mass Framework spec模块 v2
对于一个框架的成长来说,测试是必不可少的,像用手来点来点去的测试基本不算测试,只有基于代码的单元测试才能让人安心。因此我不断地升级我的测试工具,从早期的abut到现在的spec模块。它不断地添加测试函数:eq, ok, same,contains, match...最近添加的方法是near,是专门用于测试CSS样式值,像width, height, opacity, border-top-width等值在各浏览器下总差1,2像素,更有甚者,webkit系的连浮点数也出来了。由于一个框架拥有许多模块,因此测试显示区也分为许多版块,如何处理同步与异步的关系非常重要,前一版本专门搞了个Deferred异步列队,但我发现其实mass的模块加载模块中的ready列队就是现成的异步列队,因此这版本就省下许多代码。本版本还处理了中文显示问题,这主要是因为FF私自对函体内的中文进行转码,我搞了uni2hanzi把它还原回来了。
CSS部分
@CHARSET "UTF-8";
#dom-spec-result {
border:5px solid #00a7ea;
padding:10px;
background:#03c9fa;
list-style-type:none;
}
.dom-spec-summary {
height: 2em;
line-height: 2em;
margin: 0;
font-size: 13px;
font-weight: bold;
text-indent: 2em;
background:#008000;
color:#fff;
}
.dom-spec-detail{
list-style: none;
margin: 0;
padding: 0;
}
.dom-spec-detail li{
margin: 0;
padding:0;
border: 2px solid #03c9fa;
text-indent: 1em;
}
.dom-spec-pass{
background:#a9ea00;
}
.dom-spec-unpass{
background:#cd0000;
color:#fff;
}
.dom-spec-detail pre{
margin: 1em;
text-indent: 0;
font-style: normal;
background: #F0F8FF;
padding: 2px;
color:#000;
border:2px outset #c0c0c0;
}
.dom-spec-error{
background: #000;
color:#fff;
}
.dom-spec-log{
background: #cc9!important;
}
/*用于点击展开*/
.dom-spec-slide {
background:#a9ea00;
text-indent: 2em;
line-height: 1.4em;
height: 1.4em;
margin: 0;
}
.dom-spec-diff {
background: red;
margin: 1em;
}
.dom-spec-diff div{
width:45%;
float: left;
}
.dom-spec-diff pre{
background: #00cc00;
}
/* new clearfix */
.clearfix:after {
visibility: hidden;
display: block;
font-size: 0;
content: " ";
clear: both;
height: 0;
}
* html .clearfix { zoom: 1; } /* IE6 */
*:first-child+html .clearfix { zoom: 1; } /* IE7 */
JS部分
//==================================================
// 测试模块
//==================================================
(function(global,DOC){
var dom = global[DOC.URL.replace(/(#.+|\W)/g,'')];
dom.define("first/spec", function(){
dom.log("已加载spec模块")
//模块为dom添加如下方法:
//quote isEqual dump Deferred runTest addTestModule
//在全局命名空间下多添加一个函数 expect
dom.mix(dom,{
//在字符串两端加上引号,并对其内部一些字符进行转义,用于JSON与引用
quote :global.JSON && JSON.stringify || String.quote || (function(){
var meta = {
'\t':'t',
'\n':'n',
'\v':'v',
'f':'f',
'\r':'\r',
'\'':'\'',
'\"':'\"',
'\\':'\\'
},
reg = /[\x00-\x1F\'\"\\\u007F-\uFFFF]/g,
regFn = function(c){
if (c in meta) return '\\' + meta[c];
var ord = c.charCodeAt(0);
return ord < 0x20 ? '\\x0' + ord.toString(16)
: ord < 0x7F ? '\\' + c
: ord < 0x100 ? '\\x' + ord.toString(16)
: ord < 0x1000 ? '\\u0' + ord.toString(16)
: '\\u' + ord.toString(16)
};
return function (str) {
return '"' + str.replace(reg, regFn)+ '"';
}
})(),
//比较对象是否相等或相似
isEqual: function(a, b) {
if (a === b) {
return true;
} else if (a === null || b === null || typeof a === "undefined" || typeof b === "undefined" || dom.type(a) !== dom.type(b)) {
return false; // don't lose time with error prone cases
} else {
switch(dom.type(a)){
case "String":
case "Boolean":
case "Number":
case "Null":
case "Undefined":
//处理简单类型的伪对象与字面值相比较的情况,如1 v new Number(1)
if (b instanceof a.constructor || a instanceof b.constructor) {
return a == b;
}
return a === b;
case "NaN":
return isNaN(b);
case "Date":
return a.valueOf() === b.valueOf();
case "NodeList":
case "Arguments":
case "Array":
var len = a.length;
if (len !== b.length)
return false;
for (var i = 0; i < len; i++) {
if (!this.isEqual(a[i], b[i])) {
return false;
}
}
return true;
default:
for (var key in b) {
if (!this.isEqual(a[key], b[key])) {
return false;
}
}
return true;
}
}
},
//用于查看对象的内部构造
dump : function(obj, indent) {
indent = indent || "";
if (obj === null)
return indent + "null";
if (obj === void 0)
return indent + "undefined";
if (obj.nodeType === 9)
return indent + "[object Document]";
if (obj.nodeType)
return indent + "[object " + (obj.tagName || "Node") +"]";
var arr = [],type = dom.type(obj),self = arguments.callee,next = indent + "\t";
switch (type) {
case "Boolean":
case "Number":
case "NaN":
case "RegExp":
return indent + obj;
case "String":
return indent + dom.quote(obj);
case "Function":
return (indent + obj).replace(/\n/g, "\n" + indent);
case "Date":
return indent + '(new Date(' + obj.valueOf() + '))';
case "XMLHttpRequest" :
case "Window" :
return indent + "[object "+type +"]";
case "NodeList":
case "Arguments":
case "Array":
for (var i = 0, n = obj.length; i < n; ++i)
arr.push(self(obj[i], next).replace(/^\s* /g, next));
return indent + "[\n" + arr.join(",\n") + "\n" + indent + "]";
default:
for ( i in obj) {
arr.push(next + self(i) + ": " + self(obj[i], next).replace(/^\s+/g, ""));
}
return indent + "{\n" + arr.join(",\n") + "\n" + indent + "}";
}
}
});
//这里尽量不依赖其他核主模块
var $ = function(id) {
return DOC.getElementById(id);
};
var parseHTML = function() {//用于生成元素节点,注意第一层只能用一个元素
var div = DOC.createElement("div");
return function(html) {
div.innerHTML = html;
return div.firstChild;
};
}();
//在字符串嵌入表达式 http://www.cnblogs.com/rubylouvre/archive/2011/03/06/1972176.html
var reg_format = /\\?\#{([^{}]+)\}/gm;
var format = function(str, object){
var array = dom.slice(arguments,1);
return str.replace(reg_format, function(match, name){
if (match.charAt(0) == '\\')
return match.slice(1);
var index = Number(name)
if(index >=0 )
return array[index];
if(object && object[name] !== void 0)
return object[name];
return '' ; ;
});
}
var Expect = function(actual){
return this instanceof Expect ? this.init(actual) : new Expect(actual);
}
function getUnpassExpect(str){
var boolIndex = 1,ret = "error!",section = 0, qualifier = "("
for(var j=1;j < str.length;j++){
if(str.charAt(j) == "("){
boolIndex++
}else if(str.charAt(j) == ")"){
boolIndex--
}else if(str.charAt(j) != qualifier && boolIndex == 0){
section++
if(section == 1){
qualifier = ")"//取得expect(...)中的部分
boolIndex = -1
}else if(section == 2){
boolIndex = 1;//取得ok,eq,match,log等函数名
qualifier = ")"
}else if(section == 3){//取得最后的函数体,并返回整个匹配项
ret = "expect" + str.slice(0,j)
break
}
}
}
return ret;
}
dom.require("ready",function(){
var html = ['<div id="dom-spec-result"><p class="dom-spec-summary">',
'<span id="dom-spec-failures" title="0">0</span> failures ',
'<span id="dom-spec-errors" title="0">0</span> errors ',
'<span id="dom-spec-done" title="0">0</span>% done ',
'<span id="dom-spec-time" title="0">0</span>ms </p>',
'<p class="dom-spec-summary">',global.navigator.userAgent,
'</p><div id="dom-spec-cases"><div id="loading">正在加载测试数据中,请耐心等特</div></div></div>'];
//div#dom-spec-result为整个系统的容器
//div#dom-spec-summary用于放置各种统计
//div#dom-spec-cases用于放置测试模块
DOC.body.appendChild(parseHTML(html.join("")));
});
dom.mix(Expect,{
refreshTime : function(){//刷新花费时间
var el = $("dom-spec-time");
var times = parseInt(el.title,10) + (new Date - Expect.now);
el.title = times;
el.innerHTML = times
},
addTestModule : function(title, cases) {
dom.require("ready",function(){
var moduleId = "dom-spec-"+title, names = [];
if(!$(moduleId)){//在主显示区中添加一个版块
/** =================每个模块大抵是下面的样子===============
<div class="dom-spec-case" id="dom-spec-dom.js">
<p><a href="javascript:void(0)">JS文件名字</a></p>
<ul style="display: none;" class="dom-spec-detail">
测试结果
</ul>
</div>
*/
var html = ['<div id="#{0}" class="dom-spec-case">',
'<p class="dom-spec-slide"><a href="javascript:void(0)">#{1}</a></p>',
'<ul class="dom-spec-detail" style="display:none;"></ul></div>'].join('');
$("dom-spec-cases").appendChild(parseHTML(format(html, moduleId, title)));
}
for(var name in cases){//取得describe第二个参数的那个对象所包含的所有函数,并放到异步列队中逐一执行它们
if(cases.hasOwnProperty(name)){
names.push(name);
}
};
(function runTest(){
if((name = names.shift())){
var suite = cases[name],//测试函数
caseId = "dom-spec-case-"+name.replace(/\./g,"-");
if(!Expect.removeLoading){
var loading = $("loading");
loading.parentNode.removeChild(loading);
Expect.removeLoading = 1
}
if(!$(caseId)){//对应一个方法
var parentNode = $(moduleId).getElementsByTagName("ul")[0];
//处理函数体的显示
var safe = (suite+"").replace(/</g,"<").replace(/>/g,">");
//从函数体内分解出所有测试单元
Expect.expectArray = safe.split("expect");
//函数体本身
var node = parseHTML(format('<li id="#{0}">#{1}<pre>#{2}</pre></li>',caseId,name,uni2hanzi(safe)));
parentNode.appendChild(node);
}
Expect.Client = $(caseId);//对应一个LI元素
Expect.PASS = 1;//用于判定此测试套件有没有通过
Expect.boolIndex = 0;//用于记录当前是执行到第几条测试
Expect.totalIndex = 0;
Expect.now = new Date;
try{
suite();//执行测试套件
}catch(err){
Expect.PASS = 2;
var htm = ["第",Expect.boolIndex,"行测试发生错误\n",Expect.Msgs[Expect.boolIndex],"\n"];
for(var e in err){
htm.push(e+" "+(err[e]+"").slice(0,100)+"\n");
}
htm = '<pre title="error">'+htm.join("").replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>')+"</pre>";
Expect.Client.appendChild(parseHTML(htm));
var errors = $("dom-spec-errors");
errors.title++;
errors.innerHTML = errors.title;
}
$(caseId).className = Expect.CLASS[Expect.PASS];
Expect.refreshTime();//更新测试所花的时间
setTimeout(runTest,16);
}
})();
});
},
CLASS : {
0:"dom-spec-unpass",
1:"dom-spec-pass",
2:"dom-spec-error"
},
Msgs:{},
prototype:{
init:function(actual){//传入一个目标值以进行比较或打印
this.actual = actual;
return this;
},
ok:function(msg){//判定是否返回true
this._should("ok",void 0,msg);
},
ng:function(msg){//判定是否返回false
this._should("ng",void 0,msg);
},
log:function(msg){//不做判断,只打印结果,用于随机数等肉眼验证
this._should("log",msg);
},
eq:function(expected,msg){//判定目标值与expected是否全等
this._should("eq", expected, msg);
},
near:function(expected, msg){
this._should("near", expected, msg);
},
match:function(fn,msg){//判定目标值与expected是否全等
this._should("match", fn, msg);
},
not:function(expected,msg){//判定目标值与expected是否非全等
this._should("not", expected,msg);
},
has:function(prop,msg){//判定目标值是否包含prop属性
this._should("has", prop,msg);
},
contains:function(el,msg){//判定目标值是否包含el这个元素(用于数组或类数组)
this._should("contains", el,msg);
},
same: function(expected,msg){//判定结果是否与expected相似(用于数组或对象或函数等复合类型)
this._should("same", expected,msg);
},
_should:function(method,expected, msg){//上面方法的内部实现,比较真伪,并渲染结果到页面
var actual = this.actual,bool = false;
if(method != "log"){
Expect.Msgs[Expect.boolIndex] = msg;
Expect.boolIndex++;
}
Expect.totalIndex++
switch(method){
case "ok"://布尔真测试
bool = actual === true;
expected = true;
break;
case "ng"://布尔非测试
bool = actual === false;
expected = false;
break;
case "eq"://同一性真测试
bool = actual == expected;
break;
case "near":
var threshold = arguments[3] | 0;
return Math.abs(parseFloat(this.actual) - parseFloat(expected)) <= threshold;
break;
case "not"://同一性非测试
bool = actual != expected;
break;
case "same":
bool = dom.isEqual(actual, expected);
break
case "has":
bool = Object.prototype.hasOwnProperty.call(actual, expected);
break;
case "match":
bool = expected(actual);
break;
case "contains":
for(var i = 0,n = actual.length; i < n ;i++ ){
if(actual === expected ){
bool = true;
break;
}
}
break;
case "log":
bool = "";
Expect.Client.appendChild(parseHTML('<pre class="dom-spec-log" title="log">'+(expected||"")+" "+dom.dump(actual)+'</pre>'));
break;
}
// Expect.Msgs[Expect.boolIndex] = msg;
//修改统计栏的数值
var done = $("dom-spec-done");
var errors = $("dom-spec-errors");
var failures = $("dom-spec-failures");
if(typeof bool === "boolean"){
Expect.PASS = ~~bool;
if(!bool){//如果没有通过
failures.title++;
failures.innerHTML = failures.title;
var statement = getUnpassExpect((Expect.expectArray[Expect.totalIndex] || ""))
var html = ['<div class="dom-spec-diff clearfix">'+(msg ? "<p>"+msg+"</p>" : "")+'<p>本测试套件中第',Expect.boolIndex,
'条测试出错: ',statement,'</p><div>actual:<pre title="actual">'+dom.type(actual)+" : "+dom.dump(actual)+'</pre></div>',
'<div>expected:<pre title="expected">'+dom.type(expected)+" : "+dom.dump(expected)+'</pre></div>',
'</div>'];
Expect.Client.appendChild(parseHTML(html.join('')));
}
done.title++;
done.innerHTML = (((done.title-errors.title-failures.title)/done.title)*100).toFixed(0);
}
}
}
});
//用于收起或展开详细测试结果
dom.bind(DOC,"click",function(e){
var target = e && e.target || event.srcElement;
if(target.tagName === "A"){
var parent = target.parentNode.parentNode;
if(parent.className== "dom-spec-case"){//用于切换详情面板
var ul = parent.getElementsByTagName("ul")[0];
var display = ul.style.display;
ul.style.display = display === "none" ? "" : "none";
}
}
});
//shortcut
//暴露到全局作用域
global.expect = Expect;
dom.addTestModule = Expect.addTestModule;
//此函数是解决FF无法显示函数体内的汉字问题
var uni2hanzi = global.netscape ? function(s){
return unescape(s.replace(/\\u/g,'%u'));
}: function(s){
return s
}
})
})(this,this.document);
//2011.8.9 增加getUnpassExpect函数,用于取得没有通过的expect并显示出来
//2011.10.26 优化format与quote
//2011.10.27 runTest添加参数,用于等特一定做量的测试模块都加载完毕才执行
//2011.10.31 去掉deferred模块的依赖,依靠ready列队自行添加测试的模块
用法:
//主页面引用
dom.require("ready,test/dom,test/lang", dom.noop);
测试用的JS文件:
// test/dom.js
dom.define("test/dom","first/spec",function(){
dom.isWindow = function(obj){//单独提出来,专门用于测试对window的判定
return dom.type(obj,"Window")
};
dom.addTestModule('模块加载模块-dom', {
'type': function() {
expect(dom.type("string")).eq("String");
expect(dom.type(1)).eq("Number");
expect(dom.type(!1)).eq("Boolean");
expect(dom.type(NaN)).eq("NaN");
expect(dom.type(/test/i)).eq("RegExp");
expect(dom.type(dom.noop)).eq("Function");
expect(dom.type(null)).eq("Null");
expect(dom.type({})).eq("Object");
expect(dom.type([])).eq("Array");
expect(dom.type(new Date)).eq("Date");
expect(dom.type(window)).eq("Window");
expect(dom.type(document)).eq("Document");
expect(dom.type(document.documentElement)).eq("HTML");
expect(dom.type(document.body)).eq("BODY");
expect(dom.type(document.childNodes)).eq("NodeList");
expect(dom.type(document.getElementsByTagName("*"))).eq("NodeList");
expect(dom.type(arguments)).eq("Arguments");
expect(dom.type(1,"Number")).eq(true);
},
"isWindow" : function(){
var test1 = {};
test1.window = test1;
test1.document = document;
expect(dom.isWindow(test1)).ng();
var test2 = {};
test2.window = window;
test2.document = document;
expect(dom.isWindow(test1)).ng();
expect(dom.isWindow(window)).ok();
var iframe = document.createElement("iframe");
document.body.appendChild(iframe);
var iwin = iframe.contentWindow || iframe.contentDocument.parentWindow;
expect(dom.isWindow(iwin)).ok();
document.body.removeChild(iframe);
var wg = {
document : {}
}, wgdoc = wg.document;
wg.window = wg;
wgdoc.createElement = function(){
return wg;
};
wgdoc.getElementsByTagName = function(){
return [wg];
};
wgdoc.parentWindow = wg;
wg.insertBefore = function(){};
wg.firstChild = wg.firstChild;
wg.removeChild = function(){};
expect(dom.isWindow(wg)).ng();//false
},
"oneObject":function(){
expect(dom.oneObject("aa,bb,cc")).same({
"aa":1,
"bb":1,
"cc":1
});
expect(dom.oneObject([1,2,3],false)).same({
"1":false,
"2":false,
"3":false
});
}
});
});
// test/lang.js
dom.define("test/lang","lang,first/spec",function(dom, $$){
dom.addTestModule("语言扩展模块-lang",{
"dom.isPlainObject": function() {
expect(dom.isPlainObject([])).ng();//false
expect(dom.isPlainObject(1)).ng();//false
expect(dom.isPlainObject(null)).ng();//false
expect(dom.isPlainObject(void 0)).ng();//false
expect(dom.isPlainObject(window)).ng();//false
expect(dom.isPlainObject(document.body)).ng();//false
expect(window.location).log();
expect(dom.isPlainObject(window.location)).ng();//false
var fn = function(){}
expect(dom.isPlainObject(fn)).ng();//false
fn.prototype = {
someMethod: function(){}
};
expect(dom.isPlainObject(new fn)).ng();//false
expect(dom.isPlainObject({})).ok();//true
expect(dom.isPlainObject({
aa:"aa",
bb:"bb",
cc:"cc"
})).ok();//true
expect(dom.isPlainObject(new Object)).ok();//true
},
"dom.isArrayLike":function(){
expect(dom.isArrayLike(arguments)).ok();//1
expect(dom.isArrayLike(document.links)).ok();//2
expect(dom.isArrayLike(document.documentElement.childNodes)).ok();
expect(dom.isArrayLike({
0:"a",
1:"b",
length:2
})).ok();
var tag = dom.tag
var html = tag("select",tag("option","aaa") + tag("option","bbb")+ tag("option","ccc"))
var div = document.createElement("div");
div.innerHTML = html;
var select = div.firstChild;
expect(dom.isArrayLike(select)).ng();
},
"dom.isNative":function(){
expect(dom.isNative(Array.prototype,"slice")).ok();
expect(dom.isNative(Array.prototype,"indexOf")).log();
expect(dom.isNative(Array.prototype,"forEach")).log();
expect(dom.isNative(String.prototype,"quote")).log();
expect(dom.isNative(String.prototype,"trim")).log();
expect(dom.isNative(Function.prototype,"bind")).log();
},
"dom.range":function(){
expect(dom.range(10)).same([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
expect(dom.range(1, 11)).same([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
expect(dom.range(0, 30, 5)).same([0, 5, 10, 15, 20, 25]);
expect(dom.range(0, -10, -1)).same([0, -1, -2, -3, -4, -5, -6, -7, -8, -9]);
expect(dom.range(0)).same([]);
},
"dom.format":function(){
expect(dom.format("pi is #{0}", Math.PI)).eq("pi is 3.141592653589793");
var a = dom.format("style.#{name}=((isEnd ? #{end} : adapter.#{type}( #{from}, #{change},'#{easing}',per ))|0)+'#{unit}';",{
name:"width",
end:"0",
type:"_default",
from:"200",
change:"200",
easing:"linear",
unit:"px"
}) ;
expect(a).eq("style.width=((isEnd ? 0 : adapter._default( 200, 200,'linear',per ))|0)+'px';");
},
"dom.tag":function(){
var tag = dom.tag
var html = tag("h1 title='aaa'","sss")
('a href=#' ,
tag("img src='http://www.google.com.hk/images/nav_logo83.png'")
('br')
('' ,"View larger image") );
expect(html+"").eq("<h1 title='aaa'>sss</h1><a href=#><img src='http://www.google.com.hk/images/nav_logo83.png'><br>View larger image</a>");
},
"dom.parseXML":function(){
var str = "<note><to>Tove</to><from>Jani</from><heading>Reminder</heading><body>Don't forget me this weekend!</body></note>"
expect(dom.parseXML(str).nodeType).eq(9)//[object XMLDocument]
},
"String2":function(){
expect($$("aaabbbcc").contains("bbb")).ok();
expect($$('http://index').startsWith('http')).ok();
expect($$('image.gif').endsWith('.gif')).ok();
expect($$('image.gif').endsWith('.GIF')).ng();
expect($$('image.gif').endsWith(".GIF",true)).ok();
expect($$('司徒正美').byteLen()).eq(8);
expect($$('').empty()).ok();
expect($$(' ').empty()).ng();
expect($$(' ').blank()).ok();
expect($$('').blank()).ok();
expect($$('\n').blank()).ok();
expect($$(' a').blank()).ng();
expect($$("this is a test test").truncate(10)).eq("this is...");
expect($$("foo-bar").camelize()).eq("fooBar");
expect($$("boo boo boo").capitalize()).eq("Boo boo boo");
expect($$("fooBar").underscored()).eq("foo_bar");
expect($$("foo-bar").underscored()).eq("foo_bar");
expect($$("10.23").toInt()).eq(10);
expect($$("1.23").toFloat()).eq(1.23);
expect($$("animals.sheep[1]").escapeRegExp()).eq("animals\\.sheep\\[1\\]");
expect($$("2").padLeft(4)).eq("0002");
expect($$("2").padRight(4," ")).eq("2 ");
expect($$("ruby").times(2)).eq("rubyruby");
},
"Array2":function(){
var a = ["aaa",1,2,undefined,3,4,null,{
2:2
}];
//复制一个副本
var b = $$(a).clone();
expect(a).same(b);//1
expect(a).not(b);//2
expect($$(a).first()).eq('aaa');//3
expect($$(a).first(function(el){//4
return el >1
})).eq(2);
expect($$(a).last()).same({//5
2:2
});
expect($$(a).last(function(el){//6
return el >1
})).eq(4);
expect($$(a).contains(2)).ok();//7
expect($$(a).diff([1,2,3])).same(["aaa",undefined,4,null,{
2:2
}]);
expect($$(b).remove(1)).same([1]);
expect($$(b).removeAt(1)).same([2]);
expect($$(a).shuffle()).log();
expect($$(a).random()).log();
expect($$(a).compact()).same(["aaa",1,2,3,4,{
2:2
}]);
expect($$(a).ensure(3,4,5)).same(["aaa",1,2,undefined,3,4,null,{
2:2
},5]);
var c = [3,4,6,1,45,9,5,3,4,22,3];
expect($$(c).min()).eq(1);
expect($$(c).max()).eq(45);
expect($$(c).unique()).same([6,1,45,9,5,4,22,3]);
expect($$([1, 2, 1, 3, 1, 4]).unique()).same([2,3,1,4]);
var d =['frank', ['bob', 'lisa'], ['jill', ['tom', 'sally']]];
expect($$(d).flatten()).same(['frank', 'bob', 'lisa', 'jill', 'tom', 'sally']);
var e = ['hello', 'world', 'this', 'is', 'nice'];
expect($$(e).pluck("length")).same([5, 5, 4, 2, 4]);
expect($$(e).sortBy(function(s) {
return s.length;
})).same(["is","this","nice","hello","world"]);
var f = [0,1,2,9];
var g = [0,5,2];
expect($$(f).diff(g)).same([1,9]);
var h = [1,2,3];
h = $$(h).union([2,3,4,5,6]);//取并集
expect(h).same([1,2,3,4,5,6]);
var j = [1, 2, 3, "a"];
j = $$(j).intersect([1, "a", 2]);//取交集
expect(j).same([1, 2, "a"]);
},
"Number2" : function(){
var a = [];
$$(8).downto(4, function(i) {
a.push(i);
});
expect(a).same([8,7,6,5,4]);
expect($$(4.444).round(1)).eq(4.4);
expect($$(4.444).round(2)).eq(4.44);
expect($$(4.444).round(3)).eq(4.444);
expect($$(7).constrain(3,5)).eq(5);
expect($$(4).constrain(3,5)).eq(4);
expect($$(4).nearer(3,9)).eq(3);
expect($$(454).nearer(-4543,6576)).eq(-4543);
},
"Object2":function(){
var a = {
a:"one",
b:"two",
c:"three"
};
expect($$(a).subset(["a","c"])).same({
a: 'one',
c: 'three'
});
a = {
first: 'Sunday',
second: 'Monday',
third: 'Tuesday'
};
var b = [];
$$(a).forEach(function(value,key){
b.push(value);
});
expect(b).same(["Sunday","Monday","Tuesday"]);
a = {
e:1,
b:"aaa",
c:[1,2,3],
d:{
bb:"bb"
}
};
expect($$(a).clone()).same(a);
var obj1 = {
a: 0,
b: 1
};
var obj2 = {
c: 2,
d: 3
};
var obj3 = {
a: 4,
d: 5
};
var merged = $$(obj1).merge(obj2, obj3);
expect(obj1).same(merged);
var nestedObj1 = {
a: {
b: 1,
c: 1
}
};
var nestedObj2 = {
a: {
b: 2
}
};
var nested = $$(nestedObj1).merge(nestedObj2);
expect(nested).same({
a: {
b: 2,
c: 1
}
});
a = {
a:1,
b:2,
c:3
};
expect($$(a).without("a")).same({
b:2,
c:3
});
}
});
});
相关链接
机器瞎学/数据掩埋/模式混淆/人工智障/深度遗忘/神经掉线/计算机幻觉/专注单身二十五年
浙公网安备 33010602011771号