assert模块源码

1.assert断言模块主要解决:

  • 测试需求,提供校验值是否为真、相等/不相等、深度匹配/不匹配等调试方法,不满足校验条件的通过fail函数构造AssertionError对象并抛出。
  • 抛出错误,构造执行函数block,通过block函数抛出错误对象Error,捕获该错误对象,与期望值比较,assert.throw方法中若由block捕获的错误匹配expected期望的校验要求(包括正则、构造函数、以block捕获错误为参数的函数),则既不抛出Error错误,也不抛出AssertionError错误;assert.doesNotThrow方法,若block捕获错误符合期望,抛出AssertionError错误,若不符合,抛出Error错误。

2.assert一般测试方法的构建:

  • 通过assert.throw(block[,error][,message])方法校验block函数执行时捕获的错误是否符合期望error的校验条件,因此该测试方法的实现在于构造block函数。或者重新构建assert方法

3.与jquery-unit的比较:

  • assert模块相等性比较更为细致,还需顾及buffer、ArrayBuffer、DataView对象。
  • 添加一般测试方法,jquery-validate提供了定制校验方法的功能,可以用于多个校验框,jquery-unit也能构造特定的通用的校验方法用于多个测试对象,assert需要反复重写block函数构建,或者重新构建assert方法。

4.使用

  • assert.AssertionError(options) 配置AssertionError错误对象
  • assert.fail(actual, expected, message, operator) 配置AssertionError错误对象,并抛出该错误,actual为实际值,expected为期望值,message错误消息,operater分隔符
  • assert(value, message), assert.ok(value, [message]) 校验value是否为真
  • assert.equal(actual, expected, [message]) 校验两者是否相等==
  • assert.notEqual(actual, expected, [message]) 校验两者是否不相等!=
  • assert.deepEqual(actual, expected, [message]) 数组、对象、时间对象、正则对象、ArrayBuffer对象、arguments对象深度匹配,非严格模式
  • assert.deepStrictEqual(actual, expected, [message]) 数组、对象、时间对象、正则对象、ArrayBuffer对象、arguments对象深度匹配,严格模式
  • assert.notDeepEqual(actual, expected, [message]) 深度匹配返回否值,非严格模式
  • assert.notDeepStrictEqual(actual, expected, [message]) 深度匹配返回否值,严格模式
  • assert.strictEqual(actual, expected, [message]) 相等比较===
  • assert.notStrictEqual(actual, expected, [message]) 不相等比较!==
  • assert.throws(block, [error], [message]) block没有错误抛出AssertionError错误,或者错误不符期望,抛出block捕获的错误
  • assert.doesNotThrow(block, [message]) 没有期望或者block捕获错误符合期望,抛出AssertionError错误;block捕获错误不符合期望,抛出block捕获的错误
  • assert.ifError(value) 参数为Error对象,直接抛出该错误对象

5源码:

'use strict';

// 比较字符串、buffer对象
function compare(a,b){
    if ( a===b ){
      return 0;
    }

    var x=a.length;
    var y=b.length;

    for ( var i=0, len=Math.min(x, y); i<len; ++i ){
        if ( a[i]!==b[i] ){
          x=a[i];
          y=b[i];
          break;
        }
    }

    if ( x<y ){
        return -1;
    }
    if ( y<x ){
        return 1;
    }
    return 0;
}

// 判断是否buffer对象
function isBuffer(b){
    if ( global.Buffer && typeof global.Buffer.isBuffer==='function' ){
      return global.Buffer.isBuffer(b);
    }
    return !!(b!=null && b._isBuffer);
}

var util=require('util/');
var hasOwn=Object.prototype.hasOwnProperty;
var pSlice=Array.prototype.slice;

// 是否拥有函数名
var functionsHaveNames=(function(){
  return function foo(){}.name==='foo';
}());

// 调用toString方法将对象转化为字符串
function pToString(obj){
  return Object.prototype.toString.call(obj);
}

// ArrayBuffer是二进制数据的原始缓冲区,该缓冲区用于存储各种类型化数组的数据
// var buffer=new ArrayBuffer(12);
// var x=new Int32Array(buffer);// 也可以直接创建
//                              // Int8Array 8位二补码有符号整数
//                              // Uint8Array 8位无符号整数
//                              // Int16Array 16位二补码有符号整数
//                              // Uint16Array 16位无符号整数
//                              // Int32Array 32位二补码有符号整数
//                              // Uint32Array 32位无符号整数
//                              // Float32Array 32位 IEEE 浮点数
//                              // Float64Array 64位 IEEE 浮点数
// x[0]=1234;console.log(x[0])  // 1234

// DataView可以对数据作更细致的操作,即每项设置不同的数据类型
// var buffer=new ArrayBuffer(12);
// var x=new DataView(buffer, 0);
// x.setInt8(0, 22);
// x.setFloat32(1, Math.PI);
// console.log(x.getInt8(0)); // 22
// console.log(x.getFloat32(1)); // 3.1415927410125732

// 判断是否ArrayBuffer对象
function isView(arrbuf){
    if ( isBuffer(arrbuf) ){
        return false;
    }
    if ( typeof global.ArrayBuffer!=='function' ){
        return false;
    }
    if ( typeof ArrayBuffer.isView==='function' ){
        return ArrayBuffer.isView(arrbuf);
    }
    if ( !arrbuf ){
        return false;
    }
    if ( arrbuf instanceof DataView ){
        return true;
    }
    if ( arrbuf.buffer && arrbuf.buffer instanceof ArrayBuffer ){
        return true;
    }
    return false;
}

var assert=module.exports=ok;

// 获取函数名
var regex=/\s*function\s+([^\(\s]*)\s*/;
function getName(func){
    if ( !util.isFunction(func) ){
        return;
    }
    if ( functionsHaveNames ){
        return func.name;
    }
    var str=func.toString();
    var match=str.match(regex);
    return match && match[1];
}

// AssertionError形式的错误对象,继承Error错误对象,用于校验失败后抛出
// new assert.AssertionError({ message: message,
//                             actual: actual,
//                             expected: expected })
assert.AssertionError=function AssertionError(options){
    this.name='AssertionError';
    this.actual=options.actual;// 实际值
    this.expected=options.expected;// 期望值
    this.operator=options.operator;// 分割符
    if ( options.message ){
        this.message=options.message;
        this.generatedMessage=false;
    }else{
        this.message=getMessage(this);// 以实际值+operator+期望值的形式构建默认错误消息
        this.generatedMessage=true;
    }

    // 获取错误的堆栈信息
    var stackStartFunction=options.stackStartFunction || fail;
    if ( Error.captureStackTrace ){
        Error.captureStackTrace(this, stackStartFunction);
    }else{
        // non v8 browsers so we can have a stacktrace
        var err=new Error();
        if ( err.stack ){
            var out=err.stack;

            // try to strip useless frames
            var fn_name=getName(stackStartFunction);
            var idx=out.indexOf('\n'+fn_name);
            if ( idx>=0 ){
                // once we have located the function frame
                // we need to strip out everything before it (and its line)
                var next_line=out.indexOf('\n', idx+1);
                out=out.substring(next_line+1);
            }

            this.stack = out;
        }
    }
};

util.inherits(assert.AssertionError, Error);

// 截取字符串
function truncate(s, n) {
    if ( typeof s==='string' ){
        return s.length<n ? s : s.slice(0, n);
    } else {
        return s;
    }
}

// 将对象转化为字符串后输出,或将函数转化为[Function: fnName]的形式
function inspect(something){
    if ( functionsHaveNames || !util.isFunction(something) ){
        return util.inspect(something);// 将任意对象转化成字符串
    }
    var rawname=getName(something);
    var name=rawname ? ': '+rawname : '';
    return '[Function'+name+']';
}

// 以实际值+分割符+期望值的形式构建默认错误消息
function getMessage(self) {
    return truncate(inspect(self.actual), 128)+' '+
           self.operator+' '+
           truncate(inspect(self.expected), 128);
}

// 配置AssertionError的实际值、期望值、错误消息、分割符、堆栈函数,并抛出错误
function fail(actual, expected, message, operator, stackStartFunction){
    throw new assert.AssertionError({
        message: message,
        actual: actual,
        expected: expected,
        operator: operator,
        stackStartFunction: stackStartFunction
    });
}

assert.fail=fail;

// 校验value是否为真
function ok(value, message){
  if (!value) fail(value, true, message, '==', assert.ok);
}
assert.ok=ok;

// 校验实际值和期望值是否相等
assert.equal=function equal(actual, expected, message){
    if ( actual!=expected ) fail(actual, expected, message, '==', assert.equal);
};

// 校验实际值和期望值是否不相等
assert.notEqual=function notEqual(actual, expected, message){
    if ( actual==expected ){
        fail(actual, expected, message, '!=', assert.notEqual);
    }
};

// 对象等深度比较,非严格模式值比较
assert.deepEqual=function deepEqual(actual, expected, message){
    if ( !_deepEqual(actual, expected, false) ){
      fail(actual, expected, message, 'deepEqual', assert.deepEqual);
    }
};

// 对象等深度比较,非严格模式引用地址比较
assert.deepStrictEqual=function deepStrictEqual(actual, expected, message){
    if ( !_deepEqual(actual, expected, true) ){
        fail(actual, expected, message, 'deepStrictEqual', assert.deepStrictEqual);
    }
};

// buffer对象、ArrayBuffer对象、时间对象、正则对象、数组、对象比较
function _deepEqual(actual, expected, strict, memos){
    if ( actual===expected ){
        return true;

    // buffer对象相等比较
    }else if( isBuffer(actual) && isBuffer(expected) ){
        return compare(actual, expected)===0;

    // 时间对象比较
    }else if( util.isDate(actual) && util.isDate(expected) ){
      return actual.getTime()===expected.getTime();

    // 正则对象比较
    }else if( util.isRegExp(actual) && util.isRegExp(expected) ){
        return actual.source===expected.source &&
               actual.global===expected.global &&
               actual.multiline===expected.multiline &&
               actual.lastIndex===expected.lastIndex &&
               actual.ignoreCase===expected.ignoreCase;

    // null值比较,分为严格比较和不严格比较
    }else if( (actual===null || typeof actual!=='object') &&
               (expected===null || typeof expected !== 'object')){
      return strict ? actual===expected : actual==expected;

    // 判断ArrayBuffer对象是否相等
    }else if( isView(actual) && isView(expected) && pToString(actual)===pToString(expected) &&
            !(actual instanceof Float32Array || actual instanceof Float64Array) ){
        return compare(new Uint8Array(actual.buffer),new Uint8Array(expected.buffer))===0;

    }else if( isBuffer(actual)!==isBuffer(expected) ){
        return false;

    }else{
        // 关于memos以及数组相等判断
        memos=memos || {actual: [], expected: []};

        var actualIndex=memos.actual.indexOf(actual);
        if ( actualIndex!==-1 ){
            if ( actualIndex===memos.expected.indexOf(expected) ){
                return true;
            }
        }

        memos.actual.push(actual);
        memos.expected.push(expected);

        return objEquiv(actual, expected, strict, memos);
    }
}

// 是否arguments参数对象
function isArguments(object){
  return Object.prototype.toString.call(object)=='[object Arguments]';
}

// arguments参数对象、对象、null、undefined比较
function objEquiv(a, b, strict, actualVisitedObjects){
    if ( a===null || a===undefined || b===null || b===undefined )
        return false;

    // util.isPrimitive???
    if ( util.isPrimitive(a) || util.isPrimitive(b) )
        return a===b;
    if ( strict && Object.getPrototypeOf(a) !== Object.getPrototypeOf(b) )
        return false;

    // arguments参数对象比较
    var aIsArgs=isArguments(a);
    var bIsArgs=isArguments(b);
    if ( (aIsArgs && !bIsArgs) || (!aIsArgs && bIsArgs) )
        return false;
    if ( aIsArgs ){
        a=pSlice.call(a);
        b=pSlice.call(b);
        return _deepEqual(a,b,strict);
    }

    // 对象比较,先比较键,再比较值
    var ka=objectKeys(a);
    var kb=objectKeys(b);
    var key, i;

    if ( ka.length!==kb.length )
        return false;

    ka.sort();
    kb.sort();
    for ( i=ka.length-1; i>=0; i-- ){
        if ( ka[i]!==kb[i] )
            return false;
    }

    // 递归比较值
    for ( i=ka.length-1; i>=0; i-- ){
        key=ka[i];
        if (!_deepEqual(a[key], b[key], strict, actualVisitedObjects))
            return false;
    }
    return true;
}

// 对象等深度比较,非严格模式值比较
assert.notDeepEqual=function notDeepEqual(actual, expected, message){
    if (_deepEqual(actual, expected, false)) {
        fail(actual, expected, message, 'notDeepEqual', assert.notDeepEqual);
    }
};

// 对象等深度比较,非严格模式引用地址比较
assert.notDeepStrictEqual=notDeepStrictEqual;
function notDeepStrictEqual(actual, expected, message){
    if (_deepEqual(actual, expected, true)) {
        fail(actual, expected, message, 'notDeepStrictEqual', notDeepStrictEqual);
    }
}

// ===相等判断
assert.strictEqual = function strictEqual(actual, expected, message) {
  if (actual !== expected) {
    fail(actual, expected, message, '===', assert.strictEqual);
  }
};

// !==不相等判断
assert.notStrictEqual = function notStrictEqual(actual, expected, message) {
  if (actual === expected) {
    fail(actual, expected, message, '!==', assert.notStrictEqual);
  }
};

// 用正则、是否实例、函数校验由block函数获得的错误actual
function expectedException(actual, expected){
    if ( !actual || !expected ){
        return false;
    }

    // 当block函数抛出错误throw new Error("Wrong value"),捕获后用正则/value/校验该error为真
    if ( Object.prototype.toString.call(expected)=='[object RegExp]' ){
        return expected.test(actual);
    }

    try{
        if ( actual instanceof expected ){
            return true;
        }
    }catch (e){
      // Ignore.  The instanceof check doesn't work for arrow functions.
    }

    if ( Error.isPrototypeOf(expected) ){
        return false;
    }

    return expected.call({}, actual) === true;
}

// 执行block,有错则捕获错误,返回为真,否则为否
function _tryBlock(block){
    var error;
    try {
        block();
    }catch (e){
        error=e;
    }
    return error;
}

// shouldThrow为真时,block没有错误抛出AssertionError错误,或者错误不符期望,抛出block捕获的错误
// shouldThrow为否时,没有期望或者block捕获错误符合期望,抛出AssertionError错误
//                    block捕获错误不符合期望,抛出block捕获的错误
function _throws(shouldThrow, block, expected, message){
    var actual;

    if (typeof block!=='function'){
        throw new TypeError('"block" argument must be a function');
    }

    if ( typeof expected==='string' ){
        message=expected;
        expected=null;
    }

    actual=_tryBlock(block);// 获取错误或undefined

    message=(expected && expected.name ? ' ('+expected.name+').' : '.')+
            (message ? ' '+message : '.');

    if ( shouldThrow && !actual ){
        fail(actual, expected, 'Missing expected exception'+message);
    }

    var userProvidedMessage=typeof message==='string';
    var isUnwantedException=!shouldThrow && util.isError(actual);
    var isUnexpectedException=!shouldThrow && actual && !expected;

    // shouldThrow为否,且actual是期望捕获的错误,用AssertionError的方式抛出错误
    if ( (isUnwantedException && userProvidedMessage && expectedException(actual, expected)) ||
        isUnexpectedException ){
        fail(actual, expected, 'Got unwanted exception'+message);
    }

    // shouldThrow为真,且actual不是期望捕获的错误,或者shouldThrow为否,actual捕获到错误,抛出actual错误
    if ( (shouldThrow && actual && expected && !expectedException(actual, expected)) || 
        (!shouldThrow && actual) ){
        throw actual;
    }
}

// block没有错误抛出AssertionError错误,或者错误不符期望,抛出block捕获的错误
assert.throws=function(block, /*optional*/error, /*optional*/message){
    _throws(true, block, error, message);
};

// 没有期望或者block捕获错误符合期望,抛出AssertionError错误
// block捕获错误不符合期望,抛出block捕获的错误
assert.doesNotThrow=function(block, /*optional*/error, /*optional*/message) {
    _throws(false, block, error, message);
};

// 参数为Error对象,直接抛出该错误对象
assert.ifError=function(err){if (err) throw err;};

// 获取对象的键
var objectKeys=Object.keys || function (obj){
    var keys=[];
    for ( var key in obj ){
      if ( hasOwn.call(obj, key) ) keys.push(key);
    }
    return keys;
};

 

 

 

 

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值