Skip to content

open-node/func-delegate

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

25 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

func-deleglate

Function arguments validate and call chainning

Build status codecov

Usage

npm install func-delegate --save
describe("func-delegate", function() {
  describe("#normal-only-type", function() {
    var add = function(a, b) { return a + b; };
    add = delegate(add, [{
      name: 'num1',
      type: Number
    }, {
      name: 'num2',
      type: Number
    }]);
    it("Type assert", function(done) {
      assert.ok(add instanceof Function, '处理后的仍然是一个函数');
      assert.ok(add.num1 instanceof Function, '接收参数的函数 num1');
      assert.ok(add.num2 instanceof Function, '接收参数的函数 num2');
      done();
    });

    it("exec assert", function(done) {
      assert.equal(3, add(1, 2), '正常执行');
      assert.equal(3, add.num1(1).num2(2).exec(), '链式调用');
      done();
    });

    it("Exception assert", function(done) {
      assert.throws(function() {
        add(1, '2');
      }, function(err) {
        return (err instanceof Error) && err.message === 'Argument `num2` type must be `Number`';
      }, 'Num2 is string');

      assert.throws(function() {
        add.num2('2').num1(1).exec();
      }, function(err) {
        return (err instanceof Error) && err.message === 'Argument `num2` type must be `Number`';
      }, '链式调用 num2 is string')

      assert.throws(function() {
        add.num1(1).num2('2').exec();
      }, function(err) {
        return (err instanceof Error) && err.message === 'Argument `num2` type must be `Number`';
      }, '链式调用 num2 是 string, 顺序无关')
      done();
    });
  });

  describe("#validate allowNull", function() {
    var add = function(a, b, sqrt) {
      var sum = a + b;
      if (sqrt === true) {
        return Math.sqrt(sum);
      } else {
        return sum;
      }
    };
    add = delegate(add, [{
      name: 'num1',
      type: Number
    }, {
      name: 'num2',
      type: Number
    }, {
      name: 'sqrt',
      type: Boolean,
      allowNull: true
    }]);
    it("type assert", function(done) {
      assert.ok(add instanceof Function, '处理后的仍然是一个函数');
      assert.ok(add.num1 instanceof Function, 'num1 是接收参数的函数');
      assert.ok(add.num2 instanceof Function, 'num2 是接收参数的函数');
      assert.ok(add.sqrt instanceof Function, 'sqrt 是接收参数的函数');
      done();
    });

    it("exec assert", function(done) {
      assert.equal(3, add(1, 2), '普通调用,缺失 sqrt 参数');
      assert.equal(16, add.num1(7).num2(9).exec(), '链式执行缺失 sqrt 参数');
      assert.equal(4, add.num1(7).num2(9).sqrt(true).exec(), '链式执行 sqrt true');
      assert.equal(16, add.num1(7).num2(9).sqrt(false).exec(), 'sqrt false');
      assert.equal(16, add.sqrt(false).num1(7).num2(9).exec(), '顺序无关');
      done();
    });

    it("Exception assert", function(done) {
      assert.throws(function() {
        add(1, '2');
      }, function(err) {
        return (err instanceof Error) && err.message === 'Argument `num2` type must be `Number`';
      });

      assert.throws(function() {
        add.num2('2').num1(1).exec();
      }, function(err) {
        return (err instanceof Error) && err.message === 'Argument `num2` type must be `Number`';
      })

      assert.throws(function() {
        add.num1(1).num2('2').exec();
      }, function(err) {
        return (err instanceof Error) && err.message === 'Argument `num2` type must be `Number`';
      })

      assert.throws(function() {
        add.num1(1).num2(2).sqrt('hello').exec();
      }, function(err) {
        return (err instanceof Error) && err.message === 'Argument `sqrt` type must be `Boolean`';
      })
      done();
    });
  });

  describe("#validate rule and defaultValue", function() {
    var person = function(name, email, age) {
      return {
        name: name,
        email: email,
        age: age
      };
    };
    person = delegate(person, [{
      name: 'Name',
      type: String,
      validate: {
        matches: /^赵/,
        length: function(v) {
          return v.length > 1 && v.length < 4;
        }
      },
      message: 'Name must be a string, start with `赵`, lenght gt 1 and lt 4'
    }, {
      name: 'email',
      type: String,
      validate: {
        isEmail: true
      }
    }, {
      name: 'age',
      type: Number,
      defaultValue: 18,
      allowNull: true,
      validate: {
        max: 200
      },
      message: "Age must be a number, max value is 200, default is 18"
    }]);
    it("Type assert", function(done) {
      assert.ok(person instanceof Function, '处理后的仍然是一个函数');
      assert.ok(person.Name instanceof Function, 'Name');
      assert.ok(person.email instanceof Function, 'email');
      assert.ok(person.age instanceof Function, 'age');
      done()
    });

    it("exec assert", function(done) {
      assert.deepEqual({
        email: '13740080@qq.com',
        name: '赵雄飞',
        age: 18
      }, person('赵雄飞', '13740080@qq.com'));
      assert.deepEqual({
        email: '13740080@qq.com',
        name: '赵雄飞',
        age: 18
      }, person.Name('赵雄飞').email('13740080@qq.com').exec());
      assert.deepEqual({
        email: '13740080@qq.com',
        name: '赵雄飞',
        age: 36
      }, person.Name('赵雄飞').email('13740080@qq.com').age(36).exec());
      done()
    });

    it("Exception assert", function(done) {
      assert.throws(function() {
        person('王方', '223251686@qq.com')
      }, function(err) {
        return (err instanceof Error) && err.message === 'Name must be a string, start with `赵`, lenght gt 1 and lt 4'
      });

      assert.throws(function() {
        person('赵导耳机', '223251686@qq.com')
      }, function(err) {
        return (err instanceof Error) && err.message === 'Name must be a string, start with `赵`, lenght gt 1 and lt 4'
      });

      assert.throws(function() {
        person.Name('王方').email('223251686@qq.com').exec();
      }, function(err) {
        return (err instanceof Error) && err.message === 'Name must be a string, start with `赵`, lenght gt 1 and lt 4'
      })

      assert.throws(function() {
        person.Name('赵星梦').email('223251686').exec();
      }, function(err) {
        return (err instanceof Error) && err.message === '`email` validate failure: isEmail'
      })

      done();
    });
  });

  describe("#iterator validate", function() {
    var lib = function(books) {
      return {
        books: books,
        size: books.length
      };
    };
    lib = delegate(lib, [{
      name: 'books',
      type: Array,
      iterator: {
        name: {
          type: String,
          allowNull: false,
          validate: {
            length: [1, 20]
          },
          message: '书名必填是字符串,长度为 1 - 20'
        },
        price: {
          type: Number,
          allowNull: true,
          validate: {
            max: 300,
            min: 10
          },
          message: '价格选填,数字类型,最大 300, 最小 10'
        }
      }
    }]);
    it("Type assert", function(done) {
      assert.ok(lib instanceof Function, '处理后的仍然是一个函数');
      assert.ok(lib.books instanceof Function, 'books 是接收参数的函数');
      assert.ok(lib.exec instanceof Function, 'exec 是执行函数');
      done()
    });

    it("exec assert", function(done) {
      assert.deepEqual({
        books: [{
          name: 'JavaScript 权威指南',
          price: 35.26
        }, {
          name: 'MySQL 性能优化'
        }],
        size: 2
      }, lib([{name: 'JavaScript 权威指南', price: 35.26}, {name: 'MySQL 性能优化'}]))
      assert.deepEqual({
        books: [{
          name: 'JavaScript 权威指南',
          price: 35.26
        }, {
          name: 'MySQL 性能优化'
        }],
        size: 2
      }, lib.books([{name: 'JavaScript 权威指南', price: 35.26}, {name: 'MySQL 性能优化'}]).exec());
      done()
    });

    it("Exception assert", function(done) {
      assert.throws(function() {
        lib('hello world');
      }, function(err) {
        return (err instanceof Error) && err.message === 'Argument `books` type must be `Array`'
      }, '参数类型错误');

      assert.throws(function() {
        lib([{name: []}]);
      }, function(err) {
        return (err instanceof Error) && err.message === '书名必填是字符串,长度为 1 - 20'
      }, 'iterator 里类型错误');

      assert.throws(function() {
        lib.books([{name: 'Hello world', price: 'Redstone'}]).exec();
      }, function(err) {
        return (err instanceof Error) && err.message === '价格选填,数字类型,最大 300, 最小 10'
      }, 'iterator 价格类型不对');

      assert.throws(function() {
        lib.books([{name: 'Hello world', price: 500}]).exec();
      }, function(err) {
        return (err instanceof Error) && err.message === '价格选填,数字类型,最大 300, 最小 10'
      }, 'iterator 价格类型不对');

      assert.throws(function() {
        lib.books([{name: 'Hello world', price: 5}]).exec();
      }, function(err) {
        return (err instanceof Error) && err.message === '价格选填,数字类型,最大 300, 最小 10'
      }, 'iterator 价格类型不对');

      assert.throws(function() {
        lib.books([{name: 'Hello world'}, {name: []}]).exec();
      }, function(err) {
        return (err instanceof Error) && err.message === '书名必填是字符串,长度为 1 - 20'
      }, 'iterator 时某些数据的类型不正确');

      assert.throws(function() {
        lib.books([{name: 'Hello world Hello world Hello world Hello world'}]).exec();
      }, function(err) {
        return (err instanceof Error) && err.message === '书名必填是字符串,长度为 1 - 20'
      }, 'iterator 内书名超出长度');

      done();
    });
  });
});