UNPKG

stepler

Version:

Define iteration rules for certain data structure and compute next step value from input data.

168 lines (126 loc) 4.96 kB
import { assert } from "chai"; import sinon from "sinon"; import iterator from "../stepler"; describe("basic", () => { var data; var opts; beforeEach(() => { data = { val: 1, min: 0, max: 3 }; opts = { val: ({ val }) => val, min: ({ min }) => min, max: ({ max }) => max }; }); afterEach(() => { data = null; opts = null; }); it("should compute next value", () => { assert.strictEqual(iterator(opts)(data), 2); }); it("should compute prev value", () => { opts.step = -1; assert.strictEqual(iterator(opts)(data), 0); }); it("should allow to define step size", () => { opts.step = 2; assert(iterator(opts)(data) === 3); }); it("should return formatted value", () => { opts.format = (v, data) => ({ result: v * 4, max: data.max }); assert.deepEqual(iterator(opts)(data), { result: 8, max: 3 }); }); it("should pass direction to format function as last arg", () => { const spy = sinon.spy(); opts.format = spy; iterator({ ...opts, step: 1 })(data); iterator({ ...opts, step: -1 })(data); assert.deepEqual(spy.firstCall.args[2], { forward: true }); assert.deepEqual(spy.secondCall.args[2], { forward: false }); }); describe("overflow", () => { it("should not overflow limits by default", () => { data.val = data.max; assert.strictEqual(iterator(opts)(data), data.max, "Overflows limits moving forward"); opts.step = -1; data.val = data.min; assert.strictEqual(iterator(opts)(data), data.min, "Overflows limits moving backward"); }); it("should loop", () => { opts.overflow = "loop"; data.val = data.max; assert.strictEqual(iterator(opts)(data), data.min); opts.step = -1; data.val = data.min; assert.strictEqual(iterator(opts)(data), data.max); }); it("should snap", () => { opts.overflow = "snap"; opts.step = 2; data.val = data.max - 1; assert.strictEqual(iterator(opts)(data), data.max); data.val = data.max; assert.strictEqual(iterator(opts)(data), data.max); opts.step = -2; data.val = data.min + 1; assert.strictEqual(iterator(opts)(data), data.min); }); it("should support functions", () => { opts.step = 1; const spy = sinon.spy(); opts.overflow = spy; data.val = data.max; iterator(opts)(data); assert(spy.calledOnce); assert(spy.calledWith(data.val + 1, data)); assert.strictEqual(spy.args[0].length, 3); assert.deepEqual(spy.args[0][2], { val: data.val, forward: true, max: data.max, min: data.min }); }); it("should NOT apply 'format' to overflowing result if 'overflow' is a function", () => { const overflowingResult = {}; const overflowHandler = sinon.spy(() => overflowingResult); const formatHandler = sinon.spy(); data.val = data.max; const res = iterator({ ...opts, overflow: overflowHandler, format: formatHandler })(data); assert.isFalse(formatHandler.called); assert.equal(res, overflowingResult); }); it("should throw", () => { data.val = data.max; opts.overflow = "invalid"; assert.throws(() => iterator(opts)(data), /Unknown value for 'overflow' option/); }); }); describe("configuring", () => { it("should require 'val' and 'max' options, and set 'min' to 0 by default", () => { const { val, max } = opts; const fn = () => iterator(opts)(data); const re = /Required option .* is missed/; opts.val = null; assert.throws(fn, re, "Option 'val' is not required"); opts.val = val; opts.max = null; assert.throws(fn, re, "Option 'max' is not required"); opts.max = max; opts.min = null; opts.step = -1; data.val = data.min; assert.strictEqual(iterator(opts)(data), data.min, "Option 'min' isn't set to 0 by default"); }); it("should allow to define options both as values and functions", () => { opts = { val: 1, min: 0, max: 3, step: 1 }; Object.keys(data).forEach(key => { assert.strictEqual(iterator(opts)(), 2); const val = opts[key]; opts[key] = () => val; assert.strictEqual(iterator(opts)(), 2); }); }); }); });