diff --git a/src/__test__/unit/builtInHandler.spec.ts b/src/__test__/unit/builtInHandler.spec.ts index 6f2cddc8..07a95818 100644 --- a/src/__test__/unit/builtInHandler.spec.ts +++ b/src/__test__/unit/builtInHandler.spec.ts @@ -20,51 +20,97 @@ const oneTwoThreeFour = `[ describe('Tests for default handler', () => { // prettier-ignore each` - serviceId | fnName | args | retCode | result - ${'op'} | ${'identity'} | ${[]} | ${0} | ${{}} - ${'op'} | ${'identity'} | ${[1]} | ${0} | ${1} - ${'op'} | ${'identity'} | ${[1, 2]} | ${1} | ${'identity accepts up to 1 arguments, received 2 arguments'} + serviceId | fnName | args | retCode | result + ${'op'} | ${'identity'} | ${[]} | ${0} | ${{}} + ${'op'} | ${'identity'} | ${[1]} | ${0} | ${1} + ${'op'} | ${'identity'} | ${[1, 2]} | ${1} | ${'identity accepts up to 1 arguments, received 2 arguments'} - ${'op'} | ${'noop'} | ${[1, 2]} | ${0} | ${{}} + ${'op'} | ${'noop'} | ${[1, 2]} | ${0} | ${{}} - ${'op'} | ${'array'} | ${[1, 2, 3]} | ${0} | ${[1, 2, 3]} + ${'op'} | ${'array'} | ${[1, 2, 3]} | ${0} | ${[1, 2, 3]} - ${'op'} | ${'array_length'} | ${[[1, 2, 3]]} | ${0} | ${3} - ${'op'} | ${'array_length'} | ${[]} | ${1} | ${'array_length accepts exactly one argument, found: 0'} + ${'op'} | ${'array_length'} | ${[[1, 2, 3]]} | ${0} | ${3} + ${'op'} | ${'array_length'} | ${[]} | ${1} | ${'array_length accepts exactly one argument, found: 0'} - ${'op'} | ${'concat'} | ${[[1, 2], [3, 4], [5, 6]]} | ${0} | ${[1, 2, 3, 4, 5, 6]} - ${'op'} | ${'concat'} | ${[[1, 2]]} | ${0} | ${[1, 2]} - ${'op'} | ${'concat'} | ${[]} | ${0} | ${[]} - ${'op'} | ${'concat'} | ${[1, [1, 2], 1]} | ${1} | ${"All arguments of 'concat' must be arrays: arguments 0, 2 are not"} + ${'op'} | ${'concat'} | ${[[1, 2], [3, 4], [5, 6]]} | ${0} | ${[1, 2, 3, 4, 5, 6]} + ${'op'} | ${'concat'} | ${[[1, 2]]} | ${0} | ${[1, 2]} + ${'op'} | ${'concat'} | ${[]} | ${0} | ${[]} + ${'op'} | ${'concat'} | ${[1, [1, 2], 1]} | ${1} | ${"All arguments of 'concat' must be arrays: arguments 0, 2 are not"} - ${'op'} | ${'string_to_b58'} | ${["test"]} | ${0} | ${"3yZe7d"} - ${'op'} | ${'string_to_b58'} | ${["test", 1]} | ${1} | ${"string_to_b58 accepts only one string argument"} + ${'op'} | ${'string_to_b58'} | ${["test"]} | ${0} | ${"3yZe7d"} + ${'op'} | ${'string_to_b58'} | ${["test", 1]} | ${1} | ${"string_to_b58 accepts only one string argument"} - ${'op'} | ${'string_from_b58'} | ${["3yZe7d"]} | ${0} | ${"test"} - ${'op'} | ${'string_from_b58'} | ${["3yZe7d", 1]} | ${1} | ${"string_from_b58 accepts only one string argument"} + ${'op'} | ${'string_from_b58'} | ${["3yZe7d"]} | ${0} | ${"test"} + ${'op'} | ${'string_from_b58'} | ${["3yZe7d", 1]} | ${1} | ${"string_from_b58 accepts only one string argument"} - ${'op'} | ${'bytes_to_b58'} | ${[[116, 101, 115, 116]]} | ${0} | ${"3yZe7d"} - ${'op'} | ${'bytes_to_b58'} | ${[[116, 101, 115, 116], 1]} | ${1} | ${"bytes_to_b58 accepts only single argument: array of numbers"} + ${'op'} | ${'bytes_to_b58'} | ${[[116, 101, 115, 116]]} | ${0} | ${"3yZe7d"} + ${'op'} | ${'bytes_to_b58'} | ${[[116, 101, 115, 116], 1]} | ${1} | ${"bytes_to_b58 accepts only single argument: array of numbers"} - ${'op'} | ${'bytes_from_b58'} | ${["3yZe7d"]} | ${0} | ${[116, 101, 115, 116]} - ${'op'} | ${'bytes_from_b58'} | ${["3yZe7d", 1]} | ${1} | ${"bytes_from_b58 accepts only one string argument"} + ${'op'} | ${'bytes_from_b58'} | ${["3yZe7d"]} | ${0} | ${[116, 101, 115, 116]} + ${'op'} | ${'bytes_from_b58'} | ${["3yZe7d", 1]} | ${1} | ${"bytes_from_b58 accepts only one string argument"} - ${'op'} | ${'sha256_string'} | ${["hello, world!"]} | ${0} | ${"QmVQ8pg6L1tpoWYeq6dpoWqnzZoSLCh7E96fCFXKvfKD3u"} - ${'op'} | ${'sha256_string'} | ${["hello, world!", true]} | ${0} | ${"84V7ZxLW7qKsx1Qvbd63BdGaHxUc3TfT2MBPqAXM7Wyu"} - ${'op'} | ${'sha256_string'} | ${[]} | ${1} | ${"sha256_string accepts 1-3 arguments, found: 0"} + ${'op'} | ${'sha256_string'} | ${["hello, world!"]} | ${0} | ${"QmVQ8pg6L1tpoWYeq6dpoWqnzZoSLCh7E96fCFXKvfKD3u"} + ${'op'} | ${'sha256_string'} | ${["hello, world!", true]} | ${0} | ${"84V7ZxLW7qKsx1Qvbd63BdGaHxUc3TfT2MBPqAXM7Wyu"} + ${'op'} | ${'sha256_string'} | ${[]} | ${1} | ${"sha256_string accepts 1-3 arguments, found: 0"} - ${'op'} | ${'concat_strings'} | ${[]} | ${0} | ${""} - ${'op'} | ${'concat_strings'} | ${["a", "b", "c"]} | ${0} | ${"abc"} + ${'op'} | ${'concat_strings'} | ${[]} | ${0} | ${""} + ${'op'} | ${'concat_strings'} | ${["a", "b", "c"]} | ${0} | ${"abc"} - ${'peer'} | ${'timeout'} | ${[200, []]} | ${0} | ${[]}} - ${'peer'} | ${'timeout'} | ${[200, ['test']]} | ${0} | ${['test']}} - ${'peer'} | ${'timeout'} | ${[]} | ${1} | ${'timeout accepts exactly two arguments: timeout duration in ms and a message string'}} - ${'peer'} | ${'timeout'} | ${[200, 'test', 1]} | ${1} | ${'timeout accepts exactly two arguments: timeout duration in ms and a message string'}} + ${'peer'} | ${'timeout'} | ${[200, []]} | ${0} | ${[]}} + ${'peer'} | ${'timeout'} | ${[200, ['test']]} | ${0} | ${['test']}} + ${'peer'} | ${'timeout'} | ${[]} | ${1} | ${'timeout accepts exactly two arguments: timeout duration in ms and a message string'}} + ${'peer'} | ${'timeout'} | ${[200, 'test', 1]} | ${1} | ${'timeout accepts exactly two arguments: timeout duration in ms and a message string'}} - ${'debug'} | ${'stringify'} | ${[]} | ${0} | ${'""'}} - ${'debug'} | ${'stringify'} | ${[{a: 10, b: 20}]} | ${0} | ${a10b20}} - ${'debug'} | ${'stringify'} | ${[1, 2, 3, 4]} | ${0} | ${oneTwoThreeFour}} + ${'debug'} | ${'stringify'} | ${[]} | ${0} | ${'""'}} + ${'debug'} | ${'stringify'} | ${[{a: 10, b: 20}]} | ${0} | ${a10b20}} + ${'debug'} | ${'stringify'} | ${[1, 2, 3, 4]} | ${0} | ${oneTwoThreeFour}} + ${'math'} | ${'add'}" | ${[2, 2]} | ${0} | ${4} + ${'math'} | ${'add'}" | ${[2]} | ${1} | ${"Expected 2 argument(s). Got 1"} + + ${'math'} | ${'sub'}" | ${[2, 2]} | ${0} | ${0} + ${'math'} | ${'sub'}" | ${[2, 3]} | ${0} | ${-1} + + ${'math'} | ${'mul'}" | ${[2, 2]} | ${0} | ${4} + ${'math'} | ${'mul'}" | ${[2, 0]} | ${0} | ${0} + ${'math'} | ${'mul'}" | ${[2, -1]} | ${0} | ${-2} + + ${'math'} | ${'fmul'}" | ${[10, 0.66]} | ${0} | ${6} + ${'math'} | ${'fmul'}" | ${[0.5, 0.5]} | ${0} | ${0} + ${'math'} | ${'fmul'}" | ${[100.5, 0.5]} | ${0} | ${50} + + ${'math'} | ${'div'}" | ${[2, 2]} | ${0} | ${1} + ${'math'} | ${'div'}" | ${[2, 3]} | ${0} | ${0} + ${'math'} | ${'div'}" | ${[10, 5]} | ${0} | ${2} + + ${'math'} | ${'rem'}" | ${[10, 3]} | ${0} | ${1} + + ${'math'} | ${'pow'}" | ${[2, 2]} | ${0} | ${4} + ${'math'} | ${'pow'}" | ${[2, 0]} | ${0} | ${1} + + ${'math'} | ${'log'}" | ${[2, 2]} | ${0} | ${1} + ${'math'} | ${'log'}" | ${[2, 4]} | ${0} | ${2} + + ${'cmp'} | ${'gt'}" | ${[2, 4]} | ${0} | ${false} + ${'cmp'} | ${'gte'}" | ${[2, 4]} | ${0} | ${false} + ${'cmp'} | ${'gte'}" | ${[4, 2]} | ${0} | ${true} + ${'cmp'} | ${'gte'}" | ${[2, 2]} | ${0} | ${true} + + ${'cmp'} | ${'lt'}" | ${[2, 4]} | ${0} | ${true} + ${'cmp'} | ${'lte'}" | ${[2, 4]} | ${0} | ${true} + ${'cmp'} | ${'lte'}" | ${[4, 2]} | ${0} | ${false} + ${'cmp'} | ${'lte'}" | ${[2, 2]} | ${0} | ${true} + + ${'cmp'} | ${'cmp'}" | ${[2, 4]} | ${0} | ${-1} + ${'cmp'} | ${'cmp'}" | ${[2, -4]} | ${0} | ${1} + ${'cmp'} | ${'cmp'}" | ${[2, 2]} | ${0} | ${0} + + ${'array'} | ${'sum'}" | ${[[1, 2, 3]]} | ${0} | ${6} + ${'array'} | ${'dedup'}" | ${[["a", "a", "b", "c", "a", "b", "c"]]} | ${0} | ${["a", "b", "c"]} + ${'array'} | ${'intersect'}" | ${[["a", "b", "c"], ["c", "b", "d"]]} | ${0} | ${["b", "c"]} + ${'array'} | ${'diff'}" | ${[["a", "b", "c"], ["c", "b", "d"]]} | ${0} | ${["a"]} + ${'array'} | ${'sdiff'}" | ${[["a", "b", "c"], ["c", "b", "d"]]} | ${0} | ${["a", "d"]} + `.test( // '$fnName with $args expected retcode: $retCode and result: $result', diff --git a/src/internal/builtins/common.ts b/src/internal/builtins/common.ts index 4cc8f3d6..24bedecc 100644 --- a/src/internal/builtins/common.ts +++ b/src/internal/builtins/common.ts @@ -288,79 +288,183 @@ export const builtInServices = { math: { add: (req) => { - return errorNotImpl('math.add'); + let err; + if ((err = checkForArgumentsCount(req, 2))) { + return err; + } + const [x, y] = req.args; + return success(x + y); }, sub: (req) => { - return errorNotImpl('math.sub'); + let err; + if ((err = checkForArgumentsCount(req, 2))) { + return err; + } + const [x, y] = req.args; + return success(x - y); }, mul: (req) => { - return errorNotImpl('math.mul'); + let err; + if ((err = checkForArgumentsCount(req, 2))) { + return err; + } + const [x, y] = req.args; + return success(x * y); }, fmul: (req) => { - return errorNotImpl('math.fmul'); + let err; + if ((err = checkForArgumentsCount(req, 2))) { + return err; + } + const [x, y] = req.args; + return success(Math.floor(x * y)); }, div: (req) => { - return errorNotImpl('math.div'); + let err; + if ((err = checkForArgumentsCount(req, 2))) { + return err; + } + const [x, y] = req.args; + return success(Math.floor(x / y)); }, rem: (req) => { - return errorNotImpl('math.rem'); + let err; + if ((err = checkForArgumentsCount(req, 2))) { + return err; + } + const [x, y] = req.args; + return success(x % y); }, pow: (req) => { - return errorNotImpl('math.pow'); + let err; + if ((err = checkForArgumentsCount(req, 2))) { + return err; + } + const [x, y] = req.args; + return success(Math.pow(x, y)); }, log: (req) => { - return errorNotImpl('math.log'); + let err; + if ((err = checkForArgumentsCount(req, 2))) { + return err; + } + const [x, y] = req.args; + return success(Math.log(y) / Math.log(x)); }, }, cmp: { gt: (req) => { - return errorNotImpl('cmp.gt'); + let err; + if ((err = checkForArgumentsCount(req, 2))) { + return err; + } + const [x, y] = req.args; + return success(x > y); }, gte: (req) => { - return errorNotImpl('cmp.gte'); + let err; + if ((err = checkForArgumentsCount(req, 2))) { + return err; + } + const [x, y] = req.args; + return success(x >= y); }, lt: (req) => { - return errorNotImpl('cmp.lt'); + let err; + if ((err = checkForArgumentsCount(req, 2))) { + return err; + } + const [x, y] = req.args; + return success(x < y); }, lte: (req) => { - return errorNotImpl('cmp.lte'); + let err; + if ((err = checkForArgumentsCount(req, 2))) { + return err; + } + const [x, y] = req.args; + return success(x <= y); }, cmp: (req) => { - return errorNotImpl('cmp.cmp'); + let err; + if ((err = checkForArgumentsCount(req, 2))) { + return err; + } + const [x, y] = req.args; + return success(x === y ? 0 : x > y ? 1 : -1); }, }, array: { sum: (req) => { - return errorNotImpl('array.sum'); + let err; + if ((err = checkForArgumentsCount(req, 1))) { + return err; + } + const [xs] = req.args; + return success(xs.reduce((agg, cur) => agg + cur, 0)); }, dedup: (req) => { - return errorNotImpl('array.dedup'); + let err; + if ((err = checkForArgumentsCount(req, 1))) { + return err; + } + const [xs] = req.args; + const set = new Set(xs); + return success(Array.from(set)); }, intersect: (req) => { - return errorNotImpl('array.intersect'); + let err; + if ((err = checkForArgumentsCount(req, 2))) { + return err; + } + const [xs, ys] = req.args; + const intersection = xs.filter((x) => ys.includes(x)); + return success(intersection); }, diff: (req) => { - return errorNotImpl('array.diff'); + let err; + if ((err = checkForArgumentsCount(req, 2))) { + return err; + } + const [xs, ys] = req.args; + const diff = xs.filter((x) => !ys.includes(x)); + return success(diff); }, sdiff: (req) => { - return errorNotImpl('array.sdiff'); + let err; + if ((err = checkForArgumentsCount(req, 2))) { + return err; + } + const [xs, ys] = req.args; + const sdiff = [ + // force new line + ...xs.filter((y) => !ys.includes(y)), + ...ys.filter((x) => !xs.includes(x)), + ]; + return success(sdiff); }, }, }; + +const checkForArgumentsCount = (req, count: number) => { + if (req.args.length !== count) { + return error(`Expected ${count} argument(s). Got ${req.args.length}`); + } +};