diff --git a/.gitignore b/.gitignore
index 12e1b62..0b88317 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
node_modules
.DS_Store
-.project
\ No newline at end of file
+.project
+*.log
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index 12e1b62..0b88317 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
node_modules
.DS_Store
-.project
\ No newline at end of file
+.project
+*.log
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..63e4d7c
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,8 @@
+language: node_js
+node_js:
+ - 0.10
+
+before_script:
+ - npm install -g grunt-cli
+ - export DISPLAY=:99.0
+ - sh -e /etc/init.d/xvfb start
diff --git a/.gitignore b/.gitignore
index 12e1b62..0b88317 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
node_modules
.DS_Store
-.project
\ No newline at end of file
+.project
+*.log
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..63e4d7c
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,8 @@
+language: node_js
+node_js:
+ - 0.10
+
+before_script:
+ - npm install -g grunt-cli
+ - export DISPLAY=:99.0
+ - sh -e /etc/init.d/xvfb start
diff --git a/Gruntfile.js b/Gruntfile.js
index b083b49..103938c 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -1,10 +1,12 @@
+'use strict';
+
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-connect');
- grunt.loadNpmTasks('grunt-contrib-qunit');
grunt.loadNpmTasks('grunt-contrib-yuidoc');
+ grunt.loadTasks('tasks');
var root = 'src/pixi/',
debug = 'bin/pixi.dev.js',
@@ -79,7 +81,7 @@
},
files: {
srcBlob: '<%= dirs.src %>/**/*.js',
- testBlob: '<%= dirs.test %>/unit/**/*.js',
+ testBlob: '<%= dirs.test %>/{functional,lib/pixi,unit}/**/*.js',
build: '<%= dirs.build %>/pixi.dev.js',
buildMin: '<%= dirs.build %>/pixi.js'
},
@@ -94,7 +96,12 @@
},
jshint: {
beforeconcat: srcFiles,
- test: ['<%= files.testBlob %>'],
+ test: {
+ src: ['<%= files.testBlob %>'],
+ options: {
+ expr: true
+ }
+ },
options: {
asi: true,
smarttabs: true
@@ -128,12 +135,6 @@
]
},
connect: {
- qunit: {
- options: {
- port: grunt.option('port-test') || 9002,
- base: './'
- }
- },
test: {
options: {
port: grunt.option('port-test') || 9002,
@@ -142,13 +143,6 @@
}
}
},
- qunit: {
- all: {
- options: {
- urls: ['http://localhost:' + (grunt.option('port-test') || 9002) + '/test/index.html']
- }
- }
- },
yuidoc: {
compile: {
name: '<%= pkg.name %>',
@@ -161,6 +155,13 @@
outdir: '<%= dirs.docs %>'
}
}
+ },
+ karma: {
+ unit: {
+ configFile: 'test/karma.conf.js',
+ // browsers: ['Chrome'],
+ singleRun: true
+ }
}
});
@@ -182,9 +183,10 @@
}
)
- grunt.registerTask('default', ['concat', 'uglify', 'distribute']);
grunt.registerTask('build', ['concat', 'uglify', 'distribute']);
- grunt.registerTask('test', ['build', 'connect:qunit', 'qunit']);
+ grunt.registerTask('test', ['concat', 'jshint:test', 'karma']);
grunt.registerTask('docs', ['yuidoc']);
-
-}
\ No newline at end of file
+ grunt.registerTask('default', ['test', 'uglify', 'distribute']);
+ // Travis CI task.
+ grunt.registerTask('travis', ['test']);
+}
diff --git a/.gitignore b/.gitignore
index 12e1b62..0b88317 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
node_modules
.DS_Store
-.project
\ No newline at end of file
+.project
+*.log
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..63e4d7c
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,8 @@
+language: node_js
+node_js:
+ - 0.10
+
+before_script:
+ - npm install -g grunt-cli
+ - export DISPLAY=:99.0
+ - sh -e /etc/init.d/xvfb start
diff --git a/Gruntfile.js b/Gruntfile.js
index b083b49..103938c 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -1,10 +1,12 @@
+'use strict';
+
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-connect');
- grunt.loadNpmTasks('grunt-contrib-qunit');
grunt.loadNpmTasks('grunt-contrib-yuidoc');
+ grunt.loadTasks('tasks');
var root = 'src/pixi/',
debug = 'bin/pixi.dev.js',
@@ -79,7 +81,7 @@
},
files: {
srcBlob: '<%= dirs.src %>/**/*.js',
- testBlob: '<%= dirs.test %>/unit/**/*.js',
+ testBlob: '<%= dirs.test %>/{functional,lib/pixi,unit}/**/*.js',
build: '<%= dirs.build %>/pixi.dev.js',
buildMin: '<%= dirs.build %>/pixi.js'
},
@@ -94,7 +96,12 @@
},
jshint: {
beforeconcat: srcFiles,
- test: ['<%= files.testBlob %>'],
+ test: {
+ src: ['<%= files.testBlob %>'],
+ options: {
+ expr: true
+ }
+ },
options: {
asi: true,
smarttabs: true
@@ -128,12 +135,6 @@
]
},
connect: {
- qunit: {
- options: {
- port: grunt.option('port-test') || 9002,
- base: './'
- }
- },
test: {
options: {
port: grunt.option('port-test') || 9002,
@@ -142,13 +143,6 @@
}
}
},
- qunit: {
- all: {
- options: {
- urls: ['http://localhost:' + (grunt.option('port-test') || 9002) + '/test/index.html']
- }
- }
- },
yuidoc: {
compile: {
name: '<%= pkg.name %>',
@@ -161,6 +155,13 @@
outdir: '<%= dirs.docs %>'
}
}
+ },
+ karma: {
+ unit: {
+ configFile: 'test/karma.conf.js',
+ // browsers: ['Chrome'],
+ singleRun: true
+ }
}
});
@@ -182,9 +183,10 @@
}
)
- grunt.registerTask('default', ['concat', 'uglify', 'distribute']);
grunt.registerTask('build', ['concat', 'uglify', 'distribute']);
- grunt.registerTask('test', ['build', 'connect:qunit', 'qunit']);
+ grunt.registerTask('test', ['concat', 'jshint:test', 'karma']);
grunt.registerTask('docs', ['yuidoc']);
-
-}
\ No newline at end of file
+ grunt.registerTask('default', ['test', 'uglify', 'distribute']);
+ // Travis CI task.
+ grunt.registerTask('travis', ['test']);
+}
diff --git a/README.md b/README.md
index c62ef86..690cfe4 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,8 @@

+[](http://travis-ci.org/drkibitz/pixi.js)
+
#### JavaScript 2D Renderer ####
The aim of this project is to provide a fast lightweight 2D library that works
diff --git a/.gitignore b/.gitignore
index 12e1b62..0b88317 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
node_modules
.DS_Store
-.project
\ No newline at end of file
+.project
+*.log
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..63e4d7c
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,8 @@
+language: node_js
+node_js:
+ - 0.10
+
+before_script:
+ - npm install -g grunt-cli
+ - export DISPLAY=:99.0
+ - sh -e /etc/init.d/xvfb start
diff --git a/Gruntfile.js b/Gruntfile.js
index b083b49..103938c 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -1,10 +1,12 @@
+'use strict';
+
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-connect');
- grunt.loadNpmTasks('grunt-contrib-qunit');
grunt.loadNpmTasks('grunt-contrib-yuidoc');
+ grunt.loadTasks('tasks');
var root = 'src/pixi/',
debug = 'bin/pixi.dev.js',
@@ -79,7 +81,7 @@
},
files: {
srcBlob: '<%= dirs.src %>/**/*.js',
- testBlob: '<%= dirs.test %>/unit/**/*.js',
+ testBlob: '<%= dirs.test %>/{functional,lib/pixi,unit}/**/*.js',
build: '<%= dirs.build %>/pixi.dev.js',
buildMin: '<%= dirs.build %>/pixi.js'
},
@@ -94,7 +96,12 @@
},
jshint: {
beforeconcat: srcFiles,
- test: ['<%= files.testBlob %>'],
+ test: {
+ src: ['<%= files.testBlob %>'],
+ options: {
+ expr: true
+ }
+ },
options: {
asi: true,
smarttabs: true
@@ -128,12 +135,6 @@
]
},
connect: {
- qunit: {
- options: {
- port: grunt.option('port-test') || 9002,
- base: './'
- }
- },
test: {
options: {
port: grunt.option('port-test') || 9002,
@@ -142,13 +143,6 @@
}
}
},
- qunit: {
- all: {
- options: {
- urls: ['http://localhost:' + (grunt.option('port-test') || 9002) + '/test/index.html']
- }
- }
- },
yuidoc: {
compile: {
name: '<%= pkg.name %>',
@@ -161,6 +155,13 @@
outdir: '<%= dirs.docs %>'
}
}
+ },
+ karma: {
+ unit: {
+ configFile: 'test/karma.conf.js',
+ // browsers: ['Chrome'],
+ singleRun: true
+ }
}
});
@@ -182,9 +183,10 @@
}
)
- grunt.registerTask('default', ['concat', 'uglify', 'distribute']);
grunt.registerTask('build', ['concat', 'uglify', 'distribute']);
- grunt.registerTask('test', ['build', 'connect:qunit', 'qunit']);
+ grunt.registerTask('test', ['concat', 'jshint:test', 'karma']);
grunt.registerTask('docs', ['yuidoc']);
-
-}
\ No newline at end of file
+ grunt.registerTask('default', ['test', 'uglify', 'distribute']);
+ // Travis CI task.
+ grunt.registerTask('travis', ['test']);
+}
diff --git a/README.md b/README.md
index c62ef86..690cfe4 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,8 @@

+[](http://travis-ci.org/drkibitz/pixi.js)
+
#### JavaScript 2D Renderer ####
The aim of this project is to provide a fast lightweight 2D library that works
diff --git a/package.json b/package.json
index b373240..1246a68 100644
--- a/package.json
+++ b/package.json
@@ -18,14 +18,21 @@
"main": "bin/pixi.js",
+ "scripts": {
+ "test": "grunt travis --verbose"
+ },
+
"dependencies": {},
"devDependencies": {
"grunt": "~0.4.x",
- "grunt-contrib-jshint": "0.3.x",
+ "grunt-contrib-jshint": "0.6.x",
"grunt-contrib-uglify": "0.2.x",
- "grunt-contrib-connect": "0.2.x",
- "grunt-contrib-qunit": "0.2.x",
+ "grunt-contrib-connect": "0.3.x",
"grunt-contrib-yuidoc": "0.4.x",
- "grunt-contrib-concat": "0.1.x"
+ "grunt-contrib-concat": "0.3.x",
+ "chai": "~1.7.0",
+ "karma": "0.11.0",
+ "karma-firefox-launcher": "0.1.0",
+ "karma-mocha": "0.1.0"
}
}
diff --git a/.gitignore b/.gitignore
index 12e1b62..0b88317 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
node_modules
.DS_Store
-.project
\ No newline at end of file
+.project
+*.log
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..63e4d7c
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,8 @@
+language: node_js
+node_js:
+ - 0.10
+
+before_script:
+ - npm install -g grunt-cli
+ - export DISPLAY=:99.0
+ - sh -e /etc/init.d/xvfb start
diff --git a/Gruntfile.js b/Gruntfile.js
index b083b49..103938c 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -1,10 +1,12 @@
+'use strict';
+
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-connect');
- grunt.loadNpmTasks('grunt-contrib-qunit');
grunt.loadNpmTasks('grunt-contrib-yuidoc');
+ grunt.loadTasks('tasks');
var root = 'src/pixi/',
debug = 'bin/pixi.dev.js',
@@ -79,7 +81,7 @@
},
files: {
srcBlob: '<%= dirs.src %>/**/*.js',
- testBlob: '<%= dirs.test %>/unit/**/*.js',
+ testBlob: '<%= dirs.test %>/{functional,lib/pixi,unit}/**/*.js',
build: '<%= dirs.build %>/pixi.dev.js',
buildMin: '<%= dirs.build %>/pixi.js'
},
@@ -94,7 +96,12 @@
},
jshint: {
beforeconcat: srcFiles,
- test: ['<%= files.testBlob %>'],
+ test: {
+ src: ['<%= files.testBlob %>'],
+ options: {
+ expr: true
+ }
+ },
options: {
asi: true,
smarttabs: true
@@ -128,12 +135,6 @@
]
},
connect: {
- qunit: {
- options: {
- port: grunt.option('port-test') || 9002,
- base: './'
- }
- },
test: {
options: {
port: grunt.option('port-test') || 9002,
@@ -142,13 +143,6 @@
}
}
},
- qunit: {
- all: {
- options: {
- urls: ['http://localhost:' + (grunt.option('port-test') || 9002) + '/test/index.html']
- }
- }
- },
yuidoc: {
compile: {
name: '<%= pkg.name %>',
@@ -161,6 +155,13 @@
outdir: '<%= dirs.docs %>'
}
}
+ },
+ karma: {
+ unit: {
+ configFile: 'test/karma.conf.js',
+ // browsers: ['Chrome'],
+ singleRun: true
+ }
}
});
@@ -182,9 +183,10 @@
}
)
- grunt.registerTask('default', ['concat', 'uglify', 'distribute']);
grunt.registerTask('build', ['concat', 'uglify', 'distribute']);
- grunt.registerTask('test', ['build', 'connect:qunit', 'qunit']);
+ grunt.registerTask('test', ['concat', 'jshint:test', 'karma']);
grunt.registerTask('docs', ['yuidoc']);
-
-}
\ No newline at end of file
+ grunt.registerTask('default', ['test', 'uglify', 'distribute']);
+ // Travis CI task.
+ grunt.registerTask('travis', ['test']);
+}
diff --git a/README.md b/README.md
index c62ef86..690cfe4 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,8 @@

+[](http://travis-ci.org/drkibitz/pixi.js)
+
#### JavaScript 2D Renderer ####
The aim of this project is to provide a fast lightweight 2D library that works
diff --git a/package.json b/package.json
index b373240..1246a68 100644
--- a/package.json
+++ b/package.json
@@ -18,14 +18,21 @@
"main": "bin/pixi.js",
+ "scripts": {
+ "test": "grunt travis --verbose"
+ },
+
"dependencies": {},
"devDependencies": {
"grunt": "~0.4.x",
- "grunt-contrib-jshint": "0.3.x",
+ "grunt-contrib-jshint": "0.6.x",
"grunt-contrib-uglify": "0.2.x",
- "grunt-contrib-connect": "0.2.x",
- "grunt-contrib-qunit": "0.2.x",
+ "grunt-contrib-connect": "0.3.x",
"grunt-contrib-yuidoc": "0.4.x",
- "grunt-contrib-concat": "0.1.x"
+ "grunt-contrib-concat": "0.3.x",
+ "chai": "~1.7.0",
+ "karma": "0.11.0",
+ "karma-firefox-launcher": "0.1.0",
+ "karma-mocha": "0.1.0"
}
}
diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js
index a7c520e..ee82bbd 100644
--- a/src/pixi/InteractionManager.js
+++ b/src/pixi/InteractionManager.js
@@ -62,7 +62,6 @@
this.onTouchEnd = this.onTouchEnd.bind(this);
this.onTouchMove = this.onTouchMove.bind(this);
-
this.last = 0;
}
diff --git a/.gitignore b/.gitignore
index 12e1b62..0b88317 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
node_modules
.DS_Store
-.project
\ No newline at end of file
+.project
+*.log
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..63e4d7c
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,8 @@
+language: node_js
+node_js:
+ - 0.10
+
+before_script:
+ - npm install -g grunt-cli
+ - export DISPLAY=:99.0
+ - sh -e /etc/init.d/xvfb start
diff --git a/Gruntfile.js b/Gruntfile.js
index b083b49..103938c 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -1,10 +1,12 @@
+'use strict';
+
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-connect');
- grunt.loadNpmTasks('grunt-contrib-qunit');
grunt.loadNpmTasks('grunt-contrib-yuidoc');
+ grunt.loadTasks('tasks');
var root = 'src/pixi/',
debug = 'bin/pixi.dev.js',
@@ -79,7 +81,7 @@
},
files: {
srcBlob: '<%= dirs.src %>/**/*.js',
- testBlob: '<%= dirs.test %>/unit/**/*.js',
+ testBlob: '<%= dirs.test %>/{functional,lib/pixi,unit}/**/*.js',
build: '<%= dirs.build %>/pixi.dev.js',
buildMin: '<%= dirs.build %>/pixi.js'
},
@@ -94,7 +96,12 @@
},
jshint: {
beforeconcat: srcFiles,
- test: ['<%= files.testBlob %>'],
+ test: {
+ src: ['<%= files.testBlob %>'],
+ options: {
+ expr: true
+ }
+ },
options: {
asi: true,
smarttabs: true
@@ -128,12 +135,6 @@
]
},
connect: {
- qunit: {
- options: {
- port: grunt.option('port-test') || 9002,
- base: './'
- }
- },
test: {
options: {
port: grunt.option('port-test') || 9002,
@@ -142,13 +143,6 @@
}
}
},
- qunit: {
- all: {
- options: {
- urls: ['http://localhost:' + (grunt.option('port-test') || 9002) + '/test/index.html']
- }
- }
- },
yuidoc: {
compile: {
name: '<%= pkg.name %>',
@@ -161,6 +155,13 @@
outdir: '<%= dirs.docs %>'
}
}
+ },
+ karma: {
+ unit: {
+ configFile: 'test/karma.conf.js',
+ // browsers: ['Chrome'],
+ singleRun: true
+ }
}
});
@@ -182,9 +183,10 @@
}
)
- grunt.registerTask('default', ['concat', 'uglify', 'distribute']);
grunt.registerTask('build', ['concat', 'uglify', 'distribute']);
- grunt.registerTask('test', ['build', 'connect:qunit', 'qunit']);
+ grunt.registerTask('test', ['concat', 'jshint:test', 'karma']);
grunt.registerTask('docs', ['yuidoc']);
-
-}
\ No newline at end of file
+ grunt.registerTask('default', ['test', 'uglify', 'distribute']);
+ // Travis CI task.
+ grunt.registerTask('travis', ['test']);
+}
diff --git a/README.md b/README.md
index c62ef86..690cfe4 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,8 @@

+[](http://travis-ci.org/drkibitz/pixi.js)
+
#### JavaScript 2D Renderer ####
The aim of this project is to provide a fast lightweight 2D library that works
diff --git a/package.json b/package.json
index b373240..1246a68 100644
--- a/package.json
+++ b/package.json
@@ -18,14 +18,21 @@
"main": "bin/pixi.js",
+ "scripts": {
+ "test": "grunt travis --verbose"
+ },
+
"dependencies": {},
"devDependencies": {
"grunt": "~0.4.x",
- "grunt-contrib-jshint": "0.3.x",
+ "grunt-contrib-jshint": "0.6.x",
"grunt-contrib-uglify": "0.2.x",
- "grunt-contrib-connect": "0.2.x",
- "grunt-contrib-qunit": "0.2.x",
+ "grunt-contrib-connect": "0.3.x",
"grunt-contrib-yuidoc": "0.4.x",
- "grunt-contrib-concat": "0.1.x"
+ "grunt-contrib-concat": "0.3.x",
+ "chai": "~1.7.0",
+ "karma": "0.11.0",
+ "karma-firefox-launcher": "0.1.0",
+ "karma-mocha": "0.1.0"
}
}
diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js
index a7c520e..ee82bbd 100644
--- a/src/pixi/InteractionManager.js
+++ b/src/pixi/InteractionManager.js
@@ -62,7 +62,6 @@
this.onTouchEnd = this.onTouchEnd.bind(this);
this.onTouchMove = this.onTouchMove.bind(this);
-
this.last = 0;
}
diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js
index 1a95d20..eef1059 100644
--- a/src/pixi/core/Ellipse.js
+++ b/src/pixi/core/Ellipse.js
@@ -78,7 +78,7 @@
return (normx + normy < 0.25);
}
-PIXI.Ellipse.getBounds = function()
+PIXI.Ellipse.prototype.getBounds = function()
{
return new PIXI.Rectangle(this.x, this.y, this.width, this.height);
}
diff --git a/.gitignore b/.gitignore
index 12e1b62..0b88317 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
node_modules
.DS_Store
-.project
\ No newline at end of file
+.project
+*.log
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..63e4d7c
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,8 @@
+language: node_js
+node_js:
+ - 0.10
+
+before_script:
+ - npm install -g grunt-cli
+ - export DISPLAY=:99.0
+ - sh -e /etc/init.d/xvfb start
diff --git a/Gruntfile.js b/Gruntfile.js
index b083b49..103938c 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -1,10 +1,12 @@
+'use strict';
+
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-connect');
- grunt.loadNpmTasks('grunt-contrib-qunit');
grunt.loadNpmTasks('grunt-contrib-yuidoc');
+ grunt.loadTasks('tasks');
var root = 'src/pixi/',
debug = 'bin/pixi.dev.js',
@@ -79,7 +81,7 @@
},
files: {
srcBlob: '<%= dirs.src %>/**/*.js',
- testBlob: '<%= dirs.test %>/unit/**/*.js',
+ testBlob: '<%= dirs.test %>/{functional,lib/pixi,unit}/**/*.js',
build: '<%= dirs.build %>/pixi.dev.js',
buildMin: '<%= dirs.build %>/pixi.js'
},
@@ -94,7 +96,12 @@
},
jshint: {
beforeconcat: srcFiles,
- test: ['<%= files.testBlob %>'],
+ test: {
+ src: ['<%= files.testBlob %>'],
+ options: {
+ expr: true
+ }
+ },
options: {
asi: true,
smarttabs: true
@@ -128,12 +135,6 @@
]
},
connect: {
- qunit: {
- options: {
- port: grunt.option('port-test') || 9002,
- base: './'
- }
- },
test: {
options: {
port: grunt.option('port-test') || 9002,
@@ -142,13 +143,6 @@
}
}
},
- qunit: {
- all: {
- options: {
- urls: ['http://localhost:' + (grunt.option('port-test') || 9002) + '/test/index.html']
- }
- }
- },
yuidoc: {
compile: {
name: '<%= pkg.name %>',
@@ -161,6 +155,13 @@
outdir: '<%= dirs.docs %>'
}
}
+ },
+ karma: {
+ unit: {
+ configFile: 'test/karma.conf.js',
+ // browsers: ['Chrome'],
+ singleRun: true
+ }
}
});
@@ -182,9 +183,10 @@
}
)
- grunt.registerTask('default', ['concat', 'uglify', 'distribute']);
grunt.registerTask('build', ['concat', 'uglify', 'distribute']);
- grunt.registerTask('test', ['build', 'connect:qunit', 'qunit']);
+ grunt.registerTask('test', ['concat', 'jshint:test', 'karma']);
grunt.registerTask('docs', ['yuidoc']);
-
-}
\ No newline at end of file
+ grunt.registerTask('default', ['test', 'uglify', 'distribute']);
+ // Travis CI task.
+ grunt.registerTask('travis', ['test']);
+}
diff --git a/README.md b/README.md
index c62ef86..690cfe4 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,8 @@

+[](http://travis-ci.org/drkibitz/pixi.js)
+
#### JavaScript 2D Renderer ####
The aim of this project is to provide a fast lightweight 2D library that works
diff --git a/package.json b/package.json
index b373240..1246a68 100644
--- a/package.json
+++ b/package.json
@@ -18,14 +18,21 @@
"main": "bin/pixi.js",
+ "scripts": {
+ "test": "grunt travis --verbose"
+ },
+
"dependencies": {},
"devDependencies": {
"grunt": "~0.4.x",
- "grunt-contrib-jshint": "0.3.x",
+ "grunt-contrib-jshint": "0.6.x",
"grunt-contrib-uglify": "0.2.x",
- "grunt-contrib-connect": "0.2.x",
- "grunt-contrib-qunit": "0.2.x",
+ "grunt-contrib-connect": "0.3.x",
"grunt-contrib-yuidoc": "0.4.x",
- "grunt-contrib-concat": "0.1.x"
+ "grunt-contrib-concat": "0.3.x",
+ "chai": "~1.7.0",
+ "karma": "0.11.0",
+ "karma-firefox-launcher": "0.1.0",
+ "karma-mocha": "0.1.0"
}
}
diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js
index a7c520e..ee82bbd 100644
--- a/src/pixi/InteractionManager.js
+++ b/src/pixi/InteractionManager.js
@@ -62,7 +62,6 @@
this.onTouchEnd = this.onTouchEnd.bind(this);
this.onTouchMove = this.onTouchMove.bind(this);
-
this.last = 0;
}
diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js
index 1a95d20..eef1059 100644
--- a/src/pixi/core/Ellipse.js
+++ b/src/pixi/core/Ellipse.js
@@ -78,7 +78,7 @@
return (normx + normy < 0.25);
}
-PIXI.Ellipse.getBounds = function()
+PIXI.Ellipse.prototype.getBounds = function()
{
return new PIXI.Rectangle(this.x, this.y, this.width, this.height);
}
diff --git a/tasks/karma.js b/tasks/karma.js
new file mode 100644
index 0000000..c340485
--- /dev/null
+++ b/tasks/karma.js
@@ -0,0 +1,27 @@
+'use strict';
+
+var path = require('path');
+var server = require('karma').server;
+
+module.exports = function (grunt) {
+ grunt.registerMultiTask('karma', 'run karma.', function() {
+ var done = this.async();
+ var options = this.options({
+ background: false
+ });
+ var data = this.data;
+
+ //merge options onto data, with data taking precedence
+ data = grunt.util._.merge(options, data);
+ data.configFile = path.resolve(data.configFile);
+ if (data.configFile) {
+ data.configFile = grunt.template.process(data.configFile);
+ }
+
+ server.start(
+ data,
+ function(code) {
+ done(!code);
+ });
+ });
+};
diff --git a/.gitignore b/.gitignore
index 12e1b62..0b88317 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
node_modules
.DS_Store
-.project
\ No newline at end of file
+.project
+*.log
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..63e4d7c
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,8 @@
+language: node_js
+node_js:
+ - 0.10
+
+before_script:
+ - npm install -g grunt-cli
+ - export DISPLAY=:99.0
+ - sh -e /etc/init.d/xvfb start
diff --git a/Gruntfile.js b/Gruntfile.js
index b083b49..103938c 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -1,10 +1,12 @@
+'use strict';
+
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-connect');
- grunt.loadNpmTasks('grunt-contrib-qunit');
grunt.loadNpmTasks('grunt-contrib-yuidoc');
+ grunt.loadTasks('tasks');
var root = 'src/pixi/',
debug = 'bin/pixi.dev.js',
@@ -79,7 +81,7 @@
},
files: {
srcBlob: '<%= dirs.src %>/**/*.js',
- testBlob: '<%= dirs.test %>/unit/**/*.js',
+ testBlob: '<%= dirs.test %>/{functional,lib/pixi,unit}/**/*.js',
build: '<%= dirs.build %>/pixi.dev.js',
buildMin: '<%= dirs.build %>/pixi.js'
},
@@ -94,7 +96,12 @@
},
jshint: {
beforeconcat: srcFiles,
- test: ['<%= files.testBlob %>'],
+ test: {
+ src: ['<%= files.testBlob %>'],
+ options: {
+ expr: true
+ }
+ },
options: {
asi: true,
smarttabs: true
@@ -128,12 +135,6 @@
]
},
connect: {
- qunit: {
- options: {
- port: grunt.option('port-test') || 9002,
- base: './'
- }
- },
test: {
options: {
port: grunt.option('port-test') || 9002,
@@ -142,13 +143,6 @@
}
}
},
- qunit: {
- all: {
- options: {
- urls: ['http://localhost:' + (grunt.option('port-test') || 9002) + '/test/index.html']
- }
- }
- },
yuidoc: {
compile: {
name: '<%= pkg.name %>',
@@ -161,6 +155,13 @@
outdir: '<%= dirs.docs %>'
}
}
+ },
+ karma: {
+ unit: {
+ configFile: 'test/karma.conf.js',
+ // browsers: ['Chrome'],
+ singleRun: true
+ }
}
});
@@ -182,9 +183,10 @@
}
)
- grunt.registerTask('default', ['concat', 'uglify', 'distribute']);
grunt.registerTask('build', ['concat', 'uglify', 'distribute']);
- grunt.registerTask('test', ['build', 'connect:qunit', 'qunit']);
+ grunt.registerTask('test', ['concat', 'jshint:test', 'karma']);
grunt.registerTask('docs', ['yuidoc']);
-
-}
\ No newline at end of file
+ grunt.registerTask('default', ['test', 'uglify', 'distribute']);
+ // Travis CI task.
+ grunt.registerTask('travis', ['test']);
+}
diff --git a/README.md b/README.md
index c62ef86..690cfe4 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,8 @@

+[](http://travis-ci.org/drkibitz/pixi.js)
+
#### JavaScript 2D Renderer ####
The aim of this project is to provide a fast lightweight 2D library that works
diff --git a/package.json b/package.json
index b373240..1246a68 100644
--- a/package.json
+++ b/package.json
@@ -18,14 +18,21 @@
"main": "bin/pixi.js",
+ "scripts": {
+ "test": "grunt travis --verbose"
+ },
+
"dependencies": {},
"devDependencies": {
"grunt": "~0.4.x",
- "grunt-contrib-jshint": "0.3.x",
+ "grunt-contrib-jshint": "0.6.x",
"grunt-contrib-uglify": "0.2.x",
- "grunt-contrib-connect": "0.2.x",
- "grunt-contrib-qunit": "0.2.x",
+ "grunt-contrib-connect": "0.3.x",
"grunt-contrib-yuidoc": "0.4.x",
- "grunt-contrib-concat": "0.1.x"
+ "grunt-contrib-concat": "0.3.x",
+ "chai": "~1.7.0",
+ "karma": "0.11.0",
+ "karma-firefox-launcher": "0.1.0",
+ "karma-mocha": "0.1.0"
}
}
diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js
index a7c520e..ee82bbd 100644
--- a/src/pixi/InteractionManager.js
+++ b/src/pixi/InteractionManager.js
@@ -62,7 +62,6 @@
this.onTouchEnd = this.onTouchEnd.bind(this);
this.onTouchMove = this.onTouchMove.bind(this);
-
this.last = 0;
}
diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js
index 1a95d20..eef1059 100644
--- a/src/pixi/core/Ellipse.js
+++ b/src/pixi/core/Ellipse.js
@@ -78,7 +78,7 @@
return (normx + normy < 0.25);
}
-PIXI.Ellipse.getBounds = function()
+PIXI.Ellipse.prototype.getBounds = function()
{
return new PIXI.Rectangle(this.x, this.y, this.width, this.height);
}
diff --git a/tasks/karma.js b/tasks/karma.js
new file mode 100644
index 0000000..c340485
--- /dev/null
+++ b/tasks/karma.js
@@ -0,0 +1,27 @@
+'use strict';
+
+var path = require('path');
+var server = require('karma').server;
+
+module.exports = function (grunt) {
+ grunt.registerMultiTask('karma', 'run karma.', function() {
+ var done = this.async();
+ var options = this.options({
+ background: false
+ });
+ var data = this.data;
+
+ //merge options onto data, with data taking precedence
+ data = grunt.util._.merge(options, data);
+ data.configFile = path.resolve(data.configFile);
+ if (data.configFile) {
+ data.configFile = grunt.template.process(data.configFile);
+ }
+
+ server.start(
+ data,
+ function(code) {
+ done(!code);
+ });
+ });
+};
diff --git a/test/functional/example-1-basics/bunny.png b/test/functional/example-1-basics/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/functional/example-1-basics/bunny.png
Binary files differ
diff --git a/.gitignore b/.gitignore
index 12e1b62..0b88317 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
node_modules
.DS_Store
-.project
\ No newline at end of file
+.project
+*.log
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..63e4d7c
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,8 @@
+language: node_js
+node_js:
+ - 0.10
+
+before_script:
+ - npm install -g grunt-cli
+ - export DISPLAY=:99.0
+ - sh -e /etc/init.d/xvfb start
diff --git a/Gruntfile.js b/Gruntfile.js
index b083b49..103938c 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -1,10 +1,12 @@
+'use strict';
+
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-connect');
- grunt.loadNpmTasks('grunt-contrib-qunit');
grunt.loadNpmTasks('grunt-contrib-yuidoc');
+ grunt.loadTasks('tasks');
var root = 'src/pixi/',
debug = 'bin/pixi.dev.js',
@@ -79,7 +81,7 @@
},
files: {
srcBlob: '<%= dirs.src %>/**/*.js',
- testBlob: '<%= dirs.test %>/unit/**/*.js',
+ testBlob: '<%= dirs.test %>/{functional,lib/pixi,unit}/**/*.js',
build: '<%= dirs.build %>/pixi.dev.js',
buildMin: '<%= dirs.build %>/pixi.js'
},
@@ -94,7 +96,12 @@
},
jshint: {
beforeconcat: srcFiles,
- test: ['<%= files.testBlob %>'],
+ test: {
+ src: ['<%= files.testBlob %>'],
+ options: {
+ expr: true
+ }
+ },
options: {
asi: true,
smarttabs: true
@@ -128,12 +135,6 @@
]
},
connect: {
- qunit: {
- options: {
- port: grunt.option('port-test') || 9002,
- base: './'
- }
- },
test: {
options: {
port: grunt.option('port-test') || 9002,
@@ -142,13 +143,6 @@
}
}
},
- qunit: {
- all: {
- options: {
- urls: ['http://localhost:' + (grunt.option('port-test') || 9002) + '/test/index.html']
- }
- }
- },
yuidoc: {
compile: {
name: '<%= pkg.name %>',
@@ -161,6 +155,13 @@
outdir: '<%= dirs.docs %>'
}
}
+ },
+ karma: {
+ unit: {
+ configFile: 'test/karma.conf.js',
+ // browsers: ['Chrome'],
+ singleRun: true
+ }
}
});
@@ -182,9 +183,10 @@
}
)
- grunt.registerTask('default', ['concat', 'uglify', 'distribute']);
grunt.registerTask('build', ['concat', 'uglify', 'distribute']);
- grunt.registerTask('test', ['build', 'connect:qunit', 'qunit']);
+ grunt.registerTask('test', ['concat', 'jshint:test', 'karma']);
grunt.registerTask('docs', ['yuidoc']);
-
-}
\ No newline at end of file
+ grunt.registerTask('default', ['test', 'uglify', 'distribute']);
+ // Travis CI task.
+ grunt.registerTask('travis', ['test']);
+}
diff --git a/README.md b/README.md
index c62ef86..690cfe4 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,8 @@

+[](http://travis-ci.org/drkibitz/pixi.js)
+
#### JavaScript 2D Renderer ####
The aim of this project is to provide a fast lightweight 2D library that works
diff --git a/package.json b/package.json
index b373240..1246a68 100644
--- a/package.json
+++ b/package.json
@@ -18,14 +18,21 @@
"main": "bin/pixi.js",
+ "scripts": {
+ "test": "grunt travis --verbose"
+ },
+
"dependencies": {},
"devDependencies": {
"grunt": "~0.4.x",
- "grunt-contrib-jshint": "0.3.x",
+ "grunt-contrib-jshint": "0.6.x",
"grunt-contrib-uglify": "0.2.x",
- "grunt-contrib-connect": "0.2.x",
- "grunt-contrib-qunit": "0.2.x",
+ "grunt-contrib-connect": "0.3.x",
"grunt-contrib-yuidoc": "0.4.x",
- "grunt-contrib-concat": "0.1.x"
+ "grunt-contrib-concat": "0.3.x",
+ "chai": "~1.7.0",
+ "karma": "0.11.0",
+ "karma-firefox-launcher": "0.1.0",
+ "karma-mocha": "0.1.0"
}
}
diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js
index a7c520e..ee82bbd 100644
--- a/src/pixi/InteractionManager.js
+++ b/src/pixi/InteractionManager.js
@@ -62,7 +62,6 @@
this.onTouchEnd = this.onTouchEnd.bind(this);
this.onTouchMove = this.onTouchMove.bind(this);
-
this.last = 0;
}
diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js
index 1a95d20..eef1059 100644
--- a/src/pixi/core/Ellipse.js
+++ b/src/pixi/core/Ellipse.js
@@ -78,7 +78,7 @@
return (normx + normy < 0.25);
}
-PIXI.Ellipse.getBounds = function()
+PIXI.Ellipse.prototype.getBounds = function()
{
return new PIXI.Rectangle(this.x, this.y, this.width, this.height);
}
diff --git a/tasks/karma.js b/tasks/karma.js
new file mode 100644
index 0000000..c340485
--- /dev/null
+++ b/tasks/karma.js
@@ -0,0 +1,27 @@
+'use strict';
+
+var path = require('path');
+var server = require('karma').server;
+
+module.exports = function (grunt) {
+ grunt.registerMultiTask('karma', 'run karma.', function() {
+ var done = this.async();
+ var options = this.options({
+ background: false
+ });
+ var data = this.data;
+
+ //merge options onto data, with data taking precedence
+ data = grunt.util._.merge(options, data);
+ data.configFile = path.resolve(data.configFile);
+ if (data.configFile) {
+ data.configFile = grunt.template.process(data.configFile);
+ }
+
+ server.start(
+ data,
+ function(code) {
+ done(!code);
+ });
+ });
+};
diff --git a/test/functional/example-1-basics/bunny.png b/test/functional/example-1-basics/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/functional/example-1-basics/bunny.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-30.png b/test/functional/example-1-basics/frame-30.png
new file mode 100644
index 0000000..96e3409
--- /dev/null
+++ b/test/functional/example-1-basics/frame-30.png
Binary files differ
diff --git a/.gitignore b/.gitignore
index 12e1b62..0b88317 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
node_modules
.DS_Store
-.project
\ No newline at end of file
+.project
+*.log
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..63e4d7c
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,8 @@
+language: node_js
+node_js:
+ - 0.10
+
+before_script:
+ - npm install -g grunt-cli
+ - export DISPLAY=:99.0
+ - sh -e /etc/init.d/xvfb start
diff --git a/Gruntfile.js b/Gruntfile.js
index b083b49..103938c 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -1,10 +1,12 @@
+'use strict';
+
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-connect');
- grunt.loadNpmTasks('grunt-contrib-qunit');
grunt.loadNpmTasks('grunt-contrib-yuidoc');
+ grunt.loadTasks('tasks');
var root = 'src/pixi/',
debug = 'bin/pixi.dev.js',
@@ -79,7 +81,7 @@
},
files: {
srcBlob: '<%= dirs.src %>/**/*.js',
- testBlob: '<%= dirs.test %>/unit/**/*.js',
+ testBlob: '<%= dirs.test %>/{functional,lib/pixi,unit}/**/*.js',
build: '<%= dirs.build %>/pixi.dev.js',
buildMin: '<%= dirs.build %>/pixi.js'
},
@@ -94,7 +96,12 @@
},
jshint: {
beforeconcat: srcFiles,
- test: ['<%= files.testBlob %>'],
+ test: {
+ src: ['<%= files.testBlob %>'],
+ options: {
+ expr: true
+ }
+ },
options: {
asi: true,
smarttabs: true
@@ -128,12 +135,6 @@
]
},
connect: {
- qunit: {
- options: {
- port: grunt.option('port-test') || 9002,
- base: './'
- }
- },
test: {
options: {
port: grunt.option('port-test') || 9002,
@@ -142,13 +143,6 @@
}
}
},
- qunit: {
- all: {
- options: {
- urls: ['http://localhost:' + (grunt.option('port-test') || 9002) + '/test/index.html']
- }
- }
- },
yuidoc: {
compile: {
name: '<%= pkg.name %>',
@@ -161,6 +155,13 @@
outdir: '<%= dirs.docs %>'
}
}
+ },
+ karma: {
+ unit: {
+ configFile: 'test/karma.conf.js',
+ // browsers: ['Chrome'],
+ singleRun: true
+ }
}
});
@@ -182,9 +183,10 @@
}
)
- grunt.registerTask('default', ['concat', 'uglify', 'distribute']);
grunt.registerTask('build', ['concat', 'uglify', 'distribute']);
- grunt.registerTask('test', ['build', 'connect:qunit', 'qunit']);
+ grunt.registerTask('test', ['concat', 'jshint:test', 'karma']);
grunt.registerTask('docs', ['yuidoc']);
-
-}
\ No newline at end of file
+ grunt.registerTask('default', ['test', 'uglify', 'distribute']);
+ // Travis CI task.
+ grunt.registerTask('travis', ['test']);
+}
diff --git a/README.md b/README.md
index c62ef86..690cfe4 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,8 @@

+[](http://travis-ci.org/drkibitz/pixi.js)
+
#### JavaScript 2D Renderer ####
The aim of this project is to provide a fast lightweight 2D library that works
diff --git a/package.json b/package.json
index b373240..1246a68 100644
--- a/package.json
+++ b/package.json
@@ -18,14 +18,21 @@
"main": "bin/pixi.js",
+ "scripts": {
+ "test": "grunt travis --verbose"
+ },
+
"dependencies": {},
"devDependencies": {
"grunt": "~0.4.x",
- "grunt-contrib-jshint": "0.3.x",
+ "grunt-contrib-jshint": "0.6.x",
"grunt-contrib-uglify": "0.2.x",
- "grunt-contrib-connect": "0.2.x",
- "grunt-contrib-qunit": "0.2.x",
+ "grunt-contrib-connect": "0.3.x",
"grunt-contrib-yuidoc": "0.4.x",
- "grunt-contrib-concat": "0.1.x"
+ "grunt-contrib-concat": "0.3.x",
+ "chai": "~1.7.0",
+ "karma": "0.11.0",
+ "karma-firefox-launcher": "0.1.0",
+ "karma-mocha": "0.1.0"
}
}
diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js
index a7c520e..ee82bbd 100644
--- a/src/pixi/InteractionManager.js
+++ b/src/pixi/InteractionManager.js
@@ -62,7 +62,6 @@
this.onTouchEnd = this.onTouchEnd.bind(this);
this.onTouchMove = this.onTouchMove.bind(this);
-
this.last = 0;
}
diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js
index 1a95d20..eef1059 100644
--- a/src/pixi/core/Ellipse.js
+++ b/src/pixi/core/Ellipse.js
@@ -78,7 +78,7 @@
return (normx + normy < 0.25);
}
-PIXI.Ellipse.getBounds = function()
+PIXI.Ellipse.prototype.getBounds = function()
{
return new PIXI.Rectangle(this.x, this.y, this.width, this.height);
}
diff --git a/tasks/karma.js b/tasks/karma.js
new file mode 100644
index 0000000..c340485
--- /dev/null
+++ b/tasks/karma.js
@@ -0,0 +1,27 @@
+'use strict';
+
+var path = require('path');
+var server = require('karma').server;
+
+module.exports = function (grunt) {
+ grunt.registerMultiTask('karma', 'run karma.', function() {
+ var done = this.async();
+ var options = this.options({
+ background: false
+ });
+ var data = this.data;
+
+ //merge options onto data, with data taking precedence
+ data = grunt.util._.merge(options, data);
+ data.configFile = path.resolve(data.configFile);
+ if (data.configFile) {
+ data.configFile = grunt.template.process(data.configFile);
+ }
+
+ server.start(
+ data,
+ function(code) {
+ done(!code);
+ });
+ });
+};
diff --git a/test/functional/example-1-basics/bunny.png b/test/functional/example-1-basics/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/functional/example-1-basics/bunny.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-30.png b/test/functional/example-1-basics/frame-30.png
new file mode 100644
index 0000000..96e3409
--- /dev/null
+++ b/test/functional/example-1-basics/frame-30.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-60.png b/test/functional/example-1-basics/frame-60.png
new file mode 100644
index 0000000..af3f4ce
--- /dev/null
+++ b/test/functional/example-1-basics/frame-60.png
Binary files differ
diff --git a/.gitignore b/.gitignore
index 12e1b62..0b88317 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
node_modules
.DS_Store
-.project
\ No newline at end of file
+.project
+*.log
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..63e4d7c
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,8 @@
+language: node_js
+node_js:
+ - 0.10
+
+before_script:
+ - npm install -g grunt-cli
+ - export DISPLAY=:99.0
+ - sh -e /etc/init.d/xvfb start
diff --git a/Gruntfile.js b/Gruntfile.js
index b083b49..103938c 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -1,10 +1,12 @@
+'use strict';
+
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-connect');
- grunt.loadNpmTasks('grunt-contrib-qunit');
grunt.loadNpmTasks('grunt-contrib-yuidoc');
+ grunt.loadTasks('tasks');
var root = 'src/pixi/',
debug = 'bin/pixi.dev.js',
@@ -79,7 +81,7 @@
},
files: {
srcBlob: '<%= dirs.src %>/**/*.js',
- testBlob: '<%= dirs.test %>/unit/**/*.js',
+ testBlob: '<%= dirs.test %>/{functional,lib/pixi,unit}/**/*.js',
build: '<%= dirs.build %>/pixi.dev.js',
buildMin: '<%= dirs.build %>/pixi.js'
},
@@ -94,7 +96,12 @@
},
jshint: {
beforeconcat: srcFiles,
- test: ['<%= files.testBlob %>'],
+ test: {
+ src: ['<%= files.testBlob %>'],
+ options: {
+ expr: true
+ }
+ },
options: {
asi: true,
smarttabs: true
@@ -128,12 +135,6 @@
]
},
connect: {
- qunit: {
- options: {
- port: grunt.option('port-test') || 9002,
- base: './'
- }
- },
test: {
options: {
port: grunt.option('port-test') || 9002,
@@ -142,13 +143,6 @@
}
}
},
- qunit: {
- all: {
- options: {
- urls: ['http://localhost:' + (grunt.option('port-test') || 9002) + '/test/index.html']
- }
- }
- },
yuidoc: {
compile: {
name: '<%= pkg.name %>',
@@ -161,6 +155,13 @@
outdir: '<%= dirs.docs %>'
}
}
+ },
+ karma: {
+ unit: {
+ configFile: 'test/karma.conf.js',
+ // browsers: ['Chrome'],
+ singleRun: true
+ }
}
});
@@ -182,9 +183,10 @@
}
)
- grunt.registerTask('default', ['concat', 'uglify', 'distribute']);
grunt.registerTask('build', ['concat', 'uglify', 'distribute']);
- grunt.registerTask('test', ['build', 'connect:qunit', 'qunit']);
+ grunt.registerTask('test', ['concat', 'jshint:test', 'karma']);
grunt.registerTask('docs', ['yuidoc']);
-
-}
\ No newline at end of file
+ grunt.registerTask('default', ['test', 'uglify', 'distribute']);
+ // Travis CI task.
+ grunt.registerTask('travis', ['test']);
+}
diff --git a/README.md b/README.md
index c62ef86..690cfe4 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,8 @@

+[](http://travis-ci.org/drkibitz/pixi.js)
+
#### JavaScript 2D Renderer ####
The aim of this project is to provide a fast lightweight 2D library that works
diff --git a/package.json b/package.json
index b373240..1246a68 100644
--- a/package.json
+++ b/package.json
@@ -18,14 +18,21 @@
"main": "bin/pixi.js",
+ "scripts": {
+ "test": "grunt travis --verbose"
+ },
+
"dependencies": {},
"devDependencies": {
"grunt": "~0.4.x",
- "grunt-contrib-jshint": "0.3.x",
+ "grunt-contrib-jshint": "0.6.x",
"grunt-contrib-uglify": "0.2.x",
- "grunt-contrib-connect": "0.2.x",
- "grunt-contrib-qunit": "0.2.x",
+ "grunt-contrib-connect": "0.3.x",
"grunt-contrib-yuidoc": "0.4.x",
- "grunt-contrib-concat": "0.1.x"
+ "grunt-contrib-concat": "0.3.x",
+ "chai": "~1.7.0",
+ "karma": "0.11.0",
+ "karma-firefox-launcher": "0.1.0",
+ "karma-mocha": "0.1.0"
}
}
diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js
index a7c520e..ee82bbd 100644
--- a/src/pixi/InteractionManager.js
+++ b/src/pixi/InteractionManager.js
@@ -62,7 +62,6 @@
this.onTouchEnd = this.onTouchEnd.bind(this);
this.onTouchMove = this.onTouchMove.bind(this);
-
this.last = 0;
}
diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js
index 1a95d20..eef1059 100644
--- a/src/pixi/core/Ellipse.js
+++ b/src/pixi/core/Ellipse.js
@@ -78,7 +78,7 @@
return (normx + normy < 0.25);
}
-PIXI.Ellipse.getBounds = function()
+PIXI.Ellipse.prototype.getBounds = function()
{
return new PIXI.Rectangle(this.x, this.y, this.width, this.height);
}
diff --git a/tasks/karma.js b/tasks/karma.js
new file mode 100644
index 0000000..c340485
--- /dev/null
+++ b/tasks/karma.js
@@ -0,0 +1,27 @@
+'use strict';
+
+var path = require('path');
+var server = require('karma').server;
+
+module.exports = function (grunt) {
+ grunt.registerMultiTask('karma', 'run karma.', function() {
+ var done = this.async();
+ var options = this.options({
+ background: false
+ });
+ var data = this.data;
+
+ //merge options onto data, with data taking precedence
+ data = grunt.util._.merge(options, data);
+ data.configFile = path.resolve(data.configFile);
+ if (data.configFile) {
+ data.configFile = grunt.template.process(data.configFile);
+ }
+
+ server.start(
+ data,
+ function(code) {
+ done(!code);
+ });
+ });
+};
diff --git a/test/functional/example-1-basics/bunny.png b/test/functional/example-1-basics/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/functional/example-1-basics/bunny.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-30.png b/test/functional/example-1-basics/frame-30.png
new file mode 100644
index 0000000..96e3409
--- /dev/null
+++ b/test/functional/example-1-basics/frame-30.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-60.png b/test/functional/example-1-basics/frame-60.png
new file mode 100644
index 0000000..af3f4ce
--- /dev/null
+++ b/test/functional/example-1-basics/frame-60.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-90.png b/test/functional/example-1-basics/frame-90.png
new file mode 100644
index 0000000..099b823
--- /dev/null
+++ b/test/functional/example-1-basics/frame-90.png
Binary files differ
diff --git a/.gitignore b/.gitignore
index 12e1b62..0b88317 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
node_modules
.DS_Store
-.project
\ No newline at end of file
+.project
+*.log
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..63e4d7c
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,8 @@
+language: node_js
+node_js:
+ - 0.10
+
+before_script:
+ - npm install -g grunt-cli
+ - export DISPLAY=:99.0
+ - sh -e /etc/init.d/xvfb start
diff --git a/Gruntfile.js b/Gruntfile.js
index b083b49..103938c 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -1,10 +1,12 @@
+'use strict';
+
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-connect');
- grunt.loadNpmTasks('grunt-contrib-qunit');
grunt.loadNpmTasks('grunt-contrib-yuidoc');
+ grunt.loadTasks('tasks');
var root = 'src/pixi/',
debug = 'bin/pixi.dev.js',
@@ -79,7 +81,7 @@
},
files: {
srcBlob: '<%= dirs.src %>/**/*.js',
- testBlob: '<%= dirs.test %>/unit/**/*.js',
+ testBlob: '<%= dirs.test %>/{functional,lib/pixi,unit}/**/*.js',
build: '<%= dirs.build %>/pixi.dev.js',
buildMin: '<%= dirs.build %>/pixi.js'
},
@@ -94,7 +96,12 @@
},
jshint: {
beforeconcat: srcFiles,
- test: ['<%= files.testBlob %>'],
+ test: {
+ src: ['<%= files.testBlob %>'],
+ options: {
+ expr: true
+ }
+ },
options: {
asi: true,
smarttabs: true
@@ -128,12 +135,6 @@
]
},
connect: {
- qunit: {
- options: {
- port: grunt.option('port-test') || 9002,
- base: './'
- }
- },
test: {
options: {
port: grunt.option('port-test') || 9002,
@@ -142,13 +143,6 @@
}
}
},
- qunit: {
- all: {
- options: {
- urls: ['http://localhost:' + (grunt.option('port-test') || 9002) + '/test/index.html']
- }
- }
- },
yuidoc: {
compile: {
name: '<%= pkg.name %>',
@@ -161,6 +155,13 @@
outdir: '<%= dirs.docs %>'
}
}
+ },
+ karma: {
+ unit: {
+ configFile: 'test/karma.conf.js',
+ // browsers: ['Chrome'],
+ singleRun: true
+ }
}
});
@@ -182,9 +183,10 @@
}
)
- grunt.registerTask('default', ['concat', 'uglify', 'distribute']);
grunt.registerTask('build', ['concat', 'uglify', 'distribute']);
- grunt.registerTask('test', ['build', 'connect:qunit', 'qunit']);
+ grunt.registerTask('test', ['concat', 'jshint:test', 'karma']);
grunt.registerTask('docs', ['yuidoc']);
-
-}
\ No newline at end of file
+ grunt.registerTask('default', ['test', 'uglify', 'distribute']);
+ // Travis CI task.
+ grunt.registerTask('travis', ['test']);
+}
diff --git a/README.md b/README.md
index c62ef86..690cfe4 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,8 @@

+[](http://travis-ci.org/drkibitz/pixi.js)
+
#### JavaScript 2D Renderer ####
The aim of this project is to provide a fast lightweight 2D library that works
diff --git a/package.json b/package.json
index b373240..1246a68 100644
--- a/package.json
+++ b/package.json
@@ -18,14 +18,21 @@
"main": "bin/pixi.js",
+ "scripts": {
+ "test": "grunt travis --verbose"
+ },
+
"dependencies": {},
"devDependencies": {
"grunt": "~0.4.x",
- "grunt-contrib-jshint": "0.3.x",
+ "grunt-contrib-jshint": "0.6.x",
"grunt-contrib-uglify": "0.2.x",
- "grunt-contrib-connect": "0.2.x",
- "grunt-contrib-qunit": "0.2.x",
+ "grunt-contrib-connect": "0.3.x",
"grunt-contrib-yuidoc": "0.4.x",
- "grunt-contrib-concat": "0.1.x"
+ "grunt-contrib-concat": "0.3.x",
+ "chai": "~1.7.0",
+ "karma": "0.11.0",
+ "karma-firefox-launcher": "0.1.0",
+ "karma-mocha": "0.1.0"
}
}
diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js
index a7c520e..ee82bbd 100644
--- a/src/pixi/InteractionManager.js
+++ b/src/pixi/InteractionManager.js
@@ -62,7 +62,6 @@
this.onTouchEnd = this.onTouchEnd.bind(this);
this.onTouchMove = this.onTouchMove.bind(this);
-
this.last = 0;
}
diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js
index 1a95d20..eef1059 100644
--- a/src/pixi/core/Ellipse.js
+++ b/src/pixi/core/Ellipse.js
@@ -78,7 +78,7 @@
return (normx + normy < 0.25);
}
-PIXI.Ellipse.getBounds = function()
+PIXI.Ellipse.prototype.getBounds = function()
{
return new PIXI.Rectangle(this.x, this.y, this.width, this.height);
}
diff --git a/tasks/karma.js b/tasks/karma.js
new file mode 100644
index 0000000..c340485
--- /dev/null
+++ b/tasks/karma.js
@@ -0,0 +1,27 @@
+'use strict';
+
+var path = require('path');
+var server = require('karma').server;
+
+module.exports = function (grunt) {
+ grunt.registerMultiTask('karma', 'run karma.', function() {
+ var done = this.async();
+ var options = this.options({
+ background: false
+ });
+ var data = this.data;
+
+ //merge options onto data, with data taking precedence
+ data = grunt.util._.merge(options, data);
+ data.configFile = path.resolve(data.configFile);
+ if (data.configFile) {
+ data.configFile = grunt.template.process(data.configFile);
+ }
+
+ server.start(
+ data,
+ function(code) {
+ done(!code);
+ });
+ });
+};
diff --git a/test/functional/example-1-basics/bunny.png b/test/functional/example-1-basics/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/functional/example-1-basics/bunny.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-30.png b/test/functional/example-1-basics/frame-30.png
new file mode 100644
index 0000000..96e3409
--- /dev/null
+++ b/test/functional/example-1-basics/frame-30.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-60.png b/test/functional/example-1-basics/frame-60.png
new file mode 100644
index 0000000..af3f4ce
--- /dev/null
+++ b/test/functional/example-1-basics/frame-60.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-90.png b/test/functional/example-1-basics/frame-90.png
new file mode 100644
index 0000000..099b823
--- /dev/null
+++ b/test/functional/example-1-basics/frame-90.png
Binary files differ
diff --git a/test/functional/example-1-basics/index.js b/test/functional/example-1-basics/index.js
new file mode 100644
index 0000000..7ae7a98
--- /dev/null
+++ b/test/functional/example-1-basics/index.js
@@ -0,0 +1,133 @@
+describe('Example 1 - Basics', function () {
+ 'use strict';
+
+ var baseUri = '/base/test/functional/example-1-basics';
+ var expect = chai.expect;
+ var currentFrame = 0;
+ var frameEvents = {};
+ var stage;
+ var renderer;
+ var bunny;
+
+ function onFrame(frame, callback) {
+ frameEvents[frame] = callback;
+ }
+
+ function animate() {
+ currentFrame += 1;
+
+ requestAnimFrame( animate );
+
+ // just for fun, lets rotate mr rabbit a little
+ bunny.rotation += 0.1;
+
+ // render the stage
+ renderer.render(stage);
+
+ if (frameEvents[currentFrame])
+ frameEvents[currentFrame](currentFrame);
+ }
+
+ function initScene() {
+ // create an new instance of a pixi stage
+ stage = new PIXI.Stage(0x66FF99);
+
+ // create a renderer instance
+ renderer = PIXI.autoDetectRenderer(400, 300);
+ console.log('Is PIXI.WebGLRenderer: ' + (renderer instanceof PIXI.WebGLRenderer));
+
+ // add the renderer view element to the DOM
+ document.body.appendChild(renderer.view);
+
+ requestAnimFrame( animate );
+
+ // create a texture from an image path
+ var texture = PIXI.Texture.fromImage(baseUri + "/bunny.png");
+ // create a new Sprite using the texture
+ bunny = new PIXI.Sprite(texture);
+
+ // center the sprites anchor point
+ bunny.anchor.x = 0.5;
+ bunny.anchor.y = 0.5;
+
+ // move the sprite t the center of the screen
+ bunny.position.x = 200;
+ bunny.position.y = 150;
+
+ stage.addChild(bunny);
+ }
+
+ it('assets loaded', function (done) {
+ var loader = new PIXI.AssetLoader([
+ baseUri + '/bunny.png',
+ baseUri + '/frame-30.png',
+ baseUri + '/frame-60.png',
+ baseUri + '/frame-90.png'
+ ]);
+ // loader.on('onProgress', function (event) {
+ // console.log(event.content);
+ // });
+ loader.on('onComplete', function (event) {
+ done();
+ initScene();
+ });
+ loader.load();
+ });
+
+ it('frame 30 should match', function (done) {
+ this.timeout(700);
+ onFrame(30, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-30.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 60 should match', function (done) {
+ this.timeout(1200);
+ onFrame(60, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-60.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 90 should match', function (done) {
+ this.timeout(1700);
+ onFrame(90, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-90.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ // it('capture something', function (done) {
+ // this.timeout(2000000);
+ // onFrame(30, function () {
+ // var img = new Image();
+ // img.src = renderer.view.toDataURL('image/png');
+ // document.body.appendChild(img);
+ // });
+ // });
+});
diff --git a/.gitignore b/.gitignore
index 12e1b62..0b88317 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
node_modules
.DS_Store
-.project
\ No newline at end of file
+.project
+*.log
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..63e4d7c
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,8 @@
+language: node_js
+node_js:
+ - 0.10
+
+before_script:
+ - npm install -g grunt-cli
+ - export DISPLAY=:99.0
+ - sh -e /etc/init.d/xvfb start
diff --git a/Gruntfile.js b/Gruntfile.js
index b083b49..103938c 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -1,10 +1,12 @@
+'use strict';
+
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-connect');
- grunt.loadNpmTasks('grunt-contrib-qunit');
grunt.loadNpmTasks('grunt-contrib-yuidoc');
+ grunt.loadTasks('tasks');
var root = 'src/pixi/',
debug = 'bin/pixi.dev.js',
@@ -79,7 +81,7 @@
},
files: {
srcBlob: '<%= dirs.src %>/**/*.js',
- testBlob: '<%= dirs.test %>/unit/**/*.js',
+ testBlob: '<%= dirs.test %>/{functional,lib/pixi,unit}/**/*.js',
build: '<%= dirs.build %>/pixi.dev.js',
buildMin: '<%= dirs.build %>/pixi.js'
},
@@ -94,7 +96,12 @@
},
jshint: {
beforeconcat: srcFiles,
- test: ['<%= files.testBlob %>'],
+ test: {
+ src: ['<%= files.testBlob %>'],
+ options: {
+ expr: true
+ }
+ },
options: {
asi: true,
smarttabs: true
@@ -128,12 +135,6 @@
]
},
connect: {
- qunit: {
- options: {
- port: grunt.option('port-test') || 9002,
- base: './'
- }
- },
test: {
options: {
port: grunt.option('port-test') || 9002,
@@ -142,13 +143,6 @@
}
}
},
- qunit: {
- all: {
- options: {
- urls: ['http://localhost:' + (grunt.option('port-test') || 9002) + '/test/index.html']
- }
- }
- },
yuidoc: {
compile: {
name: '<%= pkg.name %>',
@@ -161,6 +155,13 @@
outdir: '<%= dirs.docs %>'
}
}
+ },
+ karma: {
+ unit: {
+ configFile: 'test/karma.conf.js',
+ // browsers: ['Chrome'],
+ singleRun: true
+ }
}
});
@@ -182,9 +183,10 @@
}
)
- grunt.registerTask('default', ['concat', 'uglify', 'distribute']);
grunt.registerTask('build', ['concat', 'uglify', 'distribute']);
- grunt.registerTask('test', ['build', 'connect:qunit', 'qunit']);
+ grunt.registerTask('test', ['concat', 'jshint:test', 'karma']);
grunt.registerTask('docs', ['yuidoc']);
-
-}
\ No newline at end of file
+ grunt.registerTask('default', ['test', 'uglify', 'distribute']);
+ // Travis CI task.
+ grunt.registerTask('travis', ['test']);
+}
diff --git a/README.md b/README.md
index c62ef86..690cfe4 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,8 @@

+[](http://travis-ci.org/drkibitz/pixi.js)
+
#### JavaScript 2D Renderer ####
The aim of this project is to provide a fast lightweight 2D library that works
diff --git a/package.json b/package.json
index b373240..1246a68 100644
--- a/package.json
+++ b/package.json
@@ -18,14 +18,21 @@
"main": "bin/pixi.js",
+ "scripts": {
+ "test": "grunt travis --verbose"
+ },
+
"dependencies": {},
"devDependencies": {
"grunt": "~0.4.x",
- "grunt-contrib-jshint": "0.3.x",
+ "grunt-contrib-jshint": "0.6.x",
"grunt-contrib-uglify": "0.2.x",
- "grunt-contrib-connect": "0.2.x",
- "grunt-contrib-qunit": "0.2.x",
+ "grunt-contrib-connect": "0.3.x",
"grunt-contrib-yuidoc": "0.4.x",
- "grunt-contrib-concat": "0.1.x"
+ "grunt-contrib-concat": "0.3.x",
+ "chai": "~1.7.0",
+ "karma": "0.11.0",
+ "karma-firefox-launcher": "0.1.0",
+ "karma-mocha": "0.1.0"
}
}
diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js
index a7c520e..ee82bbd 100644
--- a/src/pixi/InteractionManager.js
+++ b/src/pixi/InteractionManager.js
@@ -62,7 +62,6 @@
this.onTouchEnd = this.onTouchEnd.bind(this);
this.onTouchMove = this.onTouchMove.bind(this);
-
this.last = 0;
}
diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js
index 1a95d20..eef1059 100644
--- a/src/pixi/core/Ellipse.js
+++ b/src/pixi/core/Ellipse.js
@@ -78,7 +78,7 @@
return (normx + normy < 0.25);
}
-PIXI.Ellipse.getBounds = function()
+PIXI.Ellipse.prototype.getBounds = function()
{
return new PIXI.Rectangle(this.x, this.y, this.width, this.height);
}
diff --git a/tasks/karma.js b/tasks/karma.js
new file mode 100644
index 0000000..c340485
--- /dev/null
+++ b/tasks/karma.js
@@ -0,0 +1,27 @@
+'use strict';
+
+var path = require('path');
+var server = require('karma').server;
+
+module.exports = function (grunt) {
+ grunt.registerMultiTask('karma', 'run karma.', function() {
+ var done = this.async();
+ var options = this.options({
+ background: false
+ });
+ var data = this.data;
+
+ //merge options onto data, with data taking precedence
+ data = grunt.util._.merge(options, data);
+ data.configFile = path.resolve(data.configFile);
+ if (data.configFile) {
+ data.configFile = grunt.template.process(data.configFile);
+ }
+
+ server.start(
+ data,
+ function(code) {
+ done(!code);
+ });
+ });
+};
diff --git a/test/functional/example-1-basics/bunny.png b/test/functional/example-1-basics/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/functional/example-1-basics/bunny.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-30.png b/test/functional/example-1-basics/frame-30.png
new file mode 100644
index 0000000..96e3409
--- /dev/null
+++ b/test/functional/example-1-basics/frame-30.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-60.png b/test/functional/example-1-basics/frame-60.png
new file mode 100644
index 0000000..af3f4ce
--- /dev/null
+++ b/test/functional/example-1-basics/frame-60.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-90.png b/test/functional/example-1-basics/frame-90.png
new file mode 100644
index 0000000..099b823
--- /dev/null
+++ b/test/functional/example-1-basics/frame-90.png
Binary files differ
diff --git a/test/functional/example-1-basics/index.js b/test/functional/example-1-basics/index.js
new file mode 100644
index 0000000..7ae7a98
--- /dev/null
+++ b/test/functional/example-1-basics/index.js
@@ -0,0 +1,133 @@
+describe('Example 1 - Basics', function () {
+ 'use strict';
+
+ var baseUri = '/base/test/functional/example-1-basics';
+ var expect = chai.expect;
+ var currentFrame = 0;
+ var frameEvents = {};
+ var stage;
+ var renderer;
+ var bunny;
+
+ function onFrame(frame, callback) {
+ frameEvents[frame] = callback;
+ }
+
+ function animate() {
+ currentFrame += 1;
+
+ requestAnimFrame( animate );
+
+ // just for fun, lets rotate mr rabbit a little
+ bunny.rotation += 0.1;
+
+ // render the stage
+ renderer.render(stage);
+
+ if (frameEvents[currentFrame])
+ frameEvents[currentFrame](currentFrame);
+ }
+
+ function initScene() {
+ // create an new instance of a pixi stage
+ stage = new PIXI.Stage(0x66FF99);
+
+ // create a renderer instance
+ renderer = PIXI.autoDetectRenderer(400, 300);
+ console.log('Is PIXI.WebGLRenderer: ' + (renderer instanceof PIXI.WebGLRenderer));
+
+ // add the renderer view element to the DOM
+ document.body.appendChild(renderer.view);
+
+ requestAnimFrame( animate );
+
+ // create a texture from an image path
+ var texture = PIXI.Texture.fromImage(baseUri + "/bunny.png");
+ // create a new Sprite using the texture
+ bunny = new PIXI.Sprite(texture);
+
+ // center the sprites anchor point
+ bunny.anchor.x = 0.5;
+ bunny.anchor.y = 0.5;
+
+ // move the sprite t the center of the screen
+ bunny.position.x = 200;
+ bunny.position.y = 150;
+
+ stage.addChild(bunny);
+ }
+
+ it('assets loaded', function (done) {
+ var loader = new PIXI.AssetLoader([
+ baseUri + '/bunny.png',
+ baseUri + '/frame-30.png',
+ baseUri + '/frame-60.png',
+ baseUri + '/frame-90.png'
+ ]);
+ // loader.on('onProgress', function (event) {
+ // console.log(event.content);
+ // });
+ loader.on('onComplete', function (event) {
+ done();
+ initScene();
+ });
+ loader.load();
+ });
+
+ it('frame 30 should match', function (done) {
+ this.timeout(700);
+ onFrame(30, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-30.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 60 should match', function (done) {
+ this.timeout(1200);
+ onFrame(60, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-60.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 90 should match', function (done) {
+ this.timeout(1700);
+ onFrame(90, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-90.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ // it('capture something', function (done) {
+ // this.timeout(2000000);
+ // onFrame(30, function () {
+ // var img = new Image();
+ // img.src = renderer.view.toDataURL('image/png');
+ // document.body.appendChild(img);
+ // });
+ // });
+});
diff --git a/test/index.html b/test/index.html
deleted file mode 100644
index 9cbcac5..0000000
--- a/test/index.html
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
- Pixi.js Test Suite
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index 12e1b62..0b88317 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
node_modules
.DS_Store
-.project
\ No newline at end of file
+.project
+*.log
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..63e4d7c
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,8 @@
+language: node_js
+node_js:
+ - 0.10
+
+before_script:
+ - npm install -g grunt-cli
+ - export DISPLAY=:99.0
+ - sh -e /etc/init.d/xvfb start
diff --git a/Gruntfile.js b/Gruntfile.js
index b083b49..103938c 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -1,10 +1,12 @@
+'use strict';
+
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-connect');
- grunt.loadNpmTasks('grunt-contrib-qunit');
grunt.loadNpmTasks('grunt-contrib-yuidoc');
+ grunt.loadTasks('tasks');
var root = 'src/pixi/',
debug = 'bin/pixi.dev.js',
@@ -79,7 +81,7 @@
},
files: {
srcBlob: '<%= dirs.src %>/**/*.js',
- testBlob: '<%= dirs.test %>/unit/**/*.js',
+ testBlob: '<%= dirs.test %>/{functional,lib/pixi,unit}/**/*.js',
build: '<%= dirs.build %>/pixi.dev.js',
buildMin: '<%= dirs.build %>/pixi.js'
},
@@ -94,7 +96,12 @@
},
jshint: {
beforeconcat: srcFiles,
- test: ['<%= files.testBlob %>'],
+ test: {
+ src: ['<%= files.testBlob %>'],
+ options: {
+ expr: true
+ }
+ },
options: {
asi: true,
smarttabs: true
@@ -128,12 +135,6 @@
]
},
connect: {
- qunit: {
- options: {
- port: grunt.option('port-test') || 9002,
- base: './'
- }
- },
test: {
options: {
port: grunt.option('port-test') || 9002,
@@ -142,13 +143,6 @@
}
}
},
- qunit: {
- all: {
- options: {
- urls: ['http://localhost:' + (grunt.option('port-test') || 9002) + '/test/index.html']
- }
- }
- },
yuidoc: {
compile: {
name: '<%= pkg.name %>',
@@ -161,6 +155,13 @@
outdir: '<%= dirs.docs %>'
}
}
+ },
+ karma: {
+ unit: {
+ configFile: 'test/karma.conf.js',
+ // browsers: ['Chrome'],
+ singleRun: true
+ }
}
});
@@ -182,9 +183,10 @@
}
)
- grunt.registerTask('default', ['concat', 'uglify', 'distribute']);
grunt.registerTask('build', ['concat', 'uglify', 'distribute']);
- grunt.registerTask('test', ['build', 'connect:qunit', 'qunit']);
+ grunt.registerTask('test', ['concat', 'jshint:test', 'karma']);
grunt.registerTask('docs', ['yuidoc']);
-
-}
\ No newline at end of file
+ grunt.registerTask('default', ['test', 'uglify', 'distribute']);
+ // Travis CI task.
+ grunt.registerTask('travis', ['test']);
+}
diff --git a/README.md b/README.md
index c62ef86..690cfe4 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,8 @@

+[](http://travis-ci.org/drkibitz/pixi.js)
+
#### JavaScript 2D Renderer ####
The aim of this project is to provide a fast lightweight 2D library that works
diff --git a/package.json b/package.json
index b373240..1246a68 100644
--- a/package.json
+++ b/package.json
@@ -18,14 +18,21 @@
"main": "bin/pixi.js",
+ "scripts": {
+ "test": "grunt travis --verbose"
+ },
+
"dependencies": {},
"devDependencies": {
"grunt": "~0.4.x",
- "grunt-contrib-jshint": "0.3.x",
+ "grunt-contrib-jshint": "0.6.x",
"grunt-contrib-uglify": "0.2.x",
- "grunt-contrib-connect": "0.2.x",
- "grunt-contrib-qunit": "0.2.x",
+ "grunt-contrib-connect": "0.3.x",
"grunt-contrib-yuidoc": "0.4.x",
- "grunt-contrib-concat": "0.1.x"
+ "grunt-contrib-concat": "0.3.x",
+ "chai": "~1.7.0",
+ "karma": "0.11.0",
+ "karma-firefox-launcher": "0.1.0",
+ "karma-mocha": "0.1.0"
}
}
diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js
index a7c520e..ee82bbd 100644
--- a/src/pixi/InteractionManager.js
+++ b/src/pixi/InteractionManager.js
@@ -62,7 +62,6 @@
this.onTouchEnd = this.onTouchEnd.bind(this);
this.onTouchMove = this.onTouchMove.bind(this);
-
this.last = 0;
}
diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js
index 1a95d20..eef1059 100644
--- a/src/pixi/core/Ellipse.js
+++ b/src/pixi/core/Ellipse.js
@@ -78,7 +78,7 @@
return (normx + normy < 0.25);
}
-PIXI.Ellipse.getBounds = function()
+PIXI.Ellipse.prototype.getBounds = function()
{
return new PIXI.Rectangle(this.x, this.y, this.width, this.height);
}
diff --git a/tasks/karma.js b/tasks/karma.js
new file mode 100644
index 0000000..c340485
--- /dev/null
+++ b/tasks/karma.js
@@ -0,0 +1,27 @@
+'use strict';
+
+var path = require('path');
+var server = require('karma').server;
+
+module.exports = function (grunt) {
+ grunt.registerMultiTask('karma', 'run karma.', function() {
+ var done = this.async();
+ var options = this.options({
+ background: false
+ });
+ var data = this.data;
+
+ //merge options onto data, with data taking precedence
+ data = grunt.util._.merge(options, data);
+ data.configFile = path.resolve(data.configFile);
+ if (data.configFile) {
+ data.configFile = grunt.template.process(data.configFile);
+ }
+
+ server.start(
+ data,
+ function(code) {
+ done(!code);
+ });
+ });
+};
diff --git a/test/functional/example-1-basics/bunny.png b/test/functional/example-1-basics/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/functional/example-1-basics/bunny.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-30.png b/test/functional/example-1-basics/frame-30.png
new file mode 100644
index 0000000..96e3409
--- /dev/null
+++ b/test/functional/example-1-basics/frame-30.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-60.png b/test/functional/example-1-basics/frame-60.png
new file mode 100644
index 0000000..af3f4ce
--- /dev/null
+++ b/test/functional/example-1-basics/frame-60.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-90.png b/test/functional/example-1-basics/frame-90.png
new file mode 100644
index 0000000..099b823
--- /dev/null
+++ b/test/functional/example-1-basics/frame-90.png
Binary files differ
diff --git a/test/functional/example-1-basics/index.js b/test/functional/example-1-basics/index.js
new file mode 100644
index 0000000..7ae7a98
--- /dev/null
+++ b/test/functional/example-1-basics/index.js
@@ -0,0 +1,133 @@
+describe('Example 1 - Basics', function () {
+ 'use strict';
+
+ var baseUri = '/base/test/functional/example-1-basics';
+ var expect = chai.expect;
+ var currentFrame = 0;
+ var frameEvents = {};
+ var stage;
+ var renderer;
+ var bunny;
+
+ function onFrame(frame, callback) {
+ frameEvents[frame] = callback;
+ }
+
+ function animate() {
+ currentFrame += 1;
+
+ requestAnimFrame( animate );
+
+ // just for fun, lets rotate mr rabbit a little
+ bunny.rotation += 0.1;
+
+ // render the stage
+ renderer.render(stage);
+
+ if (frameEvents[currentFrame])
+ frameEvents[currentFrame](currentFrame);
+ }
+
+ function initScene() {
+ // create an new instance of a pixi stage
+ stage = new PIXI.Stage(0x66FF99);
+
+ // create a renderer instance
+ renderer = PIXI.autoDetectRenderer(400, 300);
+ console.log('Is PIXI.WebGLRenderer: ' + (renderer instanceof PIXI.WebGLRenderer));
+
+ // add the renderer view element to the DOM
+ document.body.appendChild(renderer.view);
+
+ requestAnimFrame( animate );
+
+ // create a texture from an image path
+ var texture = PIXI.Texture.fromImage(baseUri + "/bunny.png");
+ // create a new Sprite using the texture
+ bunny = new PIXI.Sprite(texture);
+
+ // center the sprites anchor point
+ bunny.anchor.x = 0.5;
+ bunny.anchor.y = 0.5;
+
+ // move the sprite t the center of the screen
+ bunny.position.x = 200;
+ bunny.position.y = 150;
+
+ stage.addChild(bunny);
+ }
+
+ it('assets loaded', function (done) {
+ var loader = new PIXI.AssetLoader([
+ baseUri + '/bunny.png',
+ baseUri + '/frame-30.png',
+ baseUri + '/frame-60.png',
+ baseUri + '/frame-90.png'
+ ]);
+ // loader.on('onProgress', function (event) {
+ // console.log(event.content);
+ // });
+ loader.on('onComplete', function (event) {
+ done();
+ initScene();
+ });
+ loader.load();
+ });
+
+ it('frame 30 should match', function (done) {
+ this.timeout(700);
+ onFrame(30, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-30.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 60 should match', function (done) {
+ this.timeout(1200);
+ onFrame(60, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-60.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 90 should match', function (done) {
+ this.timeout(1700);
+ onFrame(90, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-90.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ // it('capture something', function (done) {
+ // this.timeout(2000000);
+ // onFrame(30, function () {
+ // var img = new Image();
+ // img.src = renderer.view.toDataURL('image/png');
+ // document.body.appendChild(img);
+ // });
+ // });
+});
diff --git a/test/index.html b/test/index.html
deleted file mode 100644
index 9cbcac5..0000000
--- a/test/index.html
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
- Pixi.js Test Suite
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/test/karma.conf.js b/test/karma.conf.js
new file mode 100644
index 0000000..c66a696
--- /dev/null
+++ b/test/karma.conf.js
@@ -0,0 +1,82 @@
+module.exports = function(config) {
+ config.set({
+
+ // base path, that will be used to resolve files and exclude
+ basePath : '../',
+
+ frameworks : ['mocha'],
+
+ // list of files / patterns to load in the browser
+ files : [
+ 'node_modules/chai/chai.js',
+ 'bin/pixi.dev.js',
+ 'test/lib/**/*.js',
+ 'test/unit/**/*.js',
+ // 'test/functional/**/*.js',
+ {pattern: 'test/**/*.png', watched: false, included: false, served: true}
+ ],
+
+ // list of files to exclude
+ exclude : [],
+
+ // use dolts reporter, as travis terminal does not support escaping sequences
+ // possible values: 'dots', 'progress', 'junit', 'teamcity'
+ // CLI --reporters progress
+ reporters : ['progress'],
+
+ // web server port
+ // CLI --port 9876
+ port : 9876,
+
+ // cli runner port
+ // CLI --runner-port 9100
+ runnerPort : 9100,
+
+ // enable / disable colors in the output (reporters and logs)
+ // CLI --colors --no-colors
+ colors : true,
+
+ // level of logging
+ // possible values: karma.LOG_DISABLE || karma.LOG_ERROR || karma.LOG_WARN || karma.LOG_INFO || karma.LOG_DEBUG
+ // CLI --log-level debug
+ logLevel : config.LOG_DEBUG,
+
+ // enable / disable watching file and executing tests whenever any file changes
+ // CLI --auto-watch --no-auto-watch
+ autoWatch : false,
+
+ // Start these browsers, currently available:
+ // - Chrome
+ // - ChromeCanary
+ // - Firefox
+ // - Opera
+ // - Safari (only Mac)
+ // - PhantomJS
+ // - IE (only Windows)
+ // CLI --browsers Chrome,Firefox,Safari
+ browsers : ['Firefox'],
+
+ // If browser does not capture in given timeout [ms], kill it
+ // CLI --capture-timeout 5000
+ captureTimeout : 5000,
+
+ // Auto run tests on start (when browsers are captured) and exit
+ // CLI --single-run --no-single-run
+ singleRun : true,
+
+ // report which specs are slower than 500ms
+ // CLI --report-slower-than 500
+ reportSlowerThan : 1000,
+
+ preprocessors : {
+ // '**/client/js/*.js': 'coverage'
+ },
+
+ plugins : [
+ 'karma-mocha',
+ // 'karma-chrome-launcher',
+ 'karma-firefox-launcher',
+ // 'karma-phantomjs-launcher'
+ ]
+ });
+};
diff --git a/.gitignore b/.gitignore
index 12e1b62..0b88317 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
node_modules
.DS_Store
-.project
\ No newline at end of file
+.project
+*.log
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..63e4d7c
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,8 @@
+language: node_js
+node_js:
+ - 0.10
+
+before_script:
+ - npm install -g grunt-cli
+ - export DISPLAY=:99.0
+ - sh -e /etc/init.d/xvfb start
diff --git a/Gruntfile.js b/Gruntfile.js
index b083b49..103938c 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -1,10 +1,12 @@
+'use strict';
+
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-connect');
- grunt.loadNpmTasks('grunt-contrib-qunit');
grunt.loadNpmTasks('grunt-contrib-yuidoc');
+ grunt.loadTasks('tasks');
var root = 'src/pixi/',
debug = 'bin/pixi.dev.js',
@@ -79,7 +81,7 @@
},
files: {
srcBlob: '<%= dirs.src %>/**/*.js',
- testBlob: '<%= dirs.test %>/unit/**/*.js',
+ testBlob: '<%= dirs.test %>/{functional,lib/pixi,unit}/**/*.js',
build: '<%= dirs.build %>/pixi.dev.js',
buildMin: '<%= dirs.build %>/pixi.js'
},
@@ -94,7 +96,12 @@
},
jshint: {
beforeconcat: srcFiles,
- test: ['<%= files.testBlob %>'],
+ test: {
+ src: ['<%= files.testBlob %>'],
+ options: {
+ expr: true
+ }
+ },
options: {
asi: true,
smarttabs: true
@@ -128,12 +135,6 @@
]
},
connect: {
- qunit: {
- options: {
- port: grunt.option('port-test') || 9002,
- base: './'
- }
- },
test: {
options: {
port: grunt.option('port-test') || 9002,
@@ -142,13 +143,6 @@
}
}
},
- qunit: {
- all: {
- options: {
- urls: ['http://localhost:' + (grunt.option('port-test') || 9002) + '/test/index.html']
- }
- }
- },
yuidoc: {
compile: {
name: '<%= pkg.name %>',
@@ -161,6 +155,13 @@
outdir: '<%= dirs.docs %>'
}
}
+ },
+ karma: {
+ unit: {
+ configFile: 'test/karma.conf.js',
+ // browsers: ['Chrome'],
+ singleRun: true
+ }
}
});
@@ -182,9 +183,10 @@
}
)
- grunt.registerTask('default', ['concat', 'uglify', 'distribute']);
grunt.registerTask('build', ['concat', 'uglify', 'distribute']);
- grunt.registerTask('test', ['build', 'connect:qunit', 'qunit']);
+ grunt.registerTask('test', ['concat', 'jshint:test', 'karma']);
grunt.registerTask('docs', ['yuidoc']);
-
-}
\ No newline at end of file
+ grunt.registerTask('default', ['test', 'uglify', 'distribute']);
+ // Travis CI task.
+ grunt.registerTask('travis', ['test']);
+}
diff --git a/README.md b/README.md
index c62ef86..690cfe4 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,8 @@

+[](http://travis-ci.org/drkibitz/pixi.js)
+
#### JavaScript 2D Renderer ####
The aim of this project is to provide a fast lightweight 2D library that works
diff --git a/package.json b/package.json
index b373240..1246a68 100644
--- a/package.json
+++ b/package.json
@@ -18,14 +18,21 @@
"main": "bin/pixi.js",
+ "scripts": {
+ "test": "grunt travis --verbose"
+ },
+
"dependencies": {},
"devDependencies": {
"grunt": "~0.4.x",
- "grunt-contrib-jshint": "0.3.x",
+ "grunt-contrib-jshint": "0.6.x",
"grunt-contrib-uglify": "0.2.x",
- "grunt-contrib-connect": "0.2.x",
- "grunt-contrib-qunit": "0.2.x",
+ "grunt-contrib-connect": "0.3.x",
"grunt-contrib-yuidoc": "0.4.x",
- "grunt-contrib-concat": "0.1.x"
+ "grunt-contrib-concat": "0.3.x",
+ "chai": "~1.7.0",
+ "karma": "0.11.0",
+ "karma-firefox-launcher": "0.1.0",
+ "karma-mocha": "0.1.0"
}
}
diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js
index a7c520e..ee82bbd 100644
--- a/src/pixi/InteractionManager.js
+++ b/src/pixi/InteractionManager.js
@@ -62,7 +62,6 @@
this.onTouchEnd = this.onTouchEnd.bind(this);
this.onTouchMove = this.onTouchMove.bind(this);
-
this.last = 0;
}
diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js
index 1a95d20..eef1059 100644
--- a/src/pixi/core/Ellipse.js
+++ b/src/pixi/core/Ellipse.js
@@ -78,7 +78,7 @@
return (normx + normy < 0.25);
}
-PIXI.Ellipse.getBounds = function()
+PIXI.Ellipse.prototype.getBounds = function()
{
return new PIXI.Rectangle(this.x, this.y, this.width, this.height);
}
diff --git a/tasks/karma.js b/tasks/karma.js
new file mode 100644
index 0000000..c340485
--- /dev/null
+++ b/tasks/karma.js
@@ -0,0 +1,27 @@
+'use strict';
+
+var path = require('path');
+var server = require('karma').server;
+
+module.exports = function (grunt) {
+ grunt.registerMultiTask('karma', 'run karma.', function() {
+ var done = this.async();
+ var options = this.options({
+ background: false
+ });
+ var data = this.data;
+
+ //merge options onto data, with data taking precedence
+ data = grunt.util._.merge(options, data);
+ data.configFile = path.resolve(data.configFile);
+ if (data.configFile) {
+ data.configFile = grunt.template.process(data.configFile);
+ }
+
+ server.start(
+ data,
+ function(code) {
+ done(!code);
+ });
+ });
+};
diff --git a/test/functional/example-1-basics/bunny.png b/test/functional/example-1-basics/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/functional/example-1-basics/bunny.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-30.png b/test/functional/example-1-basics/frame-30.png
new file mode 100644
index 0000000..96e3409
--- /dev/null
+++ b/test/functional/example-1-basics/frame-30.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-60.png b/test/functional/example-1-basics/frame-60.png
new file mode 100644
index 0000000..af3f4ce
--- /dev/null
+++ b/test/functional/example-1-basics/frame-60.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-90.png b/test/functional/example-1-basics/frame-90.png
new file mode 100644
index 0000000..099b823
--- /dev/null
+++ b/test/functional/example-1-basics/frame-90.png
Binary files differ
diff --git a/test/functional/example-1-basics/index.js b/test/functional/example-1-basics/index.js
new file mode 100644
index 0000000..7ae7a98
--- /dev/null
+++ b/test/functional/example-1-basics/index.js
@@ -0,0 +1,133 @@
+describe('Example 1 - Basics', function () {
+ 'use strict';
+
+ var baseUri = '/base/test/functional/example-1-basics';
+ var expect = chai.expect;
+ var currentFrame = 0;
+ var frameEvents = {};
+ var stage;
+ var renderer;
+ var bunny;
+
+ function onFrame(frame, callback) {
+ frameEvents[frame] = callback;
+ }
+
+ function animate() {
+ currentFrame += 1;
+
+ requestAnimFrame( animate );
+
+ // just for fun, lets rotate mr rabbit a little
+ bunny.rotation += 0.1;
+
+ // render the stage
+ renderer.render(stage);
+
+ if (frameEvents[currentFrame])
+ frameEvents[currentFrame](currentFrame);
+ }
+
+ function initScene() {
+ // create an new instance of a pixi stage
+ stage = new PIXI.Stage(0x66FF99);
+
+ // create a renderer instance
+ renderer = PIXI.autoDetectRenderer(400, 300);
+ console.log('Is PIXI.WebGLRenderer: ' + (renderer instanceof PIXI.WebGLRenderer));
+
+ // add the renderer view element to the DOM
+ document.body.appendChild(renderer.view);
+
+ requestAnimFrame( animate );
+
+ // create a texture from an image path
+ var texture = PIXI.Texture.fromImage(baseUri + "/bunny.png");
+ // create a new Sprite using the texture
+ bunny = new PIXI.Sprite(texture);
+
+ // center the sprites anchor point
+ bunny.anchor.x = 0.5;
+ bunny.anchor.y = 0.5;
+
+ // move the sprite t the center of the screen
+ bunny.position.x = 200;
+ bunny.position.y = 150;
+
+ stage.addChild(bunny);
+ }
+
+ it('assets loaded', function (done) {
+ var loader = new PIXI.AssetLoader([
+ baseUri + '/bunny.png',
+ baseUri + '/frame-30.png',
+ baseUri + '/frame-60.png',
+ baseUri + '/frame-90.png'
+ ]);
+ // loader.on('onProgress', function (event) {
+ // console.log(event.content);
+ // });
+ loader.on('onComplete', function (event) {
+ done();
+ initScene();
+ });
+ loader.load();
+ });
+
+ it('frame 30 should match', function (done) {
+ this.timeout(700);
+ onFrame(30, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-30.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 60 should match', function (done) {
+ this.timeout(1200);
+ onFrame(60, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-60.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 90 should match', function (done) {
+ this.timeout(1700);
+ onFrame(90, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-90.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ // it('capture something', function (done) {
+ // this.timeout(2000000);
+ // onFrame(30, function () {
+ // var img = new Image();
+ // img.src = renderer.view.toDataURL('image/png');
+ // document.body.appendChild(img);
+ // });
+ // });
+});
diff --git a/test/index.html b/test/index.html
deleted file mode 100644
index 9cbcac5..0000000
--- a/test/index.html
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
- Pixi.js Test Suite
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/test/karma.conf.js b/test/karma.conf.js
new file mode 100644
index 0000000..c66a696
--- /dev/null
+++ b/test/karma.conf.js
@@ -0,0 +1,82 @@
+module.exports = function(config) {
+ config.set({
+
+ // base path, that will be used to resolve files and exclude
+ basePath : '../',
+
+ frameworks : ['mocha'],
+
+ // list of files / patterns to load in the browser
+ files : [
+ 'node_modules/chai/chai.js',
+ 'bin/pixi.dev.js',
+ 'test/lib/**/*.js',
+ 'test/unit/**/*.js',
+ // 'test/functional/**/*.js',
+ {pattern: 'test/**/*.png', watched: false, included: false, served: true}
+ ],
+
+ // list of files to exclude
+ exclude : [],
+
+ // use dolts reporter, as travis terminal does not support escaping sequences
+ // possible values: 'dots', 'progress', 'junit', 'teamcity'
+ // CLI --reporters progress
+ reporters : ['progress'],
+
+ // web server port
+ // CLI --port 9876
+ port : 9876,
+
+ // cli runner port
+ // CLI --runner-port 9100
+ runnerPort : 9100,
+
+ // enable / disable colors in the output (reporters and logs)
+ // CLI --colors --no-colors
+ colors : true,
+
+ // level of logging
+ // possible values: karma.LOG_DISABLE || karma.LOG_ERROR || karma.LOG_WARN || karma.LOG_INFO || karma.LOG_DEBUG
+ // CLI --log-level debug
+ logLevel : config.LOG_DEBUG,
+
+ // enable / disable watching file and executing tests whenever any file changes
+ // CLI --auto-watch --no-auto-watch
+ autoWatch : false,
+
+ // Start these browsers, currently available:
+ // - Chrome
+ // - ChromeCanary
+ // - Firefox
+ // - Opera
+ // - Safari (only Mac)
+ // - PhantomJS
+ // - IE (only Windows)
+ // CLI --browsers Chrome,Firefox,Safari
+ browsers : ['Firefox'],
+
+ // If browser does not capture in given timeout [ms], kill it
+ // CLI --capture-timeout 5000
+ captureTimeout : 5000,
+
+ // Auto run tests on start (when browsers are captured) and exit
+ // CLI --single-run --no-single-run
+ singleRun : true,
+
+ // report which specs are slower than 500ms
+ // CLI --report-slower-than 500
+ reportSlowerThan : 1000,
+
+ preprocessors : {
+ // '**/client/js/*.js': 'coverage'
+ },
+
+ plugins : [
+ 'karma-mocha',
+ // 'karma-chrome-launcher',
+ 'karma-firefox-launcher',
+ // 'karma-phantomjs-launcher'
+ ]
+ });
+};
diff --git a/test/lib/pixi/core/Matrix.js b/test/lib/pixi/core/Matrix.js
new file mode 100644
index 0000000..d26386b
--- /dev/null
+++ b/test/lib/pixi/core/Matrix.js
@@ -0,0 +1,40 @@
+
+function pixi_core_Matrix_confirmNewMat3(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(1);
+ expect(matrix[5]).to.equal(0);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(1);
+}
+
+function pixi_core_Matrix_confirmNewMat4(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[0]).to.equal(1);
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(0);
+ expect(matrix[5]).to.equal(1);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(0);
+ expect(matrix[9]).to.equal(0);
+ expect(matrix[10]).to.equal(1);
+ expect(matrix[11]).to.equal(0);
+ expect(matrix[12]).to.equal(0);
+ expect(matrix[13]).to.equal(0);
+ expect(matrix[14]).to.equal(0);
+ expect(matrix[15]).to.equal(1);
+}
diff --git a/.gitignore b/.gitignore
index 12e1b62..0b88317 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
node_modules
.DS_Store
-.project
\ No newline at end of file
+.project
+*.log
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..63e4d7c
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,8 @@
+language: node_js
+node_js:
+ - 0.10
+
+before_script:
+ - npm install -g grunt-cli
+ - export DISPLAY=:99.0
+ - sh -e /etc/init.d/xvfb start
diff --git a/Gruntfile.js b/Gruntfile.js
index b083b49..103938c 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -1,10 +1,12 @@
+'use strict';
+
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-connect');
- grunt.loadNpmTasks('grunt-contrib-qunit');
grunt.loadNpmTasks('grunt-contrib-yuidoc');
+ grunt.loadTasks('tasks');
var root = 'src/pixi/',
debug = 'bin/pixi.dev.js',
@@ -79,7 +81,7 @@
},
files: {
srcBlob: '<%= dirs.src %>/**/*.js',
- testBlob: '<%= dirs.test %>/unit/**/*.js',
+ testBlob: '<%= dirs.test %>/{functional,lib/pixi,unit}/**/*.js',
build: '<%= dirs.build %>/pixi.dev.js',
buildMin: '<%= dirs.build %>/pixi.js'
},
@@ -94,7 +96,12 @@
},
jshint: {
beforeconcat: srcFiles,
- test: ['<%= files.testBlob %>'],
+ test: {
+ src: ['<%= files.testBlob %>'],
+ options: {
+ expr: true
+ }
+ },
options: {
asi: true,
smarttabs: true
@@ -128,12 +135,6 @@
]
},
connect: {
- qunit: {
- options: {
- port: grunt.option('port-test') || 9002,
- base: './'
- }
- },
test: {
options: {
port: grunt.option('port-test') || 9002,
@@ -142,13 +143,6 @@
}
}
},
- qunit: {
- all: {
- options: {
- urls: ['http://localhost:' + (grunt.option('port-test') || 9002) + '/test/index.html']
- }
- }
- },
yuidoc: {
compile: {
name: '<%= pkg.name %>',
@@ -161,6 +155,13 @@
outdir: '<%= dirs.docs %>'
}
}
+ },
+ karma: {
+ unit: {
+ configFile: 'test/karma.conf.js',
+ // browsers: ['Chrome'],
+ singleRun: true
+ }
}
});
@@ -182,9 +183,10 @@
}
)
- grunt.registerTask('default', ['concat', 'uglify', 'distribute']);
grunt.registerTask('build', ['concat', 'uglify', 'distribute']);
- grunt.registerTask('test', ['build', 'connect:qunit', 'qunit']);
+ grunt.registerTask('test', ['concat', 'jshint:test', 'karma']);
grunt.registerTask('docs', ['yuidoc']);
-
-}
\ No newline at end of file
+ grunt.registerTask('default', ['test', 'uglify', 'distribute']);
+ // Travis CI task.
+ grunt.registerTask('travis', ['test']);
+}
diff --git a/README.md b/README.md
index c62ef86..690cfe4 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,8 @@

+[](http://travis-ci.org/drkibitz/pixi.js)
+
#### JavaScript 2D Renderer ####
The aim of this project is to provide a fast lightweight 2D library that works
diff --git a/package.json b/package.json
index b373240..1246a68 100644
--- a/package.json
+++ b/package.json
@@ -18,14 +18,21 @@
"main": "bin/pixi.js",
+ "scripts": {
+ "test": "grunt travis --verbose"
+ },
+
"dependencies": {},
"devDependencies": {
"grunt": "~0.4.x",
- "grunt-contrib-jshint": "0.3.x",
+ "grunt-contrib-jshint": "0.6.x",
"grunt-contrib-uglify": "0.2.x",
- "grunt-contrib-connect": "0.2.x",
- "grunt-contrib-qunit": "0.2.x",
+ "grunt-contrib-connect": "0.3.x",
"grunt-contrib-yuidoc": "0.4.x",
- "grunt-contrib-concat": "0.1.x"
+ "grunt-contrib-concat": "0.3.x",
+ "chai": "~1.7.0",
+ "karma": "0.11.0",
+ "karma-firefox-launcher": "0.1.0",
+ "karma-mocha": "0.1.0"
}
}
diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js
index a7c520e..ee82bbd 100644
--- a/src/pixi/InteractionManager.js
+++ b/src/pixi/InteractionManager.js
@@ -62,7 +62,6 @@
this.onTouchEnd = this.onTouchEnd.bind(this);
this.onTouchMove = this.onTouchMove.bind(this);
-
this.last = 0;
}
diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js
index 1a95d20..eef1059 100644
--- a/src/pixi/core/Ellipse.js
+++ b/src/pixi/core/Ellipse.js
@@ -78,7 +78,7 @@
return (normx + normy < 0.25);
}
-PIXI.Ellipse.getBounds = function()
+PIXI.Ellipse.prototype.getBounds = function()
{
return new PIXI.Rectangle(this.x, this.y, this.width, this.height);
}
diff --git a/tasks/karma.js b/tasks/karma.js
new file mode 100644
index 0000000..c340485
--- /dev/null
+++ b/tasks/karma.js
@@ -0,0 +1,27 @@
+'use strict';
+
+var path = require('path');
+var server = require('karma').server;
+
+module.exports = function (grunt) {
+ grunt.registerMultiTask('karma', 'run karma.', function() {
+ var done = this.async();
+ var options = this.options({
+ background: false
+ });
+ var data = this.data;
+
+ //merge options onto data, with data taking precedence
+ data = grunt.util._.merge(options, data);
+ data.configFile = path.resolve(data.configFile);
+ if (data.configFile) {
+ data.configFile = grunt.template.process(data.configFile);
+ }
+
+ server.start(
+ data,
+ function(code) {
+ done(!code);
+ });
+ });
+};
diff --git a/test/functional/example-1-basics/bunny.png b/test/functional/example-1-basics/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/functional/example-1-basics/bunny.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-30.png b/test/functional/example-1-basics/frame-30.png
new file mode 100644
index 0000000..96e3409
--- /dev/null
+++ b/test/functional/example-1-basics/frame-30.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-60.png b/test/functional/example-1-basics/frame-60.png
new file mode 100644
index 0000000..af3f4ce
--- /dev/null
+++ b/test/functional/example-1-basics/frame-60.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-90.png b/test/functional/example-1-basics/frame-90.png
new file mode 100644
index 0000000..099b823
--- /dev/null
+++ b/test/functional/example-1-basics/frame-90.png
Binary files differ
diff --git a/test/functional/example-1-basics/index.js b/test/functional/example-1-basics/index.js
new file mode 100644
index 0000000..7ae7a98
--- /dev/null
+++ b/test/functional/example-1-basics/index.js
@@ -0,0 +1,133 @@
+describe('Example 1 - Basics', function () {
+ 'use strict';
+
+ var baseUri = '/base/test/functional/example-1-basics';
+ var expect = chai.expect;
+ var currentFrame = 0;
+ var frameEvents = {};
+ var stage;
+ var renderer;
+ var bunny;
+
+ function onFrame(frame, callback) {
+ frameEvents[frame] = callback;
+ }
+
+ function animate() {
+ currentFrame += 1;
+
+ requestAnimFrame( animate );
+
+ // just for fun, lets rotate mr rabbit a little
+ bunny.rotation += 0.1;
+
+ // render the stage
+ renderer.render(stage);
+
+ if (frameEvents[currentFrame])
+ frameEvents[currentFrame](currentFrame);
+ }
+
+ function initScene() {
+ // create an new instance of a pixi stage
+ stage = new PIXI.Stage(0x66FF99);
+
+ // create a renderer instance
+ renderer = PIXI.autoDetectRenderer(400, 300);
+ console.log('Is PIXI.WebGLRenderer: ' + (renderer instanceof PIXI.WebGLRenderer));
+
+ // add the renderer view element to the DOM
+ document.body.appendChild(renderer.view);
+
+ requestAnimFrame( animate );
+
+ // create a texture from an image path
+ var texture = PIXI.Texture.fromImage(baseUri + "/bunny.png");
+ // create a new Sprite using the texture
+ bunny = new PIXI.Sprite(texture);
+
+ // center the sprites anchor point
+ bunny.anchor.x = 0.5;
+ bunny.anchor.y = 0.5;
+
+ // move the sprite t the center of the screen
+ bunny.position.x = 200;
+ bunny.position.y = 150;
+
+ stage.addChild(bunny);
+ }
+
+ it('assets loaded', function (done) {
+ var loader = new PIXI.AssetLoader([
+ baseUri + '/bunny.png',
+ baseUri + '/frame-30.png',
+ baseUri + '/frame-60.png',
+ baseUri + '/frame-90.png'
+ ]);
+ // loader.on('onProgress', function (event) {
+ // console.log(event.content);
+ // });
+ loader.on('onComplete', function (event) {
+ done();
+ initScene();
+ });
+ loader.load();
+ });
+
+ it('frame 30 should match', function (done) {
+ this.timeout(700);
+ onFrame(30, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-30.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 60 should match', function (done) {
+ this.timeout(1200);
+ onFrame(60, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-60.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 90 should match', function (done) {
+ this.timeout(1700);
+ onFrame(90, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-90.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ // it('capture something', function (done) {
+ // this.timeout(2000000);
+ // onFrame(30, function () {
+ // var img = new Image();
+ // img.src = renderer.view.toDataURL('image/png');
+ // document.body.appendChild(img);
+ // });
+ // });
+});
diff --git a/test/index.html b/test/index.html
deleted file mode 100644
index 9cbcac5..0000000
--- a/test/index.html
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
- Pixi.js Test Suite
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/test/karma.conf.js b/test/karma.conf.js
new file mode 100644
index 0000000..c66a696
--- /dev/null
+++ b/test/karma.conf.js
@@ -0,0 +1,82 @@
+module.exports = function(config) {
+ config.set({
+
+ // base path, that will be used to resolve files and exclude
+ basePath : '../',
+
+ frameworks : ['mocha'],
+
+ // list of files / patterns to load in the browser
+ files : [
+ 'node_modules/chai/chai.js',
+ 'bin/pixi.dev.js',
+ 'test/lib/**/*.js',
+ 'test/unit/**/*.js',
+ // 'test/functional/**/*.js',
+ {pattern: 'test/**/*.png', watched: false, included: false, served: true}
+ ],
+
+ // list of files to exclude
+ exclude : [],
+
+ // use dolts reporter, as travis terminal does not support escaping sequences
+ // possible values: 'dots', 'progress', 'junit', 'teamcity'
+ // CLI --reporters progress
+ reporters : ['progress'],
+
+ // web server port
+ // CLI --port 9876
+ port : 9876,
+
+ // cli runner port
+ // CLI --runner-port 9100
+ runnerPort : 9100,
+
+ // enable / disable colors in the output (reporters and logs)
+ // CLI --colors --no-colors
+ colors : true,
+
+ // level of logging
+ // possible values: karma.LOG_DISABLE || karma.LOG_ERROR || karma.LOG_WARN || karma.LOG_INFO || karma.LOG_DEBUG
+ // CLI --log-level debug
+ logLevel : config.LOG_DEBUG,
+
+ // enable / disable watching file and executing tests whenever any file changes
+ // CLI --auto-watch --no-auto-watch
+ autoWatch : false,
+
+ // Start these browsers, currently available:
+ // - Chrome
+ // - ChromeCanary
+ // - Firefox
+ // - Opera
+ // - Safari (only Mac)
+ // - PhantomJS
+ // - IE (only Windows)
+ // CLI --browsers Chrome,Firefox,Safari
+ browsers : ['Firefox'],
+
+ // If browser does not capture in given timeout [ms], kill it
+ // CLI --capture-timeout 5000
+ captureTimeout : 5000,
+
+ // Auto run tests on start (when browsers are captured) and exit
+ // CLI --single-run --no-single-run
+ singleRun : true,
+
+ // report which specs are slower than 500ms
+ // CLI --report-slower-than 500
+ reportSlowerThan : 1000,
+
+ preprocessors : {
+ // '**/client/js/*.js': 'coverage'
+ },
+
+ plugins : [
+ 'karma-mocha',
+ // 'karma-chrome-launcher',
+ 'karma-firefox-launcher',
+ // 'karma-phantomjs-launcher'
+ ]
+ });
+};
diff --git a/test/lib/pixi/core/Matrix.js b/test/lib/pixi/core/Matrix.js
new file mode 100644
index 0000000..d26386b
--- /dev/null
+++ b/test/lib/pixi/core/Matrix.js
@@ -0,0 +1,40 @@
+
+function pixi_core_Matrix_confirmNewMat3(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(1);
+ expect(matrix[5]).to.equal(0);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(1);
+}
+
+function pixi_core_Matrix_confirmNewMat4(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[0]).to.equal(1);
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(0);
+ expect(matrix[5]).to.equal(1);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(0);
+ expect(matrix[9]).to.equal(0);
+ expect(matrix[10]).to.equal(1);
+ expect(matrix[11]).to.equal(0);
+ expect(matrix[12]).to.equal(0);
+ expect(matrix[13]).to.equal(0);
+ expect(matrix[14]).to.equal(0);
+ expect(matrix[15]).to.equal(1);
+}
diff --git a/test/lib/pixi/core/Point.js b/test/lib/pixi/core/Point.js
new file mode 100644
index 0000000..e5df07b
--- /dev/null
+++ b/test/lib/pixi/core/Point.js
@@ -0,0 +1,10 @@
+
+function pixi_core_Point_confirm(obj, x, y) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Point);
+ expect(obj).to.respondTo('clone');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+}
diff --git a/.gitignore b/.gitignore
index 12e1b62..0b88317 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
node_modules
.DS_Store
-.project
\ No newline at end of file
+.project
+*.log
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..63e4d7c
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,8 @@
+language: node_js
+node_js:
+ - 0.10
+
+before_script:
+ - npm install -g grunt-cli
+ - export DISPLAY=:99.0
+ - sh -e /etc/init.d/xvfb start
diff --git a/Gruntfile.js b/Gruntfile.js
index b083b49..103938c 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -1,10 +1,12 @@
+'use strict';
+
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-connect');
- grunt.loadNpmTasks('grunt-contrib-qunit');
grunt.loadNpmTasks('grunt-contrib-yuidoc');
+ grunt.loadTasks('tasks');
var root = 'src/pixi/',
debug = 'bin/pixi.dev.js',
@@ -79,7 +81,7 @@
},
files: {
srcBlob: '<%= dirs.src %>/**/*.js',
- testBlob: '<%= dirs.test %>/unit/**/*.js',
+ testBlob: '<%= dirs.test %>/{functional,lib/pixi,unit}/**/*.js',
build: '<%= dirs.build %>/pixi.dev.js',
buildMin: '<%= dirs.build %>/pixi.js'
},
@@ -94,7 +96,12 @@
},
jshint: {
beforeconcat: srcFiles,
- test: ['<%= files.testBlob %>'],
+ test: {
+ src: ['<%= files.testBlob %>'],
+ options: {
+ expr: true
+ }
+ },
options: {
asi: true,
smarttabs: true
@@ -128,12 +135,6 @@
]
},
connect: {
- qunit: {
- options: {
- port: grunt.option('port-test') || 9002,
- base: './'
- }
- },
test: {
options: {
port: grunt.option('port-test') || 9002,
@@ -142,13 +143,6 @@
}
}
},
- qunit: {
- all: {
- options: {
- urls: ['http://localhost:' + (grunt.option('port-test') || 9002) + '/test/index.html']
- }
- }
- },
yuidoc: {
compile: {
name: '<%= pkg.name %>',
@@ -161,6 +155,13 @@
outdir: '<%= dirs.docs %>'
}
}
+ },
+ karma: {
+ unit: {
+ configFile: 'test/karma.conf.js',
+ // browsers: ['Chrome'],
+ singleRun: true
+ }
}
});
@@ -182,9 +183,10 @@
}
)
- grunt.registerTask('default', ['concat', 'uglify', 'distribute']);
grunt.registerTask('build', ['concat', 'uglify', 'distribute']);
- grunt.registerTask('test', ['build', 'connect:qunit', 'qunit']);
+ grunt.registerTask('test', ['concat', 'jshint:test', 'karma']);
grunt.registerTask('docs', ['yuidoc']);
-
-}
\ No newline at end of file
+ grunt.registerTask('default', ['test', 'uglify', 'distribute']);
+ // Travis CI task.
+ grunt.registerTask('travis', ['test']);
+}
diff --git a/README.md b/README.md
index c62ef86..690cfe4 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,8 @@

+[](http://travis-ci.org/drkibitz/pixi.js)
+
#### JavaScript 2D Renderer ####
The aim of this project is to provide a fast lightweight 2D library that works
diff --git a/package.json b/package.json
index b373240..1246a68 100644
--- a/package.json
+++ b/package.json
@@ -18,14 +18,21 @@
"main": "bin/pixi.js",
+ "scripts": {
+ "test": "grunt travis --verbose"
+ },
+
"dependencies": {},
"devDependencies": {
"grunt": "~0.4.x",
- "grunt-contrib-jshint": "0.3.x",
+ "grunt-contrib-jshint": "0.6.x",
"grunt-contrib-uglify": "0.2.x",
- "grunt-contrib-connect": "0.2.x",
- "grunt-contrib-qunit": "0.2.x",
+ "grunt-contrib-connect": "0.3.x",
"grunt-contrib-yuidoc": "0.4.x",
- "grunt-contrib-concat": "0.1.x"
+ "grunt-contrib-concat": "0.3.x",
+ "chai": "~1.7.0",
+ "karma": "0.11.0",
+ "karma-firefox-launcher": "0.1.0",
+ "karma-mocha": "0.1.0"
}
}
diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js
index a7c520e..ee82bbd 100644
--- a/src/pixi/InteractionManager.js
+++ b/src/pixi/InteractionManager.js
@@ -62,7 +62,6 @@
this.onTouchEnd = this.onTouchEnd.bind(this);
this.onTouchMove = this.onTouchMove.bind(this);
-
this.last = 0;
}
diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js
index 1a95d20..eef1059 100644
--- a/src/pixi/core/Ellipse.js
+++ b/src/pixi/core/Ellipse.js
@@ -78,7 +78,7 @@
return (normx + normy < 0.25);
}
-PIXI.Ellipse.getBounds = function()
+PIXI.Ellipse.prototype.getBounds = function()
{
return new PIXI.Rectangle(this.x, this.y, this.width, this.height);
}
diff --git a/tasks/karma.js b/tasks/karma.js
new file mode 100644
index 0000000..c340485
--- /dev/null
+++ b/tasks/karma.js
@@ -0,0 +1,27 @@
+'use strict';
+
+var path = require('path');
+var server = require('karma').server;
+
+module.exports = function (grunt) {
+ grunt.registerMultiTask('karma', 'run karma.', function() {
+ var done = this.async();
+ var options = this.options({
+ background: false
+ });
+ var data = this.data;
+
+ //merge options onto data, with data taking precedence
+ data = grunt.util._.merge(options, data);
+ data.configFile = path.resolve(data.configFile);
+ if (data.configFile) {
+ data.configFile = grunt.template.process(data.configFile);
+ }
+
+ server.start(
+ data,
+ function(code) {
+ done(!code);
+ });
+ });
+};
diff --git a/test/functional/example-1-basics/bunny.png b/test/functional/example-1-basics/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/functional/example-1-basics/bunny.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-30.png b/test/functional/example-1-basics/frame-30.png
new file mode 100644
index 0000000..96e3409
--- /dev/null
+++ b/test/functional/example-1-basics/frame-30.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-60.png b/test/functional/example-1-basics/frame-60.png
new file mode 100644
index 0000000..af3f4ce
--- /dev/null
+++ b/test/functional/example-1-basics/frame-60.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-90.png b/test/functional/example-1-basics/frame-90.png
new file mode 100644
index 0000000..099b823
--- /dev/null
+++ b/test/functional/example-1-basics/frame-90.png
Binary files differ
diff --git a/test/functional/example-1-basics/index.js b/test/functional/example-1-basics/index.js
new file mode 100644
index 0000000..7ae7a98
--- /dev/null
+++ b/test/functional/example-1-basics/index.js
@@ -0,0 +1,133 @@
+describe('Example 1 - Basics', function () {
+ 'use strict';
+
+ var baseUri = '/base/test/functional/example-1-basics';
+ var expect = chai.expect;
+ var currentFrame = 0;
+ var frameEvents = {};
+ var stage;
+ var renderer;
+ var bunny;
+
+ function onFrame(frame, callback) {
+ frameEvents[frame] = callback;
+ }
+
+ function animate() {
+ currentFrame += 1;
+
+ requestAnimFrame( animate );
+
+ // just for fun, lets rotate mr rabbit a little
+ bunny.rotation += 0.1;
+
+ // render the stage
+ renderer.render(stage);
+
+ if (frameEvents[currentFrame])
+ frameEvents[currentFrame](currentFrame);
+ }
+
+ function initScene() {
+ // create an new instance of a pixi stage
+ stage = new PIXI.Stage(0x66FF99);
+
+ // create a renderer instance
+ renderer = PIXI.autoDetectRenderer(400, 300);
+ console.log('Is PIXI.WebGLRenderer: ' + (renderer instanceof PIXI.WebGLRenderer));
+
+ // add the renderer view element to the DOM
+ document.body.appendChild(renderer.view);
+
+ requestAnimFrame( animate );
+
+ // create a texture from an image path
+ var texture = PIXI.Texture.fromImage(baseUri + "/bunny.png");
+ // create a new Sprite using the texture
+ bunny = new PIXI.Sprite(texture);
+
+ // center the sprites anchor point
+ bunny.anchor.x = 0.5;
+ bunny.anchor.y = 0.5;
+
+ // move the sprite t the center of the screen
+ bunny.position.x = 200;
+ bunny.position.y = 150;
+
+ stage.addChild(bunny);
+ }
+
+ it('assets loaded', function (done) {
+ var loader = new PIXI.AssetLoader([
+ baseUri + '/bunny.png',
+ baseUri + '/frame-30.png',
+ baseUri + '/frame-60.png',
+ baseUri + '/frame-90.png'
+ ]);
+ // loader.on('onProgress', function (event) {
+ // console.log(event.content);
+ // });
+ loader.on('onComplete', function (event) {
+ done();
+ initScene();
+ });
+ loader.load();
+ });
+
+ it('frame 30 should match', function (done) {
+ this.timeout(700);
+ onFrame(30, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-30.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 60 should match', function (done) {
+ this.timeout(1200);
+ onFrame(60, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-60.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 90 should match', function (done) {
+ this.timeout(1700);
+ onFrame(90, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-90.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ // it('capture something', function (done) {
+ // this.timeout(2000000);
+ // onFrame(30, function () {
+ // var img = new Image();
+ // img.src = renderer.view.toDataURL('image/png');
+ // document.body.appendChild(img);
+ // });
+ // });
+});
diff --git a/test/index.html b/test/index.html
deleted file mode 100644
index 9cbcac5..0000000
--- a/test/index.html
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
- Pixi.js Test Suite
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/test/karma.conf.js b/test/karma.conf.js
new file mode 100644
index 0000000..c66a696
--- /dev/null
+++ b/test/karma.conf.js
@@ -0,0 +1,82 @@
+module.exports = function(config) {
+ config.set({
+
+ // base path, that will be used to resolve files and exclude
+ basePath : '../',
+
+ frameworks : ['mocha'],
+
+ // list of files / patterns to load in the browser
+ files : [
+ 'node_modules/chai/chai.js',
+ 'bin/pixi.dev.js',
+ 'test/lib/**/*.js',
+ 'test/unit/**/*.js',
+ // 'test/functional/**/*.js',
+ {pattern: 'test/**/*.png', watched: false, included: false, served: true}
+ ],
+
+ // list of files to exclude
+ exclude : [],
+
+ // use dolts reporter, as travis terminal does not support escaping sequences
+ // possible values: 'dots', 'progress', 'junit', 'teamcity'
+ // CLI --reporters progress
+ reporters : ['progress'],
+
+ // web server port
+ // CLI --port 9876
+ port : 9876,
+
+ // cli runner port
+ // CLI --runner-port 9100
+ runnerPort : 9100,
+
+ // enable / disable colors in the output (reporters and logs)
+ // CLI --colors --no-colors
+ colors : true,
+
+ // level of logging
+ // possible values: karma.LOG_DISABLE || karma.LOG_ERROR || karma.LOG_WARN || karma.LOG_INFO || karma.LOG_DEBUG
+ // CLI --log-level debug
+ logLevel : config.LOG_DEBUG,
+
+ // enable / disable watching file and executing tests whenever any file changes
+ // CLI --auto-watch --no-auto-watch
+ autoWatch : false,
+
+ // Start these browsers, currently available:
+ // - Chrome
+ // - ChromeCanary
+ // - Firefox
+ // - Opera
+ // - Safari (only Mac)
+ // - PhantomJS
+ // - IE (only Windows)
+ // CLI --browsers Chrome,Firefox,Safari
+ browsers : ['Firefox'],
+
+ // If browser does not capture in given timeout [ms], kill it
+ // CLI --capture-timeout 5000
+ captureTimeout : 5000,
+
+ // Auto run tests on start (when browsers are captured) and exit
+ // CLI --single-run --no-single-run
+ singleRun : true,
+
+ // report which specs are slower than 500ms
+ // CLI --report-slower-than 500
+ reportSlowerThan : 1000,
+
+ preprocessors : {
+ // '**/client/js/*.js': 'coverage'
+ },
+
+ plugins : [
+ 'karma-mocha',
+ // 'karma-chrome-launcher',
+ 'karma-firefox-launcher',
+ // 'karma-phantomjs-launcher'
+ ]
+ });
+};
diff --git a/test/lib/pixi/core/Matrix.js b/test/lib/pixi/core/Matrix.js
new file mode 100644
index 0000000..d26386b
--- /dev/null
+++ b/test/lib/pixi/core/Matrix.js
@@ -0,0 +1,40 @@
+
+function pixi_core_Matrix_confirmNewMat3(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(1);
+ expect(matrix[5]).to.equal(0);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(1);
+}
+
+function pixi_core_Matrix_confirmNewMat4(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[0]).to.equal(1);
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(0);
+ expect(matrix[5]).to.equal(1);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(0);
+ expect(matrix[9]).to.equal(0);
+ expect(matrix[10]).to.equal(1);
+ expect(matrix[11]).to.equal(0);
+ expect(matrix[12]).to.equal(0);
+ expect(matrix[13]).to.equal(0);
+ expect(matrix[14]).to.equal(0);
+ expect(matrix[15]).to.equal(1);
+}
diff --git a/test/lib/pixi/core/Point.js b/test/lib/pixi/core/Point.js
new file mode 100644
index 0000000..e5df07b
--- /dev/null
+++ b/test/lib/pixi/core/Point.js
@@ -0,0 +1,10 @@
+
+function pixi_core_Point_confirm(obj, x, y) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Point);
+ expect(obj).to.respondTo('clone');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+}
diff --git a/test/lib/pixi/core/Rectangle.js b/test/lib/pixi/core/Rectangle.js
new file mode 100644
index 0000000..23f0d12
--- /dev/null
+++ b/test/lib/pixi/core/Rectangle.js
@@ -0,0 +1,13 @@
+
+function pixi_core_Rectangle_confirm(obj, x, y, width, height) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Rectangle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+ expect(obj).to.have.property('width', width);
+ expect(obj).to.have.property('height', height);
+}
diff --git a/.gitignore b/.gitignore
index 12e1b62..0b88317 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
node_modules
.DS_Store
-.project
\ No newline at end of file
+.project
+*.log
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..63e4d7c
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,8 @@
+language: node_js
+node_js:
+ - 0.10
+
+before_script:
+ - npm install -g grunt-cli
+ - export DISPLAY=:99.0
+ - sh -e /etc/init.d/xvfb start
diff --git a/Gruntfile.js b/Gruntfile.js
index b083b49..103938c 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -1,10 +1,12 @@
+'use strict';
+
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-connect');
- grunt.loadNpmTasks('grunt-contrib-qunit');
grunt.loadNpmTasks('grunt-contrib-yuidoc');
+ grunt.loadTasks('tasks');
var root = 'src/pixi/',
debug = 'bin/pixi.dev.js',
@@ -79,7 +81,7 @@
},
files: {
srcBlob: '<%= dirs.src %>/**/*.js',
- testBlob: '<%= dirs.test %>/unit/**/*.js',
+ testBlob: '<%= dirs.test %>/{functional,lib/pixi,unit}/**/*.js',
build: '<%= dirs.build %>/pixi.dev.js',
buildMin: '<%= dirs.build %>/pixi.js'
},
@@ -94,7 +96,12 @@
},
jshint: {
beforeconcat: srcFiles,
- test: ['<%= files.testBlob %>'],
+ test: {
+ src: ['<%= files.testBlob %>'],
+ options: {
+ expr: true
+ }
+ },
options: {
asi: true,
smarttabs: true
@@ -128,12 +135,6 @@
]
},
connect: {
- qunit: {
- options: {
- port: grunt.option('port-test') || 9002,
- base: './'
- }
- },
test: {
options: {
port: grunt.option('port-test') || 9002,
@@ -142,13 +143,6 @@
}
}
},
- qunit: {
- all: {
- options: {
- urls: ['http://localhost:' + (grunt.option('port-test') || 9002) + '/test/index.html']
- }
- }
- },
yuidoc: {
compile: {
name: '<%= pkg.name %>',
@@ -161,6 +155,13 @@
outdir: '<%= dirs.docs %>'
}
}
+ },
+ karma: {
+ unit: {
+ configFile: 'test/karma.conf.js',
+ // browsers: ['Chrome'],
+ singleRun: true
+ }
}
});
@@ -182,9 +183,10 @@
}
)
- grunt.registerTask('default', ['concat', 'uglify', 'distribute']);
grunt.registerTask('build', ['concat', 'uglify', 'distribute']);
- grunt.registerTask('test', ['build', 'connect:qunit', 'qunit']);
+ grunt.registerTask('test', ['concat', 'jshint:test', 'karma']);
grunt.registerTask('docs', ['yuidoc']);
-
-}
\ No newline at end of file
+ grunt.registerTask('default', ['test', 'uglify', 'distribute']);
+ // Travis CI task.
+ grunt.registerTask('travis', ['test']);
+}
diff --git a/README.md b/README.md
index c62ef86..690cfe4 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,8 @@

+[](http://travis-ci.org/drkibitz/pixi.js)
+
#### JavaScript 2D Renderer ####
The aim of this project is to provide a fast lightweight 2D library that works
diff --git a/package.json b/package.json
index b373240..1246a68 100644
--- a/package.json
+++ b/package.json
@@ -18,14 +18,21 @@
"main": "bin/pixi.js",
+ "scripts": {
+ "test": "grunt travis --verbose"
+ },
+
"dependencies": {},
"devDependencies": {
"grunt": "~0.4.x",
- "grunt-contrib-jshint": "0.3.x",
+ "grunt-contrib-jshint": "0.6.x",
"grunt-contrib-uglify": "0.2.x",
- "grunt-contrib-connect": "0.2.x",
- "grunt-contrib-qunit": "0.2.x",
+ "grunt-contrib-connect": "0.3.x",
"grunt-contrib-yuidoc": "0.4.x",
- "grunt-contrib-concat": "0.1.x"
+ "grunt-contrib-concat": "0.3.x",
+ "chai": "~1.7.0",
+ "karma": "0.11.0",
+ "karma-firefox-launcher": "0.1.0",
+ "karma-mocha": "0.1.0"
}
}
diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js
index a7c520e..ee82bbd 100644
--- a/src/pixi/InteractionManager.js
+++ b/src/pixi/InteractionManager.js
@@ -62,7 +62,6 @@
this.onTouchEnd = this.onTouchEnd.bind(this);
this.onTouchMove = this.onTouchMove.bind(this);
-
this.last = 0;
}
diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js
index 1a95d20..eef1059 100644
--- a/src/pixi/core/Ellipse.js
+++ b/src/pixi/core/Ellipse.js
@@ -78,7 +78,7 @@
return (normx + normy < 0.25);
}
-PIXI.Ellipse.getBounds = function()
+PIXI.Ellipse.prototype.getBounds = function()
{
return new PIXI.Rectangle(this.x, this.y, this.width, this.height);
}
diff --git a/tasks/karma.js b/tasks/karma.js
new file mode 100644
index 0000000..c340485
--- /dev/null
+++ b/tasks/karma.js
@@ -0,0 +1,27 @@
+'use strict';
+
+var path = require('path');
+var server = require('karma').server;
+
+module.exports = function (grunt) {
+ grunt.registerMultiTask('karma', 'run karma.', function() {
+ var done = this.async();
+ var options = this.options({
+ background: false
+ });
+ var data = this.data;
+
+ //merge options onto data, with data taking precedence
+ data = grunt.util._.merge(options, data);
+ data.configFile = path.resolve(data.configFile);
+ if (data.configFile) {
+ data.configFile = grunt.template.process(data.configFile);
+ }
+
+ server.start(
+ data,
+ function(code) {
+ done(!code);
+ });
+ });
+};
diff --git a/test/functional/example-1-basics/bunny.png b/test/functional/example-1-basics/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/functional/example-1-basics/bunny.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-30.png b/test/functional/example-1-basics/frame-30.png
new file mode 100644
index 0000000..96e3409
--- /dev/null
+++ b/test/functional/example-1-basics/frame-30.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-60.png b/test/functional/example-1-basics/frame-60.png
new file mode 100644
index 0000000..af3f4ce
--- /dev/null
+++ b/test/functional/example-1-basics/frame-60.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-90.png b/test/functional/example-1-basics/frame-90.png
new file mode 100644
index 0000000..099b823
--- /dev/null
+++ b/test/functional/example-1-basics/frame-90.png
Binary files differ
diff --git a/test/functional/example-1-basics/index.js b/test/functional/example-1-basics/index.js
new file mode 100644
index 0000000..7ae7a98
--- /dev/null
+++ b/test/functional/example-1-basics/index.js
@@ -0,0 +1,133 @@
+describe('Example 1 - Basics', function () {
+ 'use strict';
+
+ var baseUri = '/base/test/functional/example-1-basics';
+ var expect = chai.expect;
+ var currentFrame = 0;
+ var frameEvents = {};
+ var stage;
+ var renderer;
+ var bunny;
+
+ function onFrame(frame, callback) {
+ frameEvents[frame] = callback;
+ }
+
+ function animate() {
+ currentFrame += 1;
+
+ requestAnimFrame( animate );
+
+ // just for fun, lets rotate mr rabbit a little
+ bunny.rotation += 0.1;
+
+ // render the stage
+ renderer.render(stage);
+
+ if (frameEvents[currentFrame])
+ frameEvents[currentFrame](currentFrame);
+ }
+
+ function initScene() {
+ // create an new instance of a pixi stage
+ stage = new PIXI.Stage(0x66FF99);
+
+ // create a renderer instance
+ renderer = PIXI.autoDetectRenderer(400, 300);
+ console.log('Is PIXI.WebGLRenderer: ' + (renderer instanceof PIXI.WebGLRenderer));
+
+ // add the renderer view element to the DOM
+ document.body.appendChild(renderer.view);
+
+ requestAnimFrame( animate );
+
+ // create a texture from an image path
+ var texture = PIXI.Texture.fromImage(baseUri + "/bunny.png");
+ // create a new Sprite using the texture
+ bunny = new PIXI.Sprite(texture);
+
+ // center the sprites anchor point
+ bunny.anchor.x = 0.5;
+ bunny.anchor.y = 0.5;
+
+ // move the sprite t the center of the screen
+ bunny.position.x = 200;
+ bunny.position.y = 150;
+
+ stage.addChild(bunny);
+ }
+
+ it('assets loaded', function (done) {
+ var loader = new PIXI.AssetLoader([
+ baseUri + '/bunny.png',
+ baseUri + '/frame-30.png',
+ baseUri + '/frame-60.png',
+ baseUri + '/frame-90.png'
+ ]);
+ // loader.on('onProgress', function (event) {
+ // console.log(event.content);
+ // });
+ loader.on('onComplete', function (event) {
+ done();
+ initScene();
+ });
+ loader.load();
+ });
+
+ it('frame 30 should match', function (done) {
+ this.timeout(700);
+ onFrame(30, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-30.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 60 should match', function (done) {
+ this.timeout(1200);
+ onFrame(60, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-60.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 90 should match', function (done) {
+ this.timeout(1700);
+ onFrame(90, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-90.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ // it('capture something', function (done) {
+ // this.timeout(2000000);
+ // onFrame(30, function () {
+ // var img = new Image();
+ // img.src = renderer.view.toDataURL('image/png');
+ // document.body.appendChild(img);
+ // });
+ // });
+});
diff --git a/test/index.html b/test/index.html
deleted file mode 100644
index 9cbcac5..0000000
--- a/test/index.html
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
- Pixi.js Test Suite
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/test/karma.conf.js b/test/karma.conf.js
new file mode 100644
index 0000000..c66a696
--- /dev/null
+++ b/test/karma.conf.js
@@ -0,0 +1,82 @@
+module.exports = function(config) {
+ config.set({
+
+ // base path, that will be used to resolve files and exclude
+ basePath : '../',
+
+ frameworks : ['mocha'],
+
+ // list of files / patterns to load in the browser
+ files : [
+ 'node_modules/chai/chai.js',
+ 'bin/pixi.dev.js',
+ 'test/lib/**/*.js',
+ 'test/unit/**/*.js',
+ // 'test/functional/**/*.js',
+ {pattern: 'test/**/*.png', watched: false, included: false, served: true}
+ ],
+
+ // list of files to exclude
+ exclude : [],
+
+ // use dolts reporter, as travis terminal does not support escaping sequences
+ // possible values: 'dots', 'progress', 'junit', 'teamcity'
+ // CLI --reporters progress
+ reporters : ['progress'],
+
+ // web server port
+ // CLI --port 9876
+ port : 9876,
+
+ // cli runner port
+ // CLI --runner-port 9100
+ runnerPort : 9100,
+
+ // enable / disable colors in the output (reporters and logs)
+ // CLI --colors --no-colors
+ colors : true,
+
+ // level of logging
+ // possible values: karma.LOG_DISABLE || karma.LOG_ERROR || karma.LOG_WARN || karma.LOG_INFO || karma.LOG_DEBUG
+ // CLI --log-level debug
+ logLevel : config.LOG_DEBUG,
+
+ // enable / disable watching file and executing tests whenever any file changes
+ // CLI --auto-watch --no-auto-watch
+ autoWatch : false,
+
+ // Start these browsers, currently available:
+ // - Chrome
+ // - ChromeCanary
+ // - Firefox
+ // - Opera
+ // - Safari (only Mac)
+ // - PhantomJS
+ // - IE (only Windows)
+ // CLI --browsers Chrome,Firefox,Safari
+ browsers : ['Firefox'],
+
+ // If browser does not capture in given timeout [ms], kill it
+ // CLI --capture-timeout 5000
+ captureTimeout : 5000,
+
+ // Auto run tests on start (when browsers are captured) and exit
+ // CLI --single-run --no-single-run
+ singleRun : true,
+
+ // report which specs are slower than 500ms
+ // CLI --report-slower-than 500
+ reportSlowerThan : 1000,
+
+ preprocessors : {
+ // '**/client/js/*.js': 'coverage'
+ },
+
+ plugins : [
+ 'karma-mocha',
+ // 'karma-chrome-launcher',
+ 'karma-firefox-launcher',
+ // 'karma-phantomjs-launcher'
+ ]
+ });
+};
diff --git a/test/lib/pixi/core/Matrix.js b/test/lib/pixi/core/Matrix.js
new file mode 100644
index 0000000..d26386b
--- /dev/null
+++ b/test/lib/pixi/core/Matrix.js
@@ -0,0 +1,40 @@
+
+function pixi_core_Matrix_confirmNewMat3(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(1);
+ expect(matrix[5]).to.equal(0);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(1);
+}
+
+function pixi_core_Matrix_confirmNewMat4(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[0]).to.equal(1);
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(0);
+ expect(matrix[5]).to.equal(1);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(0);
+ expect(matrix[9]).to.equal(0);
+ expect(matrix[10]).to.equal(1);
+ expect(matrix[11]).to.equal(0);
+ expect(matrix[12]).to.equal(0);
+ expect(matrix[13]).to.equal(0);
+ expect(matrix[14]).to.equal(0);
+ expect(matrix[15]).to.equal(1);
+}
diff --git a/test/lib/pixi/core/Point.js b/test/lib/pixi/core/Point.js
new file mode 100644
index 0000000..e5df07b
--- /dev/null
+++ b/test/lib/pixi/core/Point.js
@@ -0,0 +1,10 @@
+
+function pixi_core_Point_confirm(obj, x, y) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Point);
+ expect(obj).to.respondTo('clone');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+}
diff --git a/test/lib/pixi/core/Rectangle.js b/test/lib/pixi/core/Rectangle.js
new file mode 100644
index 0000000..23f0d12
--- /dev/null
+++ b/test/lib/pixi/core/Rectangle.js
@@ -0,0 +1,13 @@
+
+function pixi_core_Rectangle_confirm(obj, x, y, width, height) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Rectangle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+ expect(obj).to.have.property('width', width);
+ expect(obj).to.have.property('height', height);
+}
diff --git a/test/lib/pixi/display/DisplayObject.js b/test/lib/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..1388a7f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObject.js
@@ -0,0 +1,43 @@
+
+function pixi_display_DisplayObject_confirmNew(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObject);
+ expect(obj).to.respondTo('setInteractive');
+ expect(obj).to.respondTo('addFilter');
+ expect(obj).to.respondTo('removeFilter');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.property('last', obj);
+ expect(obj).to.have.property('first', obj);
+
+ expect(obj).to.contain.property('position');
+ pixi_core_Point_confirm(obj.position, 0, 0);
+ expect(obj).to.contain.property('scale');
+ pixi_core_Point_confirm(obj.scale, 1, 1);
+ expect(obj).to.contain.property('pivot');
+ pixi_core_Point_confirm(obj.pivot, 0, 0);
+
+ expect(obj).to.have.property('rotation', 0);
+ expect(obj).to.have.property('alpha', 1);
+ expect(obj).to.have.property('visible', true);
+ expect(obj).to.have.property('buttonMode', false);
+ expect(obj).to.have.property('parent', null);
+ expect(obj).to.have.property('worldAlpha', 1);
+
+ expect(obj).to.have.property('hitArea');
+ expect(obj).to.have.property('interactive'); // TODO: Have a better default value
+ expect('mask' in obj).to.be.true; // TODO: Have a better default value
+ expect(obj.mask).to.be.undefined;
+
+ expect(obj).to.have.property('renderable');
+ expect(obj).to.have.property('stage');
+
+ expect(obj).to.have.deep.property('worldTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ expect(obj).to.have.deep.property('localTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.localTransform);
+
+ expect(obj).to.have.deep.property('color.length', 0);
+ expect(obj).to.have.property('dynamic', true);
+}
diff --git a/.gitignore b/.gitignore
index 12e1b62..0b88317 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
node_modules
.DS_Store
-.project
\ No newline at end of file
+.project
+*.log
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..63e4d7c
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,8 @@
+language: node_js
+node_js:
+ - 0.10
+
+before_script:
+ - npm install -g grunt-cli
+ - export DISPLAY=:99.0
+ - sh -e /etc/init.d/xvfb start
diff --git a/Gruntfile.js b/Gruntfile.js
index b083b49..103938c 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -1,10 +1,12 @@
+'use strict';
+
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-connect');
- grunt.loadNpmTasks('grunt-contrib-qunit');
grunt.loadNpmTasks('grunt-contrib-yuidoc');
+ grunt.loadTasks('tasks');
var root = 'src/pixi/',
debug = 'bin/pixi.dev.js',
@@ -79,7 +81,7 @@
},
files: {
srcBlob: '<%= dirs.src %>/**/*.js',
- testBlob: '<%= dirs.test %>/unit/**/*.js',
+ testBlob: '<%= dirs.test %>/{functional,lib/pixi,unit}/**/*.js',
build: '<%= dirs.build %>/pixi.dev.js',
buildMin: '<%= dirs.build %>/pixi.js'
},
@@ -94,7 +96,12 @@
},
jshint: {
beforeconcat: srcFiles,
- test: ['<%= files.testBlob %>'],
+ test: {
+ src: ['<%= files.testBlob %>'],
+ options: {
+ expr: true
+ }
+ },
options: {
asi: true,
smarttabs: true
@@ -128,12 +135,6 @@
]
},
connect: {
- qunit: {
- options: {
- port: grunt.option('port-test') || 9002,
- base: './'
- }
- },
test: {
options: {
port: grunt.option('port-test') || 9002,
@@ -142,13 +143,6 @@
}
}
},
- qunit: {
- all: {
- options: {
- urls: ['http://localhost:' + (grunt.option('port-test') || 9002) + '/test/index.html']
- }
- }
- },
yuidoc: {
compile: {
name: '<%= pkg.name %>',
@@ -161,6 +155,13 @@
outdir: '<%= dirs.docs %>'
}
}
+ },
+ karma: {
+ unit: {
+ configFile: 'test/karma.conf.js',
+ // browsers: ['Chrome'],
+ singleRun: true
+ }
}
});
@@ -182,9 +183,10 @@
}
)
- grunt.registerTask('default', ['concat', 'uglify', 'distribute']);
grunt.registerTask('build', ['concat', 'uglify', 'distribute']);
- grunt.registerTask('test', ['build', 'connect:qunit', 'qunit']);
+ grunt.registerTask('test', ['concat', 'jshint:test', 'karma']);
grunt.registerTask('docs', ['yuidoc']);
-
-}
\ No newline at end of file
+ grunt.registerTask('default', ['test', 'uglify', 'distribute']);
+ // Travis CI task.
+ grunt.registerTask('travis', ['test']);
+}
diff --git a/README.md b/README.md
index c62ef86..690cfe4 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,8 @@

+[](http://travis-ci.org/drkibitz/pixi.js)
+
#### JavaScript 2D Renderer ####
The aim of this project is to provide a fast lightweight 2D library that works
diff --git a/package.json b/package.json
index b373240..1246a68 100644
--- a/package.json
+++ b/package.json
@@ -18,14 +18,21 @@
"main": "bin/pixi.js",
+ "scripts": {
+ "test": "grunt travis --verbose"
+ },
+
"dependencies": {},
"devDependencies": {
"grunt": "~0.4.x",
- "grunt-contrib-jshint": "0.3.x",
+ "grunt-contrib-jshint": "0.6.x",
"grunt-contrib-uglify": "0.2.x",
- "grunt-contrib-connect": "0.2.x",
- "grunt-contrib-qunit": "0.2.x",
+ "grunt-contrib-connect": "0.3.x",
"grunt-contrib-yuidoc": "0.4.x",
- "grunt-contrib-concat": "0.1.x"
+ "grunt-contrib-concat": "0.3.x",
+ "chai": "~1.7.0",
+ "karma": "0.11.0",
+ "karma-firefox-launcher": "0.1.0",
+ "karma-mocha": "0.1.0"
}
}
diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js
index a7c520e..ee82bbd 100644
--- a/src/pixi/InteractionManager.js
+++ b/src/pixi/InteractionManager.js
@@ -62,7 +62,6 @@
this.onTouchEnd = this.onTouchEnd.bind(this);
this.onTouchMove = this.onTouchMove.bind(this);
-
this.last = 0;
}
diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js
index 1a95d20..eef1059 100644
--- a/src/pixi/core/Ellipse.js
+++ b/src/pixi/core/Ellipse.js
@@ -78,7 +78,7 @@
return (normx + normy < 0.25);
}
-PIXI.Ellipse.getBounds = function()
+PIXI.Ellipse.prototype.getBounds = function()
{
return new PIXI.Rectangle(this.x, this.y, this.width, this.height);
}
diff --git a/tasks/karma.js b/tasks/karma.js
new file mode 100644
index 0000000..c340485
--- /dev/null
+++ b/tasks/karma.js
@@ -0,0 +1,27 @@
+'use strict';
+
+var path = require('path');
+var server = require('karma').server;
+
+module.exports = function (grunt) {
+ grunt.registerMultiTask('karma', 'run karma.', function() {
+ var done = this.async();
+ var options = this.options({
+ background: false
+ });
+ var data = this.data;
+
+ //merge options onto data, with data taking precedence
+ data = grunt.util._.merge(options, data);
+ data.configFile = path.resolve(data.configFile);
+ if (data.configFile) {
+ data.configFile = grunt.template.process(data.configFile);
+ }
+
+ server.start(
+ data,
+ function(code) {
+ done(!code);
+ });
+ });
+};
diff --git a/test/functional/example-1-basics/bunny.png b/test/functional/example-1-basics/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/functional/example-1-basics/bunny.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-30.png b/test/functional/example-1-basics/frame-30.png
new file mode 100644
index 0000000..96e3409
--- /dev/null
+++ b/test/functional/example-1-basics/frame-30.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-60.png b/test/functional/example-1-basics/frame-60.png
new file mode 100644
index 0000000..af3f4ce
--- /dev/null
+++ b/test/functional/example-1-basics/frame-60.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-90.png b/test/functional/example-1-basics/frame-90.png
new file mode 100644
index 0000000..099b823
--- /dev/null
+++ b/test/functional/example-1-basics/frame-90.png
Binary files differ
diff --git a/test/functional/example-1-basics/index.js b/test/functional/example-1-basics/index.js
new file mode 100644
index 0000000..7ae7a98
--- /dev/null
+++ b/test/functional/example-1-basics/index.js
@@ -0,0 +1,133 @@
+describe('Example 1 - Basics', function () {
+ 'use strict';
+
+ var baseUri = '/base/test/functional/example-1-basics';
+ var expect = chai.expect;
+ var currentFrame = 0;
+ var frameEvents = {};
+ var stage;
+ var renderer;
+ var bunny;
+
+ function onFrame(frame, callback) {
+ frameEvents[frame] = callback;
+ }
+
+ function animate() {
+ currentFrame += 1;
+
+ requestAnimFrame( animate );
+
+ // just for fun, lets rotate mr rabbit a little
+ bunny.rotation += 0.1;
+
+ // render the stage
+ renderer.render(stage);
+
+ if (frameEvents[currentFrame])
+ frameEvents[currentFrame](currentFrame);
+ }
+
+ function initScene() {
+ // create an new instance of a pixi stage
+ stage = new PIXI.Stage(0x66FF99);
+
+ // create a renderer instance
+ renderer = PIXI.autoDetectRenderer(400, 300);
+ console.log('Is PIXI.WebGLRenderer: ' + (renderer instanceof PIXI.WebGLRenderer));
+
+ // add the renderer view element to the DOM
+ document.body.appendChild(renderer.view);
+
+ requestAnimFrame( animate );
+
+ // create a texture from an image path
+ var texture = PIXI.Texture.fromImage(baseUri + "/bunny.png");
+ // create a new Sprite using the texture
+ bunny = new PIXI.Sprite(texture);
+
+ // center the sprites anchor point
+ bunny.anchor.x = 0.5;
+ bunny.anchor.y = 0.5;
+
+ // move the sprite t the center of the screen
+ bunny.position.x = 200;
+ bunny.position.y = 150;
+
+ stage.addChild(bunny);
+ }
+
+ it('assets loaded', function (done) {
+ var loader = new PIXI.AssetLoader([
+ baseUri + '/bunny.png',
+ baseUri + '/frame-30.png',
+ baseUri + '/frame-60.png',
+ baseUri + '/frame-90.png'
+ ]);
+ // loader.on('onProgress', function (event) {
+ // console.log(event.content);
+ // });
+ loader.on('onComplete', function (event) {
+ done();
+ initScene();
+ });
+ loader.load();
+ });
+
+ it('frame 30 should match', function (done) {
+ this.timeout(700);
+ onFrame(30, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-30.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 60 should match', function (done) {
+ this.timeout(1200);
+ onFrame(60, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-60.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 90 should match', function (done) {
+ this.timeout(1700);
+ onFrame(90, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-90.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ // it('capture something', function (done) {
+ // this.timeout(2000000);
+ // onFrame(30, function () {
+ // var img = new Image();
+ // img.src = renderer.view.toDataURL('image/png');
+ // document.body.appendChild(img);
+ // });
+ // });
+});
diff --git a/test/index.html b/test/index.html
deleted file mode 100644
index 9cbcac5..0000000
--- a/test/index.html
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
- Pixi.js Test Suite
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/test/karma.conf.js b/test/karma.conf.js
new file mode 100644
index 0000000..c66a696
--- /dev/null
+++ b/test/karma.conf.js
@@ -0,0 +1,82 @@
+module.exports = function(config) {
+ config.set({
+
+ // base path, that will be used to resolve files and exclude
+ basePath : '../',
+
+ frameworks : ['mocha'],
+
+ // list of files / patterns to load in the browser
+ files : [
+ 'node_modules/chai/chai.js',
+ 'bin/pixi.dev.js',
+ 'test/lib/**/*.js',
+ 'test/unit/**/*.js',
+ // 'test/functional/**/*.js',
+ {pattern: 'test/**/*.png', watched: false, included: false, served: true}
+ ],
+
+ // list of files to exclude
+ exclude : [],
+
+ // use dolts reporter, as travis terminal does not support escaping sequences
+ // possible values: 'dots', 'progress', 'junit', 'teamcity'
+ // CLI --reporters progress
+ reporters : ['progress'],
+
+ // web server port
+ // CLI --port 9876
+ port : 9876,
+
+ // cli runner port
+ // CLI --runner-port 9100
+ runnerPort : 9100,
+
+ // enable / disable colors in the output (reporters and logs)
+ // CLI --colors --no-colors
+ colors : true,
+
+ // level of logging
+ // possible values: karma.LOG_DISABLE || karma.LOG_ERROR || karma.LOG_WARN || karma.LOG_INFO || karma.LOG_DEBUG
+ // CLI --log-level debug
+ logLevel : config.LOG_DEBUG,
+
+ // enable / disable watching file and executing tests whenever any file changes
+ // CLI --auto-watch --no-auto-watch
+ autoWatch : false,
+
+ // Start these browsers, currently available:
+ // - Chrome
+ // - ChromeCanary
+ // - Firefox
+ // - Opera
+ // - Safari (only Mac)
+ // - PhantomJS
+ // - IE (only Windows)
+ // CLI --browsers Chrome,Firefox,Safari
+ browsers : ['Firefox'],
+
+ // If browser does not capture in given timeout [ms], kill it
+ // CLI --capture-timeout 5000
+ captureTimeout : 5000,
+
+ // Auto run tests on start (when browsers are captured) and exit
+ // CLI --single-run --no-single-run
+ singleRun : true,
+
+ // report which specs are slower than 500ms
+ // CLI --report-slower-than 500
+ reportSlowerThan : 1000,
+
+ preprocessors : {
+ // '**/client/js/*.js': 'coverage'
+ },
+
+ plugins : [
+ 'karma-mocha',
+ // 'karma-chrome-launcher',
+ 'karma-firefox-launcher',
+ // 'karma-phantomjs-launcher'
+ ]
+ });
+};
diff --git a/test/lib/pixi/core/Matrix.js b/test/lib/pixi/core/Matrix.js
new file mode 100644
index 0000000..d26386b
--- /dev/null
+++ b/test/lib/pixi/core/Matrix.js
@@ -0,0 +1,40 @@
+
+function pixi_core_Matrix_confirmNewMat3(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(1);
+ expect(matrix[5]).to.equal(0);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(1);
+}
+
+function pixi_core_Matrix_confirmNewMat4(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[0]).to.equal(1);
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(0);
+ expect(matrix[5]).to.equal(1);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(0);
+ expect(matrix[9]).to.equal(0);
+ expect(matrix[10]).to.equal(1);
+ expect(matrix[11]).to.equal(0);
+ expect(matrix[12]).to.equal(0);
+ expect(matrix[13]).to.equal(0);
+ expect(matrix[14]).to.equal(0);
+ expect(matrix[15]).to.equal(1);
+}
diff --git a/test/lib/pixi/core/Point.js b/test/lib/pixi/core/Point.js
new file mode 100644
index 0000000..e5df07b
--- /dev/null
+++ b/test/lib/pixi/core/Point.js
@@ -0,0 +1,10 @@
+
+function pixi_core_Point_confirm(obj, x, y) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Point);
+ expect(obj).to.respondTo('clone');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+}
diff --git a/test/lib/pixi/core/Rectangle.js b/test/lib/pixi/core/Rectangle.js
new file mode 100644
index 0000000..23f0d12
--- /dev/null
+++ b/test/lib/pixi/core/Rectangle.js
@@ -0,0 +1,13 @@
+
+function pixi_core_Rectangle_confirm(obj, x, y, width, height) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Rectangle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+ expect(obj).to.have.property('width', width);
+ expect(obj).to.have.property('height', height);
+}
diff --git a/test/lib/pixi/display/DisplayObject.js b/test/lib/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..1388a7f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObject.js
@@ -0,0 +1,43 @@
+
+function pixi_display_DisplayObject_confirmNew(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObject);
+ expect(obj).to.respondTo('setInteractive');
+ expect(obj).to.respondTo('addFilter');
+ expect(obj).to.respondTo('removeFilter');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.property('last', obj);
+ expect(obj).to.have.property('first', obj);
+
+ expect(obj).to.contain.property('position');
+ pixi_core_Point_confirm(obj.position, 0, 0);
+ expect(obj).to.contain.property('scale');
+ pixi_core_Point_confirm(obj.scale, 1, 1);
+ expect(obj).to.contain.property('pivot');
+ pixi_core_Point_confirm(obj.pivot, 0, 0);
+
+ expect(obj).to.have.property('rotation', 0);
+ expect(obj).to.have.property('alpha', 1);
+ expect(obj).to.have.property('visible', true);
+ expect(obj).to.have.property('buttonMode', false);
+ expect(obj).to.have.property('parent', null);
+ expect(obj).to.have.property('worldAlpha', 1);
+
+ expect(obj).to.have.property('hitArea');
+ expect(obj).to.have.property('interactive'); // TODO: Have a better default value
+ expect('mask' in obj).to.be.true; // TODO: Have a better default value
+ expect(obj.mask).to.be.undefined;
+
+ expect(obj).to.have.property('renderable');
+ expect(obj).to.have.property('stage');
+
+ expect(obj).to.have.deep.property('worldTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ expect(obj).to.have.deep.property('localTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.localTransform);
+
+ expect(obj).to.have.deep.property('color.length', 0);
+ expect(obj).to.have.property('dynamic', true);
+}
diff --git a/test/lib/pixi/display/DisplayObjectContainer.js b/test/lib/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..085c59f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,16 @@
+
+function pixi_display_DisplayObjectContainer_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObject_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObjectContainer);
+ expect(obj).to.respondTo('addChild');
+ expect(obj).to.respondTo('addChildAt');
+ expect(obj).to.respondTo('swapChildren');
+ expect(obj).to.respondTo('getChildAt');
+ expect(obj).to.respondTo('removeChild');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('children.length', 0);
+}
diff --git a/.gitignore b/.gitignore
index 12e1b62..0b88317 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
node_modules
.DS_Store
-.project
\ No newline at end of file
+.project
+*.log
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..63e4d7c
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,8 @@
+language: node_js
+node_js:
+ - 0.10
+
+before_script:
+ - npm install -g grunt-cli
+ - export DISPLAY=:99.0
+ - sh -e /etc/init.d/xvfb start
diff --git a/Gruntfile.js b/Gruntfile.js
index b083b49..103938c 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -1,10 +1,12 @@
+'use strict';
+
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-connect');
- grunt.loadNpmTasks('grunt-contrib-qunit');
grunt.loadNpmTasks('grunt-contrib-yuidoc');
+ grunt.loadTasks('tasks');
var root = 'src/pixi/',
debug = 'bin/pixi.dev.js',
@@ -79,7 +81,7 @@
},
files: {
srcBlob: '<%= dirs.src %>/**/*.js',
- testBlob: '<%= dirs.test %>/unit/**/*.js',
+ testBlob: '<%= dirs.test %>/{functional,lib/pixi,unit}/**/*.js',
build: '<%= dirs.build %>/pixi.dev.js',
buildMin: '<%= dirs.build %>/pixi.js'
},
@@ -94,7 +96,12 @@
},
jshint: {
beforeconcat: srcFiles,
- test: ['<%= files.testBlob %>'],
+ test: {
+ src: ['<%= files.testBlob %>'],
+ options: {
+ expr: true
+ }
+ },
options: {
asi: true,
smarttabs: true
@@ -128,12 +135,6 @@
]
},
connect: {
- qunit: {
- options: {
- port: grunt.option('port-test') || 9002,
- base: './'
- }
- },
test: {
options: {
port: grunt.option('port-test') || 9002,
@@ -142,13 +143,6 @@
}
}
},
- qunit: {
- all: {
- options: {
- urls: ['http://localhost:' + (grunt.option('port-test') || 9002) + '/test/index.html']
- }
- }
- },
yuidoc: {
compile: {
name: '<%= pkg.name %>',
@@ -161,6 +155,13 @@
outdir: '<%= dirs.docs %>'
}
}
+ },
+ karma: {
+ unit: {
+ configFile: 'test/karma.conf.js',
+ // browsers: ['Chrome'],
+ singleRun: true
+ }
}
});
@@ -182,9 +183,10 @@
}
)
- grunt.registerTask('default', ['concat', 'uglify', 'distribute']);
grunt.registerTask('build', ['concat', 'uglify', 'distribute']);
- grunt.registerTask('test', ['build', 'connect:qunit', 'qunit']);
+ grunt.registerTask('test', ['concat', 'jshint:test', 'karma']);
grunt.registerTask('docs', ['yuidoc']);
-
-}
\ No newline at end of file
+ grunt.registerTask('default', ['test', 'uglify', 'distribute']);
+ // Travis CI task.
+ grunt.registerTask('travis', ['test']);
+}
diff --git a/README.md b/README.md
index c62ef86..690cfe4 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,8 @@

+[](http://travis-ci.org/drkibitz/pixi.js)
+
#### JavaScript 2D Renderer ####
The aim of this project is to provide a fast lightweight 2D library that works
diff --git a/package.json b/package.json
index b373240..1246a68 100644
--- a/package.json
+++ b/package.json
@@ -18,14 +18,21 @@
"main": "bin/pixi.js",
+ "scripts": {
+ "test": "grunt travis --verbose"
+ },
+
"dependencies": {},
"devDependencies": {
"grunt": "~0.4.x",
- "grunt-contrib-jshint": "0.3.x",
+ "grunt-contrib-jshint": "0.6.x",
"grunt-contrib-uglify": "0.2.x",
- "grunt-contrib-connect": "0.2.x",
- "grunt-contrib-qunit": "0.2.x",
+ "grunt-contrib-connect": "0.3.x",
"grunt-contrib-yuidoc": "0.4.x",
- "grunt-contrib-concat": "0.1.x"
+ "grunt-contrib-concat": "0.3.x",
+ "chai": "~1.7.0",
+ "karma": "0.11.0",
+ "karma-firefox-launcher": "0.1.0",
+ "karma-mocha": "0.1.0"
}
}
diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js
index a7c520e..ee82bbd 100644
--- a/src/pixi/InteractionManager.js
+++ b/src/pixi/InteractionManager.js
@@ -62,7 +62,6 @@
this.onTouchEnd = this.onTouchEnd.bind(this);
this.onTouchMove = this.onTouchMove.bind(this);
-
this.last = 0;
}
diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js
index 1a95d20..eef1059 100644
--- a/src/pixi/core/Ellipse.js
+++ b/src/pixi/core/Ellipse.js
@@ -78,7 +78,7 @@
return (normx + normy < 0.25);
}
-PIXI.Ellipse.getBounds = function()
+PIXI.Ellipse.prototype.getBounds = function()
{
return new PIXI.Rectangle(this.x, this.y, this.width, this.height);
}
diff --git a/tasks/karma.js b/tasks/karma.js
new file mode 100644
index 0000000..c340485
--- /dev/null
+++ b/tasks/karma.js
@@ -0,0 +1,27 @@
+'use strict';
+
+var path = require('path');
+var server = require('karma').server;
+
+module.exports = function (grunt) {
+ grunt.registerMultiTask('karma', 'run karma.', function() {
+ var done = this.async();
+ var options = this.options({
+ background: false
+ });
+ var data = this.data;
+
+ //merge options onto data, with data taking precedence
+ data = grunt.util._.merge(options, data);
+ data.configFile = path.resolve(data.configFile);
+ if (data.configFile) {
+ data.configFile = grunt.template.process(data.configFile);
+ }
+
+ server.start(
+ data,
+ function(code) {
+ done(!code);
+ });
+ });
+};
diff --git a/test/functional/example-1-basics/bunny.png b/test/functional/example-1-basics/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/functional/example-1-basics/bunny.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-30.png b/test/functional/example-1-basics/frame-30.png
new file mode 100644
index 0000000..96e3409
--- /dev/null
+++ b/test/functional/example-1-basics/frame-30.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-60.png b/test/functional/example-1-basics/frame-60.png
new file mode 100644
index 0000000..af3f4ce
--- /dev/null
+++ b/test/functional/example-1-basics/frame-60.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-90.png b/test/functional/example-1-basics/frame-90.png
new file mode 100644
index 0000000..099b823
--- /dev/null
+++ b/test/functional/example-1-basics/frame-90.png
Binary files differ
diff --git a/test/functional/example-1-basics/index.js b/test/functional/example-1-basics/index.js
new file mode 100644
index 0000000..7ae7a98
--- /dev/null
+++ b/test/functional/example-1-basics/index.js
@@ -0,0 +1,133 @@
+describe('Example 1 - Basics', function () {
+ 'use strict';
+
+ var baseUri = '/base/test/functional/example-1-basics';
+ var expect = chai.expect;
+ var currentFrame = 0;
+ var frameEvents = {};
+ var stage;
+ var renderer;
+ var bunny;
+
+ function onFrame(frame, callback) {
+ frameEvents[frame] = callback;
+ }
+
+ function animate() {
+ currentFrame += 1;
+
+ requestAnimFrame( animate );
+
+ // just for fun, lets rotate mr rabbit a little
+ bunny.rotation += 0.1;
+
+ // render the stage
+ renderer.render(stage);
+
+ if (frameEvents[currentFrame])
+ frameEvents[currentFrame](currentFrame);
+ }
+
+ function initScene() {
+ // create an new instance of a pixi stage
+ stage = new PIXI.Stage(0x66FF99);
+
+ // create a renderer instance
+ renderer = PIXI.autoDetectRenderer(400, 300);
+ console.log('Is PIXI.WebGLRenderer: ' + (renderer instanceof PIXI.WebGLRenderer));
+
+ // add the renderer view element to the DOM
+ document.body.appendChild(renderer.view);
+
+ requestAnimFrame( animate );
+
+ // create a texture from an image path
+ var texture = PIXI.Texture.fromImage(baseUri + "/bunny.png");
+ // create a new Sprite using the texture
+ bunny = new PIXI.Sprite(texture);
+
+ // center the sprites anchor point
+ bunny.anchor.x = 0.5;
+ bunny.anchor.y = 0.5;
+
+ // move the sprite t the center of the screen
+ bunny.position.x = 200;
+ bunny.position.y = 150;
+
+ stage.addChild(bunny);
+ }
+
+ it('assets loaded', function (done) {
+ var loader = new PIXI.AssetLoader([
+ baseUri + '/bunny.png',
+ baseUri + '/frame-30.png',
+ baseUri + '/frame-60.png',
+ baseUri + '/frame-90.png'
+ ]);
+ // loader.on('onProgress', function (event) {
+ // console.log(event.content);
+ // });
+ loader.on('onComplete', function (event) {
+ done();
+ initScene();
+ });
+ loader.load();
+ });
+
+ it('frame 30 should match', function (done) {
+ this.timeout(700);
+ onFrame(30, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-30.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 60 should match', function (done) {
+ this.timeout(1200);
+ onFrame(60, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-60.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 90 should match', function (done) {
+ this.timeout(1700);
+ onFrame(90, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-90.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ // it('capture something', function (done) {
+ // this.timeout(2000000);
+ // onFrame(30, function () {
+ // var img = new Image();
+ // img.src = renderer.view.toDataURL('image/png');
+ // document.body.appendChild(img);
+ // });
+ // });
+});
diff --git a/test/index.html b/test/index.html
deleted file mode 100644
index 9cbcac5..0000000
--- a/test/index.html
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
- Pixi.js Test Suite
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/test/karma.conf.js b/test/karma.conf.js
new file mode 100644
index 0000000..c66a696
--- /dev/null
+++ b/test/karma.conf.js
@@ -0,0 +1,82 @@
+module.exports = function(config) {
+ config.set({
+
+ // base path, that will be used to resolve files and exclude
+ basePath : '../',
+
+ frameworks : ['mocha'],
+
+ // list of files / patterns to load in the browser
+ files : [
+ 'node_modules/chai/chai.js',
+ 'bin/pixi.dev.js',
+ 'test/lib/**/*.js',
+ 'test/unit/**/*.js',
+ // 'test/functional/**/*.js',
+ {pattern: 'test/**/*.png', watched: false, included: false, served: true}
+ ],
+
+ // list of files to exclude
+ exclude : [],
+
+ // use dolts reporter, as travis terminal does not support escaping sequences
+ // possible values: 'dots', 'progress', 'junit', 'teamcity'
+ // CLI --reporters progress
+ reporters : ['progress'],
+
+ // web server port
+ // CLI --port 9876
+ port : 9876,
+
+ // cli runner port
+ // CLI --runner-port 9100
+ runnerPort : 9100,
+
+ // enable / disable colors in the output (reporters and logs)
+ // CLI --colors --no-colors
+ colors : true,
+
+ // level of logging
+ // possible values: karma.LOG_DISABLE || karma.LOG_ERROR || karma.LOG_WARN || karma.LOG_INFO || karma.LOG_DEBUG
+ // CLI --log-level debug
+ logLevel : config.LOG_DEBUG,
+
+ // enable / disable watching file and executing tests whenever any file changes
+ // CLI --auto-watch --no-auto-watch
+ autoWatch : false,
+
+ // Start these browsers, currently available:
+ // - Chrome
+ // - ChromeCanary
+ // - Firefox
+ // - Opera
+ // - Safari (only Mac)
+ // - PhantomJS
+ // - IE (only Windows)
+ // CLI --browsers Chrome,Firefox,Safari
+ browsers : ['Firefox'],
+
+ // If browser does not capture in given timeout [ms], kill it
+ // CLI --capture-timeout 5000
+ captureTimeout : 5000,
+
+ // Auto run tests on start (when browsers are captured) and exit
+ // CLI --single-run --no-single-run
+ singleRun : true,
+
+ // report which specs are slower than 500ms
+ // CLI --report-slower-than 500
+ reportSlowerThan : 1000,
+
+ preprocessors : {
+ // '**/client/js/*.js': 'coverage'
+ },
+
+ plugins : [
+ 'karma-mocha',
+ // 'karma-chrome-launcher',
+ 'karma-firefox-launcher',
+ // 'karma-phantomjs-launcher'
+ ]
+ });
+};
diff --git a/test/lib/pixi/core/Matrix.js b/test/lib/pixi/core/Matrix.js
new file mode 100644
index 0000000..d26386b
--- /dev/null
+++ b/test/lib/pixi/core/Matrix.js
@@ -0,0 +1,40 @@
+
+function pixi_core_Matrix_confirmNewMat3(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(1);
+ expect(matrix[5]).to.equal(0);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(1);
+}
+
+function pixi_core_Matrix_confirmNewMat4(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[0]).to.equal(1);
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(0);
+ expect(matrix[5]).to.equal(1);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(0);
+ expect(matrix[9]).to.equal(0);
+ expect(matrix[10]).to.equal(1);
+ expect(matrix[11]).to.equal(0);
+ expect(matrix[12]).to.equal(0);
+ expect(matrix[13]).to.equal(0);
+ expect(matrix[14]).to.equal(0);
+ expect(matrix[15]).to.equal(1);
+}
diff --git a/test/lib/pixi/core/Point.js b/test/lib/pixi/core/Point.js
new file mode 100644
index 0000000..e5df07b
--- /dev/null
+++ b/test/lib/pixi/core/Point.js
@@ -0,0 +1,10 @@
+
+function pixi_core_Point_confirm(obj, x, y) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Point);
+ expect(obj).to.respondTo('clone');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+}
diff --git a/test/lib/pixi/core/Rectangle.js b/test/lib/pixi/core/Rectangle.js
new file mode 100644
index 0000000..23f0d12
--- /dev/null
+++ b/test/lib/pixi/core/Rectangle.js
@@ -0,0 +1,13 @@
+
+function pixi_core_Rectangle_confirm(obj, x, y, width, height) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Rectangle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+ expect(obj).to.have.property('width', width);
+ expect(obj).to.have.property('height', height);
+}
diff --git a/test/lib/pixi/display/DisplayObject.js b/test/lib/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..1388a7f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObject.js
@@ -0,0 +1,43 @@
+
+function pixi_display_DisplayObject_confirmNew(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObject);
+ expect(obj).to.respondTo('setInteractive');
+ expect(obj).to.respondTo('addFilter');
+ expect(obj).to.respondTo('removeFilter');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.property('last', obj);
+ expect(obj).to.have.property('first', obj);
+
+ expect(obj).to.contain.property('position');
+ pixi_core_Point_confirm(obj.position, 0, 0);
+ expect(obj).to.contain.property('scale');
+ pixi_core_Point_confirm(obj.scale, 1, 1);
+ expect(obj).to.contain.property('pivot');
+ pixi_core_Point_confirm(obj.pivot, 0, 0);
+
+ expect(obj).to.have.property('rotation', 0);
+ expect(obj).to.have.property('alpha', 1);
+ expect(obj).to.have.property('visible', true);
+ expect(obj).to.have.property('buttonMode', false);
+ expect(obj).to.have.property('parent', null);
+ expect(obj).to.have.property('worldAlpha', 1);
+
+ expect(obj).to.have.property('hitArea');
+ expect(obj).to.have.property('interactive'); // TODO: Have a better default value
+ expect('mask' in obj).to.be.true; // TODO: Have a better default value
+ expect(obj.mask).to.be.undefined;
+
+ expect(obj).to.have.property('renderable');
+ expect(obj).to.have.property('stage');
+
+ expect(obj).to.have.deep.property('worldTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ expect(obj).to.have.deep.property('localTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.localTransform);
+
+ expect(obj).to.have.deep.property('color.length', 0);
+ expect(obj).to.have.property('dynamic', true);
+}
diff --git a/test/lib/pixi/display/DisplayObjectContainer.js b/test/lib/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..085c59f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,16 @@
+
+function pixi_display_DisplayObjectContainer_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObject_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObjectContainer);
+ expect(obj).to.respondTo('addChild');
+ expect(obj).to.respondTo('addChildAt');
+ expect(obj).to.respondTo('swapChildren');
+ expect(obj).to.respondTo('getChildAt');
+ expect(obj).to.respondTo('removeChild');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('children.length', 0);
+}
diff --git a/test/lib/pixi/display/Sprite.js b/test/lib/pixi/display/Sprite.js
new file mode 100644
index 0000000..cc7a2d6
--- /dev/null
+++ b/test/lib/pixi/display/Sprite.js
@@ -0,0 +1,28 @@
+
+function pixi_display_Sprite_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Sprite);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', true);
+ expect(obj).to.have.property('stage', null);
+
+ expect(obj).to.have.property('anchor');
+ pixi_core_Point_confirm(obj.anchor, 0, 0);
+
+ expect(obj).to.have.property('blendMode', PIXI.blendModes.NORMAL);
+ expect(obj).to.have.property('width', 1); // TODO: is 1 expected
+ expect(obj).to.have.property('height', 1); // TODO: is 1 expected
+
+ // FIXME: Just make this a boolean that is always there
+ expect(!!obj.updateFrame).to.equal(obj.texture.baseTexture.hasLoaded);
+
+ expect(obj).to.have.property('texture');
+ pixi_textures_Texture_confirmNew(obj.texture, done);
+}
diff --git a/.gitignore b/.gitignore
index 12e1b62..0b88317 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
node_modules
.DS_Store
-.project
\ No newline at end of file
+.project
+*.log
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..63e4d7c
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,8 @@
+language: node_js
+node_js:
+ - 0.10
+
+before_script:
+ - npm install -g grunt-cli
+ - export DISPLAY=:99.0
+ - sh -e /etc/init.d/xvfb start
diff --git a/Gruntfile.js b/Gruntfile.js
index b083b49..103938c 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -1,10 +1,12 @@
+'use strict';
+
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-connect');
- grunt.loadNpmTasks('grunt-contrib-qunit');
grunt.loadNpmTasks('grunt-contrib-yuidoc');
+ grunt.loadTasks('tasks');
var root = 'src/pixi/',
debug = 'bin/pixi.dev.js',
@@ -79,7 +81,7 @@
},
files: {
srcBlob: '<%= dirs.src %>/**/*.js',
- testBlob: '<%= dirs.test %>/unit/**/*.js',
+ testBlob: '<%= dirs.test %>/{functional,lib/pixi,unit}/**/*.js',
build: '<%= dirs.build %>/pixi.dev.js',
buildMin: '<%= dirs.build %>/pixi.js'
},
@@ -94,7 +96,12 @@
},
jshint: {
beforeconcat: srcFiles,
- test: ['<%= files.testBlob %>'],
+ test: {
+ src: ['<%= files.testBlob %>'],
+ options: {
+ expr: true
+ }
+ },
options: {
asi: true,
smarttabs: true
@@ -128,12 +135,6 @@
]
},
connect: {
- qunit: {
- options: {
- port: grunt.option('port-test') || 9002,
- base: './'
- }
- },
test: {
options: {
port: grunt.option('port-test') || 9002,
@@ -142,13 +143,6 @@
}
}
},
- qunit: {
- all: {
- options: {
- urls: ['http://localhost:' + (grunt.option('port-test') || 9002) + '/test/index.html']
- }
- }
- },
yuidoc: {
compile: {
name: '<%= pkg.name %>',
@@ -161,6 +155,13 @@
outdir: '<%= dirs.docs %>'
}
}
+ },
+ karma: {
+ unit: {
+ configFile: 'test/karma.conf.js',
+ // browsers: ['Chrome'],
+ singleRun: true
+ }
}
});
@@ -182,9 +183,10 @@
}
)
- grunt.registerTask('default', ['concat', 'uglify', 'distribute']);
grunt.registerTask('build', ['concat', 'uglify', 'distribute']);
- grunt.registerTask('test', ['build', 'connect:qunit', 'qunit']);
+ grunt.registerTask('test', ['concat', 'jshint:test', 'karma']);
grunt.registerTask('docs', ['yuidoc']);
-
-}
\ No newline at end of file
+ grunt.registerTask('default', ['test', 'uglify', 'distribute']);
+ // Travis CI task.
+ grunt.registerTask('travis', ['test']);
+}
diff --git a/README.md b/README.md
index c62ef86..690cfe4 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,8 @@

+[](http://travis-ci.org/drkibitz/pixi.js)
+
#### JavaScript 2D Renderer ####
The aim of this project is to provide a fast lightweight 2D library that works
diff --git a/package.json b/package.json
index b373240..1246a68 100644
--- a/package.json
+++ b/package.json
@@ -18,14 +18,21 @@
"main": "bin/pixi.js",
+ "scripts": {
+ "test": "grunt travis --verbose"
+ },
+
"dependencies": {},
"devDependencies": {
"grunt": "~0.4.x",
- "grunt-contrib-jshint": "0.3.x",
+ "grunt-contrib-jshint": "0.6.x",
"grunt-contrib-uglify": "0.2.x",
- "grunt-contrib-connect": "0.2.x",
- "grunt-contrib-qunit": "0.2.x",
+ "grunt-contrib-connect": "0.3.x",
"grunt-contrib-yuidoc": "0.4.x",
- "grunt-contrib-concat": "0.1.x"
+ "grunt-contrib-concat": "0.3.x",
+ "chai": "~1.7.0",
+ "karma": "0.11.0",
+ "karma-firefox-launcher": "0.1.0",
+ "karma-mocha": "0.1.0"
}
}
diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js
index a7c520e..ee82bbd 100644
--- a/src/pixi/InteractionManager.js
+++ b/src/pixi/InteractionManager.js
@@ -62,7 +62,6 @@
this.onTouchEnd = this.onTouchEnd.bind(this);
this.onTouchMove = this.onTouchMove.bind(this);
-
this.last = 0;
}
diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js
index 1a95d20..eef1059 100644
--- a/src/pixi/core/Ellipse.js
+++ b/src/pixi/core/Ellipse.js
@@ -78,7 +78,7 @@
return (normx + normy < 0.25);
}
-PIXI.Ellipse.getBounds = function()
+PIXI.Ellipse.prototype.getBounds = function()
{
return new PIXI.Rectangle(this.x, this.y, this.width, this.height);
}
diff --git a/tasks/karma.js b/tasks/karma.js
new file mode 100644
index 0000000..c340485
--- /dev/null
+++ b/tasks/karma.js
@@ -0,0 +1,27 @@
+'use strict';
+
+var path = require('path');
+var server = require('karma').server;
+
+module.exports = function (grunt) {
+ grunt.registerMultiTask('karma', 'run karma.', function() {
+ var done = this.async();
+ var options = this.options({
+ background: false
+ });
+ var data = this.data;
+
+ //merge options onto data, with data taking precedence
+ data = grunt.util._.merge(options, data);
+ data.configFile = path.resolve(data.configFile);
+ if (data.configFile) {
+ data.configFile = grunt.template.process(data.configFile);
+ }
+
+ server.start(
+ data,
+ function(code) {
+ done(!code);
+ });
+ });
+};
diff --git a/test/functional/example-1-basics/bunny.png b/test/functional/example-1-basics/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/functional/example-1-basics/bunny.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-30.png b/test/functional/example-1-basics/frame-30.png
new file mode 100644
index 0000000..96e3409
--- /dev/null
+++ b/test/functional/example-1-basics/frame-30.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-60.png b/test/functional/example-1-basics/frame-60.png
new file mode 100644
index 0000000..af3f4ce
--- /dev/null
+++ b/test/functional/example-1-basics/frame-60.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-90.png b/test/functional/example-1-basics/frame-90.png
new file mode 100644
index 0000000..099b823
--- /dev/null
+++ b/test/functional/example-1-basics/frame-90.png
Binary files differ
diff --git a/test/functional/example-1-basics/index.js b/test/functional/example-1-basics/index.js
new file mode 100644
index 0000000..7ae7a98
--- /dev/null
+++ b/test/functional/example-1-basics/index.js
@@ -0,0 +1,133 @@
+describe('Example 1 - Basics', function () {
+ 'use strict';
+
+ var baseUri = '/base/test/functional/example-1-basics';
+ var expect = chai.expect;
+ var currentFrame = 0;
+ var frameEvents = {};
+ var stage;
+ var renderer;
+ var bunny;
+
+ function onFrame(frame, callback) {
+ frameEvents[frame] = callback;
+ }
+
+ function animate() {
+ currentFrame += 1;
+
+ requestAnimFrame( animate );
+
+ // just for fun, lets rotate mr rabbit a little
+ bunny.rotation += 0.1;
+
+ // render the stage
+ renderer.render(stage);
+
+ if (frameEvents[currentFrame])
+ frameEvents[currentFrame](currentFrame);
+ }
+
+ function initScene() {
+ // create an new instance of a pixi stage
+ stage = new PIXI.Stage(0x66FF99);
+
+ // create a renderer instance
+ renderer = PIXI.autoDetectRenderer(400, 300);
+ console.log('Is PIXI.WebGLRenderer: ' + (renderer instanceof PIXI.WebGLRenderer));
+
+ // add the renderer view element to the DOM
+ document.body.appendChild(renderer.view);
+
+ requestAnimFrame( animate );
+
+ // create a texture from an image path
+ var texture = PIXI.Texture.fromImage(baseUri + "/bunny.png");
+ // create a new Sprite using the texture
+ bunny = new PIXI.Sprite(texture);
+
+ // center the sprites anchor point
+ bunny.anchor.x = 0.5;
+ bunny.anchor.y = 0.5;
+
+ // move the sprite t the center of the screen
+ bunny.position.x = 200;
+ bunny.position.y = 150;
+
+ stage.addChild(bunny);
+ }
+
+ it('assets loaded', function (done) {
+ var loader = new PIXI.AssetLoader([
+ baseUri + '/bunny.png',
+ baseUri + '/frame-30.png',
+ baseUri + '/frame-60.png',
+ baseUri + '/frame-90.png'
+ ]);
+ // loader.on('onProgress', function (event) {
+ // console.log(event.content);
+ // });
+ loader.on('onComplete', function (event) {
+ done();
+ initScene();
+ });
+ loader.load();
+ });
+
+ it('frame 30 should match', function (done) {
+ this.timeout(700);
+ onFrame(30, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-30.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 60 should match', function (done) {
+ this.timeout(1200);
+ onFrame(60, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-60.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 90 should match', function (done) {
+ this.timeout(1700);
+ onFrame(90, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-90.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ // it('capture something', function (done) {
+ // this.timeout(2000000);
+ // onFrame(30, function () {
+ // var img = new Image();
+ // img.src = renderer.view.toDataURL('image/png');
+ // document.body.appendChild(img);
+ // });
+ // });
+});
diff --git a/test/index.html b/test/index.html
deleted file mode 100644
index 9cbcac5..0000000
--- a/test/index.html
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
- Pixi.js Test Suite
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/test/karma.conf.js b/test/karma.conf.js
new file mode 100644
index 0000000..c66a696
--- /dev/null
+++ b/test/karma.conf.js
@@ -0,0 +1,82 @@
+module.exports = function(config) {
+ config.set({
+
+ // base path, that will be used to resolve files and exclude
+ basePath : '../',
+
+ frameworks : ['mocha'],
+
+ // list of files / patterns to load in the browser
+ files : [
+ 'node_modules/chai/chai.js',
+ 'bin/pixi.dev.js',
+ 'test/lib/**/*.js',
+ 'test/unit/**/*.js',
+ // 'test/functional/**/*.js',
+ {pattern: 'test/**/*.png', watched: false, included: false, served: true}
+ ],
+
+ // list of files to exclude
+ exclude : [],
+
+ // use dolts reporter, as travis terminal does not support escaping sequences
+ // possible values: 'dots', 'progress', 'junit', 'teamcity'
+ // CLI --reporters progress
+ reporters : ['progress'],
+
+ // web server port
+ // CLI --port 9876
+ port : 9876,
+
+ // cli runner port
+ // CLI --runner-port 9100
+ runnerPort : 9100,
+
+ // enable / disable colors in the output (reporters and logs)
+ // CLI --colors --no-colors
+ colors : true,
+
+ // level of logging
+ // possible values: karma.LOG_DISABLE || karma.LOG_ERROR || karma.LOG_WARN || karma.LOG_INFO || karma.LOG_DEBUG
+ // CLI --log-level debug
+ logLevel : config.LOG_DEBUG,
+
+ // enable / disable watching file and executing tests whenever any file changes
+ // CLI --auto-watch --no-auto-watch
+ autoWatch : false,
+
+ // Start these browsers, currently available:
+ // - Chrome
+ // - ChromeCanary
+ // - Firefox
+ // - Opera
+ // - Safari (only Mac)
+ // - PhantomJS
+ // - IE (only Windows)
+ // CLI --browsers Chrome,Firefox,Safari
+ browsers : ['Firefox'],
+
+ // If browser does not capture in given timeout [ms], kill it
+ // CLI --capture-timeout 5000
+ captureTimeout : 5000,
+
+ // Auto run tests on start (when browsers are captured) and exit
+ // CLI --single-run --no-single-run
+ singleRun : true,
+
+ // report which specs are slower than 500ms
+ // CLI --report-slower-than 500
+ reportSlowerThan : 1000,
+
+ preprocessors : {
+ // '**/client/js/*.js': 'coverage'
+ },
+
+ plugins : [
+ 'karma-mocha',
+ // 'karma-chrome-launcher',
+ 'karma-firefox-launcher',
+ // 'karma-phantomjs-launcher'
+ ]
+ });
+};
diff --git a/test/lib/pixi/core/Matrix.js b/test/lib/pixi/core/Matrix.js
new file mode 100644
index 0000000..d26386b
--- /dev/null
+++ b/test/lib/pixi/core/Matrix.js
@@ -0,0 +1,40 @@
+
+function pixi_core_Matrix_confirmNewMat3(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(1);
+ expect(matrix[5]).to.equal(0);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(1);
+}
+
+function pixi_core_Matrix_confirmNewMat4(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[0]).to.equal(1);
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(0);
+ expect(matrix[5]).to.equal(1);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(0);
+ expect(matrix[9]).to.equal(0);
+ expect(matrix[10]).to.equal(1);
+ expect(matrix[11]).to.equal(0);
+ expect(matrix[12]).to.equal(0);
+ expect(matrix[13]).to.equal(0);
+ expect(matrix[14]).to.equal(0);
+ expect(matrix[15]).to.equal(1);
+}
diff --git a/test/lib/pixi/core/Point.js b/test/lib/pixi/core/Point.js
new file mode 100644
index 0000000..e5df07b
--- /dev/null
+++ b/test/lib/pixi/core/Point.js
@@ -0,0 +1,10 @@
+
+function pixi_core_Point_confirm(obj, x, y) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Point);
+ expect(obj).to.respondTo('clone');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+}
diff --git a/test/lib/pixi/core/Rectangle.js b/test/lib/pixi/core/Rectangle.js
new file mode 100644
index 0000000..23f0d12
--- /dev/null
+++ b/test/lib/pixi/core/Rectangle.js
@@ -0,0 +1,13 @@
+
+function pixi_core_Rectangle_confirm(obj, x, y, width, height) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Rectangle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+ expect(obj).to.have.property('width', width);
+ expect(obj).to.have.property('height', height);
+}
diff --git a/test/lib/pixi/display/DisplayObject.js b/test/lib/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..1388a7f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObject.js
@@ -0,0 +1,43 @@
+
+function pixi_display_DisplayObject_confirmNew(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObject);
+ expect(obj).to.respondTo('setInteractive');
+ expect(obj).to.respondTo('addFilter');
+ expect(obj).to.respondTo('removeFilter');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.property('last', obj);
+ expect(obj).to.have.property('first', obj);
+
+ expect(obj).to.contain.property('position');
+ pixi_core_Point_confirm(obj.position, 0, 0);
+ expect(obj).to.contain.property('scale');
+ pixi_core_Point_confirm(obj.scale, 1, 1);
+ expect(obj).to.contain.property('pivot');
+ pixi_core_Point_confirm(obj.pivot, 0, 0);
+
+ expect(obj).to.have.property('rotation', 0);
+ expect(obj).to.have.property('alpha', 1);
+ expect(obj).to.have.property('visible', true);
+ expect(obj).to.have.property('buttonMode', false);
+ expect(obj).to.have.property('parent', null);
+ expect(obj).to.have.property('worldAlpha', 1);
+
+ expect(obj).to.have.property('hitArea');
+ expect(obj).to.have.property('interactive'); // TODO: Have a better default value
+ expect('mask' in obj).to.be.true; // TODO: Have a better default value
+ expect(obj.mask).to.be.undefined;
+
+ expect(obj).to.have.property('renderable');
+ expect(obj).to.have.property('stage');
+
+ expect(obj).to.have.deep.property('worldTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ expect(obj).to.have.deep.property('localTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.localTransform);
+
+ expect(obj).to.have.deep.property('color.length', 0);
+ expect(obj).to.have.property('dynamic', true);
+}
diff --git a/test/lib/pixi/display/DisplayObjectContainer.js b/test/lib/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..085c59f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,16 @@
+
+function pixi_display_DisplayObjectContainer_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObject_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObjectContainer);
+ expect(obj).to.respondTo('addChild');
+ expect(obj).to.respondTo('addChildAt');
+ expect(obj).to.respondTo('swapChildren');
+ expect(obj).to.respondTo('getChildAt');
+ expect(obj).to.respondTo('removeChild');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('children.length', 0);
+}
diff --git a/test/lib/pixi/display/Sprite.js b/test/lib/pixi/display/Sprite.js
new file mode 100644
index 0000000..cc7a2d6
--- /dev/null
+++ b/test/lib/pixi/display/Sprite.js
@@ -0,0 +1,28 @@
+
+function pixi_display_Sprite_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Sprite);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', true);
+ expect(obj).to.have.property('stage', null);
+
+ expect(obj).to.have.property('anchor');
+ pixi_core_Point_confirm(obj.anchor, 0, 0);
+
+ expect(obj).to.have.property('blendMode', PIXI.blendModes.NORMAL);
+ expect(obj).to.have.property('width', 1); // TODO: is 1 expected
+ expect(obj).to.have.property('height', 1); // TODO: is 1 expected
+
+ // FIXME: Just make this a boolean that is always there
+ expect(!!obj.updateFrame).to.equal(obj.texture.baseTexture.hasLoaded);
+
+ expect(obj).to.have.property('texture');
+ pixi_textures_Texture_confirmNew(obj.texture, done);
+}
diff --git a/test/lib/pixi/extras/Strip.js b/test/lib/pixi/extras/Strip.js
new file mode 100644
index 0000000..8927a8a
--- /dev/null
+++ b/test/lib/pixi/extras/Strip.js
@@ -0,0 +1,12 @@
+
+function pixi_extras_Strip_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Strip);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ // TODO: Test properties
+}
diff --git a/.gitignore b/.gitignore
index 12e1b62..0b88317 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
node_modules
.DS_Store
-.project
\ No newline at end of file
+.project
+*.log
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..63e4d7c
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,8 @@
+language: node_js
+node_js:
+ - 0.10
+
+before_script:
+ - npm install -g grunt-cli
+ - export DISPLAY=:99.0
+ - sh -e /etc/init.d/xvfb start
diff --git a/Gruntfile.js b/Gruntfile.js
index b083b49..103938c 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -1,10 +1,12 @@
+'use strict';
+
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-connect');
- grunt.loadNpmTasks('grunt-contrib-qunit');
grunt.loadNpmTasks('grunt-contrib-yuidoc');
+ grunt.loadTasks('tasks');
var root = 'src/pixi/',
debug = 'bin/pixi.dev.js',
@@ -79,7 +81,7 @@
},
files: {
srcBlob: '<%= dirs.src %>/**/*.js',
- testBlob: '<%= dirs.test %>/unit/**/*.js',
+ testBlob: '<%= dirs.test %>/{functional,lib/pixi,unit}/**/*.js',
build: '<%= dirs.build %>/pixi.dev.js',
buildMin: '<%= dirs.build %>/pixi.js'
},
@@ -94,7 +96,12 @@
},
jshint: {
beforeconcat: srcFiles,
- test: ['<%= files.testBlob %>'],
+ test: {
+ src: ['<%= files.testBlob %>'],
+ options: {
+ expr: true
+ }
+ },
options: {
asi: true,
smarttabs: true
@@ -128,12 +135,6 @@
]
},
connect: {
- qunit: {
- options: {
- port: grunt.option('port-test') || 9002,
- base: './'
- }
- },
test: {
options: {
port: grunt.option('port-test') || 9002,
@@ -142,13 +143,6 @@
}
}
},
- qunit: {
- all: {
- options: {
- urls: ['http://localhost:' + (grunt.option('port-test') || 9002) + '/test/index.html']
- }
- }
- },
yuidoc: {
compile: {
name: '<%= pkg.name %>',
@@ -161,6 +155,13 @@
outdir: '<%= dirs.docs %>'
}
}
+ },
+ karma: {
+ unit: {
+ configFile: 'test/karma.conf.js',
+ // browsers: ['Chrome'],
+ singleRun: true
+ }
}
});
@@ -182,9 +183,10 @@
}
)
- grunt.registerTask('default', ['concat', 'uglify', 'distribute']);
grunt.registerTask('build', ['concat', 'uglify', 'distribute']);
- grunt.registerTask('test', ['build', 'connect:qunit', 'qunit']);
+ grunt.registerTask('test', ['concat', 'jshint:test', 'karma']);
grunt.registerTask('docs', ['yuidoc']);
-
-}
\ No newline at end of file
+ grunt.registerTask('default', ['test', 'uglify', 'distribute']);
+ // Travis CI task.
+ grunt.registerTask('travis', ['test']);
+}
diff --git a/README.md b/README.md
index c62ef86..690cfe4 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,8 @@

+[](http://travis-ci.org/drkibitz/pixi.js)
+
#### JavaScript 2D Renderer ####
The aim of this project is to provide a fast lightweight 2D library that works
diff --git a/package.json b/package.json
index b373240..1246a68 100644
--- a/package.json
+++ b/package.json
@@ -18,14 +18,21 @@
"main": "bin/pixi.js",
+ "scripts": {
+ "test": "grunt travis --verbose"
+ },
+
"dependencies": {},
"devDependencies": {
"grunt": "~0.4.x",
- "grunt-contrib-jshint": "0.3.x",
+ "grunt-contrib-jshint": "0.6.x",
"grunt-contrib-uglify": "0.2.x",
- "grunt-contrib-connect": "0.2.x",
- "grunt-contrib-qunit": "0.2.x",
+ "grunt-contrib-connect": "0.3.x",
"grunt-contrib-yuidoc": "0.4.x",
- "grunt-contrib-concat": "0.1.x"
+ "grunt-contrib-concat": "0.3.x",
+ "chai": "~1.7.0",
+ "karma": "0.11.0",
+ "karma-firefox-launcher": "0.1.0",
+ "karma-mocha": "0.1.0"
}
}
diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js
index a7c520e..ee82bbd 100644
--- a/src/pixi/InteractionManager.js
+++ b/src/pixi/InteractionManager.js
@@ -62,7 +62,6 @@
this.onTouchEnd = this.onTouchEnd.bind(this);
this.onTouchMove = this.onTouchMove.bind(this);
-
this.last = 0;
}
diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js
index 1a95d20..eef1059 100644
--- a/src/pixi/core/Ellipse.js
+++ b/src/pixi/core/Ellipse.js
@@ -78,7 +78,7 @@
return (normx + normy < 0.25);
}
-PIXI.Ellipse.getBounds = function()
+PIXI.Ellipse.prototype.getBounds = function()
{
return new PIXI.Rectangle(this.x, this.y, this.width, this.height);
}
diff --git a/tasks/karma.js b/tasks/karma.js
new file mode 100644
index 0000000..c340485
--- /dev/null
+++ b/tasks/karma.js
@@ -0,0 +1,27 @@
+'use strict';
+
+var path = require('path');
+var server = require('karma').server;
+
+module.exports = function (grunt) {
+ grunt.registerMultiTask('karma', 'run karma.', function() {
+ var done = this.async();
+ var options = this.options({
+ background: false
+ });
+ var data = this.data;
+
+ //merge options onto data, with data taking precedence
+ data = grunt.util._.merge(options, data);
+ data.configFile = path.resolve(data.configFile);
+ if (data.configFile) {
+ data.configFile = grunt.template.process(data.configFile);
+ }
+
+ server.start(
+ data,
+ function(code) {
+ done(!code);
+ });
+ });
+};
diff --git a/test/functional/example-1-basics/bunny.png b/test/functional/example-1-basics/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/functional/example-1-basics/bunny.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-30.png b/test/functional/example-1-basics/frame-30.png
new file mode 100644
index 0000000..96e3409
--- /dev/null
+++ b/test/functional/example-1-basics/frame-30.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-60.png b/test/functional/example-1-basics/frame-60.png
new file mode 100644
index 0000000..af3f4ce
--- /dev/null
+++ b/test/functional/example-1-basics/frame-60.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-90.png b/test/functional/example-1-basics/frame-90.png
new file mode 100644
index 0000000..099b823
--- /dev/null
+++ b/test/functional/example-1-basics/frame-90.png
Binary files differ
diff --git a/test/functional/example-1-basics/index.js b/test/functional/example-1-basics/index.js
new file mode 100644
index 0000000..7ae7a98
--- /dev/null
+++ b/test/functional/example-1-basics/index.js
@@ -0,0 +1,133 @@
+describe('Example 1 - Basics', function () {
+ 'use strict';
+
+ var baseUri = '/base/test/functional/example-1-basics';
+ var expect = chai.expect;
+ var currentFrame = 0;
+ var frameEvents = {};
+ var stage;
+ var renderer;
+ var bunny;
+
+ function onFrame(frame, callback) {
+ frameEvents[frame] = callback;
+ }
+
+ function animate() {
+ currentFrame += 1;
+
+ requestAnimFrame( animate );
+
+ // just for fun, lets rotate mr rabbit a little
+ bunny.rotation += 0.1;
+
+ // render the stage
+ renderer.render(stage);
+
+ if (frameEvents[currentFrame])
+ frameEvents[currentFrame](currentFrame);
+ }
+
+ function initScene() {
+ // create an new instance of a pixi stage
+ stage = new PIXI.Stage(0x66FF99);
+
+ // create a renderer instance
+ renderer = PIXI.autoDetectRenderer(400, 300);
+ console.log('Is PIXI.WebGLRenderer: ' + (renderer instanceof PIXI.WebGLRenderer));
+
+ // add the renderer view element to the DOM
+ document.body.appendChild(renderer.view);
+
+ requestAnimFrame( animate );
+
+ // create a texture from an image path
+ var texture = PIXI.Texture.fromImage(baseUri + "/bunny.png");
+ // create a new Sprite using the texture
+ bunny = new PIXI.Sprite(texture);
+
+ // center the sprites anchor point
+ bunny.anchor.x = 0.5;
+ bunny.anchor.y = 0.5;
+
+ // move the sprite t the center of the screen
+ bunny.position.x = 200;
+ bunny.position.y = 150;
+
+ stage.addChild(bunny);
+ }
+
+ it('assets loaded', function (done) {
+ var loader = new PIXI.AssetLoader([
+ baseUri + '/bunny.png',
+ baseUri + '/frame-30.png',
+ baseUri + '/frame-60.png',
+ baseUri + '/frame-90.png'
+ ]);
+ // loader.on('onProgress', function (event) {
+ // console.log(event.content);
+ // });
+ loader.on('onComplete', function (event) {
+ done();
+ initScene();
+ });
+ loader.load();
+ });
+
+ it('frame 30 should match', function (done) {
+ this.timeout(700);
+ onFrame(30, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-30.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 60 should match', function (done) {
+ this.timeout(1200);
+ onFrame(60, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-60.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 90 should match', function (done) {
+ this.timeout(1700);
+ onFrame(90, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-90.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ // it('capture something', function (done) {
+ // this.timeout(2000000);
+ // onFrame(30, function () {
+ // var img = new Image();
+ // img.src = renderer.view.toDataURL('image/png');
+ // document.body.appendChild(img);
+ // });
+ // });
+});
diff --git a/test/index.html b/test/index.html
deleted file mode 100644
index 9cbcac5..0000000
--- a/test/index.html
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
- Pixi.js Test Suite
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/test/karma.conf.js b/test/karma.conf.js
new file mode 100644
index 0000000..c66a696
--- /dev/null
+++ b/test/karma.conf.js
@@ -0,0 +1,82 @@
+module.exports = function(config) {
+ config.set({
+
+ // base path, that will be used to resolve files and exclude
+ basePath : '../',
+
+ frameworks : ['mocha'],
+
+ // list of files / patterns to load in the browser
+ files : [
+ 'node_modules/chai/chai.js',
+ 'bin/pixi.dev.js',
+ 'test/lib/**/*.js',
+ 'test/unit/**/*.js',
+ // 'test/functional/**/*.js',
+ {pattern: 'test/**/*.png', watched: false, included: false, served: true}
+ ],
+
+ // list of files to exclude
+ exclude : [],
+
+ // use dolts reporter, as travis terminal does not support escaping sequences
+ // possible values: 'dots', 'progress', 'junit', 'teamcity'
+ // CLI --reporters progress
+ reporters : ['progress'],
+
+ // web server port
+ // CLI --port 9876
+ port : 9876,
+
+ // cli runner port
+ // CLI --runner-port 9100
+ runnerPort : 9100,
+
+ // enable / disable colors in the output (reporters and logs)
+ // CLI --colors --no-colors
+ colors : true,
+
+ // level of logging
+ // possible values: karma.LOG_DISABLE || karma.LOG_ERROR || karma.LOG_WARN || karma.LOG_INFO || karma.LOG_DEBUG
+ // CLI --log-level debug
+ logLevel : config.LOG_DEBUG,
+
+ // enable / disable watching file and executing tests whenever any file changes
+ // CLI --auto-watch --no-auto-watch
+ autoWatch : false,
+
+ // Start these browsers, currently available:
+ // - Chrome
+ // - ChromeCanary
+ // - Firefox
+ // - Opera
+ // - Safari (only Mac)
+ // - PhantomJS
+ // - IE (only Windows)
+ // CLI --browsers Chrome,Firefox,Safari
+ browsers : ['Firefox'],
+
+ // If browser does not capture in given timeout [ms], kill it
+ // CLI --capture-timeout 5000
+ captureTimeout : 5000,
+
+ // Auto run tests on start (when browsers are captured) and exit
+ // CLI --single-run --no-single-run
+ singleRun : true,
+
+ // report which specs are slower than 500ms
+ // CLI --report-slower-than 500
+ reportSlowerThan : 1000,
+
+ preprocessors : {
+ // '**/client/js/*.js': 'coverage'
+ },
+
+ plugins : [
+ 'karma-mocha',
+ // 'karma-chrome-launcher',
+ 'karma-firefox-launcher',
+ // 'karma-phantomjs-launcher'
+ ]
+ });
+};
diff --git a/test/lib/pixi/core/Matrix.js b/test/lib/pixi/core/Matrix.js
new file mode 100644
index 0000000..d26386b
--- /dev/null
+++ b/test/lib/pixi/core/Matrix.js
@@ -0,0 +1,40 @@
+
+function pixi_core_Matrix_confirmNewMat3(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(1);
+ expect(matrix[5]).to.equal(0);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(1);
+}
+
+function pixi_core_Matrix_confirmNewMat4(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[0]).to.equal(1);
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(0);
+ expect(matrix[5]).to.equal(1);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(0);
+ expect(matrix[9]).to.equal(0);
+ expect(matrix[10]).to.equal(1);
+ expect(matrix[11]).to.equal(0);
+ expect(matrix[12]).to.equal(0);
+ expect(matrix[13]).to.equal(0);
+ expect(matrix[14]).to.equal(0);
+ expect(matrix[15]).to.equal(1);
+}
diff --git a/test/lib/pixi/core/Point.js b/test/lib/pixi/core/Point.js
new file mode 100644
index 0000000..e5df07b
--- /dev/null
+++ b/test/lib/pixi/core/Point.js
@@ -0,0 +1,10 @@
+
+function pixi_core_Point_confirm(obj, x, y) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Point);
+ expect(obj).to.respondTo('clone');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+}
diff --git a/test/lib/pixi/core/Rectangle.js b/test/lib/pixi/core/Rectangle.js
new file mode 100644
index 0000000..23f0d12
--- /dev/null
+++ b/test/lib/pixi/core/Rectangle.js
@@ -0,0 +1,13 @@
+
+function pixi_core_Rectangle_confirm(obj, x, y, width, height) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Rectangle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+ expect(obj).to.have.property('width', width);
+ expect(obj).to.have.property('height', height);
+}
diff --git a/test/lib/pixi/display/DisplayObject.js b/test/lib/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..1388a7f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObject.js
@@ -0,0 +1,43 @@
+
+function pixi_display_DisplayObject_confirmNew(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObject);
+ expect(obj).to.respondTo('setInteractive');
+ expect(obj).to.respondTo('addFilter');
+ expect(obj).to.respondTo('removeFilter');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.property('last', obj);
+ expect(obj).to.have.property('first', obj);
+
+ expect(obj).to.contain.property('position');
+ pixi_core_Point_confirm(obj.position, 0, 0);
+ expect(obj).to.contain.property('scale');
+ pixi_core_Point_confirm(obj.scale, 1, 1);
+ expect(obj).to.contain.property('pivot');
+ pixi_core_Point_confirm(obj.pivot, 0, 0);
+
+ expect(obj).to.have.property('rotation', 0);
+ expect(obj).to.have.property('alpha', 1);
+ expect(obj).to.have.property('visible', true);
+ expect(obj).to.have.property('buttonMode', false);
+ expect(obj).to.have.property('parent', null);
+ expect(obj).to.have.property('worldAlpha', 1);
+
+ expect(obj).to.have.property('hitArea');
+ expect(obj).to.have.property('interactive'); // TODO: Have a better default value
+ expect('mask' in obj).to.be.true; // TODO: Have a better default value
+ expect(obj.mask).to.be.undefined;
+
+ expect(obj).to.have.property('renderable');
+ expect(obj).to.have.property('stage');
+
+ expect(obj).to.have.deep.property('worldTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ expect(obj).to.have.deep.property('localTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.localTransform);
+
+ expect(obj).to.have.deep.property('color.length', 0);
+ expect(obj).to.have.property('dynamic', true);
+}
diff --git a/test/lib/pixi/display/DisplayObjectContainer.js b/test/lib/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..085c59f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,16 @@
+
+function pixi_display_DisplayObjectContainer_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObject_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObjectContainer);
+ expect(obj).to.respondTo('addChild');
+ expect(obj).to.respondTo('addChildAt');
+ expect(obj).to.respondTo('swapChildren');
+ expect(obj).to.respondTo('getChildAt');
+ expect(obj).to.respondTo('removeChild');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('children.length', 0);
+}
diff --git a/test/lib/pixi/display/Sprite.js b/test/lib/pixi/display/Sprite.js
new file mode 100644
index 0000000..cc7a2d6
--- /dev/null
+++ b/test/lib/pixi/display/Sprite.js
@@ -0,0 +1,28 @@
+
+function pixi_display_Sprite_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Sprite);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', true);
+ expect(obj).to.have.property('stage', null);
+
+ expect(obj).to.have.property('anchor');
+ pixi_core_Point_confirm(obj.anchor, 0, 0);
+
+ expect(obj).to.have.property('blendMode', PIXI.blendModes.NORMAL);
+ expect(obj).to.have.property('width', 1); // TODO: is 1 expected
+ expect(obj).to.have.property('height', 1); // TODO: is 1 expected
+
+ // FIXME: Just make this a boolean that is always there
+ expect(!!obj.updateFrame).to.equal(obj.texture.baseTexture.hasLoaded);
+
+ expect(obj).to.have.property('texture');
+ pixi_textures_Texture_confirmNew(obj.texture, done);
+}
diff --git a/test/lib/pixi/extras/Strip.js b/test/lib/pixi/extras/Strip.js
new file mode 100644
index 0000000..8927a8a
--- /dev/null
+++ b/test/lib/pixi/extras/Strip.js
@@ -0,0 +1,12 @@
+
+function pixi_extras_Strip_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Strip);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ // TODO: Test properties
+}
diff --git a/test/lib/pixi/textures/Texture.js b/test/lib/pixi/textures/Texture.js
new file mode 100644
index 0000000..d5867b6
--- /dev/null
+++ b/test/lib/pixi/textures/Texture.js
@@ -0,0 +1,31 @@
+
+function pixi_textures_Texture_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ function confirmFrameDone() {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, obj.baseTexture.width, obj.baseTexture.height);
+
+ expect(obj).to.have.property('width', obj.baseTexture.width);
+ expect(obj).to.have.property('height', obj.baseTexture.height);
+ done();
+ }
+
+ expect(obj).to.be.an.instanceof(PIXI.Texture);
+ pixi_utils_EventTarget_like(obj);
+
+ expect(obj).to.have.property('baseTexture')
+ .and.to.be.an.instanceof(PIXI.BaseTexture);
+
+ expect(obj).to.have.property('scope', obj);
+
+ expect(obj).to.have.property('trim');
+ pixi_core_Point_confirm(obj.trim, 0, 0);
+
+ expect(obj).to.have.property('frame');
+ if (obj.baseTexture.hasLoaded) {
+ confirmFrameDone();
+ } else {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, 1, 1);
+ obj.addEventListener('update', confirmFrameDone);
+ }
+}
diff --git a/.gitignore b/.gitignore
index 12e1b62..0b88317 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
node_modules
.DS_Store
-.project
\ No newline at end of file
+.project
+*.log
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..63e4d7c
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,8 @@
+language: node_js
+node_js:
+ - 0.10
+
+before_script:
+ - npm install -g grunt-cli
+ - export DISPLAY=:99.0
+ - sh -e /etc/init.d/xvfb start
diff --git a/Gruntfile.js b/Gruntfile.js
index b083b49..103938c 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -1,10 +1,12 @@
+'use strict';
+
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-connect');
- grunt.loadNpmTasks('grunt-contrib-qunit');
grunt.loadNpmTasks('grunt-contrib-yuidoc');
+ grunt.loadTasks('tasks');
var root = 'src/pixi/',
debug = 'bin/pixi.dev.js',
@@ -79,7 +81,7 @@
},
files: {
srcBlob: '<%= dirs.src %>/**/*.js',
- testBlob: '<%= dirs.test %>/unit/**/*.js',
+ testBlob: '<%= dirs.test %>/{functional,lib/pixi,unit}/**/*.js',
build: '<%= dirs.build %>/pixi.dev.js',
buildMin: '<%= dirs.build %>/pixi.js'
},
@@ -94,7 +96,12 @@
},
jshint: {
beforeconcat: srcFiles,
- test: ['<%= files.testBlob %>'],
+ test: {
+ src: ['<%= files.testBlob %>'],
+ options: {
+ expr: true
+ }
+ },
options: {
asi: true,
smarttabs: true
@@ -128,12 +135,6 @@
]
},
connect: {
- qunit: {
- options: {
- port: grunt.option('port-test') || 9002,
- base: './'
- }
- },
test: {
options: {
port: grunt.option('port-test') || 9002,
@@ -142,13 +143,6 @@
}
}
},
- qunit: {
- all: {
- options: {
- urls: ['http://localhost:' + (grunt.option('port-test') || 9002) + '/test/index.html']
- }
- }
- },
yuidoc: {
compile: {
name: '<%= pkg.name %>',
@@ -161,6 +155,13 @@
outdir: '<%= dirs.docs %>'
}
}
+ },
+ karma: {
+ unit: {
+ configFile: 'test/karma.conf.js',
+ // browsers: ['Chrome'],
+ singleRun: true
+ }
}
});
@@ -182,9 +183,10 @@
}
)
- grunt.registerTask('default', ['concat', 'uglify', 'distribute']);
grunt.registerTask('build', ['concat', 'uglify', 'distribute']);
- grunt.registerTask('test', ['build', 'connect:qunit', 'qunit']);
+ grunt.registerTask('test', ['concat', 'jshint:test', 'karma']);
grunt.registerTask('docs', ['yuidoc']);
-
-}
\ No newline at end of file
+ grunt.registerTask('default', ['test', 'uglify', 'distribute']);
+ // Travis CI task.
+ grunt.registerTask('travis', ['test']);
+}
diff --git a/README.md b/README.md
index c62ef86..690cfe4 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,8 @@

+[](http://travis-ci.org/drkibitz/pixi.js)
+
#### JavaScript 2D Renderer ####
The aim of this project is to provide a fast lightweight 2D library that works
diff --git a/package.json b/package.json
index b373240..1246a68 100644
--- a/package.json
+++ b/package.json
@@ -18,14 +18,21 @@
"main": "bin/pixi.js",
+ "scripts": {
+ "test": "grunt travis --verbose"
+ },
+
"dependencies": {},
"devDependencies": {
"grunt": "~0.4.x",
- "grunt-contrib-jshint": "0.3.x",
+ "grunt-contrib-jshint": "0.6.x",
"grunt-contrib-uglify": "0.2.x",
- "grunt-contrib-connect": "0.2.x",
- "grunt-contrib-qunit": "0.2.x",
+ "grunt-contrib-connect": "0.3.x",
"grunt-contrib-yuidoc": "0.4.x",
- "grunt-contrib-concat": "0.1.x"
+ "grunt-contrib-concat": "0.3.x",
+ "chai": "~1.7.0",
+ "karma": "0.11.0",
+ "karma-firefox-launcher": "0.1.0",
+ "karma-mocha": "0.1.0"
}
}
diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js
index a7c520e..ee82bbd 100644
--- a/src/pixi/InteractionManager.js
+++ b/src/pixi/InteractionManager.js
@@ -62,7 +62,6 @@
this.onTouchEnd = this.onTouchEnd.bind(this);
this.onTouchMove = this.onTouchMove.bind(this);
-
this.last = 0;
}
diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js
index 1a95d20..eef1059 100644
--- a/src/pixi/core/Ellipse.js
+++ b/src/pixi/core/Ellipse.js
@@ -78,7 +78,7 @@
return (normx + normy < 0.25);
}
-PIXI.Ellipse.getBounds = function()
+PIXI.Ellipse.prototype.getBounds = function()
{
return new PIXI.Rectangle(this.x, this.y, this.width, this.height);
}
diff --git a/tasks/karma.js b/tasks/karma.js
new file mode 100644
index 0000000..c340485
--- /dev/null
+++ b/tasks/karma.js
@@ -0,0 +1,27 @@
+'use strict';
+
+var path = require('path');
+var server = require('karma').server;
+
+module.exports = function (grunt) {
+ grunt.registerMultiTask('karma', 'run karma.', function() {
+ var done = this.async();
+ var options = this.options({
+ background: false
+ });
+ var data = this.data;
+
+ //merge options onto data, with data taking precedence
+ data = grunt.util._.merge(options, data);
+ data.configFile = path.resolve(data.configFile);
+ if (data.configFile) {
+ data.configFile = grunt.template.process(data.configFile);
+ }
+
+ server.start(
+ data,
+ function(code) {
+ done(!code);
+ });
+ });
+};
diff --git a/test/functional/example-1-basics/bunny.png b/test/functional/example-1-basics/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/functional/example-1-basics/bunny.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-30.png b/test/functional/example-1-basics/frame-30.png
new file mode 100644
index 0000000..96e3409
--- /dev/null
+++ b/test/functional/example-1-basics/frame-30.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-60.png b/test/functional/example-1-basics/frame-60.png
new file mode 100644
index 0000000..af3f4ce
--- /dev/null
+++ b/test/functional/example-1-basics/frame-60.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-90.png b/test/functional/example-1-basics/frame-90.png
new file mode 100644
index 0000000..099b823
--- /dev/null
+++ b/test/functional/example-1-basics/frame-90.png
Binary files differ
diff --git a/test/functional/example-1-basics/index.js b/test/functional/example-1-basics/index.js
new file mode 100644
index 0000000..7ae7a98
--- /dev/null
+++ b/test/functional/example-1-basics/index.js
@@ -0,0 +1,133 @@
+describe('Example 1 - Basics', function () {
+ 'use strict';
+
+ var baseUri = '/base/test/functional/example-1-basics';
+ var expect = chai.expect;
+ var currentFrame = 0;
+ var frameEvents = {};
+ var stage;
+ var renderer;
+ var bunny;
+
+ function onFrame(frame, callback) {
+ frameEvents[frame] = callback;
+ }
+
+ function animate() {
+ currentFrame += 1;
+
+ requestAnimFrame( animate );
+
+ // just for fun, lets rotate mr rabbit a little
+ bunny.rotation += 0.1;
+
+ // render the stage
+ renderer.render(stage);
+
+ if (frameEvents[currentFrame])
+ frameEvents[currentFrame](currentFrame);
+ }
+
+ function initScene() {
+ // create an new instance of a pixi stage
+ stage = new PIXI.Stage(0x66FF99);
+
+ // create a renderer instance
+ renderer = PIXI.autoDetectRenderer(400, 300);
+ console.log('Is PIXI.WebGLRenderer: ' + (renderer instanceof PIXI.WebGLRenderer));
+
+ // add the renderer view element to the DOM
+ document.body.appendChild(renderer.view);
+
+ requestAnimFrame( animate );
+
+ // create a texture from an image path
+ var texture = PIXI.Texture.fromImage(baseUri + "/bunny.png");
+ // create a new Sprite using the texture
+ bunny = new PIXI.Sprite(texture);
+
+ // center the sprites anchor point
+ bunny.anchor.x = 0.5;
+ bunny.anchor.y = 0.5;
+
+ // move the sprite t the center of the screen
+ bunny.position.x = 200;
+ bunny.position.y = 150;
+
+ stage.addChild(bunny);
+ }
+
+ it('assets loaded', function (done) {
+ var loader = new PIXI.AssetLoader([
+ baseUri + '/bunny.png',
+ baseUri + '/frame-30.png',
+ baseUri + '/frame-60.png',
+ baseUri + '/frame-90.png'
+ ]);
+ // loader.on('onProgress', function (event) {
+ // console.log(event.content);
+ // });
+ loader.on('onComplete', function (event) {
+ done();
+ initScene();
+ });
+ loader.load();
+ });
+
+ it('frame 30 should match', function (done) {
+ this.timeout(700);
+ onFrame(30, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-30.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 60 should match', function (done) {
+ this.timeout(1200);
+ onFrame(60, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-60.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 90 should match', function (done) {
+ this.timeout(1700);
+ onFrame(90, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-90.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ // it('capture something', function (done) {
+ // this.timeout(2000000);
+ // onFrame(30, function () {
+ // var img = new Image();
+ // img.src = renderer.view.toDataURL('image/png');
+ // document.body.appendChild(img);
+ // });
+ // });
+});
diff --git a/test/index.html b/test/index.html
deleted file mode 100644
index 9cbcac5..0000000
--- a/test/index.html
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
- Pixi.js Test Suite
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/test/karma.conf.js b/test/karma.conf.js
new file mode 100644
index 0000000..c66a696
--- /dev/null
+++ b/test/karma.conf.js
@@ -0,0 +1,82 @@
+module.exports = function(config) {
+ config.set({
+
+ // base path, that will be used to resolve files and exclude
+ basePath : '../',
+
+ frameworks : ['mocha'],
+
+ // list of files / patterns to load in the browser
+ files : [
+ 'node_modules/chai/chai.js',
+ 'bin/pixi.dev.js',
+ 'test/lib/**/*.js',
+ 'test/unit/**/*.js',
+ // 'test/functional/**/*.js',
+ {pattern: 'test/**/*.png', watched: false, included: false, served: true}
+ ],
+
+ // list of files to exclude
+ exclude : [],
+
+ // use dolts reporter, as travis terminal does not support escaping sequences
+ // possible values: 'dots', 'progress', 'junit', 'teamcity'
+ // CLI --reporters progress
+ reporters : ['progress'],
+
+ // web server port
+ // CLI --port 9876
+ port : 9876,
+
+ // cli runner port
+ // CLI --runner-port 9100
+ runnerPort : 9100,
+
+ // enable / disable colors in the output (reporters and logs)
+ // CLI --colors --no-colors
+ colors : true,
+
+ // level of logging
+ // possible values: karma.LOG_DISABLE || karma.LOG_ERROR || karma.LOG_WARN || karma.LOG_INFO || karma.LOG_DEBUG
+ // CLI --log-level debug
+ logLevel : config.LOG_DEBUG,
+
+ // enable / disable watching file and executing tests whenever any file changes
+ // CLI --auto-watch --no-auto-watch
+ autoWatch : false,
+
+ // Start these browsers, currently available:
+ // - Chrome
+ // - ChromeCanary
+ // - Firefox
+ // - Opera
+ // - Safari (only Mac)
+ // - PhantomJS
+ // - IE (only Windows)
+ // CLI --browsers Chrome,Firefox,Safari
+ browsers : ['Firefox'],
+
+ // If browser does not capture in given timeout [ms], kill it
+ // CLI --capture-timeout 5000
+ captureTimeout : 5000,
+
+ // Auto run tests on start (when browsers are captured) and exit
+ // CLI --single-run --no-single-run
+ singleRun : true,
+
+ // report which specs are slower than 500ms
+ // CLI --report-slower-than 500
+ reportSlowerThan : 1000,
+
+ preprocessors : {
+ // '**/client/js/*.js': 'coverage'
+ },
+
+ plugins : [
+ 'karma-mocha',
+ // 'karma-chrome-launcher',
+ 'karma-firefox-launcher',
+ // 'karma-phantomjs-launcher'
+ ]
+ });
+};
diff --git a/test/lib/pixi/core/Matrix.js b/test/lib/pixi/core/Matrix.js
new file mode 100644
index 0000000..d26386b
--- /dev/null
+++ b/test/lib/pixi/core/Matrix.js
@@ -0,0 +1,40 @@
+
+function pixi_core_Matrix_confirmNewMat3(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(1);
+ expect(matrix[5]).to.equal(0);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(1);
+}
+
+function pixi_core_Matrix_confirmNewMat4(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[0]).to.equal(1);
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(0);
+ expect(matrix[5]).to.equal(1);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(0);
+ expect(matrix[9]).to.equal(0);
+ expect(matrix[10]).to.equal(1);
+ expect(matrix[11]).to.equal(0);
+ expect(matrix[12]).to.equal(0);
+ expect(matrix[13]).to.equal(0);
+ expect(matrix[14]).to.equal(0);
+ expect(matrix[15]).to.equal(1);
+}
diff --git a/test/lib/pixi/core/Point.js b/test/lib/pixi/core/Point.js
new file mode 100644
index 0000000..e5df07b
--- /dev/null
+++ b/test/lib/pixi/core/Point.js
@@ -0,0 +1,10 @@
+
+function pixi_core_Point_confirm(obj, x, y) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Point);
+ expect(obj).to.respondTo('clone');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+}
diff --git a/test/lib/pixi/core/Rectangle.js b/test/lib/pixi/core/Rectangle.js
new file mode 100644
index 0000000..23f0d12
--- /dev/null
+++ b/test/lib/pixi/core/Rectangle.js
@@ -0,0 +1,13 @@
+
+function pixi_core_Rectangle_confirm(obj, x, y, width, height) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Rectangle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+ expect(obj).to.have.property('width', width);
+ expect(obj).to.have.property('height', height);
+}
diff --git a/test/lib/pixi/display/DisplayObject.js b/test/lib/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..1388a7f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObject.js
@@ -0,0 +1,43 @@
+
+function pixi_display_DisplayObject_confirmNew(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObject);
+ expect(obj).to.respondTo('setInteractive');
+ expect(obj).to.respondTo('addFilter');
+ expect(obj).to.respondTo('removeFilter');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.property('last', obj);
+ expect(obj).to.have.property('first', obj);
+
+ expect(obj).to.contain.property('position');
+ pixi_core_Point_confirm(obj.position, 0, 0);
+ expect(obj).to.contain.property('scale');
+ pixi_core_Point_confirm(obj.scale, 1, 1);
+ expect(obj).to.contain.property('pivot');
+ pixi_core_Point_confirm(obj.pivot, 0, 0);
+
+ expect(obj).to.have.property('rotation', 0);
+ expect(obj).to.have.property('alpha', 1);
+ expect(obj).to.have.property('visible', true);
+ expect(obj).to.have.property('buttonMode', false);
+ expect(obj).to.have.property('parent', null);
+ expect(obj).to.have.property('worldAlpha', 1);
+
+ expect(obj).to.have.property('hitArea');
+ expect(obj).to.have.property('interactive'); // TODO: Have a better default value
+ expect('mask' in obj).to.be.true; // TODO: Have a better default value
+ expect(obj.mask).to.be.undefined;
+
+ expect(obj).to.have.property('renderable');
+ expect(obj).to.have.property('stage');
+
+ expect(obj).to.have.deep.property('worldTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ expect(obj).to.have.deep.property('localTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.localTransform);
+
+ expect(obj).to.have.deep.property('color.length', 0);
+ expect(obj).to.have.property('dynamic', true);
+}
diff --git a/test/lib/pixi/display/DisplayObjectContainer.js b/test/lib/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..085c59f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,16 @@
+
+function pixi_display_DisplayObjectContainer_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObject_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObjectContainer);
+ expect(obj).to.respondTo('addChild');
+ expect(obj).to.respondTo('addChildAt');
+ expect(obj).to.respondTo('swapChildren');
+ expect(obj).to.respondTo('getChildAt');
+ expect(obj).to.respondTo('removeChild');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('children.length', 0);
+}
diff --git a/test/lib/pixi/display/Sprite.js b/test/lib/pixi/display/Sprite.js
new file mode 100644
index 0000000..cc7a2d6
--- /dev/null
+++ b/test/lib/pixi/display/Sprite.js
@@ -0,0 +1,28 @@
+
+function pixi_display_Sprite_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Sprite);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', true);
+ expect(obj).to.have.property('stage', null);
+
+ expect(obj).to.have.property('anchor');
+ pixi_core_Point_confirm(obj.anchor, 0, 0);
+
+ expect(obj).to.have.property('blendMode', PIXI.blendModes.NORMAL);
+ expect(obj).to.have.property('width', 1); // TODO: is 1 expected
+ expect(obj).to.have.property('height', 1); // TODO: is 1 expected
+
+ // FIXME: Just make this a boolean that is always there
+ expect(!!obj.updateFrame).to.equal(obj.texture.baseTexture.hasLoaded);
+
+ expect(obj).to.have.property('texture');
+ pixi_textures_Texture_confirmNew(obj.texture, done);
+}
diff --git a/test/lib/pixi/extras/Strip.js b/test/lib/pixi/extras/Strip.js
new file mode 100644
index 0000000..8927a8a
--- /dev/null
+++ b/test/lib/pixi/extras/Strip.js
@@ -0,0 +1,12 @@
+
+function pixi_extras_Strip_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Strip);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ // TODO: Test properties
+}
diff --git a/test/lib/pixi/textures/Texture.js b/test/lib/pixi/textures/Texture.js
new file mode 100644
index 0000000..d5867b6
--- /dev/null
+++ b/test/lib/pixi/textures/Texture.js
@@ -0,0 +1,31 @@
+
+function pixi_textures_Texture_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ function confirmFrameDone() {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, obj.baseTexture.width, obj.baseTexture.height);
+
+ expect(obj).to.have.property('width', obj.baseTexture.width);
+ expect(obj).to.have.property('height', obj.baseTexture.height);
+ done();
+ }
+
+ expect(obj).to.be.an.instanceof(PIXI.Texture);
+ pixi_utils_EventTarget_like(obj);
+
+ expect(obj).to.have.property('baseTexture')
+ .and.to.be.an.instanceof(PIXI.BaseTexture);
+
+ expect(obj).to.have.property('scope', obj);
+
+ expect(obj).to.have.property('trim');
+ pixi_core_Point_confirm(obj.trim, 0, 0);
+
+ expect(obj).to.have.property('frame');
+ if (obj.baseTexture.hasLoaded) {
+ confirmFrameDone();
+ } else {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, 1, 1);
+ obj.addEventListener('update', confirmFrameDone);
+ }
+}
diff --git a/test/lib/pixi/utils/EventTarget.js b/test/lib/pixi/utils/EventTarget.js
new file mode 100644
index 0000000..7b1dcfa
--- /dev/null
+++ b/test/lib/pixi/utils/EventTarget.js
@@ -0,0 +1,8 @@
+
+function pixi_utils_EventTarget_like(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.respondTo('addEventListener');
+ expect(obj).to.respondTo('dispatchEvent');
+ expect(obj).to.respondTo('removeEventListener');
+}
diff --git a/.gitignore b/.gitignore
index 12e1b62..0b88317 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
node_modules
.DS_Store
-.project
\ No newline at end of file
+.project
+*.log
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..63e4d7c
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,8 @@
+language: node_js
+node_js:
+ - 0.10
+
+before_script:
+ - npm install -g grunt-cli
+ - export DISPLAY=:99.0
+ - sh -e /etc/init.d/xvfb start
diff --git a/Gruntfile.js b/Gruntfile.js
index b083b49..103938c 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -1,10 +1,12 @@
+'use strict';
+
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-connect');
- grunt.loadNpmTasks('grunt-contrib-qunit');
grunt.loadNpmTasks('grunt-contrib-yuidoc');
+ grunt.loadTasks('tasks');
var root = 'src/pixi/',
debug = 'bin/pixi.dev.js',
@@ -79,7 +81,7 @@
},
files: {
srcBlob: '<%= dirs.src %>/**/*.js',
- testBlob: '<%= dirs.test %>/unit/**/*.js',
+ testBlob: '<%= dirs.test %>/{functional,lib/pixi,unit}/**/*.js',
build: '<%= dirs.build %>/pixi.dev.js',
buildMin: '<%= dirs.build %>/pixi.js'
},
@@ -94,7 +96,12 @@
},
jshint: {
beforeconcat: srcFiles,
- test: ['<%= files.testBlob %>'],
+ test: {
+ src: ['<%= files.testBlob %>'],
+ options: {
+ expr: true
+ }
+ },
options: {
asi: true,
smarttabs: true
@@ -128,12 +135,6 @@
]
},
connect: {
- qunit: {
- options: {
- port: grunt.option('port-test') || 9002,
- base: './'
- }
- },
test: {
options: {
port: grunt.option('port-test') || 9002,
@@ -142,13 +143,6 @@
}
}
},
- qunit: {
- all: {
- options: {
- urls: ['http://localhost:' + (grunt.option('port-test') || 9002) + '/test/index.html']
- }
- }
- },
yuidoc: {
compile: {
name: '<%= pkg.name %>',
@@ -161,6 +155,13 @@
outdir: '<%= dirs.docs %>'
}
}
+ },
+ karma: {
+ unit: {
+ configFile: 'test/karma.conf.js',
+ // browsers: ['Chrome'],
+ singleRun: true
+ }
}
});
@@ -182,9 +183,10 @@
}
)
- grunt.registerTask('default', ['concat', 'uglify', 'distribute']);
grunt.registerTask('build', ['concat', 'uglify', 'distribute']);
- grunt.registerTask('test', ['build', 'connect:qunit', 'qunit']);
+ grunt.registerTask('test', ['concat', 'jshint:test', 'karma']);
grunt.registerTask('docs', ['yuidoc']);
-
-}
\ No newline at end of file
+ grunt.registerTask('default', ['test', 'uglify', 'distribute']);
+ // Travis CI task.
+ grunt.registerTask('travis', ['test']);
+}
diff --git a/README.md b/README.md
index c62ef86..690cfe4 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,8 @@

+[](http://travis-ci.org/drkibitz/pixi.js)
+
#### JavaScript 2D Renderer ####
The aim of this project is to provide a fast lightweight 2D library that works
diff --git a/package.json b/package.json
index b373240..1246a68 100644
--- a/package.json
+++ b/package.json
@@ -18,14 +18,21 @@
"main": "bin/pixi.js",
+ "scripts": {
+ "test": "grunt travis --verbose"
+ },
+
"dependencies": {},
"devDependencies": {
"grunt": "~0.4.x",
- "grunt-contrib-jshint": "0.3.x",
+ "grunt-contrib-jshint": "0.6.x",
"grunt-contrib-uglify": "0.2.x",
- "grunt-contrib-connect": "0.2.x",
- "grunt-contrib-qunit": "0.2.x",
+ "grunt-contrib-connect": "0.3.x",
"grunt-contrib-yuidoc": "0.4.x",
- "grunt-contrib-concat": "0.1.x"
+ "grunt-contrib-concat": "0.3.x",
+ "chai": "~1.7.0",
+ "karma": "0.11.0",
+ "karma-firefox-launcher": "0.1.0",
+ "karma-mocha": "0.1.0"
}
}
diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js
index a7c520e..ee82bbd 100644
--- a/src/pixi/InteractionManager.js
+++ b/src/pixi/InteractionManager.js
@@ -62,7 +62,6 @@
this.onTouchEnd = this.onTouchEnd.bind(this);
this.onTouchMove = this.onTouchMove.bind(this);
-
this.last = 0;
}
diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js
index 1a95d20..eef1059 100644
--- a/src/pixi/core/Ellipse.js
+++ b/src/pixi/core/Ellipse.js
@@ -78,7 +78,7 @@
return (normx + normy < 0.25);
}
-PIXI.Ellipse.getBounds = function()
+PIXI.Ellipse.prototype.getBounds = function()
{
return new PIXI.Rectangle(this.x, this.y, this.width, this.height);
}
diff --git a/tasks/karma.js b/tasks/karma.js
new file mode 100644
index 0000000..c340485
--- /dev/null
+++ b/tasks/karma.js
@@ -0,0 +1,27 @@
+'use strict';
+
+var path = require('path');
+var server = require('karma').server;
+
+module.exports = function (grunt) {
+ grunt.registerMultiTask('karma', 'run karma.', function() {
+ var done = this.async();
+ var options = this.options({
+ background: false
+ });
+ var data = this.data;
+
+ //merge options onto data, with data taking precedence
+ data = grunt.util._.merge(options, data);
+ data.configFile = path.resolve(data.configFile);
+ if (data.configFile) {
+ data.configFile = grunt.template.process(data.configFile);
+ }
+
+ server.start(
+ data,
+ function(code) {
+ done(!code);
+ });
+ });
+};
diff --git a/test/functional/example-1-basics/bunny.png b/test/functional/example-1-basics/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/functional/example-1-basics/bunny.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-30.png b/test/functional/example-1-basics/frame-30.png
new file mode 100644
index 0000000..96e3409
--- /dev/null
+++ b/test/functional/example-1-basics/frame-30.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-60.png b/test/functional/example-1-basics/frame-60.png
new file mode 100644
index 0000000..af3f4ce
--- /dev/null
+++ b/test/functional/example-1-basics/frame-60.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-90.png b/test/functional/example-1-basics/frame-90.png
new file mode 100644
index 0000000..099b823
--- /dev/null
+++ b/test/functional/example-1-basics/frame-90.png
Binary files differ
diff --git a/test/functional/example-1-basics/index.js b/test/functional/example-1-basics/index.js
new file mode 100644
index 0000000..7ae7a98
--- /dev/null
+++ b/test/functional/example-1-basics/index.js
@@ -0,0 +1,133 @@
+describe('Example 1 - Basics', function () {
+ 'use strict';
+
+ var baseUri = '/base/test/functional/example-1-basics';
+ var expect = chai.expect;
+ var currentFrame = 0;
+ var frameEvents = {};
+ var stage;
+ var renderer;
+ var bunny;
+
+ function onFrame(frame, callback) {
+ frameEvents[frame] = callback;
+ }
+
+ function animate() {
+ currentFrame += 1;
+
+ requestAnimFrame( animate );
+
+ // just for fun, lets rotate mr rabbit a little
+ bunny.rotation += 0.1;
+
+ // render the stage
+ renderer.render(stage);
+
+ if (frameEvents[currentFrame])
+ frameEvents[currentFrame](currentFrame);
+ }
+
+ function initScene() {
+ // create an new instance of a pixi stage
+ stage = new PIXI.Stage(0x66FF99);
+
+ // create a renderer instance
+ renderer = PIXI.autoDetectRenderer(400, 300);
+ console.log('Is PIXI.WebGLRenderer: ' + (renderer instanceof PIXI.WebGLRenderer));
+
+ // add the renderer view element to the DOM
+ document.body.appendChild(renderer.view);
+
+ requestAnimFrame( animate );
+
+ // create a texture from an image path
+ var texture = PIXI.Texture.fromImage(baseUri + "/bunny.png");
+ // create a new Sprite using the texture
+ bunny = new PIXI.Sprite(texture);
+
+ // center the sprites anchor point
+ bunny.anchor.x = 0.5;
+ bunny.anchor.y = 0.5;
+
+ // move the sprite t the center of the screen
+ bunny.position.x = 200;
+ bunny.position.y = 150;
+
+ stage.addChild(bunny);
+ }
+
+ it('assets loaded', function (done) {
+ var loader = new PIXI.AssetLoader([
+ baseUri + '/bunny.png',
+ baseUri + '/frame-30.png',
+ baseUri + '/frame-60.png',
+ baseUri + '/frame-90.png'
+ ]);
+ // loader.on('onProgress', function (event) {
+ // console.log(event.content);
+ // });
+ loader.on('onComplete', function (event) {
+ done();
+ initScene();
+ });
+ loader.load();
+ });
+
+ it('frame 30 should match', function (done) {
+ this.timeout(700);
+ onFrame(30, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-30.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 60 should match', function (done) {
+ this.timeout(1200);
+ onFrame(60, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-60.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 90 should match', function (done) {
+ this.timeout(1700);
+ onFrame(90, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-90.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ // it('capture something', function (done) {
+ // this.timeout(2000000);
+ // onFrame(30, function () {
+ // var img = new Image();
+ // img.src = renderer.view.toDataURL('image/png');
+ // document.body.appendChild(img);
+ // });
+ // });
+});
diff --git a/test/index.html b/test/index.html
deleted file mode 100644
index 9cbcac5..0000000
--- a/test/index.html
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
- Pixi.js Test Suite
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/test/karma.conf.js b/test/karma.conf.js
new file mode 100644
index 0000000..c66a696
--- /dev/null
+++ b/test/karma.conf.js
@@ -0,0 +1,82 @@
+module.exports = function(config) {
+ config.set({
+
+ // base path, that will be used to resolve files and exclude
+ basePath : '../',
+
+ frameworks : ['mocha'],
+
+ // list of files / patterns to load in the browser
+ files : [
+ 'node_modules/chai/chai.js',
+ 'bin/pixi.dev.js',
+ 'test/lib/**/*.js',
+ 'test/unit/**/*.js',
+ // 'test/functional/**/*.js',
+ {pattern: 'test/**/*.png', watched: false, included: false, served: true}
+ ],
+
+ // list of files to exclude
+ exclude : [],
+
+ // use dolts reporter, as travis terminal does not support escaping sequences
+ // possible values: 'dots', 'progress', 'junit', 'teamcity'
+ // CLI --reporters progress
+ reporters : ['progress'],
+
+ // web server port
+ // CLI --port 9876
+ port : 9876,
+
+ // cli runner port
+ // CLI --runner-port 9100
+ runnerPort : 9100,
+
+ // enable / disable colors in the output (reporters and logs)
+ // CLI --colors --no-colors
+ colors : true,
+
+ // level of logging
+ // possible values: karma.LOG_DISABLE || karma.LOG_ERROR || karma.LOG_WARN || karma.LOG_INFO || karma.LOG_DEBUG
+ // CLI --log-level debug
+ logLevel : config.LOG_DEBUG,
+
+ // enable / disable watching file and executing tests whenever any file changes
+ // CLI --auto-watch --no-auto-watch
+ autoWatch : false,
+
+ // Start these browsers, currently available:
+ // - Chrome
+ // - ChromeCanary
+ // - Firefox
+ // - Opera
+ // - Safari (only Mac)
+ // - PhantomJS
+ // - IE (only Windows)
+ // CLI --browsers Chrome,Firefox,Safari
+ browsers : ['Firefox'],
+
+ // If browser does not capture in given timeout [ms], kill it
+ // CLI --capture-timeout 5000
+ captureTimeout : 5000,
+
+ // Auto run tests on start (when browsers are captured) and exit
+ // CLI --single-run --no-single-run
+ singleRun : true,
+
+ // report which specs are slower than 500ms
+ // CLI --report-slower-than 500
+ reportSlowerThan : 1000,
+
+ preprocessors : {
+ // '**/client/js/*.js': 'coverage'
+ },
+
+ plugins : [
+ 'karma-mocha',
+ // 'karma-chrome-launcher',
+ 'karma-firefox-launcher',
+ // 'karma-phantomjs-launcher'
+ ]
+ });
+};
diff --git a/test/lib/pixi/core/Matrix.js b/test/lib/pixi/core/Matrix.js
new file mode 100644
index 0000000..d26386b
--- /dev/null
+++ b/test/lib/pixi/core/Matrix.js
@@ -0,0 +1,40 @@
+
+function pixi_core_Matrix_confirmNewMat3(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(1);
+ expect(matrix[5]).to.equal(0);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(1);
+}
+
+function pixi_core_Matrix_confirmNewMat4(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[0]).to.equal(1);
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(0);
+ expect(matrix[5]).to.equal(1);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(0);
+ expect(matrix[9]).to.equal(0);
+ expect(matrix[10]).to.equal(1);
+ expect(matrix[11]).to.equal(0);
+ expect(matrix[12]).to.equal(0);
+ expect(matrix[13]).to.equal(0);
+ expect(matrix[14]).to.equal(0);
+ expect(matrix[15]).to.equal(1);
+}
diff --git a/test/lib/pixi/core/Point.js b/test/lib/pixi/core/Point.js
new file mode 100644
index 0000000..e5df07b
--- /dev/null
+++ b/test/lib/pixi/core/Point.js
@@ -0,0 +1,10 @@
+
+function pixi_core_Point_confirm(obj, x, y) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Point);
+ expect(obj).to.respondTo('clone');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+}
diff --git a/test/lib/pixi/core/Rectangle.js b/test/lib/pixi/core/Rectangle.js
new file mode 100644
index 0000000..23f0d12
--- /dev/null
+++ b/test/lib/pixi/core/Rectangle.js
@@ -0,0 +1,13 @@
+
+function pixi_core_Rectangle_confirm(obj, x, y, width, height) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Rectangle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+ expect(obj).to.have.property('width', width);
+ expect(obj).to.have.property('height', height);
+}
diff --git a/test/lib/pixi/display/DisplayObject.js b/test/lib/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..1388a7f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObject.js
@@ -0,0 +1,43 @@
+
+function pixi_display_DisplayObject_confirmNew(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObject);
+ expect(obj).to.respondTo('setInteractive');
+ expect(obj).to.respondTo('addFilter');
+ expect(obj).to.respondTo('removeFilter');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.property('last', obj);
+ expect(obj).to.have.property('first', obj);
+
+ expect(obj).to.contain.property('position');
+ pixi_core_Point_confirm(obj.position, 0, 0);
+ expect(obj).to.contain.property('scale');
+ pixi_core_Point_confirm(obj.scale, 1, 1);
+ expect(obj).to.contain.property('pivot');
+ pixi_core_Point_confirm(obj.pivot, 0, 0);
+
+ expect(obj).to.have.property('rotation', 0);
+ expect(obj).to.have.property('alpha', 1);
+ expect(obj).to.have.property('visible', true);
+ expect(obj).to.have.property('buttonMode', false);
+ expect(obj).to.have.property('parent', null);
+ expect(obj).to.have.property('worldAlpha', 1);
+
+ expect(obj).to.have.property('hitArea');
+ expect(obj).to.have.property('interactive'); // TODO: Have a better default value
+ expect('mask' in obj).to.be.true; // TODO: Have a better default value
+ expect(obj.mask).to.be.undefined;
+
+ expect(obj).to.have.property('renderable');
+ expect(obj).to.have.property('stage');
+
+ expect(obj).to.have.deep.property('worldTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ expect(obj).to.have.deep.property('localTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.localTransform);
+
+ expect(obj).to.have.deep.property('color.length', 0);
+ expect(obj).to.have.property('dynamic', true);
+}
diff --git a/test/lib/pixi/display/DisplayObjectContainer.js b/test/lib/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..085c59f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,16 @@
+
+function pixi_display_DisplayObjectContainer_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObject_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObjectContainer);
+ expect(obj).to.respondTo('addChild');
+ expect(obj).to.respondTo('addChildAt');
+ expect(obj).to.respondTo('swapChildren');
+ expect(obj).to.respondTo('getChildAt');
+ expect(obj).to.respondTo('removeChild');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('children.length', 0);
+}
diff --git a/test/lib/pixi/display/Sprite.js b/test/lib/pixi/display/Sprite.js
new file mode 100644
index 0000000..cc7a2d6
--- /dev/null
+++ b/test/lib/pixi/display/Sprite.js
@@ -0,0 +1,28 @@
+
+function pixi_display_Sprite_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Sprite);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', true);
+ expect(obj).to.have.property('stage', null);
+
+ expect(obj).to.have.property('anchor');
+ pixi_core_Point_confirm(obj.anchor, 0, 0);
+
+ expect(obj).to.have.property('blendMode', PIXI.blendModes.NORMAL);
+ expect(obj).to.have.property('width', 1); // TODO: is 1 expected
+ expect(obj).to.have.property('height', 1); // TODO: is 1 expected
+
+ // FIXME: Just make this a boolean that is always there
+ expect(!!obj.updateFrame).to.equal(obj.texture.baseTexture.hasLoaded);
+
+ expect(obj).to.have.property('texture');
+ pixi_textures_Texture_confirmNew(obj.texture, done);
+}
diff --git a/test/lib/pixi/extras/Strip.js b/test/lib/pixi/extras/Strip.js
new file mode 100644
index 0000000..8927a8a
--- /dev/null
+++ b/test/lib/pixi/extras/Strip.js
@@ -0,0 +1,12 @@
+
+function pixi_extras_Strip_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Strip);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ // TODO: Test properties
+}
diff --git a/test/lib/pixi/textures/Texture.js b/test/lib/pixi/textures/Texture.js
new file mode 100644
index 0000000..d5867b6
--- /dev/null
+++ b/test/lib/pixi/textures/Texture.js
@@ -0,0 +1,31 @@
+
+function pixi_textures_Texture_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ function confirmFrameDone() {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, obj.baseTexture.width, obj.baseTexture.height);
+
+ expect(obj).to.have.property('width', obj.baseTexture.width);
+ expect(obj).to.have.property('height', obj.baseTexture.height);
+ done();
+ }
+
+ expect(obj).to.be.an.instanceof(PIXI.Texture);
+ pixi_utils_EventTarget_like(obj);
+
+ expect(obj).to.have.property('baseTexture')
+ .and.to.be.an.instanceof(PIXI.BaseTexture);
+
+ expect(obj).to.have.property('scope', obj);
+
+ expect(obj).to.have.property('trim');
+ pixi_core_Point_confirm(obj.trim, 0, 0);
+
+ expect(obj).to.have.property('frame');
+ if (obj.baseTexture.hasLoaded) {
+ confirmFrameDone();
+ } else {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, 1, 1);
+ obj.addEventListener('update', confirmFrameDone);
+ }
+}
diff --git a/test/lib/pixi/utils/EventTarget.js b/test/lib/pixi/utils/EventTarget.js
new file mode 100644
index 0000000..7b1dcfa
--- /dev/null
+++ b/test/lib/pixi/utils/EventTarget.js
@@ -0,0 +1,8 @@
+
+function pixi_utils_EventTarget_like(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.respondTo('addEventListener');
+ expect(obj).to.respondTo('dispatchEvent');
+ expect(obj).to.respondTo('removeEventListener');
+}
diff --git a/test/lib/qunit-1.11.0.css b/test/lib/qunit-1.11.0.css
deleted file mode 100644
index d7fc0c8..0000000
--- a/test/lib/qunit-1.11.0.css
+++ /dev/null
@@ -1,244 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-/** Font Family and Sizes */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
- font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
-}
-
-#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
-#qunit-tests { font-size: smaller; }
-
-
-/** Resets */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter {
- margin: 0;
- padding: 0;
-}
-
-
-/** Header */
-
-#qunit-header {
- padding: 0.5em 0 0.5em 1em;
-
- color: #8699a4;
- background-color: #0d3349;
-
- font-size: 1.5em;
- line-height: 1em;
- font-weight: normal;
-
- border-radius: 5px 5px 0 0;
- -moz-border-radius: 5px 5px 0 0;
- -webkit-border-top-right-radius: 5px;
- -webkit-border-top-left-radius: 5px;
-}
-
-#qunit-header a {
- text-decoration: none;
- color: #c2ccd1;
-}
-
-#qunit-header a:hover,
-#qunit-header a:focus {
- color: #fff;
-}
-
-#qunit-testrunner-toolbar label {
- display: inline-block;
- padding: 0 .5em 0 .1em;
-}
-
-#qunit-banner {
- height: 5px;
-}
-
-#qunit-testrunner-toolbar {
- padding: 0.5em 0 0.5em 2em;
- color: #5E740B;
- background-color: #eee;
- overflow: hidden;
-}
-
-#qunit-userAgent {
- padding: 0.5em 0 0.5em 2.5em;
- background-color: #2b81af;
- color: #fff;
- text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
-}
-
-#qunit-modulefilter-container {
- float: right;
-}
-
-/** Tests: Pass/Fail */
-
-#qunit-tests {
- list-style-position: inside;
-}
-
-#qunit-tests li {
- padding: 0.4em 0.5em 0.4em 2.5em;
- border-bottom: 1px solid #fff;
- list-style-position: inside;
-}
-
-#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running {
- display: none;
-}
-
-#qunit-tests li strong {
- cursor: pointer;
-}
-
-#qunit-tests li a {
- padding: 0.5em;
- color: #c2ccd1;
- text-decoration: none;
-}
-#qunit-tests li a:hover,
-#qunit-tests li a:focus {
- color: #000;
-}
-
-#qunit-tests li .runtime {
- float: right;
- font-size: smaller;
-}
-
-.qunit-assert-list {
- margin-top: 0.5em;
- padding: 0.5em;
-
- background-color: #fff;
-
- border-radius: 5px;
- -moz-border-radius: 5px;
- -webkit-border-radius: 5px;
-}
-
-.qunit-collapsed {
- display: none;
-}
-
-#qunit-tests table {
- border-collapse: collapse;
- margin-top: .2em;
-}
-
-#qunit-tests th {
- text-align: right;
- vertical-align: top;
- padding: 0 .5em 0 0;
-}
-
-#qunit-tests td {
- vertical-align: top;
-}
-
-#qunit-tests pre {
- margin: 0;
- white-space: pre-wrap;
- word-wrap: break-word;
-}
-
-#qunit-tests del {
- background-color: #e0f2be;
- color: #374e0c;
- text-decoration: none;
-}
-
-#qunit-tests ins {
- background-color: #ffcaca;
- color: #500;
- text-decoration: none;
-}
-
-/*** Test Counts */
-
-#qunit-tests b.counts { color: black; }
-#qunit-tests b.passed { color: #5E740B; }
-#qunit-tests b.failed { color: #710909; }
-
-#qunit-tests li li {
- padding: 5px;
- background-color: #fff;
- border-bottom: none;
- list-style-position: inside;
-}
-
-/*** Passing Styles */
-
-#qunit-tests li li.pass {
- color: #3c510c;
- background-color: #fff;
- border-left: 10px solid #C6E746;
-}
-
-#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
-#qunit-tests .pass .test-name { color: #366097; }
-
-#qunit-tests .pass .test-actual,
-#qunit-tests .pass .test-expected { color: #999999; }
-
-#qunit-banner.qunit-pass { background-color: #C6E746; }
-
-/*** Failing Styles */
-
-#qunit-tests li li.fail {
- color: #710909;
- background-color: #fff;
- border-left: 10px solid #EE5757;
- white-space: pre;
-}
-
-#qunit-tests > li:last-child {
- border-radius: 0 0 5px 5px;
- -moz-border-radius: 0 0 5px 5px;
- -webkit-border-bottom-right-radius: 5px;
- -webkit-border-bottom-left-radius: 5px;
-}
-
-#qunit-tests .fail { color: #000000; background-color: #EE5757; }
-#qunit-tests .fail .test-name,
-#qunit-tests .fail .module-name { color: #000000; }
-
-#qunit-tests .fail .test-actual { color: #EE5757; }
-#qunit-tests .fail .test-expected { color: green; }
-
-#qunit-banner.qunit-fail { background-color: #EE5757; }
-
-
-/** Result */
-
-#qunit-testresult {
- padding: 0.5em 0.5em 0.5em 2.5em;
-
- color: #2b81af;
- background-color: #D2E0E6;
-
- border-bottom: 1px solid white;
-}
-#qunit-testresult .module-name {
- font-weight: bold;
-}
-
-/** Fixture */
-
-#qunit-fixture {
- position: absolute;
- top: -10000px;
- left: -10000px;
- width: 1000px;
- height: 1000px;
-}
diff --git a/.gitignore b/.gitignore
index 12e1b62..0b88317 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
node_modules
.DS_Store
-.project
\ No newline at end of file
+.project
+*.log
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..63e4d7c
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,8 @@
+language: node_js
+node_js:
+ - 0.10
+
+before_script:
+ - npm install -g grunt-cli
+ - export DISPLAY=:99.0
+ - sh -e /etc/init.d/xvfb start
diff --git a/Gruntfile.js b/Gruntfile.js
index b083b49..103938c 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -1,10 +1,12 @@
+'use strict';
+
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-connect');
- grunt.loadNpmTasks('grunt-contrib-qunit');
grunt.loadNpmTasks('grunt-contrib-yuidoc');
+ grunt.loadTasks('tasks');
var root = 'src/pixi/',
debug = 'bin/pixi.dev.js',
@@ -79,7 +81,7 @@
},
files: {
srcBlob: '<%= dirs.src %>/**/*.js',
- testBlob: '<%= dirs.test %>/unit/**/*.js',
+ testBlob: '<%= dirs.test %>/{functional,lib/pixi,unit}/**/*.js',
build: '<%= dirs.build %>/pixi.dev.js',
buildMin: '<%= dirs.build %>/pixi.js'
},
@@ -94,7 +96,12 @@
},
jshint: {
beforeconcat: srcFiles,
- test: ['<%= files.testBlob %>'],
+ test: {
+ src: ['<%= files.testBlob %>'],
+ options: {
+ expr: true
+ }
+ },
options: {
asi: true,
smarttabs: true
@@ -128,12 +135,6 @@
]
},
connect: {
- qunit: {
- options: {
- port: grunt.option('port-test') || 9002,
- base: './'
- }
- },
test: {
options: {
port: grunt.option('port-test') || 9002,
@@ -142,13 +143,6 @@
}
}
},
- qunit: {
- all: {
- options: {
- urls: ['http://localhost:' + (grunt.option('port-test') || 9002) + '/test/index.html']
- }
- }
- },
yuidoc: {
compile: {
name: '<%= pkg.name %>',
@@ -161,6 +155,13 @@
outdir: '<%= dirs.docs %>'
}
}
+ },
+ karma: {
+ unit: {
+ configFile: 'test/karma.conf.js',
+ // browsers: ['Chrome'],
+ singleRun: true
+ }
}
});
@@ -182,9 +183,10 @@
}
)
- grunt.registerTask('default', ['concat', 'uglify', 'distribute']);
grunt.registerTask('build', ['concat', 'uglify', 'distribute']);
- grunt.registerTask('test', ['build', 'connect:qunit', 'qunit']);
+ grunt.registerTask('test', ['concat', 'jshint:test', 'karma']);
grunt.registerTask('docs', ['yuidoc']);
-
-}
\ No newline at end of file
+ grunt.registerTask('default', ['test', 'uglify', 'distribute']);
+ // Travis CI task.
+ grunt.registerTask('travis', ['test']);
+}
diff --git a/README.md b/README.md
index c62ef86..690cfe4 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,8 @@

+[](http://travis-ci.org/drkibitz/pixi.js)
+
#### JavaScript 2D Renderer ####
The aim of this project is to provide a fast lightweight 2D library that works
diff --git a/package.json b/package.json
index b373240..1246a68 100644
--- a/package.json
+++ b/package.json
@@ -18,14 +18,21 @@
"main": "bin/pixi.js",
+ "scripts": {
+ "test": "grunt travis --verbose"
+ },
+
"dependencies": {},
"devDependencies": {
"grunt": "~0.4.x",
- "grunt-contrib-jshint": "0.3.x",
+ "grunt-contrib-jshint": "0.6.x",
"grunt-contrib-uglify": "0.2.x",
- "grunt-contrib-connect": "0.2.x",
- "grunt-contrib-qunit": "0.2.x",
+ "grunt-contrib-connect": "0.3.x",
"grunt-contrib-yuidoc": "0.4.x",
- "grunt-contrib-concat": "0.1.x"
+ "grunt-contrib-concat": "0.3.x",
+ "chai": "~1.7.0",
+ "karma": "0.11.0",
+ "karma-firefox-launcher": "0.1.0",
+ "karma-mocha": "0.1.0"
}
}
diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js
index a7c520e..ee82bbd 100644
--- a/src/pixi/InteractionManager.js
+++ b/src/pixi/InteractionManager.js
@@ -62,7 +62,6 @@
this.onTouchEnd = this.onTouchEnd.bind(this);
this.onTouchMove = this.onTouchMove.bind(this);
-
this.last = 0;
}
diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js
index 1a95d20..eef1059 100644
--- a/src/pixi/core/Ellipse.js
+++ b/src/pixi/core/Ellipse.js
@@ -78,7 +78,7 @@
return (normx + normy < 0.25);
}
-PIXI.Ellipse.getBounds = function()
+PIXI.Ellipse.prototype.getBounds = function()
{
return new PIXI.Rectangle(this.x, this.y, this.width, this.height);
}
diff --git a/tasks/karma.js b/tasks/karma.js
new file mode 100644
index 0000000..c340485
--- /dev/null
+++ b/tasks/karma.js
@@ -0,0 +1,27 @@
+'use strict';
+
+var path = require('path');
+var server = require('karma').server;
+
+module.exports = function (grunt) {
+ grunt.registerMultiTask('karma', 'run karma.', function() {
+ var done = this.async();
+ var options = this.options({
+ background: false
+ });
+ var data = this.data;
+
+ //merge options onto data, with data taking precedence
+ data = grunt.util._.merge(options, data);
+ data.configFile = path.resolve(data.configFile);
+ if (data.configFile) {
+ data.configFile = grunt.template.process(data.configFile);
+ }
+
+ server.start(
+ data,
+ function(code) {
+ done(!code);
+ });
+ });
+};
diff --git a/test/functional/example-1-basics/bunny.png b/test/functional/example-1-basics/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/functional/example-1-basics/bunny.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-30.png b/test/functional/example-1-basics/frame-30.png
new file mode 100644
index 0000000..96e3409
--- /dev/null
+++ b/test/functional/example-1-basics/frame-30.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-60.png b/test/functional/example-1-basics/frame-60.png
new file mode 100644
index 0000000..af3f4ce
--- /dev/null
+++ b/test/functional/example-1-basics/frame-60.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-90.png b/test/functional/example-1-basics/frame-90.png
new file mode 100644
index 0000000..099b823
--- /dev/null
+++ b/test/functional/example-1-basics/frame-90.png
Binary files differ
diff --git a/test/functional/example-1-basics/index.js b/test/functional/example-1-basics/index.js
new file mode 100644
index 0000000..7ae7a98
--- /dev/null
+++ b/test/functional/example-1-basics/index.js
@@ -0,0 +1,133 @@
+describe('Example 1 - Basics', function () {
+ 'use strict';
+
+ var baseUri = '/base/test/functional/example-1-basics';
+ var expect = chai.expect;
+ var currentFrame = 0;
+ var frameEvents = {};
+ var stage;
+ var renderer;
+ var bunny;
+
+ function onFrame(frame, callback) {
+ frameEvents[frame] = callback;
+ }
+
+ function animate() {
+ currentFrame += 1;
+
+ requestAnimFrame( animate );
+
+ // just for fun, lets rotate mr rabbit a little
+ bunny.rotation += 0.1;
+
+ // render the stage
+ renderer.render(stage);
+
+ if (frameEvents[currentFrame])
+ frameEvents[currentFrame](currentFrame);
+ }
+
+ function initScene() {
+ // create an new instance of a pixi stage
+ stage = new PIXI.Stage(0x66FF99);
+
+ // create a renderer instance
+ renderer = PIXI.autoDetectRenderer(400, 300);
+ console.log('Is PIXI.WebGLRenderer: ' + (renderer instanceof PIXI.WebGLRenderer));
+
+ // add the renderer view element to the DOM
+ document.body.appendChild(renderer.view);
+
+ requestAnimFrame( animate );
+
+ // create a texture from an image path
+ var texture = PIXI.Texture.fromImage(baseUri + "/bunny.png");
+ // create a new Sprite using the texture
+ bunny = new PIXI.Sprite(texture);
+
+ // center the sprites anchor point
+ bunny.anchor.x = 0.5;
+ bunny.anchor.y = 0.5;
+
+ // move the sprite t the center of the screen
+ bunny.position.x = 200;
+ bunny.position.y = 150;
+
+ stage.addChild(bunny);
+ }
+
+ it('assets loaded', function (done) {
+ var loader = new PIXI.AssetLoader([
+ baseUri + '/bunny.png',
+ baseUri + '/frame-30.png',
+ baseUri + '/frame-60.png',
+ baseUri + '/frame-90.png'
+ ]);
+ // loader.on('onProgress', function (event) {
+ // console.log(event.content);
+ // });
+ loader.on('onComplete', function (event) {
+ done();
+ initScene();
+ });
+ loader.load();
+ });
+
+ it('frame 30 should match', function (done) {
+ this.timeout(700);
+ onFrame(30, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-30.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 60 should match', function (done) {
+ this.timeout(1200);
+ onFrame(60, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-60.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 90 should match', function (done) {
+ this.timeout(1700);
+ onFrame(90, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-90.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ // it('capture something', function (done) {
+ // this.timeout(2000000);
+ // onFrame(30, function () {
+ // var img = new Image();
+ // img.src = renderer.view.toDataURL('image/png');
+ // document.body.appendChild(img);
+ // });
+ // });
+});
diff --git a/test/index.html b/test/index.html
deleted file mode 100644
index 9cbcac5..0000000
--- a/test/index.html
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
- Pixi.js Test Suite
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/test/karma.conf.js b/test/karma.conf.js
new file mode 100644
index 0000000..c66a696
--- /dev/null
+++ b/test/karma.conf.js
@@ -0,0 +1,82 @@
+module.exports = function(config) {
+ config.set({
+
+ // base path, that will be used to resolve files and exclude
+ basePath : '../',
+
+ frameworks : ['mocha'],
+
+ // list of files / patterns to load in the browser
+ files : [
+ 'node_modules/chai/chai.js',
+ 'bin/pixi.dev.js',
+ 'test/lib/**/*.js',
+ 'test/unit/**/*.js',
+ // 'test/functional/**/*.js',
+ {pattern: 'test/**/*.png', watched: false, included: false, served: true}
+ ],
+
+ // list of files to exclude
+ exclude : [],
+
+ // use dolts reporter, as travis terminal does not support escaping sequences
+ // possible values: 'dots', 'progress', 'junit', 'teamcity'
+ // CLI --reporters progress
+ reporters : ['progress'],
+
+ // web server port
+ // CLI --port 9876
+ port : 9876,
+
+ // cli runner port
+ // CLI --runner-port 9100
+ runnerPort : 9100,
+
+ // enable / disable colors in the output (reporters and logs)
+ // CLI --colors --no-colors
+ colors : true,
+
+ // level of logging
+ // possible values: karma.LOG_DISABLE || karma.LOG_ERROR || karma.LOG_WARN || karma.LOG_INFO || karma.LOG_DEBUG
+ // CLI --log-level debug
+ logLevel : config.LOG_DEBUG,
+
+ // enable / disable watching file and executing tests whenever any file changes
+ // CLI --auto-watch --no-auto-watch
+ autoWatch : false,
+
+ // Start these browsers, currently available:
+ // - Chrome
+ // - ChromeCanary
+ // - Firefox
+ // - Opera
+ // - Safari (only Mac)
+ // - PhantomJS
+ // - IE (only Windows)
+ // CLI --browsers Chrome,Firefox,Safari
+ browsers : ['Firefox'],
+
+ // If browser does not capture in given timeout [ms], kill it
+ // CLI --capture-timeout 5000
+ captureTimeout : 5000,
+
+ // Auto run tests on start (when browsers are captured) and exit
+ // CLI --single-run --no-single-run
+ singleRun : true,
+
+ // report which specs are slower than 500ms
+ // CLI --report-slower-than 500
+ reportSlowerThan : 1000,
+
+ preprocessors : {
+ // '**/client/js/*.js': 'coverage'
+ },
+
+ plugins : [
+ 'karma-mocha',
+ // 'karma-chrome-launcher',
+ 'karma-firefox-launcher',
+ // 'karma-phantomjs-launcher'
+ ]
+ });
+};
diff --git a/test/lib/pixi/core/Matrix.js b/test/lib/pixi/core/Matrix.js
new file mode 100644
index 0000000..d26386b
--- /dev/null
+++ b/test/lib/pixi/core/Matrix.js
@@ -0,0 +1,40 @@
+
+function pixi_core_Matrix_confirmNewMat3(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(1);
+ expect(matrix[5]).to.equal(0);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(1);
+}
+
+function pixi_core_Matrix_confirmNewMat4(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[0]).to.equal(1);
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(0);
+ expect(matrix[5]).to.equal(1);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(0);
+ expect(matrix[9]).to.equal(0);
+ expect(matrix[10]).to.equal(1);
+ expect(matrix[11]).to.equal(0);
+ expect(matrix[12]).to.equal(0);
+ expect(matrix[13]).to.equal(0);
+ expect(matrix[14]).to.equal(0);
+ expect(matrix[15]).to.equal(1);
+}
diff --git a/test/lib/pixi/core/Point.js b/test/lib/pixi/core/Point.js
new file mode 100644
index 0000000..e5df07b
--- /dev/null
+++ b/test/lib/pixi/core/Point.js
@@ -0,0 +1,10 @@
+
+function pixi_core_Point_confirm(obj, x, y) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Point);
+ expect(obj).to.respondTo('clone');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+}
diff --git a/test/lib/pixi/core/Rectangle.js b/test/lib/pixi/core/Rectangle.js
new file mode 100644
index 0000000..23f0d12
--- /dev/null
+++ b/test/lib/pixi/core/Rectangle.js
@@ -0,0 +1,13 @@
+
+function pixi_core_Rectangle_confirm(obj, x, y, width, height) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Rectangle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+ expect(obj).to.have.property('width', width);
+ expect(obj).to.have.property('height', height);
+}
diff --git a/test/lib/pixi/display/DisplayObject.js b/test/lib/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..1388a7f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObject.js
@@ -0,0 +1,43 @@
+
+function pixi_display_DisplayObject_confirmNew(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObject);
+ expect(obj).to.respondTo('setInteractive');
+ expect(obj).to.respondTo('addFilter');
+ expect(obj).to.respondTo('removeFilter');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.property('last', obj);
+ expect(obj).to.have.property('first', obj);
+
+ expect(obj).to.contain.property('position');
+ pixi_core_Point_confirm(obj.position, 0, 0);
+ expect(obj).to.contain.property('scale');
+ pixi_core_Point_confirm(obj.scale, 1, 1);
+ expect(obj).to.contain.property('pivot');
+ pixi_core_Point_confirm(obj.pivot, 0, 0);
+
+ expect(obj).to.have.property('rotation', 0);
+ expect(obj).to.have.property('alpha', 1);
+ expect(obj).to.have.property('visible', true);
+ expect(obj).to.have.property('buttonMode', false);
+ expect(obj).to.have.property('parent', null);
+ expect(obj).to.have.property('worldAlpha', 1);
+
+ expect(obj).to.have.property('hitArea');
+ expect(obj).to.have.property('interactive'); // TODO: Have a better default value
+ expect('mask' in obj).to.be.true; // TODO: Have a better default value
+ expect(obj.mask).to.be.undefined;
+
+ expect(obj).to.have.property('renderable');
+ expect(obj).to.have.property('stage');
+
+ expect(obj).to.have.deep.property('worldTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ expect(obj).to.have.deep.property('localTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.localTransform);
+
+ expect(obj).to.have.deep.property('color.length', 0);
+ expect(obj).to.have.property('dynamic', true);
+}
diff --git a/test/lib/pixi/display/DisplayObjectContainer.js b/test/lib/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..085c59f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,16 @@
+
+function pixi_display_DisplayObjectContainer_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObject_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObjectContainer);
+ expect(obj).to.respondTo('addChild');
+ expect(obj).to.respondTo('addChildAt');
+ expect(obj).to.respondTo('swapChildren');
+ expect(obj).to.respondTo('getChildAt');
+ expect(obj).to.respondTo('removeChild');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('children.length', 0);
+}
diff --git a/test/lib/pixi/display/Sprite.js b/test/lib/pixi/display/Sprite.js
new file mode 100644
index 0000000..cc7a2d6
--- /dev/null
+++ b/test/lib/pixi/display/Sprite.js
@@ -0,0 +1,28 @@
+
+function pixi_display_Sprite_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Sprite);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', true);
+ expect(obj).to.have.property('stage', null);
+
+ expect(obj).to.have.property('anchor');
+ pixi_core_Point_confirm(obj.anchor, 0, 0);
+
+ expect(obj).to.have.property('blendMode', PIXI.blendModes.NORMAL);
+ expect(obj).to.have.property('width', 1); // TODO: is 1 expected
+ expect(obj).to.have.property('height', 1); // TODO: is 1 expected
+
+ // FIXME: Just make this a boolean that is always there
+ expect(!!obj.updateFrame).to.equal(obj.texture.baseTexture.hasLoaded);
+
+ expect(obj).to.have.property('texture');
+ pixi_textures_Texture_confirmNew(obj.texture, done);
+}
diff --git a/test/lib/pixi/extras/Strip.js b/test/lib/pixi/extras/Strip.js
new file mode 100644
index 0000000..8927a8a
--- /dev/null
+++ b/test/lib/pixi/extras/Strip.js
@@ -0,0 +1,12 @@
+
+function pixi_extras_Strip_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Strip);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ // TODO: Test properties
+}
diff --git a/test/lib/pixi/textures/Texture.js b/test/lib/pixi/textures/Texture.js
new file mode 100644
index 0000000..d5867b6
--- /dev/null
+++ b/test/lib/pixi/textures/Texture.js
@@ -0,0 +1,31 @@
+
+function pixi_textures_Texture_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ function confirmFrameDone() {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, obj.baseTexture.width, obj.baseTexture.height);
+
+ expect(obj).to.have.property('width', obj.baseTexture.width);
+ expect(obj).to.have.property('height', obj.baseTexture.height);
+ done();
+ }
+
+ expect(obj).to.be.an.instanceof(PIXI.Texture);
+ pixi_utils_EventTarget_like(obj);
+
+ expect(obj).to.have.property('baseTexture')
+ .and.to.be.an.instanceof(PIXI.BaseTexture);
+
+ expect(obj).to.have.property('scope', obj);
+
+ expect(obj).to.have.property('trim');
+ pixi_core_Point_confirm(obj.trim, 0, 0);
+
+ expect(obj).to.have.property('frame');
+ if (obj.baseTexture.hasLoaded) {
+ confirmFrameDone();
+ } else {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, 1, 1);
+ obj.addEventListener('update', confirmFrameDone);
+ }
+}
diff --git a/test/lib/pixi/utils/EventTarget.js b/test/lib/pixi/utils/EventTarget.js
new file mode 100644
index 0000000..7b1dcfa
--- /dev/null
+++ b/test/lib/pixi/utils/EventTarget.js
@@ -0,0 +1,8 @@
+
+function pixi_utils_EventTarget_like(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.respondTo('addEventListener');
+ expect(obj).to.respondTo('dispatchEvent');
+ expect(obj).to.respondTo('removeEventListener');
+}
diff --git a/test/lib/qunit-1.11.0.css b/test/lib/qunit-1.11.0.css
deleted file mode 100644
index d7fc0c8..0000000
--- a/test/lib/qunit-1.11.0.css
+++ /dev/null
@@ -1,244 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-/** Font Family and Sizes */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
- font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
-}
-
-#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
-#qunit-tests { font-size: smaller; }
-
-
-/** Resets */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter {
- margin: 0;
- padding: 0;
-}
-
-
-/** Header */
-
-#qunit-header {
- padding: 0.5em 0 0.5em 1em;
-
- color: #8699a4;
- background-color: #0d3349;
-
- font-size: 1.5em;
- line-height: 1em;
- font-weight: normal;
-
- border-radius: 5px 5px 0 0;
- -moz-border-radius: 5px 5px 0 0;
- -webkit-border-top-right-radius: 5px;
- -webkit-border-top-left-radius: 5px;
-}
-
-#qunit-header a {
- text-decoration: none;
- color: #c2ccd1;
-}
-
-#qunit-header a:hover,
-#qunit-header a:focus {
- color: #fff;
-}
-
-#qunit-testrunner-toolbar label {
- display: inline-block;
- padding: 0 .5em 0 .1em;
-}
-
-#qunit-banner {
- height: 5px;
-}
-
-#qunit-testrunner-toolbar {
- padding: 0.5em 0 0.5em 2em;
- color: #5E740B;
- background-color: #eee;
- overflow: hidden;
-}
-
-#qunit-userAgent {
- padding: 0.5em 0 0.5em 2.5em;
- background-color: #2b81af;
- color: #fff;
- text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
-}
-
-#qunit-modulefilter-container {
- float: right;
-}
-
-/** Tests: Pass/Fail */
-
-#qunit-tests {
- list-style-position: inside;
-}
-
-#qunit-tests li {
- padding: 0.4em 0.5em 0.4em 2.5em;
- border-bottom: 1px solid #fff;
- list-style-position: inside;
-}
-
-#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running {
- display: none;
-}
-
-#qunit-tests li strong {
- cursor: pointer;
-}
-
-#qunit-tests li a {
- padding: 0.5em;
- color: #c2ccd1;
- text-decoration: none;
-}
-#qunit-tests li a:hover,
-#qunit-tests li a:focus {
- color: #000;
-}
-
-#qunit-tests li .runtime {
- float: right;
- font-size: smaller;
-}
-
-.qunit-assert-list {
- margin-top: 0.5em;
- padding: 0.5em;
-
- background-color: #fff;
-
- border-radius: 5px;
- -moz-border-radius: 5px;
- -webkit-border-radius: 5px;
-}
-
-.qunit-collapsed {
- display: none;
-}
-
-#qunit-tests table {
- border-collapse: collapse;
- margin-top: .2em;
-}
-
-#qunit-tests th {
- text-align: right;
- vertical-align: top;
- padding: 0 .5em 0 0;
-}
-
-#qunit-tests td {
- vertical-align: top;
-}
-
-#qunit-tests pre {
- margin: 0;
- white-space: pre-wrap;
- word-wrap: break-word;
-}
-
-#qunit-tests del {
- background-color: #e0f2be;
- color: #374e0c;
- text-decoration: none;
-}
-
-#qunit-tests ins {
- background-color: #ffcaca;
- color: #500;
- text-decoration: none;
-}
-
-/*** Test Counts */
-
-#qunit-tests b.counts { color: black; }
-#qunit-tests b.passed { color: #5E740B; }
-#qunit-tests b.failed { color: #710909; }
-
-#qunit-tests li li {
- padding: 5px;
- background-color: #fff;
- border-bottom: none;
- list-style-position: inside;
-}
-
-/*** Passing Styles */
-
-#qunit-tests li li.pass {
- color: #3c510c;
- background-color: #fff;
- border-left: 10px solid #C6E746;
-}
-
-#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
-#qunit-tests .pass .test-name { color: #366097; }
-
-#qunit-tests .pass .test-actual,
-#qunit-tests .pass .test-expected { color: #999999; }
-
-#qunit-banner.qunit-pass { background-color: #C6E746; }
-
-/*** Failing Styles */
-
-#qunit-tests li li.fail {
- color: #710909;
- background-color: #fff;
- border-left: 10px solid #EE5757;
- white-space: pre;
-}
-
-#qunit-tests > li:last-child {
- border-radius: 0 0 5px 5px;
- -moz-border-radius: 0 0 5px 5px;
- -webkit-border-bottom-right-radius: 5px;
- -webkit-border-bottom-left-radius: 5px;
-}
-
-#qunit-tests .fail { color: #000000; background-color: #EE5757; }
-#qunit-tests .fail .test-name,
-#qunit-tests .fail .module-name { color: #000000; }
-
-#qunit-tests .fail .test-actual { color: #EE5757; }
-#qunit-tests .fail .test-expected { color: green; }
-
-#qunit-banner.qunit-fail { background-color: #EE5757; }
-
-
-/** Result */
-
-#qunit-testresult {
- padding: 0.5em 0.5em 0.5em 2.5em;
-
- color: #2b81af;
- background-color: #D2E0E6;
-
- border-bottom: 1px solid white;
-}
-#qunit-testresult .module-name {
- font-weight: bold;
-}
-
-/** Fixture */
-
-#qunit-fixture {
- position: absolute;
- top: -10000px;
- left: -10000px;
- width: 1000px;
- height: 1000px;
-}
diff --git a/test/lib/qunit-1.11.0.js b/test/lib/qunit-1.11.0.js
deleted file mode 100644
index 302545f..0000000
--- a/test/lib/qunit-1.11.0.js
+++ /dev/null
@@ -1,2152 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-(function( window ) {
-
-var QUnit,
- assert,
- config,
- onErrorFnPrev,
- testId = 0,
- fileName = (sourceFromStacktrace( 0 ) || "" ).replace(/(:\d+)+\)?/, "").replace(/.+\//, ""),
- toString = Object.prototype.toString,
- hasOwn = Object.prototype.hasOwnProperty,
- // Keep a local reference to Date (GH-283)
- Date = window.Date,
- defined = {
- setTimeout: typeof window.setTimeout !== "undefined",
- sessionStorage: (function() {
- var x = "qunit-test-string";
- try {
- sessionStorage.setItem( x, x );
- sessionStorage.removeItem( x );
- return true;
- } catch( e ) {
- return false;
- }
- }())
- },
- /**
- * Provides a normalized error string, correcting an issue
- * with IE 7 (and prior) where Error.prototype.toString is
- * not properly implemented
- *
- * Based on http://es5.github.com/#x15.11.4.4
- *
- * @param {String|Error} error
- * @return {String} error message
- */
- errorString = function( error ) {
- var name, message,
- errorString = error.toString();
- if ( errorString.substring( 0, 7 ) === "[object" ) {
- name = error.name ? error.name.toString() : "Error";
- message = error.message ? error.message.toString() : "";
- if ( name && message ) {
- return name + ": " + message;
- } else if ( name ) {
- return name;
- } else if ( message ) {
- return message;
- } else {
- return "Error";
- }
- } else {
- return errorString;
- }
- },
- /**
- * Makes a clone of an object using only Array or Object as base,
- * and copies over the own enumerable properties.
- *
- * @param {Object} obj
- * @return {Object} New object with only the own properties (recursively).
- */
- objectValues = function( obj ) {
- // Grunt 0.3.x uses an older version of jshint that still has jshint/jshint#392.
- /*jshint newcap: false */
- var key, val,
- vals = QUnit.is( "array", obj ) ? [] : {};
- for ( key in obj ) {
- if ( hasOwn.call( obj, key ) ) {
- val = obj[key];
- vals[key] = val === Object(val) ? objectValues(val) : val;
- }
- }
- return vals;
- };
-
-function Test( settings ) {
- extend( this, settings );
- this.assertions = [];
- this.testNumber = ++Test.count;
-}
-
-Test.count = 0;
-
-Test.prototype = {
- init: function() {
- var a, b, li,
- tests = id( "qunit-tests" );
-
- if ( tests ) {
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml;
-
- // `a` initialized at top of scope
- a = document.createElement( "a" );
- a.innerHTML = "Rerun";
- a.href = QUnit.url({ testNumber: this.testNumber });
-
- li = document.createElement( "li" );
- li.appendChild( b );
- li.appendChild( a );
- li.className = "running";
- li.id = this.id = "qunit-test-output" + testId++;
-
- tests.appendChild( li );
- }
- },
- setup: function() {
- if ( this.module !== config.previousModule ) {
- if ( config.previousModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.previousModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
- config.previousModule = this.module;
- config.moduleStats = { all: 0, bad: 0 };
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- } else if ( config.autorun ) {
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- }
-
- config.current = this;
-
- this.testEnvironment = extend({
- setup: function() {},
- teardown: function() {}
- }, this.moduleTestEnvironment );
-
- this.started = +new Date();
- runLoggingCallbacks( "testStart", QUnit, {
- name: this.testName,
- module: this.module
- });
-
- // allow utility functions to access the current test environment
- // TODO why??
- QUnit.current_testEnvironment = this.testEnvironment;
-
- if ( !config.pollution ) {
- saveGlobal();
- }
- if ( config.notrycatch ) {
- this.testEnvironment.setup.call( this.testEnvironment );
- return;
- }
- try {
- this.testEnvironment.setup.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Setup failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- },
- run: function() {
- config.current = this;
-
- var running = id( "qunit-testresult" );
-
- if ( running ) {
- running.innerHTML = "Running:
" + this.nameHtml;
- }
-
- if ( this.async ) {
- QUnit.stop();
- }
-
- this.callbackStarted = +new Date();
-
- if ( config.notrycatch ) {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- return;
- }
-
- try {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- } catch( e ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
-
- QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + " " + this.stack + ": " + ( e.message || e ), extractStacktrace( e, 0 ) );
- // else next test will carry the responsibility
- saveGlobal();
-
- // Restart the tests if they're blocking
- if ( config.blocking ) {
- QUnit.start();
- }
- }
- },
- teardown: function() {
- config.current = this;
- if ( config.notrycatch ) {
- if ( typeof this.callbackRuntime === "undefined" ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
- }
- this.testEnvironment.teardown.call( this.testEnvironment );
- return;
- } else {
- try {
- this.testEnvironment.teardown.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Teardown failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- }
- checkPollution();
- },
- finish: function() {
- config.current = this;
- if ( config.requireExpects && this.expected === null ) {
- QUnit.pushFailure( "Expected number of assertions to be defined, but expect() was not called.", this.stack );
- } else if ( this.expected !== null && this.expected !== this.assertions.length ) {
- QUnit.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack );
- } else if ( this.expected === null && !this.assertions.length ) {
- QUnit.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions.", this.stack );
- }
-
- var i, assertion, a, b, time, li, ol,
- test = this,
- good = 0,
- bad = 0,
- tests = id( "qunit-tests" );
-
- this.runtime = +new Date() - this.started;
- config.stats.all += this.assertions.length;
- config.moduleStats.all += this.assertions.length;
-
- if ( tests ) {
- ol = document.createElement( "ol" );
- ol.className = "qunit-assert-list";
-
- for ( i = 0; i < this.assertions.length; i++ ) {
- assertion = this.assertions[i];
-
- li = document.createElement( "li" );
- li.className = assertion.result ? "pass" : "fail";
- li.innerHTML = assertion.message || ( assertion.result ? "okay" : "failed" );
- ol.appendChild( li );
-
- if ( assertion.result ) {
- good++;
- } else {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
-
- // store result when possible
- if ( QUnit.config.reorder && defined.sessionStorage ) {
- if ( bad ) {
- sessionStorage.setItem( "qunit-test-" + this.module + "-" + this.testName, bad );
- } else {
- sessionStorage.removeItem( "qunit-test-" + this.module + "-" + this.testName );
- }
- }
-
- if ( bad === 0 ) {
- addClass( ol, "qunit-collapsed" );
- }
-
- // `b` initialized at top of scope
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml + " (" + bad + ", " + good + ", " + this.assertions.length + ")";
-
- addEvent(b, "click", function() {
- var next = b.parentNode.lastChild,
- collapsed = hasClass( next, "qunit-collapsed" );
- ( collapsed ? removeClass : addClass )( next, "qunit-collapsed" );
- });
-
- addEvent(b, "dblclick", function( e ) {
- var target = e && e.target ? e.target : window.event.srcElement;
- if ( target.nodeName.toLowerCase() === "span" || target.nodeName.toLowerCase() === "b" ) {
- target = target.parentNode;
- }
- if ( window.location && target.nodeName.toLowerCase() === "strong" ) {
- window.location = QUnit.url({ testNumber: test.testNumber });
- }
- });
-
- // `time` initialized at top of scope
- time = document.createElement( "span" );
- time.className = "runtime";
- time.innerHTML = this.runtime + " ms";
-
- // `li` initialized at top of scope
- li = id( this.id );
- li.className = bad ? "fail" : "pass";
- li.removeChild( li.firstChild );
- a = li.firstChild;
- li.appendChild( b );
- li.appendChild( a );
- li.appendChild( time );
- li.appendChild( ol );
-
- } else {
- for ( i = 0; i < this.assertions.length; i++ ) {
- if ( !this.assertions[i].result ) {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
- }
-
- runLoggingCallbacks( "testDone", QUnit, {
- name: this.testName,
- module: this.module,
- failed: bad,
- passed: this.assertions.length - bad,
- total: this.assertions.length,
- duration: this.runtime
- });
-
- QUnit.reset();
-
- config.current = undefined;
- },
-
- queue: function() {
- var bad,
- test = this;
-
- synchronize(function() {
- test.init();
- });
- function run() {
- // each of these can by async
- synchronize(function() {
- test.setup();
- });
- synchronize(function() {
- test.run();
- });
- synchronize(function() {
- test.teardown();
- });
- synchronize(function() {
- test.finish();
- });
- }
-
- // `bad` initialized at top of scope
- // defer when previous test run passed, if storage is available
- bad = QUnit.config.reorder && defined.sessionStorage &&
- +sessionStorage.getItem( "qunit-test-" + this.module + "-" + this.testName );
-
- if ( bad ) {
- run();
- } else {
- synchronize( run, true );
- }
- }
-};
-
-// Root QUnit object.
-// `QUnit` initialized at top of scope
-QUnit = {
-
- // call on start of module test to prepend name to all tests
- module: function( name, testEnvironment ) {
- config.currentModule = name;
- config.currentModuleTestEnvironment = testEnvironment;
- config.modules[name] = true;
- },
-
- asyncTest: function( testName, expected, callback ) {
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- QUnit.test( testName, expected, callback, true );
- },
-
- test: function( testName, expected, callback, async ) {
- var test,
- nameHtml = "" + escapeText( testName ) + "";
-
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- if ( config.currentModule ) {
- nameHtml = "" + escapeText( config.currentModule ) + ": " + nameHtml;
- }
-
- test = new Test({
- nameHtml: nameHtml,
- testName: testName,
- expected: expected,
- async: async,
- callback: callback,
- module: config.currentModule,
- moduleTestEnvironment: config.currentModuleTestEnvironment,
- stack: sourceFromStacktrace( 2 )
- });
-
- if ( !validTest( test ) ) {
- return;
- }
-
- test.queue();
- },
-
- // Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through.
- expect: function( asserts ) {
- if (arguments.length === 1) {
- config.current.expected = asserts;
- } else {
- return config.current.expected;
- }
- },
-
- start: function( count ) {
- // QUnit hasn't been initialized yet.
- // Note: RequireJS (et al) may delay onLoad
- if ( config.semaphore === undefined ) {
- QUnit.begin(function() {
- // This is triggered at the top of QUnit.load, push start() to the event loop, to allow QUnit.load to finish first
- setTimeout(function() {
- QUnit.start( count );
- });
- });
- return;
- }
-
- config.semaphore -= count || 1;
- // don't start until equal number of stop-calls
- if ( config.semaphore > 0 ) {
- return;
- }
- // ignore if start is called more often then stop
- if ( config.semaphore < 0 ) {
- config.semaphore = 0;
- QUnit.pushFailure( "Called start() while already started (QUnit.config.semaphore was 0 already)", null, sourceFromStacktrace(2) );
- return;
- }
- // A slight delay, to avoid any current callbacks
- if ( defined.setTimeout ) {
- window.setTimeout(function() {
- if ( config.semaphore > 0 ) {
- return;
- }
- if ( config.timeout ) {
- clearTimeout( config.timeout );
- }
-
- config.blocking = false;
- process( true );
- }, 13);
- } else {
- config.blocking = false;
- process( true );
- }
- },
-
- stop: function( count ) {
- config.semaphore += count || 1;
- config.blocking = true;
-
- if ( config.testTimeout && defined.setTimeout ) {
- clearTimeout( config.timeout );
- config.timeout = window.setTimeout(function() {
- QUnit.ok( false, "Test timed out" );
- config.semaphore = 1;
- QUnit.start();
- }, config.testTimeout );
- }
- }
-};
-
-// `assert` initialized at top of scope
-// Asssert helpers
-// All of these must either call QUnit.push() or manually do:
-// - runLoggingCallbacks( "log", .. );
-// - config.current.assertions.push({ .. });
-// We attach it to the QUnit object *after* we expose the public API,
-// otherwise `assert` will become a global variable in browsers (#341).
-assert = {
- /**
- * Asserts rough true-ish result.
- * @name ok
- * @function
- * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" );
- */
- ok: function( result, msg ) {
- if ( !config.current ) {
- throw new Error( "ok() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
- result = !!result;
-
- var source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: msg
- };
-
- msg = escapeText( msg || (result ? "okay" : "failed" ) );
- msg = "" + msg + "";
-
- if ( !result ) {
- source = sourceFromStacktrace( 2 );
- if ( source ) {
- details.source = source;
- msg += "Source: | " + escapeText( source ) + " |
---|
";
- }
- }
- runLoggingCallbacks( "log", QUnit, details );
- config.current.assertions.push({
- result: result,
- message: msg
- });
- },
-
- /**
- * Assert that the first two arguments are equal, with an optional message.
- * Prints out both actual and expected values.
- * @name equal
- * @function
- * @example equal( format( "Received {0} bytes.", 2), "Received 2 bytes.", "format() replaces {0} with next argument" );
- */
- equal: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected == actual, actual, expected, message );
- },
-
- /**
- * @name notEqual
- * @function
- */
- notEqual: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected != actual, actual, expected, message );
- },
-
- /**
- * @name propEqual
- * @function
- */
- propEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notPropEqual
- * @function
- */
- notPropEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name deepEqual
- * @function
- */
- deepEqual: function( actual, expected, message ) {
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notDeepEqual
- * @function
- */
- notDeepEqual: function( actual, expected, message ) {
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name strictEqual
- * @function
- */
- strictEqual: function( actual, expected, message ) {
- QUnit.push( expected === actual, actual, expected, message );
- },
-
- /**
- * @name notStrictEqual
- * @function
- */
- notStrictEqual: function( actual, expected, message ) {
- QUnit.push( expected !== actual, actual, expected, message );
- },
-
- "throws": function( block, expected, message ) {
- var actual,
- expectedOutput = expected,
- ok = false;
-
- // 'expected' is optional
- if ( typeof expected === "string" ) {
- message = expected;
- expected = null;
- }
-
- config.current.ignoreGlobalErrors = true;
- try {
- block.call( config.current.testEnvironment );
- } catch (e) {
- actual = e;
- }
- config.current.ignoreGlobalErrors = false;
-
- if ( actual ) {
- // we don't want to validate thrown error
- if ( !expected ) {
- ok = true;
- expectedOutput = null;
- // expected is a regexp
- } else if ( QUnit.objectType( expected ) === "regexp" ) {
- ok = expected.test( errorString( actual ) );
- // expected is a constructor
- } else if ( actual instanceof expected ) {
- ok = true;
- // expected is a validation function which returns true is validation passed
- } else if ( expected.call( {}, actual ) === true ) {
- expectedOutput = null;
- ok = true;
- }
-
- QUnit.push( ok, actual, expectedOutput, message );
- } else {
- QUnit.pushFailure( message, null, 'No exception was thrown.' );
- }
- }
-};
-
-/**
- * @deprecate since 1.8.0
- * Kept assertion helpers in root for backwards compatibility.
- */
-extend( QUnit, assert );
-
-/**
- * @deprecated since 1.9.0
- * Kept root "raises()" for backwards compatibility.
- * (Note that we don't introduce assert.raises).
- */
-QUnit.raises = assert[ "throws" ];
-
-/**
- * @deprecated since 1.0.0, replaced with error pushes since 1.3.0
- * Kept to avoid TypeErrors for undefined methods.
- */
-QUnit.equals = function() {
- QUnit.push( false, false, false, "QUnit.equals has been deprecated since 2009 (e88049a0), use QUnit.equal instead" );
-};
-QUnit.same = function() {
- QUnit.push( false, false, false, "QUnit.same has been deprecated since 2009 (e88049a0), use QUnit.deepEqual instead" );
-};
-
-// We want access to the constructor's prototype
-(function() {
- function F() {}
- F.prototype = QUnit;
- QUnit = new F();
- // Make F QUnit's constructor so that we can add to the prototype later
- QUnit.constructor = F;
-}());
-
-/**
- * Config object: Maintain internal state
- * Later exposed as QUnit.config
- * `config` initialized at top of scope
- */
-config = {
- // The queue of tests to run
- queue: [],
-
- // block until document ready
- blocking: true,
-
- // when enabled, show only failing tests
- // gets persisted through sessionStorage and can be changed in UI via checkbox
- hidepassed: false,
-
- // by default, run previously failed tests first
- // very useful in combination with "Hide passed tests" checked
- reorder: true,
-
- // by default, modify document.title when suite is done
- altertitle: true,
-
- // when enabled, all tests must call expect()
- requireExpects: false,
-
- // add checkboxes that are persisted in the query-string
- // when enabled, the id is set to `true` as a `QUnit.config` property
- urlConfig: [
- {
- id: "noglobals",
- label: "Check for Globals",
- tooltip: "Enabling this will test if any test introduces new properties on the `window` object. Stored as query-strings."
- },
- {
- id: "notrycatch",
- label: "No try-catch",
- tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging exceptions in IE reasonable. Stored as query-strings."
- }
- ],
-
- // Set of all modules.
- modules: {},
-
- // logging callback queues
- begin: [],
- done: [],
- log: [],
- testStart: [],
- testDone: [],
- moduleStart: [],
- moduleDone: []
-};
-
-// Export global variables, unless an 'exports' object exists,
-// in that case we assume we're in CommonJS (dealt with on the bottom of the script)
-if ( typeof exports === "undefined" ) {
- extend( window, QUnit );
-
- // Expose QUnit object
- window.QUnit = QUnit;
-}
-
-// Initialize more QUnit.config and QUnit.urlParams
-(function() {
- var i,
- location = window.location || { search: "", protocol: "file:" },
- params = location.search.slice( 1 ).split( "&" ),
- length = params.length,
- urlParams = {},
- current;
-
- if ( params[ 0 ] ) {
- for ( i = 0; i < length; i++ ) {
- current = params[ i ].split( "=" );
- current[ 0 ] = decodeURIComponent( current[ 0 ] );
- // allow just a key to turn on a flag, e.g., test.html?noglobals
- current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true;
- urlParams[ current[ 0 ] ] = current[ 1 ];
- }
- }
-
- QUnit.urlParams = urlParams;
-
- // String search anywhere in moduleName+testName
- config.filter = urlParams.filter;
-
- // Exact match of the module name
- config.module = urlParams.module;
-
- config.testNumber = parseInt( urlParams.testNumber, 10 ) || null;
-
- // Figure out if we're running the tests from a server or not
- QUnit.isLocal = location.protocol === "file:";
-}());
-
-// Extend QUnit object,
-// these after set here because they should not be exposed as global functions
-extend( QUnit, {
- assert: assert,
-
- config: config,
-
- // Initialize the configuration options
- init: function() {
- extend( config, {
- stats: { all: 0, bad: 0 },
- moduleStats: { all: 0, bad: 0 },
- started: +new Date(),
- updateRate: 1000,
- blocking: false,
- autostart: true,
- autorun: false,
- filter: "",
- queue: [],
- semaphore: 1
- });
-
- var tests, banner, result,
- qunit = id( "qunit" );
-
- if ( qunit ) {
- qunit.innerHTML =
- "" +
- "" +
- "" +
- "" +
- "
";
- }
-
- tests = id( "qunit-tests" );
- banner = id( "qunit-banner" );
- result = id( "qunit-testresult" );
-
- if ( tests ) {
- tests.innerHTML = "";
- }
-
- if ( banner ) {
- banner.className = "";
- }
-
- if ( result ) {
- result.parentNode.removeChild( result );
- }
-
- if ( tests ) {
- result = document.createElement( "p" );
- result.id = "qunit-testresult";
- result.className = "result";
- tests.parentNode.insertBefore( result, tests );
- result.innerHTML = "Running...
";
- }
- },
-
- // Resets the test setup. Useful for tests that modify the DOM.
- reset: function() {
- var fixture = id( "qunit-fixture" );
- if ( fixture ) {
- fixture.innerHTML = config.fixture;
- }
- },
-
- // Trigger an event on an element.
- // @example triggerEvent( document.body, "click" );
- triggerEvent: function( elem, type, event ) {
- if ( document.createEvent ) {
- event = document.createEvent( "MouseEvents" );
- event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView,
- 0, 0, 0, 0, 0, false, false, false, false, 0, null);
-
- elem.dispatchEvent( event );
- } else if ( elem.fireEvent ) {
- elem.fireEvent( "on" + type );
- }
- },
-
- // Safe object type checking
- is: function( type, obj ) {
- return QUnit.objectType( obj ) === type;
- },
-
- objectType: function( obj ) {
- if ( typeof obj === "undefined" ) {
- return "undefined";
- // consider: typeof null === object
- }
- if ( obj === null ) {
- return "null";
- }
-
- var match = toString.call( obj ).match(/^\[object\s(.*)\]$/),
- type = match && match[1] || "";
-
- switch ( type ) {
- case "Number":
- if ( isNaN(obj) ) {
- return "nan";
- }
- return "number";
- case "String":
- case "Boolean":
- case "Array":
- case "Date":
- case "RegExp":
- case "Function":
- return type.toLowerCase();
- }
- if ( typeof obj === "object" ) {
- return "object";
- }
- return undefined;
- },
-
- push: function( result, actual, expected, message ) {
- if ( !config.current ) {
- throw new Error( "assertion outside test context, was " + sourceFromStacktrace() );
- }
-
- var output, source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: message,
- actual: actual,
- expected: expected
- };
-
- message = escapeText( message ) || ( result ? "okay" : "failed" );
- message = "" + message + "";
- output = message;
-
- if ( !result ) {
- expected = escapeText( QUnit.jsDump.parse(expected) );
- actual = escapeText( QUnit.jsDump.parse(actual) );
- output += "Expected: | " + expected + " |
";
-
- if ( actual !== expected ) {
- output += "Result: | " + actual + " |
";
- output += "Diff: | " + QUnit.diff( expected, actual ) + " |
";
- }
-
- source = sourceFromStacktrace();
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
- }
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: !!result,
- message: output
- });
- },
-
- pushFailure: function( message, source, actual ) {
- if ( !config.current ) {
- throw new Error( "pushFailure() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
-
- var output,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: false,
- message: message
- };
-
- message = escapeText( message ) || "error";
- message = "" + message + "";
- output = message;
-
- output += "";
-
- if ( actual ) {
- output += "Result: | " + escapeText( actual ) + " |
";
- }
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: false,
- message: output
- });
- },
-
- url: function( params ) {
- params = extend( extend( {}, QUnit.urlParams ), params );
- var key,
- querystring = "?";
-
- for ( key in params ) {
- if ( !hasOwn.call( params, key ) ) {
- continue;
- }
- querystring += encodeURIComponent( key ) + "=" +
- encodeURIComponent( params[ key ] ) + "&";
- }
- return window.location.protocol + "//" + window.location.host +
- window.location.pathname + querystring.slice( 0, -1 );
- },
-
- extend: extend,
- id: id,
- addEvent: addEvent
- // load, equiv, jsDump, diff: Attached later
-});
-
-/**
- * @deprecated: Created for backwards compatibility with test runner that set the hook function
- * into QUnit.{hook}, instead of invoking it and passing the hook function.
- * QUnit.constructor is set to the empty F() above so that we can add to it's prototype here.
- * Doing this allows us to tell if the following methods have been overwritten on the actual
- * QUnit object.
- */
-extend( QUnit.constructor.prototype, {
-
- // Logging callbacks; all receive a single argument with the listed properties
- // run test/logs.html for any related changes
- begin: registerLoggingCallback( "begin" ),
-
- // done: { failed, passed, total, runtime }
- done: registerLoggingCallback( "done" ),
-
- // log: { result, actual, expected, message }
- log: registerLoggingCallback( "log" ),
-
- // testStart: { name }
- testStart: registerLoggingCallback( "testStart" ),
-
- // testDone: { name, failed, passed, total, duration }
- testDone: registerLoggingCallback( "testDone" ),
-
- // moduleStart: { name }
- moduleStart: registerLoggingCallback( "moduleStart" ),
-
- // moduleDone: { name, failed, passed, total }
- moduleDone: registerLoggingCallback( "moduleDone" )
-});
-
-if ( typeof document === "undefined" || document.readyState === "complete" ) {
- config.autorun = true;
-}
-
-QUnit.load = function() {
- runLoggingCallbacks( "begin", QUnit, {} );
-
- // Initialize the config, saving the execution queue
- var banner, filter, i, label, len, main, ol, toolbar, userAgent, val,
- urlConfigCheckboxesContainer, urlConfigCheckboxes, moduleFilter,
- numModules = 0,
- moduleFilterHtml = "",
- urlConfigHtml = "",
- oldconfig = extend( {}, config );
-
- QUnit.init();
- extend(config, oldconfig);
-
- config.blocking = false;
-
- len = config.urlConfig.length;
-
- for ( i = 0; i < len; i++ ) {
- val = config.urlConfig[i];
- if ( typeof val === "string" ) {
- val = {
- id: val,
- label: val,
- tooltip: "[no tooltip available]"
- };
- }
- config[ val.id ] = QUnit.urlParams[ val.id ];
- urlConfigHtml += "";
- }
-
- moduleFilterHtml += "";
-
- // `userAgent` initialized at top of scope
- userAgent = id( "qunit-userAgent" );
- if ( userAgent ) {
- userAgent.innerHTML = navigator.userAgent;
- }
-
- // `banner` initialized at top of scope
- banner = id( "qunit-header" );
- if ( banner ) {
- banner.innerHTML = "" + banner.innerHTML + " ";
- }
-
- // `toolbar` initialized at top of scope
- toolbar = id( "qunit-testrunner-toolbar" );
- if ( toolbar ) {
- // `filter` initialized at top of scope
- filter = document.createElement( "input" );
- filter.type = "checkbox";
- filter.id = "qunit-filter-pass";
-
- addEvent( filter, "click", function() {
- var tmp,
- ol = document.getElementById( "qunit-tests" );
-
- if ( filter.checked ) {
- ol.className = ol.className + " hidepass";
- } else {
- tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " ";
- ol.className = tmp.replace( / hidepass /, " " );
- }
- if ( defined.sessionStorage ) {
- if (filter.checked) {
- sessionStorage.setItem( "qunit-filter-passed-tests", "true" );
- } else {
- sessionStorage.removeItem( "qunit-filter-passed-tests" );
- }
- }
- });
-
- if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem( "qunit-filter-passed-tests" ) ) {
- filter.checked = true;
- // `ol` initialized at top of scope
- ol = document.getElementById( "qunit-tests" );
- ol.className = ol.className + " hidepass";
- }
- toolbar.appendChild( filter );
-
- // `label` initialized at top of scope
- label = document.createElement( "label" );
- label.setAttribute( "for", "qunit-filter-pass" );
- label.setAttribute( "title", "Only show tests and assertons that fail. Stored in sessionStorage." );
- label.innerHTML = "Hide passed tests";
- toolbar.appendChild( label );
-
- urlConfigCheckboxesContainer = document.createElement("span");
- urlConfigCheckboxesContainer.innerHTML = urlConfigHtml;
- urlConfigCheckboxes = urlConfigCheckboxesContainer.getElementsByTagName("input");
- // For oldIE support:
- // * Add handlers to the individual elements instead of the container
- // * Use "click" instead of "change"
- // * Fallback from event.target to event.srcElement
- addEvents( urlConfigCheckboxes, "click", function( event ) {
- var params = {},
- target = event.target || event.srcElement;
- params[ target.name ] = target.checked ? true : undefined;
- window.location = QUnit.url( params );
- });
- toolbar.appendChild( urlConfigCheckboxesContainer );
-
- if (numModules > 1) {
- moduleFilter = document.createElement( 'span' );
- moduleFilter.setAttribute( 'id', 'qunit-modulefilter-container' );
- moduleFilter.innerHTML = moduleFilterHtml;
- addEvent( moduleFilter.lastChild, "change", function() {
- var selectBox = moduleFilter.getElementsByTagName("select")[0],
- selectedModule = decodeURIComponent(selectBox.options[selectBox.selectedIndex].value);
-
- window.location = QUnit.url( { module: ( selectedModule === "" ) ? undefined : selectedModule } );
- });
- toolbar.appendChild(moduleFilter);
- }
- }
-
- // `main` initialized at top of scope
- main = id( "qunit-fixture" );
- if ( main ) {
- config.fixture = main.innerHTML;
- }
-
- if ( config.autostart ) {
- QUnit.start();
- }
-};
-
-addEvent( window, "load", QUnit.load );
-
-// `onErrorFnPrev` initialized at top of scope
-// Preserve other handlers
-onErrorFnPrev = window.onerror;
-
-// Cover uncaught exceptions
-// Returning true will surpress the default browser handler,
-// returning false will let it run.
-window.onerror = function ( error, filePath, linerNr ) {
- var ret = false;
- if ( onErrorFnPrev ) {
- ret = onErrorFnPrev( error, filePath, linerNr );
- }
-
- // Treat return value as window.onerror itself does,
- // Only do our handling if not surpressed.
- if ( ret !== true ) {
- if ( QUnit.config.current ) {
- if ( QUnit.config.current.ignoreGlobalErrors ) {
- return true;
- }
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- } else {
- QUnit.test( "global failure", extend( function() {
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- }, { validTest: validTest } ) );
- }
- return false;
- }
-
- return ret;
-};
-
-function done() {
- config.autorun = true;
-
- // Log the last module results
- if ( config.currentModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.currentModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
-
- var i, key,
- banner = id( "qunit-banner" ),
- tests = id( "qunit-tests" ),
- runtime = +new Date() - config.started,
- passed = config.stats.all - config.stats.bad,
- html = [
- "Tests completed in ",
- runtime,
- " milliseconds.
",
- "",
- passed,
- " assertions of ",
- config.stats.all,
- " passed, ",
- config.stats.bad,
- " failed."
- ].join( "" );
-
- if ( banner ) {
- banner.className = ( config.stats.bad ? "qunit-fail" : "qunit-pass" );
- }
-
- if ( tests ) {
- id( "qunit-testresult" ).innerHTML = html;
- }
-
- if ( config.altertitle && typeof document !== "undefined" && document.title ) {
- // show ✖ for good, ✔ for bad suite result in title
- // use escape sequences in case file gets loaded with non-utf-8-charset
- document.title = [
- ( config.stats.bad ? "\u2716" : "\u2714" ),
- document.title.replace( /^[\u2714\u2716] /i, "" )
- ].join( " " );
- }
-
- // clear own sessionStorage items if all tests passed
- if ( config.reorder && defined.sessionStorage && config.stats.bad === 0 ) {
- // `key` & `i` initialized at top of scope
- for ( i = 0; i < sessionStorage.length; i++ ) {
- key = sessionStorage.key( i++ );
- if ( key.indexOf( "qunit-test-" ) === 0 ) {
- sessionStorage.removeItem( key );
- }
- }
- }
-
- // scroll back to top to show results
- if ( window.scrollTo ) {
- window.scrollTo(0, 0);
- }
-
- runLoggingCallbacks( "done", QUnit, {
- failed: config.stats.bad,
- passed: passed,
- total: config.stats.all,
- runtime: runtime
- });
-}
-
-/** @return Boolean: true if this test should be ran */
-function validTest( test ) {
- var include,
- filter = config.filter && config.filter.toLowerCase(),
- module = config.module && config.module.toLowerCase(),
- fullName = (test.module + ": " + test.testName).toLowerCase();
-
- // Internally-generated tests are always valid
- if ( test.callback && test.callback.validTest === validTest ) {
- delete test.callback.validTest;
- return true;
- }
-
- if ( config.testNumber ) {
- return test.testNumber === config.testNumber;
- }
-
- if ( module && ( !test.module || test.module.toLowerCase() !== module ) ) {
- return false;
- }
-
- if ( !filter ) {
- return true;
- }
-
- include = filter.charAt( 0 ) !== "!";
- if ( !include ) {
- filter = filter.slice( 1 );
- }
-
- // If the filter matches, we need to honour include
- if ( fullName.indexOf( filter ) !== -1 ) {
- return include;
- }
-
- // Otherwise, do the opposite
- return !include;
-}
-
-// so far supports only Firefox, Chrome and Opera (buggy), Safari (for real exceptions)
-// Later Safari and IE10 are supposed to support error.stack as well
-// See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack
-function extractStacktrace( e, offset ) {
- offset = offset === undefined ? 3 : offset;
-
- var stack, include, i;
-
- if ( e.stacktrace ) {
- // Opera
- return e.stacktrace.split( "\n" )[ offset + 3 ];
- } else if ( e.stack ) {
- // Firefox, Chrome
- stack = e.stack.split( "\n" );
- if (/^error$/i.test( stack[0] ) ) {
- stack.shift();
- }
- if ( fileName ) {
- include = [];
- for ( i = offset; i < stack.length; i++ ) {
- if ( stack[ i ].indexOf( fileName ) !== -1 ) {
- break;
- }
- include.push( stack[ i ] );
- }
- if ( include.length ) {
- return include.join( "\n" );
- }
- }
- return stack[ offset ];
- } else if ( e.sourceURL ) {
- // Safari, PhantomJS
- // hopefully one day Safari provides actual stacktraces
- // exclude useless self-reference for generated Error objects
- if ( /qunit.js$/.test( e.sourceURL ) ) {
- return;
- }
- // for actual exceptions, this is useful
- return e.sourceURL + ":" + e.line;
- }
-}
-function sourceFromStacktrace( offset ) {
- try {
- throw new Error();
- } catch ( e ) {
- return extractStacktrace( e, offset );
- }
-}
-
-/**
- * Escape text for attribute or text content.
- */
-function escapeText( s ) {
- if ( !s ) {
- return "";
- }
- s = s + "";
- // Both single quotes and double quotes (for attributes)
- return s.replace( /['"<>&]/g, function( s ) {
- switch( s ) {
- case '\'':
- return ''';
- case '"':
- return '"';
- case '<':
- return '<';
- case '>':
- return '>';
- case '&':
- return '&';
- }
- });
-}
-
-function synchronize( callback, last ) {
- config.queue.push( callback );
-
- if ( config.autorun && !config.blocking ) {
- process( last );
- }
-}
-
-function process( last ) {
- function next() {
- process( last );
- }
- var start = new Date().getTime();
- config.depth = config.depth ? config.depth + 1 : 1;
-
- while ( config.queue.length && !config.blocking ) {
- if ( !defined.setTimeout || config.updateRate <= 0 || ( ( new Date().getTime() - start ) < config.updateRate ) ) {
- config.queue.shift()();
- } else {
- window.setTimeout( next, 13 );
- break;
- }
- }
- config.depth--;
- if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) {
- done();
- }
-}
-
-function saveGlobal() {
- config.pollution = [];
-
- if ( config.noglobals ) {
- for ( var key in window ) {
- // in Opera sometimes DOM element ids show up here, ignore them
- if ( !hasOwn.call( window, key ) || /^qunit-test-output/.test( key ) ) {
- continue;
- }
- config.pollution.push( key );
- }
- }
-}
-
-function checkPollution() {
- var newGlobals,
- deletedGlobals,
- old = config.pollution;
-
- saveGlobal();
-
- newGlobals = diff( config.pollution, old );
- if ( newGlobals.length > 0 ) {
- QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join(", ") );
- }
-
- deletedGlobals = diff( old, config.pollution );
- if ( deletedGlobals.length > 0 ) {
- QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join(", ") );
- }
-}
-
-// returns a new Array with the elements that are in a but not in b
-function diff( a, b ) {
- var i, j,
- result = a.slice();
-
- for ( i = 0; i < result.length; i++ ) {
- for ( j = 0; j < b.length; j++ ) {
- if ( result[i] === b[j] ) {
- result.splice( i, 1 );
- i--;
- break;
- }
- }
- }
- return result;
-}
-
-function extend( a, b ) {
- for ( var prop in b ) {
- if ( b[ prop ] === undefined ) {
- delete a[ prop ];
-
- // Avoid "Member not found" error in IE8 caused by setting window.constructor
- } else if ( prop !== "constructor" || a !== window ) {
- a[ prop ] = b[ prop ];
- }
- }
-
- return a;
-}
-
-/**
- * @param {HTMLElement} elem
- * @param {string} type
- * @param {Function} fn
- */
-function addEvent( elem, type, fn ) {
- // Standards-based browsers
- if ( elem.addEventListener ) {
- elem.addEventListener( type, fn, false );
- // IE
- } else {
- elem.attachEvent( "on" + type, fn );
- }
-}
-
-/**
- * @param {Array|NodeList} elems
- * @param {string} type
- * @param {Function} fn
- */
-function addEvents( elems, type, fn ) {
- var i = elems.length;
- while ( i-- ) {
- addEvent( elems[i], type, fn );
- }
-}
-
-function hasClass( elem, name ) {
- return (" " + elem.className + " ").indexOf(" " + name + " ") > -1;
-}
-
-function addClass( elem, name ) {
- if ( !hasClass( elem, name ) ) {
- elem.className += (elem.className ? " " : "") + name;
- }
-}
-
-function removeClass( elem, name ) {
- var set = " " + elem.className + " ";
- // Class name may appear multiple times
- while ( set.indexOf(" " + name + " ") > -1 ) {
- set = set.replace(" " + name + " " , " ");
- }
- // If possible, trim it for prettiness, but not neccecarily
- elem.className = window.jQuery ? jQuery.trim( set ) : ( set.trim ? set.trim() : set );
-}
-
-function id( name ) {
- return !!( typeof document !== "undefined" && document && document.getElementById ) &&
- document.getElementById( name );
-}
-
-function registerLoggingCallback( key ) {
- return function( callback ) {
- config[key].push( callback );
- };
-}
-
-// Supports deprecated method of completely overwriting logging callbacks
-function runLoggingCallbacks( key, scope, args ) {
- var i, callbacks;
- if ( QUnit.hasOwnProperty( key ) ) {
- QUnit[ key ].call(scope, args );
- } else {
- callbacks = config[ key ];
- for ( i = 0; i < callbacks.length; i++ ) {
- callbacks[ i ].call( scope, args );
- }
- }
-}
-
-// Test for equality any JavaScript type.
-// Author: Philippe Rathé
-QUnit.equiv = (function() {
-
- // Call the o related callback with the given arguments.
- function bindCallbacks( o, callbacks, args ) {
- var prop = QUnit.objectType( o );
- if ( prop ) {
- if ( QUnit.objectType( callbacks[ prop ] ) === "function" ) {
- return callbacks[ prop ].apply( callbacks, args );
- } else {
- return callbacks[ prop ]; // or undefined
- }
- }
- }
-
- // the real equiv function
- var innerEquiv,
- // stack to decide between skip/abort functions
- callers = [],
- // stack to avoiding loops from circular referencing
- parents = [],
-
- getProto = Object.getPrototypeOf || function ( obj ) {
- return obj.__proto__;
- },
- callbacks = (function () {
-
- // for string, boolean, number and null
- function useStrictEquality( b, a ) {
- /*jshint eqeqeq:false */
- if ( b instanceof a.constructor || a instanceof b.constructor ) {
- // to catch short annotaion VS 'new' annotation of a
- // declaration
- // e.g. var i = 1;
- // var j = new Number(1);
- return a == b;
- } else {
- return a === b;
- }
- }
-
- return {
- "string": useStrictEquality,
- "boolean": useStrictEquality,
- "number": useStrictEquality,
- "null": useStrictEquality,
- "undefined": useStrictEquality,
-
- "nan": function( b ) {
- return isNaN( b );
- },
-
- "date": function( b, a ) {
- return QUnit.objectType( b ) === "date" && a.valueOf() === b.valueOf();
- },
-
- "regexp": function( b, a ) {
- return QUnit.objectType( b ) === "regexp" &&
- // the regex itself
- a.source === b.source &&
- // and its modifers
- a.global === b.global &&
- // (gmi) ...
- a.ignoreCase === b.ignoreCase &&
- a.multiline === b.multiline &&
- a.sticky === b.sticky;
- },
-
- // - skip when the property is a method of an instance (OOP)
- // - abort otherwise,
- // initial === would have catch identical references anyway
- "function": function() {
- var caller = callers[callers.length - 1];
- return caller !== Object && typeof caller !== "undefined";
- },
-
- "array": function( b, a ) {
- var i, j, len, loop;
-
- // b could be an object literal here
- if ( QUnit.objectType( b ) !== "array" ) {
- return false;
- }
-
- len = a.length;
- if ( len !== b.length ) {
- // safe and faster
- return false;
- }
-
- // track reference to avoid circular references
- parents.push( a );
- for ( i = 0; i < len; i++ ) {
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- loop = true;// dont rewalk array
- }
- }
- if ( !loop && !innerEquiv(a[i], b[i]) ) {
- parents.pop();
- return false;
- }
- }
- parents.pop();
- return true;
- },
-
- "object": function( b, a ) {
- var i, j, loop,
- // Default to true
- eq = true,
- aProperties = [],
- bProperties = [];
-
- // comparing constructors is more strict than using
- // instanceof
- if ( a.constructor !== b.constructor ) {
- // Allow objects with no prototype to be equivalent to
- // objects with Object as their constructor.
- if ( !(( getProto(a) === null && getProto(b) === Object.prototype ) ||
- ( getProto(b) === null && getProto(a) === Object.prototype ) ) ) {
- return false;
- }
- }
-
- // stack constructor before traversing properties
- callers.push( a.constructor );
- // track reference to avoid circular references
- parents.push( a );
-
- for ( i in a ) { // be strict: don't ensures hasOwnProperty
- // and go deep
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- // don't go down the same path twice
- loop = true;
- }
- }
- aProperties.push(i); // collect a's properties
-
- if (!loop && !innerEquiv( a[i], b[i] ) ) {
- eq = false;
- break;
- }
- }
-
- callers.pop(); // unstack, we are done
- parents.pop();
-
- for ( i in b ) {
- bProperties.push( i ); // collect b's properties
- }
-
- // Ensures identical properties name
- return eq && innerEquiv( aProperties.sort(), bProperties.sort() );
- }
- };
- }());
-
- innerEquiv = function() { // can take multiple arguments
- var args = [].slice.apply( arguments );
- if ( args.length < 2 ) {
- return true; // end transition
- }
-
- return (function( a, b ) {
- if ( a === b ) {
- return true; // catch the most you can
- } else if ( a === null || b === null || typeof a === "undefined" ||
- typeof b === "undefined" ||
- QUnit.objectType(a) !== QUnit.objectType(b) ) {
- return false; // don't lose time with error prone cases
- } else {
- return bindCallbacks(a, callbacks, [ b, a ]);
- }
-
- // apply transition with (1..n) arguments
- }( args[0], args[1] ) && arguments.callee.apply( this, args.splice(1, args.length - 1 )) );
- };
-
- return innerEquiv;
-}());
-
-/**
- * jsDump Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com |
- * http://flesler.blogspot.com Licensed under BSD
- * (http://www.opensource.org/licenses/bsd-license.php) Date: 5/15/2008
- *
- * @projectDescription Advanced and extensible data dumping for Javascript.
- * @version 1.0.0
- * @author Ariel Flesler
- * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html}
- */
-QUnit.jsDump = (function() {
- function quote( str ) {
- return '"' + str.toString().replace( /"/g, '\\"' ) + '"';
- }
- function literal( o ) {
- return o + "";
- }
- function join( pre, arr, post ) {
- var s = jsDump.separator(),
- base = jsDump.indent(),
- inner = jsDump.indent(1);
- if ( arr.join ) {
- arr = arr.join( "," + s + inner );
- }
- if ( !arr ) {
- return pre + post;
- }
- return [ pre, inner + arr, base + post ].join(s);
- }
- function array( arr, stack ) {
- var i = arr.length, ret = new Array(i);
- this.up();
- while ( i-- ) {
- ret[i] = this.parse( arr[i] , undefined , stack);
- }
- this.down();
- return join( "[", ret, "]" );
- }
-
- var reName = /^function (\w+)/,
- jsDump = {
- // type is used mostly internally, you can fix a (custom)type in advance
- parse: function( obj, type, stack ) {
- stack = stack || [ ];
- var inStack, res,
- parser = this.parsers[ type || this.typeOf(obj) ];
-
- type = typeof parser;
- inStack = inArray( obj, stack );
-
- if ( inStack !== -1 ) {
- return "recursion(" + (inStack - stack.length) + ")";
- }
- if ( type === "function" ) {
- stack.push( obj );
- res = parser.call( this, obj, stack );
- stack.pop();
- return res;
- }
- return ( type === "string" ) ? parser : this.parsers.error;
- },
- typeOf: function( obj ) {
- var type;
- if ( obj === null ) {
- type = "null";
- } else if ( typeof obj === "undefined" ) {
- type = "undefined";
- } else if ( QUnit.is( "regexp", obj) ) {
- type = "regexp";
- } else if ( QUnit.is( "date", obj) ) {
- type = "date";
- } else if ( QUnit.is( "function", obj) ) {
- type = "function";
- } else if ( typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined" ) {
- type = "window";
- } else if ( obj.nodeType === 9 ) {
- type = "document";
- } else if ( obj.nodeType ) {
- type = "node";
- } else if (
- // native arrays
- toString.call( obj ) === "[object Array]" ||
- // NodeList objects
- ( typeof obj.length === "number" && typeof obj.item !== "undefined" && ( obj.length ? obj.item(0) === obj[0] : ( obj.item( 0 ) === null && typeof obj[0] === "undefined" ) ) )
- ) {
- type = "array";
- } else if ( obj.constructor === Error.prototype.constructor ) {
- type = "error";
- } else {
- type = typeof obj;
- }
- return type;
- },
- separator: function() {
- return this.multiline ? this.HTML ? "
" : "\n" : this.HTML ? " " : " ";
- },
- // extra can be a number, shortcut for increasing-calling-decreasing
- indent: function( extra ) {
- if ( !this.multiline ) {
- return "";
- }
- var chr = this.indentChar;
- if ( this.HTML ) {
- chr = chr.replace( /\t/g, " " ).replace( / /g, " " );
- }
- return new Array( this._depth_ + (extra||0) ).join(chr);
- },
- up: function( a ) {
- this._depth_ += a || 1;
- },
- down: function( a ) {
- this._depth_ -= a || 1;
- },
- setParser: function( name, parser ) {
- this.parsers[name] = parser;
- },
- // The next 3 are exposed so you can use them
- quote: quote,
- literal: literal,
- join: join,
- //
- _depth_: 1,
- // This is the list of parsers, to modify them, use jsDump.setParser
- parsers: {
- window: "[Window]",
- document: "[Document]",
- error: function(error) {
- return "Error(\"" + error.message + "\")";
- },
- unknown: "[Unknown]",
- "null": "null",
- "undefined": "undefined",
- "function": function( fn ) {
- var ret = "function",
- // functions never have name in IE
- name = "name" in fn ? fn.name : (reName.exec(fn) || [])[1];
-
- if ( name ) {
- ret += " " + name;
- }
- ret += "( ";
-
- ret = [ ret, QUnit.jsDump.parse( fn, "functionArgs" ), "){" ].join( "" );
- return join( ret, QUnit.jsDump.parse(fn,"functionCode" ), "}" );
- },
- array: array,
- nodelist: array,
- "arguments": array,
- object: function( map, stack ) {
- var ret = [ ], keys, key, val, i;
- QUnit.jsDump.up();
- keys = [];
- for ( key in map ) {
- keys.push( key );
- }
- keys.sort();
- for ( i = 0; i < keys.length; i++ ) {
- key = keys[ i ];
- val = map[ key ];
- ret.push( QUnit.jsDump.parse( key, "key" ) + ": " + QUnit.jsDump.parse( val, undefined, stack ) );
- }
- QUnit.jsDump.down();
- return join( "{", ret, "}" );
- },
- node: function( node ) {
- var len, i, val,
- open = QUnit.jsDump.HTML ? "<" : "<",
- close = QUnit.jsDump.HTML ? ">" : ">",
- tag = node.nodeName.toLowerCase(),
- ret = open + tag,
- attrs = node.attributes;
-
- if ( attrs ) {
- for ( i = 0, len = attrs.length; i < len; i++ ) {
- val = attrs[i].nodeValue;
- // IE6 includes all attributes in .attributes, even ones not explicitly set.
- // Those have values like undefined, null, 0, false, "" or "inherit".
- if ( val && val !== "inherit" ) {
- ret += " " + attrs[i].nodeName + "=" + QUnit.jsDump.parse( val, "attribute" );
- }
- }
- }
- ret += close;
-
- // Show content of TextNode or CDATASection
- if ( node.nodeType === 3 || node.nodeType === 4 ) {
- ret += node.nodeValue;
- }
-
- return ret + open + "/" + tag + close;
- },
- // function calls it internally, it's the arguments part of the function
- functionArgs: function( fn ) {
- var args,
- l = fn.length;
-
- if ( !l ) {
- return "";
- }
-
- args = new Array(l);
- while ( l-- ) {
- // 97 is 'a'
- args[l] = String.fromCharCode(97+l);
- }
- return " " + args.join( ", " ) + " ";
- },
- // object calls it internally, the key part of an item in a map
- key: quote,
- // function calls it internally, it's the content of the function
- functionCode: "[code]",
- // node calls it internally, it's an html attribute value
- attribute: quote,
- string: quote,
- date: quote,
- regexp: literal,
- number: literal,
- "boolean": literal
- },
- // if true, entities are escaped ( <, >, \t, space and \n )
- HTML: false,
- // indentation unit
- indentChar: " ",
- // if true, items in a collection, are separated by a \n, else just a space.
- multiline: true
- };
-
- return jsDump;
-}());
-
-// from jquery.js
-function inArray( elem, array ) {
- if ( array.indexOf ) {
- return array.indexOf( elem );
- }
-
- for ( var i = 0, length = array.length; i < length; i++ ) {
- if ( array[ i ] === elem ) {
- return i;
- }
- }
-
- return -1;
-}
-
-/*
- * Javascript Diff Algorithm
- * By John Resig (http://ejohn.org/)
- * Modified by Chu Alan "sprite"
- *
- * Released under the MIT license.
- *
- * More Info:
- * http://ejohn.org/projects/javascript-diff-algorithm/
- *
- * Usage: QUnit.diff(expected, actual)
- *
- * QUnit.diff( "the quick brown fox jumped over", "the quick fox jumps over" ) == "the quick brown fox jumped jumps over"
- */
-QUnit.diff = (function() {
- /*jshint eqeqeq:false, eqnull:true */
- function diff( o, n ) {
- var i,
- ns = {},
- os = {};
-
- for ( i = 0; i < n.length; i++ ) {
- if ( !hasOwn.call( ns, n[i] ) ) {
- ns[ n[i] ] = {
- rows: [],
- o: null
- };
- }
- ns[ n[i] ].rows.push( i );
- }
-
- for ( i = 0; i < o.length; i++ ) {
- if ( !hasOwn.call( os, o[i] ) ) {
- os[ o[i] ] = {
- rows: [],
- n: null
- };
- }
- os[ o[i] ].rows.push( i );
- }
-
- for ( i in ns ) {
- if ( !hasOwn.call( ns, i ) ) {
- continue;
- }
- if ( ns[i].rows.length === 1 && hasOwn.call( os, i ) && os[i].rows.length === 1 ) {
- n[ ns[i].rows[0] ] = {
- text: n[ ns[i].rows[0] ],
- row: os[i].rows[0]
- };
- o[ os[i].rows[0] ] = {
- text: o[ os[i].rows[0] ],
- row: ns[i].rows[0]
- };
- }
- }
-
- for ( i = 0; i < n.length - 1; i++ ) {
- if ( n[i].text != null && n[ i + 1 ].text == null && n[i].row + 1 < o.length && o[ n[i].row + 1 ].text == null &&
- n[ i + 1 ] == o[ n[i].row + 1 ] ) {
-
- n[ i + 1 ] = {
- text: n[ i + 1 ],
- row: n[i].row + 1
- };
- o[ n[i].row + 1 ] = {
- text: o[ n[i].row + 1 ],
- row: i + 1
- };
- }
- }
-
- for ( i = n.length - 1; i > 0; i-- ) {
- if ( n[i].text != null && n[ i - 1 ].text == null && n[i].row > 0 && o[ n[i].row - 1 ].text == null &&
- n[ i - 1 ] == o[ n[i].row - 1 ]) {
-
- n[ i - 1 ] = {
- text: n[ i - 1 ],
- row: n[i].row - 1
- };
- o[ n[i].row - 1 ] = {
- text: o[ n[i].row - 1 ],
- row: i - 1
- };
- }
- }
-
- return {
- o: o,
- n: n
- };
- }
-
- return function( o, n ) {
- o = o.replace( /\s+$/, "" );
- n = n.replace( /\s+$/, "" );
-
- var i, pre,
- str = "",
- out = diff( o === "" ? [] : o.split(/\s+/), n === "" ? [] : n.split(/\s+/) ),
- oSpace = o.match(/\s+/g),
- nSpace = n.match(/\s+/g);
-
- if ( oSpace == null ) {
- oSpace = [ " " ];
- }
- else {
- oSpace.push( " " );
- }
-
- if ( nSpace == null ) {
- nSpace = [ " " ];
- }
- else {
- nSpace.push( " " );
- }
-
- if ( out.n.length === 0 ) {
- for ( i = 0; i < out.o.length; i++ ) {
- str += "" + out.o[i] + oSpace[i] + "";
- }
- }
- else {
- if ( out.n[0].text == null ) {
- for ( n = 0; n < out.o.length && out.o[n].text == null; n++ ) {
- str += "" + out.o[n] + oSpace[n] + "";
- }
- }
-
- for ( i = 0; i < out.n.length; i++ ) {
- if (out.n[i].text == null) {
- str += "" + out.n[i] + nSpace[i] + "";
- }
- else {
- // `pre` initialized at top of scope
- pre = "";
-
- for ( n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++ ) {
- pre += "" + out.o[n] + oSpace[n] + "";
- }
- str += " " + out.n[i].text + nSpace[i] + pre;
- }
- }
- }
-
- return str;
- };
-}());
-
-// for CommonJS enviroments, export everything
-if ( typeof exports !== "undefined" ) {
- extend( exports, QUnit );
-}
-
-// get at whatever the global object is, like window in browsers
-}( (function() {return this;}.call()) ));
diff --git a/.gitignore b/.gitignore
index 12e1b62..0b88317 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
node_modules
.DS_Store
-.project
\ No newline at end of file
+.project
+*.log
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..63e4d7c
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,8 @@
+language: node_js
+node_js:
+ - 0.10
+
+before_script:
+ - npm install -g grunt-cli
+ - export DISPLAY=:99.0
+ - sh -e /etc/init.d/xvfb start
diff --git a/Gruntfile.js b/Gruntfile.js
index b083b49..103938c 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -1,10 +1,12 @@
+'use strict';
+
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-connect');
- grunt.loadNpmTasks('grunt-contrib-qunit');
grunt.loadNpmTasks('grunt-contrib-yuidoc');
+ grunt.loadTasks('tasks');
var root = 'src/pixi/',
debug = 'bin/pixi.dev.js',
@@ -79,7 +81,7 @@
},
files: {
srcBlob: '<%= dirs.src %>/**/*.js',
- testBlob: '<%= dirs.test %>/unit/**/*.js',
+ testBlob: '<%= dirs.test %>/{functional,lib/pixi,unit}/**/*.js',
build: '<%= dirs.build %>/pixi.dev.js',
buildMin: '<%= dirs.build %>/pixi.js'
},
@@ -94,7 +96,12 @@
},
jshint: {
beforeconcat: srcFiles,
- test: ['<%= files.testBlob %>'],
+ test: {
+ src: ['<%= files.testBlob %>'],
+ options: {
+ expr: true
+ }
+ },
options: {
asi: true,
smarttabs: true
@@ -128,12 +135,6 @@
]
},
connect: {
- qunit: {
- options: {
- port: grunt.option('port-test') || 9002,
- base: './'
- }
- },
test: {
options: {
port: grunt.option('port-test') || 9002,
@@ -142,13 +143,6 @@
}
}
},
- qunit: {
- all: {
- options: {
- urls: ['http://localhost:' + (grunt.option('port-test') || 9002) + '/test/index.html']
- }
- }
- },
yuidoc: {
compile: {
name: '<%= pkg.name %>',
@@ -161,6 +155,13 @@
outdir: '<%= dirs.docs %>'
}
}
+ },
+ karma: {
+ unit: {
+ configFile: 'test/karma.conf.js',
+ // browsers: ['Chrome'],
+ singleRun: true
+ }
}
});
@@ -182,9 +183,10 @@
}
)
- grunt.registerTask('default', ['concat', 'uglify', 'distribute']);
grunt.registerTask('build', ['concat', 'uglify', 'distribute']);
- grunt.registerTask('test', ['build', 'connect:qunit', 'qunit']);
+ grunt.registerTask('test', ['concat', 'jshint:test', 'karma']);
grunt.registerTask('docs', ['yuidoc']);
-
-}
\ No newline at end of file
+ grunt.registerTask('default', ['test', 'uglify', 'distribute']);
+ // Travis CI task.
+ grunt.registerTask('travis', ['test']);
+}
diff --git a/README.md b/README.md
index c62ef86..690cfe4 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,8 @@

+[](http://travis-ci.org/drkibitz/pixi.js)
+
#### JavaScript 2D Renderer ####
The aim of this project is to provide a fast lightweight 2D library that works
diff --git a/package.json b/package.json
index b373240..1246a68 100644
--- a/package.json
+++ b/package.json
@@ -18,14 +18,21 @@
"main": "bin/pixi.js",
+ "scripts": {
+ "test": "grunt travis --verbose"
+ },
+
"dependencies": {},
"devDependencies": {
"grunt": "~0.4.x",
- "grunt-contrib-jshint": "0.3.x",
+ "grunt-contrib-jshint": "0.6.x",
"grunt-contrib-uglify": "0.2.x",
- "grunt-contrib-connect": "0.2.x",
- "grunt-contrib-qunit": "0.2.x",
+ "grunt-contrib-connect": "0.3.x",
"grunt-contrib-yuidoc": "0.4.x",
- "grunt-contrib-concat": "0.1.x"
+ "grunt-contrib-concat": "0.3.x",
+ "chai": "~1.7.0",
+ "karma": "0.11.0",
+ "karma-firefox-launcher": "0.1.0",
+ "karma-mocha": "0.1.0"
}
}
diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js
index a7c520e..ee82bbd 100644
--- a/src/pixi/InteractionManager.js
+++ b/src/pixi/InteractionManager.js
@@ -62,7 +62,6 @@
this.onTouchEnd = this.onTouchEnd.bind(this);
this.onTouchMove = this.onTouchMove.bind(this);
-
this.last = 0;
}
diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js
index 1a95d20..eef1059 100644
--- a/src/pixi/core/Ellipse.js
+++ b/src/pixi/core/Ellipse.js
@@ -78,7 +78,7 @@
return (normx + normy < 0.25);
}
-PIXI.Ellipse.getBounds = function()
+PIXI.Ellipse.prototype.getBounds = function()
{
return new PIXI.Rectangle(this.x, this.y, this.width, this.height);
}
diff --git a/tasks/karma.js b/tasks/karma.js
new file mode 100644
index 0000000..c340485
--- /dev/null
+++ b/tasks/karma.js
@@ -0,0 +1,27 @@
+'use strict';
+
+var path = require('path');
+var server = require('karma').server;
+
+module.exports = function (grunt) {
+ grunt.registerMultiTask('karma', 'run karma.', function() {
+ var done = this.async();
+ var options = this.options({
+ background: false
+ });
+ var data = this.data;
+
+ //merge options onto data, with data taking precedence
+ data = grunt.util._.merge(options, data);
+ data.configFile = path.resolve(data.configFile);
+ if (data.configFile) {
+ data.configFile = grunt.template.process(data.configFile);
+ }
+
+ server.start(
+ data,
+ function(code) {
+ done(!code);
+ });
+ });
+};
diff --git a/test/functional/example-1-basics/bunny.png b/test/functional/example-1-basics/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/functional/example-1-basics/bunny.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-30.png b/test/functional/example-1-basics/frame-30.png
new file mode 100644
index 0000000..96e3409
--- /dev/null
+++ b/test/functional/example-1-basics/frame-30.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-60.png b/test/functional/example-1-basics/frame-60.png
new file mode 100644
index 0000000..af3f4ce
--- /dev/null
+++ b/test/functional/example-1-basics/frame-60.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-90.png b/test/functional/example-1-basics/frame-90.png
new file mode 100644
index 0000000..099b823
--- /dev/null
+++ b/test/functional/example-1-basics/frame-90.png
Binary files differ
diff --git a/test/functional/example-1-basics/index.js b/test/functional/example-1-basics/index.js
new file mode 100644
index 0000000..7ae7a98
--- /dev/null
+++ b/test/functional/example-1-basics/index.js
@@ -0,0 +1,133 @@
+describe('Example 1 - Basics', function () {
+ 'use strict';
+
+ var baseUri = '/base/test/functional/example-1-basics';
+ var expect = chai.expect;
+ var currentFrame = 0;
+ var frameEvents = {};
+ var stage;
+ var renderer;
+ var bunny;
+
+ function onFrame(frame, callback) {
+ frameEvents[frame] = callback;
+ }
+
+ function animate() {
+ currentFrame += 1;
+
+ requestAnimFrame( animate );
+
+ // just for fun, lets rotate mr rabbit a little
+ bunny.rotation += 0.1;
+
+ // render the stage
+ renderer.render(stage);
+
+ if (frameEvents[currentFrame])
+ frameEvents[currentFrame](currentFrame);
+ }
+
+ function initScene() {
+ // create an new instance of a pixi stage
+ stage = new PIXI.Stage(0x66FF99);
+
+ // create a renderer instance
+ renderer = PIXI.autoDetectRenderer(400, 300);
+ console.log('Is PIXI.WebGLRenderer: ' + (renderer instanceof PIXI.WebGLRenderer));
+
+ // add the renderer view element to the DOM
+ document.body.appendChild(renderer.view);
+
+ requestAnimFrame( animate );
+
+ // create a texture from an image path
+ var texture = PIXI.Texture.fromImage(baseUri + "/bunny.png");
+ // create a new Sprite using the texture
+ bunny = new PIXI.Sprite(texture);
+
+ // center the sprites anchor point
+ bunny.anchor.x = 0.5;
+ bunny.anchor.y = 0.5;
+
+ // move the sprite t the center of the screen
+ bunny.position.x = 200;
+ bunny.position.y = 150;
+
+ stage.addChild(bunny);
+ }
+
+ it('assets loaded', function (done) {
+ var loader = new PIXI.AssetLoader([
+ baseUri + '/bunny.png',
+ baseUri + '/frame-30.png',
+ baseUri + '/frame-60.png',
+ baseUri + '/frame-90.png'
+ ]);
+ // loader.on('onProgress', function (event) {
+ // console.log(event.content);
+ // });
+ loader.on('onComplete', function (event) {
+ done();
+ initScene();
+ });
+ loader.load();
+ });
+
+ it('frame 30 should match', function (done) {
+ this.timeout(700);
+ onFrame(30, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-30.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 60 should match', function (done) {
+ this.timeout(1200);
+ onFrame(60, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-60.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 90 should match', function (done) {
+ this.timeout(1700);
+ onFrame(90, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-90.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ // it('capture something', function (done) {
+ // this.timeout(2000000);
+ // onFrame(30, function () {
+ // var img = new Image();
+ // img.src = renderer.view.toDataURL('image/png');
+ // document.body.appendChild(img);
+ // });
+ // });
+});
diff --git a/test/index.html b/test/index.html
deleted file mode 100644
index 9cbcac5..0000000
--- a/test/index.html
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
- Pixi.js Test Suite
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/test/karma.conf.js b/test/karma.conf.js
new file mode 100644
index 0000000..c66a696
--- /dev/null
+++ b/test/karma.conf.js
@@ -0,0 +1,82 @@
+module.exports = function(config) {
+ config.set({
+
+ // base path, that will be used to resolve files and exclude
+ basePath : '../',
+
+ frameworks : ['mocha'],
+
+ // list of files / patterns to load in the browser
+ files : [
+ 'node_modules/chai/chai.js',
+ 'bin/pixi.dev.js',
+ 'test/lib/**/*.js',
+ 'test/unit/**/*.js',
+ // 'test/functional/**/*.js',
+ {pattern: 'test/**/*.png', watched: false, included: false, served: true}
+ ],
+
+ // list of files to exclude
+ exclude : [],
+
+ // use dolts reporter, as travis terminal does not support escaping sequences
+ // possible values: 'dots', 'progress', 'junit', 'teamcity'
+ // CLI --reporters progress
+ reporters : ['progress'],
+
+ // web server port
+ // CLI --port 9876
+ port : 9876,
+
+ // cli runner port
+ // CLI --runner-port 9100
+ runnerPort : 9100,
+
+ // enable / disable colors in the output (reporters and logs)
+ // CLI --colors --no-colors
+ colors : true,
+
+ // level of logging
+ // possible values: karma.LOG_DISABLE || karma.LOG_ERROR || karma.LOG_WARN || karma.LOG_INFO || karma.LOG_DEBUG
+ // CLI --log-level debug
+ logLevel : config.LOG_DEBUG,
+
+ // enable / disable watching file and executing tests whenever any file changes
+ // CLI --auto-watch --no-auto-watch
+ autoWatch : false,
+
+ // Start these browsers, currently available:
+ // - Chrome
+ // - ChromeCanary
+ // - Firefox
+ // - Opera
+ // - Safari (only Mac)
+ // - PhantomJS
+ // - IE (only Windows)
+ // CLI --browsers Chrome,Firefox,Safari
+ browsers : ['Firefox'],
+
+ // If browser does not capture in given timeout [ms], kill it
+ // CLI --capture-timeout 5000
+ captureTimeout : 5000,
+
+ // Auto run tests on start (when browsers are captured) and exit
+ // CLI --single-run --no-single-run
+ singleRun : true,
+
+ // report which specs are slower than 500ms
+ // CLI --report-slower-than 500
+ reportSlowerThan : 1000,
+
+ preprocessors : {
+ // '**/client/js/*.js': 'coverage'
+ },
+
+ plugins : [
+ 'karma-mocha',
+ // 'karma-chrome-launcher',
+ 'karma-firefox-launcher',
+ // 'karma-phantomjs-launcher'
+ ]
+ });
+};
diff --git a/test/lib/pixi/core/Matrix.js b/test/lib/pixi/core/Matrix.js
new file mode 100644
index 0000000..d26386b
--- /dev/null
+++ b/test/lib/pixi/core/Matrix.js
@@ -0,0 +1,40 @@
+
+function pixi_core_Matrix_confirmNewMat3(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(1);
+ expect(matrix[5]).to.equal(0);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(1);
+}
+
+function pixi_core_Matrix_confirmNewMat4(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[0]).to.equal(1);
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(0);
+ expect(matrix[5]).to.equal(1);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(0);
+ expect(matrix[9]).to.equal(0);
+ expect(matrix[10]).to.equal(1);
+ expect(matrix[11]).to.equal(0);
+ expect(matrix[12]).to.equal(0);
+ expect(matrix[13]).to.equal(0);
+ expect(matrix[14]).to.equal(0);
+ expect(matrix[15]).to.equal(1);
+}
diff --git a/test/lib/pixi/core/Point.js b/test/lib/pixi/core/Point.js
new file mode 100644
index 0000000..e5df07b
--- /dev/null
+++ b/test/lib/pixi/core/Point.js
@@ -0,0 +1,10 @@
+
+function pixi_core_Point_confirm(obj, x, y) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Point);
+ expect(obj).to.respondTo('clone');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+}
diff --git a/test/lib/pixi/core/Rectangle.js b/test/lib/pixi/core/Rectangle.js
new file mode 100644
index 0000000..23f0d12
--- /dev/null
+++ b/test/lib/pixi/core/Rectangle.js
@@ -0,0 +1,13 @@
+
+function pixi_core_Rectangle_confirm(obj, x, y, width, height) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Rectangle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+ expect(obj).to.have.property('width', width);
+ expect(obj).to.have.property('height', height);
+}
diff --git a/test/lib/pixi/display/DisplayObject.js b/test/lib/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..1388a7f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObject.js
@@ -0,0 +1,43 @@
+
+function pixi_display_DisplayObject_confirmNew(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObject);
+ expect(obj).to.respondTo('setInteractive');
+ expect(obj).to.respondTo('addFilter');
+ expect(obj).to.respondTo('removeFilter');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.property('last', obj);
+ expect(obj).to.have.property('first', obj);
+
+ expect(obj).to.contain.property('position');
+ pixi_core_Point_confirm(obj.position, 0, 0);
+ expect(obj).to.contain.property('scale');
+ pixi_core_Point_confirm(obj.scale, 1, 1);
+ expect(obj).to.contain.property('pivot');
+ pixi_core_Point_confirm(obj.pivot, 0, 0);
+
+ expect(obj).to.have.property('rotation', 0);
+ expect(obj).to.have.property('alpha', 1);
+ expect(obj).to.have.property('visible', true);
+ expect(obj).to.have.property('buttonMode', false);
+ expect(obj).to.have.property('parent', null);
+ expect(obj).to.have.property('worldAlpha', 1);
+
+ expect(obj).to.have.property('hitArea');
+ expect(obj).to.have.property('interactive'); // TODO: Have a better default value
+ expect('mask' in obj).to.be.true; // TODO: Have a better default value
+ expect(obj.mask).to.be.undefined;
+
+ expect(obj).to.have.property('renderable');
+ expect(obj).to.have.property('stage');
+
+ expect(obj).to.have.deep.property('worldTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ expect(obj).to.have.deep.property('localTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.localTransform);
+
+ expect(obj).to.have.deep.property('color.length', 0);
+ expect(obj).to.have.property('dynamic', true);
+}
diff --git a/test/lib/pixi/display/DisplayObjectContainer.js b/test/lib/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..085c59f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,16 @@
+
+function pixi_display_DisplayObjectContainer_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObject_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObjectContainer);
+ expect(obj).to.respondTo('addChild');
+ expect(obj).to.respondTo('addChildAt');
+ expect(obj).to.respondTo('swapChildren');
+ expect(obj).to.respondTo('getChildAt');
+ expect(obj).to.respondTo('removeChild');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('children.length', 0);
+}
diff --git a/test/lib/pixi/display/Sprite.js b/test/lib/pixi/display/Sprite.js
new file mode 100644
index 0000000..cc7a2d6
--- /dev/null
+++ b/test/lib/pixi/display/Sprite.js
@@ -0,0 +1,28 @@
+
+function pixi_display_Sprite_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Sprite);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', true);
+ expect(obj).to.have.property('stage', null);
+
+ expect(obj).to.have.property('anchor');
+ pixi_core_Point_confirm(obj.anchor, 0, 0);
+
+ expect(obj).to.have.property('blendMode', PIXI.blendModes.NORMAL);
+ expect(obj).to.have.property('width', 1); // TODO: is 1 expected
+ expect(obj).to.have.property('height', 1); // TODO: is 1 expected
+
+ // FIXME: Just make this a boolean that is always there
+ expect(!!obj.updateFrame).to.equal(obj.texture.baseTexture.hasLoaded);
+
+ expect(obj).to.have.property('texture');
+ pixi_textures_Texture_confirmNew(obj.texture, done);
+}
diff --git a/test/lib/pixi/extras/Strip.js b/test/lib/pixi/extras/Strip.js
new file mode 100644
index 0000000..8927a8a
--- /dev/null
+++ b/test/lib/pixi/extras/Strip.js
@@ -0,0 +1,12 @@
+
+function pixi_extras_Strip_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Strip);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ // TODO: Test properties
+}
diff --git a/test/lib/pixi/textures/Texture.js b/test/lib/pixi/textures/Texture.js
new file mode 100644
index 0000000..d5867b6
--- /dev/null
+++ b/test/lib/pixi/textures/Texture.js
@@ -0,0 +1,31 @@
+
+function pixi_textures_Texture_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ function confirmFrameDone() {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, obj.baseTexture.width, obj.baseTexture.height);
+
+ expect(obj).to.have.property('width', obj.baseTexture.width);
+ expect(obj).to.have.property('height', obj.baseTexture.height);
+ done();
+ }
+
+ expect(obj).to.be.an.instanceof(PIXI.Texture);
+ pixi_utils_EventTarget_like(obj);
+
+ expect(obj).to.have.property('baseTexture')
+ .and.to.be.an.instanceof(PIXI.BaseTexture);
+
+ expect(obj).to.have.property('scope', obj);
+
+ expect(obj).to.have.property('trim');
+ pixi_core_Point_confirm(obj.trim, 0, 0);
+
+ expect(obj).to.have.property('frame');
+ if (obj.baseTexture.hasLoaded) {
+ confirmFrameDone();
+ } else {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, 1, 1);
+ obj.addEventListener('update', confirmFrameDone);
+ }
+}
diff --git a/test/lib/pixi/utils/EventTarget.js b/test/lib/pixi/utils/EventTarget.js
new file mode 100644
index 0000000..7b1dcfa
--- /dev/null
+++ b/test/lib/pixi/utils/EventTarget.js
@@ -0,0 +1,8 @@
+
+function pixi_utils_EventTarget_like(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.respondTo('addEventListener');
+ expect(obj).to.respondTo('dispatchEvent');
+ expect(obj).to.respondTo('removeEventListener');
+}
diff --git a/test/lib/qunit-1.11.0.css b/test/lib/qunit-1.11.0.css
deleted file mode 100644
index d7fc0c8..0000000
--- a/test/lib/qunit-1.11.0.css
+++ /dev/null
@@ -1,244 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-/** Font Family and Sizes */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
- font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
-}
-
-#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
-#qunit-tests { font-size: smaller; }
-
-
-/** Resets */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter {
- margin: 0;
- padding: 0;
-}
-
-
-/** Header */
-
-#qunit-header {
- padding: 0.5em 0 0.5em 1em;
-
- color: #8699a4;
- background-color: #0d3349;
-
- font-size: 1.5em;
- line-height: 1em;
- font-weight: normal;
-
- border-radius: 5px 5px 0 0;
- -moz-border-radius: 5px 5px 0 0;
- -webkit-border-top-right-radius: 5px;
- -webkit-border-top-left-radius: 5px;
-}
-
-#qunit-header a {
- text-decoration: none;
- color: #c2ccd1;
-}
-
-#qunit-header a:hover,
-#qunit-header a:focus {
- color: #fff;
-}
-
-#qunit-testrunner-toolbar label {
- display: inline-block;
- padding: 0 .5em 0 .1em;
-}
-
-#qunit-banner {
- height: 5px;
-}
-
-#qunit-testrunner-toolbar {
- padding: 0.5em 0 0.5em 2em;
- color: #5E740B;
- background-color: #eee;
- overflow: hidden;
-}
-
-#qunit-userAgent {
- padding: 0.5em 0 0.5em 2.5em;
- background-color: #2b81af;
- color: #fff;
- text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
-}
-
-#qunit-modulefilter-container {
- float: right;
-}
-
-/** Tests: Pass/Fail */
-
-#qunit-tests {
- list-style-position: inside;
-}
-
-#qunit-tests li {
- padding: 0.4em 0.5em 0.4em 2.5em;
- border-bottom: 1px solid #fff;
- list-style-position: inside;
-}
-
-#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running {
- display: none;
-}
-
-#qunit-tests li strong {
- cursor: pointer;
-}
-
-#qunit-tests li a {
- padding: 0.5em;
- color: #c2ccd1;
- text-decoration: none;
-}
-#qunit-tests li a:hover,
-#qunit-tests li a:focus {
- color: #000;
-}
-
-#qunit-tests li .runtime {
- float: right;
- font-size: smaller;
-}
-
-.qunit-assert-list {
- margin-top: 0.5em;
- padding: 0.5em;
-
- background-color: #fff;
-
- border-radius: 5px;
- -moz-border-radius: 5px;
- -webkit-border-radius: 5px;
-}
-
-.qunit-collapsed {
- display: none;
-}
-
-#qunit-tests table {
- border-collapse: collapse;
- margin-top: .2em;
-}
-
-#qunit-tests th {
- text-align: right;
- vertical-align: top;
- padding: 0 .5em 0 0;
-}
-
-#qunit-tests td {
- vertical-align: top;
-}
-
-#qunit-tests pre {
- margin: 0;
- white-space: pre-wrap;
- word-wrap: break-word;
-}
-
-#qunit-tests del {
- background-color: #e0f2be;
- color: #374e0c;
- text-decoration: none;
-}
-
-#qunit-tests ins {
- background-color: #ffcaca;
- color: #500;
- text-decoration: none;
-}
-
-/*** Test Counts */
-
-#qunit-tests b.counts { color: black; }
-#qunit-tests b.passed { color: #5E740B; }
-#qunit-tests b.failed { color: #710909; }
-
-#qunit-tests li li {
- padding: 5px;
- background-color: #fff;
- border-bottom: none;
- list-style-position: inside;
-}
-
-/*** Passing Styles */
-
-#qunit-tests li li.pass {
- color: #3c510c;
- background-color: #fff;
- border-left: 10px solid #C6E746;
-}
-
-#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
-#qunit-tests .pass .test-name { color: #366097; }
-
-#qunit-tests .pass .test-actual,
-#qunit-tests .pass .test-expected { color: #999999; }
-
-#qunit-banner.qunit-pass { background-color: #C6E746; }
-
-/*** Failing Styles */
-
-#qunit-tests li li.fail {
- color: #710909;
- background-color: #fff;
- border-left: 10px solid #EE5757;
- white-space: pre;
-}
-
-#qunit-tests > li:last-child {
- border-radius: 0 0 5px 5px;
- -moz-border-radius: 0 0 5px 5px;
- -webkit-border-bottom-right-radius: 5px;
- -webkit-border-bottom-left-radius: 5px;
-}
-
-#qunit-tests .fail { color: #000000; background-color: #EE5757; }
-#qunit-tests .fail .test-name,
-#qunit-tests .fail .module-name { color: #000000; }
-
-#qunit-tests .fail .test-actual { color: #EE5757; }
-#qunit-tests .fail .test-expected { color: green; }
-
-#qunit-banner.qunit-fail { background-color: #EE5757; }
-
-
-/** Result */
-
-#qunit-testresult {
- padding: 0.5em 0.5em 0.5em 2.5em;
-
- color: #2b81af;
- background-color: #D2E0E6;
-
- border-bottom: 1px solid white;
-}
-#qunit-testresult .module-name {
- font-weight: bold;
-}
-
-/** Fixture */
-
-#qunit-fixture {
- position: absolute;
- top: -10000px;
- left: -10000px;
- width: 1000px;
- height: 1000px;
-}
diff --git a/test/lib/qunit-1.11.0.js b/test/lib/qunit-1.11.0.js
deleted file mode 100644
index 302545f..0000000
--- a/test/lib/qunit-1.11.0.js
+++ /dev/null
@@ -1,2152 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-(function( window ) {
-
-var QUnit,
- assert,
- config,
- onErrorFnPrev,
- testId = 0,
- fileName = (sourceFromStacktrace( 0 ) || "" ).replace(/(:\d+)+\)?/, "").replace(/.+\//, ""),
- toString = Object.prototype.toString,
- hasOwn = Object.prototype.hasOwnProperty,
- // Keep a local reference to Date (GH-283)
- Date = window.Date,
- defined = {
- setTimeout: typeof window.setTimeout !== "undefined",
- sessionStorage: (function() {
- var x = "qunit-test-string";
- try {
- sessionStorage.setItem( x, x );
- sessionStorage.removeItem( x );
- return true;
- } catch( e ) {
- return false;
- }
- }())
- },
- /**
- * Provides a normalized error string, correcting an issue
- * with IE 7 (and prior) where Error.prototype.toString is
- * not properly implemented
- *
- * Based on http://es5.github.com/#x15.11.4.4
- *
- * @param {String|Error} error
- * @return {String} error message
- */
- errorString = function( error ) {
- var name, message,
- errorString = error.toString();
- if ( errorString.substring( 0, 7 ) === "[object" ) {
- name = error.name ? error.name.toString() : "Error";
- message = error.message ? error.message.toString() : "";
- if ( name && message ) {
- return name + ": " + message;
- } else if ( name ) {
- return name;
- } else if ( message ) {
- return message;
- } else {
- return "Error";
- }
- } else {
- return errorString;
- }
- },
- /**
- * Makes a clone of an object using only Array or Object as base,
- * and copies over the own enumerable properties.
- *
- * @param {Object} obj
- * @return {Object} New object with only the own properties (recursively).
- */
- objectValues = function( obj ) {
- // Grunt 0.3.x uses an older version of jshint that still has jshint/jshint#392.
- /*jshint newcap: false */
- var key, val,
- vals = QUnit.is( "array", obj ) ? [] : {};
- for ( key in obj ) {
- if ( hasOwn.call( obj, key ) ) {
- val = obj[key];
- vals[key] = val === Object(val) ? objectValues(val) : val;
- }
- }
- return vals;
- };
-
-function Test( settings ) {
- extend( this, settings );
- this.assertions = [];
- this.testNumber = ++Test.count;
-}
-
-Test.count = 0;
-
-Test.prototype = {
- init: function() {
- var a, b, li,
- tests = id( "qunit-tests" );
-
- if ( tests ) {
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml;
-
- // `a` initialized at top of scope
- a = document.createElement( "a" );
- a.innerHTML = "Rerun";
- a.href = QUnit.url({ testNumber: this.testNumber });
-
- li = document.createElement( "li" );
- li.appendChild( b );
- li.appendChild( a );
- li.className = "running";
- li.id = this.id = "qunit-test-output" + testId++;
-
- tests.appendChild( li );
- }
- },
- setup: function() {
- if ( this.module !== config.previousModule ) {
- if ( config.previousModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.previousModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
- config.previousModule = this.module;
- config.moduleStats = { all: 0, bad: 0 };
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- } else if ( config.autorun ) {
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- }
-
- config.current = this;
-
- this.testEnvironment = extend({
- setup: function() {},
- teardown: function() {}
- }, this.moduleTestEnvironment );
-
- this.started = +new Date();
- runLoggingCallbacks( "testStart", QUnit, {
- name: this.testName,
- module: this.module
- });
-
- // allow utility functions to access the current test environment
- // TODO why??
- QUnit.current_testEnvironment = this.testEnvironment;
-
- if ( !config.pollution ) {
- saveGlobal();
- }
- if ( config.notrycatch ) {
- this.testEnvironment.setup.call( this.testEnvironment );
- return;
- }
- try {
- this.testEnvironment.setup.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Setup failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- },
- run: function() {
- config.current = this;
-
- var running = id( "qunit-testresult" );
-
- if ( running ) {
- running.innerHTML = "Running:
" + this.nameHtml;
- }
-
- if ( this.async ) {
- QUnit.stop();
- }
-
- this.callbackStarted = +new Date();
-
- if ( config.notrycatch ) {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- return;
- }
-
- try {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- } catch( e ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
-
- QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + " " + this.stack + ": " + ( e.message || e ), extractStacktrace( e, 0 ) );
- // else next test will carry the responsibility
- saveGlobal();
-
- // Restart the tests if they're blocking
- if ( config.blocking ) {
- QUnit.start();
- }
- }
- },
- teardown: function() {
- config.current = this;
- if ( config.notrycatch ) {
- if ( typeof this.callbackRuntime === "undefined" ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
- }
- this.testEnvironment.teardown.call( this.testEnvironment );
- return;
- } else {
- try {
- this.testEnvironment.teardown.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Teardown failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- }
- checkPollution();
- },
- finish: function() {
- config.current = this;
- if ( config.requireExpects && this.expected === null ) {
- QUnit.pushFailure( "Expected number of assertions to be defined, but expect() was not called.", this.stack );
- } else if ( this.expected !== null && this.expected !== this.assertions.length ) {
- QUnit.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack );
- } else if ( this.expected === null && !this.assertions.length ) {
- QUnit.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions.", this.stack );
- }
-
- var i, assertion, a, b, time, li, ol,
- test = this,
- good = 0,
- bad = 0,
- tests = id( "qunit-tests" );
-
- this.runtime = +new Date() - this.started;
- config.stats.all += this.assertions.length;
- config.moduleStats.all += this.assertions.length;
-
- if ( tests ) {
- ol = document.createElement( "ol" );
- ol.className = "qunit-assert-list";
-
- for ( i = 0; i < this.assertions.length; i++ ) {
- assertion = this.assertions[i];
-
- li = document.createElement( "li" );
- li.className = assertion.result ? "pass" : "fail";
- li.innerHTML = assertion.message || ( assertion.result ? "okay" : "failed" );
- ol.appendChild( li );
-
- if ( assertion.result ) {
- good++;
- } else {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
-
- // store result when possible
- if ( QUnit.config.reorder && defined.sessionStorage ) {
- if ( bad ) {
- sessionStorage.setItem( "qunit-test-" + this.module + "-" + this.testName, bad );
- } else {
- sessionStorage.removeItem( "qunit-test-" + this.module + "-" + this.testName );
- }
- }
-
- if ( bad === 0 ) {
- addClass( ol, "qunit-collapsed" );
- }
-
- // `b` initialized at top of scope
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml + " (" + bad + ", " + good + ", " + this.assertions.length + ")";
-
- addEvent(b, "click", function() {
- var next = b.parentNode.lastChild,
- collapsed = hasClass( next, "qunit-collapsed" );
- ( collapsed ? removeClass : addClass )( next, "qunit-collapsed" );
- });
-
- addEvent(b, "dblclick", function( e ) {
- var target = e && e.target ? e.target : window.event.srcElement;
- if ( target.nodeName.toLowerCase() === "span" || target.nodeName.toLowerCase() === "b" ) {
- target = target.parentNode;
- }
- if ( window.location && target.nodeName.toLowerCase() === "strong" ) {
- window.location = QUnit.url({ testNumber: test.testNumber });
- }
- });
-
- // `time` initialized at top of scope
- time = document.createElement( "span" );
- time.className = "runtime";
- time.innerHTML = this.runtime + " ms";
-
- // `li` initialized at top of scope
- li = id( this.id );
- li.className = bad ? "fail" : "pass";
- li.removeChild( li.firstChild );
- a = li.firstChild;
- li.appendChild( b );
- li.appendChild( a );
- li.appendChild( time );
- li.appendChild( ol );
-
- } else {
- for ( i = 0; i < this.assertions.length; i++ ) {
- if ( !this.assertions[i].result ) {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
- }
-
- runLoggingCallbacks( "testDone", QUnit, {
- name: this.testName,
- module: this.module,
- failed: bad,
- passed: this.assertions.length - bad,
- total: this.assertions.length,
- duration: this.runtime
- });
-
- QUnit.reset();
-
- config.current = undefined;
- },
-
- queue: function() {
- var bad,
- test = this;
-
- synchronize(function() {
- test.init();
- });
- function run() {
- // each of these can by async
- synchronize(function() {
- test.setup();
- });
- synchronize(function() {
- test.run();
- });
- synchronize(function() {
- test.teardown();
- });
- synchronize(function() {
- test.finish();
- });
- }
-
- // `bad` initialized at top of scope
- // defer when previous test run passed, if storage is available
- bad = QUnit.config.reorder && defined.sessionStorage &&
- +sessionStorage.getItem( "qunit-test-" + this.module + "-" + this.testName );
-
- if ( bad ) {
- run();
- } else {
- synchronize( run, true );
- }
- }
-};
-
-// Root QUnit object.
-// `QUnit` initialized at top of scope
-QUnit = {
-
- // call on start of module test to prepend name to all tests
- module: function( name, testEnvironment ) {
- config.currentModule = name;
- config.currentModuleTestEnvironment = testEnvironment;
- config.modules[name] = true;
- },
-
- asyncTest: function( testName, expected, callback ) {
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- QUnit.test( testName, expected, callback, true );
- },
-
- test: function( testName, expected, callback, async ) {
- var test,
- nameHtml = "" + escapeText( testName ) + "";
-
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- if ( config.currentModule ) {
- nameHtml = "" + escapeText( config.currentModule ) + ": " + nameHtml;
- }
-
- test = new Test({
- nameHtml: nameHtml,
- testName: testName,
- expected: expected,
- async: async,
- callback: callback,
- module: config.currentModule,
- moduleTestEnvironment: config.currentModuleTestEnvironment,
- stack: sourceFromStacktrace( 2 )
- });
-
- if ( !validTest( test ) ) {
- return;
- }
-
- test.queue();
- },
-
- // Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through.
- expect: function( asserts ) {
- if (arguments.length === 1) {
- config.current.expected = asserts;
- } else {
- return config.current.expected;
- }
- },
-
- start: function( count ) {
- // QUnit hasn't been initialized yet.
- // Note: RequireJS (et al) may delay onLoad
- if ( config.semaphore === undefined ) {
- QUnit.begin(function() {
- // This is triggered at the top of QUnit.load, push start() to the event loop, to allow QUnit.load to finish first
- setTimeout(function() {
- QUnit.start( count );
- });
- });
- return;
- }
-
- config.semaphore -= count || 1;
- // don't start until equal number of stop-calls
- if ( config.semaphore > 0 ) {
- return;
- }
- // ignore if start is called more often then stop
- if ( config.semaphore < 0 ) {
- config.semaphore = 0;
- QUnit.pushFailure( "Called start() while already started (QUnit.config.semaphore was 0 already)", null, sourceFromStacktrace(2) );
- return;
- }
- // A slight delay, to avoid any current callbacks
- if ( defined.setTimeout ) {
- window.setTimeout(function() {
- if ( config.semaphore > 0 ) {
- return;
- }
- if ( config.timeout ) {
- clearTimeout( config.timeout );
- }
-
- config.blocking = false;
- process( true );
- }, 13);
- } else {
- config.blocking = false;
- process( true );
- }
- },
-
- stop: function( count ) {
- config.semaphore += count || 1;
- config.blocking = true;
-
- if ( config.testTimeout && defined.setTimeout ) {
- clearTimeout( config.timeout );
- config.timeout = window.setTimeout(function() {
- QUnit.ok( false, "Test timed out" );
- config.semaphore = 1;
- QUnit.start();
- }, config.testTimeout );
- }
- }
-};
-
-// `assert` initialized at top of scope
-// Asssert helpers
-// All of these must either call QUnit.push() or manually do:
-// - runLoggingCallbacks( "log", .. );
-// - config.current.assertions.push({ .. });
-// We attach it to the QUnit object *after* we expose the public API,
-// otherwise `assert` will become a global variable in browsers (#341).
-assert = {
- /**
- * Asserts rough true-ish result.
- * @name ok
- * @function
- * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" );
- */
- ok: function( result, msg ) {
- if ( !config.current ) {
- throw new Error( "ok() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
- result = !!result;
-
- var source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: msg
- };
-
- msg = escapeText( msg || (result ? "okay" : "failed" ) );
- msg = "" + msg + "";
-
- if ( !result ) {
- source = sourceFromStacktrace( 2 );
- if ( source ) {
- details.source = source;
- msg += "Source: | " + escapeText( source ) + " |
---|
";
- }
- }
- runLoggingCallbacks( "log", QUnit, details );
- config.current.assertions.push({
- result: result,
- message: msg
- });
- },
-
- /**
- * Assert that the first two arguments are equal, with an optional message.
- * Prints out both actual and expected values.
- * @name equal
- * @function
- * @example equal( format( "Received {0} bytes.", 2), "Received 2 bytes.", "format() replaces {0} with next argument" );
- */
- equal: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected == actual, actual, expected, message );
- },
-
- /**
- * @name notEqual
- * @function
- */
- notEqual: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected != actual, actual, expected, message );
- },
-
- /**
- * @name propEqual
- * @function
- */
- propEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notPropEqual
- * @function
- */
- notPropEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name deepEqual
- * @function
- */
- deepEqual: function( actual, expected, message ) {
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notDeepEqual
- * @function
- */
- notDeepEqual: function( actual, expected, message ) {
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name strictEqual
- * @function
- */
- strictEqual: function( actual, expected, message ) {
- QUnit.push( expected === actual, actual, expected, message );
- },
-
- /**
- * @name notStrictEqual
- * @function
- */
- notStrictEqual: function( actual, expected, message ) {
- QUnit.push( expected !== actual, actual, expected, message );
- },
-
- "throws": function( block, expected, message ) {
- var actual,
- expectedOutput = expected,
- ok = false;
-
- // 'expected' is optional
- if ( typeof expected === "string" ) {
- message = expected;
- expected = null;
- }
-
- config.current.ignoreGlobalErrors = true;
- try {
- block.call( config.current.testEnvironment );
- } catch (e) {
- actual = e;
- }
- config.current.ignoreGlobalErrors = false;
-
- if ( actual ) {
- // we don't want to validate thrown error
- if ( !expected ) {
- ok = true;
- expectedOutput = null;
- // expected is a regexp
- } else if ( QUnit.objectType( expected ) === "regexp" ) {
- ok = expected.test( errorString( actual ) );
- // expected is a constructor
- } else if ( actual instanceof expected ) {
- ok = true;
- // expected is a validation function which returns true is validation passed
- } else if ( expected.call( {}, actual ) === true ) {
- expectedOutput = null;
- ok = true;
- }
-
- QUnit.push( ok, actual, expectedOutput, message );
- } else {
- QUnit.pushFailure( message, null, 'No exception was thrown.' );
- }
- }
-};
-
-/**
- * @deprecate since 1.8.0
- * Kept assertion helpers in root for backwards compatibility.
- */
-extend( QUnit, assert );
-
-/**
- * @deprecated since 1.9.0
- * Kept root "raises()" for backwards compatibility.
- * (Note that we don't introduce assert.raises).
- */
-QUnit.raises = assert[ "throws" ];
-
-/**
- * @deprecated since 1.0.0, replaced with error pushes since 1.3.0
- * Kept to avoid TypeErrors for undefined methods.
- */
-QUnit.equals = function() {
- QUnit.push( false, false, false, "QUnit.equals has been deprecated since 2009 (e88049a0), use QUnit.equal instead" );
-};
-QUnit.same = function() {
- QUnit.push( false, false, false, "QUnit.same has been deprecated since 2009 (e88049a0), use QUnit.deepEqual instead" );
-};
-
-// We want access to the constructor's prototype
-(function() {
- function F() {}
- F.prototype = QUnit;
- QUnit = new F();
- // Make F QUnit's constructor so that we can add to the prototype later
- QUnit.constructor = F;
-}());
-
-/**
- * Config object: Maintain internal state
- * Later exposed as QUnit.config
- * `config` initialized at top of scope
- */
-config = {
- // The queue of tests to run
- queue: [],
-
- // block until document ready
- blocking: true,
-
- // when enabled, show only failing tests
- // gets persisted through sessionStorage and can be changed in UI via checkbox
- hidepassed: false,
-
- // by default, run previously failed tests first
- // very useful in combination with "Hide passed tests" checked
- reorder: true,
-
- // by default, modify document.title when suite is done
- altertitle: true,
-
- // when enabled, all tests must call expect()
- requireExpects: false,
-
- // add checkboxes that are persisted in the query-string
- // when enabled, the id is set to `true` as a `QUnit.config` property
- urlConfig: [
- {
- id: "noglobals",
- label: "Check for Globals",
- tooltip: "Enabling this will test if any test introduces new properties on the `window` object. Stored as query-strings."
- },
- {
- id: "notrycatch",
- label: "No try-catch",
- tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging exceptions in IE reasonable. Stored as query-strings."
- }
- ],
-
- // Set of all modules.
- modules: {},
-
- // logging callback queues
- begin: [],
- done: [],
- log: [],
- testStart: [],
- testDone: [],
- moduleStart: [],
- moduleDone: []
-};
-
-// Export global variables, unless an 'exports' object exists,
-// in that case we assume we're in CommonJS (dealt with on the bottom of the script)
-if ( typeof exports === "undefined" ) {
- extend( window, QUnit );
-
- // Expose QUnit object
- window.QUnit = QUnit;
-}
-
-// Initialize more QUnit.config and QUnit.urlParams
-(function() {
- var i,
- location = window.location || { search: "", protocol: "file:" },
- params = location.search.slice( 1 ).split( "&" ),
- length = params.length,
- urlParams = {},
- current;
-
- if ( params[ 0 ] ) {
- for ( i = 0; i < length; i++ ) {
- current = params[ i ].split( "=" );
- current[ 0 ] = decodeURIComponent( current[ 0 ] );
- // allow just a key to turn on a flag, e.g., test.html?noglobals
- current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true;
- urlParams[ current[ 0 ] ] = current[ 1 ];
- }
- }
-
- QUnit.urlParams = urlParams;
-
- // String search anywhere in moduleName+testName
- config.filter = urlParams.filter;
-
- // Exact match of the module name
- config.module = urlParams.module;
-
- config.testNumber = parseInt( urlParams.testNumber, 10 ) || null;
-
- // Figure out if we're running the tests from a server or not
- QUnit.isLocal = location.protocol === "file:";
-}());
-
-// Extend QUnit object,
-// these after set here because they should not be exposed as global functions
-extend( QUnit, {
- assert: assert,
-
- config: config,
-
- // Initialize the configuration options
- init: function() {
- extend( config, {
- stats: { all: 0, bad: 0 },
- moduleStats: { all: 0, bad: 0 },
- started: +new Date(),
- updateRate: 1000,
- blocking: false,
- autostart: true,
- autorun: false,
- filter: "",
- queue: [],
- semaphore: 1
- });
-
- var tests, banner, result,
- qunit = id( "qunit" );
-
- if ( qunit ) {
- qunit.innerHTML =
- "" +
- "" +
- "" +
- "" +
- "
";
- }
-
- tests = id( "qunit-tests" );
- banner = id( "qunit-banner" );
- result = id( "qunit-testresult" );
-
- if ( tests ) {
- tests.innerHTML = "";
- }
-
- if ( banner ) {
- banner.className = "";
- }
-
- if ( result ) {
- result.parentNode.removeChild( result );
- }
-
- if ( tests ) {
- result = document.createElement( "p" );
- result.id = "qunit-testresult";
- result.className = "result";
- tests.parentNode.insertBefore( result, tests );
- result.innerHTML = "Running...
";
- }
- },
-
- // Resets the test setup. Useful for tests that modify the DOM.
- reset: function() {
- var fixture = id( "qunit-fixture" );
- if ( fixture ) {
- fixture.innerHTML = config.fixture;
- }
- },
-
- // Trigger an event on an element.
- // @example triggerEvent( document.body, "click" );
- triggerEvent: function( elem, type, event ) {
- if ( document.createEvent ) {
- event = document.createEvent( "MouseEvents" );
- event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView,
- 0, 0, 0, 0, 0, false, false, false, false, 0, null);
-
- elem.dispatchEvent( event );
- } else if ( elem.fireEvent ) {
- elem.fireEvent( "on" + type );
- }
- },
-
- // Safe object type checking
- is: function( type, obj ) {
- return QUnit.objectType( obj ) === type;
- },
-
- objectType: function( obj ) {
- if ( typeof obj === "undefined" ) {
- return "undefined";
- // consider: typeof null === object
- }
- if ( obj === null ) {
- return "null";
- }
-
- var match = toString.call( obj ).match(/^\[object\s(.*)\]$/),
- type = match && match[1] || "";
-
- switch ( type ) {
- case "Number":
- if ( isNaN(obj) ) {
- return "nan";
- }
- return "number";
- case "String":
- case "Boolean":
- case "Array":
- case "Date":
- case "RegExp":
- case "Function":
- return type.toLowerCase();
- }
- if ( typeof obj === "object" ) {
- return "object";
- }
- return undefined;
- },
-
- push: function( result, actual, expected, message ) {
- if ( !config.current ) {
- throw new Error( "assertion outside test context, was " + sourceFromStacktrace() );
- }
-
- var output, source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: message,
- actual: actual,
- expected: expected
- };
-
- message = escapeText( message ) || ( result ? "okay" : "failed" );
- message = "" + message + "";
- output = message;
-
- if ( !result ) {
- expected = escapeText( QUnit.jsDump.parse(expected) );
- actual = escapeText( QUnit.jsDump.parse(actual) );
- output += "Expected: | " + expected + " |
";
-
- if ( actual !== expected ) {
- output += "Result: | " + actual + " |
";
- output += "Diff: | " + QUnit.diff( expected, actual ) + " |
";
- }
-
- source = sourceFromStacktrace();
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
- }
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: !!result,
- message: output
- });
- },
-
- pushFailure: function( message, source, actual ) {
- if ( !config.current ) {
- throw new Error( "pushFailure() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
-
- var output,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: false,
- message: message
- };
-
- message = escapeText( message ) || "error";
- message = "" + message + "";
- output = message;
-
- output += "";
-
- if ( actual ) {
- output += "Result: | " + escapeText( actual ) + " |
";
- }
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: false,
- message: output
- });
- },
-
- url: function( params ) {
- params = extend( extend( {}, QUnit.urlParams ), params );
- var key,
- querystring = "?";
-
- for ( key in params ) {
- if ( !hasOwn.call( params, key ) ) {
- continue;
- }
- querystring += encodeURIComponent( key ) + "=" +
- encodeURIComponent( params[ key ] ) + "&";
- }
- return window.location.protocol + "//" + window.location.host +
- window.location.pathname + querystring.slice( 0, -1 );
- },
-
- extend: extend,
- id: id,
- addEvent: addEvent
- // load, equiv, jsDump, diff: Attached later
-});
-
-/**
- * @deprecated: Created for backwards compatibility with test runner that set the hook function
- * into QUnit.{hook}, instead of invoking it and passing the hook function.
- * QUnit.constructor is set to the empty F() above so that we can add to it's prototype here.
- * Doing this allows us to tell if the following methods have been overwritten on the actual
- * QUnit object.
- */
-extend( QUnit.constructor.prototype, {
-
- // Logging callbacks; all receive a single argument with the listed properties
- // run test/logs.html for any related changes
- begin: registerLoggingCallback( "begin" ),
-
- // done: { failed, passed, total, runtime }
- done: registerLoggingCallback( "done" ),
-
- // log: { result, actual, expected, message }
- log: registerLoggingCallback( "log" ),
-
- // testStart: { name }
- testStart: registerLoggingCallback( "testStart" ),
-
- // testDone: { name, failed, passed, total, duration }
- testDone: registerLoggingCallback( "testDone" ),
-
- // moduleStart: { name }
- moduleStart: registerLoggingCallback( "moduleStart" ),
-
- // moduleDone: { name, failed, passed, total }
- moduleDone: registerLoggingCallback( "moduleDone" )
-});
-
-if ( typeof document === "undefined" || document.readyState === "complete" ) {
- config.autorun = true;
-}
-
-QUnit.load = function() {
- runLoggingCallbacks( "begin", QUnit, {} );
-
- // Initialize the config, saving the execution queue
- var banner, filter, i, label, len, main, ol, toolbar, userAgent, val,
- urlConfigCheckboxesContainer, urlConfigCheckboxes, moduleFilter,
- numModules = 0,
- moduleFilterHtml = "",
- urlConfigHtml = "",
- oldconfig = extend( {}, config );
-
- QUnit.init();
- extend(config, oldconfig);
-
- config.blocking = false;
-
- len = config.urlConfig.length;
-
- for ( i = 0; i < len; i++ ) {
- val = config.urlConfig[i];
- if ( typeof val === "string" ) {
- val = {
- id: val,
- label: val,
- tooltip: "[no tooltip available]"
- };
- }
- config[ val.id ] = QUnit.urlParams[ val.id ];
- urlConfigHtml += "";
- }
-
- moduleFilterHtml += "";
-
- // `userAgent` initialized at top of scope
- userAgent = id( "qunit-userAgent" );
- if ( userAgent ) {
- userAgent.innerHTML = navigator.userAgent;
- }
-
- // `banner` initialized at top of scope
- banner = id( "qunit-header" );
- if ( banner ) {
- banner.innerHTML = "" + banner.innerHTML + " ";
- }
-
- // `toolbar` initialized at top of scope
- toolbar = id( "qunit-testrunner-toolbar" );
- if ( toolbar ) {
- // `filter` initialized at top of scope
- filter = document.createElement( "input" );
- filter.type = "checkbox";
- filter.id = "qunit-filter-pass";
-
- addEvent( filter, "click", function() {
- var tmp,
- ol = document.getElementById( "qunit-tests" );
-
- if ( filter.checked ) {
- ol.className = ol.className + " hidepass";
- } else {
- tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " ";
- ol.className = tmp.replace( / hidepass /, " " );
- }
- if ( defined.sessionStorage ) {
- if (filter.checked) {
- sessionStorage.setItem( "qunit-filter-passed-tests", "true" );
- } else {
- sessionStorage.removeItem( "qunit-filter-passed-tests" );
- }
- }
- });
-
- if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem( "qunit-filter-passed-tests" ) ) {
- filter.checked = true;
- // `ol` initialized at top of scope
- ol = document.getElementById( "qunit-tests" );
- ol.className = ol.className + " hidepass";
- }
- toolbar.appendChild( filter );
-
- // `label` initialized at top of scope
- label = document.createElement( "label" );
- label.setAttribute( "for", "qunit-filter-pass" );
- label.setAttribute( "title", "Only show tests and assertons that fail. Stored in sessionStorage." );
- label.innerHTML = "Hide passed tests";
- toolbar.appendChild( label );
-
- urlConfigCheckboxesContainer = document.createElement("span");
- urlConfigCheckboxesContainer.innerHTML = urlConfigHtml;
- urlConfigCheckboxes = urlConfigCheckboxesContainer.getElementsByTagName("input");
- // For oldIE support:
- // * Add handlers to the individual elements instead of the container
- // * Use "click" instead of "change"
- // * Fallback from event.target to event.srcElement
- addEvents( urlConfigCheckboxes, "click", function( event ) {
- var params = {},
- target = event.target || event.srcElement;
- params[ target.name ] = target.checked ? true : undefined;
- window.location = QUnit.url( params );
- });
- toolbar.appendChild( urlConfigCheckboxesContainer );
-
- if (numModules > 1) {
- moduleFilter = document.createElement( 'span' );
- moduleFilter.setAttribute( 'id', 'qunit-modulefilter-container' );
- moduleFilter.innerHTML = moduleFilterHtml;
- addEvent( moduleFilter.lastChild, "change", function() {
- var selectBox = moduleFilter.getElementsByTagName("select")[0],
- selectedModule = decodeURIComponent(selectBox.options[selectBox.selectedIndex].value);
-
- window.location = QUnit.url( { module: ( selectedModule === "" ) ? undefined : selectedModule } );
- });
- toolbar.appendChild(moduleFilter);
- }
- }
-
- // `main` initialized at top of scope
- main = id( "qunit-fixture" );
- if ( main ) {
- config.fixture = main.innerHTML;
- }
-
- if ( config.autostart ) {
- QUnit.start();
- }
-};
-
-addEvent( window, "load", QUnit.load );
-
-// `onErrorFnPrev` initialized at top of scope
-// Preserve other handlers
-onErrorFnPrev = window.onerror;
-
-// Cover uncaught exceptions
-// Returning true will surpress the default browser handler,
-// returning false will let it run.
-window.onerror = function ( error, filePath, linerNr ) {
- var ret = false;
- if ( onErrorFnPrev ) {
- ret = onErrorFnPrev( error, filePath, linerNr );
- }
-
- // Treat return value as window.onerror itself does,
- // Only do our handling if not surpressed.
- if ( ret !== true ) {
- if ( QUnit.config.current ) {
- if ( QUnit.config.current.ignoreGlobalErrors ) {
- return true;
- }
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- } else {
- QUnit.test( "global failure", extend( function() {
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- }, { validTest: validTest } ) );
- }
- return false;
- }
-
- return ret;
-};
-
-function done() {
- config.autorun = true;
-
- // Log the last module results
- if ( config.currentModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.currentModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
-
- var i, key,
- banner = id( "qunit-banner" ),
- tests = id( "qunit-tests" ),
- runtime = +new Date() - config.started,
- passed = config.stats.all - config.stats.bad,
- html = [
- "Tests completed in ",
- runtime,
- " milliseconds.
",
- "",
- passed,
- " assertions of ",
- config.stats.all,
- " passed, ",
- config.stats.bad,
- " failed."
- ].join( "" );
-
- if ( banner ) {
- banner.className = ( config.stats.bad ? "qunit-fail" : "qunit-pass" );
- }
-
- if ( tests ) {
- id( "qunit-testresult" ).innerHTML = html;
- }
-
- if ( config.altertitle && typeof document !== "undefined" && document.title ) {
- // show ✖ for good, ✔ for bad suite result in title
- // use escape sequences in case file gets loaded with non-utf-8-charset
- document.title = [
- ( config.stats.bad ? "\u2716" : "\u2714" ),
- document.title.replace( /^[\u2714\u2716] /i, "" )
- ].join( " " );
- }
-
- // clear own sessionStorage items if all tests passed
- if ( config.reorder && defined.sessionStorage && config.stats.bad === 0 ) {
- // `key` & `i` initialized at top of scope
- for ( i = 0; i < sessionStorage.length; i++ ) {
- key = sessionStorage.key( i++ );
- if ( key.indexOf( "qunit-test-" ) === 0 ) {
- sessionStorage.removeItem( key );
- }
- }
- }
-
- // scroll back to top to show results
- if ( window.scrollTo ) {
- window.scrollTo(0, 0);
- }
-
- runLoggingCallbacks( "done", QUnit, {
- failed: config.stats.bad,
- passed: passed,
- total: config.stats.all,
- runtime: runtime
- });
-}
-
-/** @return Boolean: true if this test should be ran */
-function validTest( test ) {
- var include,
- filter = config.filter && config.filter.toLowerCase(),
- module = config.module && config.module.toLowerCase(),
- fullName = (test.module + ": " + test.testName).toLowerCase();
-
- // Internally-generated tests are always valid
- if ( test.callback && test.callback.validTest === validTest ) {
- delete test.callback.validTest;
- return true;
- }
-
- if ( config.testNumber ) {
- return test.testNumber === config.testNumber;
- }
-
- if ( module && ( !test.module || test.module.toLowerCase() !== module ) ) {
- return false;
- }
-
- if ( !filter ) {
- return true;
- }
-
- include = filter.charAt( 0 ) !== "!";
- if ( !include ) {
- filter = filter.slice( 1 );
- }
-
- // If the filter matches, we need to honour include
- if ( fullName.indexOf( filter ) !== -1 ) {
- return include;
- }
-
- // Otherwise, do the opposite
- return !include;
-}
-
-// so far supports only Firefox, Chrome and Opera (buggy), Safari (for real exceptions)
-// Later Safari and IE10 are supposed to support error.stack as well
-// See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack
-function extractStacktrace( e, offset ) {
- offset = offset === undefined ? 3 : offset;
-
- var stack, include, i;
-
- if ( e.stacktrace ) {
- // Opera
- return e.stacktrace.split( "\n" )[ offset + 3 ];
- } else if ( e.stack ) {
- // Firefox, Chrome
- stack = e.stack.split( "\n" );
- if (/^error$/i.test( stack[0] ) ) {
- stack.shift();
- }
- if ( fileName ) {
- include = [];
- for ( i = offset; i < stack.length; i++ ) {
- if ( stack[ i ].indexOf( fileName ) !== -1 ) {
- break;
- }
- include.push( stack[ i ] );
- }
- if ( include.length ) {
- return include.join( "\n" );
- }
- }
- return stack[ offset ];
- } else if ( e.sourceURL ) {
- // Safari, PhantomJS
- // hopefully one day Safari provides actual stacktraces
- // exclude useless self-reference for generated Error objects
- if ( /qunit.js$/.test( e.sourceURL ) ) {
- return;
- }
- // for actual exceptions, this is useful
- return e.sourceURL + ":" + e.line;
- }
-}
-function sourceFromStacktrace( offset ) {
- try {
- throw new Error();
- } catch ( e ) {
- return extractStacktrace( e, offset );
- }
-}
-
-/**
- * Escape text for attribute or text content.
- */
-function escapeText( s ) {
- if ( !s ) {
- return "";
- }
- s = s + "";
- // Both single quotes and double quotes (for attributes)
- return s.replace( /['"<>&]/g, function( s ) {
- switch( s ) {
- case '\'':
- return ''';
- case '"':
- return '"';
- case '<':
- return '<';
- case '>':
- return '>';
- case '&':
- return '&';
- }
- });
-}
-
-function synchronize( callback, last ) {
- config.queue.push( callback );
-
- if ( config.autorun && !config.blocking ) {
- process( last );
- }
-}
-
-function process( last ) {
- function next() {
- process( last );
- }
- var start = new Date().getTime();
- config.depth = config.depth ? config.depth + 1 : 1;
-
- while ( config.queue.length && !config.blocking ) {
- if ( !defined.setTimeout || config.updateRate <= 0 || ( ( new Date().getTime() - start ) < config.updateRate ) ) {
- config.queue.shift()();
- } else {
- window.setTimeout( next, 13 );
- break;
- }
- }
- config.depth--;
- if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) {
- done();
- }
-}
-
-function saveGlobal() {
- config.pollution = [];
-
- if ( config.noglobals ) {
- for ( var key in window ) {
- // in Opera sometimes DOM element ids show up here, ignore them
- if ( !hasOwn.call( window, key ) || /^qunit-test-output/.test( key ) ) {
- continue;
- }
- config.pollution.push( key );
- }
- }
-}
-
-function checkPollution() {
- var newGlobals,
- deletedGlobals,
- old = config.pollution;
-
- saveGlobal();
-
- newGlobals = diff( config.pollution, old );
- if ( newGlobals.length > 0 ) {
- QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join(", ") );
- }
-
- deletedGlobals = diff( old, config.pollution );
- if ( deletedGlobals.length > 0 ) {
- QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join(", ") );
- }
-}
-
-// returns a new Array with the elements that are in a but not in b
-function diff( a, b ) {
- var i, j,
- result = a.slice();
-
- for ( i = 0; i < result.length; i++ ) {
- for ( j = 0; j < b.length; j++ ) {
- if ( result[i] === b[j] ) {
- result.splice( i, 1 );
- i--;
- break;
- }
- }
- }
- return result;
-}
-
-function extend( a, b ) {
- for ( var prop in b ) {
- if ( b[ prop ] === undefined ) {
- delete a[ prop ];
-
- // Avoid "Member not found" error in IE8 caused by setting window.constructor
- } else if ( prop !== "constructor" || a !== window ) {
- a[ prop ] = b[ prop ];
- }
- }
-
- return a;
-}
-
-/**
- * @param {HTMLElement} elem
- * @param {string} type
- * @param {Function} fn
- */
-function addEvent( elem, type, fn ) {
- // Standards-based browsers
- if ( elem.addEventListener ) {
- elem.addEventListener( type, fn, false );
- // IE
- } else {
- elem.attachEvent( "on" + type, fn );
- }
-}
-
-/**
- * @param {Array|NodeList} elems
- * @param {string} type
- * @param {Function} fn
- */
-function addEvents( elems, type, fn ) {
- var i = elems.length;
- while ( i-- ) {
- addEvent( elems[i], type, fn );
- }
-}
-
-function hasClass( elem, name ) {
- return (" " + elem.className + " ").indexOf(" " + name + " ") > -1;
-}
-
-function addClass( elem, name ) {
- if ( !hasClass( elem, name ) ) {
- elem.className += (elem.className ? " " : "") + name;
- }
-}
-
-function removeClass( elem, name ) {
- var set = " " + elem.className + " ";
- // Class name may appear multiple times
- while ( set.indexOf(" " + name + " ") > -1 ) {
- set = set.replace(" " + name + " " , " ");
- }
- // If possible, trim it for prettiness, but not neccecarily
- elem.className = window.jQuery ? jQuery.trim( set ) : ( set.trim ? set.trim() : set );
-}
-
-function id( name ) {
- return !!( typeof document !== "undefined" && document && document.getElementById ) &&
- document.getElementById( name );
-}
-
-function registerLoggingCallback( key ) {
- return function( callback ) {
- config[key].push( callback );
- };
-}
-
-// Supports deprecated method of completely overwriting logging callbacks
-function runLoggingCallbacks( key, scope, args ) {
- var i, callbacks;
- if ( QUnit.hasOwnProperty( key ) ) {
- QUnit[ key ].call(scope, args );
- } else {
- callbacks = config[ key ];
- for ( i = 0; i < callbacks.length; i++ ) {
- callbacks[ i ].call( scope, args );
- }
- }
-}
-
-// Test for equality any JavaScript type.
-// Author: Philippe Rathé
-QUnit.equiv = (function() {
-
- // Call the o related callback with the given arguments.
- function bindCallbacks( o, callbacks, args ) {
- var prop = QUnit.objectType( o );
- if ( prop ) {
- if ( QUnit.objectType( callbacks[ prop ] ) === "function" ) {
- return callbacks[ prop ].apply( callbacks, args );
- } else {
- return callbacks[ prop ]; // or undefined
- }
- }
- }
-
- // the real equiv function
- var innerEquiv,
- // stack to decide between skip/abort functions
- callers = [],
- // stack to avoiding loops from circular referencing
- parents = [],
-
- getProto = Object.getPrototypeOf || function ( obj ) {
- return obj.__proto__;
- },
- callbacks = (function () {
-
- // for string, boolean, number and null
- function useStrictEquality( b, a ) {
- /*jshint eqeqeq:false */
- if ( b instanceof a.constructor || a instanceof b.constructor ) {
- // to catch short annotaion VS 'new' annotation of a
- // declaration
- // e.g. var i = 1;
- // var j = new Number(1);
- return a == b;
- } else {
- return a === b;
- }
- }
-
- return {
- "string": useStrictEquality,
- "boolean": useStrictEquality,
- "number": useStrictEquality,
- "null": useStrictEquality,
- "undefined": useStrictEquality,
-
- "nan": function( b ) {
- return isNaN( b );
- },
-
- "date": function( b, a ) {
- return QUnit.objectType( b ) === "date" && a.valueOf() === b.valueOf();
- },
-
- "regexp": function( b, a ) {
- return QUnit.objectType( b ) === "regexp" &&
- // the regex itself
- a.source === b.source &&
- // and its modifers
- a.global === b.global &&
- // (gmi) ...
- a.ignoreCase === b.ignoreCase &&
- a.multiline === b.multiline &&
- a.sticky === b.sticky;
- },
-
- // - skip when the property is a method of an instance (OOP)
- // - abort otherwise,
- // initial === would have catch identical references anyway
- "function": function() {
- var caller = callers[callers.length - 1];
- return caller !== Object && typeof caller !== "undefined";
- },
-
- "array": function( b, a ) {
- var i, j, len, loop;
-
- // b could be an object literal here
- if ( QUnit.objectType( b ) !== "array" ) {
- return false;
- }
-
- len = a.length;
- if ( len !== b.length ) {
- // safe and faster
- return false;
- }
-
- // track reference to avoid circular references
- parents.push( a );
- for ( i = 0; i < len; i++ ) {
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- loop = true;// dont rewalk array
- }
- }
- if ( !loop && !innerEquiv(a[i], b[i]) ) {
- parents.pop();
- return false;
- }
- }
- parents.pop();
- return true;
- },
-
- "object": function( b, a ) {
- var i, j, loop,
- // Default to true
- eq = true,
- aProperties = [],
- bProperties = [];
-
- // comparing constructors is more strict than using
- // instanceof
- if ( a.constructor !== b.constructor ) {
- // Allow objects with no prototype to be equivalent to
- // objects with Object as their constructor.
- if ( !(( getProto(a) === null && getProto(b) === Object.prototype ) ||
- ( getProto(b) === null && getProto(a) === Object.prototype ) ) ) {
- return false;
- }
- }
-
- // stack constructor before traversing properties
- callers.push( a.constructor );
- // track reference to avoid circular references
- parents.push( a );
-
- for ( i in a ) { // be strict: don't ensures hasOwnProperty
- // and go deep
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- // don't go down the same path twice
- loop = true;
- }
- }
- aProperties.push(i); // collect a's properties
-
- if (!loop && !innerEquiv( a[i], b[i] ) ) {
- eq = false;
- break;
- }
- }
-
- callers.pop(); // unstack, we are done
- parents.pop();
-
- for ( i in b ) {
- bProperties.push( i ); // collect b's properties
- }
-
- // Ensures identical properties name
- return eq && innerEquiv( aProperties.sort(), bProperties.sort() );
- }
- };
- }());
-
- innerEquiv = function() { // can take multiple arguments
- var args = [].slice.apply( arguments );
- if ( args.length < 2 ) {
- return true; // end transition
- }
-
- return (function( a, b ) {
- if ( a === b ) {
- return true; // catch the most you can
- } else if ( a === null || b === null || typeof a === "undefined" ||
- typeof b === "undefined" ||
- QUnit.objectType(a) !== QUnit.objectType(b) ) {
- return false; // don't lose time with error prone cases
- } else {
- return bindCallbacks(a, callbacks, [ b, a ]);
- }
-
- // apply transition with (1..n) arguments
- }( args[0], args[1] ) && arguments.callee.apply( this, args.splice(1, args.length - 1 )) );
- };
-
- return innerEquiv;
-}());
-
-/**
- * jsDump Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com |
- * http://flesler.blogspot.com Licensed under BSD
- * (http://www.opensource.org/licenses/bsd-license.php) Date: 5/15/2008
- *
- * @projectDescription Advanced and extensible data dumping for Javascript.
- * @version 1.0.0
- * @author Ariel Flesler
- * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html}
- */
-QUnit.jsDump = (function() {
- function quote( str ) {
- return '"' + str.toString().replace( /"/g, '\\"' ) + '"';
- }
- function literal( o ) {
- return o + "";
- }
- function join( pre, arr, post ) {
- var s = jsDump.separator(),
- base = jsDump.indent(),
- inner = jsDump.indent(1);
- if ( arr.join ) {
- arr = arr.join( "," + s + inner );
- }
- if ( !arr ) {
- return pre + post;
- }
- return [ pre, inner + arr, base + post ].join(s);
- }
- function array( arr, stack ) {
- var i = arr.length, ret = new Array(i);
- this.up();
- while ( i-- ) {
- ret[i] = this.parse( arr[i] , undefined , stack);
- }
- this.down();
- return join( "[", ret, "]" );
- }
-
- var reName = /^function (\w+)/,
- jsDump = {
- // type is used mostly internally, you can fix a (custom)type in advance
- parse: function( obj, type, stack ) {
- stack = stack || [ ];
- var inStack, res,
- parser = this.parsers[ type || this.typeOf(obj) ];
-
- type = typeof parser;
- inStack = inArray( obj, stack );
-
- if ( inStack !== -1 ) {
- return "recursion(" + (inStack - stack.length) + ")";
- }
- if ( type === "function" ) {
- stack.push( obj );
- res = parser.call( this, obj, stack );
- stack.pop();
- return res;
- }
- return ( type === "string" ) ? parser : this.parsers.error;
- },
- typeOf: function( obj ) {
- var type;
- if ( obj === null ) {
- type = "null";
- } else if ( typeof obj === "undefined" ) {
- type = "undefined";
- } else if ( QUnit.is( "regexp", obj) ) {
- type = "regexp";
- } else if ( QUnit.is( "date", obj) ) {
- type = "date";
- } else if ( QUnit.is( "function", obj) ) {
- type = "function";
- } else if ( typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined" ) {
- type = "window";
- } else if ( obj.nodeType === 9 ) {
- type = "document";
- } else if ( obj.nodeType ) {
- type = "node";
- } else if (
- // native arrays
- toString.call( obj ) === "[object Array]" ||
- // NodeList objects
- ( typeof obj.length === "number" && typeof obj.item !== "undefined" && ( obj.length ? obj.item(0) === obj[0] : ( obj.item( 0 ) === null && typeof obj[0] === "undefined" ) ) )
- ) {
- type = "array";
- } else if ( obj.constructor === Error.prototype.constructor ) {
- type = "error";
- } else {
- type = typeof obj;
- }
- return type;
- },
- separator: function() {
- return this.multiline ? this.HTML ? "
" : "\n" : this.HTML ? " " : " ";
- },
- // extra can be a number, shortcut for increasing-calling-decreasing
- indent: function( extra ) {
- if ( !this.multiline ) {
- return "";
- }
- var chr = this.indentChar;
- if ( this.HTML ) {
- chr = chr.replace( /\t/g, " " ).replace( / /g, " " );
- }
- return new Array( this._depth_ + (extra||0) ).join(chr);
- },
- up: function( a ) {
- this._depth_ += a || 1;
- },
- down: function( a ) {
- this._depth_ -= a || 1;
- },
- setParser: function( name, parser ) {
- this.parsers[name] = parser;
- },
- // The next 3 are exposed so you can use them
- quote: quote,
- literal: literal,
- join: join,
- //
- _depth_: 1,
- // This is the list of parsers, to modify them, use jsDump.setParser
- parsers: {
- window: "[Window]",
- document: "[Document]",
- error: function(error) {
- return "Error(\"" + error.message + "\")";
- },
- unknown: "[Unknown]",
- "null": "null",
- "undefined": "undefined",
- "function": function( fn ) {
- var ret = "function",
- // functions never have name in IE
- name = "name" in fn ? fn.name : (reName.exec(fn) || [])[1];
-
- if ( name ) {
- ret += " " + name;
- }
- ret += "( ";
-
- ret = [ ret, QUnit.jsDump.parse( fn, "functionArgs" ), "){" ].join( "" );
- return join( ret, QUnit.jsDump.parse(fn,"functionCode" ), "}" );
- },
- array: array,
- nodelist: array,
- "arguments": array,
- object: function( map, stack ) {
- var ret = [ ], keys, key, val, i;
- QUnit.jsDump.up();
- keys = [];
- for ( key in map ) {
- keys.push( key );
- }
- keys.sort();
- for ( i = 0; i < keys.length; i++ ) {
- key = keys[ i ];
- val = map[ key ];
- ret.push( QUnit.jsDump.parse( key, "key" ) + ": " + QUnit.jsDump.parse( val, undefined, stack ) );
- }
- QUnit.jsDump.down();
- return join( "{", ret, "}" );
- },
- node: function( node ) {
- var len, i, val,
- open = QUnit.jsDump.HTML ? "<" : "<",
- close = QUnit.jsDump.HTML ? ">" : ">",
- tag = node.nodeName.toLowerCase(),
- ret = open + tag,
- attrs = node.attributes;
-
- if ( attrs ) {
- for ( i = 0, len = attrs.length; i < len; i++ ) {
- val = attrs[i].nodeValue;
- // IE6 includes all attributes in .attributes, even ones not explicitly set.
- // Those have values like undefined, null, 0, false, "" or "inherit".
- if ( val && val !== "inherit" ) {
- ret += " " + attrs[i].nodeName + "=" + QUnit.jsDump.parse( val, "attribute" );
- }
- }
- }
- ret += close;
-
- // Show content of TextNode or CDATASection
- if ( node.nodeType === 3 || node.nodeType === 4 ) {
- ret += node.nodeValue;
- }
-
- return ret + open + "/" + tag + close;
- },
- // function calls it internally, it's the arguments part of the function
- functionArgs: function( fn ) {
- var args,
- l = fn.length;
-
- if ( !l ) {
- return "";
- }
-
- args = new Array(l);
- while ( l-- ) {
- // 97 is 'a'
- args[l] = String.fromCharCode(97+l);
- }
- return " " + args.join( ", " ) + " ";
- },
- // object calls it internally, the key part of an item in a map
- key: quote,
- // function calls it internally, it's the content of the function
- functionCode: "[code]",
- // node calls it internally, it's an html attribute value
- attribute: quote,
- string: quote,
- date: quote,
- regexp: literal,
- number: literal,
- "boolean": literal
- },
- // if true, entities are escaped ( <, >, \t, space and \n )
- HTML: false,
- // indentation unit
- indentChar: " ",
- // if true, items in a collection, are separated by a \n, else just a space.
- multiline: true
- };
-
- return jsDump;
-}());
-
-// from jquery.js
-function inArray( elem, array ) {
- if ( array.indexOf ) {
- return array.indexOf( elem );
- }
-
- for ( var i = 0, length = array.length; i < length; i++ ) {
- if ( array[ i ] === elem ) {
- return i;
- }
- }
-
- return -1;
-}
-
-/*
- * Javascript Diff Algorithm
- * By John Resig (http://ejohn.org/)
- * Modified by Chu Alan "sprite"
- *
- * Released under the MIT license.
- *
- * More Info:
- * http://ejohn.org/projects/javascript-diff-algorithm/
- *
- * Usage: QUnit.diff(expected, actual)
- *
- * QUnit.diff( "the quick brown fox jumped over", "the quick fox jumps over" ) == "the quick brown fox jumped jumps over"
- */
-QUnit.diff = (function() {
- /*jshint eqeqeq:false, eqnull:true */
- function diff( o, n ) {
- var i,
- ns = {},
- os = {};
-
- for ( i = 0; i < n.length; i++ ) {
- if ( !hasOwn.call( ns, n[i] ) ) {
- ns[ n[i] ] = {
- rows: [],
- o: null
- };
- }
- ns[ n[i] ].rows.push( i );
- }
-
- for ( i = 0; i < o.length; i++ ) {
- if ( !hasOwn.call( os, o[i] ) ) {
- os[ o[i] ] = {
- rows: [],
- n: null
- };
- }
- os[ o[i] ].rows.push( i );
- }
-
- for ( i in ns ) {
- if ( !hasOwn.call( ns, i ) ) {
- continue;
- }
- if ( ns[i].rows.length === 1 && hasOwn.call( os, i ) && os[i].rows.length === 1 ) {
- n[ ns[i].rows[0] ] = {
- text: n[ ns[i].rows[0] ],
- row: os[i].rows[0]
- };
- o[ os[i].rows[0] ] = {
- text: o[ os[i].rows[0] ],
- row: ns[i].rows[0]
- };
- }
- }
-
- for ( i = 0; i < n.length - 1; i++ ) {
- if ( n[i].text != null && n[ i + 1 ].text == null && n[i].row + 1 < o.length && o[ n[i].row + 1 ].text == null &&
- n[ i + 1 ] == o[ n[i].row + 1 ] ) {
-
- n[ i + 1 ] = {
- text: n[ i + 1 ],
- row: n[i].row + 1
- };
- o[ n[i].row + 1 ] = {
- text: o[ n[i].row + 1 ],
- row: i + 1
- };
- }
- }
-
- for ( i = n.length - 1; i > 0; i-- ) {
- if ( n[i].text != null && n[ i - 1 ].text == null && n[i].row > 0 && o[ n[i].row - 1 ].text == null &&
- n[ i - 1 ] == o[ n[i].row - 1 ]) {
-
- n[ i - 1 ] = {
- text: n[ i - 1 ],
- row: n[i].row - 1
- };
- o[ n[i].row - 1 ] = {
- text: o[ n[i].row - 1 ],
- row: i - 1
- };
- }
- }
-
- return {
- o: o,
- n: n
- };
- }
-
- return function( o, n ) {
- o = o.replace( /\s+$/, "" );
- n = n.replace( /\s+$/, "" );
-
- var i, pre,
- str = "",
- out = diff( o === "" ? [] : o.split(/\s+/), n === "" ? [] : n.split(/\s+/) ),
- oSpace = o.match(/\s+/g),
- nSpace = n.match(/\s+/g);
-
- if ( oSpace == null ) {
- oSpace = [ " " ];
- }
- else {
- oSpace.push( " " );
- }
-
- if ( nSpace == null ) {
- nSpace = [ " " ];
- }
- else {
- nSpace.push( " " );
- }
-
- if ( out.n.length === 0 ) {
- for ( i = 0; i < out.o.length; i++ ) {
- str += "" + out.o[i] + oSpace[i] + "";
- }
- }
- else {
- if ( out.n[0].text == null ) {
- for ( n = 0; n < out.o.length && out.o[n].text == null; n++ ) {
- str += "" + out.o[n] + oSpace[n] + "";
- }
- }
-
- for ( i = 0; i < out.n.length; i++ ) {
- if (out.n[i].text == null) {
- str += "" + out.n[i] + nSpace[i] + "";
- }
- else {
- // `pre` initialized at top of scope
- pre = "";
-
- for ( n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++ ) {
- pre += "" + out.o[n] + oSpace[n] + "";
- }
- str += " " + out.n[i].text + nSpace[i] + pre;
- }
- }
- }
-
- return str;
- };
-}());
-
-// for CommonJS enviroments, export everything
-if ( typeof exports !== "undefined" ) {
- extend( exports, QUnit );
-}
-
-// get at whatever the global object is, like window in browsers
-}( (function() {return this;}.call()) ));
diff --git a/test/lib/require.js b/test/lib/require.js
deleted file mode 100644
index 987f865..0000000
--- a/test/lib/require.js
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- RequireJS 2.1.5 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.
- Available via the MIT or new BSD license.
- see: http://github.com/jrburke/requirejs for details
-*/
-var requirejs,require,define;
-(function(aa){function I(b){return"[object Function]"===L.call(b)}function J(b){return"[object Array]"===L.call(b)}function y(b,c){if(b){var d;for(d=0;dthis.depCount&&!this.defined){if(I(n)){if(this.events.error)try{e=i.execCb(c,n,b,e)}catch(d){a=d}else e=i.execCb(c,n,b,e);this.map.isDefine&&((b=this.module)&&void 0!==b.exports&&b.exports!==this.exports?e=b.exports:void 0===e&&this.usingExports&&(e=this.exports));if(a)return a.requireMap=this.map,a.requireModules=[this.map.id],a.requireType="define",v(this.error=
-a)}else e=n;this.exports=e;if(this.map.isDefine&&!this.ignore&&(q[c]=e,l.onResourceLoad))l.onResourceLoad(i,this.map,this.depMaps);x(c);this.defined=!0}this.defining=!1;this.defined&&!this.defineEmitted&&(this.defineEmitted=!0,this.emit("defined",this.exports),this.defineEmitComplete=!0)}}else this.fetch()}},callPlugin:function(){var a=this.map,b=a.id,d=j(a.prefix);this.depMaps.push(d);t(d,"defined",u(this,function(e){var n,d;d=this.map.name;var g=this.map.parentMap?this.map.parentMap.name:null,h=
-i.makeRequire(a.parentMap,{enableBuildCallback:!0});if(this.map.unnormalized){if(e.normalize&&(d=e.normalize(d,function(a){return c(a,g,!0)})||""),e=j(a.prefix+"!"+d,this.map.parentMap),t(e,"defined",u(this,function(a){this.init([],function(){return a},null,{enabled:!0,ignore:!0})})),d=m(p,e.id)){this.depMaps.push(e);if(this.events.error)d.on("error",u(this,function(a){this.emit("error",a)}));d.enable()}}else n=u(this,function(a){this.init([],function(){return a},null,{enabled:!0})}),n.error=u(this,
-function(a){this.inited=!0;this.error=a;a.requireModules=[b];G(p,function(a){0===a.map.id.indexOf(b+"_unnormalized")&&x(a.map.id)});v(a)}),n.fromText=u(this,function(e,c){var d=a.name,g=j(d),C=O;c&&(e=c);C&&(O=!1);r(g);s(k.config,b)&&(k.config[d]=k.config[b]);try{l.exec(e)}catch(ca){return v(B("fromtexteval","fromText eval for "+b+" failed: "+ca,ca,[b]))}C&&(O=!0);this.depMaps.push(g);i.completeLoad(d);h([d],n)}),e.load(a.name,h,n,k)}));i.enable(d,this);this.pluginMaps[d.id]=d},enable:function(){V[this.map.id]=
-this;this.enabling=this.enabled=!0;y(this.depMaps,u(this,function(a,b){var c,e;if("string"===typeof a){a=j(a,this.map.isDefine?this.map:this.map.parentMap,!1,!this.skipMap);this.depMaps[b]=a;if(c=m(N,a.id)){this.depExports[b]=c(this);return}this.depCount+=1;t(a,"defined",u(this,function(a){this.defineDep(b,a);this.check()}));this.errback&&t(a,"error",this.errback)}c=a.id;e=p[c];!s(N,c)&&(e&&!e.enabled)&&i.enable(a,this)}));G(this.pluginMaps,u(this,function(a){var b=m(p,a.id);b&&!b.enabled&&i.enable(a,
-this)}));this.enabling=!1;this.check()},on:function(a,b){var c=this.events[a];c||(c=this.events[a]=[]);c.push(b)},emit:function(a,b){y(this.events[a],function(a){a(b)});"error"===a&&delete this.events[a]}};i={config:k,contextName:b,registry:p,defined:q,urlFetched:U,defQueue:H,Module:Z,makeModuleMap:j,nextTick:l.nextTick,onError:v,configure:function(a){a.baseUrl&&"/"!==a.baseUrl.charAt(a.baseUrl.length-1)&&(a.baseUrl+="/");var b=k.pkgs,c=k.shim,e={paths:!0,config:!0,map:!0};G(a,function(a,b){e[b]?
-"map"===b?(k.map||(k.map={}),R(k[b],a,!0,!0)):R(k[b],a,!0):k[b]=a});a.shim&&(G(a.shim,function(a,b){J(a)&&(a={deps:a});if((a.exports||a.init)&&!a.exportsFn)a.exportsFn=i.makeShimExports(a);c[b]=a}),k.shim=c);a.packages&&(y(a.packages,function(a){a="string"===typeof a?{name:a}:a;b[a.name]={name:a.name,location:a.location||a.name,main:(a.main||"main").replace(ja,"").replace(ea,"")}}),k.pkgs=b);G(p,function(a,b){!a.inited&&!a.map.unnormalized&&(a.map=j(b))});if(a.deps||a.callback)i.require(a.deps||[],
-a.callback)},makeShimExports:function(a){return function(){var b;a.init&&(b=a.init.apply(aa,arguments));return b||a.exports&&ba(a.exports)}},makeRequire:function(a,f){function d(e,c,h){var g,k;f.enableBuildCallback&&(c&&I(c))&&(c.__requireJsBuild=!0);if("string"===typeof e){if(I(c))return v(B("requireargs","Invalid require call"),h);if(a&&s(N,e))return N[e](p[a.id]);if(l.get)return l.get(i,e,a,d);g=j(e,a,!1,!0);g=g.id;return!s(q,g)?v(B("notloaded",'Module name "'+g+'" has not been loaded yet for context: '+
-b+(a?"":". Use require([])"))):q[g]}L();i.nextTick(function(){L();k=r(j(null,a));k.skipMap=f.skipMap;k.init(e,c,h,{enabled:!0});D()});return d}f=f||{};R(d,{isBrowser:A,toUrl:function(b){var d,f=b.lastIndexOf("."),g=b.split("/")[0];if(-1!==f&&(!("."===g||".."===g)||1h.attachEvent.toString().indexOf("[native code"))&&!Y?(O=!0,h.attachEvent("onreadystatechange",b.onScriptLoad)):(h.addEventListener("load",b.onScriptLoad,!1),h.addEventListener("error",b.onScriptError,!1)),h.src=d,K=h,D?x.insertBefore(h,D):x.appendChild(h),K=null,h;if(da)try{importScripts(d),b.completeLoad(c)}catch(j){b.onError(B("importscripts","importScripts failed for "+c+" at "+d,j,[c]))}};A&&M(document.getElementsByTagName("script"),function(b){x||(x=
-b.parentNode);if(t=b.getAttribute("data-main"))return r.baseUrl||(E=t.split("/"),Q=E.pop(),fa=E.length?E.join("/")+"/":"./",r.baseUrl=fa,t=Q),t=t.replace(ea,""),r.deps=r.deps?r.deps.concat(t):[t],!0});define=function(b,c,d){var l,h;"string"!==typeof b&&(d=c,c=b,b=null);J(c)||(d=c,c=[]);!c.length&&I(d)&&d.length&&(d.toString().replace(la,"").replace(ma,function(b,d){c.push(d)}),c=(1===d.length?["require"]:["require","exports","module"]).concat(c));if(O){if(!(l=K))P&&"interactive"===P.readyState||M(document.getElementsByTagName("script"),
-function(b){if("interactive"===b.readyState)return P=b}),l=P;l&&(b||(b=l.getAttribute("data-requiremodule")),h=F[l.getAttribute("data-requirecontext")])}(h?h.defQueue:T).push([b,c,d])};define.amd={jQuery:!0};l.exec=function(b){return eval(b)};l(r)}})(this);
diff --git a/.gitignore b/.gitignore
index 12e1b62..0b88317 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
node_modules
.DS_Store
-.project
\ No newline at end of file
+.project
+*.log
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..63e4d7c
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,8 @@
+language: node_js
+node_js:
+ - 0.10
+
+before_script:
+ - npm install -g grunt-cli
+ - export DISPLAY=:99.0
+ - sh -e /etc/init.d/xvfb start
diff --git a/Gruntfile.js b/Gruntfile.js
index b083b49..103938c 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -1,10 +1,12 @@
+'use strict';
+
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-connect');
- grunt.loadNpmTasks('grunt-contrib-qunit');
grunt.loadNpmTasks('grunt-contrib-yuidoc');
+ grunt.loadTasks('tasks');
var root = 'src/pixi/',
debug = 'bin/pixi.dev.js',
@@ -79,7 +81,7 @@
},
files: {
srcBlob: '<%= dirs.src %>/**/*.js',
- testBlob: '<%= dirs.test %>/unit/**/*.js',
+ testBlob: '<%= dirs.test %>/{functional,lib/pixi,unit}/**/*.js',
build: '<%= dirs.build %>/pixi.dev.js',
buildMin: '<%= dirs.build %>/pixi.js'
},
@@ -94,7 +96,12 @@
},
jshint: {
beforeconcat: srcFiles,
- test: ['<%= files.testBlob %>'],
+ test: {
+ src: ['<%= files.testBlob %>'],
+ options: {
+ expr: true
+ }
+ },
options: {
asi: true,
smarttabs: true
@@ -128,12 +135,6 @@
]
},
connect: {
- qunit: {
- options: {
- port: grunt.option('port-test') || 9002,
- base: './'
- }
- },
test: {
options: {
port: grunt.option('port-test') || 9002,
@@ -142,13 +143,6 @@
}
}
},
- qunit: {
- all: {
- options: {
- urls: ['http://localhost:' + (grunt.option('port-test') || 9002) + '/test/index.html']
- }
- }
- },
yuidoc: {
compile: {
name: '<%= pkg.name %>',
@@ -161,6 +155,13 @@
outdir: '<%= dirs.docs %>'
}
}
+ },
+ karma: {
+ unit: {
+ configFile: 'test/karma.conf.js',
+ // browsers: ['Chrome'],
+ singleRun: true
+ }
}
});
@@ -182,9 +183,10 @@
}
)
- grunt.registerTask('default', ['concat', 'uglify', 'distribute']);
grunt.registerTask('build', ['concat', 'uglify', 'distribute']);
- grunt.registerTask('test', ['build', 'connect:qunit', 'qunit']);
+ grunt.registerTask('test', ['concat', 'jshint:test', 'karma']);
grunt.registerTask('docs', ['yuidoc']);
-
-}
\ No newline at end of file
+ grunt.registerTask('default', ['test', 'uglify', 'distribute']);
+ // Travis CI task.
+ grunt.registerTask('travis', ['test']);
+}
diff --git a/README.md b/README.md
index c62ef86..690cfe4 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,8 @@

+[](http://travis-ci.org/drkibitz/pixi.js)
+
#### JavaScript 2D Renderer ####
The aim of this project is to provide a fast lightweight 2D library that works
diff --git a/package.json b/package.json
index b373240..1246a68 100644
--- a/package.json
+++ b/package.json
@@ -18,14 +18,21 @@
"main": "bin/pixi.js",
+ "scripts": {
+ "test": "grunt travis --verbose"
+ },
+
"dependencies": {},
"devDependencies": {
"grunt": "~0.4.x",
- "grunt-contrib-jshint": "0.3.x",
+ "grunt-contrib-jshint": "0.6.x",
"grunt-contrib-uglify": "0.2.x",
- "grunt-contrib-connect": "0.2.x",
- "grunt-contrib-qunit": "0.2.x",
+ "grunt-contrib-connect": "0.3.x",
"grunt-contrib-yuidoc": "0.4.x",
- "grunt-contrib-concat": "0.1.x"
+ "grunt-contrib-concat": "0.3.x",
+ "chai": "~1.7.0",
+ "karma": "0.11.0",
+ "karma-firefox-launcher": "0.1.0",
+ "karma-mocha": "0.1.0"
}
}
diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js
index a7c520e..ee82bbd 100644
--- a/src/pixi/InteractionManager.js
+++ b/src/pixi/InteractionManager.js
@@ -62,7 +62,6 @@
this.onTouchEnd = this.onTouchEnd.bind(this);
this.onTouchMove = this.onTouchMove.bind(this);
-
this.last = 0;
}
diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js
index 1a95d20..eef1059 100644
--- a/src/pixi/core/Ellipse.js
+++ b/src/pixi/core/Ellipse.js
@@ -78,7 +78,7 @@
return (normx + normy < 0.25);
}
-PIXI.Ellipse.getBounds = function()
+PIXI.Ellipse.prototype.getBounds = function()
{
return new PIXI.Rectangle(this.x, this.y, this.width, this.height);
}
diff --git a/tasks/karma.js b/tasks/karma.js
new file mode 100644
index 0000000..c340485
--- /dev/null
+++ b/tasks/karma.js
@@ -0,0 +1,27 @@
+'use strict';
+
+var path = require('path');
+var server = require('karma').server;
+
+module.exports = function (grunt) {
+ grunt.registerMultiTask('karma', 'run karma.', function() {
+ var done = this.async();
+ var options = this.options({
+ background: false
+ });
+ var data = this.data;
+
+ //merge options onto data, with data taking precedence
+ data = grunt.util._.merge(options, data);
+ data.configFile = path.resolve(data.configFile);
+ if (data.configFile) {
+ data.configFile = grunt.template.process(data.configFile);
+ }
+
+ server.start(
+ data,
+ function(code) {
+ done(!code);
+ });
+ });
+};
diff --git a/test/functional/example-1-basics/bunny.png b/test/functional/example-1-basics/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/functional/example-1-basics/bunny.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-30.png b/test/functional/example-1-basics/frame-30.png
new file mode 100644
index 0000000..96e3409
--- /dev/null
+++ b/test/functional/example-1-basics/frame-30.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-60.png b/test/functional/example-1-basics/frame-60.png
new file mode 100644
index 0000000..af3f4ce
--- /dev/null
+++ b/test/functional/example-1-basics/frame-60.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-90.png b/test/functional/example-1-basics/frame-90.png
new file mode 100644
index 0000000..099b823
--- /dev/null
+++ b/test/functional/example-1-basics/frame-90.png
Binary files differ
diff --git a/test/functional/example-1-basics/index.js b/test/functional/example-1-basics/index.js
new file mode 100644
index 0000000..7ae7a98
--- /dev/null
+++ b/test/functional/example-1-basics/index.js
@@ -0,0 +1,133 @@
+describe('Example 1 - Basics', function () {
+ 'use strict';
+
+ var baseUri = '/base/test/functional/example-1-basics';
+ var expect = chai.expect;
+ var currentFrame = 0;
+ var frameEvents = {};
+ var stage;
+ var renderer;
+ var bunny;
+
+ function onFrame(frame, callback) {
+ frameEvents[frame] = callback;
+ }
+
+ function animate() {
+ currentFrame += 1;
+
+ requestAnimFrame( animate );
+
+ // just for fun, lets rotate mr rabbit a little
+ bunny.rotation += 0.1;
+
+ // render the stage
+ renderer.render(stage);
+
+ if (frameEvents[currentFrame])
+ frameEvents[currentFrame](currentFrame);
+ }
+
+ function initScene() {
+ // create an new instance of a pixi stage
+ stage = new PIXI.Stage(0x66FF99);
+
+ // create a renderer instance
+ renderer = PIXI.autoDetectRenderer(400, 300);
+ console.log('Is PIXI.WebGLRenderer: ' + (renderer instanceof PIXI.WebGLRenderer));
+
+ // add the renderer view element to the DOM
+ document.body.appendChild(renderer.view);
+
+ requestAnimFrame( animate );
+
+ // create a texture from an image path
+ var texture = PIXI.Texture.fromImage(baseUri + "/bunny.png");
+ // create a new Sprite using the texture
+ bunny = new PIXI.Sprite(texture);
+
+ // center the sprites anchor point
+ bunny.anchor.x = 0.5;
+ bunny.anchor.y = 0.5;
+
+ // move the sprite t the center of the screen
+ bunny.position.x = 200;
+ bunny.position.y = 150;
+
+ stage.addChild(bunny);
+ }
+
+ it('assets loaded', function (done) {
+ var loader = new PIXI.AssetLoader([
+ baseUri + '/bunny.png',
+ baseUri + '/frame-30.png',
+ baseUri + '/frame-60.png',
+ baseUri + '/frame-90.png'
+ ]);
+ // loader.on('onProgress', function (event) {
+ // console.log(event.content);
+ // });
+ loader.on('onComplete', function (event) {
+ done();
+ initScene();
+ });
+ loader.load();
+ });
+
+ it('frame 30 should match', function (done) {
+ this.timeout(700);
+ onFrame(30, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-30.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 60 should match', function (done) {
+ this.timeout(1200);
+ onFrame(60, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-60.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 90 should match', function (done) {
+ this.timeout(1700);
+ onFrame(90, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-90.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ // it('capture something', function (done) {
+ // this.timeout(2000000);
+ // onFrame(30, function () {
+ // var img = new Image();
+ // img.src = renderer.view.toDataURL('image/png');
+ // document.body.appendChild(img);
+ // });
+ // });
+});
diff --git a/test/index.html b/test/index.html
deleted file mode 100644
index 9cbcac5..0000000
--- a/test/index.html
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
- Pixi.js Test Suite
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/test/karma.conf.js b/test/karma.conf.js
new file mode 100644
index 0000000..c66a696
--- /dev/null
+++ b/test/karma.conf.js
@@ -0,0 +1,82 @@
+module.exports = function(config) {
+ config.set({
+
+ // base path, that will be used to resolve files and exclude
+ basePath : '../',
+
+ frameworks : ['mocha'],
+
+ // list of files / patterns to load in the browser
+ files : [
+ 'node_modules/chai/chai.js',
+ 'bin/pixi.dev.js',
+ 'test/lib/**/*.js',
+ 'test/unit/**/*.js',
+ // 'test/functional/**/*.js',
+ {pattern: 'test/**/*.png', watched: false, included: false, served: true}
+ ],
+
+ // list of files to exclude
+ exclude : [],
+
+ // use dolts reporter, as travis terminal does not support escaping sequences
+ // possible values: 'dots', 'progress', 'junit', 'teamcity'
+ // CLI --reporters progress
+ reporters : ['progress'],
+
+ // web server port
+ // CLI --port 9876
+ port : 9876,
+
+ // cli runner port
+ // CLI --runner-port 9100
+ runnerPort : 9100,
+
+ // enable / disable colors in the output (reporters and logs)
+ // CLI --colors --no-colors
+ colors : true,
+
+ // level of logging
+ // possible values: karma.LOG_DISABLE || karma.LOG_ERROR || karma.LOG_WARN || karma.LOG_INFO || karma.LOG_DEBUG
+ // CLI --log-level debug
+ logLevel : config.LOG_DEBUG,
+
+ // enable / disable watching file and executing tests whenever any file changes
+ // CLI --auto-watch --no-auto-watch
+ autoWatch : false,
+
+ // Start these browsers, currently available:
+ // - Chrome
+ // - ChromeCanary
+ // - Firefox
+ // - Opera
+ // - Safari (only Mac)
+ // - PhantomJS
+ // - IE (only Windows)
+ // CLI --browsers Chrome,Firefox,Safari
+ browsers : ['Firefox'],
+
+ // If browser does not capture in given timeout [ms], kill it
+ // CLI --capture-timeout 5000
+ captureTimeout : 5000,
+
+ // Auto run tests on start (when browsers are captured) and exit
+ // CLI --single-run --no-single-run
+ singleRun : true,
+
+ // report which specs are slower than 500ms
+ // CLI --report-slower-than 500
+ reportSlowerThan : 1000,
+
+ preprocessors : {
+ // '**/client/js/*.js': 'coverage'
+ },
+
+ plugins : [
+ 'karma-mocha',
+ // 'karma-chrome-launcher',
+ 'karma-firefox-launcher',
+ // 'karma-phantomjs-launcher'
+ ]
+ });
+};
diff --git a/test/lib/pixi/core/Matrix.js b/test/lib/pixi/core/Matrix.js
new file mode 100644
index 0000000..d26386b
--- /dev/null
+++ b/test/lib/pixi/core/Matrix.js
@@ -0,0 +1,40 @@
+
+function pixi_core_Matrix_confirmNewMat3(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(1);
+ expect(matrix[5]).to.equal(0);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(1);
+}
+
+function pixi_core_Matrix_confirmNewMat4(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[0]).to.equal(1);
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(0);
+ expect(matrix[5]).to.equal(1);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(0);
+ expect(matrix[9]).to.equal(0);
+ expect(matrix[10]).to.equal(1);
+ expect(matrix[11]).to.equal(0);
+ expect(matrix[12]).to.equal(0);
+ expect(matrix[13]).to.equal(0);
+ expect(matrix[14]).to.equal(0);
+ expect(matrix[15]).to.equal(1);
+}
diff --git a/test/lib/pixi/core/Point.js b/test/lib/pixi/core/Point.js
new file mode 100644
index 0000000..e5df07b
--- /dev/null
+++ b/test/lib/pixi/core/Point.js
@@ -0,0 +1,10 @@
+
+function pixi_core_Point_confirm(obj, x, y) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Point);
+ expect(obj).to.respondTo('clone');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+}
diff --git a/test/lib/pixi/core/Rectangle.js b/test/lib/pixi/core/Rectangle.js
new file mode 100644
index 0000000..23f0d12
--- /dev/null
+++ b/test/lib/pixi/core/Rectangle.js
@@ -0,0 +1,13 @@
+
+function pixi_core_Rectangle_confirm(obj, x, y, width, height) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Rectangle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+ expect(obj).to.have.property('width', width);
+ expect(obj).to.have.property('height', height);
+}
diff --git a/test/lib/pixi/display/DisplayObject.js b/test/lib/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..1388a7f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObject.js
@@ -0,0 +1,43 @@
+
+function pixi_display_DisplayObject_confirmNew(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObject);
+ expect(obj).to.respondTo('setInteractive');
+ expect(obj).to.respondTo('addFilter');
+ expect(obj).to.respondTo('removeFilter');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.property('last', obj);
+ expect(obj).to.have.property('first', obj);
+
+ expect(obj).to.contain.property('position');
+ pixi_core_Point_confirm(obj.position, 0, 0);
+ expect(obj).to.contain.property('scale');
+ pixi_core_Point_confirm(obj.scale, 1, 1);
+ expect(obj).to.contain.property('pivot');
+ pixi_core_Point_confirm(obj.pivot, 0, 0);
+
+ expect(obj).to.have.property('rotation', 0);
+ expect(obj).to.have.property('alpha', 1);
+ expect(obj).to.have.property('visible', true);
+ expect(obj).to.have.property('buttonMode', false);
+ expect(obj).to.have.property('parent', null);
+ expect(obj).to.have.property('worldAlpha', 1);
+
+ expect(obj).to.have.property('hitArea');
+ expect(obj).to.have.property('interactive'); // TODO: Have a better default value
+ expect('mask' in obj).to.be.true; // TODO: Have a better default value
+ expect(obj.mask).to.be.undefined;
+
+ expect(obj).to.have.property('renderable');
+ expect(obj).to.have.property('stage');
+
+ expect(obj).to.have.deep.property('worldTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ expect(obj).to.have.deep.property('localTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.localTransform);
+
+ expect(obj).to.have.deep.property('color.length', 0);
+ expect(obj).to.have.property('dynamic', true);
+}
diff --git a/test/lib/pixi/display/DisplayObjectContainer.js b/test/lib/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..085c59f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,16 @@
+
+function pixi_display_DisplayObjectContainer_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObject_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObjectContainer);
+ expect(obj).to.respondTo('addChild');
+ expect(obj).to.respondTo('addChildAt');
+ expect(obj).to.respondTo('swapChildren');
+ expect(obj).to.respondTo('getChildAt');
+ expect(obj).to.respondTo('removeChild');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('children.length', 0);
+}
diff --git a/test/lib/pixi/display/Sprite.js b/test/lib/pixi/display/Sprite.js
new file mode 100644
index 0000000..cc7a2d6
--- /dev/null
+++ b/test/lib/pixi/display/Sprite.js
@@ -0,0 +1,28 @@
+
+function pixi_display_Sprite_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Sprite);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', true);
+ expect(obj).to.have.property('stage', null);
+
+ expect(obj).to.have.property('anchor');
+ pixi_core_Point_confirm(obj.anchor, 0, 0);
+
+ expect(obj).to.have.property('blendMode', PIXI.blendModes.NORMAL);
+ expect(obj).to.have.property('width', 1); // TODO: is 1 expected
+ expect(obj).to.have.property('height', 1); // TODO: is 1 expected
+
+ // FIXME: Just make this a boolean that is always there
+ expect(!!obj.updateFrame).to.equal(obj.texture.baseTexture.hasLoaded);
+
+ expect(obj).to.have.property('texture');
+ pixi_textures_Texture_confirmNew(obj.texture, done);
+}
diff --git a/test/lib/pixi/extras/Strip.js b/test/lib/pixi/extras/Strip.js
new file mode 100644
index 0000000..8927a8a
--- /dev/null
+++ b/test/lib/pixi/extras/Strip.js
@@ -0,0 +1,12 @@
+
+function pixi_extras_Strip_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Strip);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ // TODO: Test properties
+}
diff --git a/test/lib/pixi/textures/Texture.js b/test/lib/pixi/textures/Texture.js
new file mode 100644
index 0000000..d5867b6
--- /dev/null
+++ b/test/lib/pixi/textures/Texture.js
@@ -0,0 +1,31 @@
+
+function pixi_textures_Texture_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ function confirmFrameDone() {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, obj.baseTexture.width, obj.baseTexture.height);
+
+ expect(obj).to.have.property('width', obj.baseTexture.width);
+ expect(obj).to.have.property('height', obj.baseTexture.height);
+ done();
+ }
+
+ expect(obj).to.be.an.instanceof(PIXI.Texture);
+ pixi_utils_EventTarget_like(obj);
+
+ expect(obj).to.have.property('baseTexture')
+ .and.to.be.an.instanceof(PIXI.BaseTexture);
+
+ expect(obj).to.have.property('scope', obj);
+
+ expect(obj).to.have.property('trim');
+ pixi_core_Point_confirm(obj.trim, 0, 0);
+
+ expect(obj).to.have.property('frame');
+ if (obj.baseTexture.hasLoaded) {
+ confirmFrameDone();
+ } else {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, 1, 1);
+ obj.addEventListener('update', confirmFrameDone);
+ }
+}
diff --git a/test/lib/pixi/utils/EventTarget.js b/test/lib/pixi/utils/EventTarget.js
new file mode 100644
index 0000000..7b1dcfa
--- /dev/null
+++ b/test/lib/pixi/utils/EventTarget.js
@@ -0,0 +1,8 @@
+
+function pixi_utils_EventTarget_like(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.respondTo('addEventListener');
+ expect(obj).to.respondTo('dispatchEvent');
+ expect(obj).to.respondTo('removeEventListener');
+}
diff --git a/test/lib/qunit-1.11.0.css b/test/lib/qunit-1.11.0.css
deleted file mode 100644
index d7fc0c8..0000000
--- a/test/lib/qunit-1.11.0.css
+++ /dev/null
@@ -1,244 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-/** Font Family and Sizes */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
- font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
-}
-
-#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
-#qunit-tests { font-size: smaller; }
-
-
-/** Resets */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter {
- margin: 0;
- padding: 0;
-}
-
-
-/** Header */
-
-#qunit-header {
- padding: 0.5em 0 0.5em 1em;
-
- color: #8699a4;
- background-color: #0d3349;
-
- font-size: 1.5em;
- line-height: 1em;
- font-weight: normal;
-
- border-radius: 5px 5px 0 0;
- -moz-border-radius: 5px 5px 0 0;
- -webkit-border-top-right-radius: 5px;
- -webkit-border-top-left-radius: 5px;
-}
-
-#qunit-header a {
- text-decoration: none;
- color: #c2ccd1;
-}
-
-#qunit-header a:hover,
-#qunit-header a:focus {
- color: #fff;
-}
-
-#qunit-testrunner-toolbar label {
- display: inline-block;
- padding: 0 .5em 0 .1em;
-}
-
-#qunit-banner {
- height: 5px;
-}
-
-#qunit-testrunner-toolbar {
- padding: 0.5em 0 0.5em 2em;
- color: #5E740B;
- background-color: #eee;
- overflow: hidden;
-}
-
-#qunit-userAgent {
- padding: 0.5em 0 0.5em 2.5em;
- background-color: #2b81af;
- color: #fff;
- text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
-}
-
-#qunit-modulefilter-container {
- float: right;
-}
-
-/** Tests: Pass/Fail */
-
-#qunit-tests {
- list-style-position: inside;
-}
-
-#qunit-tests li {
- padding: 0.4em 0.5em 0.4em 2.5em;
- border-bottom: 1px solid #fff;
- list-style-position: inside;
-}
-
-#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running {
- display: none;
-}
-
-#qunit-tests li strong {
- cursor: pointer;
-}
-
-#qunit-tests li a {
- padding: 0.5em;
- color: #c2ccd1;
- text-decoration: none;
-}
-#qunit-tests li a:hover,
-#qunit-tests li a:focus {
- color: #000;
-}
-
-#qunit-tests li .runtime {
- float: right;
- font-size: smaller;
-}
-
-.qunit-assert-list {
- margin-top: 0.5em;
- padding: 0.5em;
-
- background-color: #fff;
-
- border-radius: 5px;
- -moz-border-radius: 5px;
- -webkit-border-radius: 5px;
-}
-
-.qunit-collapsed {
- display: none;
-}
-
-#qunit-tests table {
- border-collapse: collapse;
- margin-top: .2em;
-}
-
-#qunit-tests th {
- text-align: right;
- vertical-align: top;
- padding: 0 .5em 0 0;
-}
-
-#qunit-tests td {
- vertical-align: top;
-}
-
-#qunit-tests pre {
- margin: 0;
- white-space: pre-wrap;
- word-wrap: break-word;
-}
-
-#qunit-tests del {
- background-color: #e0f2be;
- color: #374e0c;
- text-decoration: none;
-}
-
-#qunit-tests ins {
- background-color: #ffcaca;
- color: #500;
- text-decoration: none;
-}
-
-/*** Test Counts */
-
-#qunit-tests b.counts { color: black; }
-#qunit-tests b.passed { color: #5E740B; }
-#qunit-tests b.failed { color: #710909; }
-
-#qunit-tests li li {
- padding: 5px;
- background-color: #fff;
- border-bottom: none;
- list-style-position: inside;
-}
-
-/*** Passing Styles */
-
-#qunit-tests li li.pass {
- color: #3c510c;
- background-color: #fff;
- border-left: 10px solid #C6E746;
-}
-
-#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
-#qunit-tests .pass .test-name { color: #366097; }
-
-#qunit-tests .pass .test-actual,
-#qunit-tests .pass .test-expected { color: #999999; }
-
-#qunit-banner.qunit-pass { background-color: #C6E746; }
-
-/*** Failing Styles */
-
-#qunit-tests li li.fail {
- color: #710909;
- background-color: #fff;
- border-left: 10px solid #EE5757;
- white-space: pre;
-}
-
-#qunit-tests > li:last-child {
- border-radius: 0 0 5px 5px;
- -moz-border-radius: 0 0 5px 5px;
- -webkit-border-bottom-right-radius: 5px;
- -webkit-border-bottom-left-radius: 5px;
-}
-
-#qunit-tests .fail { color: #000000; background-color: #EE5757; }
-#qunit-tests .fail .test-name,
-#qunit-tests .fail .module-name { color: #000000; }
-
-#qunit-tests .fail .test-actual { color: #EE5757; }
-#qunit-tests .fail .test-expected { color: green; }
-
-#qunit-banner.qunit-fail { background-color: #EE5757; }
-
-
-/** Result */
-
-#qunit-testresult {
- padding: 0.5em 0.5em 0.5em 2.5em;
-
- color: #2b81af;
- background-color: #D2E0E6;
-
- border-bottom: 1px solid white;
-}
-#qunit-testresult .module-name {
- font-weight: bold;
-}
-
-/** Fixture */
-
-#qunit-fixture {
- position: absolute;
- top: -10000px;
- left: -10000px;
- width: 1000px;
- height: 1000px;
-}
diff --git a/test/lib/qunit-1.11.0.js b/test/lib/qunit-1.11.0.js
deleted file mode 100644
index 302545f..0000000
--- a/test/lib/qunit-1.11.0.js
+++ /dev/null
@@ -1,2152 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-(function( window ) {
-
-var QUnit,
- assert,
- config,
- onErrorFnPrev,
- testId = 0,
- fileName = (sourceFromStacktrace( 0 ) || "" ).replace(/(:\d+)+\)?/, "").replace(/.+\//, ""),
- toString = Object.prototype.toString,
- hasOwn = Object.prototype.hasOwnProperty,
- // Keep a local reference to Date (GH-283)
- Date = window.Date,
- defined = {
- setTimeout: typeof window.setTimeout !== "undefined",
- sessionStorage: (function() {
- var x = "qunit-test-string";
- try {
- sessionStorage.setItem( x, x );
- sessionStorage.removeItem( x );
- return true;
- } catch( e ) {
- return false;
- }
- }())
- },
- /**
- * Provides a normalized error string, correcting an issue
- * with IE 7 (and prior) where Error.prototype.toString is
- * not properly implemented
- *
- * Based on http://es5.github.com/#x15.11.4.4
- *
- * @param {String|Error} error
- * @return {String} error message
- */
- errorString = function( error ) {
- var name, message,
- errorString = error.toString();
- if ( errorString.substring( 0, 7 ) === "[object" ) {
- name = error.name ? error.name.toString() : "Error";
- message = error.message ? error.message.toString() : "";
- if ( name && message ) {
- return name + ": " + message;
- } else if ( name ) {
- return name;
- } else if ( message ) {
- return message;
- } else {
- return "Error";
- }
- } else {
- return errorString;
- }
- },
- /**
- * Makes a clone of an object using only Array or Object as base,
- * and copies over the own enumerable properties.
- *
- * @param {Object} obj
- * @return {Object} New object with only the own properties (recursively).
- */
- objectValues = function( obj ) {
- // Grunt 0.3.x uses an older version of jshint that still has jshint/jshint#392.
- /*jshint newcap: false */
- var key, val,
- vals = QUnit.is( "array", obj ) ? [] : {};
- for ( key in obj ) {
- if ( hasOwn.call( obj, key ) ) {
- val = obj[key];
- vals[key] = val === Object(val) ? objectValues(val) : val;
- }
- }
- return vals;
- };
-
-function Test( settings ) {
- extend( this, settings );
- this.assertions = [];
- this.testNumber = ++Test.count;
-}
-
-Test.count = 0;
-
-Test.prototype = {
- init: function() {
- var a, b, li,
- tests = id( "qunit-tests" );
-
- if ( tests ) {
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml;
-
- // `a` initialized at top of scope
- a = document.createElement( "a" );
- a.innerHTML = "Rerun";
- a.href = QUnit.url({ testNumber: this.testNumber });
-
- li = document.createElement( "li" );
- li.appendChild( b );
- li.appendChild( a );
- li.className = "running";
- li.id = this.id = "qunit-test-output" + testId++;
-
- tests.appendChild( li );
- }
- },
- setup: function() {
- if ( this.module !== config.previousModule ) {
- if ( config.previousModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.previousModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
- config.previousModule = this.module;
- config.moduleStats = { all: 0, bad: 0 };
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- } else if ( config.autorun ) {
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- }
-
- config.current = this;
-
- this.testEnvironment = extend({
- setup: function() {},
- teardown: function() {}
- }, this.moduleTestEnvironment );
-
- this.started = +new Date();
- runLoggingCallbacks( "testStart", QUnit, {
- name: this.testName,
- module: this.module
- });
-
- // allow utility functions to access the current test environment
- // TODO why??
- QUnit.current_testEnvironment = this.testEnvironment;
-
- if ( !config.pollution ) {
- saveGlobal();
- }
- if ( config.notrycatch ) {
- this.testEnvironment.setup.call( this.testEnvironment );
- return;
- }
- try {
- this.testEnvironment.setup.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Setup failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- },
- run: function() {
- config.current = this;
-
- var running = id( "qunit-testresult" );
-
- if ( running ) {
- running.innerHTML = "Running:
" + this.nameHtml;
- }
-
- if ( this.async ) {
- QUnit.stop();
- }
-
- this.callbackStarted = +new Date();
-
- if ( config.notrycatch ) {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- return;
- }
-
- try {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- } catch( e ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
-
- QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + " " + this.stack + ": " + ( e.message || e ), extractStacktrace( e, 0 ) );
- // else next test will carry the responsibility
- saveGlobal();
-
- // Restart the tests if they're blocking
- if ( config.blocking ) {
- QUnit.start();
- }
- }
- },
- teardown: function() {
- config.current = this;
- if ( config.notrycatch ) {
- if ( typeof this.callbackRuntime === "undefined" ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
- }
- this.testEnvironment.teardown.call( this.testEnvironment );
- return;
- } else {
- try {
- this.testEnvironment.teardown.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Teardown failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- }
- checkPollution();
- },
- finish: function() {
- config.current = this;
- if ( config.requireExpects && this.expected === null ) {
- QUnit.pushFailure( "Expected number of assertions to be defined, but expect() was not called.", this.stack );
- } else if ( this.expected !== null && this.expected !== this.assertions.length ) {
- QUnit.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack );
- } else if ( this.expected === null && !this.assertions.length ) {
- QUnit.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions.", this.stack );
- }
-
- var i, assertion, a, b, time, li, ol,
- test = this,
- good = 0,
- bad = 0,
- tests = id( "qunit-tests" );
-
- this.runtime = +new Date() - this.started;
- config.stats.all += this.assertions.length;
- config.moduleStats.all += this.assertions.length;
-
- if ( tests ) {
- ol = document.createElement( "ol" );
- ol.className = "qunit-assert-list";
-
- for ( i = 0; i < this.assertions.length; i++ ) {
- assertion = this.assertions[i];
-
- li = document.createElement( "li" );
- li.className = assertion.result ? "pass" : "fail";
- li.innerHTML = assertion.message || ( assertion.result ? "okay" : "failed" );
- ol.appendChild( li );
-
- if ( assertion.result ) {
- good++;
- } else {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
-
- // store result when possible
- if ( QUnit.config.reorder && defined.sessionStorage ) {
- if ( bad ) {
- sessionStorage.setItem( "qunit-test-" + this.module + "-" + this.testName, bad );
- } else {
- sessionStorage.removeItem( "qunit-test-" + this.module + "-" + this.testName );
- }
- }
-
- if ( bad === 0 ) {
- addClass( ol, "qunit-collapsed" );
- }
-
- // `b` initialized at top of scope
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml + " (" + bad + ", " + good + ", " + this.assertions.length + ")";
-
- addEvent(b, "click", function() {
- var next = b.parentNode.lastChild,
- collapsed = hasClass( next, "qunit-collapsed" );
- ( collapsed ? removeClass : addClass )( next, "qunit-collapsed" );
- });
-
- addEvent(b, "dblclick", function( e ) {
- var target = e && e.target ? e.target : window.event.srcElement;
- if ( target.nodeName.toLowerCase() === "span" || target.nodeName.toLowerCase() === "b" ) {
- target = target.parentNode;
- }
- if ( window.location && target.nodeName.toLowerCase() === "strong" ) {
- window.location = QUnit.url({ testNumber: test.testNumber });
- }
- });
-
- // `time` initialized at top of scope
- time = document.createElement( "span" );
- time.className = "runtime";
- time.innerHTML = this.runtime + " ms";
-
- // `li` initialized at top of scope
- li = id( this.id );
- li.className = bad ? "fail" : "pass";
- li.removeChild( li.firstChild );
- a = li.firstChild;
- li.appendChild( b );
- li.appendChild( a );
- li.appendChild( time );
- li.appendChild( ol );
-
- } else {
- for ( i = 0; i < this.assertions.length; i++ ) {
- if ( !this.assertions[i].result ) {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
- }
-
- runLoggingCallbacks( "testDone", QUnit, {
- name: this.testName,
- module: this.module,
- failed: bad,
- passed: this.assertions.length - bad,
- total: this.assertions.length,
- duration: this.runtime
- });
-
- QUnit.reset();
-
- config.current = undefined;
- },
-
- queue: function() {
- var bad,
- test = this;
-
- synchronize(function() {
- test.init();
- });
- function run() {
- // each of these can by async
- synchronize(function() {
- test.setup();
- });
- synchronize(function() {
- test.run();
- });
- synchronize(function() {
- test.teardown();
- });
- synchronize(function() {
- test.finish();
- });
- }
-
- // `bad` initialized at top of scope
- // defer when previous test run passed, if storage is available
- bad = QUnit.config.reorder && defined.sessionStorage &&
- +sessionStorage.getItem( "qunit-test-" + this.module + "-" + this.testName );
-
- if ( bad ) {
- run();
- } else {
- synchronize( run, true );
- }
- }
-};
-
-// Root QUnit object.
-// `QUnit` initialized at top of scope
-QUnit = {
-
- // call on start of module test to prepend name to all tests
- module: function( name, testEnvironment ) {
- config.currentModule = name;
- config.currentModuleTestEnvironment = testEnvironment;
- config.modules[name] = true;
- },
-
- asyncTest: function( testName, expected, callback ) {
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- QUnit.test( testName, expected, callback, true );
- },
-
- test: function( testName, expected, callback, async ) {
- var test,
- nameHtml = "" + escapeText( testName ) + "";
-
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- if ( config.currentModule ) {
- nameHtml = "" + escapeText( config.currentModule ) + ": " + nameHtml;
- }
-
- test = new Test({
- nameHtml: nameHtml,
- testName: testName,
- expected: expected,
- async: async,
- callback: callback,
- module: config.currentModule,
- moduleTestEnvironment: config.currentModuleTestEnvironment,
- stack: sourceFromStacktrace( 2 )
- });
-
- if ( !validTest( test ) ) {
- return;
- }
-
- test.queue();
- },
-
- // Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through.
- expect: function( asserts ) {
- if (arguments.length === 1) {
- config.current.expected = asserts;
- } else {
- return config.current.expected;
- }
- },
-
- start: function( count ) {
- // QUnit hasn't been initialized yet.
- // Note: RequireJS (et al) may delay onLoad
- if ( config.semaphore === undefined ) {
- QUnit.begin(function() {
- // This is triggered at the top of QUnit.load, push start() to the event loop, to allow QUnit.load to finish first
- setTimeout(function() {
- QUnit.start( count );
- });
- });
- return;
- }
-
- config.semaphore -= count || 1;
- // don't start until equal number of stop-calls
- if ( config.semaphore > 0 ) {
- return;
- }
- // ignore if start is called more often then stop
- if ( config.semaphore < 0 ) {
- config.semaphore = 0;
- QUnit.pushFailure( "Called start() while already started (QUnit.config.semaphore was 0 already)", null, sourceFromStacktrace(2) );
- return;
- }
- // A slight delay, to avoid any current callbacks
- if ( defined.setTimeout ) {
- window.setTimeout(function() {
- if ( config.semaphore > 0 ) {
- return;
- }
- if ( config.timeout ) {
- clearTimeout( config.timeout );
- }
-
- config.blocking = false;
- process( true );
- }, 13);
- } else {
- config.blocking = false;
- process( true );
- }
- },
-
- stop: function( count ) {
- config.semaphore += count || 1;
- config.blocking = true;
-
- if ( config.testTimeout && defined.setTimeout ) {
- clearTimeout( config.timeout );
- config.timeout = window.setTimeout(function() {
- QUnit.ok( false, "Test timed out" );
- config.semaphore = 1;
- QUnit.start();
- }, config.testTimeout );
- }
- }
-};
-
-// `assert` initialized at top of scope
-// Asssert helpers
-// All of these must either call QUnit.push() or manually do:
-// - runLoggingCallbacks( "log", .. );
-// - config.current.assertions.push({ .. });
-// We attach it to the QUnit object *after* we expose the public API,
-// otherwise `assert` will become a global variable in browsers (#341).
-assert = {
- /**
- * Asserts rough true-ish result.
- * @name ok
- * @function
- * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" );
- */
- ok: function( result, msg ) {
- if ( !config.current ) {
- throw new Error( "ok() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
- result = !!result;
-
- var source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: msg
- };
-
- msg = escapeText( msg || (result ? "okay" : "failed" ) );
- msg = "" + msg + "";
-
- if ( !result ) {
- source = sourceFromStacktrace( 2 );
- if ( source ) {
- details.source = source;
- msg += "Source: | " + escapeText( source ) + " |
---|
";
- }
- }
- runLoggingCallbacks( "log", QUnit, details );
- config.current.assertions.push({
- result: result,
- message: msg
- });
- },
-
- /**
- * Assert that the first two arguments are equal, with an optional message.
- * Prints out both actual and expected values.
- * @name equal
- * @function
- * @example equal( format( "Received {0} bytes.", 2), "Received 2 bytes.", "format() replaces {0} with next argument" );
- */
- equal: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected == actual, actual, expected, message );
- },
-
- /**
- * @name notEqual
- * @function
- */
- notEqual: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected != actual, actual, expected, message );
- },
-
- /**
- * @name propEqual
- * @function
- */
- propEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notPropEqual
- * @function
- */
- notPropEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name deepEqual
- * @function
- */
- deepEqual: function( actual, expected, message ) {
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notDeepEqual
- * @function
- */
- notDeepEqual: function( actual, expected, message ) {
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name strictEqual
- * @function
- */
- strictEqual: function( actual, expected, message ) {
- QUnit.push( expected === actual, actual, expected, message );
- },
-
- /**
- * @name notStrictEqual
- * @function
- */
- notStrictEqual: function( actual, expected, message ) {
- QUnit.push( expected !== actual, actual, expected, message );
- },
-
- "throws": function( block, expected, message ) {
- var actual,
- expectedOutput = expected,
- ok = false;
-
- // 'expected' is optional
- if ( typeof expected === "string" ) {
- message = expected;
- expected = null;
- }
-
- config.current.ignoreGlobalErrors = true;
- try {
- block.call( config.current.testEnvironment );
- } catch (e) {
- actual = e;
- }
- config.current.ignoreGlobalErrors = false;
-
- if ( actual ) {
- // we don't want to validate thrown error
- if ( !expected ) {
- ok = true;
- expectedOutput = null;
- // expected is a regexp
- } else if ( QUnit.objectType( expected ) === "regexp" ) {
- ok = expected.test( errorString( actual ) );
- // expected is a constructor
- } else if ( actual instanceof expected ) {
- ok = true;
- // expected is a validation function which returns true is validation passed
- } else if ( expected.call( {}, actual ) === true ) {
- expectedOutput = null;
- ok = true;
- }
-
- QUnit.push( ok, actual, expectedOutput, message );
- } else {
- QUnit.pushFailure( message, null, 'No exception was thrown.' );
- }
- }
-};
-
-/**
- * @deprecate since 1.8.0
- * Kept assertion helpers in root for backwards compatibility.
- */
-extend( QUnit, assert );
-
-/**
- * @deprecated since 1.9.0
- * Kept root "raises()" for backwards compatibility.
- * (Note that we don't introduce assert.raises).
- */
-QUnit.raises = assert[ "throws" ];
-
-/**
- * @deprecated since 1.0.0, replaced with error pushes since 1.3.0
- * Kept to avoid TypeErrors for undefined methods.
- */
-QUnit.equals = function() {
- QUnit.push( false, false, false, "QUnit.equals has been deprecated since 2009 (e88049a0), use QUnit.equal instead" );
-};
-QUnit.same = function() {
- QUnit.push( false, false, false, "QUnit.same has been deprecated since 2009 (e88049a0), use QUnit.deepEqual instead" );
-};
-
-// We want access to the constructor's prototype
-(function() {
- function F() {}
- F.prototype = QUnit;
- QUnit = new F();
- // Make F QUnit's constructor so that we can add to the prototype later
- QUnit.constructor = F;
-}());
-
-/**
- * Config object: Maintain internal state
- * Later exposed as QUnit.config
- * `config` initialized at top of scope
- */
-config = {
- // The queue of tests to run
- queue: [],
-
- // block until document ready
- blocking: true,
-
- // when enabled, show only failing tests
- // gets persisted through sessionStorage and can be changed in UI via checkbox
- hidepassed: false,
-
- // by default, run previously failed tests first
- // very useful in combination with "Hide passed tests" checked
- reorder: true,
-
- // by default, modify document.title when suite is done
- altertitle: true,
-
- // when enabled, all tests must call expect()
- requireExpects: false,
-
- // add checkboxes that are persisted in the query-string
- // when enabled, the id is set to `true` as a `QUnit.config` property
- urlConfig: [
- {
- id: "noglobals",
- label: "Check for Globals",
- tooltip: "Enabling this will test if any test introduces new properties on the `window` object. Stored as query-strings."
- },
- {
- id: "notrycatch",
- label: "No try-catch",
- tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging exceptions in IE reasonable. Stored as query-strings."
- }
- ],
-
- // Set of all modules.
- modules: {},
-
- // logging callback queues
- begin: [],
- done: [],
- log: [],
- testStart: [],
- testDone: [],
- moduleStart: [],
- moduleDone: []
-};
-
-// Export global variables, unless an 'exports' object exists,
-// in that case we assume we're in CommonJS (dealt with on the bottom of the script)
-if ( typeof exports === "undefined" ) {
- extend( window, QUnit );
-
- // Expose QUnit object
- window.QUnit = QUnit;
-}
-
-// Initialize more QUnit.config and QUnit.urlParams
-(function() {
- var i,
- location = window.location || { search: "", protocol: "file:" },
- params = location.search.slice( 1 ).split( "&" ),
- length = params.length,
- urlParams = {},
- current;
-
- if ( params[ 0 ] ) {
- for ( i = 0; i < length; i++ ) {
- current = params[ i ].split( "=" );
- current[ 0 ] = decodeURIComponent( current[ 0 ] );
- // allow just a key to turn on a flag, e.g., test.html?noglobals
- current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true;
- urlParams[ current[ 0 ] ] = current[ 1 ];
- }
- }
-
- QUnit.urlParams = urlParams;
-
- // String search anywhere in moduleName+testName
- config.filter = urlParams.filter;
-
- // Exact match of the module name
- config.module = urlParams.module;
-
- config.testNumber = parseInt( urlParams.testNumber, 10 ) || null;
-
- // Figure out if we're running the tests from a server or not
- QUnit.isLocal = location.protocol === "file:";
-}());
-
-// Extend QUnit object,
-// these after set here because they should not be exposed as global functions
-extend( QUnit, {
- assert: assert,
-
- config: config,
-
- // Initialize the configuration options
- init: function() {
- extend( config, {
- stats: { all: 0, bad: 0 },
- moduleStats: { all: 0, bad: 0 },
- started: +new Date(),
- updateRate: 1000,
- blocking: false,
- autostart: true,
- autorun: false,
- filter: "",
- queue: [],
- semaphore: 1
- });
-
- var tests, banner, result,
- qunit = id( "qunit" );
-
- if ( qunit ) {
- qunit.innerHTML =
- "" +
- "" +
- "" +
- "" +
- "
";
- }
-
- tests = id( "qunit-tests" );
- banner = id( "qunit-banner" );
- result = id( "qunit-testresult" );
-
- if ( tests ) {
- tests.innerHTML = "";
- }
-
- if ( banner ) {
- banner.className = "";
- }
-
- if ( result ) {
- result.parentNode.removeChild( result );
- }
-
- if ( tests ) {
- result = document.createElement( "p" );
- result.id = "qunit-testresult";
- result.className = "result";
- tests.parentNode.insertBefore( result, tests );
- result.innerHTML = "Running...
";
- }
- },
-
- // Resets the test setup. Useful for tests that modify the DOM.
- reset: function() {
- var fixture = id( "qunit-fixture" );
- if ( fixture ) {
- fixture.innerHTML = config.fixture;
- }
- },
-
- // Trigger an event on an element.
- // @example triggerEvent( document.body, "click" );
- triggerEvent: function( elem, type, event ) {
- if ( document.createEvent ) {
- event = document.createEvent( "MouseEvents" );
- event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView,
- 0, 0, 0, 0, 0, false, false, false, false, 0, null);
-
- elem.dispatchEvent( event );
- } else if ( elem.fireEvent ) {
- elem.fireEvent( "on" + type );
- }
- },
-
- // Safe object type checking
- is: function( type, obj ) {
- return QUnit.objectType( obj ) === type;
- },
-
- objectType: function( obj ) {
- if ( typeof obj === "undefined" ) {
- return "undefined";
- // consider: typeof null === object
- }
- if ( obj === null ) {
- return "null";
- }
-
- var match = toString.call( obj ).match(/^\[object\s(.*)\]$/),
- type = match && match[1] || "";
-
- switch ( type ) {
- case "Number":
- if ( isNaN(obj) ) {
- return "nan";
- }
- return "number";
- case "String":
- case "Boolean":
- case "Array":
- case "Date":
- case "RegExp":
- case "Function":
- return type.toLowerCase();
- }
- if ( typeof obj === "object" ) {
- return "object";
- }
- return undefined;
- },
-
- push: function( result, actual, expected, message ) {
- if ( !config.current ) {
- throw new Error( "assertion outside test context, was " + sourceFromStacktrace() );
- }
-
- var output, source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: message,
- actual: actual,
- expected: expected
- };
-
- message = escapeText( message ) || ( result ? "okay" : "failed" );
- message = "" + message + "";
- output = message;
-
- if ( !result ) {
- expected = escapeText( QUnit.jsDump.parse(expected) );
- actual = escapeText( QUnit.jsDump.parse(actual) );
- output += "Expected: | " + expected + " |
";
-
- if ( actual !== expected ) {
- output += "Result: | " + actual + " |
";
- output += "Diff: | " + QUnit.diff( expected, actual ) + " |
";
- }
-
- source = sourceFromStacktrace();
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
- }
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: !!result,
- message: output
- });
- },
-
- pushFailure: function( message, source, actual ) {
- if ( !config.current ) {
- throw new Error( "pushFailure() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
-
- var output,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: false,
- message: message
- };
-
- message = escapeText( message ) || "error";
- message = "" + message + "";
- output = message;
-
- output += "";
-
- if ( actual ) {
- output += "Result: | " + escapeText( actual ) + " |
";
- }
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: false,
- message: output
- });
- },
-
- url: function( params ) {
- params = extend( extend( {}, QUnit.urlParams ), params );
- var key,
- querystring = "?";
-
- for ( key in params ) {
- if ( !hasOwn.call( params, key ) ) {
- continue;
- }
- querystring += encodeURIComponent( key ) + "=" +
- encodeURIComponent( params[ key ] ) + "&";
- }
- return window.location.protocol + "//" + window.location.host +
- window.location.pathname + querystring.slice( 0, -1 );
- },
-
- extend: extend,
- id: id,
- addEvent: addEvent
- // load, equiv, jsDump, diff: Attached later
-});
-
-/**
- * @deprecated: Created for backwards compatibility with test runner that set the hook function
- * into QUnit.{hook}, instead of invoking it and passing the hook function.
- * QUnit.constructor is set to the empty F() above so that we can add to it's prototype here.
- * Doing this allows us to tell if the following methods have been overwritten on the actual
- * QUnit object.
- */
-extend( QUnit.constructor.prototype, {
-
- // Logging callbacks; all receive a single argument with the listed properties
- // run test/logs.html for any related changes
- begin: registerLoggingCallback( "begin" ),
-
- // done: { failed, passed, total, runtime }
- done: registerLoggingCallback( "done" ),
-
- // log: { result, actual, expected, message }
- log: registerLoggingCallback( "log" ),
-
- // testStart: { name }
- testStart: registerLoggingCallback( "testStart" ),
-
- // testDone: { name, failed, passed, total, duration }
- testDone: registerLoggingCallback( "testDone" ),
-
- // moduleStart: { name }
- moduleStart: registerLoggingCallback( "moduleStart" ),
-
- // moduleDone: { name, failed, passed, total }
- moduleDone: registerLoggingCallback( "moduleDone" )
-});
-
-if ( typeof document === "undefined" || document.readyState === "complete" ) {
- config.autorun = true;
-}
-
-QUnit.load = function() {
- runLoggingCallbacks( "begin", QUnit, {} );
-
- // Initialize the config, saving the execution queue
- var banner, filter, i, label, len, main, ol, toolbar, userAgent, val,
- urlConfigCheckboxesContainer, urlConfigCheckboxes, moduleFilter,
- numModules = 0,
- moduleFilterHtml = "",
- urlConfigHtml = "",
- oldconfig = extend( {}, config );
-
- QUnit.init();
- extend(config, oldconfig);
-
- config.blocking = false;
-
- len = config.urlConfig.length;
-
- for ( i = 0; i < len; i++ ) {
- val = config.urlConfig[i];
- if ( typeof val === "string" ) {
- val = {
- id: val,
- label: val,
- tooltip: "[no tooltip available]"
- };
- }
- config[ val.id ] = QUnit.urlParams[ val.id ];
- urlConfigHtml += "";
- }
-
- moduleFilterHtml += "";
-
- // `userAgent` initialized at top of scope
- userAgent = id( "qunit-userAgent" );
- if ( userAgent ) {
- userAgent.innerHTML = navigator.userAgent;
- }
-
- // `banner` initialized at top of scope
- banner = id( "qunit-header" );
- if ( banner ) {
- banner.innerHTML = "" + banner.innerHTML + " ";
- }
-
- // `toolbar` initialized at top of scope
- toolbar = id( "qunit-testrunner-toolbar" );
- if ( toolbar ) {
- // `filter` initialized at top of scope
- filter = document.createElement( "input" );
- filter.type = "checkbox";
- filter.id = "qunit-filter-pass";
-
- addEvent( filter, "click", function() {
- var tmp,
- ol = document.getElementById( "qunit-tests" );
-
- if ( filter.checked ) {
- ol.className = ol.className + " hidepass";
- } else {
- tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " ";
- ol.className = tmp.replace( / hidepass /, " " );
- }
- if ( defined.sessionStorage ) {
- if (filter.checked) {
- sessionStorage.setItem( "qunit-filter-passed-tests", "true" );
- } else {
- sessionStorage.removeItem( "qunit-filter-passed-tests" );
- }
- }
- });
-
- if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem( "qunit-filter-passed-tests" ) ) {
- filter.checked = true;
- // `ol` initialized at top of scope
- ol = document.getElementById( "qunit-tests" );
- ol.className = ol.className + " hidepass";
- }
- toolbar.appendChild( filter );
-
- // `label` initialized at top of scope
- label = document.createElement( "label" );
- label.setAttribute( "for", "qunit-filter-pass" );
- label.setAttribute( "title", "Only show tests and assertons that fail. Stored in sessionStorage." );
- label.innerHTML = "Hide passed tests";
- toolbar.appendChild( label );
-
- urlConfigCheckboxesContainer = document.createElement("span");
- urlConfigCheckboxesContainer.innerHTML = urlConfigHtml;
- urlConfigCheckboxes = urlConfigCheckboxesContainer.getElementsByTagName("input");
- // For oldIE support:
- // * Add handlers to the individual elements instead of the container
- // * Use "click" instead of "change"
- // * Fallback from event.target to event.srcElement
- addEvents( urlConfigCheckboxes, "click", function( event ) {
- var params = {},
- target = event.target || event.srcElement;
- params[ target.name ] = target.checked ? true : undefined;
- window.location = QUnit.url( params );
- });
- toolbar.appendChild( urlConfigCheckboxesContainer );
-
- if (numModules > 1) {
- moduleFilter = document.createElement( 'span' );
- moduleFilter.setAttribute( 'id', 'qunit-modulefilter-container' );
- moduleFilter.innerHTML = moduleFilterHtml;
- addEvent( moduleFilter.lastChild, "change", function() {
- var selectBox = moduleFilter.getElementsByTagName("select")[0],
- selectedModule = decodeURIComponent(selectBox.options[selectBox.selectedIndex].value);
-
- window.location = QUnit.url( { module: ( selectedModule === "" ) ? undefined : selectedModule } );
- });
- toolbar.appendChild(moduleFilter);
- }
- }
-
- // `main` initialized at top of scope
- main = id( "qunit-fixture" );
- if ( main ) {
- config.fixture = main.innerHTML;
- }
-
- if ( config.autostart ) {
- QUnit.start();
- }
-};
-
-addEvent( window, "load", QUnit.load );
-
-// `onErrorFnPrev` initialized at top of scope
-// Preserve other handlers
-onErrorFnPrev = window.onerror;
-
-// Cover uncaught exceptions
-// Returning true will surpress the default browser handler,
-// returning false will let it run.
-window.onerror = function ( error, filePath, linerNr ) {
- var ret = false;
- if ( onErrorFnPrev ) {
- ret = onErrorFnPrev( error, filePath, linerNr );
- }
-
- // Treat return value as window.onerror itself does,
- // Only do our handling if not surpressed.
- if ( ret !== true ) {
- if ( QUnit.config.current ) {
- if ( QUnit.config.current.ignoreGlobalErrors ) {
- return true;
- }
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- } else {
- QUnit.test( "global failure", extend( function() {
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- }, { validTest: validTest } ) );
- }
- return false;
- }
-
- return ret;
-};
-
-function done() {
- config.autorun = true;
-
- // Log the last module results
- if ( config.currentModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.currentModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
-
- var i, key,
- banner = id( "qunit-banner" ),
- tests = id( "qunit-tests" ),
- runtime = +new Date() - config.started,
- passed = config.stats.all - config.stats.bad,
- html = [
- "Tests completed in ",
- runtime,
- " milliseconds.
",
- "",
- passed,
- " assertions of ",
- config.stats.all,
- " passed, ",
- config.stats.bad,
- " failed."
- ].join( "" );
-
- if ( banner ) {
- banner.className = ( config.stats.bad ? "qunit-fail" : "qunit-pass" );
- }
-
- if ( tests ) {
- id( "qunit-testresult" ).innerHTML = html;
- }
-
- if ( config.altertitle && typeof document !== "undefined" && document.title ) {
- // show ✖ for good, ✔ for bad suite result in title
- // use escape sequences in case file gets loaded with non-utf-8-charset
- document.title = [
- ( config.stats.bad ? "\u2716" : "\u2714" ),
- document.title.replace( /^[\u2714\u2716] /i, "" )
- ].join( " " );
- }
-
- // clear own sessionStorage items if all tests passed
- if ( config.reorder && defined.sessionStorage && config.stats.bad === 0 ) {
- // `key` & `i` initialized at top of scope
- for ( i = 0; i < sessionStorage.length; i++ ) {
- key = sessionStorage.key( i++ );
- if ( key.indexOf( "qunit-test-" ) === 0 ) {
- sessionStorage.removeItem( key );
- }
- }
- }
-
- // scroll back to top to show results
- if ( window.scrollTo ) {
- window.scrollTo(0, 0);
- }
-
- runLoggingCallbacks( "done", QUnit, {
- failed: config.stats.bad,
- passed: passed,
- total: config.stats.all,
- runtime: runtime
- });
-}
-
-/** @return Boolean: true if this test should be ran */
-function validTest( test ) {
- var include,
- filter = config.filter && config.filter.toLowerCase(),
- module = config.module && config.module.toLowerCase(),
- fullName = (test.module + ": " + test.testName).toLowerCase();
-
- // Internally-generated tests are always valid
- if ( test.callback && test.callback.validTest === validTest ) {
- delete test.callback.validTest;
- return true;
- }
-
- if ( config.testNumber ) {
- return test.testNumber === config.testNumber;
- }
-
- if ( module && ( !test.module || test.module.toLowerCase() !== module ) ) {
- return false;
- }
-
- if ( !filter ) {
- return true;
- }
-
- include = filter.charAt( 0 ) !== "!";
- if ( !include ) {
- filter = filter.slice( 1 );
- }
-
- // If the filter matches, we need to honour include
- if ( fullName.indexOf( filter ) !== -1 ) {
- return include;
- }
-
- // Otherwise, do the opposite
- return !include;
-}
-
-// so far supports only Firefox, Chrome and Opera (buggy), Safari (for real exceptions)
-// Later Safari and IE10 are supposed to support error.stack as well
-// See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack
-function extractStacktrace( e, offset ) {
- offset = offset === undefined ? 3 : offset;
-
- var stack, include, i;
-
- if ( e.stacktrace ) {
- // Opera
- return e.stacktrace.split( "\n" )[ offset + 3 ];
- } else if ( e.stack ) {
- // Firefox, Chrome
- stack = e.stack.split( "\n" );
- if (/^error$/i.test( stack[0] ) ) {
- stack.shift();
- }
- if ( fileName ) {
- include = [];
- for ( i = offset; i < stack.length; i++ ) {
- if ( stack[ i ].indexOf( fileName ) !== -1 ) {
- break;
- }
- include.push( stack[ i ] );
- }
- if ( include.length ) {
- return include.join( "\n" );
- }
- }
- return stack[ offset ];
- } else if ( e.sourceURL ) {
- // Safari, PhantomJS
- // hopefully one day Safari provides actual stacktraces
- // exclude useless self-reference for generated Error objects
- if ( /qunit.js$/.test( e.sourceURL ) ) {
- return;
- }
- // for actual exceptions, this is useful
- return e.sourceURL + ":" + e.line;
- }
-}
-function sourceFromStacktrace( offset ) {
- try {
- throw new Error();
- } catch ( e ) {
- return extractStacktrace( e, offset );
- }
-}
-
-/**
- * Escape text for attribute or text content.
- */
-function escapeText( s ) {
- if ( !s ) {
- return "";
- }
- s = s + "";
- // Both single quotes and double quotes (for attributes)
- return s.replace( /['"<>&]/g, function( s ) {
- switch( s ) {
- case '\'':
- return ''';
- case '"':
- return '"';
- case '<':
- return '<';
- case '>':
- return '>';
- case '&':
- return '&';
- }
- });
-}
-
-function synchronize( callback, last ) {
- config.queue.push( callback );
-
- if ( config.autorun && !config.blocking ) {
- process( last );
- }
-}
-
-function process( last ) {
- function next() {
- process( last );
- }
- var start = new Date().getTime();
- config.depth = config.depth ? config.depth + 1 : 1;
-
- while ( config.queue.length && !config.blocking ) {
- if ( !defined.setTimeout || config.updateRate <= 0 || ( ( new Date().getTime() - start ) < config.updateRate ) ) {
- config.queue.shift()();
- } else {
- window.setTimeout( next, 13 );
- break;
- }
- }
- config.depth--;
- if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) {
- done();
- }
-}
-
-function saveGlobal() {
- config.pollution = [];
-
- if ( config.noglobals ) {
- for ( var key in window ) {
- // in Opera sometimes DOM element ids show up here, ignore them
- if ( !hasOwn.call( window, key ) || /^qunit-test-output/.test( key ) ) {
- continue;
- }
- config.pollution.push( key );
- }
- }
-}
-
-function checkPollution() {
- var newGlobals,
- deletedGlobals,
- old = config.pollution;
-
- saveGlobal();
-
- newGlobals = diff( config.pollution, old );
- if ( newGlobals.length > 0 ) {
- QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join(", ") );
- }
-
- deletedGlobals = diff( old, config.pollution );
- if ( deletedGlobals.length > 0 ) {
- QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join(", ") );
- }
-}
-
-// returns a new Array with the elements that are in a but not in b
-function diff( a, b ) {
- var i, j,
- result = a.slice();
-
- for ( i = 0; i < result.length; i++ ) {
- for ( j = 0; j < b.length; j++ ) {
- if ( result[i] === b[j] ) {
- result.splice( i, 1 );
- i--;
- break;
- }
- }
- }
- return result;
-}
-
-function extend( a, b ) {
- for ( var prop in b ) {
- if ( b[ prop ] === undefined ) {
- delete a[ prop ];
-
- // Avoid "Member not found" error in IE8 caused by setting window.constructor
- } else if ( prop !== "constructor" || a !== window ) {
- a[ prop ] = b[ prop ];
- }
- }
-
- return a;
-}
-
-/**
- * @param {HTMLElement} elem
- * @param {string} type
- * @param {Function} fn
- */
-function addEvent( elem, type, fn ) {
- // Standards-based browsers
- if ( elem.addEventListener ) {
- elem.addEventListener( type, fn, false );
- // IE
- } else {
- elem.attachEvent( "on" + type, fn );
- }
-}
-
-/**
- * @param {Array|NodeList} elems
- * @param {string} type
- * @param {Function} fn
- */
-function addEvents( elems, type, fn ) {
- var i = elems.length;
- while ( i-- ) {
- addEvent( elems[i], type, fn );
- }
-}
-
-function hasClass( elem, name ) {
- return (" " + elem.className + " ").indexOf(" " + name + " ") > -1;
-}
-
-function addClass( elem, name ) {
- if ( !hasClass( elem, name ) ) {
- elem.className += (elem.className ? " " : "") + name;
- }
-}
-
-function removeClass( elem, name ) {
- var set = " " + elem.className + " ";
- // Class name may appear multiple times
- while ( set.indexOf(" " + name + " ") > -1 ) {
- set = set.replace(" " + name + " " , " ");
- }
- // If possible, trim it for prettiness, but not neccecarily
- elem.className = window.jQuery ? jQuery.trim( set ) : ( set.trim ? set.trim() : set );
-}
-
-function id( name ) {
- return !!( typeof document !== "undefined" && document && document.getElementById ) &&
- document.getElementById( name );
-}
-
-function registerLoggingCallback( key ) {
- return function( callback ) {
- config[key].push( callback );
- };
-}
-
-// Supports deprecated method of completely overwriting logging callbacks
-function runLoggingCallbacks( key, scope, args ) {
- var i, callbacks;
- if ( QUnit.hasOwnProperty( key ) ) {
- QUnit[ key ].call(scope, args );
- } else {
- callbacks = config[ key ];
- for ( i = 0; i < callbacks.length; i++ ) {
- callbacks[ i ].call( scope, args );
- }
- }
-}
-
-// Test for equality any JavaScript type.
-// Author: Philippe Rathé
-QUnit.equiv = (function() {
-
- // Call the o related callback with the given arguments.
- function bindCallbacks( o, callbacks, args ) {
- var prop = QUnit.objectType( o );
- if ( prop ) {
- if ( QUnit.objectType( callbacks[ prop ] ) === "function" ) {
- return callbacks[ prop ].apply( callbacks, args );
- } else {
- return callbacks[ prop ]; // or undefined
- }
- }
- }
-
- // the real equiv function
- var innerEquiv,
- // stack to decide between skip/abort functions
- callers = [],
- // stack to avoiding loops from circular referencing
- parents = [],
-
- getProto = Object.getPrototypeOf || function ( obj ) {
- return obj.__proto__;
- },
- callbacks = (function () {
-
- // for string, boolean, number and null
- function useStrictEquality( b, a ) {
- /*jshint eqeqeq:false */
- if ( b instanceof a.constructor || a instanceof b.constructor ) {
- // to catch short annotaion VS 'new' annotation of a
- // declaration
- // e.g. var i = 1;
- // var j = new Number(1);
- return a == b;
- } else {
- return a === b;
- }
- }
-
- return {
- "string": useStrictEquality,
- "boolean": useStrictEquality,
- "number": useStrictEquality,
- "null": useStrictEquality,
- "undefined": useStrictEquality,
-
- "nan": function( b ) {
- return isNaN( b );
- },
-
- "date": function( b, a ) {
- return QUnit.objectType( b ) === "date" && a.valueOf() === b.valueOf();
- },
-
- "regexp": function( b, a ) {
- return QUnit.objectType( b ) === "regexp" &&
- // the regex itself
- a.source === b.source &&
- // and its modifers
- a.global === b.global &&
- // (gmi) ...
- a.ignoreCase === b.ignoreCase &&
- a.multiline === b.multiline &&
- a.sticky === b.sticky;
- },
-
- // - skip when the property is a method of an instance (OOP)
- // - abort otherwise,
- // initial === would have catch identical references anyway
- "function": function() {
- var caller = callers[callers.length - 1];
- return caller !== Object && typeof caller !== "undefined";
- },
-
- "array": function( b, a ) {
- var i, j, len, loop;
-
- // b could be an object literal here
- if ( QUnit.objectType( b ) !== "array" ) {
- return false;
- }
-
- len = a.length;
- if ( len !== b.length ) {
- // safe and faster
- return false;
- }
-
- // track reference to avoid circular references
- parents.push( a );
- for ( i = 0; i < len; i++ ) {
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- loop = true;// dont rewalk array
- }
- }
- if ( !loop && !innerEquiv(a[i], b[i]) ) {
- parents.pop();
- return false;
- }
- }
- parents.pop();
- return true;
- },
-
- "object": function( b, a ) {
- var i, j, loop,
- // Default to true
- eq = true,
- aProperties = [],
- bProperties = [];
-
- // comparing constructors is more strict than using
- // instanceof
- if ( a.constructor !== b.constructor ) {
- // Allow objects with no prototype to be equivalent to
- // objects with Object as their constructor.
- if ( !(( getProto(a) === null && getProto(b) === Object.prototype ) ||
- ( getProto(b) === null && getProto(a) === Object.prototype ) ) ) {
- return false;
- }
- }
-
- // stack constructor before traversing properties
- callers.push( a.constructor );
- // track reference to avoid circular references
- parents.push( a );
-
- for ( i in a ) { // be strict: don't ensures hasOwnProperty
- // and go deep
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- // don't go down the same path twice
- loop = true;
- }
- }
- aProperties.push(i); // collect a's properties
-
- if (!loop && !innerEquiv( a[i], b[i] ) ) {
- eq = false;
- break;
- }
- }
-
- callers.pop(); // unstack, we are done
- parents.pop();
-
- for ( i in b ) {
- bProperties.push( i ); // collect b's properties
- }
-
- // Ensures identical properties name
- return eq && innerEquiv( aProperties.sort(), bProperties.sort() );
- }
- };
- }());
-
- innerEquiv = function() { // can take multiple arguments
- var args = [].slice.apply( arguments );
- if ( args.length < 2 ) {
- return true; // end transition
- }
-
- return (function( a, b ) {
- if ( a === b ) {
- return true; // catch the most you can
- } else if ( a === null || b === null || typeof a === "undefined" ||
- typeof b === "undefined" ||
- QUnit.objectType(a) !== QUnit.objectType(b) ) {
- return false; // don't lose time with error prone cases
- } else {
- return bindCallbacks(a, callbacks, [ b, a ]);
- }
-
- // apply transition with (1..n) arguments
- }( args[0], args[1] ) && arguments.callee.apply( this, args.splice(1, args.length - 1 )) );
- };
-
- return innerEquiv;
-}());
-
-/**
- * jsDump Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com |
- * http://flesler.blogspot.com Licensed under BSD
- * (http://www.opensource.org/licenses/bsd-license.php) Date: 5/15/2008
- *
- * @projectDescription Advanced and extensible data dumping for Javascript.
- * @version 1.0.0
- * @author Ariel Flesler
- * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html}
- */
-QUnit.jsDump = (function() {
- function quote( str ) {
- return '"' + str.toString().replace( /"/g, '\\"' ) + '"';
- }
- function literal( o ) {
- return o + "";
- }
- function join( pre, arr, post ) {
- var s = jsDump.separator(),
- base = jsDump.indent(),
- inner = jsDump.indent(1);
- if ( arr.join ) {
- arr = arr.join( "," + s + inner );
- }
- if ( !arr ) {
- return pre + post;
- }
- return [ pre, inner + arr, base + post ].join(s);
- }
- function array( arr, stack ) {
- var i = arr.length, ret = new Array(i);
- this.up();
- while ( i-- ) {
- ret[i] = this.parse( arr[i] , undefined , stack);
- }
- this.down();
- return join( "[", ret, "]" );
- }
-
- var reName = /^function (\w+)/,
- jsDump = {
- // type is used mostly internally, you can fix a (custom)type in advance
- parse: function( obj, type, stack ) {
- stack = stack || [ ];
- var inStack, res,
- parser = this.parsers[ type || this.typeOf(obj) ];
-
- type = typeof parser;
- inStack = inArray( obj, stack );
-
- if ( inStack !== -1 ) {
- return "recursion(" + (inStack - stack.length) + ")";
- }
- if ( type === "function" ) {
- stack.push( obj );
- res = parser.call( this, obj, stack );
- stack.pop();
- return res;
- }
- return ( type === "string" ) ? parser : this.parsers.error;
- },
- typeOf: function( obj ) {
- var type;
- if ( obj === null ) {
- type = "null";
- } else if ( typeof obj === "undefined" ) {
- type = "undefined";
- } else if ( QUnit.is( "regexp", obj) ) {
- type = "regexp";
- } else if ( QUnit.is( "date", obj) ) {
- type = "date";
- } else if ( QUnit.is( "function", obj) ) {
- type = "function";
- } else if ( typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined" ) {
- type = "window";
- } else if ( obj.nodeType === 9 ) {
- type = "document";
- } else if ( obj.nodeType ) {
- type = "node";
- } else if (
- // native arrays
- toString.call( obj ) === "[object Array]" ||
- // NodeList objects
- ( typeof obj.length === "number" && typeof obj.item !== "undefined" && ( obj.length ? obj.item(0) === obj[0] : ( obj.item( 0 ) === null && typeof obj[0] === "undefined" ) ) )
- ) {
- type = "array";
- } else if ( obj.constructor === Error.prototype.constructor ) {
- type = "error";
- } else {
- type = typeof obj;
- }
- return type;
- },
- separator: function() {
- return this.multiline ? this.HTML ? "
" : "\n" : this.HTML ? " " : " ";
- },
- // extra can be a number, shortcut for increasing-calling-decreasing
- indent: function( extra ) {
- if ( !this.multiline ) {
- return "";
- }
- var chr = this.indentChar;
- if ( this.HTML ) {
- chr = chr.replace( /\t/g, " " ).replace( / /g, " " );
- }
- return new Array( this._depth_ + (extra||0) ).join(chr);
- },
- up: function( a ) {
- this._depth_ += a || 1;
- },
- down: function( a ) {
- this._depth_ -= a || 1;
- },
- setParser: function( name, parser ) {
- this.parsers[name] = parser;
- },
- // The next 3 are exposed so you can use them
- quote: quote,
- literal: literal,
- join: join,
- //
- _depth_: 1,
- // This is the list of parsers, to modify them, use jsDump.setParser
- parsers: {
- window: "[Window]",
- document: "[Document]",
- error: function(error) {
- return "Error(\"" + error.message + "\")";
- },
- unknown: "[Unknown]",
- "null": "null",
- "undefined": "undefined",
- "function": function( fn ) {
- var ret = "function",
- // functions never have name in IE
- name = "name" in fn ? fn.name : (reName.exec(fn) || [])[1];
-
- if ( name ) {
- ret += " " + name;
- }
- ret += "( ";
-
- ret = [ ret, QUnit.jsDump.parse( fn, "functionArgs" ), "){" ].join( "" );
- return join( ret, QUnit.jsDump.parse(fn,"functionCode" ), "}" );
- },
- array: array,
- nodelist: array,
- "arguments": array,
- object: function( map, stack ) {
- var ret = [ ], keys, key, val, i;
- QUnit.jsDump.up();
- keys = [];
- for ( key in map ) {
- keys.push( key );
- }
- keys.sort();
- for ( i = 0; i < keys.length; i++ ) {
- key = keys[ i ];
- val = map[ key ];
- ret.push( QUnit.jsDump.parse( key, "key" ) + ": " + QUnit.jsDump.parse( val, undefined, stack ) );
- }
- QUnit.jsDump.down();
- return join( "{", ret, "}" );
- },
- node: function( node ) {
- var len, i, val,
- open = QUnit.jsDump.HTML ? "<" : "<",
- close = QUnit.jsDump.HTML ? ">" : ">",
- tag = node.nodeName.toLowerCase(),
- ret = open + tag,
- attrs = node.attributes;
-
- if ( attrs ) {
- for ( i = 0, len = attrs.length; i < len; i++ ) {
- val = attrs[i].nodeValue;
- // IE6 includes all attributes in .attributes, even ones not explicitly set.
- // Those have values like undefined, null, 0, false, "" or "inherit".
- if ( val && val !== "inherit" ) {
- ret += " " + attrs[i].nodeName + "=" + QUnit.jsDump.parse( val, "attribute" );
- }
- }
- }
- ret += close;
-
- // Show content of TextNode or CDATASection
- if ( node.nodeType === 3 || node.nodeType === 4 ) {
- ret += node.nodeValue;
- }
-
- return ret + open + "/" + tag + close;
- },
- // function calls it internally, it's the arguments part of the function
- functionArgs: function( fn ) {
- var args,
- l = fn.length;
-
- if ( !l ) {
- return "";
- }
-
- args = new Array(l);
- while ( l-- ) {
- // 97 is 'a'
- args[l] = String.fromCharCode(97+l);
- }
- return " " + args.join( ", " ) + " ";
- },
- // object calls it internally, the key part of an item in a map
- key: quote,
- // function calls it internally, it's the content of the function
- functionCode: "[code]",
- // node calls it internally, it's an html attribute value
- attribute: quote,
- string: quote,
- date: quote,
- regexp: literal,
- number: literal,
- "boolean": literal
- },
- // if true, entities are escaped ( <, >, \t, space and \n )
- HTML: false,
- // indentation unit
- indentChar: " ",
- // if true, items in a collection, are separated by a \n, else just a space.
- multiline: true
- };
-
- return jsDump;
-}());
-
-// from jquery.js
-function inArray( elem, array ) {
- if ( array.indexOf ) {
- return array.indexOf( elem );
- }
-
- for ( var i = 0, length = array.length; i < length; i++ ) {
- if ( array[ i ] === elem ) {
- return i;
- }
- }
-
- return -1;
-}
-
-/*
- * Javascript Diff Algorithm
- * By John Resig (http://ejohn.org/)
- * Modified by Chu Alan "sprite"
- *
- * Released under the MIT license.
- *
- * More Info:
- * http://ejohn.org/projects/javascript-diff-algorithm/
- *
- * Usage: QUnit.diff(expected, actual)
- *
- * QUnit.diff( "the quick brown fox jumped over", "the quick fox jumps over" ) == "the quick brown fox jumped jumps over"
- */
-QUnit.diff = (function() {
- /*jshint eqeqeq:false, eqnull:true */
- function diff( o, n ) {
- var i,
- ns = {},
- os = {};
-
- for ( i = 0; i < n.length; i++ ) {
- if ( !hasOwn.call( ns, n[i] ) ) {
- ns[ n[i] ] = {
- rows: [],
- o: null
- };
- }
- ns[ n[i] ].rows.push( i );
- }
-
- for ( i = 0; i < o.length; i++ ) {
- if ( !hasOwn.call( os, o[i] ) ) {
- os[ o[i] ] = {
- rows: [],
- n: null
- };
- }
- os[ o[i] ].rows.push( i );
- }
-
- for ( i in ns ) {
- if ( !hasOwn.call( ns, i ) ) {
- continue;
- }
- if ( ns[i].rows.length === 1 && hasOwn.call( os, i ) && os[i].rows.length === 1 ) {
- n[ ns[i].rows[0] ] = {
- text: n[ ns[i].rows[0] ],
- row: os[i].rows[0]
- };
- o[ os[i].rows[0] ] = {
- text: o[ os[i].rows[0] ],
- row: ns[i].rows[0]
- };
- }
- }
-
- for ( i = 0; i < n.length - 1; i++ ) {
- if ( n[i].text != null && n[ i + 1 ].text == null && n[i].row + 1 < o.length && o[ n[i].row + 1 ].text == null &&
- n[ i + 1 ] == o[ n[i].row + 1 ] ) {
-
- n[ i + 1 ] = {
- text: n[ i + 1 ],
- row: n[i].row + 1
- };
- o[ n[i].row + 1 ] = {
- text: o[ n[i].row + 1 ],
- row: i + 1
- };
- }
- }
-
- for ( i = n.length - 1; i > 0; i-- ) {
- if ( n[i].text != null && n[ i - 1 ].text == null && n[i].row > 0 && o[ n[i].row - 1 ].text == null &&
- n[ i - 1 ] == o[ n[i].row - 1 ]) {
-
- n[ i - 1 ] = {
- text: n[ i - 1 ],
- row: n[i].row - 1
- };
- o[ n[i].row - 1 ] = {
- text: o[ n[i].row - 1 ],
- row: i - 1
- };
- }
- }
-
- return {
- o: o,
- n: n
- };
- }
-
- return function( o, n ) {
- o = o.replace( /\s+$/, "" );
- n = n.replace( /\s+$/, "" );
-
- var i, pre,
- str = "",
- out = diff( o === "" ? [] : o.split(/\s+/), n === "" ? [] : n.split(/\s+/) ),
- oSpace = o.match(/\s+/g),
- nSpace = n.match(/\s+/g);
-
- if ( oSpace == null ) {
- oSpace = [ " " ];
- }
- else {
- oSpace.push( " " );
- }
-
- if ( nSpace == null ) {
- nSpace = [ " " ];
- }
- else {
- nSpace.push( " " );
- }
-
- if ( out.n.length === 0 ) {
- for ( i = 0; i < out.o.length; i++ ) {
- str += "" + out.o[i] + oSpace[i] + "";
- }
- }
- else {
- if ( out.n[0].text == null ) {
- for ( n = 0; n < out.o.length && out.o[n].text == null; n++ ) {
- str += "" + out.o[n] + oSpace[n] + "";
- }
- }
-
- for ( i = 0; i < out.n.length; i++ ) {
- if (out.n[i].text == null) {
- str += "" + out.n[i] + nSpace[i] + "";
- }
- else {
- // `pre` initialized at top of scope
- pre = "";
-
- for ( n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++ ) {
- pre += "" + out.o[n] + oSpace[n] + "";
- }
- str += " " + out.n[i].text + nSpace[i] + pre;
- }
- }
- }
-
- return str;
- };
-}());
-
-// for CommonJS enviroments, export everything
-if ( typeof exports !== "undefined" ) {
- extend( exports, QUnit );
-}
-
-// get at whatever the global object is, like window in browsers
-}( (function() {return this;}.call()) ));
diff --git a/test/lib/require.js b/test/lib/require.js
deleted file mode 100644
index 987f865..0000000
--- a/test/lib/require.js
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- RequireJS 2.1.5 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.
- Available via the MIT or new BSD license.
- see: http://github.com/jrburke/requirejs for details
-*/
-var requirejs,require,define;
-(function(aa){function I(b){return"[object Function]"===L.call(b)}function J(b){return"[object Array]"===L.call(b)}function y(b,c){if(b){var d;for(d=0;dthis.depCount&&!this.defined){if(I(n)){if(this.events.error)try{e=i.execCb(c,n,b,e)}catch(d){a=d}else e=i.execCb(c,n,b,e);this.map.isDefine&&((b=this.module)&&void 0!==b.exports&&b.exports!==this.exports?e=b.exports:void 0===e&&this.usingExports&&(e=this.exports));if(a)return a.requireMap=this.map,a.requireModules=[this.map.id],a.requireType="define",v(this.error=
-a)}else e=n;this.exports=e;if(this.map.isDefine&&!this.ignore&&(q[c]=e,l.onResourceLoad))l.onResourceLoad(i,this.map,this.depMaps);x(c);this.defined=!0}this.defining=!1;this.defined&&!this.defineEmitted&&(this.defineEmitted=!0,this.emit("defined",this.exports),this.defineEmitComplete=!0)}}else this.fetch()}},callPlugin:function(){var a=this.map,b=a.id,d=j(a.prefix);this.depMaps.push(d);t(d,"defined",u(this,function(e){var n,d;d=this.map.name;var g=this.map.parentMap?this.map.parentMap.name:null,h=
-i.makeRequire(a.parentMap,{enableBuildCallback:!0});if(this.map.unnormalized){if(e.normalize&&(d=e.normalize(d,function(a){return c(a,g,!0)})||""),e=j(a.prefix+"!"+d,this.map.parentMap),t(e,"defined",u(this,function(a){this.init([],function(){return a},null,{enabled:!0,ignore:!0})})),d=m(p,e.id)){this.depMaps.push(e);if(this.events.error)d.on("error",u(this,function(a){this.emit("error",a)}));d.enable()}}else n=u(this,function(a){this.init([],function(){return a},null,{enabled:!0})}),n.error=u(this,
-function(a){this.inited=!0;this.error=a;a.requireModules=[b];G(p,function(a){0===a.map.id.indexOf(b+"_unnormalized")&&x(a.map.id)});v(a)}),n.fromText=u(this,function(e,c){var d=a.name,g=j(d),C=O;c&&(e=c);C&&(O=!1);r(g);s(k.config,b)&&(k.config[d]=k.config[b]);try{l.exec(e)}catch(ca){return v(B("fromtexteval","fromText eval for "+b+" failed: "+ca,ca,[b]))}C&&(O=!0);this.depMaps.push(g);i.completeLoad(d);h([d],n)}),e.load(a.name,h,n,k)}));i.enable(d,this);this.pluginMaps[d.id]=d},enable:function(){V[this.map.id]=
-this;this.enabling=this.enabled=!0;y(this.depMaps,u(this,function(a,b){var c,e;if("string"===typeof a){a=j(a,this.map.isDefine?this.map:this.map.parentMap,!1,!this.skipMap);this.depMaps[b]=a;if(c=m(N,a.id)){this.depExports[b]=c(this);return}this.depCount+=1;t(a,"defined",u(this,function(a){this.defineDep(b,a);this.check()}));this.errback&&t(a,"error",this.errback)}c=a.id;e=p[c];!s(N,c)&&(e&&!e.enabled)&&i.enable(a,this)}));G(this.pluginMaps,u(this,function(a){var b=m(p,a.id);b&&!b.enabled&&i.enable(a,
-this)}));this.enabling=!1;this.check()},on:function(a,b){var c=this.events[a];c||(c=this.events[a]=[]);c.push(b)},emit:function(a,b){y(this.events[a],function(a){a(b)});"error"===a&&delete this.events[a]}};i={config:k,contextName:b,registry:p,defined:q,urlFetched:U,defQueue:H,Module:Z,makeModuleMap:j,nextTick:l.nextTick,onError:v,configure:function(a){a.baseUrl&&"/"!==a.baseUrl.charAt(a.baseUrl.length-1)&&(a.baseUrl+="/");var b=k.pkgs,c=k.shim,e={paths:!0,config:!0,map:!0};G(a,function(a,b){e[b]?
-"map"===b?(k.map||(k.map={}),R(k[b],a,!0,!0)):R(k[b],a,!0):k[b]=a});a.shim&&(G(a.shim,function(a,b){J(a)&&(a={deps:a});if((a.exports||a.init)&&!a.exportsFn)a.exportsFn=i.makeShimExports(a);c[b]=a}),k.shim=c);a.packages&&(y(a.packages,function(a){a="string"===typeof a?{name:a}:a;b[a.name]={name:a.name,location:a.location||a.name,main:(a.main||"main").replace(ja,"").replace(ea,"")}}),k.pkgs=b);G(p,function(a,b){!a.inited&&!a.map.unnormalized&&(a.map=j(b))});if(a.deps||a.callback)i.require(a.deps||[],
-a.callback)},makeShimExports:function(a){return function(){var b;a.init&&(b=a.init.apply(aa,arguments));return b||a.exports&&ba(a.exports)}},makeRequire:function(a,f){function d(e,c,h){var g,k;f.enableBuildCallback&&(c&&I(c))&&(c.__requireJsBuild=!0);if("string"===typeof e){if(I(c))return v(B("requireargs","Invalid require call"),h);if(a&&s(N,e))return N[e](p[a.id]);if(l.get)return l.get(i,e,a,d);g=j(e,a,!1,!0);g=g.id;return!s(q,g)?v(B("notloaded",'Module name "'+g+'" has not been loaded yet for context: '+
-b+(a?"":". Use require([])"))):q[g]}L();i.nextTick(function(){L();k=r(j(null,a));k.skipMap=f.skipMap;k.init(e,c,h,{enabled:!0});D()});return d}f=f||{};R(d,{isBrowser:A,toUrl:function(b){var d,f=b.lastIndexOf("."),g=b.split("/")[0];if(-1!==f&&(!("."===g||".."===g)||1h.attachEvent.toString().indexOf("[native code"))&&!Y?(O=!0,h.attachEvent("onreadystatechange",b.onScriptLoad)):(h.addEventListener("load",b.onScriptLoad,!1),h.addEventListener("error",b.onScriptError,!1)),h.src=d,K=h,D?x.insertBefore(h,D):x.appendChild(h),K=null,h;if(da)try{importScripts(d),b.completeLoad(c)}catch(j){b.onError(B("importscripts","importScripts failed for "+c+" at "+d,j,[c]))}};A&&M(document.getElementsByTagName("script"),function(b){x||(x=
-b.parentNode);if(t=b.getAttribute("data-main"))return r.baseUrl||(E=t.split("/"),Q=E.pop(),fa=E.length?E.join("/")+"/":"./",r.baseUrl=fa,t=Q),t=t.replace(ea,""),r.deps=r.deps?r.deps.concat(t):[t],!0});define=function(b,c,d){var l,h;"string"!==typeof b&&(d=c,c=b,b=null);J(c)||(d=c,c=[]);!c.length&&I(d)&&d.length&&(d.toString().replace(la,"").replace(ma,function(b,d){c.push(d)}),c=(1===d.length?["require"]:["require","exports","module"]).concat(c));if(O){if(!(l=K))P&&"interactive"===P.readyState||M(document.getElementsByTagName("script"),
-function(b){if("interactive"===b.readyState)return P=b}),l=P;l&&(b||(b=l.getAttribute("data-requiremodule")),h=F[l.getAttribute("data-requirecontext")])}(h?h.defQueue:T).push([b,c,d])};define.amd={jQuery:!0};l.exec=function(b){return eval(b)};l(r)}})(this);
diff --git a/test/lib/resemble.js b/test/lib/resemble.js
new file mode 100644
index 0000000..1cb8c29
--- /dev/null
+++ b/test/lib/resemble.js
@@ -0,0 +1,535 @@
+/*
+Author: James Cryer
+Company: Huddle
+Last updated date: 21 Feb 2013
+URL: https://github.com/Huddle/Resemble.js
+*/
+
+(function(_this){
+ 'use strict';
+
+ _this['resemble'] = function( fileData ){
+
+ var data = {};
+ var images = [];
+ var updateCallbackArray = [];
+
+ var tolerance = { // between 0 and 255
+ red: 16,
+ green: 16,
+ blue: 16,
+ minBrightness: 16,
+ maxBrightness: 240
+ };
+
+ var ignoreAntialiasing = false;
+ var ignoreColors = false;
+
+ function triggerDataUpdate(){
+ var len = updateCallbackArray.length;
+ var i;
+ for(i=0;i tolerance.maxBrightness;
+ }
+
+ function getHue(r,g,b){
+
+ r = r / 255;
+ g = g / 255;
+ b = b / 255;
+ var max = Math.max(r, g, b), min = Math.min(r, g, b);
+ var h;
+ var d;
+
+ if (max == min){
+ h = 0; // achromatic
+ } else{
+ d = max - min;
+ switch(max){
+ case r: h = (g - b) / d + (g < b ? 6 : 0); break;
+ case g: h = (b - r) / d + 2; break;
+ case b: h = (r - g) / d + 4; break;
+ }
+ h /= 6;
+ }
+
+ return h;
+ }
+
+ function isAntialiased(sourcePix, data, cacheSet, verticalPos, horizontalPos, width){
+ var offset;
+ var targetPix;
+ var distance = 1;
+ var i;
+ var j;
+ var hasHighContrastSibling = 0;
+ var hasSiblingWithDifferentHue = 0;
+ var hasEquivilantSibling = 0;
+
+ addHueInfo(sourcePix);
+
+ for (i = distance*-1; i <= distance; i++){
+ for (j = distance*-1; j <= distance; j++){
+
+ if(i===0 && j===0){
+ // ignore source pixel
+ } else {
+
+ offset = ((verticalPos+j)*width + (horizontalPos+i)) * 4;
+ targetPix = getPixelInfo(data, offset, cacheSet);
+
+ if(targetPix === null){
+ continue;
+ }
+
+ addBrightnessInfo(targetPix);
+ addHueInfo(targetPix);
+
+ if( isContrasting(sourcePix, targetPix) ){
+ hasHighContrastSibling++;
+ }
+
+ if( isRGBSame(sourcePix,targetPix) ){
+ hasEquivilantSibling++;
+ }
+
+ if( Math.abs(targetPix.h - sourcePix.h) > 0.3 ){
+ hasSiblingWithDifferentHue++;
+ }
+
+ if( hasSiblingWithDifferentHue > 1 || hasHighContrastSibling > 1){
+ return true;
+ }
+ }
+ }
+ }
+
+ if(hasEquivilantSibling < 2){
+ return true;
+ }
+
+ return false;
+ }
+
+ function errorPixel(px, offset){
+ px[offset] = 255; //r
+ px[offset + 1] = 0; //g
+ px[offset + 2] = 255; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyPixel(px, offset, data){
+ px[offset] = data.r; //r
+ px[offset + 1] = data.g; //g
+ px[offset + 2] = data.b; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyGrayScalePixel(px, offset, data){
+ px[offset] = data.brightness; //r
+ px[offset + 1] = data.brightness; //g
+ px[offset + 2] = data.brightness; //b
+ px[offset + 3] = 255; //a
+ }
+
+
+ function getPixelInfo(data, offset, cacheSet){
+ var r;
+ var g;
+ var b;
+ var d;
+
+ if(typeof data[offset] !== 'undefined'){
+ r = data[offset];
+ g = data[offset+1];
+ b = data[offset+2];
+ d = {
+ r: r,
+ g: g,
+ b: b
+ };
+
+ return d;
+ } else {
+ return null;
+ }
+ }
+
+ function addBrightnessInfo(data){
+ data.brightness = getBrightness(data.r,data.g,data.b); // 'corrected' lightness
+ }
+
+ function addHueInfo(data){
+ data.h = getHue(data.r,data.g,data.b);
+ }
+
+ function analyseImages(img1, img2, width, height){
+
+ var hiddenCanvas = document.createElement('canvas');
+
+ var data1 = img1.data;
+ var data2 = img2.data;
+
+ hiddenCanvas.width = width;
+ hiddenCanvas.height = height;
+
+ var context = hiddenCanvas.getContext('2d');
+ var imgd = context.createImageData(width,height);
+ var targetPix = imgd.data;
+
+ var mismatchCount = 0;
+
+ var time = Date.now();
+
+ var skip;
+
+ if( (width > 1200 || height > 1200) && ignoreAntialiasing){
+ skip = 6;
+ }
+
+ loop(height, width, function(verticalPos, horizontalPos){
+
+ if(skip){ // only skip if the image isn't small
+ if(verticalPos % skip === 0 || horizontalPos % skip === 0){
+ return;
+ }
+ }
+
+ var offset = (verticalPos*width + horizontalPos) * 4;
+ var pixel1 = getPixelInfo(data1, offset, 1);
+ var pixel2 = getPixelInfo(data2, offset, 2);
+
+ if(pixel1 === null || pixel2 === null){
+ return;
+ }
+
+ if (ignoreColors){
+
+ addBrightnessInfo(pixel1);
+ addBrightnessInfo(pixel2);
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ return;
+ }
+
+ if( isRGBSimilar(pixel1, pixel2) ){
+ copyPixel(targetPix, offset, pixel2);
+
+ } else if( ignoreAntialiasing && (
+ addBrightnessInfo(pixel1), // jit pixel info augmentation looks a little weird, sorry.
+ addBrightnessInfo(pixel2),
+ isAntialiased(pixel1, data1, 1, verticalPos, horizontalPos, width) ||
+ isAntialiased(pixel2, data2, 2, verticalPos, horizontalPos, width)
+ )){
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+
+ });
+
+ data.misMatchPercentage = (mismatchCount / (height*width) * 100).toFixed(2);
+ data.analysisTime = Date.now() - time;
+
+ data.getImageDataUrl = function(text){
+ var barHeight = 0;
+
+ if(text){
+ barHeight = addLabel(text,context,hiddenCanvas);
+ }
+
+ context.putImageData(imgd, 0, barHeight);
+
+ return hiddenCanvas.toDataURL("image/png");
+ };
+ }
+
+ function addLabel(text, context, hiddenCanvas){
+ var textPadding = 2;
+
+ context.font = '12px sans-serif';
+
+ var textWidth = context.measureText(text).width + textPadding*2;
+ var barHeight = 22;
+
+ if(textWidth > hiddenCanvas.width){
+ hiddenCanvas.width = textWidth;
+ }
+
+ hiddenCanvas.height += barHeight;
+
+ context.fillStyle = "#666";
+ context.fillRect(0,0,hiddenCanvas.width,barHeight -4);
+ context.fillStyle = "#fff";
+ context.fillRect(0,barHeight -4,hiddenCanvas.width, 4);
+
+ context.fillStyle = "#fff";
+ context.textBaseline = "top";
+ context.font = '12px sans-serif';
+ context.fillText(text, textPadding, 1);
+
+ return barHeight;
+ }
+
+ function normalise(img, w, h){
+ var c;
+ var context;
+
+ if(img.height < h || img.width < w){
+ c = document.createElement('canvas');
+ c.width = w;
+ c.height = h;
+ context = c.getContext('2d');
+ context.putImageData(img, 0, 0);
+ return context.getImageData(0, 0, w, h);
+ }
+
+ return img;
+ }
+
+ function compare(one, two){
+
+ function onceWeHaveBoth(){
+ var width;
+ var height;
+ if(images.length === 2){
+ width = images[0].width > images[1].width ? images[0].width : images[1].width;
+ height = images[0].height > images[1].height ? images[0].height : images[1].height;
+
+ if( (images[0].width === images[1].width) && (images[0].height === images[1].height) ){
+ data.isSameDimensions = true;
+ } else {
+ data.isSameDimensions = false;
+ }
+
+ analyseImages( normalise(images[0],width, height), normalise(images[1],width, height), width, height);
+
+ triggerDataUpdate();
+ }
+ }
+
+ images = [];
+ loadImageData(one, onceWeHaveBoth);
+ loadImageData(two, onceWeHaveBoth);
+ }
+
+ function getCompareApi(param){
+
+ var secondFileData,
+ hasMethod = typeof param === 'function';
+
+ if( !hasMethod ){
+ // assume it's file data
+ secondFileData = param;
+ }
+
+ var self = {
+ ignoreNothing: function(){
+
+ tolerance.red = 16;
+ tolerance.green = 16;
+ tolerance.blue = 16;
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreAntialiasing: function(){
+
+ tolerance.red = 32;
+ tolerance.green = 32;
+ tolerance.blue = 32;
+ tolerance.minBrightness = 64;
+ tolerance.maxBrightness = 96;
+
+ ignoreAntialiasing = true;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreColors: function(){
+
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = true;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ onComplete: function( callback ){
+
+ updateCallbackArray.push(callback);
+
+ var wrapper = function(){
+ compare(fileData, secondFileData);
+ };
+
+ wrapper();
+
+ return getCompareApi(wrapper);
+ }
+ };
+
+ return self;
+ }
+
+ return {
+ onComplete: function( callback ){
+ updateCallbackArray.push(callback);
+ loadImageData(fileData, function(imageData, width, height){
+ parseImage(imageData.data, width, height);
+ });
+ },
+ compareTo: function(secondFileData){
+ return getCompareApi(secondFileData);
+ }
+ };
+
+ };
+}(this));
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index 12e1b62..0b88317 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
node_modules
.DS_Store
-.project
\ No newline at end of file
+.project
+*.log
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..63e4d7c
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,8 @@
+language: node_js
+node_js:
+ - 0.10
+
+before_script:
+ - npm install -g grunt-cli
+ - export DISPLAY=:99.0
+ - sh -e /etc/init.d/xvfb start
diff --git a/Gruntfile.js b/Gruntfile.js
index b083b49..103938c 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -1,10 +1,12 @@
+'use strict';
+
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-connect');
- grunt.loadNpmTasks('grunt-contrib-qunit');
grunt.loadNpmTasks('grunt-contrib-yuidoc');
+ grunt.loadTasks('tasks');
var root = 'src/pixi/',
debug = 'bin/pixi.dev.js',
@@ -79,7 +81,7 @@
},
files: {
srcBlob: '<%= dirs.src %>/**/*.js',
- testBlob: '<%= dirs.test %>/unit/**/*.js',
+ testBlob: '<%= dirs.test %>/{functional,lib/pixi,unit}/**/*.js',
build: '<%= dirs.build %>/pixi.dev.js',
buildMin: '<%= dirs.build %>/pixi.js'
},
@@ -94,7 +96,12 @@
},
jshint: {
beforeconcat: srcFiles,
- test: ['<%= files.testBlob %>'],
+ test: {
+ src: ['<%= files.testBlob %>'],
+ options: {
+ expr: true
+ }
+ },
options: {
asi: true,
smarttabs: true
@@ -128,12 +135,6 @@
]
},
connect: {
- qunit: {
- options: {
- port: grunt.option('port-test') || 9002,
- base: './'
- }
- },
test: {
options: {
port: grunt.option('port-test') || 9002,
@@ -142,13 +143,6 @@
}
}
},
- qunit: {
- all: {
- options: {
- urls: ['http://localhost:' + (grunt.option('port-test') || 9002) + '/test/index.html']
- }
- }
- },
yuidoc: {
compile: {
name: '<%= pkg.name %>',
@@ -161,6 +155,13 @@
outdir: '<%= dirs.docs %>'
}
}
+ },
+ karma: {
+ unit: {
+ configFile: 'test/karma.conf.js',
+ // browsers: ['Chrome'],
+ singleRun: true
+ }
}
});
@@ -182,9 +183,10 @@
}
)
- grunt.registerTask('default', ['concat', 'uglify', 'distribute']);
grunt.registerTask('build', ['concat', 'uglify', 'distribute']);
- grunt.registerTask('test', ['build', 'connect:qunit', 'qunit']);
+ grunt.registerTask('test', ['concat', 'jshint:test', 'karma']);
grunt.registerTask('docs', ['yuidoc']);
-
-}
\ No newline at end of file
+ grunt.registerTask('default', ['test', 'uglify', 'distribute']);
+ // Travis CI task.
+ grunt.registerTask('travis', ['test']);
+}
diff --git a/README.md b/README.md
index c62ef86..690cfe4 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,8 @@

+[](http://travis-ci.org/drkibitz/pixi.js)
+
#### JavaScript 2D Renderer ####
The aim of this project is to provide a fast lightweight 2D library that works
diff --git a/package.json b/package.json
index b373240..1246a68 100644
--- a/package.json
+++ b/package.json
@@ -18,14 +18,21 @@
"main": "bin/pixi.js",
+ "scripts": {
+ "test": "grunt travis --verbose"
+ },
+
"dependencies": {},
"devDependencies": {
"grunt": "~0.4.x",
- "grunt-contrib-jshint": "0.3.x",
+ "grunt-contrib-jshint": "0.6.x",
"grunt-contrib-uglify": "0.2.x",
- "grunt-contrib-connect": "0.2.x",
- "grunt-contrib-qunit": "0.2.x",
+ "grunt-contrib-connect": "0.3.x",
"grunt-contrib-yuidoc": "0.4.x",
- "grunt-contrib-concat": "0.1.x"
+ "grunt-contrib-concat": "0.3.x",
+ "chai": "~1.7.0",
+ "karma": "0.11.0",
+ "karma-firefox-launcher": "0.1.0",
+ "karma-mocha": "0.1.0"
}
}
diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js
index a7c520e..ee82bbd 100644
--- a/src/pixi/InteractionManager.js
+++ b/src/pixi/InteractionManager.js
@@ -62,7 +62,6 @@
this.onTouchEnd = this.onTouchEnd.bind(this);
this.onTouchMove = this.onTouchMove.bind(this);
-
this.last = 0;
}
diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js
index 1a95d20..eef1059 100644
--- a/src/pixi/core/Ellipse.js
+++ b/src/pixi/core/Ellipse.js
@@ -78,7 +78,7 @@
return (normx + normy < 0.25);
}
-PIXI.Ellipse.getBounds = function()
+PIXI.Ellipse.prototype.getBounds = function()
{
return new PIXI.Rectangle(this.x, this.y, this.width, this.height);
}
diff --git a/tasks/karma.js b/tasks/karma.js
new file mode 100644
index 0000000..c340485
--- /dev/null
+++ b/tasks/karma.js
@@ -0,0 +1,27 @@
+'use strict';
+
+var path = require('path');
+var server = require('karma').server;
+
+module.exports = function (grunt) {
+ grunt.registerMultiTask('karma', 'run karma.', function() {
+ var done = this.async();
+ var options = this.options({
+ background: false
+ });
+ var data = this.data;
+
+ //merge options onto data, with data taking precedence
+ data = grunt.util._.merge(options, data);
+ data.configFile = path.resolve(data.configFile);
+ if (data.configFile) {
+ data.configFile = grunt.template.process(data.configFile);
+ }
+
+ server.start(
+ data,
+ function(code) {
+ done(!code);
+ });
+ });
+};
diff --git a/test/functional/example-1-basics/bunny.png b/test/functional/example-1-basics/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/functional/example-1-basics/bunny.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-30.png b/test/functional/example-1-basics/frame-30.png
new file mode 100644
index 0000000..96e3409
--- /dev/null
+++ b/test/functional/example-1-basics/frame-30.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-60.png b/test/functional/example-1-basics/frame-60.png
new file mode 100644
index 0000000..af3f4ce
--- /dev/null
+++ b/test/functional/example-1-basics/frame-60.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-90.png b/test/functional/example-1-basics/frame-90.png
new file mode 100644
index 0000000..099b823
--- /dev/null
+++ b/test/functional/example-1-basics/frame-90.png
Binary files differ
diff --git a/test/functional/example-1-basics/index.js b/test/functional/example-1-basics/index.js
new file mode 100644
index 0000000..7ae7a98
--- /dev/null
+++ b/test/functional/example-1-basics/index.js
@@ -0,0 +1,133 @@
+describe('Example 1 - Basics', function () {
+ 'use strict';
+
+ var baseUri = '/base/test/functional/example-1-basics';
+ var expect = chai.expect;
+ var currentFrame = 0;
+ var frameEvents = {};
+ var stage;
+ var renderer;
+ var bunny;
+
+ function onFrame(frame, callback) {
+ frameEvents[frame] = callback;
+ }
+
+ function animate() {
+ currentFrame += 1;
+
+ requestAnimFrame( animate );
+
+ // just for fun, lets rotate mr rabbit a little
+ bunny.rotation += 0.1;
+
+ // render the stage
+ renderer.render(stage);
+
+ if (frameEvents[currentFrame])
+ frameEvents[currentFrame](currentFrame);
+ }
+
+ function initScene() {
+ // create an new instance of a pixi stage
+ stage = new PIXI.Stage(0x66FF99);
+
+ // create a renderer instance
+ renderer = PIXI.autoDetectRenderer(400, 300);
+ console.log('Is PIXI.WebGLRenderer: ' + (renderer instanceof PIXI.WebGLRenderer));
+
+ // add the renderer view element to the DOM
+ document.body.appendChild(renderer.view);
+
+ requestAnimFrame( animate );
+
+ // create a texture from an image path
+ var texture = PIXI.Texture.fromImage(baseUri + "/bunny.png");
+ // create a new Sprite using the texture
+ bunny = new PIXI.Sprite(texture);
+
+ // center the sprites anchor point
+ bunny.anchor.x = 0.5;
+ bunny.anchor.y = 0.5;
+
+ // move the sprite t the center of the screen
+ bunny.position.x = 200;
+ bunny.position.y = 150;
+
+ stage.addChild(bunny);
+ }
+
+ it('assets loaded', function (done) {
+ var loader = new PIXI.AssetLoader([
+ baseUri + '/bunny.png',
+ baseUri + '/frame-30.png',
+ baseUri + '/frame-60.png',
+ baseUri + '/frame-90.png'
+ ]);
+ // loader.on('onProgress', function (event) {
+ // console.log(event.content);
+ // });
+ loader.on('onComplete', function (event) {
+ done();
+ initScene();
+ });
+ loader.load();
+ });
+
+ it('frame 30 should match', function (done) {
+ this.timeout(700);
+ onFrame(30, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-30.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 60 should match', function (done) {
+ this.timeout(1200);
+ onFrame(60, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-60.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 90 should match', function (done) {
+ this.timeout(1700);
+ onFrame(90, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-90.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ // it('capture something', function (done) {
+ // this.timeout(2000000);
+ // onFrame(30, function () {
+ // var img = new Image();
+ // img.src = renderer.view.toDataURL('image/png');
+ // document.body.appendChild(img);
+ // });
+ // });
+});
diff --git a/test/index.html b/test/index.html
deleted file mode 100644
index 9cbcac5..0000000
--- a/test/index.html
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
- Pixi.js Test Suite
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/test/karma.conf.js b/test/karma.conf.js
new file mode 100644
index 0000000..c66a696
--- /dev/null
+++ b/test/karma.conf.js
@@ -0,0 +1,82 @@
+module.exports = function(config) {
+ config.set({
+
+ // base path, that will be used to resolve files and exclude
+ basePath : '../',
+
+ frameworks : ['mocha'],
+
+ // list of files / patterns to load in the browser
+ files : [
+ 'node_modules/chai/chai.js',
+ 'bin/pixi.dev.js',
+ 'test/lib/**/*.js',
+ 'test/unit/**/*.js',
+ // 'test/functional/**/*.js',
+ {pattern: 'test/**/*.png', watched: false, included: false, served: true}
+ ],
+
+ // list of files to exclude
+ exclude : [],
+
+ // use dolts reporter, as travis terminal does not support escaping sequences
+ // possible values: 'dots', 'progress', 'junit', 'teamcity'
+ // CLI --reporters progress
+ reporters : ['progress'],
+
+ // web server port
+ // CLI --port 9876
+ port : 9876,
+
+ // cli runner port
+ // CLI --runner-port 9100
+ runnerPort : 9100,
+
+ // enable / disable colors in the output (reporters and logs)
+ // CLI --colors --no-colors
+ colors : true,
+
+ // level of logging
+ // possible values: karma.LOG_DISABLE || karma.LOG_ERROR || karma.LOG_WARN || karma.LOG_INFO || karma.LOG_DEBUG
+ // CLI --log-level debug
+ logLevel : config.LOG_DEBUG,
+
+ // enable / disable watching file and executing tests whenever any file changes
+ // CLI --auto-watch --no-auto-watch
+ autoWatch : false,
+
+ // Start these browsers, currently available:
+ // - Chrome
+ // - ChromeCanary
+ // - Firefox
+ // - Opera
+ // - Safari (only Mac)
+ // - PhantomJS
+ // - IE (only Windows)
+ // CLI --browsers Chrome,Firefox,Safari
+ browsers : ['Firefox'],
+
+ // If browser does not capture in given timeout [ms], kill it
+ // CLI --capture-timeout 5000
+ captureTimeout : 5000,
+
+ // Auto run tests on start (when browsers are captured) and exit
+ // CLI --single-run --no-single-run
+ singleRun : true,
+
+ // report which specs are slower than 500ms
+ // CLI --report-slower-than 500
+ reportSlowerThan : 1000,
+
+ preprocessors : {
+ // '**/client/js/*.js': 'coverage'
+ },
+
+ plugins : [
+ 'karma-mocha',
+ // 'karma-chrome-launcher',
+ 'karma-firefox-launcher',
+ // 'karma-phantomjs-launcher'
+ ]
+ });
+};
diff --git a/test/lib/pixi/core/Matrix.js b/test/lib/pixi/core/Matrix.js
new file mode 100644
index 0000000..d26386b
--- /dev/null
+++ b/test/lib/pixi/core/Matrix.js
@@ -0,0 +1,40 @@
+
+function pixi_core_Matrix_confirmNewMat3(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(1);
+ expect(matrix[5]).to.equal(0);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(1);
+}
+
+function pixi_core_Matrix_confirmNewMat4(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[0]).to.equal(1);
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(0);
+ expect(matrix[5]).to.equal(1);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(0);
+ expect(matrix[9]).to.equal(0);
+ expect(matrix[10]).to.equal(1);
+ expect(matrix[11]).to.equal(0);
+ expect(matrix[12]).to.equal(0);
+ expect(matrix[13]).to.equal(0);
+ expect(matrix[14]).to.equal(0);
+ expect(matrix[15]).to.equal(1);
+}
diff --git a/test/lib/pixi/core/Point.js b/test/lib/pixi/core/Point.js
new file mode 100644
index 0000000..e5df07b
--- /dev/null
+++ b/test/lib/pixi/core/Point.js
@@ -0,0 +1,10 @@
+
+function pixi_core_Point_confirm(obj, x, y) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Point);
+ expect(obj).to.respondTo('clone');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+}
diff --git a/test/lib/pixi/core/Rectangle.js b/test/lib/pixi/core/Rectangle.js
new file mode 100644
index 0000000..23f0d12
--- /dev/null
+++ b/test/lib/pixi/core/Rectangle.js
@@ -0,0 +1,13 @@
+
+function pixi_core_Rectangle_confirm(obj, x, y, width, height) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Rectangle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+ expect(obj).to.have.property('width', width);
+ expect(obj).to.have.property('height', height);
+}
diff --git a/test/lib/pixi/display/DisplayObject.js b/test/lib/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..1388a7f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObject.js
@@ -0,0 +1,43 @@
+
+function pixi_display_DisplayObject_confirmNew(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObject);
+ expect(obj).to.respondTo('setInteractive');
+ expect(obj).to.respondTo('addFilter');
+ expect(obj).to.respondTo('removeFilter');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.property('last', obj);
+ expect(obj).to.have.property('first', obj);
+
+ expect(obj).to.contain.property('position');
+ pixi_core_Point_confirm(obj.position, 0, 0);
+ expect(obj).to.contain.property('scale');
+ pixi_core_Point_confirm(obj.scale, 1, 1);
+ expect(obj).to.contain.property('pivot');
+ pixi_core_Point_confirm(obj.pivot, 0, 0);
+
+ expect(obj).to.have.property('rotation', 0);
+ expect(obj).to.have.property('alpha', 1);
+ expect(obj).to.have.property('visible', true);
+ expect(obj).to.have.property('buttonMode', false);
+ expect(obj).to.have.property('parent', null);
+ expect(obj).to.have.property('worldAlpha', 1);
+
+ expect(obj).to.have.property('hitArea');
+ expect(obj).to.have.property('interactive'); // TODO: Have a better default value
+ expect('mask' in obj).to.be.true; // TODO: Have a better default value
+ expect(obj.mask).to.be.undefined;
+
+ expect(obj).to.have.property('renderable');
+ expect(obj).to.have.property('stage');
+
+ expect(obj).to.have.deep.property('worldTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ expect(obj).to.have.deep.property('localTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.localTransform);
+
+ expect(obj).to.have.deep.property('color.length', 0);
+ expect(obj).to.have.property('dynamic', true);
+}
diff --git a/test/lib/pixi/display/DisplayObjectContainer.js b/test/lib/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..085c59f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,16 @@
+
+function pixi_display_DisplayObjectContainer_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObject_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObjectContainer);
+ expect(obj).to.respondTo('addChild');
+ expect(obj).to.respondTo('addChildAt');
+ expect(obj).to.respondTo('swapChildren');
+ expect(obj).to.respondTo('getChildAt');
+ expect(obj).to.respondTo('removeChild');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('children.length', 0);
+}
diff --git a/test/lib/pixi/display/Sprite.js b/test/lib/pixi/display/Sprite.js
new file mode 100644
index 0000000..cc7a2d6
--- /dev/null
+++ b/test/lib/pixi/display/Sprite.js
@@ -0,0 +1,28 @@
+
+function pixi_display_Sprite_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Sprite);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', true);
+ expect(obj).to.have.property('stage', null);
+
+ expect(obj).to.have.property('anchor');
+ pixi_core_Point_confirm(obj.anchor, 0, 0);
+
+ expect(obj).to.have.property('blendMode', PIXI.blendModes.NORMAL);
+ expect(obj).to.have.property('width', 1); // TODO: is 1 expected
+ expect(obj).to.have.property('height', 1); // TODO: is 1 expected
+
+ // FIXME: Just make this a boolean that is always there
+ expect(!!obj.updateFrame).to.equal(obj.texture.baseTexture.hasLoaded);
+
+ expect(obj).to.have.property('texture');
+ pixi_textures_Texture_confirmNew(obj.texture, done);
+}
diff --git a/test/lib/pixi/extras/Strip.js b/test/lib/pixi/extras/Strip.js
new file mode 100644
index 0000000..8927a8a
--- /dev/null
+++ b/test/lib/pixi/extras/Strip.js
@@ -0,0 +1,12 @@
+
+function pixi_extras_Strip_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Strip);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ // TODO: Test properties
+}
diff --git a/test/lib/pixi/textures/Texture.js b/test/lib/pixi/textures/Texture.js
new file mode 100644
index 0000000..d5867b6
--- /dev/null
+++ b/test/lib/pixi/textures/Texture.js
@@ -0,0 +1,31 @@
+
+function pixi_textures_Texture_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ function confirmFrameDone() {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, obj.baseTexture.width, obj.baseTexture.height);
+
+ expect(obj).to.have.property('width', obj.baseTexture.width);
+ expect(obj).to.have.property('height', obj.baseTexture.height);
+ done();
+ }
+
+ expect(obj).to.be.an.instanceof(PIXI.Texture);
+ pixi_utils_EventTarget_like(obj);
+
+ expect(obj).to.have.property('baseTexture')
+ .and.to.be.an.instanceof(PIXI.BaseTexture);
+
+ expect(obj).to.have.property('scope', obj);
+
+ expect(obj).to.have.property('trim');
+ pixi_core_Point_confirm(obj.trim, 0, 0);
+
+ expect(obj).to.have.property('frame');
+ if (obj.baseTexture.hasLoaded) {
+ confirmFrameDone();
+ } else {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, 1, 1);
+ obj.addEventListener('update', confirmFrameDone);
+ }
+}
diff --git a/test/lib/pixi/utils/EventTarget.js b/test/lib/pixi/utils/EventTarget.js
new file mode 100644
index 0000000..7b1dcfa
--- /dev/null
+++ b/test/lib/pixi/utils/EventTarget.js
@@ -0,0 +1,8 @@
+
+function pixi_utils_EventTarget_like(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.respondTo('addEventListener');
+ expect(obj).to.respondTo('dispatchEvent');
+ expect(obj).to.respondTo('removeEventListener');
+}
diff --git a/test/lib/qunit-1.11.0.css b/test/lib/qunit-1.11.0.css
deleted file mode 100644
index d7fc0c8..0000000
--- a/test/lib/qunit-1.11.0.css
+++ /dev/null
@@ -1,244 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-/** Font Family and Sizes */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
- font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
-}
-
-#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
-#qunit-tests { font-size: smaller; }
-
-
-/** Resets */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter {
- margin: 0;
- padding: 0;
-}
-
-
-/** Header */
-
-#qunit-header {
- padding: 0.5em 0 0.5em 1em;
-
- color: #8699a4;
- background-color: #0d3349;
-
- font-size: 1.5em;
- line-height: 1em;
- font-weight: normal;
-
- border-radius: 5px 5px 0 0;
- -moz-border-radius: 5px 5px 0 0;
- -webkit-border-top-right-radius: 5px;
- -webkit-border-top-left-radius: 5px;
-}
-
-#qunit-header a {
- text-decoration: none;
- color: #c2ccd1;
-}
-
-#qunit-header a:hover,
-#qunit-header a:focus {
- color: #fff;
-}
-
-#qunit-testrunner-toolbar label {
- display: inline-block;
- padding: 0 .5em 0 .1em;
-}
-
-#qunit-banner {
- height: 5px;
-}
-
-#qunit-testrunner-toolbar {
- padding: 0.5em 0 0.5em 2em;
- color: #5E740B;
- background-color: #eee;
- overflow: hidden;
-}
-
-#qunit-userAgent {
- padding: 0.5em 0 0.5em 2.5em;
- background-color: #2b81af;
- color: #fff;
- text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
-}
-
-#qunit-modulefilter-container {
- float: right;
-}
-
-/** Tests: Pass/Fail */
-
-#qunit-tests {
- list-style-position: inside;
-}
-
-#qunit-tests li {
- padding: 0.4em 0.5em 0.4em 2.5em;
- border-bottom: 1px solid #fff;
- list-style-position: inside;
-}
-
-#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running {
- display: none;
-}
-
-#qunit-tests li strong {
- cursor: pointer;
-}
-
-#qunit-tests li a {
- padding: 0.5em;
- color: #c2ccd1;
- text-decoration: none;
-}
-#qunit-tests li a:hover,
-#qunit-tests li a:focus {
- color: #000;
-}
-
-#qunit-tests li .runtime {
- float: right;
- font-size: smaller;
-}
-
-.qunit-assert-list {
- margin-top: 0.5em;
- padding: 0.5em;
-
- background-color: #fff;
-
- border-radius: 5px;
- -moz-border-radius: 5px;
- -webkit-border-radius: 5px;
-}
-
-.qunit-collapsed {
- display: none;
-}
-
-#qunit-tests table {
- border-collapse: collapse;
- margin-top: .2em;
-}
-
-#qunit-tests th {
- text-align: right;
- vertical-align: top;
- padding: 0 .5em 0 0;
-}
-
-#qunit-tests td {
- vertical-align: top;
-}
-
-#qunit-tests pre {
- margin: 0;
- white-space: pre-wrap;
- word-wrap: break-word;
-}
-
-#qunit-tests del {
- background-color: #e0f2be;
- color: #374e0c;
- text-decoration: none;
-}
-
-#qunit-tests ins {
- background-color: #ffcaca;
- color: #500;
- text-decoration: none;
-}
-
-/*** Test Counts */
-
-#qunit-tests b.counts { color: black; }
-#qunit-tests b.passed { color: #5E740B; }
-#qunit-tests b.failed { color: #710909; }
-
-#qunit-tests li li {
- padding: 5px;
- background-color: #fff;
- border-bottom: none;
- list-style-position: inside;
-}
-
-/*** Passing Styles */
-
-#qunit-tests li li.pass {
- color: #3c510c;
- background-color: #fff;
- border-left: 10px solid #C6E746;
-}
-
-#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
-#qunit-tests .pass .test-name { color: #366097; }
-
-#qunit-tests .pass .test-actual,
-#qunit-tests .pass .test-expected { color: #999999; }
-
-#qunit-banner.qunit-pass { background-color: #C6E746; }
-
-/*** Failing Styles */
-
-#qunit-tests li li.fail {
- color: #710909;
- background-color: #fff;
- border-left: 10px solid #EE5757;
- white-space: pre;
-}
-
-#qunit-tests > li:last-child {
- border-radius: 0 0 5px 5px;
- -moz-border-radius: 0 0 5px 5px;
- -webkit-border-bottom-right-radius: 5px;
- -webkit-border-bottom-left-radius: 5px;
-}
-
-#qunit-tests .fail { color: #000000; background-color: #EE5757; }
-#qunit-tests .fail .test-name,
-#qunit-tests .fail .module-name { color: #000000; }
-
-#qunit-tests .fail .test-actual { color: #EE5757; }
-#qunit-tests .fail .test-expected { color: green; }
-
-#qunit-banner.qunit-fail { background-color: #EE5757; }
-
-
-/** Result */
-
-#qunit-testresult {
- padding: 0.5em 0.5em 0.5em 2.5em;
-
- color: #2b81af;
- background-color: #D2E0E6;
-
- border-bottom: 1px solid white;
-}
-#qunit-testresult .module-name {
- font-weight: bold;
-}
-
-/** Fixture */
-
-#qunit-fixture {
- position: absolute;
- top: -10000px;
- left: -10000px;
- width: 1000px;
- height: 1000px;
-}
diff --git a/test/lib/qunit-1.11.0.js b/test/lib/qunit-1.11.0.js
deleted file mode 100644
index 302545f..0000000
--- a/test/lib/qunit-1.11.0.js
+++ /dev/null
@@ -1,2152 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-(function( window ) {
-
-var QUnit,
- assert,
- config,
- onErrorFnPrev,
- testId = 0,
- fileName = (sourceFromStacktrace( 0 ) || "" ).replace(/(:\d+)+\)?/, "").replace(/.+\//, ""),
- toString = Object.prototype.toString,
- hasOwn = Object.prototype.hasOwnProperty,
- // Keep a local reference to Date (GH-283)
- Date = window.Date,
- defined = {
- setTimeout: typeof window.setTimeout !== "undefined",
- sessionStorage: (function() {
- var x = "qunit-test-string";
- try {
- sessionStorage.setItem( x, x );
- sessionStorage.removeItem( x );
- return true;
- } catch( e ) {
- return false;
- }
- }())
- },
- /**
- * Provides a normalized error string, correcting an issue
- * with IE 7 (and prior) where Error.prototype.toString is
- * not properly implemented
- *
- * Based on http://es5.github.com/#x15.11.4.4
- *
- * @param {String|Error} error
- * @return {String} error message
- */
- errorString = function( error ) {
- var name, message,
- errorString = error.toString();
- if ( errorString.substring( 0, 7 ) === "[object" ) {
- name = error.name ? error.name.toString() : "Error";
- message = error.message ? error.message.toString() : "";
- if ( name && message ) {
- return name + ": " + message;
- } else if ( name ) {
- return name;
- } else if ( message ) {
- return message;
- } else {
- return "Error";
- }
- } else {
- return errorString;
- }
- },
- /**
- * Makes a clone of an object using only Array or Object as base,
- * and copies over the own enumerable properties.
- *
- * @param {Object} obj
- * @return {Object} New object with only the own properties (recursively).
- */
- objectValues = function( obj ) {
- // Grunt 0.3.x uses an older version of jshint that still has jshint/jshint#392.
- /*jshint newcap: false */
- var key, val,
- vals = QUnit.is( "array", obj ) ? [] : {};
- for ( key in obj ) {
- if ( hasOwn.call( obj, key ) ) {
- val = obj[key];
- vals[key] = val === Object(val) ? objectValues(val) : val;
- }
- }
- return vals;
- };
-
-function Test( settings ) {
- extend( this, settings );
- this.assertions = [];
- this.testNumber = ++Test.count;
-}
-
-Test.count = 0;
-
-Test.prototype = {
- init: function() {
- var a, b, li,
- tests = id( "qunit-tests" );
-
- if ( tests ) {
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml;
-
- // `a` initialized at top of scope
- a = document.createElement( "a" );
- a.innerHTML = "Rerun";
- a.href = QUnit.url({ testNumber: this.testNumber });
-
- li = document.createElement( "li" );
- li.appendChild( b );
- li.appendChild( a );
- li.className = "running";
- li.id = this.id = "qunit-test-output" + testId++;
-
- tests.appendChild( li );
- }
- },
- setup: function() {
- if ( this.module !== config.previousModule ) {
- if ( config.previousModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.previousModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
- config.previousModule = this.module;
- config.moduleStats = { all: 0, bad: 0 };
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- } else if ( config.autorun ) {
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- }
-
- config.current = this;
-
- this.testEnvironment = extend({
- setup: function() {},
- teardown: function() {}
- }, this.moduleTestEnvironment );
-
- this.started = +new Date();
- runLoggingCallbacks( "testStart", QUnit, {
- name: this.testName,
- module: this.module
- });
-
- // allow utility functions to access the current test environment
- // TODO why??
- QUnit.current_testEnvironment = this.testEnvironment;
-
- if ( !config.pollution ) {
- saveGlobal();
- }
- if ( config.notrycatch ) {
- this.testEnvironment.setup.call( this.testEnvironment );
- return;
- }
- try {
- this.testEnvironment.setup.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Setup failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- },
- run: function() {
- config.current = this;
-
- var running = id( "qunit-testresult" );
-
- if ( running ) {
- running.innerHTML = "Running:
" + this.nameHtml;
- }
-
- if ( this.async ) {
- QUnit.stop();
- }
-
- this.callbackStarted = +new Date();
-
- if ( config.notrycatch ) {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- return;
- }
-
- try {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- } catch( e ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
-
- QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + " " + this.stack + ": " + ( e.message || e ), extractStacktrace( e, 0 ) );
- // else next test will carry the responsibility
- saveGlobal();
-
- // Restart the tests if they're blocking
- if ( config.blocking ) {
- QUnit.start();
- }
- }
- },
- teardown: function() {
- config.current = this;
- if ( config.notrycatch ) {
- if ( typeof this.callbackRuntime === "undefined" ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
- }
- this.testEnvironment.teardown.call( this.testEnvironment );
- return;
- } else {
- try {
- this.testEnvironment.teardown.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Teardown failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- }
- checkPollution();
- },
- finish: function() {
- config.current = this;
- if ( config.requireExpects && this.expected === null ) {
- QUnit.pushFailure( "Expected number of assertions to be defined, but expect() was not called.", this.stack );
- } else if ( this.expected !== null && this.expected !== this.assertions.length ) {
- QUnit.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack );
- } else if ( this.expected === null && !this.assertions.length ) {
- QUnit.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions.", this.stack );
- }
-
- var i, assertion, a, b, time, li, ol,
- test = this,
- good = 0,
- bad = 0,
- tests = id( "qunit-tests" );
-
- this.runtime = +new Date() - this.started;
- config.stats.all += this.assertions.length;
- config.moduleStats.all += this.assertions.length;
-
- if ( tests ) {
- ol = document.createElement( "ol" );
- ol.className = "qunit-assert-list";
-
- for ( i = 0; i < this.assertions.length; i++ ) {
- assertion = this.assertions[i];
-
- li = document.createElement( "li" );
- li.className = assertion.result ? "pass" : "fail";
- li.innerHTML = assertion.message || ( assertion.result ? "okay" : "failed" );
- ol.appendChild( li );
-
- if ( assertion.result ) {
- good++;
- } else {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
-
- // store result when possible
- if ( QUnit.config.reorder && defined.sessionStorage ) {
- if ( bad ) {
- sessionStorage.setItem( "qunit-test-" + this.module + "-" + this.testName, bad );
- } else {
- sessionStorage.removeItem( "qunit-test-" + this.module + "-" + this.testName );
- }
- }
-
- if ( bad === 0 ) {
- addClass( ol, "qunit-collapsed" );
- }
-
- // `b` initialized at top of scope
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml + " (" + bad + ", " + good + ", " + this.assertions.length + ")";
-
- addEvent(b, "click", function() {
- var next = b.parentNode.lastChild,
- collapsed = hasClass( next, "qunit-collapsed" );
- ( collapsed ? removeClass : addClass )( next, "qunit-collapsed" );
- });
-
- addEvent(b, "dblclick", function( e ) {
- var target = e && e.target ? e.target : window.event.srcElement;
- if ( target.nodeName.toLowerCase() === "span" || target.nodeName.toLowerCase() === "b" ) {
- target = target.parentNode;
- }
- if ( window.location && target.nodeName.toLowerCase() === "strong" ) {
- window.location = QUnit.url({ testNumber: test.testNumber });
- }
- });
-
- // `time` initialized at top of scope
- time = document.createElement( "span" );
- time.className = "runtime";
- time.innerHTML = this.runtime + " ms";
-
- // `li` initialized at top of scope
- li = id( this.id );
- li.className = bad ? "fail" : "pass";
- li.removeChild( li.firstChild );
- a = li.firstChild;
- li.appendChild( b );
- li.appendChild( a );
- li.appendChild( time );
- li.appendChild( ol );
-
- } else {
- for ( i = 0; i < this.assertions.length; i++ ) {
- if ( !this.assertions[i].result ) {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
- }
-
- runLoggingCallbacks( "testDone", QUnit, {
- name: this.testName,
- module: this.module,
- failed: bad,
- passed: this.assertions.length - bad,
- total: this.assertions.length,
- duration: this.runtime
- });
-
- QUnit.reset();
-
- config.current = undefined;
- },
-
- queue: function() {
- var bad,
- test = this;
-
- synchronize(function() {
- test.init();
- });
- function run() {
- // each of these can by async
- synchronize(function() {
- test.setup();
- });
- synchronize(function() {
- test.run();
- });
- synchronize(function() {
- test.teardown();
- });
- synchronize(function() {
- test.finish();
- });
- }
-
- // `bad` initialized at top of scope
- // defer when previous test run passed, if storage is available
- bad = QUnit.config.reorder && defined.sessionStorage &&
- +sessionStorage.getItem( "qunit-test-" + this.module + "-" + this.testName );
-
- if ( bad ) {
- run();
- } else {
- synchronize( run, true );
- }
- }
-};
-
-// Root QUnit object.
-// `QUnit` initialized at top of scope
-QUnit = {
-
- // call on start of module test to prepend name to all tests
- module: function( name, testEnvironment ) {
- config.currentModule = name;
- config.currentModuleTestEnvironment = testEnvironment;
- config.modules[name] = true;
- },
-
- asyncTest: function( testName, expected, callback ) {
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- QUnit.test( testName, expected, callback, true );
- },
-
- test: function( testName, expected, callback, async ) {
- var test,
- nameHtml = "" + escapeText( testName ) + "";
-
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- if ( config.currentModule ) {
- nameHtml = "" + escapeText( config.currentModule ) + ": " + nameHtml;
- }
-
- test = new Test({
- nameHtml: nameHtml,
- testName: testName,
- expected: expected,
- async: async,
- callback: callback,
- module: config.currentModule,
- moduleTestEnvironment: config.currentModuleTestEnvironment,
- stack: sourceFromStacktrace( 2 )
- });
-
- if ( !validTest( test ) ) {
- return;
- }
-
- test.queue();
- },
-
- // Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through.
- expect: function( asserts ) {
- if (arguments.length === 1) {
- config.current.expected = asserts;
- } else {
- return config.current.expected;
- }
- },
-
- start: function( count ) {
- // QUnit hasn't been initialized yet.
- // Note: RequireJS (et al) may delay onLoad
- if ( config.semaphore === undefined ) {
- QUnit.begin(function() {
- // This is triggered at the top of QUnit.load, push start() to the event loop, to allow QUnit.load to finish first
- setTimeout(function() {
- QUnit.start( count );
- });
- });
- return;
- }
-
- config.semaphore -= count || 1;
- // don't start until equal number of stop-calls
- if ( config.semaphore > 0 ) {
- return;
- }
- // ignore if start is called more often then stop
- if ( config.semaphore < 0 ) {
- config.semaphore = 0;
- QUnit.pushFailure( "Called start() while already started (QUnit.config.semaphore was 0 already)", null, sourceFromStacktrace(2) );
- return;
- }
- // A slight delay, to avoid any current callbacks
- if ( defined.setTimeout ) {
- window.setTimeout(function() {
- if ( config.semaphore > 0 ) {
- return;
- }
- if ( config.timeout ) {
- clearTimeout( config.timeout );
- }
-
- config.blocking = false;
- process( true );
- }, 13);
- } else {
- config.blocking = false;
- process( true );
- }
- },
-
- stop: function( count ) {
- config.semaphore += count || 1;
- config.blocking = true;
-
- if ( config.testTimeout && defined.setTimeout ) {
- clearTimeout( config.timeout );
- config.timeout = window.setTimeout(function() {
- QUnit.ok( false, "Test timed out" );
- config.semaphore = 1;
- QUnit.start();
- }, config.testTimeout );
- }
- }
-};
-
-// `assert` initialized at top of scope
-// Asssert helpers
-// All of these must either call QUnit.push() or manually do:
-// - runLoggingCallbacks( "log", .. );
-// - config.current.assertions.push({ .. });
-// We attach it to the QUnit object *after* we expose the public API,
-// otherwise `assert` will become a global variable in browsers (#341).
-assert = {
- /**
- * Asserts rough true-ish result.
- * @name ok
- * @function
- * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" );
- */
- ok: function( result, msg ) {
- if ( !config.current ) {
- throw new Error( "ok() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
- result = !!result;
-
- var source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: msg
- };
-
- msg = escapeText( msg || (result ? "okay" : "failed" ) );
- msg = "" + msg + "";
-
- if ( !result ) {
- source = sourceFromStacktrace( 2 );
- if ( source ) {
- details.source = source;
- msg += "Source: | " + escapeText( source ) + " |
---|
";
- }
- }
- runLoggingCallbacks( "log", QUnit, details );
- config.current.assertions.push({
- result: result,
- message: msg
- });
- },
-
- /**
- * Assert that the first two arguments are equal, with an optional message.
- * Prints out both actual and expected values.
- * @name equal
- * @function
- * @example equal( format( "Received {0} bytes.", 2), "Received 2 bytes.", "format() replaces {0} with next argument" );
- */
- equal: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected == actual, actual, expected, message );
- },
-
- /**
- * @name notEqual
- * @function
- */
- notEqual: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected != actual, actual, expected, message );
- },
-
- /**
- * @name propEqual
- * @function
- */
- propEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notPropEqual
- * @function
- */
- notPropEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name deepEqual
- * @function
- */
- deepEqual: function( actual, expected, message ) {
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notDeepEqual
- * @function
- */
- notDeepEqual: function( actual, expected, message ) {
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name strictEqual
- * @function
- */
- strictEqual: function( actual, expected, message ) {
- QUnit.push( expected === actual, actual, expected, message );
- },
-
- /**
- * @name notStrictEqual
- * @function
- */
- notStrictEqual: function( actual, expected, message ) {
- QUnit.push( expected !== actual, actual, expected, message );
- },
-
- "throws": function( block, expected, message ) {
- var actual,
- expectedOutput = expected,
- ok = false;
-
- // 'expected' is optional
- if ( typeof expected === "string" ) {
- message = expected;
- expected = null;
- }
-
- config.current.ignoreGlobalErrors = true;
- try {
- block.call( config.current.testEnvironment );
- } catch (e) {
- actual = e;
- }
- config.current.ignoreGlobalErrors = false;
-
- if ( actual ) {
- // we don't want to validate thrown error
- if ( !expected ) {
- ok = true;
- expectedOutput = null;
- // expected is a regexp
- } else if ( QUnit.objectType( expected ) === "regexp" ) {
- ok = expected.test( errorString( actual ) );
- // expected is a constructor
- } else if ( actual instanceof expected ) {
- ok = true;
- // expected is a validation function which returns true is validation passed
- } else if ( expected.call( {}, actual ) === true ) {
- expectedOutput = null;
- ok = true;
- }
-
- QUnit.push( ok, actual, expectedOutput, message );
- } else {
- QUnit.pushFailure( message, null, 'No exception was thrown.' );
- }
- }
-};
-
-/**
- * @deprecate since 1.8.0
- * Kept assertion helpers in root for backwards compatibility.
- */
-extend( QUnit, assert );
-
-/**
- * @deprecated since 1.9.0
- * Kept root "raises()" for backwards compatibility.
- * (Note that we don't introduce assert.raises).
- */
-QUnit.raises = assert[ "throws" ];
-
-/**
- * @deprecated since 1.0.0, replaced with error pushes since 1.3.0
- * Kept to avoid TypeErrors for undefined methods.
- */
-QUnit.equals = function() {
- QUnit.push( false, false, false, "QUnit.equals has been deprecated since 2009 (e88049a0), use QUnit.equal instead" );
-};
-QUnit.same = function() {
- QUnit.push( false, false, false, "QUnit.same has been deprecated since 2009 (e88049a0), use QUnit.deepEqual instead" );
-};
-
-// We want access to the constructor's prototype
-(function() {
- function F() {}
- F.prototype = QUnit;
- QUnit = new F();
- // Make F QUnit's constructor so that we can add to the prototype later
- QUnit.constructor = F;
-}());
-
-/**
- * Config object: Maintain internal state
- * Later exposed as QUnit.config
- * `config` initialized at top of scope
- */
-config = {
- // The queue of tests to run
- queue: [],
-
- // block until document ready
- blocking: true,
-
- // when enabled, show only failing tests
- // gets persisted through sessionStorage and can be changed in UI via checkbox
- hidepassed: false,
-
- // by default, run previously failed tests first
- // very useful in combination with "Hide passed tests" checked
- reorder: true,
-
- // by default, modify document.title when suite is done
- altertitle: true,
-
- // when enabled, all tests must call expect()
- requireExpects: false,
-
- // add checkboxes that are persisted in the query-string
- // when enabled, the id is set to `true` as a `QUnit.config` property
- urlConfig: [
- {
- id: "noglobals",
- label: "Check for Globals",
- tooltip: "Enabling this will test if any test introduces new properties on the `window` object. Stored as query-strings."
- },
- {
- id: "notrycatch",
- label: "No try-catch",
- tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging exceptions in IE reasonable. Stored as query-strings."
- }
- ],
-
- // Set of all modules.
- modules: {},
-
- // logging callback queues
- begin: [],
- done: [],
- log: [],
- testStart: [],
- testDone: [],
- moduleStart: [],
- moduleDone: []
-};
-
-// Export global variables, unless an 'exports' object exists,
-// in that case we assume we're in CommonJS (dealt with on the bottom of the script)
-if ( typeof exports === "undefined" ) {
- extend( window, QUnit );
-
- // Expose QUnit object
- window.QUnit = QUnit;
-}
-
-// Initialize more QUnit.config and QUnit.urlParams
-(function() {
- var i,
- location = window.location || { search: "", protocol: "file:" },
- params = location.search.slice( 1 ).split( "&" ),
- length = params.length,
- urlParams = {},
- current;
-
- if ( params[ 0 ] ) {
- for ( i = 0; i < length; i++ ) {
- current = params[ i ].split( "=" );
- current[ 0 ] = decodeURIComponent( current[ 0 ] );
- // allow just a key to turn on a flag, e.g., test.html?noglobals
- current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true;
- urlParams[ current[ 0 ] ] = current[ 1 ];
- }
- }
-
- QUnit.urlParams = urlParams;
-
- // String search anywhere in moduleName+testName
- config.filter = urlParams.filter;
-
- // Exact match of the module name
- config.module = urlParams.module;
-
- config.testNumber = parseInt( urlParams.testNumber, 10 ) || null;
-
- // Figure out if we're running the tests from a server or not
- QUnit.isLocal = location.protocol === "file:";
-}());
-
-// Extend QUnit object,
-// these after set here because they should not be exposed as global functions
-extend( QUnit, {
- assert: assert,
-
- config: config,
-
- // Initialize the configuration options
- init: function() {
- extend( config, {
- stats: { all: 0, bad: 0 },
- moduleStats: { all: 0, bad: 0 },
- started: +new Date(),
- updateRate: 1000,
- blocking: false,
- autostart: true,
- autorun: false,
- filter: "",
- queue: [],
- semaphore: 1
- });
-
- var tests, banner, result,
- qunit = id( "qunit" );
-
- if ( qunit ) {
- qunit.innerHTML =
- "" +
- "" +
- "" +
- "" +
- "
";
- }
-
- tests = id( "qunit-tests" );
- banner = id( "qunit-banner" );
- result = id( "qunit-testresult" );
-
- if ( tests ) {
- tests.innerHTML = "";
- }
-
- if ( banner ) {
- banner.className = "";
- }
-
- if ( result ) {
- result.parentNode.removeChild( result );
- }
-
- if ( tests ) {
- result = document.createElement( "p" );
- result.id = "qunit-testresult";
- result.className = "result";
- tests.parentNode.insertBefore( result, tests );
- result.innerHTML = "Running...
";
- }
- },
-
- // Resets the test setup. Useful for tests that modify the DOM.
- reset: function() {
- var fixture = id( "qunit-fixture" );
- if ( fixture ) {
- fixture.innerHTML = config.fixture;
- }
- },
-
- // Trigger an event on an element.
- // @example triggerEvent( document.body, "click" );
- triggerEvent: function( elem, type, event ) {
- if ( document.createEvent ) {
- event = document.createEvent( "MouseEvents" );
- event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView,
- 0, 0, 0, 0, 0, false, false, false, false, 0, null);
-
- elem.dispatchEvent( event );
- } else if ( elem.fireEvent ) {
- elem.fireEvent( "on" + type );
- }
- },
-
- // Safe object type checking
- is: function( type, obj ) {
- return QUnit.objectType( obj ) === type;
- },
-
- objectType: function( obj ) {
- if ( typeof obj === "undefined" ) {
- return "undefined";
- // consider: typeof null === object
- }
- if ( obj === null ) {
- return "null";
- }
-
- var match = toString.call( obj ).match(/^\[object\s(.*)\]$/),
- type = match && match[1] || "";
-
- switch ( type ) {
- case "Number":
- if ( isNaN(obj) ) {
- return "nan";
- }
- return "number";
- case "String":
- case "Boolean":
- case "Array":
- case "Date":
- case "RegExp":
- case "Function":
- return type.toLowerCase();
- }
- if ( typeof obj === "object" ) {
- return "object";
- }
- return undefined;
- },
-
- push: function( result, actual, expected, message ) {
- if ( !config.current ) {
- throw new Error( "assertion outside test context, was " + sourceFromStacktrace() );
- }
-
- var output, source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: message,
- actual: actual,
- expected: expected
- };
-
- message = escapeText( message ) || ( result ? "okay" : "failed" );
- message = "" + message + "";
- output = message;
-
- if ( !result ) {
- expected = escapeText( QUnit.jsDump.parse(expected) );
- actual = escapeText( QUnit.jsDump.parse(actual) );
- output += "Expected: | " + expected + " |
";
-
- if ( actual !== expected ) {
- output += "Result: | " + actual + " |
";
- output += "Diff: | " + QUnit.diff( expected, actual ) + " |
";
- }
-
- source = sourceFromStacktrace();
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
- }
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: !!result,
- message: output
- });
- },
-
- pushFailure: function( message, source, actual ) {
- if ( !config.current ) {
- throw new Error( "pushFailure() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
-
- var output,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: false,
- message: message
- };
-
- message = escapeText( message ) || "error";
- message = "" + message + "";
- output = message;
-
- output += "";
-
- if ( actual ) {
- output += "Result: | " + escapeText( actual ) + " |
";
- }
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: false,
- message: output
- });
- },
-
- url: function( params ) {
- params = extend( extend( {}, QUnit.urlParams ), params );
- var key,
- querystring = "?";
-
- for ( key in params ) {
- if ( !hasOwn.call( params, key ) ) {
- continue;
- }
- querystring += encodeURIComponent( key ) + "=" +
- encodeURIComponent( params[ key ] ) + "&";
- }
- return window.location.protocol + "//" + window.location.host +
- window.location.pathname + querystring.slice( 0, -1 );
- },
-
- extend: extend,
- id: id,
- addEvent: addEvent
- // load, equiv, jsDump, diff: Attached later
-});
-
-/**
- * @deprecated: Created for backwards compatibility with test runner that set the hook function
- * into QUnit.{hook}, instead of invoking it and passing the hook function.
- * QUnit.constructor is set to the empty F() above so that we can add to it's prototype here.
- * Doing this allows us to tell if the following methods have been overwritten on the actual
- * QUnit object.
- */
-extend( QUnit.constructor.prototype, {
-
- // Logging callbacks; all receive a single argument with the listed properties
- // run test/logs.html for any related changes
- begin: registerLoggingCallback( "begin" ),
-
- // done: { failed, passed, total, runtime }
- done: registerLoggingCallback( "done" ),
-
- // log: { result, actual, expected, message }
- log: registerLoggingCallback( "log" ),
-
- // testStart: { name }
- testStart: registerLoggingCallback( "testStart" ),
-
- // testDone: { name, failed, passed, total, duration }
- testDone: registerLoggingCallback( "testDone" ),
-
- // moduleStart: { name }
- moduleStart: registerLoggingCallback( "moduleStart" ),
-
- // moduleDone: { name, failed, passed, total }
- moduleDone: registerLoggingCallback( "moduleDone" )
-});
-
-if ( typeof document === "undefined" || document.readyState === "complete" ) {
- config.autorun = true;
-}
-
-QUnit.load = function() {
- runLoggingCallbacks( "begin", QUnit, {} );
-
- // Initialize the config, saving the execution queue
- var banner, filter, i, label, len, main, ol, toolbar, userAgent, val,
- urlConfigCheckboxesContainer, urlConfigCheckboxes, moduleFilter,
- numModules = 0,
- moduleFilterHtml = "",
- urlConfigHtml = "",
- oldconfig = extend( {}, config );
-
- QUnit.init();
- extend(config, oldconfig);
-
- config.blocking = false;
-
- len = config.urlConfig.length;
-
- for ( i = 0; i < len; i++ ) {
- val = config.urlConfig[i];
- if ( typeof val === "string" ) {
- val = {
- id: val,
- label: val,
- tooltip: "[no tooltip available]"
- };
- }
- config[ val.id ] = QUnit.urlParams[ val.id ];
- urlConfigHtml += "";
- }
-
- moduleFilterHtml += "";
-
- // `userAgent` initialized at top of scope
- userAgent = id( "qunit-userAgent" );
- if ( userAgent ) {
- userAgent.innerHTML = navigator.userAgent;
- }
-
- // `banner` initialized at top of scope
- banner = id( "qunit-header" );
- if ( banner ) {
- banner.innerHTML = "" + banner.innerHTML + " ";
- }
-
- // `toolbar` initialized at top of scope
- toolbar = id( "qunit-testrunner-toolbar" );
- if ( toolbar ) {
- // `filter` initialized at top of scope
- filter = document.createElement( "input" );
- filter.type = "checkbox";
- filter.id = "qunit-filter-pass";
-
- addEvent( filter, "click", function() {
- var tmp,
- ol = document.getElementById( "qunit-tests" );
-
- if ( filter.checked ) {
- ol.className = ol.className + " hidepass";
- } else {
- tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " ";
- ol.className = tmp.replace( / hidepass /, " " );
- }
- if ( defined.sessionStorage ) {
- if (filter.checked) {
- sessionStorage.setItem( "qunit-filter-passed-tests", "true" );
- } else {
- sessionStorage.removeItem( "qunit-filter-passed-tests" );
- }
- }
- });
-
- if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem( "qunit-filter-passed-tests" ) ) {
- filter.checked = true;
- // `ol` initialized at top of scope
- ol = document.getElementById( "qunit-tests" );
- ol.className = ol.className + " hidepass";
- }
- toolbar.appendChild( filter );
-
- // `label` initialized at top of scope
- label = document.createElement( "label" );
- label.setAttribute( "for", "qunit-filter-pass" );
- label.setAttribute( "title", "Only show tests and assertons that fail. Stored in sessionStorage." );
- label.innerHTML = "Hide passed tests";
- toolbar.appendChild( label );
-
- urlConfigCheckboxesContainer = document.createElement("span");
- urlConfigCheckboxesContainer.innerHTML = urlConfigHtml;
- urlConfigCheckboxes = urlConfigCheckboxesContainer.getElementsByTagName("input");
- // For oldIE support:
- // * Add handlers to the individual elements instead of the container
- // * Use "click" instead of "change"
- // * Fallback from event.target to event.srcElement
- addEvents( urlConfigCheckboxes, "click", function( event ) {
- var params = {},
- target = event.target || event.srcElement;
- params[ target.name ] = target.checked ? true : undefined;
- window.location = QUnit.url( params );
- });
- toolbar.appendChild( urlConfigCheckboxesContainer );
-
- if (numModules > 1) {
- moduleFilter = document.createElement( 'span' );
- moduleFilter.setAttribute( 'id', 'qunit-modulefilter-container' );
- moduleFilter.innerHTML = moduleFilterHtml;
- addEvent( moduleFilter.lastChild, "change", function() {
- var selectBox = moduleFilter.getElementsByTagName("select")[0],
- selectedModule = decodeURIComponent(selectBox.options[selectBox.selectedIndex].value);
-
- window.location = QUnit.url( { module: ( selectedModule === "" ) ? undefined : selectedModule } );
- });
- toolbar.appendChild(moduleFilter);
- }
- }
-
- // `main` initialized at top of scope
- main = id( "qunit-fixture" );
- if ( main ) {
- config.fixture = main.innerHTML;
- }
-
- if ( config.autostart ) {
- QUnit.start();
- }
-};
-
-addEvent( window, "load", QUnit.load );
-
-// `onErrorFnPrev` initialized at top of scope
-// Preserve other handlers
-onErrorFnPrev = window.onerror;
-
-// Cover uncaught exceptions
-// Returning true will surpress the default browser handler,
-// returning false will let it run.
-window.onerror = function ( error, filePath, linerNr ) {
- var ret = false;
- if ( onErrorFnPrev ) {
- ret = onErrorFnPrev( error, filePath, linerNr );
- }
-
- // Treat return value as window.onerror itself does,
- // Only do our handling if not surpressed.
- if ( ret !== true ) {
- if ( QUnit.config.current ) {
- if ( QUnit.config.current.ignoreGlobalErrors ) {
- return true;
- }
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- } else {
- QUnit.test( "global failure", extend( function() {
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- }, { validTest: validTest } ) );
- }
- return false;
- }
-
- return ret;
-};
-
-function done() {
- config.autorun = true;
-
- // Log the last module results
- if ( config.currentModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.currentModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
-
- var i, key,
- banner = id( "qunit-banner" ),
- tests = id( "qunit-tests" ),
- runtime = +new Date() - config.started,
- passed = config.stats.all - config.stats.bad,
- html = [
- "Tests completed in ",
- runtime,
- " milliseconds.
",
- "",
- passed,
- " assertions of ",
- config.stats.all,
- " passed, ",
- config.stats.bad,
- " failed."
- ].join( "" );
-
- if ( banner ) {
- banner.className = ( config.stats.bad ? "qunit-fail" : "qunit-pass" );
- }
-
- if ( tests ) {
- id( "qunit-testresult" ).innerHTML = html;
- }
-
- if ( config.altertitle && typeof document !== "undefined" && document.title ) {
- // show ✖ for good, ✔ for bad suite result in title
- // use escape sequences in case file gets loaded with non-utf-8-charset
- document.title = [
- ( config.stats.bad ? "\u2716" : "\u2714" ),
- document.title.replace( /^[\u2714\u2716] /i, "" )
- ].join( " " );
- }
-
- // clear own sessionStorage items if all tests passed
- if ( config.reorder && defined.sessionStorage && config.stats.bad === 0 ) {
- // `key` & `i` initialized at top of scope
- for ( i = 0; i < sessionStorage.length; i++ ) {
- key = sessionStorage.key( i++ );
- if ( key.indexOf( "qunit-test-" ) === 0 ) {
- sessionStorage.removeItem( key );
- }
- }
- }
-
- // scroll back to top to show results
- if ( window.scrollTo ) {
- window.scrollTo(0, 0);
- }
-
- runLoggingCallbacks( "done", QUnit, {
- failed: config.stats.bad,
- passed: passed,
- total: config.stats.all,
- runtime: runtime
- });
-}
-
-/** @return Boolean: true if this test should be ran */
-function validTest( test ) {
- var include,
- filter = config.filter && config.filter.toLowerCase(),
- module = config.module && config.module.toLowerCase(),
- fullName = (test.module + ": " + test.testName).toLowerCase();
-
- // Internally-generated tests are always valid
- if ( test.callback && test.callback.validTest === validTest ) {
- delete test.callback.validTest;
- return true;
- }
-
- if ( config.testNumber ) {
- return test.testNumber === config.testNumber;
- }
-
- if ( module && ( !test.module || test.module.toLowerCase() !== module ) ) {
- return false;
- }
-
- if ( !filter ) {
- return true;
- }
-
- include = filter.charAt( 0 ) !== "!";
- if ( !include ) {
- filter = filter.slice( 1 );
- }
-
- // If the filter matches, we need to honour include
- if ( fullName.indexOf( filter ) !== -1 ) {
- return include;
- }
-
- // Otherwise, do the opposite
- return !include;
-}
-
-// so far supports only Firefox, Chrome and Opera (buggy), Safari (for real exceptions)
-// Later Safari and IE10 are supposed to support error.stack as well
-// See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack
-function extractStacktrace( e, offset ) {
- offset = offset === undefined ? 3 : offset;
-
- var stack, include, i;
-
- if ( e.stacktrace ) {
- // Opera
- return e.stacktrace.split( "\n" )[ offset + 3 ];
- } else if ( e.stack ) {
- // Firefox, Chrome
- stack = e.stack.split( "\n" );
- if (/^error$/i.test( stack[0] ) ) {
- stack.shift();
- }
- if ( fileName ) {
- include = [];
- for ( i = offset; i < stack.length; i++ ) {
- if ( stack[ i ].indexOf( fileName ) !== -1 ) {
- break;
- }
- include.push( stack[ i ] );
- }
- if ( include.length ) {
- return include.join( "\n" );
- }
- }
- return stack[ offset ];
- } else if ( e.sourceURL ) {
- // Safari, PhantomJS
- // hopefully one day Safari provides actual stacktraces
- // exclude useless self-reference for generated Error objects
- if ( /qunit.js$/.test( e.sourceURL ) ) {
- return;
- }
- // for actual exceptions, this is useful
- return e.sourceURL + ":" + e.line;
- }
-}
-function sourceFromStacktrace( offset ) {
- try {
- throw new Error();
- } catch ( e ) {
- return extractStacktrace( e, offset );
- }
-}
-
-/**
- * Escape text for attribute or text content.
- */
-function escapeText( s ) {
- if ( !s ) {
- return "";
- }
- s = s + "";
- // Both single quotes and double quotes (for attributes)
- return s.replace( /['"<>&]/g, function( s ) {
- switch( s ) {
- case '\'':
- return ''';
- case '"':
- return '"';
- case '<':
- return '<';
- case '>':
- return '>';
- case '&':
- return '&';
- }
- });
-}
-
-function synchronize( callback, last ) {
- config.queue.push( callback );
-
- if ( config.autorun && !config.blocking ) {
- process( last );
- }
-}
-
-function process( last ) {
- function next() {
- process( last );
- }
- var start = new Date().getTime();
- config.depth = config.depth ? config.depth + 1 : 1;
-
- while ( config.queue.length && !config.blocking ) {
- if ( !defined.setTimeout || config.updateRate <= 0 || ( ( new Date().getTime() - start ) < config.updateRate ) ) {
- config.queue.shift()();
- } else {
- window.setTimeout( next, 13 );
- break;
- }
- }
- config.depth--;
- if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) {
- done();
- }
-}
-
-function saveGlobal() {
- config.pollution = [];
-
- if ( config.noglobals ) {
- for ( var key in window ) {
- // in Opera sometimes DOM element ids show up here, ignore them
- if ( !hasOwn.call( window, key ) || /^qunit-test-output/.test( key ) ) {
- continue;
- }
- config.pollution.push( key );
- }
- }
-}
-
-function checkPollution() {
- var newGlobals,
- deletedGlobals,
- old = config.pollution;
-
- saveGlobal();
-
- newGlobals = diff( config.pollution, old );
- if ( newGlobals.length > 0 ) {
- QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join(", ") );
- }
-
- deletedGlobals = diff( old, config.pollution );
- if ( deletedGlobals.length > 0 ) {
- QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join(", ") );
- }
-}
-
-// returns a new Array with the elements that are in a but not in b
-function diff( a, b ) {
- var i, j,
- result = a.slice();
-
- for ( i = 0; i < result.length; i++ ) {
- for ( j = 0; j < b.length; j++ ) {
- if ( result[i] === b[j] ) {
- result.splice( i, 1 );
- i--;
- break;
- }
- }
- }
- return result;
-}
-
-function extend( a, b ) {
- for ( var prop in b ) {
- if ( b[ prop ] === undefined ) {
- delete a[ prop ];
-
- // Avoid "Member not found" error in IE8 caused by setting window.constructor
- } else if ( prop !== "constructor" || a !== window ) {
- a[ prop ] = b[ prop ];
- }
- }
-
- return a;
-}
-
-/**
- * @param {HTMLElement} elem
- * @param {string} type
- * @param {Function} fn
- */
-function addEvent( elem, type, fn ) {
- // Standards-based browsers
- if ( elem.addEventListener ) {
- elem.addEventListener( type, fn, false );
- // IE
- } else {
- elem.attachEvent( "on" + type, fn );
- }
-}
-
-/**
- * @param {Array|NodeList} elems
- * @param {string} type
- * @param {Function} fn
- */
-function addEvents( elems, type, fn ) {
- var i = elems.length;
- while ( i-- ) {
- addEvent( elems[i], type, fn );
- }
-}
-
-function hasClass( elem, name ) {
- return (" " + elem.className + " ").indexOf(" " + name + " ") > -1;
-}
-
-function addClass( elem, name ) {
- if ( !hasClass( elem, name ) ) {
- elem.className += (elem.className ? " " : "") + name;
- }
-}
-
-function removeClass( elem, name ) {
- var set = " " + elem.className + " ";
- // Class name may appear multiple times
- while ( set.indexOf(" " + name + " ") > -1 ) {
- set = set.replace(" " + name + " " , " ");
- }
- // If possible, trim it for prettiness, but not neccecarily
- elem.className = window.jQuery ? jQuery.trim( set ) : ( set.trim ? set.trim() : set );
-}
-
-function id( name ) {
- return !!( typeof document !== "undefined" && document && document.getElementById ) &&
- document.getElementById( name );
-}
-
-function registerLoggingCallback( key ) {
- return function( callback ) {
- config[key].push( callback );
- };
-}
-
-// Supports deprecated method of completely overwriting logging callbacks
-function runLoggingCallbacks( key, scope, args ) {
- var i, callbacks;
- if ( QUnit.hasOwnProperty( key ) ) {
- QUnit[ key ].call(scope, args );
- } else {
- callbacks = config[ key ];
- for ( i = 0; i < callbacks.length; i++ ) {
- callbacks[ i ].call( scope, args );
- }
- }
-}
-
-// Test for equality any JavaScript type.
-// Author: Philippe Rathé
-QUnit.equiv = (function() {
-
- // Call the o related callback with the given arguments.
- function bindCallbacks( o, callbacks, args ) {
- var prop = QUnit.objectType( o );
- if ( prop ) {
- if ( QUnit.objectType( callbacks[ prop ] ) === "function" ) {
- return callbacks[ prop ].apply( callbacks, args );
- } else {
- return callbacks[ prop ]; // or undefined
- }
- }
- }
-
- // the real equiv function
- var innerEquiv,
- // stack to decide between skip/abort functions
- callers = [],
- // stack to avoiding loops from circular referencing
- parents = [],
-
- getProto = Object.getPrototypeOf || function ( obj ) {
- return obj.__proto__;
- },
- callbacks = (function () {
-
- // for string, boolean, number and null
- function useStrictEquality( b, a ) {
- /*jshint eqeqeq:false */
- if ( b instanceof a.constructor || a instanceof b.constructor ) {
- // to catch short annotaion VS 'new' annotation of a
- // declaration
- // e.g. var i = 1;
- // var j = new Number(1);
- return a == b;
- } else {
- return a === b;
- }
- }
-
- return {
- "string": useStrictEquality,
- "boolean": useStrictEquality,
- "number": useStrictEquality,
- "null": useStrictEquality,
- "undefined": useStrictEquality,
-
- "nan": function( b ) {
- return isNaN( b );
- },
-
- "date": function( b, a ) {
- return QUnit.objectType( b ) === "date" && a.valueOf() === b.valueOf();
- },
-
- "regexp": function( b, a ) {
- return QUnit.objectType( b ) === "regexp" &&
- // the regex itself
- a.source === b.source &&
- // and its modifers
- a.global === b.global &&
- // (gmi) ...
- a.ignoreCase === b.ignoreCase &&
- a.multiline === b.multiline &&
- a.sticky === b.sticky;
- },
-
- // - skip when the property is a method of an instance (OOP)
- // - abort otherwise,
- // initial === would have catch identical references anyway
- "function": function() {
- var caller = callers[callers.length - 1];
- return caller !== Object && typeof caller !== "undefined";
- },
-
- "array": function( b, a ) {
- var i, j, len, loop;
-
- // b could be an object literal here
- if ( QUnit.objectType( b ) !== "array" ) {
- return false;
- }
-
- len = a.length;
- if ( len !== b.length ) {
- // safe and faster
- return false;
- }
-
- // track reference to avoid circular references
- parents.push( a );
- for ( i = 0; i < len; i++ ) {
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- loop = true;// dont rewalk array
- }
- }
- if ( !loop && !innerEquiv(a[i], b[i]) ) {
- parents.pop();
- return false;
- }
- }
- parents.pop();
- return true;
- },
-
- "object": function( b, a ) {
- var i, j, loop,
- // Default to true
- eq = true,
- aProperties = [],
- bProperties = [];
-
- // comparing constructors is more strict than using
- // instanceof
- if ( a.constructor !== b.constructor ) {
- // Allow objects with no prototype to be equivalent to
- // objects with Object as their constructor.
- if ( !(( getProto(a) === null && getProto(b) === Object.prototype ) ||
- ( getProto(b) === null && getProto(a) === Object.prototype ) ) ) {
- return false;
- }
- }
-
- // stack constructor before traversing properties
- callers.push( a.constructor );
- // track reference to avoid circular references
- parents.push( a );
-
- for ( i in a ) { // be strict: don't ensures hasOwnProperty
- // and go deep
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- // don't go down the same path twice
- loop = true;
- }
- }
- aProperties.push(i); // collect a's properties
-
- if (!loop && !innerEquiv( a[i], b[i] ) ) {
- eq = false;
- break;
- }
- }
-
- callers.pop(); // unstack, we are done
- parents.pop();
-
- for ( i in b ) {
- bProperties.push( i ); // collect b's properties
- }
-
- // Ensures identical properties name
- return eq && innerEquiv( aProperties.sort(), bProperties.sort() );
- }
- };
- }());
-
- innerEquiv = function() { // can take multiple arguments
- var args = [].slice.apply( arguments );
- if ( args.length < 2 ) {
- return true; // end transition
- }
-
- return (function( a, b ) {
- if ( a === b ) {
- return true; // catch the most you can
- } else if ( a === null || b === null || typeof a === "undefined" ||
- typeof b === "undefined" ||
- QUnit.objectType(a) !== QUnit.objectType(b) ) {
- return false; // don't lose time with error prone cases
- } else {
- return bindCallbacks(a, callbacks, [ b, a ]);
- }
-
- // apply transition with (1..n) arguments
- }( args[0], args[1] ) && arguments.callee.apply( this, args.splice(1, args.length - 1 )) );
- };
-
- return innerEquiv;
-}());
-
-/**
- * jsDump Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com |
- * http://flesler.blogspot.com Licensed under BSD
- * (http://www.opensource.org/licenses/bsd-license.php) Date: 5/15/2008
- *
- * @projectDescription Advanced and extensible data dumping for Javascript.
- * @version 1.0.0
- * @author Ariel Flesler
- * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html}
- */
-QUnit.jsDump = (function() {
- function quote( str ) {
- return '"' + str.toString().replace( /"/g, '\\"' ) + '"';
- }
- function literal( o ) {
- return o + "";
- }
- function join( pre, arr, post ) {
- var s = jsDump.separator(),
- base = jsDump.indent(),
- inner = jsDump.indent(1);
- if ( arr.join ) {
- arr = arr.join( "," + s + inner );
- }
- if ( !arr ) {
- return pre + post;
- }
- return [ pre, inner + arr, base + post ].join(s);
- }
- function array( arr, stack ) {
- var i = arr.length, ret = new Array(i);
- this.up();
- while ( i-- ) {
- ret[i] = this.parse( arr[i] , undefined , stack);
- }
- this.down();
- return join( "[", ret, "]" );
- }
-
- var reName = /^function (\w+)/,
- jsDump = {
- // type is used mostly internally, you can fix a (custom)type in advance
- parse: function( obj, type, stack ) {
- stack = stack || [ ];
- var inStack, res,
- parser = this.parsers[ type || this.typeOf(obj) ];
-
- type = typeof parser;
- inStack = inArray( obj, stack );
-
- if ( inStack !== -1 ) {
- return "recursion(" + (inStack - stack.length) + ")";
- }
- if ( type === "function" ) {
- stack.push( obj );
- res = parser.call( this, obj, stack );
- stack.pop();
- return res;
- }
- return ( type === "string" ) ? parser : this.parsers.error;
- },
- typeOf: function( obj ) {
- var type;
- if ( obj === null ) {
- type = "null";
- } else if ( typeof obj === "undefined" ) {
- type = "undefined";
- } else if ( QUnit.is( "regexp", obj) ) {
- type = "regexp";
- } else if ( QUnit.is( "date", obj) ) {
- type = "date";
- } else if ( QUnit.is( "function", obj) ) {
- type = "function";
- } else if ( typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined" ) {
- type = "window";
- } else if ( obj.nodeType === 9 ) {
- type = "document";
- } else if ( obj.nodeType ) {
- type = "node";
- } else if (
- // native arrays
- toString.call( obj ) === "[object Array]" ||
- // NodeList objects
- ( typeof obj.length === "number" && typeof obj.item !== "undefined" && ( obj.length ? obj.item(0) === obj[0] : ( obj.item( 0 ) === null && typeof obj[0] === "undefined" ) ) )
- ) {
- type = "array";
- } else if ( obj.constructor === Error.prototype.constructor ) {
- type = "error";
- } else {
- type = typeof obj;
- }
- return type;
- },
- separator: function() {
- return this.multiline ? this.HTML ? "
" : "\n" : this.HTML ? " " : " ";
- },
- // extra can be a number, shortcut for increasing-calling-decreasing
- indent: function( extra ) {
- if ( !this.multiline ) {
- return "";
- }
- var chr = this.indentChar;
- if ( this.HTML ) {
- chr = chr.replace( /\t/g, " " ).replace( / /g, " " );
- }
- return new Array( this._depth_ + (extra||0) ).join(chr);
- },
- up: function( a ) {
- this._depth_ += a || 1;
- },
- down: function( a ) {
- this._depth_ -= a || 1;
- },
- setParser: function( name, parser ) {
- this.parsers[name] = parser;
- },
- // The next 3 are exposed so you can use them
- quote: quote,
- literal: literal,
- join: join,
- //
- _depth_: 1,
- // This is the list of parsers, to modify them, use jsDump.setParser
- parsers: {
- window: "[Window]",
- document: "[Document]",
- error: function(error) {
- return "Error(\"" + error.message + "\")";
- },
- unknown: "[Unknown]",
- "null": "null",
- "undefined": "undefined",
- "function": function( fn ) {
- var ret = "function",
- // functions never have name in IE
- name = "name" in fn ? fn.name : (reName.exec(fn) || [])[1];
-
- if ( name ) {
- ret += " " + name;
- }
- ret += "( ";
-
- ret = [ ret, QUnit.jsDump.parse( fn, "functionArgs" ), "){" ].join( "" );
- return join( ret, QUnit.jsDump.parse(fn,"functionCode" ), "}" );
- },
- array: array,
- nodelist: array,
- "arguments": array,
- object: function( map, stack ) {
- var ret = [ ], keys, key, val, i;
- QUnit.jsDump.up();
- keys = [];
- for ( key in map ) {
- keys.push( key );
- }
- keys.sort();
- for ( i = 0; i < keys.length; i++ ) {
- key = keys[ i ];
- val = map[ key ];
- ret.push( QUnit.jsDump.parse( key, "key" ) + ": " + QUnit.jsDump.parse( val, undefined, stack ) );
- }
- QUnit.jsDump.down();
- return join( "{", ret, "}" );
- },
- node: function( node ) {
- var len, i, val,
- open = QUnit.jsDump.HTML ? "<" : "<",
- close = QUnit.jsDump.HTML ? ">" : ">",
- tag = node.nodeName.toLowerCase(),
- ret = open + tag,
- attrs = node.attributes;
-
- if ( attrs ) {
- for ( i = 0, len = attrs.length; i < len; i++ ) {
- val = attrs[i].nodeValue;
- // IE6 includes all attributes in .attributes, even ones not explicitly set.
- // Those have values like undefined, null, 0, false, "" or "inherit".
- if ( val && val !== "inherit" ) {
- ret += " " + attrs[i].nodeName + "=" + QUnit.jsDump.parse( val, "attribute" );
- }
- }
- }
- ret += close;
-
- // Show content of TextNode or CDATASection
- if ( node.nodeType === 3 || node.nodeType === 4 ) {
- ret += node.nodeValue;
- }
-
- return ret + open + "/" + tag + close;
- },
- // function calls it internally, it's the arguments part of the function
- functionArgs: function( fn ) {
- var args,
- l = fn.length;
-
- if ( !l ) {
- return "";
- }
-
- args = new Array(l);
- while ( l-- ) {
- // 97 is 'a'
- args[l] = String.fromCharCode(97+l);
- }
- return " " + args.join( ", " ) + " ";
- },
- // object calls it internally, the key part of an item in a map
- key: quote,
- // function calls it internally, it's the content of the function
- functionCode: "[code]",
- // node calls it internally, it's an html attribute value
- attribute: quote,
- string: quote,
- date: quote,
- regexp: literal,
- number: literal,
- "boolean": literal
- },
- // if true, entities are escaped ( <, >, \t, space and \n )
- HTML: false,
- // indentation unit
- indentChar: " ",
- // if true, items in a collection, are separated by a \n, else just a space.
- multiline: true
- };
-
- return jsDump;
-}());
-
-// from jquery.js
-function inArray( elem, array ) {
- if ( array.indexOf ) {
- return array.indexOf( elem );
- }
-
- for ( var i = 0, length = array.length; i < length; i++ ) {
- if ( array[ i ] === elem ) {
- return i;
- }
- }
-
- return -1;
-}
-
-/*
- * Javascript Diff Algorithm
- * By John Resig (http://ejohn.org/)
- * Modified by Chu Alan "sprite"
- *
- * Released under the MIT license.
- *
- * More Info:
- * http://ejohn.org/projects/javascript-diff-algorithm/
- *
- * Usage: QUnit.diff(expected, actual)
- *
- * QUnit.diff( "the quick brown fox jumped over", "the quick fox jumps over" ) == "the quick brown fox jumped jumps over"
- */
-QUnit.diff = (function() {
- /*jshint eqeqeq:false, eqnull:true */
- function diff( o, n ) {
- var i,
- ns = {},
- os = {};
-
- for ( i = 0; i < n.length; i++ ) {
- if ( !hasOwn.call( ns, n[i] ) ) {
- ns[ n[i] ] = {
- rows: [],
- o: null
- };
- }
- ns[ n[i] ].rows.push( i );
- }
-
- for ( i = 0; i < o.length; i++ ) {
- if ( !hasOwn.call( os, o[i] ) ) {
- os[ o[i] ] = {
- rows: [],
- n: null
- };
- }
- os[ o[i] ].rows.push( i );
- }
-
- for ( i in ns ) {
- if ( !hasOwn.call( ns, i ) ) {
- continue;
- }
- if ( ns[i].rows.length === 1 && hasOwn.call( os, i ) && os[i].rows.length === 1 ) {
- n[ ns[i].rows[0] ] = {
- text: n[ ns[i].rows[0] ],
- row: os[i].rows[0]
- };
- o[ os[i].rows[0] ] = {
- text: o[ os[i].rows[0] ],
- row: ns[i].rows[0]
- };
- }
- }
-
- for ( i = 0; i < n.length - 1; i++ ) {
- if ( n[i].text != null && n[ i + 1 ].text == null && n[i].row + 1 < o.length && o[ n[i].row + 1 ].text == null &&
- n[ i + 1 ] == o[ n[i].row + 1 ] ) {
-
- n[ i + 1 ] = {
- text: n[ i + 1 ],
- row: n[i].row + 1
- };
- o[ n[i].row + 1 ] = {
- text: o[ n[i].row + 1 ],
- row: i + 1
- };
- }
- }
-
- for ( i = n.length - 1; i > 0; i-- ) {
- if ( n[i].text != null && n[ i - 1 ].text == null && n[i].row > 0 && o[ n[i].row - 1 ].text == null &&
- n[ i - 1 ] == o[ n[i].row - 1 ]) {
-
- n[ i - 1 ] = {
- text: n[ i - 1 ],
- row: n[i].row - 1
- };
- o[ n[i].row - 1 ] = {
- text: o[ n[i].row - 1 ],
- row: i - 1
- };
- }
- }
-
- return {
- o: o,
- n: n
- };
- }
-
- return function( o, n ) {
- o = o.replace( /\s+$/, "" );
- n = n.replace( /\s+$/, "" );
-
- var i, pre,
- str = "",
- out = diff( o === "" ? [] : o.split(/\s+/), n === "" ? [] : n.split(/\s+/) ),
- oSpace = o.match(/\s+/g),
- nSpace = n.match(/\s+/g);
-
- if ( oSpace == null ) {
- oSpace = [ " " ];
- }
- else {
- oSpace.push( " " );
- }
-
- if ( nSpace == null ) {
- nSpace = [ " " ];
- }
- else {
- nSpace.push( " " );
- }
-
- if ( out.n.length === 0 ) {
- for ( i = 0; i < out.o.length; i++ ) {
- str += "" + out.o[i] + oSpace[i] + "";
- }
- }
- else {
- if ( out.n[0].text == null ) {
- for ( n = 0; n < out.o.length && out.o[n].text == null; n++ ) {
- str += "" + out.o[n] + oSpace[n] + "";
- }
- }
-
- for ( i = 0; i < out.n.length; i++ ) {
- if (out.n[i].text == null) {
- str += "" + out.n[i] + nSpace[i] + "";
- }
- else {
- // `pre` initialized at top of scope
- pre = "";
-
- for ( n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++ ) {
- pre += "" + out.o[n] + oSpace[n] + "";
- }
- str += " " + out.n[i].text + nSpace[i] + pre;
- }
- }
- }
-
- return str;
- };
-}());
-
-// for CommonJS enviroments, export everything
-if ( typeof exports !== "undefined" ) {
- extend( exports, QUnit );
-}
-
-// get at whatever the global object is, like window in browsers
-}( (function() {return this;}.call()) ));
diff --git a/test/lib/require.js b/test/lib/require.js
deleted file mode 100644
index 987f865..0000000
--- a/test/lib/require.js
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- RequireJS 2.1.5 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.
- Available via the MIT or new BSD license.
- see: http://github.com/jrburke/requirejs for details
-*/
-var requirejs,require,define;
-(function(aa){function I(b){return"[object Function]"===L.call(b)}function J(b){return"[object Array]"===L.call(b)}function y(b,c){if(b){var d;for(d=0;dthis.depCount&&!this.defined){if(I(n)){if(this.events.error)try{e=i.execCb(c,n,b,e)}catch(d){a=d}else e=i.execCb(c,n,b,e);this.map.isDefine&&((b=this.module)&&void 0!==b.exports&&b.exports!==this.exports?e=b.exports:void 0===e&&this.usingExports&&(e=this.exports));if(a)return a.requireMap=this.map,a.requireModules=[this.map.id],a.requireType="define",v(this.error=
-a)}else e=n;this.exports=e;if(this.map.isDefine&&!this.ignore&&(q[c]=e,l.onResourceLoad))l.onResourceLoad(i,this.map,this.depMaps);x(c);this.defined=!0}this.defining=!1;this.defined&&!this.defineEmitted&&(this.defineEmitted=!0,this.emit("defined",this.exports),this.defineEmitComplete=!0)}}else this.fetch()}},callPlugin:function(){var a=this.map,b=a.id,d=j(a.prefix);this.depMaps.push(d);t(d,"defined",u(this,function(e){var n,d;d=this.map.name;var g=this.map.parentMap?this.map.parentMap.name:null,h=
-i.makeRequire(a.parentMap,{enableBuildCallback:!0});if(this.map.unnormalized){if(e.normalize&&(d=e.normalize(d,function(a){return c(a,g,!0)})||""),e=j(a.prefix+"!"+d,this.map.parentMap),t(e,"defined",u(this,function(a){this.init([],function(){return a},null,{enabled:!0,ignore:!0})})),d=m(p,e.id)){this.depMaps.push(e);if(this.events.error)d.on("error",u(this,function(a){this.emit("error",a)}));d.enable()}}else n=u(this,function(a){this.init([],function(){return a},null,{enabled:!0})}),n.error=u(this,
-function(a){this.inited=!0;this.error=a;a.requireModules=[b];G(p,function(a){0===a.map.id.indexOf(b+"_unnormalized")&&x(a.map.id)});v(a)}),n.fromText=u(this,function(e,c){var d=a.name,g=j(d),C=O;c&&(e=c);C&&(O=!1);r(g);s(k.config,b)&&(k.config[d]=k.config[b]);try{l.exec(e)}catch(ca){return v(B("fromtexteval","fromText eval for "+b+" failed: "+ca,ca,[b]))}C&&(O=!0);this.depMaps.push(g);i.completeLoad(d);h([d],n)}),e.load(a.name,h,n,k)}));i.enable(d,this);this.pluginMaps[d.id]=d},enable:function(){V[this.map.id]=
-this;this.enabling=this.enabled=!0;y(this.depMaps,u(this,function(a,b){var c,e;if("string"===typeof a){a=j(a,this.map.isDefine?this.map:this.map.parentMap,!1,!this.skipMap);this.depMaps[b]=a;if(c=m(N,a.id)){this.depExports[b]=c(this);return}this.depCount+=1;t(a,"defined",u(this,function(a){this.defineDep(b,a);this.check()}));this.errback&&t(a,"error",this.errback)}c=a.id;e=p[c];!s(N,c)&&(e&&!e.enabled)&&i.enable(a,this)}));G(this.pluginMaps,u(this,function(a){var b=m(p,a.id);b&&!b.enabled&&i.enable(a,
-this)}));this.enabling=!1;this.check()},on:function(a,b){var c=this.events[a];c||(c=this.events[a]=[]);c.push(b)},emit:function(a,b){y(this.events[a],function(a){a(b)});"error"===a&&delete this.events[a]}};i={config:k,contextName:b,registry:p,defined:q,urlFetched:U,defQueue:H,Module:Z,makeModuleMap:j,nextTick:l.nextTick,onError:v,configure:function(a){a.baseUrl&&"/"!==a.baseUrl.charAt(a.baseUrl.length-1)&&(a.baseUrl+="/");var b=k.pkgs,c=k.shim,e={paths:!0,config:!0,map:!0};G(a,function(a,b){e[b]?
-"map"===b?(k.map||(k.map={}),R(k[b],a,!0,!0)):R(k[b],a,!0):k[b]=a});a.shim&&(G(a.shim,function(a,b){J(a)&&(a={deps:a});if((a.exports||a.init)&&!a.exportsFn)a.exportsFn=i.makeShimExports(a);c[b]=a}),k.shim=c);a.packages&&(y(a.packages,function(a){a="string"===typeof a?{name:a}:a;b[a.name]={name:a.name,location:a.location||a.name,main:(a.main||"main").replace(ja,"").replace(ea,"")}}),k.pkgs=b);G(p,function(a,b){!a.inited&&!a.map.unnormalized&&(a.map=j(b))});if(a.deps||a.callback)i.require(a.deps||[],
-a.callback)},makeShimExports:function(a){return function(){var b;a.init&&(b=a.init.apply(aa,arguments));return b||a.exports&&ba(a.exports)}},makeRequire:function(a,f){function d(e,c,h){var g,k;f.enableBuildCallback&&(c&&I(c))&&(c.__requireJsBuild=!0);if("string"===typeof e){if(I(c))return v(B("requireargs","Invalid require call"),h);if(a&&s(N,e))return N[e](p[a.id]);if(l.get)return l.get(i,e,a,d);g=j(e,a,!1,!0);g=g.id;return!s(q,g)?v(B("notloaded",'Module name "'+g+'" has not been loaded yet for context: '+
-b+(a?"":". Use require([])"))):q[g]}L();i.nextTick(function(){L();k=r(j(null,a));k.skipMap=f.skipMap;k.init(e,c,h,{enabled:!0});D()});return d}f=f||{};R(d,{isBrowser:A,toUrl:function(b){var d,f=b.lastIndexOf("."),g=b.split("/")[0];if(-1!==f&&(!("."===g||".."===g)||1h.attachEvent.toString().indexOf("[native code"))&&!Y?(O=!0,h.attachEvent("onreadystatechange",b.onScriptLoad)):(h.addEventListener("load",b.onScriptLoad,!1),h.addEventListener("error",b.onScriptError,!1)),h.src=d,K=h,D?x.insertBefore(h,D):x.appendChild(h),K=null,h;if(da)try{importScripts(d),b.completeLoad(c)}catch(j){b.onError(B("importscripts","importScripts failed for "+c+" at "+d,j,[c]))}};A&&M(document.getElementsByTagName("script"),function(b){x||(x=
-b.parentNode);if(t=b.getAttribute("data-main"))return r.baseUrl||(E=t.split("/"),Q=E.pop(),fa=E.length?E.join("/")+"/":"./",r.baseUrl=fa,t=Q),t=t.replace(ea,""),r.deps=r.deps?r.deps.concat(t):[t],!0});define=function(b,c,d){var l,h;"string"!==typeof b&&(d=c,c=b,b=null);J(c)||(d=c,c=[]);!c.length&&I(d)&&d.length&&(d.toString().replace(la,"").replace(ma,function(b,d){c.push(d)}),c=(1===d.length?["require"]:["require","exports","module"]).concat(c));if(O){if(!(l=K))P&&"interactive"===P.readyState||M(document.getElementsByTagName("script"),
-function(b){if("interactive"===b.readyState)return P=b}),l=P;l&&(b||(b=l.getAttribute("data-requiremodule")),h=F[l.getAttribute("data-requirecontext")])}(h?h.defQueue:T).push([b,c,d])};define.amd={jQuery:!0};l.exec=function(b){return eval(b)};l(r)}})(this);
diff --git a/test/lib/resemble.js b/test/lib/resemble.js
new file mode 100644
index 0000000..1cb8c29
--- /dev/null
+++ b/test/lib/resemble.js
@@ -0,0 +1,535 @@
+/*
+Author: James Cryer
+Company: Huddle
+Last updated date: 21 Feb 2013
+URL: https://github.com/Huddle/Resemble.js
+*/
+
+(function(_this){
+ 'use strict';
+
+ _this['resemble'] = function( fileData ){
+
+ var data = {};
+ var images = [];
+ var updateCallbackArray = [];
+
+ var tolerance = { // between 0 and 255
+ red: 16,
+ green: 16,
+ blue: 16,
+ minBrightness: 16,
+ maxBrightness: 240
+ };
+
+ var ignoreAntialiasing = false;
+ var ignoreColors = false;
+
+ function triggerDataUpdate(){
+ var len = updateCallbackArray.length;
+ var i;
+ for(i=0;i tolerance.maxBrightness;
+ }
+
+ function getHue(r,g,b){
+
+ r = r / 255;
+ g = g / 255;
+ b = b / 255;
+ var max = Math.max(r, g, b), min = Math.min(r, g, b);
+ var h;
+ var d;
+
+ if (max == min){
+ h = 0; // achromatic
+ } else{
+ d = max - min;
+ switch(max){
+ case r: h = (g - b) / d + (g < b ? 6 : 0); break;
+ case g: h = (b - r) / d + 2; break;
+ case b: h = (r - g) / d + 4; break;
+ }
+ h /= 6;
+ }
+
+ return h;
+ }
+
+ function isAntialiased(sourcePix, data, cacheSet, verticalPos, horizontalPos, width){
+ var offset;
+ var targetPix;
+ var distance = 1;
+ var i;
+ var j;
+ var hasHighContrastSibling = 0;
+ var hasSiblingWithDifferentHue = 0;
+ var hasEquivilantSibling = 0;
+
+ addHueInfo(sourcePix);
+
+ for (i = distance*-1; i <= distance; i++){
+ for (j = distance*-1; j <= distance; j++){
+
+ if(i===0 && j===0){
+ // ignore source pixel
+ } else {
+
+ offset = ((verticalPos+j)*width + (horizontalPos+i)) * 4;
+ targetPix = getPixelInfo(data, offset, cacheSet);
+
+ if(targetPix === null){
+ continue;
+ }
+
+ addBrightnessInfo(targetPix);
+ addHueInfo(targetPix);
+
+ if( isContrasting(sourcePix, targetPix) ){
+ hasHighContrastSibling++;
+ }
+
+ if( isRGBSame(sourcePix,targetPix) ){
+ hasEquivilantSibling++;
+ }
+
+ if( Math.abs(targetPix.h - sourcePix.h) > 0.3 ){
+ hasSiblingWithDifferentHue++;
+ }
+
+ if( hasSiblingWithDifferentHue > 1 || hasHighContrastSibling > 1){
+ return true;
+ }
+ }
+ }
+ }
+
+ if(hasEquivilantSibling < 2){
+ return true;
+ }
+
+ return false;
+ }
+
+ function errorPixel(px, offset){
+ px[offset] = 255; //r
+ px[offset + 1] = 0; //g
+ px[offset + 2] = 255; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyPixel(px, offset, data){
+ px[offset] = data.r; //r
+ px[offset + 1] = data.g; //g
+ px[offset + 2] = data.b; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyGrayScalePixel(px, offset, data){
+ px[offset] = data.brightness; //r
+ px[offset + 1] = data.brightness; //g
+ px[offset + 2] = data.brightness; //b
+ px[offset + 3] = 255; //a
+ }
+
+
+ function getPixelInfo(data, offset, cacheSet){
+ var r;
+ var g;
+ var b;
+ var d;
+
+ if(typeof data[offset] !== 'undefined'){
+ r = data[offset];
+ g = data[offset+1];
+ b = data[offset+2];
+ d = {
+ r: r,
+ g: g,
+ b: b
+ };
+
+ return d;
+ } else {
+ return null;
+ }
+ }
+
+ function addBrightnessInfo(data){
+ data.brightness = getBrightness(data.r,data.g,data.b); // 'corrected' lightness
+ }
+
+ function addHueInfo(data){
+ data.h = getHue(data.r,data.g,data.b);
+ }
+
+ function analyseImages(img1, img2, width, height){
+
+ var hiddenCanvas = document.createElement('canvas');
+
+ var data1 = img1.data;
+ var data2 = img2.data;
+
+ hiddenCanvas.width = width;
+ hiddenCanvas.height = height;
+
+ var context = hiddenCanvas.getContext('2d');
+ var imgd = context.createImageData(width,height);
+ var targetPix = imgd.data;
+
+ var mismatchCount = 0;
+
+ var time = Date.now();
+
+ var skip;
+
+ if( (width > 1200 || height > 1200) && ignoreAntialiasing){
+ skip = 6;
+ }
+
+ loop(height, width, function(verticalPos, horizontalPos){
+
+ if(skip){ // only skip if the image isn't small
+ if(verticalPos % skip === 0 || horizontalPos % skip === 0){
+ return;
+ }
+ }
+
+ var offset = (verticalPos*width + horizontalPos) * 4;
+ var pixel1 = getPixelInfo(data1, offset, 1);
+ var pixel2 = getPixelInfo(data2, offset, 2);
+
+ if(pixel1 === null || pixel2 === null){
+ return;
+ }
+
+ if (ignoreColors){
+
+ addBrightnessInfo(pixel1);
+ addBrightnessInfo(pixel2);
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ return;
+ }
+
+ if( isRGBSimilar(pixel1, pixel2) ){
+ copyPixel(targetPix, offset, pixel2);
+
+ } else if( ignoreAntialiasing && (
+ addBrightnessInfo(pixel1), // jit pixel info augmentation looks a little weird, sorry.
+ addBrightnessInfo(pixel2),
+ isAntialiased(pixel1, data1, 1, verticalPos, horizontalPos, width) ||
+ isAntialiased(pixel2, data2, 2, verticalPos, horizontalPos, width)
+ )){
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+
+ });
+
+ data.misMatchPercentage = (mismatchCount / (height*width) * 100).toFixed(2);
+ data.analysisTime = Date.now() - time;
+
+ data.getImageDataUrl = function(text){
+ var barHeight = 0;
+
+ if(text){
+ barHeight = addLabel(text,context,hiddenCanvas);
+ }
+
+ context.putImageData(imgd, 0, barHeight);
+
+ return hiddenCanvas.toDataURL("image/png");
+ };
+ }
+
+ function addLabel(text, context, hiddenCanvas){
+ var textPadding = 2;
+
+ context.font = '12px sans-serif';
+
+ var textWidth = context.measureText(text).width + textPadding*2;
+ var barHeight = 22;
+
+ if(textWidth > hiddenCanvas.width){
+ hiddenCanvas.width = textWidth;
+ }
+
+ hiddenCanvas.height += barHeight;
+
+ context.fillStyle = "#666";
+ context.fillRect(0,0,hiddenCanvas.width,barHeight -4);
+ context.fillStyle = "#fff";
+ context.fillRect(0,barHeight -4,hiddenCanvas.width, 4);
+
+ context.fillStyle = "#fff";
+ context.textBaseline = "top";
+ context.font = '12px sans-serif';
+ context.fillText(text, textPadding, 1);
+
+ return barHeight;
+ }
+
+ function normalise(img, w, h){
+ var c;
+ var context;
+
+ if(img.height < h || img.width < w){
+ c = document.createElement('canvas');
+ c.width = w;
+ c.height = h;
+ context = c.getContext('2d');
+ context.putImageData(img, 0, 0);
+ return context.getImageData(0, 0, w, h);
+ }
+
+ return img;
+ }
+
+ function compare(one, two){
+
+ function onceWeHaveBoth(){
+ var width;
+ var height;
+ if(images.length === 2){
+ width = images[0].width > images[1].width ? images[0].width : images[1].width;
+ height = images[0].height > images[1].height ? images[0].height : images[1].height;
+
+ if( (images[0].width === images[1].width) && (images[0].height === images[1].height) ){
+ data.isSameDimensions = true;
+ } else {
+ data.isSameDimensions = false;
+ }
+
+ analyseImages( normalise(images[0],width, height), normalise(images[1],width, height), width, height);
+
+ triggerDataUpdate();
+ }
+ }
+
+ images = [];
+ loadImageData(one, onceWeHaveBoth);
+ loadImageData(two, onceWeHaveBoth);
+ }
+
+ function getCompareApi(param){
+
+ var secondFileData,
+ hasMethod = typeof param === 'function';
+
+ if( !hasMethod ){
+ // assume it's file data
+ secondFileData = param;
+ }
+
+ var self = {
+ ignoreNothing: function(){
+
+ tolerance.red = 16;
+ tolerance.green = 16;
+ tolerance.blue = 16;
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreAntialiasing: function(){
+
+ tolerance.red = 32;
+ tolerance.green = 32;
+ tolerance.blue = 32;
+ tolerance.minBrightness = 64;
+ tolerance.maxBrightness = 96;
+
+ ignoreAntialiasing = true;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreColors: function(){
+
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = true;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ onComplete: function( callback ){
+
+ updateCallbackArray.push(callback);
+
+ var wrapper = function(){
+ compare(fileData, secondFileData);
+ };
+
+ wrapper();
+
+ return getCompareApi(wrapper);
+ }
+ };
+
+ return self;
+ }
+
+ return {
+ onComplete: function( callback ){
+ updateCallbackArray.push(callback);
+ loadImageData(fileData, function(imageData, width, height){
+ parseImage(imageData.data, width, height);
+ });
+ },
+ compareTo: function(secondFileData){
+ return getCompareApi(secondFileData);
+ }
+ };
+
+ };
+}(this));
\ No newline at end of file
diff --git a/test/testsuite.js b/test/testsuite.js
deleted file mode 100644
index b486acb..0000000
--- a/test/testsuite.js
+++ /dev/null
@@ -1,36 +0,0 @@
-requirejs.config({
- baseUrl: '/test/unit/'
-});
-
-define(function(require) {
- var testModules = [
- 'Pixi',
- 'Point',
- 'Rectangle',
- 'DisplayObject',
- 'DisplayObjectContainer',
- 'Sprite',
- 'MovieClip',
- 'InteractionManager',
- 'Stage',
- 'utils/Utils',
- 'utils/EventTarget',
- 'utils/Matrix',
- 'utils/Detector',
- 'renderers/WebGLShaders',
- 'renderers/WebGLRenderer',
- 'renderers/WebGLBatch',
- 'renderers/CanvasRenderer',
- 'extras/Strip',
- 'extras/Rope',
- 'textures/BaseTexture',
- 'textures/Texture',
- 'loaders/SpriteSheetLoader',
- 'loaders/AssetLoader'
- ];
-
- // Resolve all testModules and then start the Test Runner.
- require(testModules, function() {
- QUnit.start();
- });
-});
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index 12e1b62..0b88317 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
node_modules
.DS_Store
-.project
\ No newline at end of file
+.project
+*.log
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..63e4d7c
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,8 @@
+language: node_js
+node_js:
+ - 0.10
+
+before_script:
+ - npm install -g grunt-cli
+ - export DISPLAY=:99.0
+ - sh -e /etc/init.d/xvfb start
diff --git a/Gruntfile.js b/Gruntfile.js
index b083b49..103938c 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -1,10 +1,12 @@
+'use strict';
+
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-connect');
- grunt.loadNpmTasks('grunt-contrib-qunit');
grunt.loadNpmTasks('grunt-contrib-yuidoc');
+ grunt.loadTasks('tasks');
var root = 'src/pixi/',
debug = 'bin/pixi.dev.js',
@@ -79,7 +81,7 @@
},
files: {
srcBlob: '<%= dirs.src %>/**/*.js',
- testBlob: '<%= dirs.test %>/unit/**/*.js',
+ testBlob: '<%= dirs.test %>/{functional,lib/pixi,unit}/**/*.js',
build: '<%= dirs.build %>/pixi.dev.js',
buildMin: '<%= dirs.build %>/pixi.js'
},
@@ -94,7 +96,12 @@
},
jshint: {
beforeconcat: srcFiles,
- test: ['<%= files.testBlob %>'],
+ test: {
+ src: ['<%= files.testBlob %>'],
+ options: {
+ expr: true
+ }
+ },
options: {
asi: true,
smarttabs: true
@@ -128,12 +135,6 @@
]
},
connect: {
- qunit: {
- options: {
- port: grunt.option('port-test') || 9002,
- base: './'
- }
- },
test: {
options: {
port: grunt.option('port-test') || 9002,
@@ -142,13 +143,6 @@
}
}
},
- qunit: {
- all: {
- options: {
- urls: ['http://localhost:' + (grunt.option('port-test') || 9002) + '/test/index.html']
- }
- }
- },
yuidoc: {
compile: {
name: '<%= pkg.name %>',
@@ -161,6 +155,13 @@
outdir: '<%= dirs.docs %>'
}
}
+ },
+ karma: {
+ unit: {
+ configFile: 'test/karma.conf.js',
+ // browsers: ['Chrome'],
+ singleRun: true
+ }
}
});
@@ -182,9 +183,10 @@
}
)
- grunt.registerTask('default', ['concat', 'uglify', 'distribute']);
grunt.registerTask('build', ['concat', 'uglify', 'distribute']);
- grunt.registerTask('test', ['build', 'connect:qunit', 'qunit']);
+ grunt.registerTask('test', ['concat', 'jshint:test', 'karma']);
grunt.registerTask('docs', ['yuidoc']);
-
-}
\ No newline at end of file
+ grunt.registerTask('default', ['test', 'uglify', 'distribute']);
+ // Travis CI task.
+ grunt.registerTask('travis', ['test']);
+}
diff --git a/README.md b/README.md
index c62ef86..690cfe4 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,8 @@

+[](http://travis-ci.org/drkibitz/pixi.js)
+
#### JavaScript 2D Renderer ####
The aim of this project is to provide a fast lightweight 2D library that works
diff --git a/package.json b/package.json
index b373240..1246a68 100644
--- a/package.json
+++ b/package.json
@@ -18,14 +18,21 @@
"main": "bin/pixi.js",
+ "scripts": {
+ "test": "grunt travis --verbose"
+ },
+
"dependencies": {},
"devDependencies": {
"grunt": "~0.4.x",
- "grunt-contrib-jshint": "0.3.x",
+ "grunt-contrib-jshint": "0.6.x",
"grunt-contrib-uglify": "0.2.x",
- "grunt-contrib-connect": "0.2.x",
- "grunt-contrib-qunit": "0.2.x",
+ "grunt-contrib-connect": "0.3.x",
"grunt-contrib-yuidoc": "0.4.x",
- "grunt-contrib-concat": "0.1.x"
+ "grunt-contrib-concat": "0.3.x",
+ "chai": "~1.7.0",
+ "karma": "0.11.0",
+ "karma-firefox-launcher": "0.1.0",
+ "karma-mocha": "0.1.0"
}
}
diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js
index a7c520e..ee82bbd 100644
--- a/src/pixi/InteractionManager.js
+++ b/src/pixi/InteractionManager.js
@@ -62,7 +62,6 @@
this.onTouchEnd = this.onTouchEnd.bind(this);
this.onTouchMove = this.onTouchMove.bind(this);
-
this.last = 0;
}
diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js
index 1a95d20..eef1059 100644
--- a/src/pixi/core/Ellipse.js
+++ b/src/pixi/core/Ellipse.js
@@ -78,7 +78,7 @@
return (normx + normy < 0.25);
}
-PIXI.Ellipse.getBounds = function()
+PIXI.Ellipse.prototype.getBounds = function()
{
return new PIXI.Rectangle(this.x, this.y, this.width, this.height);
}
diff --git a/tasks/karma.js b/tasks/karma.js
new file mode 100644
index 0000000..c340485
--- /dev/null
+++ b/tasks/karma.js
@@ -0,0 +1,27 @@
+'use strict';
+
+var path = require('path');
+var server = require('karma').server;
+
+module.exports = function (grunt) {
+ grunt.registerMultiTask('karma', 'run karma.', function() {
+ var done = this.async();
+ var options = this.options({
+ background: false
+ });
+ var data = this.data;
+
+ //merge options onto data, with data taking precedence
+ data = grunt.util._.merge(options, data);
+ data.configFile = path.resolve(data.configFile);
+ if (data.configFile) {
+ data.configFile = grunt.template.process(data.configFile);
+ }
+
+ server.start(
+ data,
+ function(code) {
+ done(!code);
+ });
+ });
+};
diff --git a/test/functional/example-1-basics/bunny.png b/test/functional/example-1-basics/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/functional/example-1-basics/bunny.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-30.png b/test/functional/example-1-basics/frame-30.png
new file mode 100644
index 0000000..96e3409
--- /dev/null
+++ b/test/functional/example-1-basics/frame-30.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-60.png b/test/functional/example-1-basics/frame-60.png
new file mode 100644
index 0000000..af3f4ce
--- /dev/null
+++ b/test/functional/example-1-basics/frame-60.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-90.png b/test/functional/example-1-basics/frame-90.png
new file mode 100644
index 0000000..099b823
--- /dev/null
+++ b/test/functional/example-1-basics/frame-90.png
Binary files differ
diff --git a/test/functional/example-1-basics/index.js b/test/functional/example-1-basics/index.js
new file mode 100644
index 0000000..7ae7a98
--- /dev/null
+++ b/test/functional/example-1-basics/index.js
@@ -0,0 +1,133 @@
+describe('Example 1 - Basics', function () {
+ 'use strict';
+
+ var baseUri = '/base/test/functional/example-1-basics';
+ var expect = chai.expect;
+ var currentFrame = 0;
+ var frameEvents = {};
+ var stage;
+ var renderer;
+ var bunny;
+
+ function onFrame(frame, callback) {
+ frameEvents[frame] = callback;
+ }
+
+ function animate() {
+ currentFrame += 1;
+
+ requestAnimFrame( animate );
+
+ // just for fun, lets rotate mr rabbit a little
+ bunny.rotation += 0.1;
+
+ // render the stage
+ renderer.render(stage);
+
+ if (frameEvents[currentFrame])
+ frameEvents[currentFrame](currentFrame);
+ }
+
+ function initScene() {
+ // create an new instance of a pixi stage
+ stage = new PIXI.Stage(0x66FF99);
+
+ // create a renderer instance
+ renderer = PIXI.autoDetectRenderer(400, 300);
+ console.log('Is PIXI.WebGLRenderer: ' + (renderer instanceof PIXI.WebGLRenderer));
+
+ // add the renderer view element to the DOM
+ document.body.appendChild(renderer.view);
+
+ requestAnimFrame( animate );
+
+ // create a texture from an image path
+ var texture = PIXI.Texture.fromImage(baseUri + "/bunny.png");
+ // create a new Sprite using the texture
+ bunny = new PIXI.Sprite(texture);
+
+ // center the sprites anchor point
+ bunny.anchor.x = 0.5;
+ bunny.anchor.y = 0.5;
+
+ // move the sprite t the center of the screen
+ bunny.position.x = 200;
+ bunny.position.y = 150;
+
+ stage.addChild(bunny);
+ }
+
+ it('assets loaded', function (done) {
+ var loader = new PIXI.AssetLoader([
+ baseUri + '/bunny.png',
+ baseUri + '/frame-30.png',
+ baseUri + '/frame-60.png',
+ baseUri + '/frame-90.png'
+ ]);
+ // loader.on('onProgress', function (event) {
+ // console.log(event.content);
+ // });
+ loader.on('onComplete', function (event) {
+ done();
+ initScene();
+ });
+ loader.load();
+ });
+
+ it('frame 30 should match', function (done) {
+ this.timeout(700);
+ onFrame(30, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-30.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 60 should match', function (done) {
+ this.timeout(1200);
+ onFrame(60, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-60.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 90 should match', function (done) {
+ this.timeout(1700);
+ onFrame(90, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-90.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ // it('capture something', function (done) {
+ // this.timeout(2000000);
+ // onFrame(30, function () {
+ // var img = new Image();
+ // img.src = renderer.view.toDataURL('image/png');
+ // document.body.appendChild(img);
+ // });
+ // });
+});
diff --git a/test/index.html b/test/index.html
deleted file mode 100644
index 9cbcac5..0000000
--- a/test/index.html
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
- Pixi.js Test Suite
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/test/karma.conf.js b/test/karma.conf.js
new file mode 100644
index 0000000..c66a696
--- /dev/null
+++ b/test/karma.conf.js
@@ -0,0 +1,82 @@
+module.exports = function(config) {
+ config.set({
+
+ // base path, that will be used to resolve files and exclude
+ basePath : '../',
+
+ frameworks : ['mocha'],
+
+ // list of files / patterns to load in the browser
+ files : [
+ 'node_modules/chai/chai.js',
+ 'bin/pixi.dev.js',
+ 'test/lib/**/*.js',
+ 'test/unit/**/*.js',
+ // 'test/functional/**/*.js',
+ {pattern: 'test/**/*.png', watched: false, included: false, served: true}
+ ],
+
+ // list of files to exclude
+ exclude : [],
+
+ // use dolts reporter, as travis terminal does not support escaping sequences
+ // possible values: 'dots', 'progress', 'junit', 'teamcity'
+ // CLI --reporters progress
+ reporters : ['progress'],
+
+ // web server port
+ // CLI --port 9876
+ port : 9876,
+
+ // cli runner port
+ // CLI --runner-port 9100
+ runnerPort : 9100,
+
+ // enable / disable colors in the output (reporters and logs)
+ // CLI --colors --no-colors
+ colors : true,
+
+ // level of logging
+ // possible values: karma.LOG_DISABLE || karma.LOG_ERROR || karma.LOG_WARN || karma.LOG_INFO || karma.LOG_DEBUG
+ // CLI --log-level debug
+ logLevel : config.LOG_DEBUG,
+
+ // enable / disable watching file and executing tests whenever any file changes
+ // CLI --auto-watch --no-auto-watch
+ autoWatch : false,
+
+ // Start these browsers, currently available:
+ // - Chrome
+ // - ChromeCanary
+ // - Firefox
+ // - Opera
+ // - Safari (only Mac)
+ // - PhantomJS
+ // - IE (only Windows)
+ // CLI --browsers Chrome,Firefox,Safari
+ browsers : ['Firefox'],
+
+ // If browser does not capture in given timeout [ms], kill it
+ // CLI --capture-timeout 5000
+ captureTimeout : 5000,
+
+ // Auto run tests on start (when browsers are captured) and exit
+ // CLI --single-run --no-single-run
+ singleRun : true,
+
+ // report which specs are slower than 500ms
+ // CLI --report-slower-than 500
+ reportSlowerThan : 1000,
+
+ preprocessors : {
+ // '**/client/js/*.js': 'coverage'
+ },
+
+ plugins : [
+ 'karma-mocha',
+ // 'karma-chrome-launcher',
+ 'karma-firefox-launcher',
+ // 'karma-phantomjs-launcher'
+ ]
+ });
+};
diff --git a/test/lib/pixi/core/Matrix.js b/test/lib/pixi/core/Matrix.js
new file mode 100644
index 0000000..d26386b
--- /dev/null
+++ b/test/lib/pixi/core/Matrix.js
@@ -0,0 +1,40 @@
+
+function pixi_core_Matrix_confirmNewMat3(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(1);
+ expect(matrix[5]).to.equal(0);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(1);
+}
+
+function pixi_core_Matrix_confirmNewMat4(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[0]).to.equal(1);
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(0);
+ expect(matrix[5]).to.equal(1);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(0);
+ expect(matrix[9]).to.equal(0);
+ expect(matrix[10]).to.equal(1);
+ expect(matrix[11]).to.equal(0);
+ expect(matrix[12]).to.equal(0);
+ expect(matrix[13]).to.equal(0);
+ expect(matrix[14]).to.equal(0);
+ expect(matrix[15]).to.equal(1);
+}
diff --git a/test/lib/pixi/core/Point.js b/test/lib/pixi/core/Point.js
new file mode 100644
index 0000000..e5df07b
--- /dev/null
+++ b/test/lib/pixi/core/Point.js
@@ -0,0 +1,10 @@
+
+function pixi_core_Point_confirm(obj, x, y) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Point);
+ expect(obj).to.respondTo('clone');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+}
diff --git a/test/lib/pixi/core/Rectangle.js b/test/lib/pixi/core/Rectangle.js
new file mode 100644
index 0000000..23f0d12
--- /dev/null
+++ b/test/lib/pixi/core/Rectangle.js
@@ -0,0 +1,13 @@
+
+function pixi_core_Rectangle_confirm(obj, x, y, width, height) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Rectangle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+ expect(obj).to.have.property('width', width);
+ expect(obj).to.have.property('height', height);
+}
diff --git a/test/lib/pixi/display/DisplayObject.js b/test/lib/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..1388a7f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObject.js
@@ -0,0 +1,43 @@
+
+function pixi_display_DisplayObject_confirmNew(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObject);
+ expect(obj).to.respondTo('setInteractive');
+ expect(obj).to.respondTo('addFilter');
+ expect(obj).to.respondTo('removeFilter');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.property('last', obj);
+ expect(obj).to.have.property('first', obj);
+
+ expect(obj).to.contain.property('position');
+ pixi_core_Point_confirm(obj.position, 0, 0);
+ expect(obj).to.contain.property('scale');
+ pixi_core_Point_confirm(obj.scale, 1, 1);
+ expect(obj).to.contain.property('pivot');
+ pixi_core_Point_confirm(obj.pivot, 0, 0);
+
+ expect(obj).to.have.property('rotation', 0);
+ expect(obj).to.have.property('alpha', 1);
+ expect(obj).to.have.property('visible', true);
+ expect(obj).to.have.property('buttonMode', false);
+ expect(obj).to.have.property('parent', null);
+ expect(obj).to.have.property('worldAlpha', 1);
+
+ expect(obj).to.have.property('hitArea');
+ expect(obj).to.have.property('interactive'); // TODO: Have a better default value
+ expect('mask' in obj).to.be.true; // TODO: Have a better default value
+ expect(obj.mask).to.be.undefined;
+
+ expect(obj).to.have.property('renderable');
+ expect(obj).to.have.property('stage');
+
+ expect(obj).to.have.deep.property('worldTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ expect(obj).to.have.deep.property('localTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.localTransform);
+
+ expect(obj).to.have.deep.property('color.length', 0);
+ expect(obj).to.have.property('dynamic', true);
+}
diff --git a/test/lib/pixi/display/DisplayObjectContainer.js b/test/lib/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..085c59f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,16 @@
+
+function pixi_display_DisplayObjectContainer_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObject_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObjectContainer);
+ expect(obj).to.respondTo('addChild');
+ expect(obj).to.respondTo('addChildAt');
+ expect(obj).to.respondTo('swapChildren');
+ expect(obj).to.respondTo('getChildAt');
+ expect(obj).to.respondTo('removeChild');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('children.length', 0);
+}
diff --git a/test/lib/pixi/display/Sprite.js b/test/lib/pixi/display/Sprite.js
new file mode 100644
index 0000000..cc7a2d6
--- /dev/null
+++ b/test/lib/pixi/display/Sprite.js
@@ -0,0 +1,28 @@
+
+function pixi_display_Sprite_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Sprite);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', true);
+ expect(obj).to.have.property('stage', null);
+
+ expect(obj).to.have.property('anchor');
+ pixi_core_Point_confirm(obj.anchor, 0, 0);
+
+ expect(obj).to.have.property('blendMode', PIXI.blendModes.NORMAL);
+ expect(obj).to.have.property('width', 1); // TODO: is 1 expected
+ expect(obj).to.have.property('height', 1); // TODO: is 1 expected
+
+ // FIXME: Just make this a boolean that is always there
+ expect(!!obj.updateFrame).to.equal(obj.texture.baseTexture.hasLoaded);
+
+ expect(obj).to.have.property('texture');
+ pixi_textures_Texture_confirmNew(obj.texture, done);
+}
diff --git a/test/lib/pixi/extras/Strip.js b/test/lib/pixi/extras/Strip.js
new file mode 100644
index 0000000..8927a8a
--- /dev/null
+++ b/test/lib/pixi/extras/Strip.js
@@ -0,0 +1,12 @@
+
+function pixi_extras_Strip_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Strip);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ // TODO: Test properties
+}
diff --git a/test/lib/pixi/textures/Texture.js b/test/lib/pixi/textures/Texture.js
new file mode 100644
index 0000000..d5867b6
--- /dev/null
+++ b/test/lib/pixi/textures/Texture.js
@@ -0,0 +1,31 @@
+
+function pixi_textures_Texture_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ function confirmFrameDone() {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, obj.baseTexture.width, obj.baseTexture.height);
+
+ expect(obj).to.have.property('width', obj.baseTexture.width);
+ expect(obj).to.have.property('height', obj.baseTexture.height);
+ done();
+ }
+
+ expect(obj).to.be.an.instanceof(PIXI.Texture);
+ pixi_utils_EventTarget_like(obj);
+
+ expect(obj).to.have.property('baseTexture')
+ .and.to.be.an.instanceof(PIXI.BaseTexture);
+
+ expect(obj).to.have.property('scope', obj);
+
+ expect(obj).to.have.property('trim');
+ pixi_core_Point_confirm(obj.trim, 0, 0);
+
+ expect(obj).to.have.property('frame');
+ if (obj.baseTexture.hasLoaded) {
+ confirmFrameDone();
+ } else {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, 1, 1);
+ obj.addEventListener('update', confirmFrameDone);
+ }
+}
diff --git a/test/lib/pixi/utils/EventTarget.js b/test/lib/pixi/utils/EventTarget.js
new file mode 100644
index 0000000..7b1dcfa
--- /dev/null
+++ b/test/lib/pixi/utils/EventTarget.js
@@ -0,0 +1,8 @@
+
+function pixi_utils_EventTarget_like(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.respondTo('addEventListener');
+ expect(obj).to.respondTo('dispatchEvent');
+ expect(obj).to.respondTo('removeEventListener');
+}
diff --git a/test/lib/qunit-1.11.0.css b/test/lib/qunit-1.11.0.css
deleted file mode 100644
index d7fc0c8..0000000
--- a/test/lib/qunit-1.11.0.css
+++ /dev/null
@@ -1,244 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-/** Font Family and Sizes */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
- font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
-}
-
-#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
-#qunit-tests { font-size: smaller; }
-
-
-/** Resets */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter {
- margin: 0;
- padding: 0;
-}
-
-
-/** Header */
-
-#qunit-header {
- padding: 0.5em 0 0.5em 1em;
-
- color: #8699a4;
- background-color: #0d3349;
-
- font-size: 1.5em;
- line-height: 1em;
- font-weight: normal;
-
- border-radius: 5px 5px 0 0;
- -moz-border-radius: 5px 5px 0 0;
- -webkit-border-top-right-radius: 5px;
- -webkit-border-top-left-radius: 5px;
-}
-
-#qunit-header a {
- text-decoration: none;
- color: #c2ccd1;
-}
-
-#qunit-header a:hover,
-#qunit-header a:focus {
- color: #fff;
-}
-
-#qunit-testrunner-toolbar label {
- display: inline-block;
- padding: 0 .5em 0 .1em;
-}
-
-#qunit-banner {
- height: 5px;
-}
-
-#qunit-testrunner-toolbar {
- padding: 0.5em 0 0.5em 2em;
- color: #5E740B;
- background-color: #eee;
- overflow: hidden;
-}
-
-#qunit-userAgent {
- padding: 0.5em 0 0.5em 2.5em;
- background-color: #2b81af;
- color: #fff;
- text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
-}
-
-#qunit-modulefilter-container {
- float: right;
-}
-
-/** Tests: Pass/Fail */
-
-#qunit-tests {
- list-style-position: inside;
-}
-
-#qunit-tests li {
- padding: 0.4em 0.5em 0.4em 2.5em;
- border-bottom: 1px solid #fff;
- list-style-position: inside;
-}
-
-#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running {
- display: none;
-}
-
-#qunit-tests li strong {
- cursor: pointer;
-}
-
-#qunit-tests li a {
- padding: 0.5em;
- color: #c2ccd1;
- text-decoration: none;
-}
-#qunit-tests li a:hover,
-#qunit-tests li a:focus {
- color: #000;
-}
-
-#qunit-tests li .runtime {
- float: right;
- font-size: smaller;
-}
-
-.qunit-assert-list {
- margin-top: 0.5em;
- padding: 0.5em;
-
- background-color: #fff;
-
- border-radius: 5px;
- -moz-border-radius: 5px;
- -webkit-border-radius: 5px;
-}
-
-.qunit-collapsed {
- display: none;
-}
-
-#qunit-tests table {
- border-collapse: collapse;
- margin-top: .2em;
-}
-
-#qunit-tests th {
- text-align: right;
- vertical-align: top;
- padding: 0 .5em 0 0;
-}
-
-#qunit-tests td {
- vertical-align: top;
-}
-
-#qunit-tests pre {
- margin: 0;
- white-space: pre-wrap;
- word-wrap: break-word;
-}
-
-#qunit-tests del {
- background-color: #e0f2be;
- color: #374e0c;
- text-decoration: none;
-}
-
-#qunit-tests ins {
- background-color: #ffcaca;
- color: #500;
- text-decoration: none;
-}
-
-/*** Test Counts */
-
-#qunit-tests b.counts { color: black; }
-#qunit-tests b.passed { color: #5E740B; }
-#qunit-tests b.failed { color: #710909; }
-
-#qunit-tests li li {
- padding: 5px;
- background-color: #fff;
- border-bottom: none;
- list-style-position: inside;
-}
-
-/*** Passing Styles */
-
-#qunit-tests li li.pass {
- color: #3c510c;
- background-color: #fff;
- border-left: 10px solid #C6E746;
-}
-
-#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
-#qunit-tests .pass .test-name { color: #366097; }
-
-#qunit-tests .pass .test-actual,
-#qunit-tests .pass .test-expected { color: #999999; }
-
-#qunit-banner.qunit-pass { background-color: #C6E746; }
-
-/*** Failing Styles */
-
-#qunit-tests li li.fail {
- color: #710909;
- background-color: #fff;
- border-left: 10px solid #EE5757;
- white-space: pre;
-}
-
-#qunit-tests > li:last-child {
- border-radius: 0 0 5px 5px;
- -moz-border-radius: 0 0 5px 5px;
- -webkit-border-bottom-right-radius: 5px;
- -webkit-border-bottom-left-radius: 5px;
-}
-
-#qunit-tests .fail { color: #000000; background-color: #EE5757; }
-#qunit-tests .fail .test-name,
-#qunit-tests .fail .module-name { color: #000000; }
-
-#qunit-tests .fail .test-actual { color: #EE5757; }
-#qunit-tests .fail .test-expected { color: green; }
-
-#qunit-banner.qunit-fail { background-color: #EE5757; }
-
-
-/** Result */
-
-#qunit-testresult {
- padding: 0.5em 0.5em 0.5em 2.5em;
-
- color: #2b81af;
- background-color: #D2E0E6;
-
- border-bottom: 1px solid white;
-}
-#qunit-testresult .module-name {
- font-weight: bold;
-}
-
-/** Fixture */
-
-#qunit-fixture {
- position: absolute;
- top: -10000px;
- left: -10000px;
- width: 1000px;
- height: 1000px;
-}
diff --git a/test/lib/qunit-1.11.0.js b/test/lib/qunit-1.11.0.js
deleted file mode 100644
index 302545f..0000000
--- a/test/lib/qunit-1.11.0.js
+++ /dev/null
@@ -1,2152 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-(function( window ) {
-
-var QUnit,
- assert,
- config,
- onErrorFnPrev,
- testId = 0,
- fileName = (sourceFromStacktrace( 0 ) || "" ).replace(/(:\d+)+\)?/, "").replace(/.+\//, ""),
- toString = Object.prototype.toString,
- hasOwn = Object.prototype.hasOwnProperty,
- // Keep a local reference to Date (GH-283)
- Date = window.Date,
- defined = {
- setTimeout: typeof window.setTimeout !== "undefined",
- sessionStorage: (function() {
- var x = "qunit-test-string";
- try {
- sessionStorage.setItem( x, x );
- sessionStorage.removeItem( x );
- return true;
- } catch( e ) {
- return false;
- }
- }())
- },
- /**
- * Provides a normalized error string, correcting an issue
- * with IE 7 (and prior) where Error.prototype.toString is
- * not properly implemented
- *
- * Based on http://es5.github.com/#x15.11.4.4
- *
- * @param {String|Error} error
- * @return {String} error message
- */
- errorString = function( error ) {
- var name, message,
- errorString = error.toString();
- if ( errorString.substring( 0, 7 ) === "[object" ) {
- name = error.name ? error.name.toString() : "Error";
- message = error.message ? error.message.toString() : "";
- if ( name && message ) {
- return name + ": " + message;
- } else if ( name ) {
- return name;
- } else if ( message ) {
- return message;
- } else {
- return "Error";
- }
- } else {
- return errorString;
- }
- },
- /**
- * Makes a clone of an object using only Array or Object as base,
- * and copies over the own enumerable properties.
- *
- * @param {Object} obj
- * @return {Object} New object with only the own properties (recursively).
- */
- objectValues = function( obj ) {
- // Grunt 0.3.x uses an older version of jshint that still has jshint/jshint#392.
- /*jshint newcap: false */
- var key, val,
- vals = QUnit.is( "array", obj ) ? [] : {};
- for ( key in obj ) {
- if ( hasOwn.call( obj, key ) ) {
- val = obj[key];
- vals[key] = val === Object(val) ? objectValues(val) : val;
- }
- }
- return vals;
- };
-
-function Test( settings ) {
- extend( this, settings );
- this.assertions = [];
- this.testNumber = ++Test.count;
-}
-
-Test.count = 0;
-
-Test.prototype = {
- init: function() {
- var a, b, li,
- tests = id( "qunit-tests" );
-
- if ( tests ) {
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml;
-
- // `a` initialized at top of scope
- a = document.createElement( "a" );
- a.innerHTML = "Rerun";
- a.href = QUnit.url({ testNumber: this.testNumber });
-
- li = document.createElement( "li" );
- li.appendChild( b );
- li.appendChild( a );
- li.className = "running";
- li.id = this.id = "qunit-test-output" + testId++;
-
- tests.appendChild( li );
- }
- },
- setup: function() {
- if ( this.module !== config.previousModule ) {
- if ( config.previousModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.previousModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
- config.previousModule = this.module;
- config.moduleStats = { all: 0, bad: 0 };
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- } else if ( config.autorun ) {
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- }
-
- config.current = this;
-
- this.testEnvironment = extend({
- setup: function() {},
- teardown: function() {}
- }, this.moduleTestEnvironment );
-
- this.started = +new Date();
- runLoggingCallbacks( "testStart", QUnit, {
- name: this.testName,
- module: this.module
- });
-
- // allow utility functions to access the current test environment
- // TODO why??
- QUnit.current_testEnvironment = this.testEnvironment;
-
- if ( !config.pollution ) {
- saveGlobal();
- }
- if ( config.notrycatch ) {
- this.testEnvironment.setup.call( this.testEnvironment );
- return;
- }
- try {
- this.testEnvironment.setup.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Setup failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- },
- run: function() {
- config.current = this;
-
- var running = id( "qunit-testresult" );
-
- if ( running ) {
- running.innerHTML = "Running:
" + this.nameHtml;
- }
-
- if ( this.async ) {
- QUnit.stop();
- }
-
- this.callbackStarted = +new Date();
-
- if ( config.notrycatch ) {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- return;
- }
-
- try {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- } catch( e ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
-
- QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + " " + this.stack + ": " + ( e.message || e ), extractStacktrace( e, 0 ) );
- // else next test will carry the responsibility
- saveGlobal();
-
- // Restart the tests if they're blocking
- if ( config.blocking ) {
- QUnit.start();
- }
- }
- },
- teardown: function() {
- config.current = this;
- if ( config.notrycatch ) {
- if ( typeof this.callbackRuntime === "undefined" ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
- }
- this.testEnvironment.teardown.call( this.testEnvironment );
- return;
- } else {
- try {
- this.testEnvironment.teardown.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Teardown failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- }
- checkPollution();
- },
- finish: function() {
- config.current = this;
- if ( config.requireExpects && this.expected === null ) {
- QUnit.pushFailure( "Expected number of assertions to be defined, but expect() was not called.", this.stack );
- } else if ( this.expected !== null && this.expected !== this.assertions.length ) {
- QUnit.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack );
- } else if ( this.expected === null && !this.assertions.length ) {
- QUnit.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions.", this.stack );
- }
-
- var i, assertion, a, b, time, li, ol,
- test = this,
- good = 0,
- bad = 0,
- tests = id( "qunit-tests" );
-
- this.runtime = +new Date() - this.started;
- config.stats.all += this.assertions.length;
- config.moduleStats.all += this.assertions.length;
-
- if ( tests ) {
- ol = document.createElement( "ol" );
- ol.className = "qunit-assert-list";
-
- for ( i = 0; i < this.assertions.length; i++ ) {
- assertion = this.assertions[i];
-
- li = document.createElement( "li" );
- li.className = assertion.result ? "pass" : "fail";
- li.innerHTML = assertion.message || ( assertion.result ? "okay" : "failed" );
- ol.appendChild( li );
-
- if ( assertion.result ) {
- good++;
- } else {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
-
- // store result when possible
- if ( QUnit.config.reorder && defined.sessionStorage ) {
- if ( bad ) {
- sessionStorage.setItem( "qunit-test-" + this.module + "-" + this.testName, bad );
- } else {
- sessionStorage.removeItem( "qunit-test-" + this.module + "-" + this.testName );
- }
- }
-
- if ( bad === 0 ) {
- addClass( ol, "qunit-collapsed" );
- }
-
- // `b` initialized at top of scope
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml + " (" + bad + ", " + good + ", " + this.assertions.length + ")";
-
- addEvent(b, "click", function() {
- var next = b.parentNode.lastChild,
- collapsed = hasClass( next, "qunit-collapsed" );
- ( collapsed ? removeClass : addClass )( next, "qunit-collapsed" );
- });
-
- addEvent(b, "dblclick", function( e ) {
- var target = e && e.target ? e.target : window.event.srcElement;
- if ( target.nodeName.toLowerCase() === "span" || target.nodeName.toLowerCase() === "b" ) {
- target = target.parentNode;
- }
- if ( window.location && target.nodeName.toLowerCase() === "strong" ) {
- window.location = QUnit.url({ testNumber: test.testNumber });
- }
- });
-
- // `time` initialized at top of scope
- time = document.createElement( "span" );
- time.className = "runtime";
- time.innerHTML = this.runtime + " ms";
-
- // `li` initialized at top of scope
- li = id( this.id );
- li.className = bad ? "fail" : "pass";
- li.removeChild( li.firstChild );
- a = li.firstChild;
- li.appendChild( b );
- li.appendChild( a );
- li.appendChild( time );
- li.appendChild( ol );
-
- } else {
- for ( i = 0; i < this.assertions.length; i++ ) {
- if ( !this.assertions[i].result ) {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
- }
-
- runLoggingCallbacks( "testDone", QUnit, {
- name: this.testName,
- module: this.module,
- failed: bad,
- passed: this.assertions.length - bad,
- total: this.assertions.length,
- duration: this.runtime
- });
-
- QUnit.reset();
-
- config.current = undefined;
- },
-
- queue: function() {
- var bad,
- test = this;
-
- synchronize(function() {
- test.init();
- });
- function run() {
- // each of these can by async
- synchronize(function() {
- test.setup();
- });
- synchronize(function() {
- test.run();
- });
- synchronize(function() {
- test.teardown();
- });
- synchronize(function() {
- test.finish();
- });
- }
-
- // `bad` initialized at top of scope
- // defer when previous test run passed, if storage is available
- bad = QUnit.config.reorder && defined.sessionStorage &&
- +sessionStorage.getItem( "qunit-test-" + this.module + "-" + this.testName );
-
- if ( bad ) {
- run();
- } else {
- synchronize( run, true );
- }
- }
-};
-
-// Root QUnit object.
-// `QUnit` initialized at top of scope
-QUnit = {
-
- // call on start of module test to prepend name to all tests
- module: function( name, testEnvironment ) {
- config.currentModule = name;
- config.currentModuleTestEnvironment = testEnvironment;
- config.modules[name] = true;
- },
-
- asyncTest: function( testName, expected, callback ) {
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- QUnit.test( testName, expected, callback, true );
- },
-
- test: function( testName, expected, callback, async ) {
- var test,
- nameHtml = "" + escapeText( testName ) + "";
-
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- if ( config.currentModule ) {
- nameHtml = "" + escapeText( config.currentModule ) + ": " + nameHtml;
- }
-
- test = new Test({
- nameHtml: nameHtml,
- testName: testName,
- expected: expected,
- async: async,
- callback: callback,
- module: config.currentModule,
- moduleTestEnvironment: config.currentModuleTestEnvironment,
- stack: sourceFromStacktrace( 2 )
- });
-
- if ( !validTest( test ) ) {
- return;
- }
-
- test.queue();
- },
-
- // Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through.
- expect: function( asserts ) {
- if (arguments.length === 1) {
- config.current.expected = asserts;
- } else {
- return config.current.expected;
- }
- },
-
- start: function( count ) {
- // QUnit hasn't been initialized yet.
- // Note: RequireJS (et al) may delay onLoad
- if ( config.semaphore === undefined ) {
- QUnit.begin(function() {
- // This is triggered at the top of QUnit.load, push start() to the event loop, to allow QUnit.load to finish first
- setTimeout(function() {
- QUnit.start( count );
- });
- });
- return;
- }
-
- config.semaphore -= count || 1;
- // don't start until equal number of stop-calls
- if ( config.semaphore > 0 ) {
- return;
- }
- // ignore if start is called more often then stop
- if ( config.semaphore < 0 ) {
- config.semaphore = 0;
- QUnit.pushFailure( "Called start() while already started (QUnit.config.semaphore was 0 already)", null, sourceFromStacktrace(2) );
- return;
- }
- // A slight delay, to avoid any current callbacks
- if ( defined.setTimeout ) {
- window.setTimeout(function() {
- if ( config.semaphore > 0 ) {
- return;
- }
- if ( config.timeout ) {
- clearTimeout( config.timeout );
- }
-
- config.blocking = false;
- process( true );
- }, 13);
- } else {
- config.blocking = false;
- process( true );
- }
- },
-
- stop: function( count ) {
- config.semaphore += count || 1;
- config.blocking = true;
-
- if ( config.testTimeout && defined.setTimeout ) {
- clearTimeout( config.timeout );
- config.timeout = window.setTimeout(function() {
- QUnit.ok( false, "Test timed out" );
- config.semaphore = 1;
- QUnit.start();
- }, config.testTimeout );
- }
- }
-};
-
-// `assert` initialized at top of scope
-// Asssert helpers
-// All of these must either call QUnit.push() or manually do:
-// - runLoggingCallbacks( "log", .. );
-// - config.current.assertions.push({ .. });
-// We attach it to the QUnit object *after* we expose the public API,
-// otherwise `assert` will become a global variable in browsers (#341).
-assert = {
- /**
- * Asserts rough true-ish result.
- * @name ok
- * @function
- * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" );
- */
- ok: function( result, msg ) {
- if ( !config.current ) {
- throw new Error( "ok() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
- result = !!result;
-
- var source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: msg
- };
-
- msg = escapeText( msg || (result ? "okay" : "failed" ) );
- msg = "" + msg + "";
-
- if ( !result ) {
- source = sourceFromStacktrace( 2 );
- if ( source ) {
- details.source = source;
- msg += "Source: | " + escapeText( source ) + " |
---|
";
- }
- }
- runLoggingCallbacks( "log", QUnit, details );
- config.current.assertions.push({
- result: result,
- message: msg
- });
- },
-
- /**
- * Assert that the first two arguments are equal, with an optional message.
- * Prints out both actual and expected values.
- * @name equal
- * @function
- * @example equal( format( "Received {0} bytes.", 2), "Received 2 bytes.", "format() replaces {0} with next argument" );
- */
- equal: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected == actual, actual, expected, message );
- },
-
- /**
- * @name notEqual
- * @function
- */
- notEqual: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected != actual, actual, expected, message );
- },
-
- /**
- * @name propEqual
- * @function
- */
- propEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notPropEqual
- * @function
- */
- notPropEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name deepEqual
- * @function
- */
- deepEqual: function( actual, expected, message ) {
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notDeepEqual
- * @function
- */
- notDeepEqual: function( actual, expected, message ) {
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name strictEqual
- * @function
- */
- strictEqual: function( actual, expected, message ) {
- QUnit.push( expected === actual, actual, expected, message );
- },
-
- /**
- * @name notStrictEqual
- * @function
- */
- notStrictEqual: function( actual, expected, message ) {
- QUnit.push( expected !== actual, actual, expected, message );
- },
-
- "throws": function( block, expected, message ) {
- var actual,
- expectedOutput = expected,
- ok = false;
-
- // 'expected' is optional
- if ( typeof expected === "string" ) {
- message = expected;
- expected = null;
- }
-
- config.current.ignoreGlobalErrors = true;
- try {
- block.call( config.current.testEnvironment );
- } catch (e) {
- actual = e;
- }
- config.current.ignoreGlobalErrors = false;
-
- if ( actual ) {
- // we don't want to validate thrown error
- if ( !expected ) {
- ok = true;
- expectedOutput = null;
- // expected is a regexp
- } else if ( QUnit.objectType( expected ) === "regexp" ) {
- ok = expected.test( errorString( actual ) );
- // expected is a constructor
- } else if ( actual instanceof expected ) {
- ok = true;
- // expected is a validation function which returns true is validation passed
- } else if ( expected.call( {}, actual ) === true ) {
- expectedOutput = null;
- ok = true;
- }
-
- QUnit.push( ok, actual, expectedOutput, message );
- } else {
- QUnit.pushFailure( message, null, 'No exception was thrown.' );
- }
- }
-};
-
-/**
- * @deprecate since 1.8.0
- * Kept assertion helpers in root for backwards compatibility.
- */
-extend( QUnit, assert );
-
-/**
- * @deprecated since 1.9.0
- * Kept root "raises()" for backwards compatibility.
- * (Note that we don't introduce assert.raises).
- */
-QUnit.raises = assert[ "throws" ];
-
-/**
- * @deprecated since 1.0.0, replaced with error pushes since 1.3.0
- * Kept to avoid TypeErrors for undefined methods.
- */
-QUnit.equals = function() {
- QUnit.push( false, false, false, "QUnit.equals has been deprecated since 2009 (e88049a0), use QUnit.equal instead" );
-};
-QUnit.same = function() {
- QUnit.push( false, false, false, "QUnit.same has been deprecated since 2009 (e88049a0), use QUnit.deepEqual instead" );
-};
-
-// We want access to the constructor's prototype
-(function() {
- function F() {}
- F.prototype = QUnit;
- QUnit = new F();
- // Make F QUnit's constructor so that we can add to the prototype later
- QUnit.constructor = F;
-}());
-
-/**
- * Config object: Maintain internal state
- * Later exposed as QUnit.config
- * `config` initialized at top of scope
- */
-config = {
- // The queue of tests to run
- queue: [],
-
- // block until document ready
- blocking: true,
-
- // when enabled, show only failing tests
- // gets persisted through sessionStorage and can be changed in UI via checkbox
- hidepassed: false,
-
- // by default, run previously failed tests first
- // very useful in combination with "Hide passed tests" checked
- reorder: true,
-
- // by default, modify document.title when suite is done
- altertitle: true,
-
- // when enabled, all tests must call expect()
- requireExpects: false,
-
- // add checkboxes that are persisted in the query-string
- // when enabled, the id is set to `true` as a `QUnit.config` property
- urlConfig: [
- {
- id: "noglobals",
- label: "Check for Globals",
- tooltip: "Enabling this will test if any test introduces new properties on the `window` object. Stored as query-strings."
- },
- {
- id: "notrycatch",
- label: "No try-catch",
- tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging exceptions in IE reasonable. Stored as query-strings."
- }
- ],
-
- // Set of all modules.
- modules: {},
-
- // logging callback queues
- begin: [],
- done: [],
- log: [],
- testStart: [],
- testDone: [],
- moduleStart: [],
- moduleDone: []
-};
-
-// Export global variables, unless an 'exports' object exists,
-// in that case we assume we're in CommonJS (dealt with on the bottom of the script)
-if ( typeof exports === "undefined" ) {
- extend( window, QUnit );
-
- // Expose QUnit object
- window.QUnit = QUnit;
-}
-
-// Initialize more QUnit.config and QUnit.urlParams
-(function() {
- var i,
- location = window.location || { search: "", protocol: "file:" },
- params = location.search.slice( 1 ).split( "&" ),
- length = params.length,
- urlParams = {},
- current;
-
- if ( params[ 0 ] ) {
- for ( i = 0; i < length; i++ ) {
- current = params[ i ].split( "=" );
- current[ 0 ] = decodeURIComponent( current[ 0 ] );
- // allow just a key to turn on a flag, e.g., test.html?noglobals
- current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true;
- urlParams[ current[ 0 ] ] = current[ 1 ];
- }
- }
-
- QUnit.urlParams = urlParams;
-
- // String search anywhere in moduleName+testName
- config.filter = urlParams.filter;
-
- // Exact match of the module name
- config.module = urlParams.module;
-
- config.testNumber = parseInt( urlParams.testNumber, 10 ) || null;
-
- // Figure out if we're running the tests from a server or not
- QUnit.isLocal = location.protocol === "file:";
-}());
-
-// Extend QUnit object,
-// these after set here because they should not be exposed as global functions
-extend( QUnit, {
- assert: assert,
-
- config: config,
-
- // Initialize the configuration options
- init: function() {
- extend( config, {
- stats: { all: 0, bad: 0 },
- moduleStats: { all: 0, bad: 0 },
- started: +new Date(),
- updateRate: 1000,
- blocking: false,
- autostart: true,
- autorun: false,
- filter: "",
- queue: [],
- semaphore: 1
- });
-
- var tests, banner, result,
- qunit = id( "qunit" );
-
- if ( qunit ) {
- qunit.innerHTML =
- "" +
- "" +
- "" +
- "" +
- "
";
- }
-
- tests = id( "qunit-tests" );
- banner = id( "qunit-banner" );
- result = id( "qunit-testresult" );
-
- if ( tests ) {
- tests.innerHTML = "";
- }
-
- if ( banner ) {
- banner.className = "";
- }
-
- if ( result ) {
- result.parentNode.removeChild( result );
- }
-
- if ( tests ) {
- result = document.createElement( "p" );
- result.id = "qunit-testresult";
- result.className = "result";
- tests.parentNode.insertBefore( result, tests );
- result.innerHTML = "Running...
";
- }
- },
-
- // Resets the test setup. Useful for tests that modify the DOM.
- reset: function() {
- var fixture = id( "qunit-fixture" );
- if ( fixture ) {
- fixture.innerHTML = config.fixture;
- }
- },
-
- // Trigger an event on an element.
- // @example triggerEvent( document.body, "click" );
- triggerEvent: function( elem, type, event ) {
- if ( document.createEvent ) {
- event = document.createEvent( "MouseEvents" );
- event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView,
- 0, 0, 0, 0, 0, false, false, false, false, 0, null);
-
- elem.dispatchEvent( event );
- } else if ( elem.fireEvent ) {
- elem.fireEvent( "on" + type );
- }
- },
-
- // Safe object type checking
- is: function( type, obj ) {
- return QUnit.objectType( obj ) === type;
- },
-
- objectType: function( obj ) {
- if ( typeof obj === "undefined" ) {
- return "undefined";
- // consider: typeof null === object
- }
- if ( obj === null ) {
- return "null";
- }
-
- var match = toString.call( obj ).match(/^\[object\s(.*)\]$/),
- type = match && match[1] || "";
-
- switch ( type ) {
- case "Number":
- if ( isNaN(obj) ) {
- return "nan";
- }
- return "number";
- case "String":
- case "Boolean":
- case "Array":
- case "Date":
- case "RegExp":
- case "Function":
- return type.toLowerCase();
- }
- if ( typeof obj === "object" ) {
- return "object";
- }
- return undefined;
- },
-
- push: function( result, actual, expected, message ) {
- if ( !config.current ) {
- throw new Error( "assertion outside test context, was " + sourceFromStacktrace() );
- }
-
- var output, source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: message,
- actual: actual,
- expected: expected
- };
-
- message = escapeText( message ) || ( result ? "okay" : "failed" );
- message = "" + message + "";
- output = message;
-
- if ( !result ) {
- expected = escapeText( QUnit.jsDump.parse(expected) );
- actual = escapeText( QUnit.jsDump.parse(actual) );
- output += "Expected: | " + expected + " |
";
-
- if ( actual !== expected ) {
- output += "Result: | " + actual + " |
";
- output += "Diff: | " + QUnit.diff( expected, actual ) + " |
";
- }
-
- source = sourceFromStacktrace();
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
- }
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: !!result,
- message: output
- });
- },
-
- pushFailure: function( message, source, actual ) {
- if ( !config.current ) {
- throw new Error( "pushFailure() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
-
- var output,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: false,
- message: message
- };
-
- message = escapeText( message ) || "error";
- message = "" + message + "";
- output = message;
-
- output += "";
-
- if ( actual ) {
- output += "Result: | " + escapeText( actual ) + " |
";
- }
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: false,
- message: output
- });
- },
-
- url: function( params ) {
- params = extend( extend( {}, QUnit.urlParams ), params );
- var key,
- querystring = "?";
-
- for ( key in params ) {
- if ( !hasOwn.call( params, key ) ) {
- continue;
- }
- querystring += encodeURIComponent( key ) + "=" +
- encodeURIComponent( params[ key ] ) + "&";
- }
- return window.location.protocol + "//" + window.location.host +
- window.location.pathname + querystring.slice( 0, -1 );
- },
-
- extend: extend,
- id: id,
- addEvent: addEvent
- // load, equiv, jsDump, diff: Attached later
-});
-
-/**
- * @deprecated: Created for backwards compatibility with test runner that set the hook function
- * into QUnit.{hook}, instead of invoking it and passing the hook function.
- * QUnit.constructor is set to the empty F() above so that we can add to it's prototype here.
- * Doing this allows us to tell if the following methods have been overwritten on the actual
- * QUnit object.
- */
-extend( QUnit.constructor.prototype, {
-
- // Logging callbacks; all receive a single argument with the listed properties
- // run test/logs.html for any related changes
- begin: registerLoggingCallback( "begin" ),
-
- // done: { failed, passed, total, runtime }
- done: registerLoggingCallback( "done" ),
-
- // log: { result, actual, expected, message }
- log: registerLoggingCallback( "log" ),
-
- // testStart: { name }
- testStart: registerLoggingCallback( "testStart" ),
-
- // testDone: { name, failed, passed, total, duration }
- testDone: registerLoggingCallback( "testDone" ),
-
- // moduleStart: { name }
- moduleStart: registerLoggingCallback( "moduleStart" ),
-
- // moduleDone: { name, failed, passed, total }
- moduleDone: registerLoggingCallback( "moduleDone" )
-});
-
-if ( typeof document === "undefined" || document.readyState === "complete" ) {
- config.autorun = true;
-}
-
-QUnit.load = function() {
- runLoggingCallbacks( "begin", QUnit, {} );
-
- // Initialize the config, saving the execution queue
- var banner, filter, i, label, len, main, ol, toolbar, userAgent, val,
- urlConfigCheckboxesContainer, urlConfigCheckboxes, moduleFilter,
- numModules = 0,
- moduleFilterHtml = "",
- urlConfigHtml = "",
- oldconfig = extend( {}, config );
-
- QUnit.init();
- extend(config, oldconfig);
-
- config.blocking = false;
-
- len = config.urlConfig.length;
-
- for ( i = 0; i < len; i++ ) {
- val = config.urlConfig[i];
- if ( typeof val === "string" ) {
- val = {
- id: val,
- label: val,
- tooltip: "[no tooltip available]"
- };
- }
- config[ val.id ] = QUnit.urlParams[ val.id ];
- urlConfigHtml += "";
- }
-
- moduleFilterHtml += "";
-
- // `userAgent` initialized at top of scope
- userAgent = id( "qunit-userAgent" );
- if ( userAgent ) {
- userAgent.innerHTML = navigator.userAgent;
- }
-
- // `banner` initialized at top of scope
- banner = id( "qunit-header" );
- if ( banner ) {
- banner.innerHTML = "" + banner.innerHTML + " ";
- }
-
- // `toolbar` initialized at top of scope
- toolbar = id( "qunit-testrunner-toolbar" );
- if ( toolbar ) {
- // `filter` initialized at top of scope
- filter = document.createElement( "input" );
- filter.type = "checkbox";
- filter.id = "qunit-filter-pass";
-
- addEvent( filter, "click", function() {
- var tmp,
- ol = document.getElementById( "qunit-tests" );
-
- if ( filter.checked ) {
- ol.className = ol.className + " hidepass";
- } else {
- tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " ";
- ol.className = tmp.replace( / hidepass /, " " );
- }
- if ( defined.sessionStorage ) {
- if (filter.checked) {
- sessionStorage.setItem( "qunit-filter-passed-tests", "true" );
- } else {
- sessionStorage.removeItem( "qunit-filter-passed-tests" );
- }
- }
- });
-
- if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem( "qunit-filter-passed-tests" ) ) {
- filter.checked = true;
- // `ol` initialized at top of scope
- ol = document.getElementById( "qunit-tests" );
- ol.className = ol.className + " hidepass";
- }
- toolbar.appendChild( filter );
-
- // `label` initialized at top of scope
- label = document.createElement( "label" );
- label.setAttribute( "for", "qunit-filter-pass" );
- label.setAttribute( "title", "Only show tests and assertons that fail. Stored in sessionStorage." );
- label.innerHTML = "Hide passed tests";
- toolbar.appendChild( label );
-
- urlConfigCheckboxesContainer = document.createElement("span");
- urlConfigCheckboxesContainer.innerHTML = urlConfigHtml;
- urlConfigCheckboxes = urlConfigCheckboxesContainer.getElementsByTagName("input");
- // For oldIE support:
- // * Add handlers to the individual elements instead of the container
- // * Use "click" instead of "change"
- // * Fallback from event.target to event.srcElement
- addEvents( urlConfigCheckboxes, "click", function( event ) {
- var params = {},
- target = event.target || event.srcElement;
- params[ target.name ] = target.checked ? true : undefined;
- window.location = QUnit.url( params );
- });
- toolbar.appendChild( urlConfigCheckboxesContainer );
-
- if (numModules > 1) {
- moduleFilter = document.createElement( 'span' );
- moduleFilter.setAttribute( 'id', 'qunit-modulefilter-container' );
- moduleFilter.innerHTML = moduleFilterHtml;
- addEvent( moduleFilter.lastChild, "change", function() {
- var selectBox = moduleFilter.getElementsByTagName("select")[0],
- selectedModule = decodeURIComponent(selectBox.options[selectBox.selectedIndex].value);
-
- window.location = QUnit.url( { module: ( selectedModule === "" ) ? undefined : selectedModule } );
- });
- toolbar.appendChild(moduleFilter);
- }
- }
-
- // `main` initialized at top of scope
- main = id( "qunit-fixture" );
- if ( main ) {
- config.fixture = main.innerHTML;
- }
-
- if ( config.autostart ) {
- QUnit.start();
- }
-};
-
-addEvent( window, "load", QUnit.load );
-
-// `onErrorFnPrev` initialized at top of scope
-// Preserve other handlers
-onErrorFnPrev = window.onerror;
-
-// Cover uncaught exceptions
-// Returning true will surpress the default browser handler,
-// returning false will let it run.
-window.onerror = function ( error, filePath, linerNr ) {
- var ret = false;
- if ( onErrorFnPrev ) {
- ret = onErrorFnPrev( error, filePath, linerNr );
- }
-
- // Treat return value as window.onerror itself does,
- // Only do our handling if not surpressed.
- if ( ret !== true ) {
- if ( QUnit.config.current ) {
- if ( QUnit.config.current.ignoreGlobalErrors ) {
- return true;
- }
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- } else {
- QUnit.test( "global failure", extend( function() {
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- }, { validTest: validTest } ) );
- }
- return false;
- }
-
- return ret;
-};
-
-function done() {
- config.autorun = true;
-
- // Log the last module results
- if ( config.currentModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.currentModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
-
- var i, key,
- banner = id( "qunit-banner" ),
- tests = id( "qunit-tests" ),
- runtime = +new Date() - config.started,
- passed = config.stats.all - config.stats.bad,
- html = [
- "Tests completed in ",
- runtime,
- " milliseconds.
",
- "",
- passed,
- " assertions of ",
- config.stats.all,
- " passed, ",
- config.stats.bad,
- " failed."
- ].join( "" );
-
- if ( banner ) {
- banner.className = ( config.stats.bad ? "qunit-fail" : "qunit-pass" );
- }
-
- if ( tests ) {
- id( "qunit-testresult" ).innerHTML = html;
- }
-
- if ( config.altertitle && typeof document !== "undefined" && document.title ) {
- // show ✖ for good, ✔ for bad suite result in title
- // use escape sequences in case file gets loaded with non-utf-8-charset
- document.title = [
- ( config.stats.bad ? "\u2716" : "\u2714" ),
- document.title.replace( /^[\u2714\u2716] /i, "" )
- ].join( " " );
- }
-
- // clear own sessionStorage items if all tests passed
- if ( config.reorder && defined.sessionStorage && config.stats.bad === 0 ) {
- // `key` & `i` initialized at top of scope
- for ( i = 0; i < sessionStorage.length; i++ ) {
- key = sessionStorage.key( i++ );
- if ( key.indexOf( "qunit-test-" ) === 0 ) {
- sessionStorage.removeItem( key );
- }
- }
- }
-
- // scroll back to top to show results
- if ( window.scrollTo ) {
- window.scrollTo(0, 0);
- }
-
- runLoggingCallbacks( "done", QUnit, {
- failed: config.stats.bad,
- passed: passed,
- total: config.stats.all,
- runtime: runtime
- });
-}
-
-/** @return Boolean: true if this test should be ran */
-function validTest( test ) {
- var include,
- filter = config.filter && config.filter.toLowerCase(),
- module = config.module && config.module.toLowerCase(),
- fullName = (test.module + ": " + test.testName).toLowerCase();
-
- // Internally-generated tests are always valid
- if ( test.callback && test.callback.validTest === validTest ) {
- delete test.callback.validTest;
- return true;
- }
-
- if ( config.testNumber ) {
- return test.testNumber === config.testNumber;
- }
-
- if ( module && ( !test.module || test.module.toLowerCase() !== module ) ) {
- return false;
- }
-
- if ( !filter ) {
- return true;
- }
-
- include = filter.charAt( 0 ) !== "!";
- if ( !include ) {
- filter = filter.slice( 1 );
- }
-
- // If the filter matches, we need to honour include
- if ( fullName.indexOf( filter ) !== -1 ) {
- return include;
- }
-
- // Otherwise, do the opposite
- return !include;
-}
-
-// so far supports only Firefox, Chrome and Opera (buggy), Safari (for real exceptions)
-// Later Safari and IE10 are supposed to support error.stack as well
-// See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack
-function extractStacktrace( e, offset ) {
- offset = offset === undefined ? 3 : offset;
-
- var stack, include, i;
-
- if ( e.stacktrace ) {
- // Opera
- return e.stacktrace.split( "\n" )[ offset + 3 ];
- } else if ( e.stack ) {
- // Firefox, Chrome
- stack = e.stack.split( "\n" );
- if (/^error$/i.test( stack[0] ) ) {
- stack.shift();
- }
- if ( fileName ) {
- include = [];
- for ( i = offset; i < stack.length; i++ ) {
- if ( stack[ i ].indexOf( fileName ) !== -1 ) {
- break;
- }
- include.push( stack[ i ] );
- }
- if ( include.length ) {
- return include.join( "\n" );
- }
- }
- return stack[ offset ];
- } else if ( e.sourceURL ) {
- // Safari, PhantomJS
- // hopefully one day Safari provides actual stacktraces
- // exclude useless self-reference for generated Error objects
- if ( /qunit.js$/.test( e.sourceURL ) ) {
- return;
- }
- // for actual exceptions, this is useful
- return e.sourceURL + ":" + e.line;
- }
-}
-function sourceFromStacktrace( offset ) {
- try {
- throw new Error();
- } catch ( e ) {
- return extractStacktrace( e, offset );
- }
-}
-
-/**
- * Escape text for attribute or text content.
- */
-function escapeText( s ) {
- if ( !s ) {
- return "";
- }
- s = s + "";
- // Both single quotes and double quotes (for attributes)
- return s.replace( /['"<>&]/g, function( s ) {
- switch( s ) {
- case '\'':
- return ''';
- case '"':
- return '"';
- case '<':
- return '<';
- case '>':
- return '>';
- case '&':
- return '&';
- }
- });
-}
-
-function synchronize( callback, last ) {
- config.queue.push( callback );
-
- if ( config.autorun && !config.blocking ) {
- process( last );
- }
-}
-
-function process( last ) {
- function next() {
- process( last );
- }
- var start = new Date().getTime();
- config.depth = config.depth ? config.depth + 1 : 1;
-
- while ( config.queue.length && !config.blocking ) {
- if ( !defined.setTimeout || config.updateRate <= 0 || ( ( new Date().getTime() - start ) < config.updateRate ) ) {
- config.queue.shift()();
- } else {
- window.setTimeout( next, 13 );
- break;
- }
- }
- config.depth--;
- if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) {
- done();
- }
-}
-
-function saveGlobal() {
- config.pollution = [];
-
- if ( config.noglobals ) {
- for ( var key in window ) {
- // in Opera sometimes DOM element ids show up here, ignore them
- if ( !hasOwn.call( window, key ) || /^qunit-test-output/.test( key ) ) {
- continue;
- }
- config.pollution.push( key );
- }
- }
-}
-
-function checkPollution() {
- var newGlobals,
- deletedGlobals,
- old = config.pollution;
-
- saveGlobal();
-
- newGlobals = diff( config.pollution, old );
- if ( newGlobals.length > 0 ) {
- QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join(", ") );
- }
-
- deletedGlobals = diff( old, config.pollution );
- if ( deletedGlobals.length > 0 ) {
- QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join(", ") );
- }
-}
-
-// returns a new Array with the elements that are in a but not in b
-function diff( a, b ) {
- var i, j,
- result = a.slice();
-
- for ( i = 0; i < result.length; i++ ) {
- for ( j = 0; j < b.length; j++ ) {
- if ( result[i] === b[j] ) {
- result.splice( i, 1 );
- i--;
- break;
- }
- }
- }
- return result;
-}
-
-function extend( a, b ) {
- for ( var prop in b ) {
- if ( b[ prop ] === undefined ) {
- delete a[ prop ];
-
- // Avoid "Member not found" error in IE8 caused by setting window.constructor
- } else if ( prop !== "constructor" || a !== window ) {
- a[ prop ] = b[ prop ];
- }
- }
-
- return a;
-}
-
-/**
- * @param {HTMLElement} elem
- * @param {string} type
- * @param {Function} fn
- */
-function addEvent( elem, type, fn ) {
- // Standards-based browsers
- if ( elem.addEventListener ) {
- elem.addEventListener( type, fn, false );
- // IE
- } else {
- elem.attachEvent( "on" + type, fn );
- }
-}
-
-/**
- * @param {Array|NodeList} elems
- * @param {string} type
- * @param {Function} fn
- */
-function addEvents( elems, type, fn ) {
- var i = elems.length;
- while ( i-- ) {
- addEvent( elems[i], type, fn );
- }
-}
-
-function hasClass( elem, name ) {
- return (" " + elem.className + " ").indexOf(" " + name + " ") > -1;
-}
-
-function addClass( elem, name ) {
- if ( !hasClass( elem, name ) ) {
- elem.className += (elem.className ? " " : "") + name;
- }
-}
-
-function removeClass( elem, name ) {
- var set = " " + elem.className + " ";
- // Class name may appear multiple times
- while ( set.indexOf(" " + name + " ") > -1 ) {
- set = set.replace(" " + name + " " , " ");
- }
- // If possible, trim it for prettiness, but not neccecarily
- elem.className = window.jQuery ? jQuery.trim( set ) : ( set.trim ? set.trim() : set );
-}
-
-function id( name ) {
- return !!( typeof document !== "undefined" && document && document.getElementById ) &&
- document.getElementById( name );
-}
-
-function registerLoggingCallback( key ) {
- return function( callback ) {
- config[key].push( callback );
- };
-}
-
-// Supports deprecated method of completely overwriting logging callbacks
-function runLoggingCallbacks( key, scope, args ) {
- var i, callbacks;
- if ( QUnit.hasOwnProperty( key ) ) {
- QUnit[ key ].call(scope, args );
- } else {
- callbacks = config[ key ];
- for ( i = 0; i < callbacks.length; i++ ) {
- callbacks[ i ].call( scope, args );
- }
- }
-}
-
-// Test for equality any JavaScript type.
-// Author: Philippe Rathé
-QUnit.equiv = (function() {
-
- // Call the o related callback with the given arguments.
- function bindCallbacks( o, callbacks, args ) {
- var prop = QUnit.objectType( o );
- if ( prop ) {
- if ( QUnit.objectType( callbacks[ prop ] ) === "function" ) {
- return callbacks[ prop ].apply( callbacks, args );
- } else {
- return callbacks[ prop ]; // or undefined
- }
- }
- }
-
- // the real equiv function
- var innerEquiv,
- // stack to decide between skip/abort functions
- callers = [],
- // stack to avoiding loops from circular referencing
- parents = [],
-
- getProto = Object.getPrototypeOf || function ( obj ) {
- return obj.__proto__;
- },
- callbacks = (function () {
-
- // for string, boolean, number and null
- function useStrictEquality( b, a ) {
- /*jshint eqeqeq:false */
- if ( b instanceof a.constructor || a instanceof b.constructor ) {
- // to catch short annotaion VS 'new' annotation of a
- // declaration
- // e.g. var i = 1;
- // var j = new Number(1);
- return a == b;
- } else {
- return a === b;
- }
- }
-
- return {
- "string": useStrictEquality,
- "boolean": useStrictEquality,
- "number": useStrictEquality,
- "null": useStrictEquality,
- "undefined": useStrictEquality,
-
- "nan": function( b ) {
- return isNaN( b );
- },
-
- "date": function( b, a ) {
- return QUnit.objectType( b ) === "date" && a.valueOf() === b.valueOf();
- },
-
- "regexp": function( b, a ) {
- return QUnit.objectType( b ) === "regexp" &&
- // the regex itself
- a.source === b.source &&
- // and its modifers
- a.global === b.global &&
- // (gmi) ...
- a.ignoreCase === b.ignoreCase &&
- a.multiline === b.multiline &&
- a.sticky === b.sticky;
- },
-
- // - skip when the property is a method of an instance (OOP)
- // - abort otherwise,
- // initial === would have catch identical references anyway
- "function": function() {
- var caller = callers[callers.length - 1];
- return caller !== Object && typeof caller !== "undefined";
- },
-
- "array": function( b, a ) {
- var i, j, len, loop;
-
- // b could be an object literal here
- if ( QUnit.objectType( b ) !== "array" ) {
- return false;
- }
-
- len = a.length;
- if ( len !== b.length ) {
- // safe and faster
- return false;
- }
-
- // track reference to avoid circular references
- parents.push( a );
- for ( i = 0; i < len; i++ ) {
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- loop = true;// dont rewalk array
- }
- }
- if ( !loop && !innerEquiv(a[i], b[i]) ) {
- parents.pop();
- return false;
- }
- }
- parents.pop();
- return true;
- },
-
- "object": function( b, a ) {
- var i, j, loop,
- // Default to true
- eq = true,
- aProperties = [],
- bProperties = [];
-
- // comparing constructors is more strict than using
- // instanceof
- if ( a.constructor !== b.constructor ) {
- // Allow objects with no prototype to be equivalent to
- // objects with Object as their constructor.
- if ( !(( getProto(a) === null && getProto(b) === Object.prototype ) ||
- ( getProto(b) === null && getProto(a) === Object.prototype ) ) ) {
- return false;
- }
- }
-
- // stack constructor before traversing properties
- callers.push( a.constructor );
- // track reference to avoid circular references
- parents.push( a );
-
- for ( i in a ) { // be strict: don't ensures hasOwnProperty
- // and go deep
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- // don't go down the same path twice
- loop = true;
- }
- }
- aProperties.push(i); // collect a's properties
-
- if (!loop && !innerEquiv( a[i], b[i] ) ) {
- eq = false;
- break;
- }
- }
-
- callers.pop(); // unstack, we are done
- parents.pop();
-
- for ( i in b ) {
- bProperties.push( i ); // collect b's properties
- }
-
- // Ensures identical properties name
- return eq && innerEquiv( aProperties.sort(), bProperties.sort() );
- }
- };
- }());
-
- innerEquiv = function() { // can take multiple arguments
- var args = [].slice.apply( arguments );
- if ( args.length < 2 ) {
- return true; // end transition
- }
-
- return (function( a, b ) {
- if ( a === b ) {
- return true; // catch the most you can
- } else if ( a === null || b === null || typeof a === "undefined" ||
- typeof b === "undefined" ||
- QUnit.objectType(a) !== QUnit.objectType(b) ) {
- return false; // don't lose time with error prone cases
- } else {
- return bindCallbacks(a, callbacks, [ b, a ]);
- }
-
- // apply transition with (1..n) arguments
- }( args[0], args[1] ) && arguments.callee.apply( this, args.splice(1, args.length - 1 )) );
- };
-
- return innerEquiv;
-}());
-
-/**
- * jsDump Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com |
- * http://flesler.blogspot.com Licensed under BSD
- * (http://www.opensource.org/licenses/bsd-license.php) Date: 5/15/2008
- *
- * @projectDescription Advanced and extensible data dumping for Javascript.
- * @version 1.0.0
- * @author Ariel Flesler
- * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html}
- */
-QUnit.jsDump = (function() {
- function quote( str ) {
- return '"' + str.toString().replace( /"/g, '\\"' ) + '"';
- }
- function literal( o ) {
- return o + "";
- }
- function join( pre, arr, post ) {
- var s = jsDump.separator(),
- base = jsDump.indent(),
- inner = jsDump.indent(1);
- if ( arr.join ) {
- arr = arr.join( "," + s + inner );
- }
- if ( !arr ) {
- return pre + post;
- }
- return [ pre, inner + arr, base + post ].join(s);
- }
- function array( arr, stack ) {
- var i = arr.length, ret = new Array(i);
- this.up();
- while ( i-- ) {
- ret[i] = this.parse( arr[i] , undefined , stack);
- }
- this.down();
- return join( "[", ret, "]" );
- }
-
- var reName = /^function (\w+)/,
- jsDump = {
- // type is used mostly internally, you can fix a (custom)type in advance
- parse: function( obj, type, stack ) {
- stack = stack || [ ];
- var inStack, res,
- parser = this.parsers[ type || this.typeOf(obj) ];
-
- type = typeof parser;
- inStack = inArray( obj, stack );
-
- if ( inStack !== -1 ) {
- return "recursion(" + (inStack - stack.length) + ")";
- }
- if ( type === "function" ) {
- stack.push( obj );
- res = parser.call( this, obj, stack );
- stack.pop();
- return res;
- }
- return ( type === "string" ) ? parser : this.parsers.error;
- },
- typeOf: function( obj ) {
- var type;
- if ( obj === null ) {
- type = "null";
- } else if ( typeof obj === "undefined" ) {
- type = "undefined";
- } else if ( QUnit.is( "regexp", obj) ) {
- type = "regexp";
- } else if ( QUnit.is( "date", obj) ) {
- type = "date";
- } else if ( QUnit.is( "function", obj) ) {
- type = "function";
- } else if ( typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined" ) {
- type = "window";
- } else if ( obj.nodeType === 9 ) {
- type = "document";
- } else if ( obj.nodeType ) {
- type = "node";
- } else if (
- // native arrays
- toString.call( obj ) === "[object Array]" ||
- // NodeList objects
- ( typeof obj.length === "number" && typeof obj.item !== "undefined" && ( obj.length ? obj.item(0) === obj[0] : ( obj.item( 0 ) === null && typeof obj[0] === "undefined" ) ) )
- ) {
- type = "array";
- } else if ( obj.constructor === Error.prototype.constructor ) {
- type = "error";
- } else {
- type = typeof obj;
- }
- return type;
- },
- separator: function() {
- return this.multiline ? this.HTML ? "
" : "\n" : this.HTML ? " " : " ";
- },
- // extra can be a number, shortcut for increasing-calling-decreasing
- indent: function( extra ) {
- if ( !this.multiline ) {
- return "";
- }
- var chr = this.indentChar;
- if ( this.HTML ) {
- chr = chr.replace( /\t/g, " " ).replace( / /g, " " );
- }
- return new Array( this._depth_ + (extra||0) ).join(chr);
- },
- up: function( a ) {
- this._depth_ += a || 1;
- },
- down: function( a ) {
- this._depth_ -= a || 1;
- },
- setParser: function( name, parser ) {
- this.parsers[name] = parser;
- },
- // The next 3 are exposed so you can use them
- quote: quote,
- literal: literal,
- join: join,
- //
- _depth_: 1,
- // This is the list of parsers, to modify them, use jsDump.setParser
- parsers: {
- window: "[Window]",
- document: "[Document]",
- error: function(error) {
- return "Error(\"" + error.message + "\")";
- },
- unknown: "[Unknown]",
- "null": "null",
- "undefined": "undefined",
- "function": function( fn ) {
- var ret = "function",
- // functions never have name in IE
- name = "name" in fn ? fn.name : (reName.exec(fn) || [])[1];
-
- if ( name ) {
- ret += " " + name;
- }
- ret += "( ";
-
- ret = [ ret, QUnit.jsDump.parse( fn, "functionArgs" ), "){" ].join( "" );
- return join( ret, QUnit.jsDump.parse(fn,"functionCode" ), "}" );
- },
- array: array,
- nodelist: array,
- "arguments": array,
- object: function( map, stack ) {
- var ret = [ ], keys, key, val, i;
- QUnit.jsDump.up();
- keys = [];
- for ( key in map ) {
- keys.push( key );
- }
- keys.sort();
- for ( i = 0; i < keys.length; i++ ) {
- key = keys[ i ];
- val = map[ key ];
- ret.push( QUnit.jsDump.parse( key, "key" ) + ": " + QUnit.jsDump.parse( val, undefined, stack ) );
- }
- QUnit.jsDump.down();
- return join( "{", ret, "}" );
- },
- node: function( node ) {
- var len, i, val,
- open = QUnit.jsDump.HTML ? "<" : "<",
- close = QUnit.jsDump.HTML ? ">" : ">",
- tag = node.nodeName.toLowerCase(),
- ret = open + tag,
- attrs = node.attributes;
-
- if ( attrs ) {
- for ( i = 0, len = attrs.length; i < len; i++ ) {
- val = attrs[i].nodeValue;
- // IE6 includes all attributes in .attributes, even ones not explicitly set.
- // Those have values like undefined, null, 0, false, "" or "inherit".
- if ( val && val !== "inherit" ) {
- ret += " " + attrs[i].nodeName + "=" + QUnit.jsDump.parse( val, "attribute" );
- }
- }
- }
- ret += close;
-
- // Show content of TextNode or CDATASection
- if ( node.nodeType === 3 || node.nodeType === 4 ) {
- ret += node.nodeValue;
- }
-
- return ret + open + "/" + tag + close;
- },
- // function calls it internally, it's the arguments part of the function
- functionArgs: function( fn ) {
- var args,
- l = fn.length;
-
- if ( !l ) {
- return "";
- }
-
- args = new Array(l);
- while ( l-- ) {
- // 97 is 'a'
- args[l] = String.fromCharCode(97+l);
- }
- return " " + args.join( ", " ) + " ";
- },
- // object calls it internally, the key part of an item in a map
- key: quote,
- // function calls it internally, it's the content of the function
- functionCode: "[code]",
- // node calls it internally, it's an html attribute value
- attribute: quote,
- string: quote,
- date: quote,
- regexp: literal,
- number: literal,
- "boolean": literal
- },
- // if true, entities are escaped ( <, >, \t, space and \n )
- HTML: false,
- // indentation unit
- indentChar: " ",
- // if true, items in a collection, are separated by a \n, else just a space.
- multiline: true
- };
-
- return jsDump;
-}());
-
-// from jquery.js
-function inArray( elem, array ) {
- if ( array.indexOf ) {
- return array.indexOf( elem );
- }
-
- for ( var i = 0, length = array.length; i < length; i++ ) {
- if ( array[ i ] === elem ) {
- return i;
- }
- }
-
- return -1;
-}
-
-/*
- * Javascript Diff Algorithm
- * By John Resig (http://ejohn.org/)
- * Modified by Chu Alan "sprite"
- *
- * Released under the MIT license.
- *
- * More Info:
- * http://ejohn.org/projects/javascript-diff-algorithm/
- *
- * Usage: QUnit.diff(expected, actual)
- *
- * QUnit.diff( "the quick brown fox jumped over", "the quick fox jumps over" ) == "the quick brown fox jumped jumps over"
- */
-QUnit.diff = (function() {
- /*jshint eqeqeq:false, eqnull:true */
- function diff( o, n ) {
- var i,
- ns = {},
- os = {};
-
- for ( i = 0; i < n.length; i++ ) {
- if ( !hasOwn.call( ns, n[i] ) ) {
- ns[ n[i] ] = {
- rows: [],
- o: null
- };
- }
- ns[ n[i] ].rows.push( i );
- }
-
- for ( i = 0; i < o.length; i++ ) {
- if ( !hasOwn.call( os, o[i] ) ) {
- os[ o[i] ] = {
- rows: [],
- n: null
- };
- }
- os[ o[i] ].rows.push( i );
- }
-
- for ( i in ns ) {
- if ( !hasOwn.call( ns, i ) ) {
- continue;
- }
- if ( ns[i].rows.length === 1 && hasOwn.call( os, i ) && os[i].rows.length === 1 ) {
- n[ ns[i].rows[0] ] = {
- text: n[ ns[i].rows[0] ],
- row: os[i].rows[0]
- };
- o[ os[i].rows[0] ] = {
- text: o[ os[i].rows[0] ],
- row: ns[i].rows[0]
- };
- }
- }
-
- for ( i = 0; i < n.length - 1; i++ ) {
- if ( n[i].text != null && n[ i + 1 ].text == null && n[i].row + 1 < o.length && o[ n[i].row + 1 ].text == null &&
- n[ i + 1 ] == o[ n[i].row + 1 ] ) {
-
- n[ i + 1 ] = {
- text: n[ i + 1 ],
- row: n[i].row + 1
- };
- o[ n[i].row + 1 ] = {
- text: o[ n[i].row + 1 ],
- row: i + 1
- };
- }
- }
-
- for ( i = n.length - 1; i > 0; i-- ) {
- if ( n[i].text != null && n[ i - 1 ].text == null && n[i].row > 0 && o[ n[i].row - 1 ].text == null &&
- n[ i - 1 ] == o[ n[i].row - 1 ]) {
-
- n[ i - 1 ] = {
- text: n[ i - 1 ],
- row: n[i].row - 1
- };
- o[ n[i].row - 1 ] = {
- text: o[ n[i].row - 1 ],
- row: i - 1
- };
- }
- }
-
- return {
- o: o,
- n: n
- };
- }
-
- return function( o, n ) {
- o = o.replace( /\s+$/, "" );
- n = n.replace( /\s+$/, "" );
-
- var i, pre,
- str = "",
- out = diff( o === "" ? [] : o.split(/\s+/), n === "" ? [] : n.split(/\s+/) ),
- oSpace = o.match(/\s+/g),
- nSpace = n.match(/\s+/g);
-
- if ( oSpace == null ) {
- oSpace = [ " " ];
- }
- else {
- oSpace.push( " " );
- }
-
- if ( nSpace == null ) {
- nSpace = [ " " ];
- }
- else {
- nSpace.push( " " );
- }
-
- if ( out.n.length === 0 ) {
- for ( i = 0; i < out.o.length; i++ ) {
- str += "" + out.o[i] + oSpace[i] + "";
- }
- }
- else {
- if ( out.n[0].text == null ) {
- for ( n = 0; n < out.o.length && out.o[n].text == null; n++ ) {
- str += "" + out.o[n] + oSpace[n] + "";
- }
- }
-
- for ( i = 0; i < out.n.length; i++ ) {
- if (out.n[i].text == null) {
- str += "" + out.n[i] + nSpace[i] + "";
- }
- else {
- // `pre` initialized at top of scope
- pre = "";
-
- for ( n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++ ) {
- pre += "" + out.o[n] + oSpace[n] + "";
- }
- str += " " + out.n[i].text + nSpace[i] + pre;
- }
- }
- }
-
- return str;
- };
-}());
-
-// for CommonJS enviroments, export everything
-if ( typeof exports !== "undefined" ) {
- extend( exports, QUnit );
-}
-
-// get at whatever the global object is, like window in browsers
-}( (function() {return this;}.call()) ));
diff --git a/test/lib/require.js b/test/lib/require.js
deleted file mode 100644
index 987f865..0000000
--- a/test/lib/require.js
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- RequireJS 2.1.5 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.
- Available via the MIT or new BSD license.
- see: http://github.com/jrburke/requirejs for details
-*/
-var requirejs,require,define;
-(function(aa){function I(b){return"[object Function]"===L.call(b)}function J(b){return"[object Array]"===L.call(b)}function y(b,c){if(b){var d;for(d=0;dthis.depCount&&!this.defined){if(I(n)){if(this.events.error)try{e=i.execCb(c,n,b,e)}catch(d){a=d}else e=i.execCb(c,n,b,e);this.map.isDefine&&((b=this.module)&&void 0!==b.exports&&b.exports!==this.exports?e=b.exports:void 0===e&&this.usingExports&&(e=this.exports));if(a)return a.requireMap=this.map,a.requireModules=[this.map.id],a.requireType="define",v(this.error=
-a)}else e=n;this.exports=e;if(this.map.isDefine&&!this.ignore&&(q[c]=e,l.onResourceLoad))l.onResourceLoad(i,this.map,this.depMaps);x(c);this.defined=!0}this.defining=!1;this.defined&&!this.defineEmitted&&(this.defineEmitted=!0,this.emit("defined",this.exports),this.defineEmitComplete=!0)}}else this.fetch()}},callPlugin:function(){var a=this.map,b=a.id,d=j(a.prefix);this.depMaps.push(d);t(d,"defined",u(this,function(e){var n,d;d=this.map.name;var g=this.map.parentMap?this.map.parentMap.name:null,h=
-i.makeRequire(a.parentMap,{enableBuildCallback:!0});if(this.map.unnormalized){if(e.normalize&&(d=e.normalize(d,function(a){return c(a,g,!0)})||""),e=j(a.prefix+"!"+d,this.map.parentMap),t(e,"defined",u(this,function(a){this.init([],function(){return a},null,{enabled:!0,ignore:!0})})),d=m(p,e.id)){this.depMaps.push(e);if(this.events.error)d.on("error",u(this,function(a){this.emit("error",a)}));d.enable()}}else n=u(this,function(a){this.init([],function(){return a},null,{enabled:!0})}),n.error=u(this,
-function(a){this.inited=!0;this.error=a;a.requireModules=[b];G(p,function(a){0===a.map.id.indexOf(b+"_unnormalized")&&x(a.map.id)});v(a)}),n.fromText=u(this,function(e,c){var d=a.name,g=j(d),C=O;c&&(e=c);C&&(O=!1);r(g);s(k.config,b)&&(k.config[d]=k.config[b]);try{l.exec(e)}catch(ca){return v(B("fromtexteval","fromText eval for "+b+" failed: "+ca,ca,[b]))}C&&(O=!0);this.depMaps.push(g);i.completeLoad(d);h([d],n)}),e.load(a.name,h,n,k)}));i.enable(d,this);this.pluginMaps[d.id]=d},enable:function(){V[this.map.id]=
-this;this.enabling=this.enabled=!0;y(this.depMaps,u(this,function(a,b){var c,e;if("string"===typeof a){a=j(a,this.map.isDefine?this.map:this.map.parentMap,!1,!this.skipMap);this.depMaps[b]=a;if(c=m(N,a.id)){this.depExports[b]=c(this);return}this.depCount+=1;t(a,"defined",u(this,function(a){this.defineDep(b,a);this.check()}));this.errback&&t(a,"error",this.errback)}c=a.id;e=p[c];!s(N,c)&&(e&&!e.enabled)&&i.enable(a,this)}));G(this.pluginMaps,u(this,function(a){var b=m(p,a.id);b&&!b.enabled&&i.enable(a,
-this)}));this.enabling=!1;this.check()},on:function(a,b){var c=this.events[a];c||(c=this.events[a]=[]);c.push(b)},emit:function(a,b){y(this.events[a],function(a){a(b)});"error"===a&&delete this.events[a]}};i={config:k,contextName:b,registry:p,defined:q,urlFetched:U,defQueue:H,Module:Z,makeModuleMap:j,nextTick:l.nextTick,onError:v,configure:function(a){a.baseUrl&&"/"!==a.baseUrl.charAt(a.baseUrl.length-1)&&(a.baseUrl+="/");var b=k.pkgs,c=k.shim,e={paths:!0,config:!0,map:!0};G(a,function(a,b){e[b]?
-"map"===b?(k.map||(k.map={}),R(k[b],a,!0,!0)):R(k[b],a,!0):k[b]=a});a.shim&&(G(a.shim,function(a,b){J(a)&&(a={deps:a});if((a.exports||a.init)&&!a.exportsFn)a.exportsFn=i.makeShimExports(a);c[b]=a}),k.shim=c);a.packages&&(y(a.packages,function(a){a="string"===typeof a?{name:a}:a;b[a.name]={name:a.name,location:a.location||a.name,main:(a.main||"main").replace(ja,"").replace(ea,"")}}),k.pkgs=b);G(p,function(a,b){!a.inited&&!a.map.unnormalized&&(a.map=j(b))});if(a.deps||a.callback)i.require(a.deps||[],
-a.callback)},makeShimExports:function(a){return function(){var b;a.init&&(b=a.init.apply(aa,arguments));return b||a.exports&&ba(a.exports)}},makeRequire:function(a,f){function d(e,c,h){var g,k;f.enableBuildCallback&&(c&&I(c))&&(c.__requireJsBuild=!0);if("string"===typeof e){if(I(c))return v(B("requireargs","Invalid require call"),h);if(a&&s(N,e))return N[e](p[a.id]);if(l.get)return l.get(i,e,a,d);g=j(e,a,!1,!0);g=g.id;return!s(q,g)?v(B("notloaded",'Module name "'+g+'" has not been loaded yet for context: '+
-b+(a?"":". Use require([])"))):q[g]}L();i.nextTick(function(){L();k=r(j(null,a));k.skipMap=f.skipMap;k.init(e,c,h,{enabled:!0});D()});return d}f=f||{};R(d,{isBrowser:A,toUrl:function(b){var d,f=b.lastIndexOf("."),g=b.split("/")[0];if(-1!==f&&(!("."===g||".."===g)||1h.attachEvent.toString().indexOf("[native code"))&&!Y?(O=!0,h.attachEvent("onreadystatechange",b.onScriptLoad)):(h.addEventListener("load",b.onScriptLoad,!1),h.addEventListener("error",b.onScriptError,!1)),h.src=d,K=h,D?x.insertBefore(h,D):x.appendChild(h),K=null,h;if(da)try{importScripts(d),b.completeLoad(c)}catch(j){b.onError(B("importscripts","importScripts failed for "+c+" at "+d,j,[c]))}};A&&M(document.getElementsByTagName("script"),function(b){x||(x=
-b.parentNode);if(t=b.getAttribute("data-main"))return r.baseUrl||(E=t.split("/"),Q=E.pop(),fa=E.length?E.join("/")+"/":"./",r.baseUrl=fa,t=Q),t=t.replace(ea,""),r.deps=r.deps?r.deps.concat(t):[t],!0});define=function(b,c,d){var l,h;"string"!==typeof b&&(d=c,c=b,b=null);J(c)||(d=c,c=[]);!c.length&&I(d)&&d.length&&(d.toString().replace(la,"").replace(ma,function(b,d){c.push(d)}),c=(1===d.length?["require"]:["require","exports","module"]).concat(c));if(O){if(!(l=K))P&&"interactive"===P.readyState||M(document.getElementsByTagName("script"),
-function(b){if("interactive"===b.readyState)return P=b}),l=P;l&&(b||(b=l.getAttribute("data-requiremodule")),h=F[l.getAttribute("data-requirecontext")])}(h?h.defQueue:T).push([b,c,d])};define.amd={jQuery:!0};l.exec=function(b){return eval(b)};l(r)}})(this);
diff --git a/test/lib/resemble.js b/test/lib/resemble.js
new file mode 100644
index 0000000..1cb8c29
--- /dev/null
+++ b/test/lib/resemble.js
@@ -0,0 +1,535 @@
+/*
+Author: James Cryer
+Company: Huddle
+Last updated date: 21 Feb 2013
+URL: https://github.com/Huddle/Resemble.js
+*/
+
+(function(_this){
+ 'use strict';
+
+ _this['resemble'] = function( fileData ){
+
+ var data = {};
+ var images = [];
+ var updateCallbackArray = [];
+
+ var tolerance = { // between 0 and 255
+ red: 16,
+ green: 16,
+ blue: 16,
+ minBrightness: 16,
+ maxBrightness: 240
+ };
+
+ var ignoreAntialiasing = false;
+ var ignoreColors = false;
+
+ function triggerDataUpdate(){
+ var len = updateCallbackArray.length;
+ var i;
+ for(i=0;i tolerance.maxBrightness;
+ }
+
+ function getHue(r,g,b){
+
+ r = r / 255;
+ g = g / 255;
+ b = b / 255;
+ var max = Math.max(r, g, b), min = Math.min(r, g, b);
+ var h;
+ var d;
+
+ if (max == min){
+ h = 0; // achromatic
+ } else{
+ d = max - min;
+ switch(max){
+ case r: h = (g - b) / d + (g < b ? 6 : 0); break;
+ case g: h = (b - r) / d + 2; break;
+ case b: h = (r - g) / d + 4; break;
+ }
+ h /= 6;
+ }
+
+ return h;
+ }
+
+ function isAntialiased(sourcePix, data, cacheSet, verticalPos, horizontalPos, width){
+ var offset;
+ var targetPix;
+ var distance = 1;
+ var i;
+ var j;
+ var hasHighContrastSibling = 0;
+ var hasSiblingWithDifferentHue = 0;
+ var hasEquivilantSibling = 0;
+
+ addHueInfo(sourcePix);
+
+ for (i = distance*-1; i <= distance; i++){
+ for (j = distance*-1; j <= distance; j++){
+
+ if(i===0 && j===0){
+ // ignore source pixel
+ } else {
+
+ offset = ((verticalPos+j)*width + (horizontalPos+i)) * 4;
+ targetPix = getPixelInfo(data, offset, cacheSet);
+
+ if(targetPix === null){
+ continue;
+ }
+
+ addBrightnessInfo(targetPix);
+ addHueInfo(targetPix);
+
+ if( isContrasting(sourcePix, targetPix) ){
+ hasHighContrastSibling++;
+ }
+
+ if( isRGBSame(sourcePix,targetPix) ){
+ hasEquivilantSibling++;
+ }
+
+ if( Math.abs(targetPix.h - sourcePix.h) > 0.3 ){
+ hasSiblingWithDifferentHue++;
+ }
+
+ if( hasSiblingWithDifferentHue > 1 || hasHighContrastSibling > 1){
+ return true;
+ }
+ }
+ }
+ }
+
+ if(hasEquivilantSibling < 2){
+ return true;
+ }
+
+ return false;
+ }
+
+ function errorPixel(px, offset){
+ px[offset] = 255; //r
+ px[offset + 1] = 0; //g
+ px[offset + 2] = 255; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyPixel(px, offset, data){
+ px[offset] = data.r; //r
+ px[offset + 1] = data.g; //g
+ px[offset + 2] = data.b; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyGrayScalePixel(px, offset, data){
+ px[offset] = data.brightness; //r
+ px[offset + 1] = data.brightness; //g
+ px[offset + 2] = data.brightness; //b
+ px[offset + 3] = 255; //a
+ }
+
+
+ function getPixelInfo(data, offset, cacheSet){
+ var r;
+ var g;
+ var b;
+ var d;
+
+ if(typeof data[offset] !== 'undefined'){
+ r = data[offset];
+ g = data[offset+1];
+ b = data[offset+2];
+ d = {
+ r: r,
+ g: g,
+ b: b
+ };
+
+ return d;
+ } else {
+ return null;
+ }
+ }
+
+ function addBrightnessInfo(data){
+ data.brightness = getBrightness(data.r,data.g,data.b); // 'corrected' lightness
+ }
+
+ function addHueInfo(data){
+ data.h = getHue(data.r,data.g,data.b);
+ }
+
+ function analyseImages(img1, img2, width, height){
+
+ var hiddenCanvas = document.createElement('canvas');
+
+ var data1 = img1.data;
+ var data2 = img2.data;
+
+ hiddenCanvas.width = width;
+ hiddenCanvas.height = height;
+
+ var context = hiddenCanvas.getContext('2d');
+ var imgd = context.createImageData(width,height);
+ var targetPix = imgd.data;
+
+ var mismatchCount = 0;
+
+ var time = Date.now();
+
+ var skip;
+
+ if( (width > 1200 || height > 1200) && ignoreAntialiasing){
+ skip = 6;
+ }
+
+ loop(height, width, function(verticalPos, horizontalPos){
+
+ if(skip){ // only skip if the image isn't small
+ if(verticalPos % skip === 0 || horizontalPos % skip === 0){
+ return;
+ }
+ }
+
+ var offset = (verticalPos*width + horizontalPos) * 4;
+ var pixel1 = getPixelInfo(data1, offset, 1);
+ var pixel2 = getPixelInfo(data2, offset, 2);
+
+ if(pixel1 === null || pixel2 === null){
+ return;
+ }
+
+ if (ignoreColors){
+
+ addBrightnessInfo(pixel1);
+ addBrightnessInfo(pixel2);
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ return;
+ }
+
+ if( isRGBSimilar(pixel1, pixel2) ){
+ copyPixel(targetPix, offset, pixel2);
+
+ } else if( ignoreAntialiasing && (
+ addBrightnessInfo(pixel1), // jit pixel info augmentation looks a little weird, sorry.
+ addBrightnessInfo(pixel2),
+ isAntialiased(pixel1, data1, 1, verticalPos, horizontalPos, width) ||
+ isAntialiased(pixel2, data2, 2, verticalPos, horizontalPos, width)
+ )){
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+
+ });
+
+ data.misMatchPercentage = (mismatchCount / (height*width) * 100).toFixed(2);
+ data.analysisTime = Date.now() - time;
+
+ data.getImageDataUrl = function(text){
+ var barHeight = 0;
+
+ if(text){
+ barHeight = addLabel(text,context,hiddenCanvas);
+ }
+
+ context.putImageData(imgd, 0, barHeight);
+
+ return hiddenCanvas.toDataURL("image/png");
+ };
+ }
+
+ function addLabel(text, context, hiddenCanvas){
+ var textPadding = 2;
+
+ context.font = '12px sans-serif';
+
+ var textWidth = context.measureText(text).width + textPadding*2;
+ var barHeight = 22;
+
+ if(textWidth > hiddenCanvas.width){
+ hiddenCanvas.width = textWidth;
+ }
+
+ hiddenCanvas.height += barHeight;
+
+ context.fillStyle = "#666";
+ context.fillRect(0,0,hiddenCanvas.width,barHeight -4);
+ context.fillStyle = "#fff";
+ context.fillRect(0,barHeight -4,hiddenCanvas.width, 4);
+
+ context.fillStyle = "#fff";
+ context.textBaseline = "top";
+ context.font = '12px sans-serif';
+ context.fillText(text, textPadding, 1);
+
+ return barHeight;
+ }
+
+ function normalise(img, w, h){
+ var c;
+ var context;
+
+ if(img.height < h || img.width < w){
+ c = document.createElement('canvas');
+ c.width = w;
+ c.height = h;
+ context = c.getContext('2d');
+ context.putImageData(img, 0, 0);
+ return context.getImageData(0, 0, w, h);
+ }
+
+ return img;
+ }
+
+ function compare(one, two){
+
+ function onceWeHaveBoth(){
+ var width;
+ var height;
+ if(images.length === 2){
+ width = images[0].width > images[1].width ? images[0].width : images[1].width;
+ height = images[0].height > images[1].height ? images[0].height : images[1].height;
+
+ if( (images[0].width === images[1].width) && (images[0].height === images[1].height) ){
+ data.isSameDimensions = true;
+ } else {
+ data.isSameDimensions = false;
+ }
+
+ analyseImages( normalise(images[0],width, height), normalise(images[1],width, height), width, height);
+
+ triggerDataUpdate();
+ }
+ }
+
+ images = [];
+ loadImageData(one, onceWeHaveBoth);
+ loadImageData(two, onceWeHaveBoth);
+ }
+
+ function getCompareApi(param){
+
+ var secondFileData,
+ hasMethod = typeof param === 'function';
+
+ if( !hasMethod ){
+ // assume it's file data
+ secondFileData = param;
+ }
+
+ var self = {
+ ignoreNothing: function(){
+
+ tolerance.red = 16;
+ tolerance.green = 16;
+ tolerance.blue = 16;
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreAntialiasing: function(){
+
+ tolerance.red = 32;
+ tolerance.green = 32;
+ tolerance.blue = 32;
+ tolerance.minBrightness = 64;
+ tolerance.maxBrightness = 96;
+
+ ignoreAntialiasing = true;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreColors: function(){
+
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = true;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ onComplete: function( callback ){
+
+ updateCallbackArray.push(callback);
+
+ var wrapper = function(){
+ compare(fileData, secondFileData);
+ };
+
+ wrapper();
+
+ return getCompareApi(wrapper);
+ }
+ };
+
+ return self;
+ }
+
+ return {
+ onComplete: function( callback ){
+ updateCallbackArray.push(callback);
+ loadImageData(fileData, function(imageData, width, height){
+ parseImage(imageData.data, width, height);
+ });
+ },
+ compareTo: function(secondFileData){
+ return getCompareApi(secondFileData);
+ }
+ };
+
+ };
+}(this));
\ No newline at end of file
diff --git a/test/testsuite.js b/test/testsuite.js
deleted file mode 100644
index b486acb..0000000
--- a/test/testsuite.js
+++ /dev/null
@@ -1,36 +0,0 @@
-requirejs.config({
- baseUrl: '/test/unit/'
-});
-
-define(function(require) {
- var testModules = [
- 'Pixi',
- 'Point',
- 'Rectangle',
- 'DisplayObject',
- 'DisplayObjectContainer',
- 'Sprite',
- 'MovieClip',
- 'InteractionManager',
- 'Stage',
- 'utils/Utils',
- 'utils/EventTarget',
- 'utils/Matrix',
- 'utils/Detector',
- 'renderers/WebGLShaders',
- 'renderers/WebGLRenderer',
- 'renderers/WebGLBatch',
- 'renderers/CanvasRenderer',
- 'extras/Strip',
- 'extras/Rope',
- 'textures/BaseTexture',
- 'textures/Texture',
- 'loaders/SpriteSheetLoader',
- 'loaders/AssetLoader'
- ];
-
- // Resolve all testModules and then start the Test Runner.
- require(testModules, function() {
- QUnit.start();
- });
-});
\ No newline at end of file
diff --git a/test/textures/SpriteSheet-Aliens.png b/test/textures/SpriteSheet-Aliens.png
new file mode 100644
index 0000000..210acb1
--- /dev/null
+++ b/test/textures/SpriteSheet-Aliens.png
Binary files differ
diff --git a/.gitignore b/.gitignore
index 12e1b62..0b88317 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
node_modules
.DS_Store
-.project
\ No newline at end of file
+.project
+*.log
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..63e4d7c
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,8 @@
+language: node_js
+node_js:
+ - 0.10
+
+before_script:
+ - npm install -g grunt-cli
+ - export DISPLAY=:99.0
+ - sh -e /etc/init.d/xvfb start
diff --git a/Gruntfile.js b/Gruntfile.js
index b083b49..103938c 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -1,10 +1,12 @@
+'use strict';
+
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-connect');
- grunt.loadNpmTasks('grunt-contrib-qunit');
grunt.loadNpmTasks('grunt-contrib-yuidoc');
+ grunt.loadTasks('tasks');
var root = 'src/pixi/',
debug = 'bin/pixi.dev.js',
@@ -79,7 +81,7 @@
},
files: {
srcBlob: '<%= dirs.src %>/**/*.js',
- testBlob: '<%= dirs.test %>/unit/**/*.js',
+ testBlob: '<%= dirs.test %>/{functional,lib/pixi,unit}/**/*.js',
build: '<%= dirs.build %>/pixi.dev.js',
buildMin: '<%= dirs.build %>/pixi.js'
},
@@ -94,7 +96,12 @@
},
jshint: {
beforeconcat: srcFiles,
- test: ['<%= files.testBlob %>'],
+ test: {
+ src: ['<%= files.testBlob %>'],
+ options: {
+ expr: true
+ }
+ },
options: {
asi: true,
smarttabs: true
@@ -128,12 +135,6 @@
]
},
connect: {
- qunit: {
- options: {
- port: grunt.option('port-test') || 9002,
- base: './'
- }
- },
test: {
options: {
port: grunt.option('port-test') || 9002,
@@ -142,13 +143,6 @@
}
}
},
- qunit: {
- all: {
- options: {
- urls: ['http://localhost:' + (grunt.option('port-test') || 9002) + '/test/index.html']
- }
- }
- },
yuidoc: {
compile: {
name: '<%= pkg.name %>',
@@ -161,6 +155,13 @@
outdir: '<%= dirs.docs %>'
}
}
+ },
+ karma: {
+ unit: {
+ configFile: 'test/karma.conf.js',
+ // browsers: ['Chrome'],
+ singleRun: true
+ }
}
});
@@ -182,9 +183,10 @@
}
)
- grunt.registerTask('default', ['concat', 'uglify', 'distribute']);
grunt.registerTask('build', ['concat', 'uglify', 'distribute']);
- grunt.registerTask('test', ['build', 'connect:qunit', 'qunit']);
+ grunt.registerTask('test', ['concat', 'jshint:test', 'karma']);
grunt.registerTask('docs', ['yuidoc']);
-
-}
\ No newline at end of file
+ grunt.registerTask('default', ['test', 'uglify', 'distribute']);
+ // Travis CI task.
+ grunt.registerTask('travis', ['test']);
+}
diff --git a/README.md b/README.md
index c62ef86..690cfe4 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,8 @@

+[](http://travis-ci.org/drkibitz/pixi.js)
+
#### JavaScript 2D Renderer ####
The aim of this project is to provide a fast lightweight 2D library that works
diff --git a/package.json b/package.json
index b373240..1246a68 100644
--- a/package.json
+++ b/package.json
@@ -18,14 +18,21 @@
"main": "bin/pixi.js",
+ "scripts": {
+ "test": "grunt travis --verbose"
+ },
+
"dependencies": {},
"devDependencies": {
"grunt": "~0.4.x",
- "grunt-contrib-jshint": "0.3.x",
+ "grunt-contrib-jshint": "0.6.x",
"grunt-contrib-uglify": "0.2.x",
- "grunt-contrib-connect": "0.2.x",
- "grunt-contrib-qunit": "0.2.x",
+ "grunt-contrib-connect": "0.3.x",
"grunt-contrib-yuidoc": "0.4.x",
- "grunt-contrib-concat": "0.1.x"
+ "grunt-contrib-concat": "0.3.x",
+ "chai": "~1.7.0",
+ "karma": "0.11.0",
+ "karma-firefox-launcher": "0.1.0",
+ "karma-mocha": "0.1.0"
}
}
diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js
index a7c520e..ee82bbd 100644
--- a/src/pixi/InteractionManager.js
+++ b/src/pixi/InteractionManager.js
@@ -62,7 +62,6 @@
this.onTouchEnd = this.onTouchEnd.bind(this);
this.onTouchMove = this.onTouchMove.bind(this);
-
this.last = 0;
}
diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js
index 1a95d20..eef1059 100644
--- a/src/pixi/core/Ellipse.js
+++ b/src/pixi/core/Ellipse.js
@@ -78,7 +78,7 @@
return (normx + normy < 0.25);
}
-PIXI.Ellipse.getBounds = function()
+PIXI.Ellipse.prototype.getBounds = function()
{
return new PIXI.Rectangle(this.x, this.y, this.width, this.height);
}
diff --git a/tasks/karma.js b/tasks/karma.js
new file mode 100644
index 0000000..c340485
--- /dev/null
+++ b/tasks/karma.js
@@ -0,0 +1,27 @@
+'use strict';
+
+var path = require('path');
+var server = require('karma').server;
+
+module.exports = function (grunt) {
+ grunt.registerMultiTask('karma', 'run karma.', function() {
+ var done = this.async();
+ var options = this.options({
+ background: false
+ });
+ var data = this.data;
+
+ //merge options onto data, with data taking precedence
+ data = grunt.util._.merge(options, data);
+ data.configFile = path.resolve(data.configFile);
+ if (data.configFile) {
+ data.configFile = grunt.template.process(data.configFile);
+ }
+
+ server.start(
+ data,
+ function(code) {
+ done(!code);
+ });
+ });
+};
diff --git a/test/functional/example-1-basics/bunny.png b/test/functional/example-1-basics/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/functional/example-1-basics/bunny.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-30.png b/test/functional/example-1-basics/frame-30.png
new file mode 100644
index 0000000..96e3409
--- /dev/null
+++ b/test/functional/example-1-basics/frame-30.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-60.png b/test/functional/example-1-basics/frame-60.png
new file mode 100644
index 0000000..af3f4ce
--- /dev/null
+++ b/test/functional/example-1-basics/frame-60.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-90.png b/test/functional/example-1-basics/frame-90.png
new file mode 100644
index 0000000..099b823
--- /dev/null
+++ b/test/functional/example-1-basics/frame-90.png
Binary files differ
diff --git a/test/functional/example-1-basics/index.js b/test/functional/example-1-basics/index.js
new file mode 100644
index 0000000..7ae7a98
--- /dev/null
+++ b/test/functional/example-1-basics/index.js
@@ -0,0 +1,133 @@
+describe('Example 1 - Basics', function () {
+ 'use strict';
+
+ var baseUri = '/base/test/functional/example-1-basics';
+ var expect = chai.expect;
+ var currentFrame = 0;
+ var frameEvents = {};
+ var stage;
+ var renderer;
+ var bunny;
+
+ function onFrame(frame, callback) {
+ frameEvents[frame] = callback;
+ }
+
+ function animate() {
+ currentFrame += 1;
+
+ requestAnimFrame( animate );
+
+ // just for fun, lets rotate mr rabbit a little
+ bunny.rotation += 0.1;
+
+ // render the stage
+ renderer.render(stage);
+
+ if (frameEvents[currentFrame])
+ frameEvents[currentFrame](currentFrame);
+ }
+
+ function initScene() {
+ // create an new instance of a pixi stage
+ stage = new PIXI.Stage(0x66FF99);
+
+ // create a renderer instance
+ renderer = PIXI.autoDetectRenderer(400, 300);
+ console.log('Is PIXI.WebGLRenderer: ' + (renderer instanceof PIXI.WebGLRenderer));
+
+ // add the renderer view element to the DOM
+ document.body.appendChild(renderer.view);
+
+ requestAnimFrame( animate );
+
+ // create a texture from an image path
+ var texture = PIXI.Texture.fromImage(baseUri + "/bunny.png");
+ // create a new Sprite using the texture
+ bunny = new PIXI.Sprite(texture);
+
+ // center the sprites anchor point
+ bunny.anchor.x = 0.5;
+ bunny.anchor.y = 0.5;
+
+ // move the sprite t the center of the screen
+ bunny.position.x = 200;
+ bunny.position.y = 150;
+
+ stage.addChild(bunny);
+ }
+
+ it('assets loaded', function (done) {
+ var loader = new PIXI.AssetLoader([
+ baseUri + '/bunny.png',
+ baseUri + '/frame-30.png',
+ baseUri + '/frame-60.png',
+ baseUri + '/frame-90.png'
+ ]);
+ // loader.on('onProgress', function (event) {
+ // console.log(event.content);
+ // });
+ loader.on('onComplete', function (event) {
+ done();
+ initScene();
+ });
+ loader.load();
+ });
+
+ it('frame 30 should match', function (done) {
+ this.timeout(700);
+ onFrame(30, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-30.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 60 should match', function (done) {
+ this.timeout(1200);
+ onFrame(60, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-60.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 90 should match', function (done) {
+ this.timeout(1700);
+ onFrame(90, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-90.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ // it('capture something', function (done) {
+ // this.timeout(2000000);
+ // onFrame(30, function () {
+ // var img = new Image();
+ // img.src = renderer.view.toDataURL('image/png');
+ // document.body.appendChild(img);
+ // });
+ // });
+});
diff --git a/test/index.html b/test/index.html
deleted file mode 100644
index 9cbcac5..0000000
--- a/test/index.html
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
- Pixi.js Test Suite
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/test/karma.conf.js b/test/karma.conf.js
new file mode 100644
index 0000000..c66a696
--- /dev/null
+++ b/test/karma.conf.js
@@ -0,0 +1,82 @@
+module.exports = function(config) {
+ config.set({
+
+ // base path, that will be used to resolve files and exclude
+ basePath : '../',
+
+ frameworks : ['mocha'],
+
+ // list of files / patterns to load in the browser
+ files : [
+ 'node_modules/chai/chai.js',
+ 'bin/pixi.dev.js',
+ 'test/lib/**/*.js',
+ 'test/unit/**/*.js',
+ // 'test/functional/**/*.js',
+ {pattern: 'test/**/*.png', watched: false, included: false, served: true}
+ ],
+
+ // list of files to exclude
+ exclude : [],
+
+ // use dolts reporter, as travis terminal does not support escaping sequences
+ // possible values: 'dots', 'progress', 'junit', 'teamcity'
+ // CLI --reporters progress
+ reporters : ['progress'],
+
+ // web server port
+ // CLI --port 9876
+ port : 9876,
+
+ // cli runner port
+ // CLI --runner-port 9100
+ runnerPort : 9100,
+
+ // enable / disable colors in the output (reporters and logs)
+ // CLI --colors --no-colors
+ colors : true,
+
+ // level of logging
+ // possible values: karma.LOG_DISABLE || karma.LOG_ERROR || karma.LOG_WARN || karma.LOG_INFO || karma.LOG_DEBUG
+ // CLI --log-level debug
+ logLevel : config.LOG_DEBUG,
+
+ // enable / disable watching file and executing tests whenever any file changes
+ // CLI --auto-watch --no-auto-watch
+ autoWatch : false,
+
+ // Start these browsers, currently available:
+ // - Chrome
+ // - ChromeCanary
+ // - Firefox
+ // - Opera
+ // - Safari (only Mac)
+ // - PhantomJS
+ // - IE (only Windows)
+ // CLI --browsers Chrome,Firefox,Safari
+ browsers : ['Firefox'],
+
+ // If browser does not capture in given timeout [ms], kill it
+ // CLI --capture-timeout 5000
+ captureTimeout : 5000,
+
+ // Auto run tests on start (when browsers are captured) and exit
+ // CLI --single-run --no-single-run
+ singleRun : true,
+
+ // report which specs are slower than 500ms
+ // CLI --report-slower-than 500
+ reportSlowerThan : 1000,
+
+ preprocessors : {
+ // '**/client/js/*.js': 'coverage'
+ },
+
+ plugins : [
+ 'karma-mocha',
+ // 'karma-chrome-launcher',
+ 'karma-firefox-launcher',
+ // 'karma-phantomjs-launcher'
+ ]
+ });
+};
diff --git a/test/lib/pixi/core/Matrix.js b/test/lib/pixi/core/Matrix.js
new file mode 100644
index 0000000..d26386b
--- /dev/null
+++ b/test/lib/pixi/core/Matrix.js
@@ -0,0 +1,40 @@
+
+function pixi_core_Matrix_confirmNewMat3(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(1);
+ expect(matrix[5]).to.equal(0);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(1);
+}
+
+function pixi_core_Matrix_confirmNewMat4(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[0]).to.equal(1);
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(0);
+ expect(matrix[5]).to.equal(1);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(0);
+ expect(matrix[9]).to.equal(0);
+ expect(matrix[10]).to.equal(1);
+ expect(matrix[11]).to.equal(0);
+ expect(matrix[12]).to.equal(0);
+ expect(matrix[13]).to.equal(0);
+ expect(matrix[14]).to.equal(0);
+ expect(matrix[15]).to.equal(1);
+}
diff --git a/test/lib/pixi/core/Point.js b/test/lib/pixi/core/Point.js
new file mode 100644
index 0000000..e5df07b
--- /dev/null
+++ b/test/lib/pixi/core/Point.js
@@ -0,0 +1,10 @@
+
+function pixi_core_Point_confirm(obj, x, y) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Point);
+ expect(obj).to.respondTo('clone');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+}
diff --git a/test/lib/pixi/core/Rectangle.js b/test/lib/pixi/core/Rectangle.js
new file mode 100644
index 0000000..23f0d12
--- /dev/null
+++ b/test/lib/pixi/core/Rectangle.js
@@ -0,0 +1,13 @@
+
+function pixi_core_Rectangle_confirm(obj, x, y, width, height) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Rectangle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+ expect(obj).to.have.property('width', width);
+ expect(obj).to.have.property('height', height);
+}
diff --git a/test/lib/pixi/display/DisplayObject.js b/test/lib/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..1388a7f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObject.js
@@ -0,0 +1,43 @@
+
+function pixi_display_DisplayObject_confirmNew(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObject);
+ expect(obj).to.respondTo('setInteractive');
+ expect(obj).to.respondTo('addFilter');
+ expect(obj).to.respondTo('removeFilter');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.property('last', obj);
+ expect(obj).to.have.property('first', obj);
+
+ expect(obj).to.contain.property('position');
+ pixi_core_Point_confirm(obj.position, 0, 0);
+ expect(obj).to.contain.property('scale');
+ pixi_core_Point_confirm(obj.scale, 1, 1);
+ expect(obj).to.contain.property('pivot');
+ pixi_core_Point_confirm(obj.pivot, 0, 0);
+
+ expect(obj).to.have.property('rotation', 0);
+ expect(obj).to.have.property('alpha', 1);
+ expect(obj).to.have.property('visible', true);
+ expect(obj).to.have.property('buttonMode', false);
+ expect(obj).to.have.property('parent', null);
+ expect(obj).to.have.property('worldAlpha', 1);
+
+ expect(obj).to.have.property('hitArea');
+ expect(obj).to.have.property('interactive'); // TODO: Have a better default value
+ expect('mask' in obj).to.be.true; // TODO: Have a better default value
+ expect(obj.mask).to.be.undefined;
+
+ expect(obj).to.have.property('renderable');
+ expect(obj).to.have.property('stage');
+
+ expect(obj).to.have.deep.property('worldTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ expect(obj).to.have.deep.property('localTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.localTransform);
+
+ expect(obj).to.have.deep.property('color.length', 0);
+ expect(obj).to.have.property('dynamic', true);
+}
diff --git a/test/lib/pixi/display/DisplayObjectContainer.js b/test/lib/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..085c59f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,16 @@
+
+function pixi_display_DisplayObjectContainer_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObject_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObjectContainer);
+ expect(obj).to.respondTo('addChild');
+ expect(obj).to.respondTo('addChildAt');
+ expect(obj).to.respondTo('swapChildren');
+ expect(obj).to.respondTo('getChildAt');
+ expect(obj).to.respondTo('removeChild');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('children.length', 0);
+}
diff --git a/test/lib/pixi/display/Sprite.js b/test/lib/pixi/display/Sprite.js
new file mode 100644
index 0000000..cc7a2d6
--- /dev/null
+++ b/test/lib/pixi/display/Sprite.js
@@ -0,0 +1,28 @@
+
+function pixi_display_Sprite_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Sprite);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', true);
+ expect(obj).to.have.property('stage', null);
+
+ expect(obj).to.have.property('anchor');
+ pixi_core_Point_confirm(obj.anchor, 0, 0);
+
+ expect(obj).to.have.property('blendMode', PIXI.blendModes.NORMAL);
+ expect(obj).to.have.property('width', 1); // TODO: is 1 expected
+ expect(obj).to.have.property('height', 1); // TODO: is 1 expected
+
+ // FIXME: Just make this a boolean that is always there
+ expect(!!obj.updateFrame).to.equal(obj.texture.baseTexture.hasLoaded);
+
+ expect(obj).to.have.property('texture');
+ pixi_textures_Texture_confirmNew(obj.texture, done);
+}
diff --git a/test/lib/pixi/extras/Strip.js b/test/lib/pixi/extras/Strip.js
new file mode 100644
index 0000000..8927a8a
--- /dev/null
+++ b/test/lib/pixi/extras/Strip.js
@@ -0,0 +1,12 @@
+
+function pixi_extras_Strip_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Strip);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ // TODO: Test properties
+}
diff --git a/test/lib/pixi/textures/Texture.js b/test/lib/pixi/textures/Texture.js
new file mode 100644
index 0000000..d5867b6
--- /dev/null
+++ b/test/lib/pixi/textures/Texture.js
@@ -0,0 +1,31 @@
+
+function pixi_textures_Texture_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ function confirmFrameDone() {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, obj.baseTexture.width, obj.baseTexture.height);
+
+ expect(obj).to.have.property('width', obj.baseTexture.width);
+ expect(obj).to.have.property('height', obj.baseTexture.height);
+ done();
+ }
+
+ expect(obj).to.be.an.instanceof(PIXI.Texture);
+ pixi_utils_EventTarget_like(obj);
+
+ expect(obj).to.have.property('baseTexture')
+ .and.to.be.an.instanceof(PIXI.BaseTexture);
+
+ expect(obj).to.have.property('scope', obj);
+
+ expect(obj).to.have.property('trim');
+ pixi_core_Point_confirm(obj.trim, 0, 0);
+
+ expect(obj).to.have.property('frame');
+ if (obj.baseTexture.hasLoaded) {
+ confirmFrameDone();
+ } else {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, 1, 1);
+ obj.addEventListener('update', confirmFrameDone);
+ }
+}
diff --git a/test/lib/pixi/utils/EventTarget.js b/test/lib/pixi/utils/EventTarget.js
new file mode 100644
index 0000000..7b1dcfa
--- /dev/null
+++ b/test/lib/pixi/utils/EventTarget.js
@@ -0,0 +1,8 @@
+
+function pixi_utils_EventTarget_like(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.respondTo('addEventListener');
+ expect(obj).to.respondTo('dispatchEvent');
+ expect(obj).to.respondTo('removeEventListener');
+}
diff --git a/test/lib/qunit-1.11.0.css b/test/lib/qunit-1.11.0.css
deleted file mode 100644
index d7fc0c8..0000000
--- a/test/lib/qunit-1.11.0.css
+++ /dev/null
@@ -1,244 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-/** Font Family and Sizes */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
- font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
-}
-
-#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
-#qunit-tests { font-size: smaller; }
-
-
-/** Resets */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter {
- margin: 0;
- padding: 0;
-}
-
-
-/** Header */
-
-#qunit-header {
- padding: 0.5em 0 0.5em 1em;
-
- color: #8699a4;
- background-color: #0d3349;
-
- font-size: 1.5em;
- line-height: 1em;
- font-weight: normal;
-
- border-radius: 5px 5px 0 0;
- -moz-border-radius: 5px 5px 0 0;
- -webkit-border-top-right-radius: 5px;
- -webkit-border-top-left-radius: 5px;
-}
-
-#qunit-header a {
- text-decoration: none;
- color: #c2ccd1;
-}
-
-#qunit-header a:hover,
-#qunit-header a:focus {
- color: #fff;
-}
-
-#qunit-testrunner-toolbar label {
- display: inline-block;
- padding: 0 .5em 0 .1em;
-}
-
-#qunit-banner {
- height: 5px;
-}
-
-#qunit-testrunner-toolbar {
- padding: 0.5em 0 0.5em 2em;
- color: #5E740B;
- background-color: #eee;
- overflow: hidden;
-}
-
-#qunit-userAgent {
- padding: 0.5em 0 0.5em 2.5em;
- background-color: #2b81af;
- color: #fff;
- text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
-}
-
-#qunit-modulefilter-container {
- float: right;
-}
-
-/** Tests: Pass/Fail */
-
-#qunit-tests {
- list-style-position: inside;
-}
-
-#qunit-tests li {
- padding: 0.4em 0.5em 0.4em 2.5em;
- border-bottom: 1px solid #fff;
- list-style-position: inside;
-}
-
-#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running {
- display: none;
-}
-
-#qunit-tests li strong {
- cursor: pointer;
-}
-
-#qunit-tests li a {
- padding: 0.5em;
- color: #c2ccd1;
- text-decoration: none;
-}
-#qunit-tests li a:hover,
-#qunit-tests li a:focus {
- color: #000;
-}
-
-#qunit-tests li .runtime {
- float: right;
- font-size: smaller;
-}
-
-.qunit-assert-list {
- margin-top: 0.5em;
- padding: 0.5em;
-
- background-color: #fff;
-
- border-radius: 5px;
- -moz-border-radius: 5px;
- -webkit-border-radius: 5px;
-}
-
-.qunit-collapsed {
- display: none;
-}
-
-#qunit-tests table {
- border-collapse: collapse;
- margin-top: .2em;
-}
-
-#qunit-tests th {
- text-align: right;
- vertical-align: top;
- padding: 0 .5em 0 0;
-}
-
-#qunit-tests td {
- vertical-align: top;
-}
-
-#qunit-tests pre {
- margin: 0;
- white-space: pre-wrap;
- word-wrap: break-word;
-}
-
-#qunit-tests del {
- background-color: #e0f2be;
- color: #374e0c;
- text-decoration: none;
-}
-
-#qunit-tests ins {
- background-color: #ffcaca;
- color: #500;
- text-decoration: none;
-}
-
-/*** Test Counts */
-
-#qunit-tests b.counts { color: black; }
-#qunit-tests b.passed { color: #5E740B; }
-#qunit-tests b.failed { color: #710909; }
-
-#qunit-tests li li {
- padding: 5px;
- background-color: #fff;
- border-bottom: none;
- list-style-position: inside;
-}
-
-/*** Passing Styles */
-
-#qunit-tests li li.pass {
- color: #3c510c;
- background-color: #fff;
- border-left: 10px solid #C6E746;
-}
-
-#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
-#qunit-tests .pass .test-name { color: #366097; }
-
-#qunit-tests .pass .test-actual,
-#qunit-tests .pass .test-expected { color: #999999; }
-
-#qunit-banner.qunit-pass { background-color: #C6E746; }
-
-/*** Failing Styles */
-
-#qunit-tests li li.fail {
- color: #710909;
- background-color: #fff;
- border-left: 10px solid #EE5757;
- white-space: pre;
-}
-
-#qunit-tests > li:last-child {
- border-radius: 0 0 5px 5px;
- -moz-border-radius: 0 0 5px 5px;
- -webkit-border-bottom-right-radius: 5px;
- -webkit-border-bottom-left-radius: 5px;
-}
-
-#qunit-tests .fail { color: #000000; background-color: #EE5757; }
-#qunit-tests .fail .test-name,
-#qunit-tests .fail .module-name { color: #000000; }
-
-#qunit-tests .fail .test-actual { color: #EE5757; }
-#qunit-tests .fail .test-expected { color: green; }
-
-#qunit-banner.qunit-fail { background-color: #EE5757; }
-
-
-/** Result */
-
-#qunit-testresult {
- padding: 0.5em 0.5em 0.5em 2.5em;
-
- color: #2b81af;
- background-color: #D2E0E6;
-
- border-bottom: 1px solid white;
-}
-#qunit-testresult .module-name {
- font-weight: bold;
-}
-
-/** Fixture */
-
-#qunit-fixture {
- position: absolute;
- top: -10000px;
- left: -10000px;
- width: 1000px;
- height: 1000px;
-}
diff --git a/test/lib/qunit-1.11.0.js b/test/lib/qunit-1.11.0.js
deleted file mode 100644
index 302545f..0000000
--- a/test/lib/qunit-1.11.0.js
+++ /dev/null
@@ -1,2152 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-(function( window ) {
-
-var QUnit,
- assert,
- config,
- onErrorFnPrev,
- testId = 0,
- fileName = (sourceFromStacktrace( 0 ) || "" ).replace(/(:\d+)+\)?/, "").replace(/.+\//, ""),
- toString = Object.prototype.toString,
- hasOwn = Object.prototype.hasOwnProperty,
- // Keep a local reference to Date (GH-283)
- Date = window.Date,
- defined = {
- setTimeout: typeof window.setTimeout !== "undefined",
- sessionStorage: (function() {
- var x = "qunit-test-string";
- try {
- sessionStorage.setItem( x, x );
- sessionStorage.removeItem( x );
- return true;
- } catch( e ) {
- return false;
- }
- }())
- },
- /**
- * Provides a normalized error string, correcting an issue
- * with IE 7 (and prior) where Error.prototype.toString is
- * not properly implemented
- *
- * Based on http://es5.github.com/#x15.11.4.4
- *
- * @param {String|Error} error
- * @return {String} error message
- */
- errorString = function( error ) {
- var name, message,
- errorString = error.toString();
- if ( errorString.substring( 0, 7 ) === "[object" ) {
- name = error.name ? error.name.toString() : "Error";
- message = error.message ? error.message.toString() : "";
- if ( name && message ) {
- return name + ": " + message;
- } else if ( name ) {
- return name;
- } else if ( message ) {
- return message;
- } else {
- return "Error";
- }
- } else {
- return errorString;
- }
- },
- /**
- * Makes a clone of an object using only Array or Object as base,
- * and copies over the own enumerable properties.
- *
- * @param {Object} obj
- * @return {Object} New object with only the own properties (recursively).
- */
- objectValues = function( obj ) {
- // Grunt 0.3.x uses an older version of jshint that still has jshint/jshint#392.
- /*jshint newcap: false */
- var key, val,
- vals = QUnit.is( "array", obj ) ? [] : {};
- for ( key in obj ) {
- if ( hasOwn.call( obj, key ) ) {
- val = obj[key];
- vals[key] = val === Object(val) ? objectValues(val) : val;
- }
- }
- return vals;
- };
-
-function Test( settings ) {
- extend( this, settings );
- this.assertions = [];
- this.testNumber = ++Test.count;
-}
-
-Test.count = 0;
-
-Test.prototype = {
- init: function() {
- var a, b, li,
- tests = id( "qunit-tests" );
-
- if ( tests ) {
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml;
-
- // `a` initialized at top of scope
- a = document.createElement( "a" );
- a.innerHTML = "Rerun";
- a.href = QUnit.url({ testNumber: this.testNumber });
-
- li = document.createElement( "li" );
- li.appendChild( b );
- li.appendChild( a );
- li.className = "running";
- li.id = this.id = "qunit-test-output" + testId++;
-
- tests.appendChild( li );
- }
- },
- setup: function() {
- if ( this.module !== config.previousModule ) {
- if ( config.previousModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.previousModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
- config.previousModule = this.module;
- config.moduleStats = { all: 0, bad: 0 };
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- } else if ( config.autorun ) {
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- }
-
- config.current = this;
-
- this.testEnvironment = extend({
- setup: function() {},
- teardown: function() {}
- }, this.moduleTestEnvironment );
-
- this.started = +new Date();
- runLoggingCallbacks( "testStart", QUnit, {
- name: this.testName,
- module: this.module
- });
-
- // allow utility functions to access the current test environment
- // TODO why??
- QUnit.current_testEnvironment = this.testEnvironment;
-
- if ( !config.pollution ) {
- saveGlobal();
- }
- if ( config.notrycatch ) {
- this.testEnvironment.setup.call( this.testEnvironment );
- return;
- }
- try {
- this.testEnvironment.setup.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Setup failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- },
- run: function() {
- config.current = this;
-
- var running = id( "qunit-testresult" );
-
- if ( running ) {
- running.innerHTML = "Running:
" + this.nameHtml;
- }
-
- if ( this.async ) {
- QUnit.stop();
- }
-
- this.callbackStarted = +new Date();
-
- if ( config.notrycatch ) {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- return;
- }
-
- try {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- } catch( e ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
-
- QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + " " + this.stack + ": " + ( e.message || e ), extractStacktrace( e, 0 ) );
- // else next test will carry the responsibility
- saveGlobal();
-
- // Restart the tests if they're blocking
- if ( config.blocking ) {
- QUnit.start();
- }
- }
- },
- teardown: function() {
- config.current = this;
- if ( config.notrycatch ) {
- if ( typeof this.callbackRuntime === "undefined" ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
- }
- this.testEnvironment.teardown.call( this.testEnvironment );
- return;
- } else {
- try {
- this.testEnvironment.teardown.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Teardown failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- }
- checkPollution();
- },
- finish: function() {
- config.current = this;
- if ( config.requireExpects && this.expected === null ) {
- QUnit.pushFailure( "Expected number of assertions to be defined, but expect() was not called.", this.stack );
- } else if ( this.expected !== null && this.expected !== this.assertions.length ) {
- QUnit.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack );
- } else if ( this.expected === null && !this.assertions.length ) {
- QUnit.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions.", this.stack );
- }
-
- var i, assertion, a, b, time, li, ol,
- test = this,
- good = 0,
- bad = 0,
- tests = id( "qunit-tests" );
-
- this.runtime = +new Date() - this.started;
- config.stats.all += this.assertions.length;
- config.moduleStats.all += this.assertions.length;
-
- if ( tests ) {
- ol = document.createElement( "ol" );
- ol.className = "qunit-assert-list";
-
- for ( i = 0; i < this.assertions.length; i++ ) {
- assertion = this.assertions[i];
-
- li = document.createElement( "li" );
- li.className = assertion.result ? "pass" : "fail";
- li.innerHTML = assertion.message || ( assertion.result ? "okay" : "failed" );
- ol.appendChild( li );
-
- if ( assertion.result ) {
- good++;
- } else {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
-
- // store result when possible
- if ( QUnit.config.reorder && defined.sessionStorage ) {
- if ( bad ) {
- sessionStorage.setItem( "qunit-test-" + this.module + "-" + this.testName, bad );
- } else {
- sessionStorage.removeItem( "qunit-test-" + this.module + "-" + this.testName );
- }
- }
-
- if ( bad === 0 ) {
- addClass( ol, "qunit-collapsed" );
- }
-
- // `b` initialized at top of scope
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml + " (" + bad + ", " + good + ", " + this.assertions.length + ")";
-
- addEvent(b, "click", function() {
- var next = b.parentNode.lastChild,
- collapsed = hasClass( next, "qunit-collapsed" );
- ( collapsed ? removeClass : addClass )( next, "qunit-collapsed" );
- });
-
- addEvent(b, "dblclick", function( e ) {
- var target = e && e.target ? e.target : window.event.srcElement;
- if ( target.nodeName.toLowerCase() === "span" || target.nodeName.toLowerCase() === "b" ) {
- target = target.parentNode;
- }
- if ( window.location && target.nodeName.toLowerCase() === "strong" ) {
- window.location = QUnit.url({ testNumber: test.testNumber });
- }
- });
-
- // `time` initialized at top of scope
- time = document.createElement( "span" );
- time.className = "runtime";
- time.innerHTML = this.runtime + " ms";
-
- // `li` initialized at top of scope
- li = id( this.id );
- li.className = bad ? "fail" : "pass";
- li.removeChild( li.firstChild );
- a = li.firstChild;
- li.appendChild( b );
- li.appendChild( a );
- li.appendChild( time );
- li.appendChild( ol );
-
- } else {
- for ( i = 0; i < this.assertions.length; i++ ) {
- if ( !this.assertions[i].result ) {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
- }
-
- runLoggingCallbacks( "testDone", QUnit, {
- name: this.testName,
- module: this.module,
- failed: bad,
- passed: this.assertions.length - bad,
- total: this.assertions.length,
- duration: this.runtime
- });
-
- QUnit.reset();
-
- config.current = undefined;
- },
-
- queue: function() {
- var bad,
- test = this;
-
- synchronize(function() {
- test.init();
- });
- function run() {
- // each of these can by async
- synchronize(function() {
- test.setup();
- });
- synchronize(function() {
- test.run();
- });
- synchronize(function() {
- test.teardown();
- });
- synchronize(function() {
- test.finish();
- });
- }
-
- // `bad` initialized at top of scope
- // defer when previous test run passed, if storage is available
- bad = QUnit.config.reorder && defined.sessionStorage &&
- +sessionStorage.getItem( "qunit-test-" + this.module + "-" + this.testName );
-
- if ( bad ) {
- run();
- } else {
- synchronize( run, true );
- }
- }
-};
-
-// Root QUnit object.
-// `QUnit` initialized at top of scope
-QUnit = {
-
- // call on start of module test to prepend name to all tests
- module: function( name, testEnvironment ) {
- config.currentModule = name;
- config.currentModuleTestEnvironment = testEnvironment;
- config.modules[name] = true;
- },
-
- asyncTest: function( testName, expected, callback ) {
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- QUnit.test( testName, expected, callback, true );
- },
-
- test: function( testName, expected, callback, async ) {
- var test,
- nameHtml = "" + escapeText( testName ) + "";
-
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- if ( config.currentModule ) {
- nameHtml = "" + escapeText( config.currentModule ) + ": " + nameHtml;
- }
-
- test = new Test({
- nameHtml: nameHtml,
- testName: testName,
- expected: expected,
- async: async,
- callback: callback,
- module: config.currentModule,
- moduleTestEnvironment: config.currentModuleTestEnvironment,
- stack: sourceFromStacktrace( 2 )
- });
-
- if ( !validTest( test ) ) {
- return;
- }
-
- test.queue();
- },
-
- // Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through.
- expect: function( asserts ) {
- if (arguments.length === 1) {
- config.current.expected = asserts;
- } else {
- return config.current.expected;
- }
- },
-
- start: function( count ) {
- // QUnit hasn't been initialized yet.
- // Note: RequireJS (et al) may delay onLoad
- if ( config.semaphore === undefined ) {
- QUnit.begin(function() {
- // This is triggered at the top of QUnit.load, push start() to the event loop, to allow QUnit.load to finish first
- setTimeout(function() {
- QUnit.start( count );
- });
- });
- return;
- }
-
- config.semaphore -= count || 1;
- // don't start until equal number of stop-calls
- if ( config.semaphore > 0 ) {
- return;
- }
- // ignore if start is called more often then stop
- if ( config.semaphore < 0 ) {
- config.semaphore = 0;
- QUnit.pushFailure( "Called start() while already started (QUnit.config.semaphore was 0 already)", null, sourceFromStacktrace(2) );
- return;
- }
- // A slight delay, to avoid any current callbacks
- if ( defined.setTimeout ) {
- window.setTimeout(function() {
- if ( config.semaphore > 0 ) {
- return;
- }
- if ( config.timeout ) {
- clearTimeout( config.timeout );
- }
-
- config.blocking = false;
- process( true );
- }, 13);
- } else {
- config.blocking = false;
- process( true );
- }
- },
-
- stop: function( count ) {
- config.semaphore += count || 1;
- config.blocking = true;
-
- if ( config.testTimeout && defined.setTimeout ) {
- clearTimeout( config.timeout );
- config.timeout = window.setTimeout(function() {
- QUnit.ok( false, "Test timed out" );
- config.semaphore = 1;
- QUnit.start();
- }, config.testTimeout );
- }
- }
-};
-
-// `assert` initialized at top of scope
-// Asssert helpers
-// All of these must either call QUnit.push() or manually do:
-// - runLoggingCallbacks( "log", .. );
-// - config.current.assertions.push({ .. });
-// We attach it to the QUnit object *after* we expose the public API,
-// otherwise `assert` will become a global variable in browsers (#341).
-assert = {
- /**
- * Asserts rough true-ish result.
- * @name ok
- * @function
- * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" );
- */
- ok: function( result, msg ) {
- if ( !config.current ) {
- throw new Error( "ok() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
- result = !!result;
-
- var source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: msg
- };
-
- msg = escapeText( msg || (result ? "okay" : "failed" ) );
- msg = "" + msg + "";
-
- if ( !result ) {
- source = sourceFromStacktrace( 2 );
- if ( source ) {
- details.source = source;
- msg += "Source: | " + escapeText( source ) + " |
---|
";
- }
- }
- runLoggingCallbacks( "log", QUnit, details );
- config.current.assertions.push({
- result: result,
- message: msg
- });
- },
-
- /**
- * Assert that the first two arguments are equal, with an optional message.
- * Prints out both actual and expected values.
- * @name equal
- * @function
- * @example equal( format( "Received {0} bytes.", 2), "Received 2 bytes.", "format() replaces {0} with next argument" );
- */
- equal: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected == actual, actual, expected, message );
- },
-
- /**
- * @name notEqual
- * @function
- */
- notEqual: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected != actual, actual, expected, message );
- },
-
- /**
- * @name propEqual
- * @function
- */
- propEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notPropEqual
- * @function
- */
- notPropEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name deepEqual
- * @function
- */
- deepEqual: function( actual, expected, message ) {
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notDeepEqual
- * @function
- */
- notDeepEqual: function( actual, expected, message ) {
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name strictEqual
- * @function
- */
- strictEqual: function( actual, expected, message ) {
- QUnit.push( expected === actual, actual, expected, message );
- },
-
- /**
- * @name notStrictEqual
- * @function
- */
- notStrictEqual: function( actual, expected, message ) {
- QUnit.push( expected !== actual, actual, expected, message );
- },
-
- "throws": function( block, expected, message ) {
- var actual,
- expectedOutput = expected,
- ok = false;
-
- // 'expected' is optional
- if ( typeof expected === "string" ) {
- message = expected;
- expected = null;
- }
-
- config.current.ignoreGlobalErrors = true;
- try {
- block.call( config.current.testEnvironment );
- } catch (e) {
- actual = e;
- }
- config.current.ignoreGlobalErrors = false;
-
- if ( actual ) {
- // we don't want to validate thrown error
- if ( !expected ) {
- ok = true;
- expectedOutput = null;
- // expected is a regexp
- } else if ( QUnit.objectType( expected ) === "regexp" ) {
- ok = expected.test( errorString( actual ) );
- // expected is a constructor
- } else if ( actual instanceof expected ) {
- ok = true;
- // expected is a validation function which returns true is validation passed
- } else if ( expected.call( {}, actual ) === true ) {
- expectedOutput = null;
- ok = true;
- }
-
- QUnit.push( ok, actual, expectedOutput, message );
- } else {
- QUnit.pushFailure( message, null, 'No exception was thrown.' );
- }
- }
-};
-
-/**
- * @deprecate since 1.8.0
- * Kept assertion helpers in root for backwards compatibility.
- */
-extend( QUnit, assert );
-
-/**
- * @deprecated since 1.9.0
- * Kept root "raises()" for backwards compatibility.
- * (Note that we don't introduce assert.raises).
- */
-QUnit.raises = assert[ "throws" ];
-
-/**
- * @deprecated since 1.0.0, replaced with error pushes since 1.3.0
- * Kept to avoid TypeErrors for undefined methods.
- */
-QUnit.equals = function() {
- QUnit.push( false, false, false, "QUnit.equals has been deprecated since 2009 (e88049a0), use QUnit.equal instead" );
-};
-QUnit.same = function() {
- QUnit.push( false, false, false, "QUnit.same has been deprecated since 2009 (e88049a0), use QUnit.deepEqual instead" );
-};
-
-// We want access to the constructor's prototype
-(function() {
- function F() {}
- F.prototype = QUnit;
- QUnit = new F();
- // Make F QUnit's constructor so that we can add to the prototype later
- QUnit.constructor = F;
-}());
-
-/**
- * Config object: Maintain internal state
- * Later exposed as QUnit.config
- * `config` initialized at top of scope
- */
-config = {
- // The queue of tests to run
- queue: [],
-
- // block until document ready
- blocking: true,
-
- // when enabled, show only failing tests
- // gets persisted through sessionStorage and can be changed in UI via checkbox
- hidepassed: false,
-
- // by default, run previously failed tests first
- // very useful in combination with "Hide passed tests" checked
- reorder: true,
-
- // by default, modify document.title when suite is done
- altertitle: true,
-
- // when enabled, all tests must call expect()
- requireExpects: false,
-
- // add checkboxes that are persisted in the query-string
- // when enabled, the id is set to `true` as a `QUnit.config` property
- urlConfig: [
- {
- id: "noglobals",
- label: "Check for Globals",
- tooltip: "Enabling this will test if any test introduces new properties on the `window` object. Stored as query-strings."
- },
- {
- id: "notrycatch",
- label: "No try-catch",
- tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging exceptions in IE reasonable. Stored as query-strings."
- }
- ],
-
- // Set of all modules.
- modules: {},
-
- // logging callback queues
- begin: [],
- done: [],
- log: [],
- testStart: [],
- testDone: [],
- moduleStart: [],
- moduleDone: []
-};
-
-// Export global variables, unless an 'exports' object exists,
-// in that case we assume we're in CommonJS (dealt with on the bottom of the script)
-if ( typeof exports === "undefined" ) {
- extend( window, QUnit );
-
- // Expose QUnit object
- window.QUnit = QUnit;
-}
-
-// Initialize more QUnit.config and QUnit.urlParams
-(function() {
- var i,
- location = window.location || { search: "", protocol: "file:" },
- params = location.search.slice( 1 ).split( "&" ),
- length = params.length,
- urlParams = {},
- current;
-
- if ( params[ 0 ] ) {
- for ( i = 0; i < length; i++ ) {
- current = params[ i ].split( "=" );
- current[ 0 ] = decodeURIComponent( current[ 0 ] );
- // allow just a key to turn on a flag, e.g., test.html?noglobals
- current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true;
- urlParams[ current[ 0 ] ] = current[ 1 ];
- }
- }
-
- QUnit.urlParams = urlParams;
-
- // String search anywhere in moduleName+testName
- config.filter = urlParams.filter;
-
- // Exact match of the module name
- config.module = urlParams.module;
-
- config.testNumber = parseInt( urlParams.testNumber, 10 ) || null;
-
- // Figure out if we're running the tests from a server or not
- QUnit.isLocal = location.protocol === "file:";
-}());
-
-// Extend QUnit object,
-// these after set here because they should not be exposed as global functions
-extend( QUnit, {
- assert: assert,
-
- config: config,
-
- // Initialize the configuration options
- init: function() {
- extend( config, {
- stats: { all: 0, bad: 0 },
- moduleStats: { all: 0, bad: 0 },
- started: +new Date(),
- updateRate: 1000,
- blocking: false,
- autostart: true,
- autorun: false,
- filter: "",
- queue: [],
- semaphore: 1
- });
-
- var tests, banner, result,
- qunit = id( "qunit" );
-
- if ( qunit ) {
- qunit.innerHTML =
- "" +
- "" +
- "" +
- "" +
- "
";
- }
-
- tests = id( "qunit-tests" );
- banner = id( "qunit-banner" );
- result = id( "qunit-testresult" );
-
- if ( tests ) {
- tests.innerHTML = "";
- }
-
- if ( banner ) {
- banner.className = "";
- }
-
- if ( result ) {
- result.parentNode.removeChild( result );
- }
-
- if ( tests ) {
- result = document.createElement( "p" );
- result.id = "qunit-testresult";
- result.className = "result";
- tests.parentNode.insertBefore( result, tests );
- result.innerHTML = "Running...
";
- }
- },
-
- // Resets the test setup. Useful for tests that modify the DOM.
- reset: function() {
- var fixture = id( "qunit-fixture" );
- if ( fixture ) {
- fixture.innerHTML = config.fixture;
- }
- },
-
- // Trigger an event on an element.
- // @example triggerEvent( document.body, "click" );
- triggerEvent: function( elem, type, event ) {
- if ( document.createEvent ) {
- event = document.createEvent( "MouseEvents" );
- event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView,
- 0, 0, 0, 0, 0, false, false, false, false, 0, null);
-
- elem.dispatchEvent( event );
- } else if ( elem.fireEvent ) {
- elem.fireEvent( "on" + type );
- }
- },
-
- // Safe object type checking
- is: function( type, obj ) {
- return QUnit.objectType( obj ) === type;
- },
-
- objectType: function( obj ) {
- if ( typeof obj === "undefined" ) {
- return "undefined";
- // consider: typeof null === object
- }
- if ( obj === null ) {
- return "null";
- }
-
- var match = toString.call( obj ).match(/^\[object\s(.*)\]$/),
- type = match && match[1] || "";
-
- switch ( type ) {
- case "Number":
- if ( isNaN(obj) ) {
- return "nan";
- }
- return "number";
- case "String":
- case "Boolean":
- case "Array":
- case "Date":
- case "RegExp":
- case "Function":
- return type.toLowerCase();
- }
- if ( typeof obj === "object" ) {
- return "object";
- }
- return undefined;
- },
-
- push: function( result, actual, expected, message ) {
- if ( !config.current ) {
- throw new Error( "assertion outside test context, was " + sourceFromStacktrace() );
- }
-
- var output, source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: message,
- actual: actual,
- expected: expected
- };
-
- message = escapeText( message ) || ( result ? "okay" : "failed" );
- message = "" + message + "";
- output = message;
-
- if ( !result ) {
- expected = escapeText( QUnit.jsDump.parse(expected) );
- actual = escapeText( QUnit.jsDump.parse(actual) );
- output += "Expected: | " + expected + " |
";
-
- if ( actual !== expected ) {
- output += "Result: | " + actual + " |
";
- output += "Diff: | " + QUnit.diff( expected, actual ) + " |
";
- }
-
- source = sourceFromStacktrace();
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
- }
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: !!result,
- message: output
- });
- },
-
- pushFailure: function( message, source, actual ) {
- if ( !config.current ) {
- throw new Error( "pushFailure() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
-
- var output,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: false,
- message: message
- };
-
- message = escapeText( message ) || "error";
- message = "" + message + "";
- output = message;
-
- output += "";
-
- if ( actual ) {
- output += "Result: | " + escapeText( actual ) + " |
";
- }
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: false,
- message: output
- });
- },
-
- url: function( params ) {
- params = extend( extend( {}, QUnit.urlParams ), params );
- var key,
- querystring = "?";
-
- for ( key in params ) {
- if ( !hasOwn.call( params, key ) ) {
- continue;
- }
- querystring += encodeURIComponent( key ) + "=" +
- encodeURIComponent( params[ key ] ) + "&";
- }
- return window.location.protocol + "//" + window.location.host +
- window.location.pathname + querystring.slice( 0, -1 );
- },
-
- extend: extend,
- id: id,
- addEvent: addEvent
- // load, equiv, jsDump, diff: Attached later
-});
-
-/**
- * @deprecated: Created for backwards compatibility with test runner that set the hook function
- * into QUnit.{hook}, instead of invoking it and passing the hook function.
- * QUnit.constructor is set to the empty F() above so that we can add to it's prototype here.
- * Doing this allows us to tell if the following methods have been overwritten on the actual
- * QUnit object.
- */
-extend( QUnit.constructor.prototype, {
-
- // Logging callbacks; all receive a single argument with the listed properties
- // run test/logs.html for any related changes
- begin: registerLoggingCallback( "begin" ),
-
- // done: { failed, passed, total, runtime }
- done: registerLoggingCallback( "done" ),
-
- // log: { result, actual, expected, message }
- log: registerLoggingCallback( "log" ),
-
- // testStart: { name }
- testStart: registerLoggingCallback( "testStart" ),
-
- // testDone: { name, failed, passed, total, duration }
- testDone: registerLoggingCallback( "testDone" ),
-
- // moduleStart: { name }
- moduleStart: registerLoggingCallback( "moduleStart" ),
-
- // moduleDone: { name, failed, passed, total }
- moduleDone: registerLoggingCallback( "moduleDone" )
-});
-
-if ( typeof document === "undefined" || document.readyState === "complete" ) {
- config.autorun = true;
-}
-
-QUnit.load = function() {
- runLoggingCallbacks( "begin", QUnit, {} );
-
- // Initialize the config, saving the execution queue
- var banner, filter, i, label, len, main, ol, toolbar, userAgent, val,
- urlConfigCheckboxesContainer, urlConfigCheckboxes, moduleFilter,
- numModules = 0,
- moduleFilterHtml = "",
- urlConfigHtml = "",
- oldconfig = extend( {}, config );
-
- QUnit.init();
- extend(config, oldconfig);
-
- config.blocking = false;
-
- len = config.urlConfig.length;
-
- for ( i = 0; i < len; i++ ) {
- val = config.urlConfig[i];
- if ( typeof val === "string" ) {
- val = {
- id: val,
- label: val,
- tooltip: "[no tooltip available]"
- };
- }
- config[ val.id ] = QUnit.urlParams[ val.id ];
- urlConfigHtml += "";
- }
-
- moduleFilterHtml += "";
-
- // `userAgent` initialized at top of scope
- userAgent = id( "qunit-userAgent" );
- if ( userAgent ) {
- userAgent.innerHTML = navigator.userAgent;
- }
-
- // `banner` initialized at top of scope
- banner = id( "qunit-header" );
- if ( banner ) {
- banner.innerHTML = "" + banner.innerHTML + " ";
- }
-
- // `toolbar` initialized at top of scope
- toolbar = id( "qunit-testrunner-toolbar" );
- if ( toolbar ) {
- // `filter` initialized at top of scope
- filter = document.createElement( "input" );
- filter.type = "checkbox";
- filter.id = "qunit-filter-pass";
-
- addEvent( filter, "click", function() {
- var tmp,
- ol = document.getElementById( "qunit-tests" );
-
- if ( filter.checked ) {
- ol.className = ol.className + " hidepass";
- } else {
- tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " ";
- ol.className = tmp.replace( / hidepass /, " " );
- }
- if ( defined.sessionStorage ) {
- if (filter.checked) {
- sessionStorage.setItem( "qunit-filter-passed-tests", "true" );
- } else {
- sessionStorage.removeItem( "qunit-filter-passed-tests" );
- }
- }
- });
-
- if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem( "qunit-filter-passed-tests" ) ) {
- filter.checked = true;
- // `ol` initialized at top of scope
- ol = document.getElementById( "qunit-tests" );
- ol.className = ol.className + " hidepass";
- }
- toolbar.appendChild( filter );
-
- // `label` initialized at top of scope
- label = document.createElement( "label" );
- label.setAttribute( "for", "qunit-filter-pass" );
- label.setAttribute( "title", "Only show tests and assertons that fail. Stored in sessionStorage." );
- label.innerHTML = "Hide passed tests";
- toolbar.appendChild( label );
-
- urlConfigCheckboxesContainer = document.createElement("span");
- urlConfigCheckboxesContainer.innerHTML = urlConfigHtml;
- urlConfigCheckboxes = urlConfigCheckboxesContainer.getElementsByTagName("input");
- // For oldIE support:
- // * Add handlers to the individual elements instead of the container
- // * Use "click" instead of "change"
- // * Fallback from event.target to event.srcElement
- addEvents( urlConfigCheckboxes, "click", function( event ) {
- var params = {},
- target = event.target || event.srcElement;
- params[ target.name ] = target.checked ? true : undefined;
- window.location = QUnit.url( params );
- });
- toolbar.appendChild( urlConfigCheckboxesContainer );
-
- if (numModules > 1) {
- moduleFilter = document.createElement( 'span' );
- moduleFilter.setAttribute( 'id', 'qunit-modulefilter-container' );
- moduleFilter.innerHTML = moduleFilterHtml;
- addEvent( moduleFilter.lastChild, "change", function() {
- var selectBox = moduleFilter.getElementsByTagName("select")[0],
- selectedModule = decodeURIComponent(selectBox.options[selectBox.selectedIndex].value);
-
- window.location = QUnit.url( { module: ( selectedModule === "" ) ? undefined : selectedModule } );
- });
- toolbar.appendChild(moduleFilter);
- }
- }
-
- // `main` initialized at top of scope
- main = id( "qunit-fixture" );
- if ( main ) {
- config.fixture = main.innerHTML;
- }
-
- if ( config.autostart ) {
- QUnit.start();
- }
-};
-
-addEvent( window, "load", QUnit.load );
-
-// `onErrorFnPrev` initialized at top of scope
-// Preserve other handlers
-onErrorFnPrev = window.onerror;
-
-// Cover uncaught exceptions
-// Returning true will surpress the default browser handler,
-// returning false will let it run.
-window.onerror = function ( error, filePath, linerNr ) {
- var ret = false;
- if ( onErrorFnPrev ) {
- ret = onErrorFnPrev( error, filePath, linerNr );
- }
-
- // Treat return value as window.onerror itself does,
- // Only do our handling if not surpressed.
- if ( ret !== true ) {
- if ( QUnit.config.current ) {
- if ( QUnit.config.current.ignoreGlobalErrors ) {
- return true;
- }
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- } else {
- QUnit.test( "global failure", extend( function() {
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- }, { validTest: validTest } ) );
- }
- return false;
- }
-
- return ret;
-};
-
-function done() {
- config.autorun = true;
-
- // Log the last module results
- if ( config.currentModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.currentModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
-
- var i, key,
- banner = id( "qunit-banner" ),
- tests = id( "qunit-tests" ),
- runtime = +new Date() - config.started,
- passed = config.stats.all - config.stats.bad,
- html = [
- "Tests completed in ",
- runtime,
- " milliseconds.
",
- "",
- passed,
- " assertions of ",
- config.stats.all,
- " passed, ",
- config.stats.bad,
- " failed."
- ].join( "" );
-
- if ( banner ) {
- banner.className = ( config.stats.bad ? "qunit-fail" : "qunit-pass" );
- }
-
- if ( tests ) {
- id( "qunit-testresult" ).innerHTML = html;
- }
-
- if ( config.altertitle && typeof document !== "undefined" && document.title ) {
- // show ✖ for good, ✔ for bad suite result in title
- // use escape sequences in case file gets loaded with non-utf-8-charset
- document.title = [
- ( config.stats.bad ? "\u2716" : "\u2714" ),
- document.title.replace( /^[\u2714\u2716] /i, "" )
- ].join( " " );
- }
-
- // clear own sessionStorage items if all tests passed
- if ( config.reorder && defined.sessionStorage && config.stats.bad === 0 ) {
- // `key` & `i` initialized at top of scope
- for ( i = 0; i < sessionStorage.length; i++ ) {
- key = sessionStorage.key( i++ );
- if ( key.indexOf( "qunit-test-" ) === 0 ) {
- sessionStorage.removeItem( key );
- }
- }
- }
-
- // scroll back to top to show results
- if ( window.scrollTo ) {
- window.scrollTo(0, 0);
- }
-
- runLoggingCallbacks( "done", QUnit, {
- failed: config.stats.bad,
- passed: passed,
- total: config.stats.all,
- runtime: runtime
- });
-}
-
-/** @return Boolean: true if this test should be ran */
-function validTest( test ) {
- var include,
- filter = config.filter && config.filter.toLowerCase(),
- module = config.module && config.module.toLowerCase(),
- fullName = (test.module + ": " + test.testName).toLowerCase();
-
- // Internally-generated tests are always valid
- if ( test.callback && test.callback.validTest === validTest ) {
- delete test.callback.validTest;
- return true;
- }
-
- if ( config.testNumber ) {
- return test.testNumber === config.testNumber;
- }
-
- if ( module && ( !test.module || test.module.toLowerCase() !== module ) ) {
- return false;
- }
-
- if ( !filter ) {
- return true;
- }
-
- include = filter.charAt( 0 ) !== "!";
- if ( !include ) {
- filter = filter.slice( 1 );
- }
-
- // If the filter matches, we need to honour include
- if ( fullName.indexOf( filter ) !== -1 ) {
- return include;
- }
-
- // Otherwise, do the opposite
- return !include;
-}
-
-// so far supports only Firefox, Chrome and Opera (buggy), Safari (for real exceptions)
-// Later Safari and IE10 are supposed to support error.stack as well
-// See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack
-function extractStacktrace( e, offset ) {
- offset = offset === undefined ? 3 : offset;
-
- var stack, include, i;
-
- if ( e.stacktrace ) {
- // Opera
- return e.stacktrace.split( "\n" )[ offset + 3 ];
- } else if ( e.stack ) {
- // Firefox, Chrome
- stack = e.stack.split( "\n" );
- if (/^error$/i.test( stack[0] ) ) {
- stack.shift();
- }
- if ( fileName ) {
- include = [];
- for ( i = offset; i < stack.length; i++ ) {
- if ( stack[ i ].indexOf( fileName ) !== -1 ) {
- break;
- }
- include.push( stack[ i ] );
- }
- if ( include.length ) {
- return include.join( "\n" );
- }
- }
- return stack[ offset ];
- } else if ( e.sourceURL ) {
- // Safari, PhantomJS
- // hopefully one day Safari provides actual stacktraces
- // exclude useless self-reference for generated Error objects
- if ( /qunit.js$/.test( e.sourceURL ) ) {
- return;
- }
- // for actual exceptions, this is useful
- return e.sourceURL + ":" + e.line;
- }
-}
-function sourceFromStacktrace( offset ) {
- try {
- throw new Error();
- } catch ( e ) {
- return extractStacktrace( e, offset );
- }
-}
-
-/**
- * Escape text for attribute or text content.
- */
-function escapeText( s ) {
- if ( !s ) {
- return "";
- }
- s = s + "";
- // Both single quotes and double quotes (for attributes)
- return s.replace( /['"<>&]/g, function( s ) {
- switch( s ) {
- case '\'':
- return ''';
- case '"':
- return '"';
- case '<':
- return '<';
- case '>':
- return '>';
- case '&':
- return '&';
- }
- });
-}
-
-function synchronize( callback, last ) {
- config.queue.push( callback );
-
- if ( config.autorun && !config.blocking ) {
- process( last );
- }
-}
-
-function process( last ) {
- function next() {
- process( last );
- }
- var start = new Date().getTime();
- config.depth = config.depth ? config.depth + 1 : 1;
-
- while ( config.queue.length && !config.blocking ) {
- if ( !defined.setTimeout || config.updateRate <= 0 || ( ( new Date().getTime() - start ) < config.updateRate ) ) {
- config.queue.shift()();
- } else {
- window.setTimeout( next, 13 );
- break;
- }
- }
- config.depth--;
- if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) {
- done();
- }
-}
-
-function saveGlobal() {
- config.pollution = [];
-
- if ( config.noglobals ) {
- for ( var key in window ) {
- // in Opera sometimes DOM element ids show up here, ignore them
- if ( !hasOwn.call( window, key ) || /^qunit-test-output/.test( key ) ) {
- continue;
- }
- config.pollution.push( key );
- }
- }
-}
-
-function checkPollution() {
- var newGlobals,
- deletedGlobals,
- old = config.pollution;
-
- saveGlobal();
-
- newGlobals = diff( config.pollution, old );
- if ( newGlobals.length > 0 ) {
- QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join(", ") );
- }
-
- deletedGlobals = diff( old, config.pollution );
- if ( deletedGlobals.length > 0 ) {
- QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join(", ") );
- }
-}
-
-// returns a new Array with the elements that are in a but not in b
-function diff( a, b ) {
- var i, j,
- result = a.slice();
-
- for ( i = 0; i < result.length; i++ ) {
- for ( j = 0; j < b.length; j++ ) {
- if ( result[i] === b[j] ) {
- result.splice( i, 1 );
- i--;
- break;
- }
- }
- }
- return result;
-}
-
-function extend( a, b ) {
- for ( var prop in b ) {
- if ( b[ prop ] === undefined ) {
- delete a[ prop ];
-
- // Avoid "Member not found" error in IE8 caused by setting window.constructor
- } else if ( prop !== "constructor" || a !== window ) {
- a[ prop ] = b[ prop ];
- }
- }
-
- return a;
-}
-
-/**
- * @param {HTMLElement} elem
- * @param {string} type
- * @param {Function} fn
- */
-function addEvent( elem, type, fn ) {
- // Standards-based browsers
- if ( elem.addEventListener ) {
- elem.addEventListener( type, fn, false );
- // IE
- } else {
- elem.attachEvent( "on" + type, fn );
- }
-}
-
-/**
- * @param {Array|NodeList} elems
- * @param {string} type
- * @param {Function} fn
- */
-function addEvents( elems, type, fn ) {
- var i = elems.length;
- while ( i-- ) {
- addEvent( elems[i], type, fn );
- }
-}
-
-function hasClass( elem, name ) {
- return (" " + elem.className + " ").indexOf(" " + name + " ") > -1;
-}
-
-function addClass( elem, name ) {
- if ( !hasClass( elem, name ) ) {
- elem.className += (elem.className ? " " : "") + name;
- }
-}
-
-function removeClass( elem, name ) {
- var set = " " + elem.className + " ";
- // Class name may appear multiple times
- while ( set.indexOf(" " + name + " ") > -1 ) {
- set = set.replace(" " + name + " " , " ");
- }
- // If possible, trim it for prettiness, but not neccecarily
- elem.className = window.jQuery ? jQuery.trim( set ) : ( set.trim ? set.trim() : set );
-}
-
-function id( name ) {
- return !!( typeof document !== "undefined" && document && document.getElementById ) &&
- document.getElementById( name );
-}
-
-function registerLoggingCallback( key ) {
- return function( callback ) {
- config[key].push( callback );
- };
-}
-
-// Supports deprecated method of completely overwriting logging callbacks
-function runLoggingCallbacks( key, scope, args ) {
- var i, callbacks;
- if ( QUnit.hasOwnProperty( key ) ) {
- QUnit[ key ].call(scope, args );
- } else {
- callbacks = config[ key ];
- for ( i = 0; i < callbacks.length; i++ ) {
- callbacks[ i ].call( scope, args );
- }
- }
-}
-
-// Test for equality any JavaScript type.
-// Author: Philippe Rathé
-QUnit.equiv = (function() {
-
- // Call the o related callback with the given arguments.
- function bindCallbacks( o, callbacks, args ) {
- var prop = QUnit.objectType( o );
- if ( prop ) {
- if ( QUnit.objectType( callbacks[ prop ] ) === "function" ) {
- return callbacks[ prop ].apply( callbacks, args );
- } else {
- return callbacks[ prop ]; // or undefined
- }
- }
- }
-
- // the real equiv function
- var innerEquiv,
- // stack to decide between skip/abort functions
- callers = [],
- // stack to avoiding loops from circular referencing
- parents = [],
-
- getProto = Object.getPrototypeOf || function ( obj ) {
- return obj.__proto__;
- },
- callbacks = (function () {
-
- // for string, boolean, number and null
- function useStrictEquality( b, a ) {
- /*jshint eqeqeq:false */
- if ( b instanceof a.constructor || a instanceof b.constructor ) {
- // to catch short annotaion VS 'new' annotation of a
- // declaration
- // e.g. var i = 1;
- // var j = new Number(1);
- return a == b;
- } else {
- return a === b;
- }
- }
-
- return {
- "string": useStrictEquality,
- "boolean": useStrictEquality,
- "number": useStrictEquality,
- "null": useStrictEquality,
- "undefined": useStrictEquality,
-
- "nan": function( b ) {
- return isNaN( b );
- },
-
- "date": function( b, a ) {
- return QUnit.objectType( b ) === "date" && a.valueOf() === b.valueOf();
- },
-
- "regexp": function( b, a ) {
- return QUnit.objectType( b ) === "regexp" &&
- // the regex itself
- a.source === b.source &&
- // and its modifers
- a.global === b.global &&
- // (gmi) ...
- a.ignoreCase === b.ignoreCase &&
- a.multiline === b.multiline &&
- a.sticky === b.sticky;
- },
-
- // - skip when the property is a method of an instance (OOP)
- // - abort otherwise,
- // initial === would have catch identical references anyway
- "function": function() {
- var caller = callers[callers.length - 1];
- return caller !== Object && typeof caller !== "undefined";
- },
-
- "array": function( b, a ) {
- var i, j, len, loop;
-
- // b could be an object literal here
- if ( QUnit.objectType( b ) !== "array" ) {
- return false;
- }
-
- len = a.length;
- if ( len !== b.length ) {
- // safe and faster
- return false;
- }
-
- // track reference to avoid circular references
- parents.push( a );
- for ( i = 0; i < len; i++ ) {
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- loop = true;// dont rewalk array
- }
- }
- if ( !loop && !innerEquiv(a[i], b[i]) ) {
- parents.pop();
- return false;
- }
- }
- parents.pop();
- return true;
- },
-
- "object": function( b, a ) {
- var i, j, loop,
- // Default to true
- eq = true,
- aProperties = [],
- bProperties = [];
-
- // comparing constructors is more strict than using
- // instanceof
- if ( a.constructor !== b.constructor ) {
- // Allow objects with no prototype to be equivalent to
- // objects with Object as their constructor.
- if ( !(( getProto(a) === null && getProto(b) === Object.prototype ) ||
- ( getProto(b) === null && getProto(a) === Object.prototype ) ) ) {
- return false;
- }
- }
-
- // stack constructor before traversing properties
- callers.push( a.constructor );
- // track reference to avoid circular references
- parents.push( a );
-
- for ( i in a ) { // be strict: don't ensures hasOwnProperty
- // and go deep
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- // don't go down the same path twice
- loop = true;
- }
- }
- aProperties.push(i); // collect a's properties
-
- if (!loop && !innerEquiv( a[i], b[i] ) ) {
- eq = false;
- break;
- }
- }
-
- callers.pop(); // unstack, we are done
- parents.pop();
-
- for ( i in b ) {
- bProperties.push( i ); // collect b's properties
- }
-
- // Ensures identical properties name
- return eq && innerEquiv( aProperties.sort(), bProperties.sort() );
- }
- };
- }());
-
- innerEquiv = function() { // can take multiple arguments
- var args = [].slice.apply( arguments );
- if ( args.length < 2 ) {
- return true; // end transition
- }
-
- return (function( a, b ) {
- if ( a === b ) {
- return true; // catch the most you can
- } else if ( a === null || b === null || typeof a === "undefined" ||
- typeof b === "undefined" ||
- QUnit.objectType(a) !== QUnit.objectType(b) ) {
- return false; // don't lose time with error prone cases
- } else {
- return bindCallbacks(a, callbacks, [ b, a ]);
- }
-
- // apply transition with (1..n) arguments
- }( args[0], args[1] ) && arguments.callee.apply( this, args.splice(1, args.length - 1 )) );
- };
-
- return innerEquiv;
-}());
-
-/**
- * jsDump Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com |
- * http://flesler.blogspot.com Licensed under BSD
- * (http://www.opensource.org/licenses/bsd-license.php) Date: 5/15/2008
- *
- * @projectDescription Advanced and extensible data dumping for Javascript.
- * @version 1.0.0
- * @author Ariel Flesler
- * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html}
- */
-QUnit.jsDump = (function() {
- function quote( str ) {
- return '"' + str.toString().replace( /"/g, '\\"' ) + '"';
- }
- function literal( o ) {
- return o + "";
- }
- function join( pre, arr, post ) {
- var s = jsDump.separator(),
- base = jsDump.indent(),
- inner = jsDump.indent(1);
- if ( arr.join ) {
- arr = arr.join( "," + s + inner );
- }
- if ( !arr ) {
- return pre + post;
- }
- return [ pre, inner + arr, base + post ].join(s);
- }
- function array( arr, stack ) {
- var i = arr.length, ret = new Array(i);
- this.up();
- while ( i-- ) {
- ret[i] = this.parse( arr[i] , undefined , stack);
- }
- this.down();
- return join( "[", ret, "]" );
- }
-
- var reName = /^function (\w+)/,
- jsDump = {
- // type is used mostly internally, you can fix a (custom)type in advance
- parse: function( obj, type, stack ) {
- stack = stack || [ ];
- var inStack, res,
- parser = this.parsers[ type || this.typeOf(obj) ];
-
- type = typeof parser;
- inStack = inArray( obj, stack );
-
- if ( inStack !== -1 ) {
- return "recursion(" + (inStack - stack.length) + ")";
- }
- if ( type === "function" ) {
- stack.push( obj );
- res = parser.call( this, obj, stack );
- stack.pop();
- return res;
- }
- return ( type === "string" ) ? parser : this.parsers.error;
- },
- typeOf: function( obj ) {
- var type;
- if ( obj === null ) {
- type = "null";
- } else if ( typeof obj === "undefined" ) {
- type = "undefined";
- } else if ( QUnit.is( "regexp", obj) ) {
- type = "regexp";
- } else if ( QUnit.is( "date", obj) ) {
- type = "date";
- } else if ( QUnit.is( "function", obj) ) {
- type = "function";
- } else if ( typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined" ) {
- type = "window";
- } else if ( obj.nodeType === 9 ) {
- type = "document";
- } else if ( obj.nodeType ) {
- type = "node";
- } else if (
- // native arrays
- toString.call( obj ) === "[object Array]" ||
- // NodeList objects
- ( typeof obj.length === "number" && typeof obj.item !== "undefined" && ( obj.length ? obj.item(0) === obj[0] : ( obj.item( 0 ) === null && typeof obj[0] === "undefined" ) ) )
- ) {
- type = "array";
- } else if ( obj.constructor === Error.prototype.constructor ) {
- type = "error";
- } else {
- type = typeof obj;
- }
- return type;
- },
- separator: function() {
- return this.multiline ? this.HTML ? "
" : "\n" : this.HTML ? " " : " ";
- },
- // extra can be a number, shortcut for increasing-calling-decreasing
- indent: function( extra ) {
- if ( !this.multiline ) {
- return "";
- }
- var chr = this.indentChar;
- if ( this.HTML ) {
- chr = chr.replace( /\t/g, " " ).replace( / /g, " " );
- }
- return new Array( this._depth_ + (extra||0) ).join(chr);
- },
- up: function( a ) {
- this._depth_ += a || 1;
- },
- down: function( a ) {
- this._depth_ -= a || 1;
- },
- setParser: function( name, parser ) {
- this.parsers[name] = parser;
- },
- // The next 3 are exposed so you can use them
- quote: quote,
- literal: literal,
- join: join,
- //
- _depth_: 1,
- // This is the list of parsers, to modify them, use jsDump.setParser
- parsers: {
- window: "[Window]",
- document: "[Document]",
- error: function(error) {
- return "Error(\"" + error.message + "\")";
- },
- unknown: "[Unknown]",
- "null": "null",
- "undefined": "undefined",
- "function": function( fn ) {
- var ret = "function",
- // functions never have name in IE
- name = "name" in fn ? fn.name : (reName.exec(fn) || [])[1];
-
- if ( name ) {
- ret += " " + name;
- }
- ret += "( ";
-
- ret = [ ret, QUnit.jsDump.parse( fn, "functionArgs" ), "){" ].join( "" );
- return join( ret, QUnit.jsDump.parse(fn,"functionCode" ), "}" );
- },
- array: array,
- nodelist: array,
- "arguments": array,
- object: function( map, stack ) {
- var ret = [ ], keys, key, val, i;
- QUnit.jsDump.up();
- keys = [];
- for ( key in map ) {
- keys.push( key );
- }
- keys.sort();
- for ( i = 0; i < keys.length; i++ ) {
- key = keys[ i ];
- val = map[ key ];
- ret.push( QUnit.jsDump.parse( key, "key" ) + ": " + QUnit.jsDump.parse( val, undefined, stack ) );
- }
- QUnit.jsDump.down();
- return join( "{", ret, "}" );
- },
- node: function( node ) {
- var len, i, val,
- open = QUnit.jsDump.HTML ? "<" : "<",
- close = QUnit.jsDump.HTML ? ">" : ">",
- tag = node.nodeName.toLowerCase(),
- ret = open + tag,
- attrs = node.attributes;
-
- if ( attrs ) {
- for ( i = 0, len = attrs.length; i < len; i++ ) {
- val = attrs[i].nodeValue;
- // IE6 includes all attributes in .attributes, even ones not explicitly set.
- // Those have values like undefined, null, 0, false, "" or "inherit".
- if ( val && val !== "inherit" ) {
- ret += " " + attrs[i].nodeName + "=" + QUnit.jsDump.parse( val, "attribute" );
- }
- }
- }
- ret += close;
-
- // Show content of TextNode or CDATASection
- if ( node.nodeType === 3 || node.nodeType === 4 ) {
- ret += node.nodeValue;
- }
-
- return ret + open + "/" + tag + close;
- },
- // function calls it internally, it's the arguments part of the function
- functionArgs: function( fn ) {
- var args,
- l = fn.length;
-
- if ( !l ) {
- return "";
- }
-
- args = new Array(l);
- while ( l-- ) {
- // 97 is 'a'
- args[l] = String.fromCharCode(97+l);
- }
- return " " + args.join( ", " ) + " ";
- },
- // object calls it internally, the key part of an item in a map
- key: quote,
- // function calls it internally, it's the content of the function
- functionCode: "[code]",
- // node calls it internally, it's an html attribute value
- attribute: quote,
- string: quote,
- date: quote,
- regexp: literal,
- number: literal,
- "boolean": literal
- },
- // if true, entities are escaped ( <, >, \t, space and \n )
- HTML: false,
- // indentation unit
- indentChar: " ",
- // if true, items in a collection, are separated by a \n, else just a space.
- multiline: true
- };
-
- return jsDump;
-}());
-
-// from jquery.js
-function inArray( elem, array ) {
- if ( array.indexOf ) {
- return array.indexOf( elem );
- }
-
- for ( var i = 0, length = array.length; i < length; i++ ) {
- if ( array[ i ] === elem ) {
- return i;
- }
- }
-
- return -1;
-}
-
-/*
- * Javascript Diff Algorithm
- * By John Resig (http://ejohn.org/)
- * Modified by Chu Alan "sprite"
- *
- * Released under the MIT license.
- *
- * More Info:
- * http://ejohn.org/projects/javascript-diff-algorithm/
- *
- * Usage: QUnit.diff(expected, actual)
- *
- * QUnit.diff( "the quick brown fox jumped over", "the quick fox jumps over" ) == "the quick brown fox jumped jumps over"
- */
-QUnit.diff = (function() {
- /*jshint eqeqeq:false, eqnull:true */
- function diff( o, n ) {
- var i,
- ns = {},
- os = {};
-
- for ( i = 0; i < n.length; i++ ) {
- if ( !hasOwn.call( ns, n[i] ) ) {
- ns[ n[i] ] = {
- rows: [],
- o: null
- };
- }
- ns[ n[i] ].rows.push( i );
- }
-
- for ( i = 0; i < o.length; i++ ) {
- if ( !hasOwn.call( os, o[i] ) ) {
- os[ o[i] ] = {
- rows: [],
- n: null
- };
- }
- os[ o[i] ].rows.push( i );
- }
-
- for ( i in ns ) {
- if ( !hasOwn.call( ns, i ) ) {
- continue;
- }
- if ( ns[i].rows.length === 1 && hasOwn.call( os, i ) && os[i].rows.length === 1 ) {
- n[ ns[i].rows[0] ] = {
- text: n[ ns[i].rows[0] ],
- row: os[i].rows[0]
- };
- o[ os[i].rows[0] ] = {
- text: o[ os[i].rows[0] ],
- row: ns[i].rows[0]
- };
- }
- }
-
- for ( i = 0; i < n.length - 1; i++ ) {
- if ( n[i].text != null && n[ i + 1 ].text == null && n[i].row + 1 < o.length && o[ n[i].row + 1 ].text == null &&
- n[ i + 1 ] == o[ n[i].row + 1 ] ) {
-
- n[ i + 1 ] = {
- text: n[ i + 1 ],
- row: n[i].row + 1
- };
- o[ n[i].row + 1 ] = {
- text: o[ n[i].row + 1 ],
- row: i + 1
- };
- }
- }
-
- for ( i = n.length - 1; i > 0; i-- ) {
- if ( n[i].text != null && n[ i - 1 ].text == null && n[i].row > 0 && o[ n[i].row - 1 ].text == null &&
- n[ i - 1 ] == o[ n[i].row - 1 ]) {
-
- n[ i - 1 ] = {
- text: n[ i - 1 ],
- row: n[i].row - 1
- };
- o[ n[i].row - 1 ] = {
- text: o[ n[i].row - 1 ],
- row: i - 1
- };
- }
- }
-
- return {
- o: o,
- n: n
- };
- }
-
- return function( o, n ) {
- o = o.replace( /\s+$/, "" );
- n = n.replace( /\s+$/, "" );
-
- var i, pre,
- str = "",
- out = diff( o === "" ? [] : o.split(/\s+/), n === "" ? [] : n.split(/\s+/) ),
- oSpace = o.match(/\s+/g),
- nSpace = n.match(/\s+/g);
-
- if ( oSpace == null ) {
- oSpace = [ " " ];
- }
- else {
- oSpace.push( " " );
- }
-
- if ( nSpace == null ) {
- nSpace = [ " " ];
- }
- else {
- nSpace.push( " " );
- }
-
- if ( out.n.length === 0 ) {
- for ( i = 0; i < out.o.length; i++ ) {
- str += "" + out.o[i] + oSpace[i] + "";
- }
- }
- else {
- if ( out.n[0].text == null ) {
- for ( n = 0; n < out.o.length && out.o[n].text == null; n++ ) {
- str += "" + out.o[n] + oSpace[n] + "";
- }
- }
-
- for ( i = 0; i < out.n.length; i++ ) {
- if (out.n[i].text == null) {
- str += "" + out.n[i] + nSpace[i] + "";
- }
- else {
- // `pre` initialized at top of scope
- pre = "";
-
- for ( n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++ ) {
- pre += "" + out.o[n] + oSpace[n] + "";
- }
- str += " " + out.n[i].text + nSpace[i] + pre;
- }
- }
- }
-
- return str;
- };
-}());
-
-// for CommonJS enviroments, export everything
-if ( typeof exports !== "undefined" ) {
- extend( exports, QUnit );
-}
-
-// get at whatever the global object is, like window in browsers
-}( (function() {return this;}.call()) ));
diff --git a/test/lib/require.js b/test/lib/require.js
deleted file mode 100644
index 987f865..0000000
--- a/test/lib/require.js
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- RequireJS 2.1.5 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.
- Available via the MIT or new BSD license.
- see: http://github.com/jrburke/requirejs for details
-*/
-var requirejs,require,define;
-(function(aa){function I(b){return"[object Function]"===L.call(b)}function J(b){return"[object Array]"===L.call(b)}function y(b,c){if(b){var d;for(d=0;dthis.depCount&&!this.defined){if(I(n)){if(this.events.error)try{e=i.execCb(c,n,b,e)}catch(d){a=d}else e=i.execCb(c,n,b,e);this.map.isDefine&&((b=this.module)&&void 0!==b.exports&&b.exports!==this.exports?e=b.exports:void 0===e&&this.usingExports&&(e=this.exports));if(a)return a.requireMap=this.map,a.requireModules=[this.map.id],a.requireType="define",v(this.error=
-a)}else e=n;this.exports=e;if(this.map.isDefine&&!this.ignore&&(q[c]=e,l.onResourceLoad))l.onResourceLoad(i,this.map,this.depMaps);x(c);this.defined=!0}this.defining=!1;this.defined&&!this.defineEmitted&&(this.defineEmitted=!0,this.emit("defined",this.exports),this.defineEmitComplete=!0)}}else this.fetch()}},callPlugin:function(){var a=this.map,b=a.id,d=j(a.prefix);this.depMaps.push(d);t(d,"defined",u(this,function(e){var n,d;d=this.map.name;var g=this.map.parentMap?this.map.parentMap.name:null,h=
-i.makeRequire(a.parentMap,{enableBuildCallback:!0});if(this.map.unnormalized){if(e.normalize&&(d=e.normalize(d,function(a){return c(a,g,!0)})||""),e=j(a.prefix+"!"+d,this.map.parentMap),t(e,"defined",u(this,function(a){this.init([],function(){return a},null,{enabled:!0,ignore:!0})})),d=m(p,e.id)){this.depMaps.push(e);if(this.events.error)d.on("error",u(this,function(a){this.emit("error",a)}));d.enable()}}else n=u(this,function(a){this.init([],function(){return a},null,{enabled:!0})}),n.error=u(this,
-function(a){this.inited=!0;this.error=a;a.requireModules=[b];G(p,function(a){0===a.map.id.indexOf(b+"_unnormalized")&&x(a.map.id)});v(a)}),n.fromText=u(this,function(e,c){var d=a.name,g=j(d),C=O;c&&(e=c);C&&(O=!1);r(g);s(k.config,b)&&(k.config[d]=k.config[b]);try{l.exec(e)}catch(ca){return v(B("fromtexteval","fromText eval for "+b+" failed: "+ca,ca,[b]))}C&&(O=!0);this.depMaps.push(g);i.completeLoad(d);h([d],n)}),e.load(a.name,h,n,k)}));i.enable(d,this);this.pluginMaps[d.id]=d},enable:function(){V[this.map.id]=
-this;this.enabling=this.enabled=!0;y(this.depMaps,u(this,function(a,b){var c,e;if("string"===typeof a){a=j(a,this.map.isDefine?this.map:this.map.parentMap,!1,!this.skipMap);this.depMaps[b]=a;if(c=m(N,a.id)){this.depExports[b]=c(this);return}this.depCount+=1;t(a,"defined",u(this,function(a){this.defineDep(b,a);this.check()}));this.errback&&t(a,"error",this.errback)}c=a.id;e=p[c];!s(N,c)&&(e&&!e.enabled)&&i.enable(a,this)}));G(this.pluginMaps,u(this,function(a){var b=m(p,a.id);b&&!b.enabled&&i.enable(a,
-this)}));this.enabling=!1;this.check()},on:function(a,b){var c=this.events[a];c||(c=this.events[a]=[]);c.push(b)},emit:function(a,b){y(this.events[a],function(a){a(b)});"error"===a&&delete this.events[a]}};i={config:k,contextName:b,registry:p,defined:q,urlFetched:U,defQueue:H,Module:Z,makeModuleMap:j,nextTick:l.nextTick,onError:v,configure:function(a){a.baseUrl&&"/"!==a.baseUrl.charAt(a.baseUrl.length-1)&&(a.baseUrl+="/");var b=k.pkgs,c=k.shim,e={paths:!0,config:!0,map:!0};G(a,function(a,b){e[b]?
-"map"===b?(k.map||(k.map={}),R(k[b],a,!0,!0)):R(k[b],a,!0):k[b]=a});a.shim&&(G(a.shim,function(a,b){J(a)&&(a={deps:a});if((a.exports||a.init)&&!a.exportsFn)a.exportsFn=i.makeShimExports(a);c[b]=a}),k.shim=c);a.packages&&(y(a.packages,function(a){a="string"===typeof a?{name:a}:a;b[a.name]={name:a.name,location:a.location||a.name,main:(a.main||"main").replace(ja,"").replace(ea,"")}}),k.pkgs=b);G(p,function(a,b){!a.inited&&!a.map.unnormalized&&(a.map=j(b))});if(a.deps||a.callback)i.require(a.deps||[],
-a.callback)},makeShimExports:function(a){return function(){var b;a.init&&(b=a.init.apply(aa,arguments));return b||a.exports&&ba(a.exports)}},makeRequire:function(a,f){function d(e,c,h){var g,k;f.enableBuildCallback&&(c&&I(c))&&(c.__requireJsBuild=!0);if("string"===typeof e){if(I(c))return v(B("requireargs","Invalid require call"),h);if(a&&s(N,e))return N[e](p[a.id]);if(l.get)return l.get(i,e,a,d);g=j(e,a,!1,!0);g=g.id;return!s(q,g)?v(B("notloaded",'Module name "'+g+'" has not been loaded yet for context: '+
-b+(a?"":". Use require([])"))):q[g]}L();i.nextTick(function(){L();k=r(j(null,a));k.skipMap=f.skipMap;k.init(e,c,h,{enabled:!0});D()});return d}f=f||{};R(d,{isBrowser:A,toUrl:function(b){var d,f=b.lastIndexOf("."),g=b.split("/")[0];if(-1!==f&&(!("."===g||".."===g)||1h.attachEvent.toString().indexOf("[native code"))&&!Y?(O=!0,h.attachEvent("onreadystatechange",b.onScriptLoad)):(h.addEventListener("load",b.onScriptLoad,!1),h.addEventListener("error",b.onScriptError,!1)),h.src=d,K=h,D?x.insertBefore(h,D):x.appendChild(h),K=null,h;if(da)try{importScripts(d),b.completeLoad(c)}catch(j){b.onError(B("importscripts","importScripts failed for "+c+" at "+d,j,[c]))}};A&&M(document.getElementsByTagName("script"),function(b){x||(x=
-b.parentNode);if(t=b.getAttribute("data-main"))return r.baseUrl||(E=t.split("/"),Q=E.pop(),fa=E.length?E.join("/")+"/":"./",r.baseUrl=fa,t=Q),t=t.replace(ea,""),r.deps=r.deps?r.deps.concat(t):[t],!0});define=function(b,c,d){var l,h;"string"!==typeof b&&(d=c,c=b,b=null);J(c)||(d=c,c=[]);!c.length&&I(d)&&d.length&&(d.toString().replace(la,"").replace(ma,function(b,d){c.push(d)}),c=(1===d.length?["require"]:["require","exports","module"]).concat(c));if(O){if(!(l=K))P&&"interactive"===P.readyState||M(document.getElementsByTagName("script"),
-function(b){if("interactive"===b.readyState)return P=b}),l=P;l&&(b||(b=l.getAttribute("data-requiremodule")),h=F[l.getAttribute("data-requirecontext")])}(h?h.defQueue:T).push([b,c,d])};define.amd={jQuery:!0};l.exec=function(b){return eval(b)};l(r)}})(this);
diff --git a/test/lib/resemble.js b/test/lib/resemble.js
new file mode 100644
index 0000000..1cb8c29
--- /dev/null
+++ b/test/lib/resemble.js
@@ -0,0 +1,535 @@
+/*
+Author: James Cryer
+Company: Huddle
+Last updated date: 21 Feb 2013
+URL: https://github.com/Huddle/Resemble.js
+*/
+
+(function(_this){
+ 'use strict';
+
+ _this['resemble'] = function( fileData ){
+
+ var data = {};
+ var images = [];
+ var updateCallbackArray = [];
+
+ var tolerance = { // between 0 and 255
+ red: 16,
+ green: 16,
+ blue: 16,
+ minBrightness: 16,
+ maxBrightness: 240
+ };
+
+ var ignoreAntialiasing = false;
+ var ignoreColors = false;
+
+ function triggerDataUpdate(){
+ var len = updateCallbackArray.length;
+ var i;
+ for(i=0;i tolerance.maxBrightness;
+ }
+
+ function getHue(r,g,b){
+
+ r = r / 255;
+ g = g / 255;
+ b = b / 255;
+ var max = Math.max(r, g, b), min = Math.min(r, g, b);
+ var h;
+ var d;
+
+ if (max == min){
+ h = 0; // achromatic
+ } else{
+ d = max - min;
+ switch(max){
+ case r: h = (g - b) / d + (g < b ? 6 : 0); break;
+ case g: h = (b - r) / d + 2; break;
+ case b: h = (r - g) / d + 4; break;
+ }
+ h /= 6;
+ }
+
+ return h;
+ }
+
+ function isAntialiased(sourcePix, data, cacheSet, verticalPos, horizontalPos, width){
+ var offset;
+ var targetPix;
+ var distance = 1;
+ var i;
+ var j;
+ var hasHighContrastSibling = 0;
+ var hasSiblingWithDifferentHue = 0;
+ var hasEquivilantSibling = 0;
+
+ addHueInfo(sourcePix);
+
+ for (i = distance*-1; i <= distance; i++){
+ for (j = distance*-1; j <= distance; j++){
+
+ if(i===0 && j===0){
+ // ignore source pixel
+ } else {
+
+ offset = ((verticalPos+j)*width + (horizontalPos+i)) * 4;
+ targetPix = getPixelInfo(data, offset, cacheSet);
+
+ if(targetPix === null){
+ continue;
+ }
+
+ addBrightnessInfo(targetPix);
+ addHueInfo(targetPix);
+
+ if( isContrasting(sourcePix, targetPix) ){
+ hasHighContrastSibling++;
+ }
+
+ if( isRGBSame(sourcePix,targetPix) ){
+ hasEquivilantSibling++;
+ }
+
+ if( Math.abs(targetPix.h - sourcePix.h) > 0.3 ){
+ hasSiblingWithDifferentHue++;
+ }
+
+ if( hasSiblingWithDifferentHue > 1 || hasHighContrastSibling > 1){
+ return true;
+ }
+ }
+ }
+ }
+
+ if(hasEquivilantSibling < 2){
+ return true;
+ }
+
+ return false;
+ }
+
+ function errorPixel(px, offset){
+ px[offset] = 255; //r
+ px[offset + 1] = 0; //g
+ px[offset + 2] = 255; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyPixel(px, offset, data){
+ px[offset] = data.r; //r
+ px[offset + 1] = data.g; //g
+ px[offset + 2] = data.b; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyGrayScalePixel(px, offset, data){
+ px[offset] = data.brightness; //r
+ px[offset + 1] = data.brightness; //g
+ px[offset + 2] = data.brightness; //b
+ px[offset + 3] = 255; //a
+ }
+
+
+ function getPixelInfo(data, offset, cacheSet){
+ var r;
+ var g;
+ var b;
+ var d;
+
+ if(typeof data[offset] !== 'undefined'){
+ r = data[offset];
+ g = data[offset+1];
+ b = data[offset+2];
+ d = {
+ r: r,
+ g: g,
+ b: b
+ };
+
+ return d;
+ } else {
+ return null;
+ }
+ }
+
+ function addBrightnessInfo(data){
+ data.brightness = getBrightness(data.r,data.g,data.b); // 'corrected' lightness
+ }
+
+ function addHueInfo(data){
+ data.h = getHue(data.r,data.g,data.b);
+ }
+
+ function analyseImages(img1, img2, width, height){
+
+ var hiddenCanvas = document.createElement('canvas');
+
+ var data1 = img1.data;
+ var data2 = img2.data;
+
+ hiddenCanvas.width = width;
+ hiddenCanvas.height = height;
+
+ var context = hiddenCanvas.getContext('2d');
+ var imgd = context.createImageData(width,height);
+ var targetPix = imgd.data;
+
+ var mismatchCount = 0;
+
+ var time = Date.now();
+
+ var skip;
+
+ if( (width > 1200 || height > 1200) && ignoreAntialiasing){
+ skip = 6;
+ }
+
+ loop(height, width, function(verticalPos, horizontalPos){
+
+ if(skip){ // only skip if the image isn't small
+ if(verticalPos % skip === 0 || horizontalPos % skip === 0){
+ return;
+ }
+ }
+
+ var offset = (verticalPos*width + horizontalPos) * 4;
+ var pixel1 = getPixelInfo(data1, offset, 1);
+ var pixel2 = getPixelInfo(data2, offset, 2);
+
+ if(pixel1 === null || pixel2 === null){
+ return;
+ }
+
+ if (ignoreColors){
+
+ addBrightnessInfo(pixel1);
+ addBrightnessInfo(pixel2);
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ return;
+ }
+
+ if( isRGBSimilar(pixel1, pixel2) ){
+ copyPixel(targetPix, offset, pixel2);
+
+ } else if( ignoreAntialiasing && (
+ addBrightnessInfo(pixel1), // jit pixel info augmentation looks a little weird, sorry.
+ addBrightnessInfo(pixel2),
+ isAntialiased(pixel1, data1, 1, verticalPos, horizontalPos, width) ||
+ isAntialiased(pixel2, data2, 2, verticalPos, horizontalPos, width)
+ )){
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+
+ });
+
+ data.misMatchPercentage = (mismatchCount / (height*width) * 100).toFixed(2);
+ data.analysisTime = Date.now() - time;
+
+ data.getImageDataUrl = function(text){
+ var barHeight = 0;
+
+ if(text){
+ barHeight = addLabel(text,context,hiddenCanvas);
+ }
+
+ context.putImageData(imgd, 0, barHeight);
+
+ return hiddenCanvas.toDataURL("image/png");
+ };
+ }
+
+ function addLabel(text, context, hiddenCanvas){
+ var textPadding = 2;
+
+ context.font = '12px sans-serif';
+
+ var textWidth = context.measureText(text).width + textPadding*2;
+ var barHeight = 22;
+
+ if(textWidth > hiddenCanvas.width){
+ hiddenCanvas.width = textWidth;
+ }
+
+ hiddenCanvas.height += barHeight;
+
+ context.fillStyle = "#666";
+ context.fillRect(0,0,hiddenCanvas.width,barHeight -4);
+ context.fillStyle = "#fff";
+ context.fillRect(0,barHeight -4,hiddenCanvas.width, 4);
+
+ context.fillStyle = "#fff";
+ context.textBaseline = "top";
+ context.font = '12px sans-serif';
+ context.fillText(text, textPadding, 1);
+
+ return barHeight;
+ }
+
+ function normalise(img, w, h){
+ var c;
+ var context;
+
+ if(img.height < h || img.width < w){
+ c = document.createElement('canvas');
+ c.width = w;
+ c.height = h;
+ context = c.getContext('2d');
+ context.putImageData(img, 0, 0);
+ return context.getImageData(0, 0, w, h);
+ }
+
+ return img;
+ }
+
+ function compare(one, two){
+
+ function onceWeHaveBoth(){
+ var width;
+ var height;
+ if(images.length === 2){
+ width = images[0].width > images[1].width ? images[0].width : images[1].width;
+ height = images[0].height > images[1].height ? images[0].height : images[1].height;
+
+ if( (images[0].width === images[1].width) && (images[0].height === images[1].height) ){
+ data.isSameDimensions = true;
+ } else {
+ data.isSameDimensions = false;
+ }
+
+ analyseImages( normalise(images[0],width, height), normalise(images[1],width, height), width, height);
+
+ triggerDataUpdate();
+ }
+ }
+
+ images = [];
+ loadImageData(one, onceWeHaveBoth);
+ loadImageData(two, onceWeHaveBoth);
+ }
+
+ function getCompareApi(param){
+
+ var secondFileData,
+ hasMethod = typeof param === 'function';
+
+ if( !hasMethod ){
+ // assume it's file data
+ secondFileData = param;
+ }
+
+ var self = {
+ ignoreNothing: function(){
+
+ tolerance.red = 16;
+ tolerance.green = 16;
+ tolerance.blue = 16;
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreAntialiasing: function(){
+
+ tolerance.red = 32;
+ tolerance.green = 32;
+ tolerance.blue = 32;
+ tolerance.minBrightness = 64;
+ tolerance.maxBrightness = 96;
+
+ ignoreAntialiasing = true;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreColors: function(){
+
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = true;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ onComplete: function( callback ){
+
+ updateCallbackArray.push(callback);
+
+ var wrapper = function(){
+ compare(fileData, secondFileData);
+ };
+
+ wrapper();
+
+ return getCompareApi(wrapper);
+ }
+ };
+
+ return self;
+ }
+
+ return {
+ onComplete: function( callback ){
+ updateCallbackArray.push(callback);
+ loadImageData(fileData, function(imageData, width, height){
+ parseImage(imageData.data, width, height);
+ });
+ },
+ compareTo: function(secondFileData){
+ return getCompareApi(secondFileData);
+ }
+ };
+
+ };
+}(this));
\ No newline at end of file
diff --git a/test/testsuite.js b/test/testsuite.js
deleted file mode 100644
index b486acb..0000000
--- a/test/testsuite.js
+++ /dev/null
@@ -1,36 +0,0 @@
-requirejs.config({
- baseUrl: '/test/unit/'
-});
-
-define(function(require) {
- var testModules = [
- 'Pixi',
- 'Point',
- 'Rectangle',
- 'DisplayObject',
- 'DisplayObjectContainer',
- 'Sprite',
- 'MovieClip',
- 'InteractionManager',
- 'Stage',
- 'utils/Utils',
- 'utils/EventTarget',
- 'utils/Matrix',
- 'utils/Detector',
- 'renderers/WebGLShaders',
- 'renderers/WebGLRenderer',
- 'renderers/WebGLBatch',
- 'renderers/CanvasRenderer',
- 'extras/Strip',
- 'extras/Rope',
- 'textures/BaseTexture',
- 'textures/Texture',
- 'loaders/SpriteSheetLoader',
- 'loaders/AssetLoader'
- ];
-
- // Resolve all testModules and then start the Test Runner.
- require(testModules, function() {
- QUnit.start();
- });
-});
\ No newline at end of file
diff --git a/test/textures/SpriteSheet-Aliens.png b/test/textures/SpriteSheet-Aliens.png
new file mode 100644
index 0000000..210acb1
--- /dev/null
+++ b/test/textures/SpriteSheet-Aliens.png
Binary files differ
diff --git a/test/textures/SpriteSheet-Explosion.png b/test/textures/SpriteSheet-Explosion.png
new file mode 100755
index 0000000..79e1a69
--- /dev/null
+++ b/test/textures/SpriteSheet-Explosion.png
Binary files differ
diff --git a/.gitignore b/.gitignore
index 12e1b62..0b88317 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
node_modules
.DS_Store
-.project
\ No newline at end of file
+.project
+*.log
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..63e4d7c
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,8 @@
+language: node_js
+node_js:
+ - 0.10
+
+before_script:
+ - npm install -g grunt-cli
+ - export DISPLAY=:99.0
+ - sh -e /etc/init.d/xvfb start
diff --git a/Gruntfile.js b/Gruntfile.js
index b083b49..103938c 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -1,10 +1,12 @@
+'use strict';
+
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-connect');
- grunt.loadNpmTasks('grunt-contrib-qunit');
grunt.loadNpmTasks('grunt-contrib-yuidoc');
+ grunt.loadTasks('tasks');
var root = 'src/pixi/',
debug = 'bin/pixi.dev.js',
@@ -79,7 +81,7 @@
},
files: {
srcBlob: '<%= dirs.src %>/**/*.js',
- testBlob: '<%= dirs.test %>/unit/**/*.js',
+ testBlob: '<%= dirs.test %>/{functional,lib/pixi,unit}/**/*.js',
build: '<%= dirs.build %>/pixi.dev.js',
buildMin: '<%= dirs.build %>/pixi.js'
},
@@ -94,7 +96,12 @@
},
jshint: {
beforeconcat: srcFiles,
- test: ['<%= files.testBlob %>'],
+ test: {
+ src: ['<%= files.testBlob %>'],
+ options: {
+ expr: true
+ }
+ },
options: {
asi: true,
smarttabs: true
@@ -128,12 +135,6 @@
]
},
connect: {
- qunit: {
- options: {
- port: grunt.option('port-test') || 9002,
- base: './'
- }
- },
test: {
options: {
port: grunt.option('port-test') || 9002,
@@ -142,13 +143,6 @@
}
}
},
- qunit: {
- all: {
- options: {
- urls: ['http://localhost:' + (grunt.option('port-test') || 9002) + '/test/index.html']
- }
- }
- },
yuidoc: {
compile: {
name: '<%= pkg.name %>',
@@ -161,6 +155,13 @@
outdir: '<%= dirs.docs %>'
}
}
+ },
+ karma: {
+ unit: {
+ configFile: 'test/karma.conf.js',
+ // browsers: ['Chrome'],
+ singleRun: true
+ }
}
});
@@ -182,9 +183,10 @@
}
)
- grunt.registerTask('default', ['concat', 'uglify', 'distribute']);
grunt.registerTask('build', ['concat', 'uglify', 'distribute']);
- grunt.registerTask('test', ['build', 'connect:qunit', 'qunit']);
+ grunt.registerTask('test', ['concat', 'jshint:test', 'karma']);
grunt.registerTask('docs', ['yuidoc']);
-
-}
\ No newline at end of file
+ grunt.registerTask('default', ['test', 'uglify', 'distribute']);
+ // Travis CI task.
+ grunt.registerTask('travis', ['test']);
+}
diff --git a/README.md b/README.md
index c62ef86..690cfe4 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,8 @@

+[](http://travis-ci.org/drkibitz/pixi.js)
+
#### JavaScript 2D Renderer ####
The aim of this project is to provide a fast lightweight 2D library that works
diff --git a/package.json b/package.json
index b373240..1246a68 100644
--- a/package.json
+++ b/package.json
@@ -18,14 +18,21 @@
"main": "bin/pixi.js",
+ "scripts": {
+ "test": "grunt travis --verbose"
+ },
+
"dependencies": {},
"devDependencies": {
"grunt": "~0.4.x",
- "grunt-contrib-jshint": "0.3.x",
+ "grunt-contrib-jshint": "0.6.x",
"grunt-contrib-uglify": "0.2.x",
- "grunt-contrib-connect": "0.2.x",
- "grunt-contrib-qunit": "0.2.x",
+ "grunt-contrib-connect": "0.3.x",
"grunt-contrib-yuidoc": "0.4.x",
- "grunt-contrib-concat": "0.1.x"
+ "grunt-contrib-concat": "0.3.x",
+ "chai": "~1.7.0",
+ "karma": "0.11.0",
+ "karma-firefox-launcher": "0.1.0",
+ "karma-mocha": "0.1.0"
}
}
diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js
index a7c520e..ee82bbd 100644
--- a/src/pixi/InteractionManager.js
+++ b/src/pixi/InteractionManager.js
@@ -62,7 +62,6 @@
this.onTouchEnd = this.onTouchEnd.bind(this);
this.onTouchMove = this.onTouchMove.bind(this);
-
this.last = 0;
}
diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js
index 1a95d20..eef1059 100644
--- a/src/pixi/core/Ellipse.js
+++ b/src/pixi/core/Ellipse.js
@@ -78,7 +78,7 @@
return (normx + normy < 0.25);
}
-PIXI.Ellipse.getBounds = function()
+PIXI.Ellipse.prototype.getBounds = function()
{
return new PIXI.Rectangle(this.x, this.y, this.width, this.height);
}
diff --git a/tasks/karma.js b/tasks/karma.js
new file mode 100644
index 0000000..c340485
--- /dev/null
+++ b/tasks/karma.js
@@ -0,0 +1,27 @@
+'use strict';
+
+var path = require('path');
+var server = require('karma').server;
+
+module.exports = function (grunt) {
+ grunt.registerMultiTask('karma', 'run karma.', function() {
+ var done = this.async();
+ var options = this.options({
+ background: false
+ });
+ var data = this.data;
+
+ //merge options onto data, with data taking precedence
+ data = grunt.util._.merge(options, data);
+ data.configFile = path.resolve(data.configFile);
+ if (data.configFile) {
+ data.configFile = grunt.template.process(data.configFile);
+ }
+
+ server.start(
+ data,
+ function(code) {
+ done(!code);
+ });
+ });
+};
diff --git a/test/functional/example-1-basics/bunny.png b/test/functional/example-1-basics/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/functional/example-1-basics/bunny.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-30.png b/test/functional/example-1-basics/frame-30.png
new file mode 100644
index 0000000..96e3409
--- /dev/null
+++ b/test/functional/example-1-basics/frame-30.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-60.png b/test/functional/example-1-basics/frame-60.png
new file mode 100644
index 0000000..af3f4ce
--- /dev/null
+++ b/test/functional/example-1-basics/frame-60.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-90.png b/test/functional/example-1-basics/frame-90.png
new file mode 100644
index 0000000..099b823
--- /dev/null
+++ b/test/functional/example-1-basics/frame-90.png
Binary files differ
diff --git a/test/functional/example-1-basics/index.js b/test/functional/example-1-basics/index.js
new file mode 100644
index 0000000..7ae7a98
--- /dev/null
+++ b/test/functional/example-1-basics/index.js
@@ -0,0 +1,133 @@
+describe('Example 1 - Basics', function () {
+ 'use strict';
+
+ var baseUri = '/base/test/functional/example-1-basics';
+ var expect = chai.expect;
+ var currentFrame = 0;
+ var frameEvents = {};
+ var stage;
+ var renderer;
+ var bunny;
+
+ function onFrame(frame, callback) {
+ frameEvents[frame] = callback;
+ }
+
+ function animate() {
+ currentFrame += 1;
+
+ requestAnimFrame( animate );
+
+ // just for fun, lets rotate mr rabbit a little
+ bunny.rotation += 0.1;
+
+ // render the stage
+ renderer.render(stage);
+
+ if (frameEvents[currentFrame])
+ frameEvents[currentFrame](currentFrame);
+ }
+
+ function initScene() {
+ // create an new instance of a pixi stage
+ stage = new PIXI.Stage(0x66FF99);
+
+ // create a renderer instance
+ renderer = PIXI.autoDetectRenderer(400, 300);
+ console.log('Is PIXI.WebGLRenderer: ' + (renderer instanceof PIXI.WebGLRenderer));
+
+ // add the renderer view element to the DOM
+ document.body.appendChild(renderer.view);
+
+ requestAnimFrame( animate );
+
+ // create a texture from an image path
+ var texture = PIXI.Texture.fromImage(baseUri + "/bunny.png");
+ // create a new Sprite using the texture
+ bunny = new PIXI.Sprite(texture);
+
+ // center the sprites anchor point
+ bunny.anchor.x = 0.5;
+ bunny.anchor.y = 0.5;
+
+ // move the sprite t the center of the screen
+ bunny.position.x = 200;
+ bunny.position.y = 150;
+
+ stage.addChild(bunny);
+ }
+
+ it('assets loaded', function (done) {
+ var loader = new PIXI.AssetLoader([
+ baseUri + '/bunny.png',
+ baseUri + '/frame-30.png',
+ baseUri + '/frame-60.png',
+ baseUri + '/frame-90.png'
+ ]);
+ // loader.on('onProgress', function (event) {
+ // console.log(event.content);
+ // });
+ loader.on('onComplete', function (event) {
+ done();
+ initScene();
+ });
+ loader.load();
+ });
+
+ it('frame 30 should match', function (done) {
+ this.timeout(700);
+ onFrame(30, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-30.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 60 should match', function (done) {
+ this.timeout(1200);
+ onFrame(60, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-60.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 90 should match', function (done) {
+ this.timeout(1700);
+ onFrame(90, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-90.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ // it('capture something', function (done) {
+ // this.timeout(2000000);
+ // onFrame(30, function () {
+ // var img = new Image();
+ // img.src = renderer.view.toDataURL('image/png');
+ // document.body.appendChild(img);
+ // });
+ // });
+});
diff --git a/test/index.html b/test/index.html
deleted file mode 100644
index 9cbcac5..0000000
--- a/test/index.html
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
- Pixi.js Test Suite
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/test/karma.conf.js b/test/karma.conf.js
new file mode 100644
index 0000000..c66a696
--- /dev/null
+++ b/test/karma.conf.js
@@ -0,0 +1,82 @@
+module.exports = function(config) {
+ config.set({
+
+ // base path, that will be used to resolve files and exclude
+ basePath : '../',
+
+ frameworks : ['mocha'],
+
+ // list of files / patterns to load in the browser
+ files : [
+ 'node_modules/chai/chai.js',
+ 'bin/pixi.dev.js',
+ 'test/lib/**/*.js',
+ 'test/unit/**/*.js',
+ // 'test/functional/**/*.js',
+ {pattern: 'test/**/*.png', watched: false, included: false, served: true}
+ ],
+
+ // list of files to exclude
+ exclude : [],
+
+ // use dolts reporter, as travis terminal does not support escaping sequences
+ // possible values: 'dots', 'progress', 'junit', 'teamcity'
+ // CLI --reporters progress
+ reporters : ['progress'],
+
+ // web server port
+ // CLI --port 9876
+ port : 9876,
+
+ // cli runner port
+ // CLI --runner-port 9100
+ runnerPort : 9100,
+
+ // enable / disable colors in the output (reporters and logs)
+ // CLI --colors --no-colors
+ colors : true,
+
+ // level of logging
+ // possible values: karma.LOG_DISABLE || karma.LOG_ERROR || karma.LOG_WARN || karma.LOG_INFO || karma.LOG_DEBUG
+ // CLI --log-level debug
+ logLevel : config.LOG_DEBUG,
+
+ // enable / disable watching file and executing tests whenever any file changes
+ // CLI --auto-watch --no-auto-watch
+ autoWatch : false,
+
+ // Start these browsers, currently available:
+ // - Chrome
+ // - ChromeCanary
+ // - Firefox
+ // - Opera
+ // - Safari (only Mac)
+ // - PhantomJS
+ // - IE (only Windows)
+ // CLI --browsers Chrome,Firefox,Safari
+ browsers : ['Firefox'],
+
+ // If browser does not capture in given timeout [ms], kill it
+ // CLI --capture-timeout 5000
+ captureTimeout : 5000,
+
+ // Auto run tests on start (when browsers are captured) and exit
+ // CLI --single-run --no-single-run
+ singleRun : true,
+
+ // report which specs are slower than 500ms
+ // CLI --report-slower-than 500
+ reportSlowerThan : 1000,
+
+ preprocessors : {
+ // '**/client/js/*.js': 'coverage'
+ },
+
+ plugins : [
+ 'karma-mocha',
+ // 'karma-chrome-launcher',
+ 'karma-firefox-launcher',
+ // 'karma-phantomjs-launcher'
+ ]
+ });
+};
diff --git a/test/lib/pixi/core/Matrix.js b/test/lib/pixi/core/Matrix.js
new file mode 100644
index 0000000..d26386b
--- /dev/null
+++ b/test/lib/pixi/core/Matrix.js
@@ -0,0 +1,40 @@
+
+function pixi_core_Matrix_confirmNewMat3(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(1);
+ expect(matrix[5]).to.equal(0);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(1);
+}
+
+function pixi_core_Matrix_confirmNewMat4(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[0]).to.equal(1);
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(0);
+ expect(matrix[5]).to.equal(1);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(0);
+ expect(matrix[9]).to.equal(0);
+ expect(matrix[10]).to.equal(1);
+ expect(matrix[11]).to.equal(0);
+ expect(matrix[12]).to.equal(0);
+ expect(matrix[13]).to.equal(0);
+ expect(matrix[14]).to.equal(0);
+ expect(matrix[15]).to.equal(1);
+}
diff --git a/test/lib/pixi/core/Point.js b/test/lib/pixi/core/Point.js
new file mode 100644
index 0000000..e5df07b
--- /dev/null
+++ b/test/lib/pixi/core/Point.js
@@ -0,0 +1,10 @@
+
+function pixi_core_Point_confirm(obj, x, y) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Point);
+ expect(obj).to.respondTo('clone');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+}
diff --git a/test/lib/pixi/core/Rectangle.js b/test/lib/pixi/core/Rectangle.js
new file mode 100644
index 0000000..23f0d12
--- /dev/null
+++ b/test/lib/pixi/core/Rectangle.js
@@ -0,0 +1,13 @@
+
+function pixi_core_Rectangle_confirm(obj, x, y, width, height) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Rectangle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+ expect(obj).to.have.property('width', width);
+ expect(obj).to.have.property('height', height);
+}
diff --git a/test/lib/pixi/display/DisplayObject.js b/test/lib/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..1388a7f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObject.js
@@ -0,0 +1,43 @@
+
+function pixi_display_DisplayObject_confirmNew(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObject);
+ expect(obj).to.respondTo('setInteractive');
+ expect(obj).to.respondTo('addFilter');
+ expect(obj).to.respondTo('removeFilter');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.property('last', obj);
+ expect(obj).to.have.property('first', obj);
+
+ expect(obj).to.contain.property('position');
+ pixi_core_Point_confirm(obj.position, 0, 0);
+ expect(obj).to.contain.property('scale');
+ pixi_core_Point_confirm(obj.scale, 1, 1);
+ expect(obj).to.contain.property('pivot');
+ pixi_core_Point_confirm(obj.pivot, 0, 0);
+
+ expect(obj).to.have.property('rotation', 0);
+ expect(obj).to.have.property('alpha', 1);
+ expect(obj).to.have.property('visible', true);
+ expect(obj).to.have.property('buttonMode', false);
+ expect(obj).to.have.property('parent', null);
+ expect(obj).to.have.property('worldAlpha', 1);
+
+ expect(obj).to.have.property('hitArea');
+ expect(obj).to.have.property('interactive'); // TODO: Have a better default value
+ expect('mask' in obj).to.be.true; // TODO: Have a better default value
+ expect(obj.mask).to.be.undefined;
+
+ expect(obj).to.have.property('renderable');
+ expect(obj).to.have.property('stage');
+
+ expect(obj).to.have.deep.property('worldTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ expect(obj).to.have.deep.property('localTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.localTransform);
+
+ expect(obj).to.have.deep.property('color.length', 0);
+ expect(obj).to.have.property('dynamic', true);
+}
diff --git a/test/lib/pixi/display/DisplayObjectContainer.js b/test/lib/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..085c59f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,16 @@
+
+function pixi_display_DisplayObjectContainer_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObject_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObjectContainer);
+ expect(obj).to.respondTo('addChild');
+ expect(obj).to.respondTo('addChildAt');
+ expect(obj).to.respondTo('swapChildren');
+ expect(obj).to.respondTo('getChildAt');
+ expect(obj).to.respondTo('removeChild');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('children.length', 0);
+}
diff --git a/test/lib/pixi/display/Sprite.js b/test/lib/pixi/display/Sprite.js
new file mode 100644
index 0000000..cc7a2d6
--- /dev/null
+++ b/test/lib/pixi/display/Sprite.js
@@ -0,0 +1,28 @@
+
+function pixi_display_Sprite_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Sprite);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', true);
+ expect(obj).to.have.property('stage', null);
+
+ expect(obj).to.have.property('anchor');
+ pixi_core_Point_confirm(obj.anchor, 0, 0);
+
+ expect(obj).to.have.property('blendMode', PIXI.blendModes.NORMAL);
+ expect(obj).to.have.property('width', 1); // TODO: is 1 expected
+ expect(obj).to.have.property('height', 1); // TODO: is 1 expected
+
+ // FIXME: Just make this a boolean that is always there
+ expect(!!obj.updateFrame).to.equal(obj.texture.baseTexture.hasLoaded);
+
+ expect(obj).to.have.property('texture');
+ pixi_textures_Texture_confirmNew(obj.texture, done);
+}
diff --git a/test/lib/pixi/extras/Strip.js b/test/lib/pixi/extras/Strip.js
new file mode 100644
index 0000000..8927a8a
--- /dev/null
+++ b/test/lib/pixi/extras/Strip.js
@@ -0,0 +1,12 @@
+
+function pixi_extras_Strip_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Strip);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ // TODO: Test properties
+}
diff --git a/test/lib/pixi/textures/Texture.js b/test/lib/pixi/textures/Texture.js
new file mode 100644
index 0000000..d5867b6
--- /dev/null
+++ b/test/lib/pixi/textures/Texture.js
@@ -0,0 +1,31 @@
+
+function pixi_textures_Texture_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ function confirmFrameDone() {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, obj.baseTexture.width, obj.baseTexture.height);
+
+ expect(obj).to.have.property('width', obj.baseTexture.width);
+ expect(obj).to.have.property('height', obj.baseTexture.height);
+ done();
+ }
+
+ expect(obj).to.be.an.instanceof(PIXI.Texture);
+ pixi_utils_EventTarget_like(obj);
+
+ expect(obj).to.have.property('baseTexture')
+ .and.to.be.an.instanceof(PIXI.BaseTexture);
+
+ expect(obj).to.have.property('scope', obj);
+
+ expect(obj).to.have.property('trim');
+ pixi_core_Point_confirm(obj.trim, 0, 0);
+
+ expect(obj).to.have.property('frame');
+ if (obj.baseTexture.hasLoaded) {
+ confirmFrameDone();
+ } else {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, 1, 1);
+ obj.addEventListener('update', confirmFrameDone);
+ }
+}
diff --git a/test/lib/pixi/utils/EventTarget.js b/test/lib/pixi/utils/EventTarget.js
new file mode 100644
index 0000000..7b1dcfa
--- /dev/null
+++ b/test/lib/pixi/utils/EventTarget.js
@@ -0,0 +1,8 @@
+
+function pixi_utils_EventTarget_like(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.respondTo('addEventListener');
+ expect(obj).to.respondTo('dispatchEvent');
+ expect(obj).to.respondTo('removeEventListener');
+}
diff --git a/test/lib/qunit-1.11.0.css b/test/lib/qunit-1.11.0.css
deleted file mode 100644
index d7fc0c8..0000000
--- a/test/lib/qunit-1.11.0.css
+++ /dev/null
@@ -1,244 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-/** Font Family and Sizes */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
- font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
-}
-
-#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
-#qunit-tests { font-size: smaller; }
-
-
-/** Resets */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter {
- margin: 0;
- padding: 0;
-}
-
-
-/** Header */
-
-#qunit-header {
- padding: 0.5em 0 0.5em 1em;
-
- color: #8699a4;
- background-color: #0d3349;
-
- font-size: 1.5em;
- line-height: 1em;
- font-weight: normal;
-
- border-radius: 5px 5px 0 0;
- -moz-border-radius: 5px 5px 0 0;
- -webkit-border-top-right-radius: 5px;
- -webkit-border-top-left-radius: 5px;
-}
-
-#qunit-header a {
- text-decoration: none;
- color: #c2ccd1;
-}
-
-#qunit-header a:hover,
-#qunit-header a:focus {
- color: #fff;
-}
-
-#qunit-testrunner-toolbar label {
- display: inline-block;
- padding: 0 .5em 0 .1em;
-}
-
-#qunit-banner {
- height: 5px;
-}
-
-#qunit-testrunner-toolbar {
- padding: 0.5em 0 0.5em 2em;
- color: #5E740B;
- background-color: #eee;
- overflow: hidden;
-}
-
-#qunit-userAgent {
- padding: 0.5em 0 0.5em 2.5em;
- background-color: #2b81af;
- color: #fff;
- text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
-}
-
-#qunit-modulefilter-container {
- float: right;
-}
-
-/** Tests: Pass/Fail */
-
-#qunit-tests {
- list-style-position: inside;
-}
-
-#qunit-tests li {
- padding: 0.4em 0.5em 0.4em 2.5em;
- border-bottom: 1px solid #fff;
- list-style-position: inside;
-}
-
-#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running {
- display: none;
-}
-
-#qunit-tests li strong {
- cursor: pointer;
-}
-
-#qunit-tests li a {
- padding: 0.5em;
- color: #c2ccd1;
- text-decoration: none;
-}
-#qunit-tests li a:hover,
-#qunit-tests li a:focus {
- color: #000;
-}
-
-#qunit-tests li .runtime {
- float: right;
- font-size: smaller;
-}
-
-.qunit-assert-list {
- margin-top: 0.5em;
- padding: 0.5em;
-
- background-color: #fff;
-
- border-radius: 5px;
- -moz-border-radius: 5px;
- -webkit-border-radius: 5px;
-}
-
-.qunit-collapsed {
- display: none;
-}
-
-#qunit-tests table {
- border-collapse: collapse;
- margin-top: .2em;
-}
-
-#qunit-tests th {
- text-align: right;
- vertical-align: top;
- padding: 0 .5em 0 0;
-}
-
-#qunit-tests td {
- vertical-align: top;
-}
-
-#qunit-tests pre {
- margin: 0;
- white-space: pre-wrap;
- word-wrap: break-word;
-}
-
-#qunit-tests del {
- background-color: #e0f2be;
- color: #374e0c;
- text-decoration: none;
-}
-
-#qunit-tests ins {
- background-color: #ffcaca;
- color: #500;
- text-decoration: none;
-}
-
-/*** Test Counts */
-
-#qunit-tests b.counts { color: black; }
-#qunit-tests b.passed { color: #5E740B; }
-#qunit-tests b.failed { color: #710909; }
-
-#qunit-tests li li {
- padding: 5px;
- background-color: #fff;
- border-bottom: none;
- list-style-position: inside;
-}
-
-/*** Passing Styles */
-
-#qunit-tests li li.pass {
- color: #3c510c;
- background-color: #fff;
- border-left: 10px solid #C6E746;
-}
-
-#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
-#qunit-tests .pass .test-name { color: #366097; }
-
-#qunit-tests .pass .test-actual,
-#qunit-tests .pass .test-expected { color: #999999; }
-
-#qunit-banner.qunit-pass { background-color: #C6E746; }
-
-/*** Failing Styles */
-
-#qunit-tests li li.fail {
- color: #710909;
- background-color: #fff;
- border-left: 10px solid #EE5757;
- white-space: pre;
-}
-
-#qunit-tests > li:last-child {
- border-radius: 0 0 5px 5px;
- -moz-border-radius: 0 0 5px 5px;
- -webkit-border-bottom-right-radius: 5px;
- -webkit-border-bottom-left-radius: 5px;
-}
-
-#qunit-tests .fail { color: #000000; background-color: #EE5757; }
-#qunit-tests .fail .test-name,
-#qunit-tests .fail .module-name { color: #000000; }
-
-#qunit-tests .fail .test-actual { color: #EE5757; }
-#qunit-tests .fail .test-expected { color: green; }
-
-#qunit-banner.qunit-fail { background-color: #EE5757; }
-
-
-/** Result */
-
-#qunit-testresult {
- padding: 0.5em 0.5em 0.5em 2.5em;
-
- color: #2b81af;
- background-color: #D2E0E6;
-
- border-bottom: 1px solid white;
-}
-#qunit-testresult .module-name {
- font-weight: bold;
-}
-
-/** Fixture */
-
-#qunit-fixture {
- position: absolute;
- top: -10000px;
- left: -10000px;
- width: 1000px;
- height: 1000px;
-}
diff --git a/test/lib/qunit-1.11.0.js b/test/lib/qunit-1.11.0.js
deleted file mode 100644
index 302545f..0000000
--- a/test/lib/qunit-1.11.0.js
+++ /dev/null
@@ -1,2152 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-(function( window ) {
-
-var QUnit,
- assert,
- config,
- onErrorFnPrev,
- testId = 0,
- fileName = (sourceFromStacktrace( 0 ) || "" ).replace(/(:\d+)+\)?/, "").replace(/.+\//, ""),
- toString = Object.prototype.toString,
- hasOwn = Object.prototype.hasOwnProperty,
- // Keep a local reference to Date (GH-283)
- Date = window.Date,
- defined = {
- setTimeout: typeof window.setTimeout !== "undefined",
- sessionStorage: (function() {
- var x = "qunit-test-string";
- try {
- sessionStorage.setItem( x, x );
- sessionStorage.removeItem( x );
- return true;
- } catch( e ) {
- return false;
- }
- }())
- },
- /**
- * Provides a normalized error string, correcting an issue
- * with IE 7 (and prior) where Error.prototype.toString is
- * not properly implemented
- *
- * Based on http://es5.github.com/#x15.11.4.4
- *
- * @param {String|Error} error
- * @return {String} error message
- */
- errorString = function( error ) {
- var name, message,
- errorString = error.toString();
- if ( errorString.substring( 0, 7 ) === "[object" ) {
- name = error.name ? error.name.toString() : "Error";
- message = error.message ? error.message.toString() : "";
- if ( name && message ) {
- return name + ": " + message;
- } else if ( name ) {
- return name;
- } else if ( message ) {
- return message;
- } else {
- return "Error";
- }
- } else {
- return errorString;
- }
- },
- /**
- * Makes a clone of an object using only Array or Object as base,
- * and copies over the own enumerable properties.
- *
- * @param {Object} obj
- * @return {Object} New object with only the own properties (recursively).
- */
- objectValues = function( obj ) {
- // Grunt 0.3.x uses an older version of jshint that still has jshint/jshint#392.
- /*jshint newcap: false */
- var key, val,
- vals = QUnit.is( "array", obj ) ? [] : {};
- for ( key in obj ) {
- if ( hasOwn.call( obj, key ) ) {
- val = obj[key];
- vals[key] = val === Object(val) ? objectValues(val) : val;
- }
- }
- return vals;
- };
-
-function Test( settings ) {
- extend( this, settings );
- this.assertions = [];
- this.testNumber = ++Test.count;
-}
-
-Test.count = 0;
-
-Test.prototype = {
- init: function() {
- var a, b, li,
- tests = id( "qunit-tests" );
-
- if ( tests ) {
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml;
-
- // `a` initialized at top of scope
- a = document.createElement( "a" );
- a.innerHTML = "Rerun";
- a.href = QUnit.url({ testNumber: this.testNumber });
-
- li = document.createElement( "li" );
- li.appendChild( b );
- li.appendChild( a );
- li.className = "running";
- li.id = this.id = "qunit-test-output" + testId++;
-
- tests.appendChild( li );
- }
- },
- setup: function() {
- if ( this.module !== config.previousModule ) {
- if ( config.previousModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.previousModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
- config.previousModule = this.module;
- config.moduleStats = { all: 0, bad: 0 };
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- } else if ( config.autorun ) {
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- }
-
- config.current = this;
-
- this.testEnvironment = extend({
- setup: function() {},
- teardown: function() {}
- }, this.moduleTestEnvironment );
-
- this.started = +new Date();
- runLoggingCallbacks( "testStart", QUnit, {
- name: this.testName,
- module: this.module
- });
-
- // allow utility functions to access the current test environment
- // TODO why??
- QUnit.current_testEnvironment = this.testEnvironment;
-
- if ( !config.pollution ) {
- saveGlobal();
- }
- if ( config.notrycatch ) {
- this.testEnvironment.setup.call( this.testEnvironment );
- return;
- }
- try {
- this.testEnvironment.setup.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Setup failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- },
- run: function() {
- config.current = this;
-
- var running = id( "qunit-testresult" );
-
- if ( running ) {
- running.innerHTML = "Running:
" + this.nameHtml;
- }
-
- if ( this.async ) {
- QUnit.stop();
- }
-
- this.callbackStarted = +new Date();
-
- if ( config.notrycatch ) {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- return;
- }
-
- try {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- } catch( e ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
-
- QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + " " + this.stack + ": " + ( e.message || e ), extractStacktrace( e, 0 ) );
- // else next test will carry the responsibility
- saveGlobal();
-
- // Restart the tests if they're blocking
- if ( config.blocking ) {
- QUnit.start();
- }
- }
- },
- teardown: function() {
- config.current = this;
- if ( config.notrycatch ) {
- if ( typeof this.callbackRuntime === "undefined" ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
- }
- this.testEnvironment.teardown.call( this.testEnvironment );
- return;
- } else {
- try {
- this.testEnvironment.teardown.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Teardown failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- }
- checkPollution();
- },
- finish: function() {
- config.current = this;
- if ( config.requireExpects && this.expected === null ) {
- QUnit.pushFailure( "Expected number of assertions to be defined, but expect() was not called.", this.stack );
- } else if ( this.expected !== null && this.expected !== this.assertions.length ) {
- QUnit.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack );
- } else if ( this.expected === null && !this.assertions.length ) {
- QUnit.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions.", this.stack );
- }
-
- var i, assertion, a, b, time, li, ol,
- test = this,
- good = 0,
- bad = 0,
- tests = id( "qunit-tests" );
-
- this.runtime = +new Date() - this.started;
- config.stats.all += this.assertions.length;
- config.moduleStats.all += this.assertions.length;
-
- if ( tests ) {
- ol = document.createElement( "ol" );
- ol.className = "qunit-assert-list";
-
- for ( i = 0; i < this.assertions.length; i++ ) {
- assertion = this.assertions[i];
-
- li = document.createElement( "li" );
- li.className = assertion.result ? "pass" : "fail";
- li.innerHTML = assertion.message || ( assertion.result ? "okay" : "failed" );
- ol.appendChild( li );
-
- if ( assertion.result ) {
- good++;
- } else {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
-
- // store result when possible
- if ( QUnit.config.reorder && defined.sessionStorage ) {
- if ( bad ) {
- sessionStorage.setItem( "qunit-test-" + this.module + "-" + this.testName, bad );
- } else {
- sessionStorage.removeItem( "qunit-test-" + this.module + "-" + this.testName );
- }
- }
-
- if ( bad === 0 ) {
- addClass( ol, "qunit-collapsed" );
- }
-
- // `b` initialized at top of scope
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml + " (" + bad + ", " + good + ", " + this.assertions.length + ")";
-
- addEvent(b, "click", function() {
- var next = b.parentNode.lastChild,
- collapsed = hasClass( next, "qunit-collapsed" );
- ( collapsed ? removeClass : addClass )( next, "qunit-collapsed" );
- });
-
- addEvent(b, "dblclick", function( e ) {
- var target = e && e.target ? e.target : window.event.srcElement;
- if ( target.nodeName.toLowerCase() === "span" || target.nodeName.toLowerCase() === "b" ) {
- target = target.parentNode;
- }
- if ( window.location && target.nodeName.toLowerCase() === "strong" ) {
- window.location = QUnit.url({ testNumber: test.testNumber });
- }
- });
-
- // `time` initialized at top of scope
- time = document.createElement( "span" );
- time.className = "runtime";
- time.innerHTML = this.runtime + " ms";
-
- // `li` initialized at top of scope
- li = id( this.id );
- li.className = bad ? "fail" : "pass";
- li.removeChild( li.firstChild );
- a = li.firstChild;
- li.appendChild( b );
- li.appendChild( a );
- li.appendChild( time );
- li.appendChild( ol );
-
- } else {
- for ( i = 0; i < this.assertions.length; i++ ) {
- if ( !this.assertions[i].result ) {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
- }
-
- runLoggingCallbacks( "testDone", QUnit, {
- name: this.testName,
- module: this.module,
- failed: bad,
- passed: this.assertions.length - bad,
- total: this.assertions.length,
- duration: this.runtime
- });
-
- QUnit.reset();
-
- config.current = undefined;
- },
-
- queue: function() {
- var bad,
- test = this;
-
- synchronize(function() {
- test.init();
- });
- function run() {
- // each of these can by async
- synchronize(function() {
- test.setup();
- });
- synchronize(function() {
- test.run();
- });
- synchronize(function() {
- test.teardown();
- });
- synchronize(function() {
- test.finish();
- });
- }
-
- // `bad` initialized at top of scope
- // defer when previous test run passed, if storage is available
- bad = QUnit.config.reorder && defined.sessionStorage &&
- +sessionStorage.getItem( "qunit-test-" + this.module + "-" + this.testName );
-
- if ( bad ) {
- run();
- } else {
- synchronize( run, true );
- }
- }
-};
-
-// Root QUnit object.
-// `QUnit` initialized at top of scope
-QUnit = {
-
- // call on start of module test to prepend name to all tests
- module: function( name, testEnvironment ) {
- config.currentModule = name;
- config.currentModuleTestEnvironment = testEnvironment;
- config.modules[name] = true;
- },
-
- asyncTest: function( testName, expected, callback ) {
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- QUnit.test( testName, expected, callback, true );
- },
-
- test: function( testName, expected, callback, async ) {
- var test,
- nameHtml = "" + escapeText( testName ) + "";
-
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- if ( config.currentModule ) {
- nameHtml = "" + escapeText( config.currentModule ) + ": " + nameHtml;
- }
-
- test = new Test({
- nameHtml: nameHtml,
- testName: testName,
- expected: expected,
- async: async,
- callback: callback,
- module: config.currentModule,
- moduleTestEnvironment: config.currentModuleTestEnvironment,
- stack: sourceFromStacktrace( 2 )
- });
-
- if ( !validTest( test ) ) {
- return;
- }
-
- test.queue();
- },
-
- // Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through.
- expect: function( asserts ) {
- if (arguments.length === 1) {
- config.current.expected = asserts;
- } else {
- return config.current.expected;
- }
- },
-
- start: function( count ) {
- // QUnit hasn't been initialized yet.
- // Note: RequireJS (et al) may delay onLoad
- if ( config.semaphore === undefined ) {
- QUnit.begin(function() {
- // This is triggered at the top of QUnit.load, push start() to the event loop, to allow QUnit.load to finish first
- setTimeout(function() {
- QUnit.start( count );
- });
- });
- return;
- }
-
- config.semaphore -= count || 1;
- // don't start until equal number of stop-calls
- if ( config.semaphore > 0 ) {
- return;
- }
- // ignore if start is called more often then stop
- if ( config.semaphore < 0 ) {
- config.semaphore = 0;
- QUnit.pushFailure( "Called start() while already started (QUnit.config.semaphore was 0 already)", null, sourceFromStacktrace(2) );
- return;
- }
- // A slight delay, to avoid any current callbacks
- if ( defined.setTimeout ) {
- window.setTimeout(function() {
- if ( config.semaphore > 0 ) {
- return;
- }
- if ( config.timeout ) {
- clearTimeout( config.timeout );
- }
-
- config.blocking = false;
- process( true );
- }, 13);
- } else {
- config.blocking = false;
- process( true );
- }
- },
-
- stop: function( count ) {
- config.semaphore += count || 1;
- config.blocking = true;
-
- if ( config.testTimeout && defined.setTimeout ) {
- clearTimeout( config.timeout );
- config.timeout = window.setTimeout(function() {
- QUnit.ok( false, "Test timed out" );
- config.semaphore = 1;
- QUnit.start();
- }, config.testTimeout );
- }
- }
-};
-
-// `assert` initialized at top of scope
-// Asssert helpers
-// All of these must either call QUnit.push() or manually do:
-// - runLoggingCallbacks( "log", .. );
-// - config.current.assertions.push({ .. });
-// We attach it to the QUnit object *after* we expose the public API,
-// otherwise `assert` will become a global variable in browsers (#341).
-assert = {
- /**
- * Asserts rough true-ish result.
- * @name ok
- * @function
- * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" );
- */
- ok: function( result, msg ) {
- if ( !config.current ) {
- throw new Error( "ok() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
- result = !!result;
-
- var source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: msg
- };
-
- msg = escapeText( msg || (result ? "okay" : "failed" ) );
- msg = "" + msg + "";
-
- if ( !result ) {
- source = sourceFromStacktrace( 2 );
- if ( source ) {
- details.source = source;
- msg += "Source: | " + escapeText( source ) + " |
---|
";
- }
- }
- runLoggingCallbacks( "log", QUnit, details );
- config.current.assertions.push({
- result: result,
- message: msg
- });
- },
-
- /**
- * Assert that the first two arguments are equal, with an optional message.
- * Prints out both actual and expected values.
- * @name equal
- * @function
- * @example equal( format( "Received {0} bytes.", 2), "Received 2 bytes.", "format() replaces {0} with next argument" );
- */
- equal: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected == actual, actual, expected, message );
- },
-
- /**
- * @name notEqual
- * @function
- */
- notEqual: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected != actual, actual, expected, message );
- },
-
- /**
- * @name propEqual
- * @function
- */
- propEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notPropEqual
- * @function
- */
- notPropEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name deepEqual
- * @function
- */
- deepEqual: function( actual, expected, message ) {
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notDeepEqual
- * @function
- */
- notDeepEqual: function( actual, expected, message ) {
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name strictEqual
- * @function
- */
- strictEqual: function( actual, expected, message ) {
- QUnit.push( expected === actual, actual, expected, message );
- },
-
- /**
- * @name notStrictEqual
- * @function
- */
- notStrictEqual: function( actual, expected, message ) {
- QUnit.push( expected !== actual, actual, expected, message );
- },
-
- "throws": function( block, expected, message ) {
- var actual,
- expectedOutput = expected,
- ok = false;
-
- // 'expected' is optional
- if ( typeof expected === "string" ) {
- message = expected;
- expected = null;
- }
-
- config.current.ignoreGlobalErrors = true;
- try {
- block.call( config.current.testEnvironment );
- } catch (e) {
- actual = e;
- }
- config.current.ignoreGlobalErrors = false;
-
- if ( actual ) {
- // we don't want to validate thrown error
- if ( !expected ) {
- ok = true;
- expectedOutput = null;
- // expected is a regexp
- } else if ( QUnit.objectType( expected ) === "regexp" ) {
- ok = expected.test( errorString( actual ) );
- // expected is a constructor
- } else if ( actual instanceof expected ) {
- ok = true;
- // expected is a validation function which returns true is validation passed
- } else if ( expected.call( {}, actual ) === true ) {
- expectedOutput = null;
- ok = true;
- }
-
- QUnit.push( ok, actual, expectedOutput, message );
- } else {
- QUnit.pushFailure( message, null, 'No exception was thrown.' );
- }
- }
-};
-
-/**
- * @deprecate since 1.8.0
- * Kept assertion helpers in root for backwards compatibility.
- */
-extend( QUnit, assert );
-
-/**
- * @deprecated since 1.9.0
- * Kept root "raises()" for backwards compatibility.
- * (Note that we don't introduce assert.raises).
- */
-QUnit.raises = assert[ "throws" ];
-
-/**
- * @deprecated since 1.0.0, replaced with error pushes since 1.3.0
- * Kept to avoid TypeErrors for undefined methods.
- */
-QUnit.equals = function() {
- QUnit.push( false, false, false, "QUnit.equals has been deprecated since 2009 (e88049a0), use QUnit.equal instead" );
-};
-QUnit.same = function() {
- QUnit.push( false, false, false, "QUnit.same has been deprecated since 2009 (e88049a0), use QUnit.deepEqual instead" );
-};
-
-// We want access to the constructor's prototype
-(function() {
- function F() {}
- F.prototype = QUnit;
- QUnit = new F();
- // Make F QUnit's constructor so that we can add to the prototype later
- QUnit.constructor = F;
-}());
-
-/**
- * Config object: Maintain internal state
- * Later exposed as QUnit.config
- * `config` initialized at top of scope
- */
-config = {
- // The queue of tests to run
- queue: [],
-
- // block until document ready
- blocking: true,
-
- // when enabled, show only failing tests
- // gets persisted through sessionStorage and can be changed in UI via checkbox
- hidepassed: false,
-
- // by default, run previously failed tests first
- // very useful in combination with "Hide passed tests" checked
- reorder: true,
-
- // by default, modify document.title when suite is done
- altertitle: true,
-
- // when enabled, all tests must call expect()
- requireExpects: false,
-
- // add checkboxes that are persisted in the query-string
- // when enabled, the id is set to `true` as a `QUnit.config` property
- urlConfig: [
- {
- id: "noglobals",
- label: "Check for Globals",
- tooltip: "Enabling this will test if any test introduces new properties on the `window` object. Stored as query-strings."
- },
- {
- id: "notrycatch",
- label: "No try-catch",
- tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging exceptions in IE reasonable. Stored as query-strings."
- }
- ],
-
- // Set of all modules.
- modules: {},
-
- // logging callback queues
- begin: [],
- done: [],
- log: [],
- testStart: [],
- testDone: [],
- moduleStart: [],
- moduleDone: []
-};
-
-// Export global variables, unless an 'exports' object exists,
-// in that case we assume we're in CommonJS (dealt with on the bottom of the script)
-if ( typeof exports === "undefined" ) {
- extend( window, QUnit );
-
- // Expose QUnit object
- window.QUnit = QUnit;
-}
-
-// Initialize more QUnit.config and QUnit.urlParams
-(function() {
- var i,
- location = window.location || { search: "", protocol: "file:" },
- params = location.search.slice( 1 ).split( "&" ),
- length = params.length,
- urlParams = {},
- current;
-
- if ( params[ 0 ] ) {
- for ( i = 0; i < length; i++ ) {
- current = params[ i ].split( "=" );
- current[ 0 ] = decodeURIComponent( current[ 0 ] );
- // allow just a key to turn on a flag, e.g., test.html?noglobals
- current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true;
- urlParams[ current[ 0 ] ] = current[ 1 ];
- }
- }
-
- QUnit.urlParams = urlParams;
-
- // String search anywhere in moduleName+testName
- config.filter = urlParams.filter;
-
- // Exact match of the module name
- config.module = urlParams.module;
-
- config.testNumber = parseInt( urlParams.testNumber, 10 ) || null;
-
- // Figure out if we're running the tests from a server or not
- QUnit.isLocal = location.protocol === "file:";
-}());
-
-// Extend QUnit object,
-// these after set here because they should not be exposed as global functions
-extend( QUnit, {
- assert: assert,
-
- config: config,
-
- // Initialize the configuration options
- init: function() {
- extend( config, {
- stats: { all: 0, bad: 0 },
- moduleStats: { all: 0, bad: 0 },
- started: +new Date(),
- updateRate: 1000,
- blocking: false,
- autostart: true,
- autorun: false,
- filter: "",
- queue: [],
- semaphore: 1
- });
-
- var tests, banner, result,
- qunit = id( "qunit" );
-
- if ( qunit ) {
- qunit.innerHTML =
- "" +
- "" +
- "" +
- "" +
- "
";
- }
-
- tests = id( "qunit-tests" );
- banner = id( "qunit-banner" );
- result = id( "qunit-testresult" );
-
- if ( tests ) {
- tests.innerHTML = "";
- }
-
- if ( banner ) {
- banner.className = "";
- }
-
- if ( result ) {
- result.parentNode.removeChild( result );
- }
-
- if ( tests ) {
- result = document.createElement( "p" );
- result.id = "qunit-testresult";
- result.className = "result";
- tests.parentNode.insertBefore( result, tests );
- result.innerHTML = "Running...
";
- }
- },
-
- // Resets the test setup. Useful for tests that modify the DOM.
- reset: function() {
- var fixture = id( "qunit-fixture" );
- if ( fixture ) {
- fixture.innerHTML = config.fixture;
- }
- },
-
- // Trigger an event on an element.
- // @example triggerEvent( document.body, "click" );
- triggerEvent: function( elem, type, event ) {
- if ( document.createEvent ) {
- event = document.createEvent( "MouseEvents" );
- event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView,
- 0, 0, 0, 0, 0, false, false, false, false, 0, null);
-
- elem.dispatchEvent( event );
- } else if ( elem.fireEvent ) {
- elem.fireEvent( "on" + type );
- }
- },
-
- // Safe object type checking
- is: function( type, obj ) {
- return QUnit.objectType( obj ) === type;
- },
-
- objectType: function( obj ) {
- if ( typeof obj === "undefined" ) {
- return "undefined";
- // consider: typeof null === object
- }
- if ( obj === null ) {
- return "null";
- }
-
- var match = toString.call( obj ).match(/^\[object\s(.*)\]$/),
- type = match && match[1] || "";
-
- switch ( type ) {
- case "Number":
- if ( isNaN(obj) ) {
- return "nan";
- }
- return "number";
- case "String":
- case "Boolean":
- case "Array":
- case "Date":
- case "RegExp":
- case "Function":
- return type.toLowerCase();
- }
- if ( typeof obj === "object" ) {
- return "object";
- }
- return undefined;
- },
-
- push: function( result, actual, expected, message ) {
- if ( !config.current ) {
- throw new Error( "assertion outside test context, was " + sourceFromStacktrace() );
- }
-
- var output, source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: message,
- actual: actual,
- expected: expected
- };
-
- message = escapeText( message ) || ( result ? "okay" : "failed" );
- message = "" + message + "";
- output = message;
-
- if ( !result ) {
- expected = escapeText( QUnit.jsDump.parse(expected) );
- actual = escapeText( QUnit.jsDump.parse(actual) );
- output += "Expected: | " + expected + " |
";
-
- if ( actual !== expected ) {
- output += "Result: | " + actual + " |
";
- output += "Diff: | " + QUnit.diff( expected, actual ) + " |
";
- }
-
- source = sourceFromStacktrace();
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
- }
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: !!result,
- message: output
- });
- },
-
- pushFailure: function( message, source, actual ) {
- if ( !config.current ) {
- throw new Error( "pushFailure() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
-
- var output,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: false,
- message: message
- };
-
- message = escapeText( message ) || "error";
- message = "" + message + "";
- output = message;
-
- output += "";
-
- if ( actual ) {
- output += "Result: | " + escapeText( actual ) + " |
";
- }
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: false,
- message: output
- });
- },
-
- url: function( params ) {
- params = extend( extend( {}, QUnit.urlParams ), params );
- var key,
- querystring = "?";
-
- for ( key in params ) {
- if ( !hasOwn.call( params, key ) ) {
- continue;
- }
- querystring += encodeURIComponent( key ) + "=" +
- encodeURIComponent( params[ key ] ) + "&";
- }
- return window.location.protocol + "//" + window.location.host +
- window.location.pathname + querystring.slice( 0, -1 );
- },
-
- extend: extend,
- id: id,
- addEvent: addEvent
- // load, equiv, jsDump, diff: Attached later
-});
-
-/**
- * @deprecated: Created for backwards compatibility with test runner that set the hook function
- * into QUnit.{hook}, instead of invoking it and passing the hook function.
- * QUnit.constructor is set to the empty F() above so that we can add to it's prototype here.
- * Doing this allows us to tell if the following methods have been overwritten on the actual
- * QUnit object.
- */
-extend( QUnit.constructor.prototype, {
-
- // Logging callbacks; all receive a single argument with the listed properties
- // run test/logs.html for any related changes
- begin: registerLoggingCallback( "begin" ),
-
- // done: { failed, passed, total, runtime }
- done: registerLoggingCallback( "done" ),
-
- // log: { result, actual, expected, message }
- log: registerLoggingCallback( "log" ),
-
- // testStart: { name }
- testStart: registerLoggingCallback( "testStart" ),
-
- // testDone: { name, failed, passed, total, duration }
- testDone: registerLoggingCallback( "testDone" ),
-
- // moduleStart: { name }
- moduleStart: registerLoggingCallback( "moduleStart" ),
-
- // moduleDone: { name, failed, passed, total }
- moduleDone: registerLoggingCallback( "moduleDone" )
-});
-
-if ( typeof document === "undefined" || document.readyState === "complete" ) {
- config.autorun = true;
-}
-
-QUnit.load = function() {
- runLoggingCallbacks( "begin", QUnit, {} );
-
- // Initialize the config, saving the execution queue
- var banner, filter, i, label, len, main, ol, toolbar, userAgent, val,
- urlConfigCheckboxesContainer, urlConfigCheckboxes, moduleFilter,
- numModules = 0,
- moduleFilterHtml = "",
- urlConfigHtml = "",
- oldconfig = extend( {}, config );
-
- QUnit.init();
- extend(config, oldconfig);
-
- config.blocking = false;
-
- len = config.urlConfig.length;
-
- for ( i = 0; i < len; i++ ) {
- val = config.urlConfig[i];
- if ( typeof val === "string" ) {
- val = {
- id: val,
- label: val,
- tooltip: "[no tooltip available]"
- };
- }
- config[ val.id ] = QUnit.urlParams[ val.id ];
- urlConfigHtml += "";
- }
-
- moduleFilterHtml += "";
-
- // `userAgent` initialized at top of scope
- userAgent = id( "qunit-userAgent" );
- if ( userAgent ) {
- userAgent.innerHTML = navigator.userAgent;
- }
-
- // `banner` initialized at top of scope
- banner = id( "qunit-header" );
- if ( banner ) {
- banner.innerHTML = "" + banner.innerHTML + " ";
- }
-
- // `toolbar` initialized at top of scope
- toolbar = id( "qunit-testrunner-toolbar" );
- if ( toolbar ) {
- // `filter` initialized at top of scope
- filter = document.createElement( "input" );
- filter.type = "checkbox";
- filter.id = "qunit-filter-pass";
-
- addEvent( filter, "click", function() {
- var tmp,
- ol = document.getElementById( "qunit-tests" );
-
- if ( filter.checked ) {
- ol.className = ol.className + " hidepass";
- } else {
- tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " ";
- ol.className = tmp.replace( / hidepass /, " " );
- }
- if ( defined.sessionStorage ) {
- if (filter.checked) {
- sessionStorage.setItem( "qunit-filter-passed-tests", "true" );
- } else {
- sessionStorage.removeItem( "qunit-filter-passed-tests" );
- }
- }
- });
-
- if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem( "qunit-filter-passed-tests" ) ) {
- filter.checked = true;
- // `ol` initialized at top of scope
- ol = document.getElementById( "qunit-tests" );
- ol.className = ol.className + " hidepass";
- }
- toolbar.appendChild( filter );
-
- // `label` initialized at top of scope
- label = document.createElement( "label" );
- label.setAttribute( "for", "qunit-filter-pass" );
- label.setAttribute( "title", "Only show tests and assertons that fail. Stored in sessionStorage." );
- label.innerHTML = "Hide passed tests";
- toolbar.appendChild( label );
-
- urlConfigCheckboxesContainer = document.createElement("span");
- urlConfigCheckboxesContainer.innerHTML = urlConfigHtml;
- urlConfigCheckboxes = urlConfigCheckboxesContainer.getElementsByTagName("input");
- // For oldIE support:
- // * Add handlers to the individual elements instead of the container
- // * Use "click" instead of "change"
- // * Fallback from event.target to event.srcElement
- addEvents( urlConfigCheckboxes, "click", function( event ) {
- var params = {},
- target = event.target || event.srcElement;
- params[ target.name ] = target.checked ? true : undefined;
- window.location = QUnit.url( params );
- });
- toolbar.appendChild( urlConfigCheckboxesContainer );
-
- if (numModules > 1) {
- moduleFilter = document.createElement( 'span' );
- moduleFilter.setAttribute( 'id', 'qunit-modulefilter-container' );
- moduleFilter.innerHTML = moduleFilterHtml;
- addEvent( moduleFilter.lastChild, "change", function() {
- var selectBox = moduleFilter.getElementsByTagName("select")[0],
- selectedModule = decodeURIComponent(selectBox.options[selectBox.selectedIndex].value);
-
- window.location = QUnit.url( { module: ( selectedModule === "" ) ? undefined : selectedModule } );
- });
- toolbar.appendChild(moduleFilter);
- }
- }
-
- // `main` initialized at top of scope
- main = id( "qunit-fixture" );
- if ( main ) {
- config.fixture = main.innerHTML;
- }
-
- if ( config.autostart ) {
- QUnit.start();
- }
-};
-
-addEvent( window, "load", QUnit.load );
-
-// `onErrorFnPrev` initialized at top of scope
-// Preserve other handlers
-onErrorFnPrev = window.onerror;
-
-// Cover uncaught exceptions
-// Returning true will surpress the default browser handler,
-// returning false will let it run.
-window.onerror = function ( error, filePath, linerNr ) {
- var ret = false;
- if ( onErrorFnPrev ) {
- ret = onErrorFnPrev( error, filePath, linerNr );
- }
-
- // Treat return value as window.onerror itself does,
- // Only do our handling if not surpressed.
- if ( ret !== true ) {
- if ( QUnit.config.current ) {
- if ( QUnit.config.current.ignoreGlobalErrors ) {
- return true;
- }
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- } else {
- QUnit.test( "global failure", extend( function() {
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- }, { validTest: validTest } ) );
- }
- return false;
- }
-
- return ret;
-};
-
-function done() {
- config.autorun = true;
-
- // Log the last module results
- if ( config.currentModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.currentModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
-
- var i, key,
- banner = id( "qunit-banner" ),
- tests = id( "qunit-tests" ),
- runtime = +new Date() - config.started,
- passed = config.stats.all - config.stats.bad,
- html = [
- "Tests completed in ",
- runtime,
- " milliseconds.
",
- "",
- passed,
- " assertions of ",
- config.stats.all,
- " passed, ",
- config.stats.bad,
- " failed."
- ].join( "" );
-
- if ( banner ) {
- banner.className = ( config.stats.bad ? "qunit-fail" : "qunit-pass" );
- }
-
- if ( tests ) {
- id( "qunit-testresult" ).innerHTML = html;
- }
-
- if ( config.altertitle && typeof document !== "undefined" && document.title ) {
- // show ✖ for good, ✔ for bad suite result in title
- // use escape sequences in case file gets loaded with non-utf-8-charset
- document.title = [
- ( config.stats.bad ? "\u2716" : "\u2714" ),
- document.title.replace( /^[\u2714\u2716] /i, "" )
- ].join( " " );
- }
-
- // clear own sessionStorage items if all tests passed
- if ( config.reorder && defined.sessionStorage && config.stats.bad === 0 ) {
- // `key` & `i` initialized at top of scope
- for ( i = 0; i < sessionStorage.length; i++ ) {
- key = sessionStorage.key( i++ );
- if ( key.indexOf( "qunit-test-" ) === 0 ) {
- sessionStorage.removeItem( key );
- }
- }
- }
-
- // scroll back to top to show results
- if ( window.scrollTo ) {
- window.scrollTo(0, 0);
- }
-
- runLoggingCallbacks( "done", QUnit, {
- failed: config.stats.bad,
- passed: passed,
- total: config.stats.all,
- runtime: runtime
- });
-}
-
-/** @return Boolean: true if this test should be ran */
-function validTest( test ) {
- var include,
- filter = config.filter && config.filter.toLowerCase(),
- module = config.module && config.module.toLowerCase(),
- fullName = (test.module + ": " + test.testName).toLowerCase();
-
- // Internally-generated tests are always valid
- if ( test.callback && test.callback.validTest === validTest ) {
- delete test.callback.validTest;
- return true;
- }
-
- if ( config.testNumber ) {
- return test.testNumber === config.testNumber;
- }
-
- if ( module && ( !test.module || test.module.toLowerCase() !== module ) ) {
- return false;
- }
-
- if ( !filter ) {
- return true;
- }
-
- include = filter.charAt( 0 ) !== "!";
- if ( !include ) {
- filter = filter.slice( 1 );
- }
-
- // If the filter matches, we need to honour include
- if ( fullName.indexOf( filter ) !== -1 ) {
- return include;
- }
-
- // Otherwise, do the opposite
- return !include;
-}
-
-// so far supports only Firefox, Chrome and Opera (buggy), Safari (for real exceptions)
-// Later Safari and IE10 are supposed to support error.stack as well
-// See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack
-function extractStacktrace( e, offset ) {
- offset = offset === undefined ? 3 : offset;
-
- var stack, include, i;
-
- if ( e.stacktrace ) {
- // Opera
- return e.stacktrace.split( "\n" )[ offset + 3 ];
- } else if ( e.stack ) {
- // Firefox, Chrome
- stack = e.stack.split( "\n" );
- if (/^error$/i.test( stack[0] ) ) {
- stack.shift();
- }
- if ( fileName ) {
- include = [];
- for ( i = offset; i < stack.length; i++ ) {
- if ( stack[ i ].indexOf( fileName ) !== -1 ) {
- break;
- }
- include.push( stack[ i ] );
- }
- if ( include.length ) {
- return include.join( "\n" );
- }
- }
- return stack[ offset ];
- } else if ( e.sourceURL ) {
- // Safari, PhantomJS
- // hopefully one day Safari provides actual stacktraces
- // exclude useless self-reference for generated Error objects
- if ( /qunit.js$/.test( e.sourceURL ) ) {
- return;
- }
- // for actual exceptions, this is useful
- return e.sourceURL + ":" + e.line;
- }
-}
-function sourceFromStacktrace( offset ) {
- try {
- throw new Error();
- } catch ( e ) {
- return extractStacktrace( e, offset );
- }
-}
-
-/**
- * Escape text for attribute or text content.
- */
-function escapeText( s ) {
- if ( !s ) {
- return "";
- }
- s = s + "";
- // Both single quotes and double quotes (for attributes)
- return s.replace( /['"<>&]/g, function( s ) {
- switch( s ) {
- case '\'':
- return ''';
- case '"':
- return '"';
- case '<':
- return '<';
- case '>':
- return '>';
- case '&':
- return '&';
- }
- });
-}
-
-function synchronize( callback, last ) {
- config.queue.push( callback );
-
- if ( config.autorun && !config.blocking ) {
- process( last );
- }
-}
-
-function process( last ) {
- function next() {
- process( last );
- }
- var start = new Date().getTime();
- config.depth = config.depth ? config.depth + 1 : 1;
-
- while ( config.queue.length && !config.blocking ) {
- if ( !defined.setTimeout || config.updateRate <= 0 || ( ( new Date().getTime() - start ) < config.updateRate ) ) {
- config.queue.shift()();
- } else {
- window.setTimeout( next, 13 );
- break;
- }
- }
- config.depth--;
- if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) {
- done();
- }
-}
-
-function saveGlobal() {
- config.pollution = [];
-
- if ( config.noglobals ) {
- for ( var key in window ) {
- // in Opera sometimes DOM element ids show up here, ignore them
- if ( !hasOwn.call( window, key ) || /^qunit-test-output/.test( key ) ) {
- continue;
- }
- config.pollution.push( key );
- }
- }
-}
-
-function checkPollution() {
- var newGlobals,
- deletedGlobals,
- old = config.pollution;
-
- saveGlobal();
-
- newGlobals = diff( config.pollution, old );
- if ( newGlobals.length > 0 ) {
- QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join(", ") );
- }
-
- deletedGlobals = diff( old, config.pollution );
- if ( deletedGlobals.length > 0 ) {
- QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join(", ") );
- }
-}
-
-// returns a new Array with the elements that are in a but not in b
-function diff( a, b ) {
- var i, j,
- result = a.slice();
-
- for ( i = 0; i < result.length; i++ ) {
- for ( j = 0; j < b.length; j++ ) {
- if ( result[i] === b[j] ) {
- result.splice( i, 1 );
- i--;
- break;
- }
- }
- }
- return result;
-}
-
-function extend( a, b ) {
- for ( var prop in b ) {
- if ( b[ prop ] === undefined ) {
- delete a[ prop ];
-
- // Avoid "Member not found" error in IE8 caused by setting window.constructor
- } else if ( prop !== "constructor" || a !== window ) {
- a[ prop ] = b[ prop ];
- }
- }
-
- return a;
-}
-
-/**
- * @param {HTMLElement} elem
- * @param {string} type
- * @param {Function} fn
- */
-function addEvent( elem, type, fn ) {
- // Standards-based browsers
- if ( elem.addEventListener ) {
- elem.addEventListener( type, fn, false );
- // IE
- } else {
- elem.attachEvent( "on" + type, fn );
- }
-}
-
-/**
- * @param {Array|NodeList} elems
- * @param {string} type
- * @param {Function} fn
- */
-function addEvents( elems, type, fn ) {
- var i = elems.length;
- while ( i-- ) {
- addEvent( elems[i], type, fn );
- }
-}
-
-function hasClass( elem, name ) {
- return (" " + elem.className + " ").indexOf(" " + name + " ") > -1;
-}
-
-function addClass( elem, name ) {
- if ( !hasClass( elem, name ) ) {
- elem.className += (elem.className ? " " : "") + name;
- }
-}
-
-function removeClass( elem, name ) {
- var set = " " + elem.className + " ";
- // Class name may appear multiple times
- while ( set.indexOf(" " + name + " ") > -1 ) {
- set = set.replace(" " + name + " " , " ");
- }
- // If possible, trim it for prettiness, but not neccecarily
- elem.className = window.jQuery ? jQuery.trim( set ) : ( set.trim ? set.trim() : set );
-}
-
-function id( name ) {
- return !!( typeof document !== "undefined" && document && document.getElementById ) &&
- document.getElementById( name );
-}
-
-function registerLoggingCallback( key ) {
- return function( callback ) {
- config[key].push( callback );
- };
-}
-
-// Supports deprecated method of completely overwriting logging callbacks
-function runLoggingCallbacks( key, scope, args ) {
- var i, callbacks;
- if ( QUnit.hasOwnProperty( key ) ) {
- QUnit[ key ].call(scope, args );
- } else {
- callbacks = config[ key ];
- for ( i = 0; i < callbacks.length; i++ ) {
- callbacks[ i ].call( scope, args );
- }
- }
-}
-
-// Test for equality any JavaScript type.
-// Author: Philippe Rathé
-QUnit.equiv = (function() {
-
- // Call the o related callback with the given arguments.
- function bindCallbacks( o, callbacks, args ) {
- var prop = QUnit.objectType( o );
- if ( prop ) {
- if ( QUnit.objectType( callbacks[ prop ] ) === "function" ) {
- return callbacks[ prop ].apply( callbacks, args );
- } else {
- return callbacks[ prop ]; // or undefined
- }
- }
- }
-
- // the real equiv function
- var innerEquiv,
- // stack to decide between skip/abort functions
- callers = [],
- // stack to avoiding loops from circular referencing
- parents = [],
-
- getProto = Object.getPrototypeOf || function ( obj ) {
- return obj.__proto__;
- },
- callbacks = (function () {
-
- // for string, boolean, number and null
- function useStrictEquality( b, a ) {
- /*jshint eqeqeq:false */
- if ( b instanceof a.constructor || a instanceof b.constructor ) {
- // to catch short annotaion VS 'new' annotation of a
- // declaration
- // e.g. var i = 1;
- // var j = new Number(1);
- return a == b;
- } else {
- return a === b;
- }
- }
-
- return {
- "string": useStrictEquality,
- "boolean": useStrictEquality,
- "number": useStrictEquality,
- "null": useStrictEquality,
- "undefined": useStrictEquality,
-
- "nan": function( b ) {
- return isNaN( b );
- },
-
- "date": function( b, a ) {
- return QUnit.objectType( b ) === "date" && a.valueOf() === b.valueOf();
- },
-
- "regexp": function( b, a ) {
- return QUnit.objectType( b ) === "regexp" &&
- // the regex itself
- a.source === b.source &&
- // and its modifers
- a.global === b.global &&
- // (gmi) ...
- a.ignoreCase === b.ignoreCase &&
- a.multiline === b.multiline &&
- a.sticky === b.sticky;
- },
-
- // - skip when the property is a method of an instance (OOP)
- // - abort otherwise,
- // initial === would have catch identical references anyway
- "function": function() {
- var caller = callers[callers.length - 1];
- return caller !== Object && typeof caller !== "undefined";
- },
-
- "array": function( b, a ) {
- var i, j, len, loop;
-
- // b could be an object literal here
- if ( QUnit.objectType( b ) !== "array" ) {
- return false;
- }
-
- len = a.length;
- if ( len !== b.length ) {
- // safe and faster
- return false;
- }
-
- // track reference to avoid circular references
- parents.push( a );
- for ( i = 0; i < len; i++ ) {
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- loop = true;// dont rewalk array
- }
- }
- if ( !loop && !innerEquiv(a[i], b[i]) ) {
- parents.pop();
- return false;
- }
- }
- parents.pop();
- return true;
- },
-
- "object": function( b, a ) {
- var i, j, loop,
- // Default to true
- eq = true,
- aProperties = [],
- bProperties = [];
-
- // comparing constructors is more strict than using
- // instanceof
- if ( a.constructor !== b.constructor ) {
- // Allow objects with no prototype to be equivalent to
- // objects with Object as their constructor.
- if ( !(( getProto(a) === null && getProto(b) === Object.prototype ) ||
- ( getProto(b) === null && getProto(a) === Object.prototype ) ) ) {
- return false;
- }
- }
-
- // stack constructor before traversing properties
- callers.push( a.constructor );
- // track reference to avoid circular references
- parents.push( a );
-
- for ( i in a ) { // be strict: don't ensures hasOwnProperty
- // and go deep
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- // don't go down the same path twice
- loop = true;
- }
- }
- aProperties.push(i); // collect a's properties
-
- if (!loop && !innerEquiv( a[i], b[i] ) ) {
- eq = false;
- break;
- }
- }
-
- callers.pop(); // unstack, we are done
- parents.pop();
-
- for ( i in b ) {
- bProperties.push( i ); // collect b's properties
- }
-
- // Ensures identical properties name
- return eq && innerEquiv( aProperties.sort(), bProperties.sort() );
- }
- };
- }());
-
- innerEquiv = function() { // can take multiple arguments
- var args = [].slice.apply( arguments );
- if ( args.length < 2 ) {
- return true; // end transition
- }
-
- return (function( a, b ) {
- if ( a === b ) {
- return true; // catch the most you can
- } else if ( a === null || b === null || typeof a === "undefined" ||
- typeof b === "undefined" ||
- QUnit.objectType(a) !== QUnit.objectType(b) ) {
- return false; // don't lose time with error prone cases
- } else {
- return bindCallbacks(a, callbacks, [ b, a ]);
- }
-
- // apply transition with (1..n) arguments
- }( args[0], args[1] ) && arguments.callee.apply( this, args.splice(1, args.length - 1 )) );
- };
-
- return innerEquiv;
-}());
-
-/**
- * jsDump Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com |
- * http://flesler.blogspot.com Licensed under BSD
- * (http://www.opensource.org/licenses/bsd-license.php) Date: 5/15/2008
- *
- * @projectDescription Advanced and extensible data dumping for Javascript.
- * @version 1.0.0
- * @author Ariel Flesler
- * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html}
- */
-QUnit.jsDump = (function() {
- function quote( str ) {
- return '"' + str.toString().replace( /"/g, '\\"' ) + '"';
- }
- function literal( o ) {
- return o + "";
- }
- function join( pre, arr, post ) {
- var s = jsDump.separator(),
- base = jsDump.indent(),
- inner = jsDump.indent(1);
- if ( arr.join ) {
- arr = arr.join( "," + s + inner );
- }
- if ( !arr ) {
- return pre + post;
- }
- return [ pre, inner + arr, base + post ].join(s);
- }
- function array( arr, stack ) {
- var i = arr.length, ret = new Array(i);
- this.up();
- while ( i-- ) {
- ret[i] = this.parse( arr[i] , undefined , stack);
- }
- this.down();
- return join( "[", ret, "]" );
- }
-
- var reName = /^function (\w+)/,
- jsDump = {
- // type is used mostly internally, you can fix a (custom)type in advance
- parse: function( obj, type, stack ) {
- stack = stack || [ ];
- var inStack, res,
- parser = this.parsers[ type || this.typeOf(obj) ];
-
- type = typeof parser;
- inStack = inArray( obj, stack );
-
- if ( inStack !== -1 ) {
- return "recursion(" + (inStack - stack.length) + ")";
- }
- if ( type === "function" ) {
- stack.push( obj );
- res = parser.call( this, obj, stack );
- stack.pop();
- return res;
- }
- return ( type === "string" ) ? parser : this.parsers.error;
- },
- typeOf: function( obj ) {
- var type;
- if ( obj === null ) {
- type = "null";
- } else if ( typeof obj === "undefined" ) {
- type = "undefined";
- } else if ( QUnit.is( "regexp", obj) ) {
- type = "regexp";
- } else if ( QUnit.is( "date", obj) ) {
- type = "date";
- } else if ( QUnit.is( "function", obj) ) {
- type = "function";
- } else if ( typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined" ) {
- type = "window";
- } else if ( obj.nodeType === 9 ) {
- type = "document";
- } else if ( obj.nodeType ) {
- type = "node";
- } else if (
- // native arrays
- toString.call( obj ) === "[object Array]" ||
- // NodeList objects
- ( typeof obj.length === "number" && typeof obj.item !== "undefined" && ( obj.length ? obj.item(0) === obj[0] : ( obj.item( 0 ) === null && typeof obj[0] === "undefined" ) ) )
- ) {
- type = "array";
- } else if ( obj.constructor === Error.prototype.constructor ) {
- type = "error";
- } else {
- type = typeof obj;
- }
- return type;
- },
- separator: function() {
- return this.multiline ? this.HTML ? "
" : "\n" : this.HTML ? " " : " ";
- },
- // extra can be a number, shortcut for increasing-calling-decreasing
- indent: function( extra ) {
- if ( !this.multiline ) {
- return "";
- }
- var chr = this.indentChar;
- if ( this.HTML ) {
- chr = chr.replace( /\t/g, " " ).replace( / /g, " " );
- }
- return new Array( this._depth_ + (extra||0) ).join(chr);
- },
- up: function( a ) {
- this._depth_ += a || 1;
- },
- down: function( a ) {
- this._depth_ -= a || 1;
- },
- setParser: function( name, parser ) {
- this.parsers[name] = parser;
- },
- // The next 3 are exposed so you can use them
- quote: quote,
- literal: literal,
- join: join,
- //
- _depth_: 1,
- // This is the list of parsers, to modify them, use jsDump.setParser
- parsers: {
- window: "[Window]",
- document: "[Document]",
- error: function(error) {
- return "Error(\"" + error.message + "\")";
- },
- unknown: "[Unknown]",
- "null": "null",
- "undefined": "undefined",
- "function": function( fn ) {
- var ret = "function",
- // functions never have name in IE
- name = "name" in fn ? fn.name : (reName.exec(fn) || [])[1];
-
- if ( name ) {
- ret += " " + name;
- }
- ret += "( ";
-
- ret = [ ret, QUnit.jsDump.parse( fn, "functionArgs" ), "){" ].join( "" );
- return join( ret, QUnit.jsDump.parse(fn,"functionCode" ), "}" );
- },
- array: array,
- nodelist: array,
- "arguments": array,
- object: function( map, stack ) {
- var ret = [ ], keys, key, val, i;
- QUnit.jsDump.up();
- keys = [];
- for ( key in map ) {
- keys.push( key );
- }
- keys.sort();
- for ( i = 0; i < keys.length; i++ ) {
- key = keys[ i ];
- val = map[ key ];
- ret.push( QUnit.jsDump.parse( key, "key" ) + ": " + QUnit.jsDump.parse( val, undefined, stack ) );
- }
- QUnit.jsDump.down();
- return join( "{", ret, "}" );
- },
- node: function( node ) {
- var len, i, val,
- open = QUnit.jsDump.HTML ? "<" : "<",
- close = QUnit.jsDump.HTML ? ">" : ">",
- tag = node.nodeName.toLowerCase(),
- ret = open + tag,
- attrs = node.attributes;
-
- if ( attrs ) {
- for ( i = 0, len = attrs.length; i < len; i++ ) {
- val = attrs[i].nodeValue;
- // IE6 includes all attributes in .attributes, even ones not explicitly set.
- // Those have values like undefined, null, 0, false, "" or "inherit".
- if ( val && val !== "inherit" ) {
- ret += " " + attrs[i].nodeName + "=" + QUnit.jsDump.parse( val, "attribute" );
- }
- }
- }
- ret += close;
-
- // Show content of TextNode or CDATASection
- if ( node.nodeType === 3 || node.nodeType === 4 ) {
- ret += node.nodeValue;
- }
-
- return ret + open + "/" + tag + close;
- },
- // function calls it internally, it's the arguments part of the function
- functionArgs: function( fn ) {
- var args,
- l = fn.length;
-
- if ( !l ) {
- return "";
- }
-
- args = new Array(l);
- while ( l-- ) {
- // 97 is 'a'
- args[l] = String.fromCharCode(97+l);
- }
- return " " + args.join( ", " ) + " ";
- },
- // object calls it internally, the key part of an item in a map
- key: quote,
- // function calls it internally, it's the content of the function
- functionCode: "[code]",
- // node calls it internally, it's an html attribute value
- attribute: quote,
- string: quote,
- date: quote,
- regexp: literal,
- number: literal,
- "boolean": literal
- },
- // if true, entities are escaped ( <, >, \t, space and \n )
- HTML: false,
- // indentation unit
- indentChar: " ",
- // if true, items in a collection, are separated by a \n, else just a space.
- multiline: true
- };
-
- return jsDump;
-}());
-
-// from jquery.js
-function inArray( elem, array ) {
- if ( array.indexOf ) {
- return array.indexOf( elem );
- }
-
- for ( var i = 0, length = array.length; i < length; i++ ) {
- if ( array[ i ] === elem ) {
- return i;
- }
- }
-
- return -1;
-}
-
-/*
- * Javascript Diff Algorithm
- * By John Resig (http://ejohn.org/)
- * Modified by Chu Alan "sprite"
- *
- * Released under the MIT license.
- *
- * More Info:
- * http://ejohn.org/projects/javascript-diff-algorithm/
- *
- * Usage: QUnit.diff(expected, actual)
- *
- * QUnit.diff( "the quick brown fox jumped over", "the quick fox jumps over" ) == "the quick brown fox jumped jumps over"
- */
-QUnit.diff = (function() {
- /*jshint eqeqeq:false, eqnull:true */
- function diff( o, n ) {
- var i,
- ns = {},
- os = {};
-
- for ( i = 0; i < n.length; i++ ) {
- if ( !hasOwn.call( ns, n[i] ) ) {
- ns[ n[i] ] = {
- rows: [],
- o: null
- };
- }
- ns[ n[i] ].rows.push( i );
- }
-
- for ( i = 0; i < o.length; i++ ) {
- if ( !hasOwn.call( os, o[i] ) ) {
- os[ o[i] ] = {
- rows: [],
- n: null
- };
- }
- os[ o[i] ].rows.push( i );
- }
-
- for ( i in ns ) {
- if ( !hasOwn.call( ns, i ) ) {
- continue;
- }
- if ( ns[i].rows.length === 1 && hasOwn.call( os, i ) && os[i].rows.length === 1 ) {
- n[ ns[i].rows[0] ] = {
- text: n[ ns[i].rows[0] ],
- row: os[i].rows[0]
- };
- o[ os[i].rows[0] ] = {
- text: o[ os[i].rows[0] ],
- row: ns[i].rows[0]
- };
- }
- }
-
- for ( i = 0; i < n.length - 1; i++ ) {
- if ( n[i].text != null && n[ i + 1 ].text == null && n[i].row + 1 < o.length && o[ n[i].row + 1 ].text == null &&
- n[ i + 1 ] == o[ n[i].row + 1 ] ) {
-
- n[ i + 1 ] = {
- text: n[ i + 1 ],
- row: n[i].row + 1
- };
- o[ n[i].row + 1 ] = {
- text: o[ n[i].row + 1 ],
- row: i + 1
- };
- }
- }
-
- for ( i = n.length - 1; i > 0; i-- ) {
- if ( n[i].text != null && n[ i - 1 ].text == null && n[i].row > 0 && o[ n[i].row - 1 ].text == null &&
- n[ i - 1 ] == o[ n[i].row - 1 ]) {
-
- n[ i - 1 ] = {
- text: n[ i - 1 ],
- row: n[i].row - 1
- };
- o[ n[i].row - 1 ] = {
- text: o[ n[i].row - 1 ],
- row: i - 1
- };
- }
- }
-
- return {
- o: o,
- n: n
- };
- }
-
- return function( o, n ) {
- o = o.replace( /\s+$/, "" );
- n = n.replace( /\s+$/, "" );
-
- var i, pre,
- str = "",
- out = diff( o === "" ? [] : o.split(/\s+/), n === "" ? [] : n.split(/\s+/) ),
- oSpace = o.match(/\s+/g),
- nSpace = n.match(/\s+/g);
-
- if ( oSpace == null ) {
- oSpace = [ " " ];
- }
- else {
- oSpace.push( " " );
- }
-
- if ( nSpace == null ) {
- nSpace = [ " " ];
- }
- else {
- nSpace.push( " " );
- }
-
- if ( out.n.length === 0 ) {
- for ( i = 0; i < out.o.length; i++ ) {
- str += "" + out.o[i] + oSpace[i] + "";
- }
- }
- else {
- if ( out.n[0].text == null ) {
- for ( n = 0; n < out.o.length && out.o[n].text == null; n++ ) {
- str += "" + out.o[n] + oSpace[n] + "";
- }
- }
-
- for ( i = 0; i < out.n.length; i++ ) {
- if (out.n[i].text == null) {
- str += "" + out.n[i] + nSpace[i] + "";
- }
- else {
- // `pre` initialized at top of scope
- pre = "";
-
- for ( n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++ ) {
- pre += "" + out.o[n] + oSpace[n] + "";
- }
- str += " " + out.n[i].text + nSpace[i] + pre;
- }
- }
- }
-
- return str;
- };
-}());
-
-// for CommonJS enviroments, export everything
-if ( typeof exports !== "undefined" ) {
- extend( exports, QUnit );
-}
-
-// get at whatever the global object is, like window in browsers
-}( (function() {return this;}.call()) ));
diff --git a/test/lib/require.js b/test/lib/require.js
deleted file mode 100644
index 987f865..0000000
--- a/test/lib/require.js
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- RequireJS 2.1.5 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.
- Available via the MIT or new BSD license.
- see: http://github.com/jrburke/requirejs for details
-*/
-var requirejs,require,define;
-(function(aa){function I(b){return"[object Function]"===L.call(b)}function J(b){return"[object Array]"===L.call(b)}function y(b,c){if(b){var d;for(d=0;dthis.depCount&&!this.defined){if(I(n)){if(this.events.error)try{e=i.execCb(c,n,b,e)}catch(d){a=d}else e=i.execCb(c,n,b,e);this.map.isDefine&&((b=this.module)&&void 0!==b.exports&&b.exports!==this.exports?e=b.exports:void 0===e&&this.usingExports&&(e=this.exports));if(a)return a.requireMap=this.map,a.requireModules=[this.map.id],a.requireType="define",v(this.error=
-a)}else e=n;this.exports=e;if(this.map.isDefine&&!this.ignore&&(q[c]=e,l.onResourceLoad))l.onResourceLoad(i,this.map,this.depMaps);x(c);this.defined=!0}this.defining=!1;this.defined&&!this.defineEmitted&&(this.defineEmitted=!0,this.emit("defined",this.exports),this.defineEmitComplete=!0)}}else this.fetch()}},callPlugin:function(){var a=this.map,b=a.id,d=j(a.prefix);this.depMaps.push(d);t(d,"defined",u(this,function(e){var n,d;d=this.map.name;var g=this.map.parentMap?this.map.parentMap.name:null,h=
-i.makeRequire(a.parentMap,{enableBuildCallback:!0});if(this.map.unnormalized){if(e.normalize&&(d=e.normalize(d,function(a){return c(a,g,!0)})||""),e=j(a.prefix+"!"+d,this.map.parentMap),t(e,"defined",u(this,function(a){this.init([],function(){return a},null,{enabled:!0,ignore:!0})})),d=m(p,e.id)){this.depMaps.push(e);if(this.events.error)d.on("error",u(this,function(a){this.emit("error",a)}));d.enable()}}else n=u(this,function(a){this.init([],function(){return a},null,{enabled:!0})}),n.error=u(this,
-function(a){this.inited=!0;this.error=a;a.requireModules=[b];G(p,function(a){0===a.map.id.indexOf(b+"_unnormalized")&&x(a.map.id)});v(a)}),n.fromText=u(this,function(e,c){var d=a.name,g=j(d),C=O;c&&(e=c);C&&(O=!1);r(g);s(k.config,b)&&(k.config[d]=k.config[b]);try{l.exec(e)}catch(ca){return v(B("fromtexteval","fromText eval for "+b+" failed: "+ca,ca,[b]))}C&&(O=!0);this.depMaps.push(g);i.completeLoad(d);h([d],n)}),e.load(a.name,h,n,k)}));i.enable(d,this);this.pluginMaps[d.id]=d},enable:function(){V[this.map.id]=
-this;this.enabling=this.enabled=!0;y(this.depMaps,u(this,function(a,b){var c,e;if("string"===typeof a){a=j(a,this.map.isDefine?this.map:this.map.parentMap,!1,!this.skipMap);this.depMaps[b]=a;if(c=m(N,a.id)){this.depExports[b]=c(this);return}this.depCount+=1;t(a,"defined",u(this,function(a){this.defineDep(b,a);this.check()}));this.errback&&t(a,"error",this.errback)}c=a.id;e=p[c];!s(N,c)&&(e&&!e.enabled)&&i.enable(a,this)}));G(this.pluginMaps,u(this,function(a){var b=m(p,a.id);b&&!b.enabled&&i.enable(a,
-this)}));this.enabling=!1;this.check()},on:function(a,b){var c=this.events[a];c||(c=this.events[a]=[]);c.push(b)},emit:function(a,b){y(this.events[a],function(a){a(b)});"error"===a&&delete this.events[a]}};i={config:k,contextName:b,registry:p,defined:q,urlFetched:U,defQueue:H,Module:Z,makeModuleMap:j,nextTick:l.nextTick,onError:v,configure:function(a){a.baseUrl&&"/"!==a.baseUrl.charAt(a.baseUrl.length-1)&&(a.baseUrl+="/");var b=k.pkgs,c=k.shim,e={paths:!0,config:!0,map:!0};G(a,function(a,b){e[b]?
-"map"===b?(k.map||(k.map={}),R(k[b],a,!0,!0)):R(k[b],a,!0):k[b]=a});a.shim&&(G(a.shim,function(a,b){J(a)&&(a={deps:a});if((a.exports||a.init)&&!a.exportsFn)a.exportsFn=i.makeShimExports(a);c[b]=a}),k.shim=c);a.packages&&(y(a.packages,function(a){a="string"===typeof a?{name:a}:a;b[a.name]={name:a.name,location:a.location||a.name,main:(a.main||"main").replace(ja,"").replace(ea,"")}}),k.pkgs=b);G(p,function(a,b){!a.inited&&!a.map.unnormalized&&(a.map=j(b))});if(a.deps||a.callback)i.require(a.deps||[],
-a.callback)},makeShimExports:function(a){return function(){var b;a.init&&(b=a.init.apply(aa,arguments));return b||a.exports&&ba(a.exports)}},makeRequire:function(a,f){function d(e,c,h){var g,k;f.enableBuildCallback&&(c&&I(c))&&(c.__requireJsBuild=!0);if("string"===typeof e){if(I(c))return v(B("requireargs","Invalid require call"),h);if(a&&s(N,e))return N[e](p[a.id]);if(l.get)return l.get(i,e,a,d);g=j(e,a,!1,!0);g=g.id;return!s(q,g)?v(B("notloaded",'Module name "'+g+'" has not been loaded yet for context: '+
-b+(a?"":". Use require([])"))):q[g]}L();i.nextTick(function(){L();k=r(j(null,a));k.skipMap=f.skipMap;k.init(e,c,h,{enabled:!0});D()});return d}f=f||{};R(d,{isBrowser:A,toUrl:function(b){var d,f=b.lastIndexOf("."),g=b.split("/")[0];if(-1!==f&&(!("."===g||".."===g)||1h.attachEvent.toString().indexOf("[native code"))&&!Y?(O=!0,h.attachEvent("onreadystatechange",b.onScriptLoad)):(h.addEventListener("load",b.onScriptLoad,!1),h.addEventListener("error",b.onScriptError,!1)),h.src=d,K=h,D?x.insertBefore(h,D):x.appendChild(h),K=null,h;if(da)try{importScripts(d),b.completeLoad(c)}catch(j){b.onError(B("importscripts","importScripts failed for "+c+" at "+d,j,[c]))}};A&&M(document.getElementsByTagName("script"),function(b){x||(x=
-b.parentNode);if(t=b.getAttribute("data-main"))return r.baseUrl||(E=t.split("/"),Q=E.pop(),fa=E.length?E.join("/")+"/":"./",r.baseUrl=fa,t=Q),t=t.replace(ea,""),r.deps=r.deps?r.deps.concat(t):[t],!0});define=function(b,c,d){var l,h;"string"!==typeof b&&(d=c,c=b,b=null);J(c)||(d=c,c=[]);!c.length&&I(d)&&d.length&&(d.toString().replace(la,"").replace(ma,function(b,d){c.push(d)}),c=(1===d.length?["require"]:["require","exports","module"]).concat(c));if(O){if(!(l=K))P&&"interactive"===P.readyState||M(document.getElementsByTagName("script"),
-function(b){if("interactive"===b.readyState)return P=b}),l=P;l&&(b||(b=l.getAttribute("data-requiremodule")),h=F[l.getAttribute("data-requirecontext")])}(h?h.defQueue:T).push([b,c,d])};define.amd={jQuery:!0};l.exec=function(b){return eval(b)};l(r)}})(this);
diff --git a/test/lib/resemble.js b/test/lib/resemble.js
new file mode 100644
index 0000000..1cb8c29
--- /dev/null
+++ b/test/lib/resemble.js
@@ -0,0 +1,535 @@
+/*
+Author: James Cryer
+Company: Huddle
+Last updated date: 21 Feb 2013
+URL: https://github.com/Huddle/Resemble.js
+*/
+
+(function(_this){
+ 'use strict';
+
+ _this['resemble'] = function( fileData ){
+
+ var data = {};
+ var images = [];
+ var updateCallbackArray = [];
+
+ var tolerance = { // between 0 and 255
+ red: 16,
+ green: 16,
+ blue: 16,
+ minBrightness: 16,
+ maxBrightness: 240
+ };
+
+ var ignoreAntialiasing = false;
+ var ignoreColors = false;
+
+ function triggerDataUpdate(){
+ var len = updateCallbackArray.length;
+ var i;
+ for(i=0;i tolerance.maxBrightness;
+ }
+
+ function getHue(r,g,b){
+
+ r = r / 255;
+ g = g / 255;
+ b = b / 255;
+ var max = Math.max(r, g, b), min = Math.min(r, g, b);
+ var h;
+ var d;
+
+ if (max == min){
+ h = 0; // achromatic
+ } else{
+ d = max - min;
+ switch(max){
+ case r: h = (g - b) / d + (g < b ? 6 : 0); break;
+ case g: h = (b - r) / d + 2; break;
+ case b: h = (r - g) / d + 4; break;
+ }
+ h /= 6;
+ }
+
+ return h;
+ }
+
+ function isAntialiased(sourcePix, data, cacheSet, verticalPos, horizontalPos, width){
+ var offset;
+ var targetPix;
+ var distance = 1;
+ var i;
+ var j;
+ var hasHighContrastSibling = 0;
+ var hasSiblingWithDifferentHue = 0;
+ var hasEquivilantSibling = 0;
+
+ addHueInfo(sourcePix);
+
+ for (i = distance*-1; i <= distance; i++){
+ for (j = distance*-1; j <= distance; j++){
+
+ if(i===0 && j===0){
+ // ignore source pixel
+ } else {
+
+ offset = ((verticalPos+j)*width + (horizontalPos+i)) * 4;
+ targetPix = getPixelInfo(data, offset, cacheSet);
+
+ if(targetPix === null){
+ continue;
+ }
+
+ addBrightnessInfo(targetPix);
+ addHueInfo(targetPix);
+
+ if( isContrasting(sourcePix, targetPix) ){
+ hasHighContrastSibling++;
+ }
+
+ if( isRGBSame(sourcePix,targetPix) ){
+ hasEquivilantSibling++;
+ }
+
+ if( Math.abs(targetPix.h - sourcePix.h) > 0.3 ){
+ hasSiblingWithDifferentHue++;
+ }
+
+ if( hasSiblingWithDifferentHue > 1 || hasHighContrastSibling > 1){
+ return true;
+ }
+ }
+ }
+ }
+
+ if(hasEquivilantSibling < 2){
+ return true;
+ }
+
+ return false;
+ }
+
+ function errorPixel(px, offset){
+ px[offset] = 255; //r
+ px[offset + 1] = 0; //g
+ px[offset + 2] = 255; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyPixel(px, offset, data){
+ px[offset] = data.r; //r
+ px[offset + 1] = data.g; //g
+ px[offset + 2] = data.b; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyGrayScalePixel(px, offset, data){
+ px[offset] = data.brightness; //r
+ px[offset + 1] = data.brightness; //g
+ px[offset + 2] = data.brightness; //b
+ px[offset + 3] = 255; //a
+ }
+
+
+ function getPixelInfo(data, offset, cacheSet){
+ var r;
+ var g;
+ var b;
+ var d;
+
+ if(typeof data[offset] !== 'undefined'){
+ r = data[offset];
+ g = data[offset+1];
+ b = data[offset+2];
+ d = {
+ r: r,
+ g: g,
+ b: b
+ };
+
+ return d;
+ } else {
+ return null;
+ }
+ }
+
+ function addBrightnessInfo(data){
+ data.brightness = getBrightness(data.r,data.g,data.b); // 'corrected' lightness
+ }
+
+ function addHueInfo(data){
+ data.h = getHue(data.r,data.g,data.b);
+ }
+
+ function analyseImages(img1, img2, width, height){
+
+ var hiddenCanvas = document.createElement('canvas');
+
+ var data1 = img1.data;
+ var data2 = img2.data;
+
+ hiddenCanvas.width = width;
+ hiddenCanvas.height = height;
+
+ var context = hiddenCanvas.getContext('2d');
+ var imgd = context.createImageData(width,height);
+ var targetPix = imgd.data;
+
+ var mismatchCount = 0;
+
+ var time = Date.now();
+
+ var skip;
+
+ if( (width > 1200 || height > 1200) && ignoreAntialiasing){
+ skip = 6;
+ }
+
+ loop(height, width, function(verticalPos, horizontalPos){
+
+ if(skip){ // only skip if the image isn't small
+ if(verticalPos % skip === 0 || horizontalPos % skip === 0){
+ return;
+ }
+ }
+
+ var offset = (verticalPos*width + horizontalPos) * 4;
+ var pixel1 = getPixelInfo(data1, offset, 1);
+ var pixel2 = getPixelInfo(data2, offset, 2);
+
+ if(pixel1 === null || pixel2 === null){
+ return;
+ }
+
+ if (ignoreColors){
+
+ addBrightnessInfo(pixel1);
+ addBrightnessInfo(pixel2);
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ return;
+ }
+
+ if( isRGBSimilar(pixel1, pixel2) ){
+ copyPixel(targetPix, offset, pixel2);
+
+ } else if( ignoreAntialiasing && (
+ addBrightnessInfo(pixel1), // jit pixel info augmentation looks a little weird, sorry.
+ addBrightnessInfo(pixel2),
+ isAntialiased(pixel1, data1, 1, verticalPos, horizontalPos, width) ||
+ isAntialiased(pixel2, data2, 2, verticalPos, horizontalPos, width)
+ )){
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+
+ });
+
+ data.misMatchPercentage = (mismatchCount / (height*width) * 100).toFixed(2);
+ data.analysisTime = Date.now() - time;
+
+ data.getImageDataUrl = function(text){
+ var barHeight = 0;
+
+ if(text){
+ barHeight = addLabel(text,context,hiddenCanvas);
+ }
+
+ context.putImageData(imgd, 0, barHeight);
+
+ return hiddenCanvas.toDataURL("image/png");
+ };
+ }
+
+ function addLabel(text, context, hiddenCanvas){
+ var textPadding = 2;
+
+ context.font = '12px sans-serif';
+
+ var textWidth = context.measureText(text).width + textPadding*2;
+ var barHeight = 22;
+
+ if(textWidth > hiddenCanvas.width){
+ hiddenCanvas.width = textWidth;
+ }
+
+ hiddenCanvas.height += barHeight;
+
+ context.fillStyle = "#666";
+ context.fillRect(0,0,hiddenCanvas.width,barHeight -4);
+ context.fillStyle = "#fff";
+ context.fillRect(0,barHeight -4,hiddenCanvas.width, 4);
+
+ context.fillStyle = "#fff";
+ context.textBaseline = "top";
+ context.font = '12px sans-serif';
+ context.fillText(text, textPadding, 1);
+
+ return barHeight;
+ }
+
+ function normalise(img, w, h){
+ var c;
+ var context;
+
+ if(img.height < h || img.width < w){
+ c = document.createElement('canvas');
+ c.width = w;
+ c.height = h;
+ context = c.getContext('2d');
+ context.putImageData(img, 0, 0);
+ return context.getImageData(0, 0, w, h);
+ }
+
+ return img;
+ }
+
+ function compare(one, two){
+
+ function onceWeHaveBoth(){
+ var width;
+ var height;
+ if(images.length === 2){
+ width = images[0].width > images[1].width ? images[0].width : images[1].width;
+ height = images[0].height > images[1].height ? images[0].height : images[1].height;
+
+ if( (images[0].width === images[1].width) && (images[0].height === images[1].height) ){
+ data.isSameDimensions = true;
+ } else {
+ data.isSameDimensions = false;
+ }
+
+ analyseImages( normalise(images[0],width, height), normalise(images[1],width, height), width, height);
+
+ triggerDataUpdate();
+ }
+ }
+
+ images = [];
+ loadImageData(one, onceWeHaveBoth);
+ loadImageData(two, onceWeHaveBoth);
+ }
+
+ function getCompareApi(param){
+
+ var secondFileData,
+ hasMethod = typeof param === 'function';
+
+ if( !hasMethod ){
+ // assume it's file data
+ secondFileData = param;
+ }
+
+ var self = {
+ ignoreNothing: function(){
+
+ tolerance.red = 16;
+ tolerance.green = 16;
+ tolerance.blue = 16;
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreAntialiasing: function(){
+
+ tolerance.red = 32;
+ tolerance.green = 32;
+ tolerance.blue = 32;
+ tolerance.minBrightness = 64;
+ tolerance.maxBrightness = 96;
+
+ ignoreAntialiasing = true;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreColors: function(){
+
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = true;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ onComplete: function( callback ){
+
+ updateCallbackArray.push(callback);
+
+ var wrapper = function(){
+ compare(fileData, secondFileData);
+ };
+
+ wrapper();
+
+ return getCompareApi(wrapper);
+ }
+ };
+
+ return self;
+ }
+
+ return {
+ onComplete: function( callback ){
+ updateCallbackArray.push(callback);
+ loadImageData(fileData, function(imageData, width, height){
+ parseImage(imageData.data, width, height);
+ });
+ },
+ compareTo: function(secondFileData){
+ return getCompareApi(secondFileData);
+ }
+ };
+
+ };
+}(this));
\ No newline at end of file
diff --git a/test/testsuite.js b/test/testsuite.js
deleted file mode 100644
index b486acb..0000000
--- a/test/testsuite.js
+++ /dev/null
@@ -1,36 +0,0 @@
-requirejs.config({
- baseUrl: '/test/unit/'
-});
-
-define(function(require) {
- var testModules = [
- 'Pixi',
- 'Point',
- 'Rectangle',
- 'DisplayObject',
- 'DisplayObjectContainer',
- 'Sprite',
- 'MovieClip',
- 'InteractionManager',
- 'Stage',
- 'utils/Utils',
- 'utils/EventTarget',
- 'utils/Matrix',
- 'utils/Detector',
- 'renderers/WebGLShaders',
- 'renderers/WebGLRenderer',
- 'renderers/WebGLBatch',
- 'renderers/CanvasRenderer',
- 'extras/Strip',
- 'extras/Rope',
- 'textures/BaseTexture',
- 'textures/Texture',
- 'loaders/SpriteSheetLoader',
- 'loaders/AssetLoader'
- ];
-
- // Resolve all testModules and then start the Test Runner.
- require(testModules, function() {
- QUnit.start();
- });
-});
\ No newline at end of file
diff --git a/test/textures/SpriteSheet-Aliens.png b/test/textures/SpriteSheet-Aliens.png
new file mode 100644
index 0000000..210acb1
--- /dev/null
+++ b/test/textures/SpriteSheet-Aliens.png
Binary files differ
diff --git a/test/textures/SpriteSheet-Explosion.png b/test/textures/SpriteSheet-Explosion.png
new file mode 100755
index 0000000..79e1a69
--- /dev/null
+++ b/test/textures/SpriteSheet-Explosion.png
Binary files differ
diff --git a/test/textures/bunny.png b/test/textures/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/textures/bunny.png
Binary files differ
diff --git a/.gitignore b/.gitignore
index 12e1b62..0b88317 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
node_modules
.DS_Store
-.project
\ No newline at end of file
+.project
+*.log
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..63e4d7c
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,8 @@
+language: node_js
+node_js:
+ - 0.10
+
+before_script:
+ - npm install -g grunt-cli
+ - export DISPLAY=:99.0
+ - sh -e /etc/init.d/xvfb start
diff --git a/Gruntfile.js b/Gruntfile.js
index b083b49..103938c 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -1,10 +1,12 @@
+'use strict';
+
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-connect');
- grunt.loadNpmTasks('grunt-contrib-qunit');
grunt.loadNpmTasks('grunt-contrib-yuidoc');
+ grunt.loadTasks('tasks');
var root = 'src/pixi/',
debug = 'bin/pixi.dev.js',
@@ -79,7 +81,7 @@
},
files: {
srcBlob: '<%= dirs.src %>/**/*.js',
- testBlob: '<%= dirs.test %>/unit/**/*.js',
+ testBlob: '<%= dirs.test %>/{functional,lib/pixi,unit}/**/*.js',
build: '<%= dirs.build %>/pixi.dev.js',
buildMin: '<%= dirs.build %>/pixi.js'
},
@@ -94,7 +96,12 @@
},
jshint: {
beforeconcat: srcFiles,
- test: ['<%= files.testBlob %>'],
+ test: {
+ src: ['<%= files.testBlob %>'],
+ options: {
+ expr: true
+ }
+ },
options: {
asi: true,
smarttabs: true
@@ -128,12 +135,6 @@
]
},
connect: {
- qunit: {
- options: {
- port: grunt.option('port-test') || 9002,
- base: './'
- }
- },
test: {
options: {
port: grunt.option('port-test') || 9002,
@@ -142,13 +143,6 @@
}
}
},
- qunit: {
- all: {
- options: {
- urls: ['http://localhost:' + (grunt.option('port-test') || 9002) + '/test/index.html']
- }
- }
- },
yuidoc: {
compile: {
name: '<%= pkg.name %>',
@@ -161,6 +155,13 @@
outdir: '<%= dirs.docs %>'
}
}
+ },
+ karma: {
+ unit: {
+ configFile: 'test/karma.conf.js',
+ // browsers: ['Chrome'],
+ singleRun: true
+ }
}
});
@@ -182,9 +183,10 @@
}
)
- grunt.registerTask('default', ['concat', 'uglify', 'distribute']);
grunt.registerTask('build', ['concat', 'uglify', 'distribute']);
- grunt.registerTask('test', ['build', 'connect:qunit', 'qunit']);
+ grunt.registerTask('test', ['concat', 'jshint:test', 'karma']);
grunt.registerTask('docs', ['yuidoc']);
-
-}
\ No newline at end of file
+ grunt.registerTask('default', ['test', 'uglify', 'distribute']);
+ // Travis CI task.
+ grunt.registerTask('travis', ['test']);
+}
diff --git a/README.md b/README.md
index c62ef86..690cfe4 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,8 @@

+[](http://travis-ci.org/drkibitz/pixi.js)
+
#### JavaScript 2D Renderer ####
The aim of this project is to provide a fast lightweight 2D library that works
diff --git a/package.json b/package.json
index b373240..1246a68 100644
--- a/package.json
+++ b/package.json
@@ -18,14 +18,21 @@
"main": "bin/pixi.js",
+ "scripts": {
+ "test": "grunt travis --verbose"
+ },
+
"dependencies": {},
"devDependencies": {
"grunt": "~0.4.x",
- "grunt-contrib-jshint": "0.3.x",
+ "grunt-contrib-jshint": "0.6.x",
"grunt-contrib-uglify": "0.2.x",
- "grunt-contrib-connect": "0.2.x",
- "grunt-contrib-qunit": "0.2.x",
+ "grunt-contrib-connect": "0.3.x",
"grunt-contrib-yuidoc": "0.4.x",
- "grunt-contrib-concat": "0.1.x"
+ "grunt-contrib-concat": "0.3.x",
+ "chai": "~1.7.0",
+ "karma": "0.11.0",
+ "karma-firefox-launcher": "0.1.0",
+ "karma-mocha": "0.1.0"
}
}
diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js
index a7c520e..ee82bbd 100644
--- a/src/pixi/InteractionManager.js
+++ b/src/pixi/InteractionManager.js
@@ -62,7 +62,6 @@
this.onTouchEnd = this.onTouchEnd.bind(this);
this.onTouchMove = this.onTouchMove.bind(this);
-
this.last = 0;
}
diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js
index 1a95d20..eef1059 100644
--- a/src/pixi/core/Ellipse.js
+++ b/src/pixi/core/Ellipse.js
@@ -78,7 +78,7 @@
return (normx + normy < 0.25);
}
-PIXI.Ellipse.getBounds = function()
+PIXI.Ellipse.prototype.getBounds = function()
{
return new PIXI.Rectangle(this.x, this.y, this.width, this.height);
}
diff --git a/tasks/karma.js b/tasks/karma.js
new file mode 100644
index 0000000..c340485
--- /dev/null
+++ b/tasks/karma.js
@@ -0,0 +1,27 @@
+'use strict';
+
+var path = require('path');
+var server = require('karma').server;
+
+module.exports = function (grunt) {
+ grunt.registerMultiTask('karma', 'run karma.', function() {
+ var done = this.async();
+ var options = this.options({
+ background: false
+ });
+ var data = this.data;
+
+ //merge options onto data, with data taking precedence
+ data = grunt.util._.merge(options, data);
+ data.configFile = path.resolve(data.configFile);
+ if (data.configFile) {
+ data.configFile = grunt.template.process(data.configFile);
+ }
+
+ server.start(
+ data,
+ function(code) {
+ done(!code);
+ });
+ });
+};
diff --git a/test/functional/example-1-basics/bunny.png b/test/functional/example-1-basics/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/functional/example-1-basics/bunny.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-30.png b/test/functional/example-1-basics/frame-30.png
new file mode 100644
index 0000000..96e3409
--- /dev/null
+++ b/test/functional/example-1-basics/frame-30.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-60.png b/test/functional/example-1-basics/frame-60.png
new file mode 100644
index 0000000..af3f4ce
--- /dev/null
+++ b/test/functional/example-1-basics/frame-60.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-90.png b/test/functional/example-1-basics/frame-90.png
new file mode 100644
index 0000000..099b823
--- /dev/null
+++ b/test/functional/example-1-basics/frame-90.png
Binary files differ
diff --git a/test/functional/example-1-basics/index.js b/test/functional/example-1-basics/index.js
new file mode 100644
index 0000000..7ae7a98
--- /dev/null
+++ b/test/functional/example-1-basics/index.js
@@ -0,0 +1,133 @@
+describe('Example 1 - Basics', function () {
+ 'use strict';
+
+ var baseUri = '/base/test/functional/example-1-basics';
+ var expect = chai.expect;
+ var currentFrame = 0;
+ var frameEvents = {};
+ var stage;
+ var renderer;
+ var bunny;
+
+ function onFrame(frame, callback) {
+ frameEvents[frame] = callback;
+ }
+
+ function animate() {
+ currentFrame += 1;
+
+ requestAnimFrame( animate );
+
+ // just for fun, lets rotate mr rabbit a little
+ bunny.rotation += 0.1;
+
+ // render the stage
+ renderer.render(stage);
+
+ if (frameEvents[currentFrame])
+ frameEvents[currentFrame](currentFrame);
+ }
+
+ function initScene() {
+ // create an new instance of a pixi stage
+ stage = new PIXI.Stage(0x66FF99);
+
+ // create a renderer instance
+ renderer = PIXI.autoDetectRenderer(400, 300);
+ console.log('Is PIXI.WebGLRenderer: ' + (renderer instanceof PIXI.WebGLRenderer));
+
+ // add the renderer view element to the DOM
+ document.body.appendChild(renderer.view);
+
+ requestAnimFrame( animate );
+
+ // create a texture from an image path
+ var texture = PIXI.Texture.fromImage(baseUri + "/bunny.png");
+ // create a new Sprite using the texture
+ bunny = new PIXI.Sprite(texture);
+
+ // center the sprites anchor point
+ bunny.anchor.x = 0.5;
+ bunny.anchor.y = 0.5;
+
+ // move the sprite t the center of the screen
+ bunny.position.x = 200;
+ bunny.position.y = 150;
+
+ stage.addChild(bunny);
+ }
+
+ it('assets loaded', function (done) {
+ var loader = new PIXI.AssetLoader([
+ baseUri + '/bunny.png',
+ baseUri + '/frame-30.png',
+ baseUri + '/frame-60.png',
+ baseUri + '/frame-90.png'
+ ]);
+ // loader.on('onProgress', function (event) {
+ // console.log(event.content);
+ // });
+ loader.on('onComplete', function (event) {
+ done();
+ initScene();
+ });
+ loader.load();
+ });
+
+ it('frame 30 should match', function (done) {
+ this.timeout(700);
+ onFrame(30, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-30.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 60 should match', function (done) {
+ this.timeout(1200);
+ onFrame(60, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-60.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 90 should match', function (done) {
+ this.timeout(1700);
+ onFrame(90, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-90.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ // it('capture something', function (done) {
+ // this.timeout(2000000);
+ // onFrame(30, function () {
+ // var img = new Image();
+ // img.src = renderer.view.toDataURL('image/png');
+ // document.body.appendChild(img);
+ // });
+ // });
+});
diff --git a/test/index.html b/test/index.html
deleted file mode 100644
index 9cbcac5..0000000
--- a/test/index.html
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
- Pixi.js Test Suite
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/test/karma.conf.js b/test/karma.conf.js
new file mode 100644
index 0000000..c66a696
--- /dev/null
+++ b/test/karma.conf.js
@@ -0,0 +1,82 @@
+module.exports = function(config) {
+ config.set({
+
+ // base path, that will be used to resolve files and exclude
+ basePath : '../',
+
+ frameworks : ['mocha'],
+
+ // list of files / patterns to load in the browser
+ files : [
+ 'node_modules/chai/chai.js',
+ 'bin/pixi.dev.js',
+ 'test/lib/**/*.js',
+ 'test/unit/**/*.js',
+ // 'test/functional/**/*.js',
+ {pattern: 'test/**/*.png', watched: false, included: false, served: true}
+ ],
+
+ // list of files to exclude
+ exclude : [],
+
+ // use dolts reporter, as travis terminal does not support escaping sequences
+ // possible values: 'dots', 'progress', 'junit', 'teamcity'
+ // CLI --reporters progress
+ reporters : ['progress'],
+
+ // web server port
+ // CLI --port 9876
+ port : 9876,
+
+ // cli runner port
+ // CLI --runner-port 9100
+ runnerPort : 9100,
+
+ // enable / disable colors in the output (reporters and logs)
+ // CLI --colors --no-colors
+ colors : true,
+
+ // level of logging
+ // possible values: karma.LOG_DISABLE || karma.LOG_ERROR || karma.LOG_WARN || karma.LOG_INFO || karma.LOG_DEBUG
+ // CLI --log-level debug
+ logLevel : config.LOG_DEBUG,
+
+ // enable / disable watching file and executing tests whenever any file changes
+ // CLI --auto-watch --no-auto-watch
+ autoWatch : false,
+
+ // Start these browsers, currently available:
+ // - Chrome
+ // - ChromeCanary
+ // - Firefox
+ // - Opera
+ // - Safari (only Mac)
+ // - PhantomJS
+ // - IE (only Windows)
+ // CLI --browsers Chrome,Firefox,Safari
+ browsers : ['Firefox'],
+
+ // If browser does not capture in given timeout [ms], kill it
+ // CLI --capture-timeout 5000
+ captureTimeout : 5000,
+
+ // Auto run tests on start (when browsers are captured) and exit
+ // CLI --single-run --no-single-run
+ singleRun : true,
+
+ // report which specs are slower than 500ms
+ // CLI --report-slower-than 500
+ reportSlowerThan : 1000,
+
+ preprocessors : {
+ // '**/client/js/*.js': 'coverage'
+ },
+
+ plugins : [
+ 'karma-mocha',
+ // 'karma-chrome-launcher',
+ 'karma-firefox-launcher',
+ // 'karma-phantomjs-launcher'
+ ]
+ });
+};
diff --git a/test/lib/pixi/core/Matrix.js b/test/lib/pixi/core/Matrix.js
new file mode 100644
index 0000000..d26386b
--- /dev/null
+++ b/test/lib/pixi/core/Matrix.js
@@ -0,0 +1,40 @@
+
+function pixi_core_Matrix_confirmNewMat3(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(1);
+ expect(matrix[5]).to.equal(0);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(1);
+}
+
+function pixi_core_Matrix_confirmNewMat4(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[0]).to.equal(1);
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(0);
+ expect(matrix[5]).to.equal(1);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(0);
+ expect(matrix[9]).to.equal(0);
+ expect(matrix[10]).to.equal(1);
+ expect(matrix[11]).to.equal(0);
+ expect(matrix[12]).to.equal(0);
+ expect(matrix[13]).to.equal(0);
+ expect(matrix[14]).to.equal(0);
+ expect(matrix[15]).to.equal(1);
+}
diff --git a/test/lib/pixi/core/Point.js b/test/lib/pixi/core/Point.js
new file mode 100644
index 0000000..e5df07b
--- /dev/null
+++ b/test/lib/pixi/core/Point.js
@@ -0,0 +1,10 @@
+
+function pixi_core_Point_confirm(obj, x, y) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Point);
+ expect(obj).to.respondTo('clone');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+}
diff --git a/test/lib/pixi/core/Rectangle.js b/test/lib/pixi/core/Rectangle.js
new file mode 100644
index 0000000..23f0d12
--- /dev/null
+++ b/test/lib/pixi/core/Rectangle.js
@@ -0,0 +1,13 @@
+
+function pixi_core_Rectangle_confirm(obj, x, y, width, height) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Rectangle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+ expect(obj).to.have.property('width', width);
+ expect(obj).to.have.property('height', height);
+}
diff --git a/test/lib/pixi/display/DisplayObject.js b/test/lib/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..1388a7f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObject.js
@@ -0,0 +1,43 @@
+
+function pixi_display_DisplayObject_confirmNew(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObject);
+ expect(obj).to.respondTo('setInteractive');
+ expect(obj).to.respondTo('addFilter');
+ expect(obj).to.respondTo('removeFilter');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.property('last', obj);
+ expect(obj).to.have.property('first', obj);
+
+ expect(obj).to.contain.property('position');
+ pixi_core_Point_confirm(obj.position, 0, 0);
+ expect(obj).to.contain.property('scale');
+ pixi_core_Point_confirm(obj.scale, 1, 1);
+ expect(obj).to.contain.property('pivot');
+ pixi_core_Point_confirm(obj.pivot, 0, 0);
+
+ expect(obj).to.have.property('rotation', 0);
+ expect(obj).to.have.property('alpha', 1);
+ expect(obj).to.have.property('visible', true);
+ expect(obj).to.have.property('buttonMode', false);
+ expect(obj).to.have.property('parent', null);
+ expect(obj).to.have.property('worldAlpha', 1);
+
+ expect(obj).to.have.property('hitArea');
+ expect(obj).to.have.property('interactive'); // TODO: Have a better default value
+ expect('mask' in obj).to.be.true; // TODO: Have a better default value
+ expect(obj.mask).to.be.undefined;
+
+ expect(obj).to.have.property('renderable');
+ expect(obj).to.have.property('stage');
+
+ expect(obj).to.have.deep.property('worldTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ expect(obj).to.have.deep.property('localTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.localTransform);
+
+ expect(obj).to.have.deep.property('color.length', 0);
+ expect(obj).to.have.property('dynamic', true);
+}
diff --git a/test/lib/pixi/display/DisplayObjectContainer.js b/test/lib/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..085c59f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,16 @@
+
+function pixi_display_DisplayObjectContainer_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObject_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObjectContainer);
+ expect(obj).to.respondTo('addChild');
+ expect(obj).to.respondTo('addChildAt');
+ expect(obj).to.respondTo('swapChildren');
+ expect(obj).to.respondTo('getChildAt');
+ expect(obj).to.respondTo('removeChild');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('children.length', 0);
+}
diff --git a/test/lib/pixi/display/Sprite.js b/test/lib/pixi/display/Sprite.js
new file mode 100644
index 0000000..cc7a2d6
--- /dev/null
+++ b/test/lib/pixi/display/Sprite.js
@@ -0,0 +1,28 @@
+
+function pixi_display_Sprite_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Sprite);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', true);
+ expect(obj).to.have.property('stage', null);
+
+ expect(obj).to.have.property('anchor');
+ pixi_core_Point_confirm(obj.anchor, 0, 0);
+
+ expect(obj).to.have.property('blendMode', PIXI.blendModes.NORMAL);
+ expect(obj).to.have.property('width', 1); // TODO: is 1 expected
+ expect(obj).to.have.property('height', 1); // TODO: is 1 expected
+
+ // FIXME: Just make this a boolean that is always there
+ expect(!!obj.updateFrame).to.equal(obj.texture.baseTexture.hasLoaded);
+
+ expect(obj).to.have.property('texture');
+ pixi_textures_Texture_confirmNew(obj.texture, done);
+}
diff --git a/test/lib/pixi/extras/Strip.js b/test/lib/pixi/extras/Strip.js
new file mode 100644
index 0000000..8927a8a
--- /dev/null
+++ b/test/lib/pixi/extras/Strip.js
@@ -0,0 +1,12 @@
+
+function pixi_extras_Strip_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Strip);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ // TODO: Test properties
+}
diff --git a/test/lib/pixi/textures/Texture.js b/test/lib/pixi/textures/Texture.js
new file mode 100644
index 0000000..d5867b6
--- /dev/null
+++ b/test/lib/pixi/textures/Texture.js
@@ -0,0 +1,31 @@
+
+function pixi_textures_Texture_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ function confirmFrameDone() {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, obj.baseTexture.width, obj.baseTexture.height);
+
+ expect(obj).to.have.property('width', obj.baseTexture.width);
+ expect(obj).to.have.property('height', obj.baseTexture.height);
+ done();
+ }
+
+ expect(obj).to.be.an.instanceof(PIXI.Texture);
+ pixi_utils_EventTarget_like(obj);
+
+ expect(obj).to.have.property('baseTexture')
+ .and.to.be.an.instanceof(PIXI.BaseTexture);
+
+ expect(obj).to.have.property('scope', obj);
+
+ expect(obj).to.have.property('trim');
+ pixi_core_Point_confirm(obj.trim, 0, 0);
+
+ expect(obj).to.have.property('frame');
+ if (obj.baseTexture.hasLoaded) {
+ confirmFrameDone();
+ } else {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, 1, 1);
+ obj.addEventListener('update', confirmFrameDone);
+ }
+}
diff --git a/test/lib/pixi/utils/EventTarget.js b/test/lib/pixi/utils/EventTarget.js
new file mode 100644
index 0000000..7b1dcfa
--- /dev/null
+++ b/test/lib/pixi/utils/EventTarget.js
@@ -0,0 +1,8 @@
+
+function pixi_utils_EventTarget_like(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.respondTo('addEventListener');
+ expect(obj).to.respondTo('dispatchEvent');
+ expect(obj).to.respondTo('removeEventListener');
+}
diff --git a/test/lib/qunit-1.11.0.css b/test/lib/qunit-1.11.0.css
deleted file mode 100644
index d7fc0c8..0000000
--- a/test/lib/qunit-1.11.0.css
+++ /dev/null
@@ -1,244 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-/** Font Family and Sizes */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
- font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
-}
-
-#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
-#qunit-tests { font-size: smaller; }
-
-
-/** Resets */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter {
- margin: 0;
- padding: 0;
-}
-
-
-/** Header */
-
-#qunit-header {
- padding: 0.5em 0 0.5em 1em;
-
- color: #8699a4;
- background-color: #0d3349;
-
- font-size: 1.5em;
- line-height: 1em;
- font-weight: normal;
-
- border-radius: 5px 5px 0 0;
- -moz-border-radius: 5px 5px 0 0;
- -webkit-border-top-right-radius: 5px;
- -webkit-border-top-left-radius: 5px;
-}
-
-#qunit-header a {
- text-decoration: none;
- color: #c2ccd1;
-}
-
-#qunit-header a:hover,
-#qunit-header a:focus {
- color: #fff;
-}
-
-#qunit-testrunner-toolbar label {
- display: inline-block;
- padding: 0 .5em 0 .1em;
-}
-
-#qunit-banner {
- height: 5px;
-}
-
-#qunit-testrunner-toolbar {
- padding: 0.5em 0 0.5em 2em;
- color: #5E740B;
- background-color: #eee;
- overflow: hidden;
-}
-
-#qunit-userAgent {
- padding: 0.5em 0 0.5em 2.5em;
- background-color: #2b81af;
- color: #fff;
- text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
-}
-
-#qunit-modulefilter-container {
- float: right;
-}
-
-/** Tests: Pass/Fail */
-
-#qunit-tests {
- list-style-position: inside;
-}
-
-#qunit-tests li {
- padding: 0.4em 0.5em 0.4em 2.5em;
- border-bottom: 1px solid #fff;
- list-style-position: inside;
-}
-
-#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running {
- display: none;
-}
-
-#qunit-tests li strong {
- cursor: pointer;
-}
-
-#qunit-tests li a {
- padding: 0.5em;
- color: #c2ccd1;
- text-decoration: none;
-}
-#qunit-tests li a:hover,
-#qunit-tests li a:focus {
- color: #000;
-}
-
-#qunit-tests li .runtime {
- float: right;
- font-size: smaller;
-}
-
-.qunit-assert-list {
- margin-top: 0.5em;
- padding: 0.5em;
-
- background-color: #fff;
-
- border-radius: 5px;
- -moz-border-radius: 5px;
- -webkit-border-radius: 5px;
-}
-
-.qunit-collapsed {
- display: none;
-}
-
-#qunit-tests table {
- border-collapse: collapse;
- margin-top: .2em;
-}
-
-#qunit-tests th {
- text-align: right;
- vertical-align: top;
- padding: 0 .5em 0 0;
-}
-
-#qunit-tests td {
- vertical-align: top;
-}
-
-#qunit-tests pre {
- margin: 0;
- white-space: pre-wrap;
- word-wrap: break-word;
-}
-
-#qunit-tests del {
- background-color: #e0f2be;
- color: #374e0c;
- text-decoration: none;
-}
-
-#qunit-tests ins {
- background-color: #ffcaca;
- color: #500;
- text-decoration: none;
-}
-
-/*** Test Counts */
-
-#qunit-tests b.counts { color: black; }
-#qunit-tests b.passed { color: #5E740B; }
-#qunit-tests b.failed { color: #710909; }
-
-#qunit-tests li li {
- padding: 5px;
- background-color: #fff;
- border-bottom: none;
- list-style-position: inside;
-}
-
-/*** Passing Styles */
-
-#qunit-tests li li.pass {
- color: #3c510c;
- background-color: #fff;
- border-left: 10px solid #C6E746;
-}
-
-#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
-#qunit-tests .pass .test-name { color: #366097; }
-
-#qunit-tests .pass .test-actual,
-#qunit-tests .pass .test-expected { color: #999999; }
-
-#qunit-banner.qunit-pass { background-color: #C6E746; }
-
-/*** Failing Styles */
-
-#qunit-tests li li.fail {
- color: #710909;
- background-color: #fff;
- border-left: 10px solid #EE5757;
- white-space: pre;
-}
-
-#qunit-tests > li:last-child {
- border-radius: 0 0 5px 5px;
- -moz-border-radius: 0 0 5px 5px;
- -webkit-border-bottom-right-radius: 5px;
- -webkit-border-bottom-left-radius: 5px;
-}
-
-#qunit-tests .fail { color: #000000; background-color: #EE5757; }
-#qunit-tests .fail .test-name,
-#qunit-tests .fail .module-name { color: #000000; }
-
-#qunit-tests .fail .test-actual { color: #EE5757; }
-#qunit-tests .fail .test-expected { color: green; }
-
-#qunit-banner.qunit-fail { background-color: #EE5757; }
-
-
-/** Result */
-
-#qunit-testresult {
- padding: 0.5em 0.5em 0.5em 2.5em;
-
- color: #2b81af;
- background-color: #D2E0E6;
-
- border-bottom: 1px solid white;
-}
-#qunit-testresult .module-name {
- font-weight: bold;
-}
-
-/** Fixture */
-
-#qunit-fixture {
- position: absolute;
- top: -10000px;
- left: -10000px;
- width: 1000px;
- height: 1000px;
-}
diff --git a/test/lib/qunit-1.11.0.js b/test/lib/qunit-1.11.0.js
deleted file mode 100644
index 302545f..0000000
--- a/test/lib/qunit-1.11.0.js
+++ /dev/null
@@ -1,2152 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-(function( window ) {
-
-var QUnit,
- assert,
- config,
- onErrorFnPrev,
- testId = 0,
- fileName = (sourceFromStacktrace( 0 ) || "" ).replace(/(:\d+)+\)?/, "").replace(/.+\//, ""),
- toString = Object.prototype.toString,
- hasOwn = Object.prototype.hasOwnProperty,
- // Keep a local reference to Date (GH-283)
- Date = window.Date,
- defined = {
- setTimeout: typeof window.setTimeout !== "undefined",
- sessionStorage: (function() {
- var x = "qunit-test-string";
- try {
- sessionStorage.setItem( x, x );
- sessionStorage.removeItem( x );
- return true;
- } catch( e ) {
- return false;
- }
- }())
- },
- /**
- * Provides a normalized error string, correcting an issue
- * with IE 7 (and prior) where Error.prototype.toString is
- * not properly implemented
- *
- * Based on http://es5.github.com/#x15.11.4.4
- *
- * @param {String|Error} error
- * @return {String} error message
- */
- errorString = function( error ) {
- var name, message,
- errorString = error.toString();
- if ( errorString.substring( 0, 7 ) === "[object" ) {
- name = error.name ? error.name.toString() : "Error";
- message = error.message ? error.message.toString() : "";
- if ( name && message ) {
- return name + ": " + message;
- } else if ( name ) {
- return name;
- } else if ( message ) {
- return message;
- } else {
- return "Error";
- }
- } else {
- return errorString;
- }
- },
- /**
- * Makes a clone of an object using only Array or Object as base,
- * and copies over the own enumerable properties.
- *
- * @param {Object} obj
- * @return {Object} New object with only the own properties (recursively).
- */
- objectValues = function( obj ) {
- // Grunt 0.3.x uses an older version of jshint that still has jshint/jshint#392.
- /*jshint newcap: false */
- var key, val,
- vals = QUnit.is( "array", obj ) ? [] : {};
- for ( key in obj ) {
- if ( hasOwn.call( obj, key ) ) {
- val = obj[key];
- vals[key] = val === Object(val) ? objectValues(val) : val;
- }
- }
- return vals;
- };
-
-function Test( settings ) {
- extend( this, settings );
- this.assertions = [];
- this.testNumber = ++Test.count;
-}
-
-Test.count = 0;
-
-Test.prototype = {
- init: function() {
- var a, b, li,
- tests = id( "qunit-tests" );
-
- if ( tests ) {
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml;
-
- // `a` initialized at top of scope
- a = document.createElement( "a" );
- a.innerHTML = "Rerun";
- a.href = QUnit.url({ testNumber: this.testNumber });
-
- li = document.createElement( "li" );
- li.appendChild( b );
- li.appendChild( a );
- li.className = "running";
- li.id = this.id = "qunit-test-output" + testId++;
-
- tests.appendChild( li );
- }
- },
- setup: function() {
- if ( this.module !== config.previousModule ) {
- if ( config.previousModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.previousModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
- config.previousModule = this.module;
- config.moduleStats = { all: 0, bad: 0 };
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- } else if ( config.autorun ) {
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- }
-
- config.current = this;
-
- this.testEnvironment = extend({
- setup: function() {},
- teardown: function() {}
- }, this.moduleTestEnvironment );
-
- this.started = +new Date();
- runLoggingCallbacks( "testStart", QUnit, {
- name: this.testName,
- module: this.module
- });
-
- // allow utility functions to access the current test environment
- // TODO why??
- QUnit.current_testEnvironment = this.testEnvironment;
-
- if ( !config.pollution ) {
- saveGlobal();
- }
- if ( config.notrycatch ) {
- this.testEnvironment.setup.call( this.testEnvironment );
- return;
- }
- try {
- this.testEnvironment.setup.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Setup failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- },
- run: function() {
- config.current = this;
-
- var running = id( "qunit-testresult" );
-
- if ( running ) {
- running.innerHTML = "Running:
" + this.nameHtml;
- }
-
- if ( this.async ) {
- QUnit.stop();
- }
-
- this.callbackStarted = +new Date();
-
- if ( config.notrycatch ) {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- return;
- }
-
- try {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- } catch( e ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
-
- QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + " " + this.stack + ": " + ( e.message || e ), extractStacktrace( e, 0 ) );
- // else next test will carry the responsibility
- saveGlobal();
-
- // Restart the tests if they're blocking
- if ( config.blocking ) {
- QUnit.start();
- }
- }
- },
- teardown: function() {
- config.current = this;
- if ( config.notrycatch ) {
- if ( typeof this.callbackRuntime === "undefined" ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
- }
- this.testEnvironment.teardown.call( this.testEnvironment );
- return;
- } else {
- try {
- this.testEnvironment.teardown.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Teardown failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- }
- checkPollution();
- },
- finish: function() {
- config.current = this;
- if ( config.requireExpects && this.expected === null ) {
- QUnit.pushFailure( "Expected number of assertions to be defined, but expect() was not called.", this.stack );
- } else if ( this.expected !== null && this.expected !== this.assertions.length ) {
- QUnit.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack );
- } else if ( this.expected === null && !this.assertions.length ) {
- QUnit.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions.", this.stack );
- }
-
- var i, assertion, a, b, time, li, ol,
- test = this,
- good = 0,
- bad = 0,
- tests = id( "qunit-tests" );
-
- this.runtime = +new Date() - this.started;
- config.stats.all += this.assertions.length;
- config.moduleStats.all += this.assertions.length;
-
- if ( tests ) {
- ol = document.createElement( "ol" );
- ol.className = "qunit-assert-list";
-
- for ( i = 0; i < this.assertions.length; i++ ) {
- assertion = this.assertions[i];
-
- li = document.createElement( "li" );
- li.className = assertion.result ? "pass" : "fail";
- li.innerHTML = assertion.message || ( assertion.result ? "okay" : "failed" );
- ol.appendChild( li );
-
- if ( assertion.result ) {
- good++;
- } else {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
-
- // store result when possible
- if ( QUnit.config.reorder && defined.sessionStorage ) {
- if ( bad ) {
- sessionStorage.setItem( "qunit-test-" + this.module + "-" + this.testName, bad );
- } else {
- sessionStorage.removeItem( "qunit-test-" + this.module + "-" + this.testName );
- }
- }
-
- if ( bad === 0 ) {
- addClass( ol, "qunit-collapsed" );
- }
-
- // `b` initialized at top of scope
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml + " (" + bad + ", " + good + ", " + this.assertions.length + ")";
-
- addEvent(b, "click", function() {
- var next = b.parentNode.lastChild,
- collapsed = hasClass( next, "qunit-collapsed" );
- ( collapsed ? removeClass : addClass )( next, "qunit-collapsed" );
- });
-
- addEvent(b, "dblclick", function( e ) {
- var target = e && e.target ? e.target : window.event.srcElement;
- if ( target.nodeName.toLowerCase() === "span" || target.nodeName.toLowerCase() === "b" ) {
- target = target.parentNode;
- }
- if ( window.location && target.nodeName.toLowerCase() === "strong" ) {
- window.location = QUnit.url({ testNumber: test.testNumber });
- }
- });
-
- // `time` initialized at top of scope
- time = document.createElement( "span" );
- time.className = "runtime";
- time.innerHTML = this.runtime + " ms";
-
- // `li` initialized at top of scope
- li = id( this.id );
- li.className = bad ? "fail" : "pass";
- li.removeChild( li.firstChild );
- a = li.firstChild;
- li.appendChild( b );
- li.appendChild( a );
- li.appendChild( time );
- li.appendChild( ol );
-
- } else {
- for ( i = 0; i < this.assertions.length; i++ ) {
- if ( !this.assertions[i].result ) {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
- }
-
- runLoggingCallbacks( "testDone", QUnit, {
- name: this.testName,
- module: this.module,
- failed: bad,
- passed: this.assertions.length - bad,
- total: this.assertions.length,
- duration: this.runtime
- });
-
- QUnit.reset();
-
- config.current = undefined;
- },
-
- queue: function() {
- var bad,
- test = this;
-
- synchronize(function() {
- test.init();
- });
- function run() {
- // each of these can by async
- synchronize(function() {
- test.setup();
- });
- synchronize(function() {
- test.run();
- });
- synchronize(function() {
- test.teardown();
- });
- synchronize(function() {
- test.finish();
- });
- }
-
- // `bad` initialized at top of scope
- // defer when previous test run passed, if storage is available
- bad = QUnit.config.reorder && defined.sessionStorage &&
- +sessionStorage.getItem( "qunit-test-" + this.module + "-" + this.testName );
-
- if ( bad ) {
- run();
- } else {
- synchronize( run, true );
- }
- }
-};
-
-// Root QUnit object.
-// `QUnit` initialized at top of scope
-QUnit = {
-
- // call on start of module test to prepend name to all tests
- module: function( name, testEnvironment ) {
- config.currentModule = name;
- config.currentModuleTestEnvironment = testEnvironment;
- config.modules[name] = true;
- },
-
- asyncTest: function( testName, expected, callback ) {
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- QUnit.test( testName, expected, callback, true );
- },
-
- test: function( testName, expected, callback, async ) {
- var test,
- nameHtml = "" + escapeText( testName ) + "";
-
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- if ( config.currentModule ) {
- nameHtml = "" + escapeText( config.currentModule ) + ": " + nameHtml;
- }
-
- test = new Test({
- nameHtml: nameHtml,
- testName: testName,
- expected: expected,
- async: async,
- callback: callback,
- module: config.currentModule,
- moduleTestEnvironment: config.currentModuleTestEnvironment,
- stack: sourceFromStacktrace( 2 )
- });
-
- if ( !validTest( test ) ) {
- return;
- }
-
- test.queue();
- },
-
- // Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through.
- expect: function( asserts ) {
- if (arguments.length === 1) {
- config.current.expected = asserts;
- } else {
- return config.current.expected;
- }
- },
-
- start: function( count ) {
- // QUnit hasn't been initialized yet.
- // Note: RequireJS (et al) may delay onLoad
- if ( config.semaphore === undefined ) {
- QUnit.begin(function() {
- // This is triggered at the top of QUnit.load, push start() to the event loop, to allow QUnit.load to finish first
- setTimeout(function() {
- QUnit.start( count );
- });
- });
- return;
- }
-
- config.semaphore -= count || 1;
- // don't start until equal number of stop-calls
- if ( config.semaphore > 0 ) {
- return;
- }
- // ignore if start is called more often then stop
- if ( config.semaphore < 0 ) {
- config.semaphore = 0;
- QUnit.pushFailure( "Called start() while already started (QUnit.config.semaphore was 0 already)", null, sourceFromStacktrace(2) );
- return;
- }
- // A slight delay, to avoid any current callbacks
- if ( defined.setTimeout ) {
- window.setTimeout(function() {
- if ( config.semaphore > 0 ) {
- return;
- }
- if ( config.timeout ) {
- clearTimeout( config.timeout );
- }
-
- config.blocking = false;
- process( true );
- }, 13);
- } else {
- config.blocking = false;
- process( true );
- }
- },
-
- stop: function( count ) {
- config.semaphore += count || 1;
- config.blocking = true;
-
- if ( config.testTimeout && defined.setTimeout ) {
- clearTimeout( config.timeout );
- config.timeout = window.setTimeout(function() {
- QUnit.ok( false, "Test timed out" );
- config.semaphore = 1;
- QUnit.start();
- }, config.testTimeout );
- }
- }
-};
-
-// `assert` initialized at top of scope
-// Asssert helpers
-// All of these must either call QUnit.push() or manually do:
-// - runLoggingCallbacks( "log", .. );
-// - config.current.assertions.push({ .. });
-// We attach it to the QUnit object *after* we expose the public API,
-// otherwise `assert` will become a global variable in browsers (#341).
-assert = {
- /**
- * Asserts rough true-ish result.
- * @name ok
- * @function
- * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" );
- */
- ok: function( result, msg ) {
- if ( !config.current ) {
- throw new Error( "ok() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
- result = !!result;
-
- var source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: msg
- };
-
- msg = escapeText( msg || (result ? "okay" : "failed" ) );
- msg = "" + msg + "";
-
- if ( !result ) {
- source = sourceFromStacktrace( 2 );
- if ( source ) {
- details.source = source;
- msg += "Source: | " + escapeText( source ) + " |
---|
";
- }
- }
- runLoggingCallbacks( "log", QUnit, details );
- config.current.assertions.push({
- result: result,
- message: msg
- });
- },
-
- /**
- * Assert that the first two arguments are equal, with an optional message.
- * Prints out both actual and expected values.
- * @name equal
- * @function
- * @example equal( format( "Received {0} bytes.", 2), "Received 2 bytes.", "format() replaces {0} with next argument" );
- */
- equal: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected == actual, actual, expected, message );
- },
-
- /**
- * @name notEqual
- * @function
- */
- notEqual: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected != actual, actual, expected, message );
- },
-
- /**
- * @name propEqual
- * @function
- */
- propEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notPropEqual
- * @function
- */
- notPropEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name deepEqual
- * @function
- */
- deepEqual: function( actual, expected, message ) {
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notDeepEqual
- * @function
- */
- notDeepEqual: function( actual, expected, message ) {
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name strictEqual
- * @function
- */
- strictEqual: function( actual, expected, message ) {
- QUnit.push( expected === actual, actual, expected, message );
- },
-
- /**
- * @name notStrictEqual
- * @function
- */
- notStrictEqual: function( actual, expected, message ) {
- QUnit.push( expected !== actual, actual, expected, message );
- },
-
- "throws": function( block, expected, message ) {
- var actual,
- expectedOutput = expected,
- ok = false;
-
- // 'expected' is optional
- if ( typeof expected === "string" ) {
- message = expected;
- expected = null;
- }
-
- config.current.ignoreGlobalErrors = true;
- try {
- block.call( config.current.testEnvironment );
- } catch (e) {
- actual = e;
- }
- config.current.ignoreGlobalErrors = false;
-
- if ( actual ) {
- // we don't want to validate thrown error
- if ( !expected ) {
- ok = true;
- expectedOutput = null;
- // expected is a regexp
- } else if ( QUnit.objectType( expected ) === "regexp" ) {
- ok = expected.test( errorString( actual ) );
- // expected is a constructor
- } else if ( actual instanceof expected ) {
- ok = true;
- // expected is a validation function which returns true is validation passed
- } else if ( expected.call( {}, actual ) === true ) {
- expectedOutput = null;
- ok = true;
- }
-
- QUnit.push( ok, actual, expectedOutput, message );
- } else {
- QUnit.pushFailure( message, null, 'No exception was thrown.' );
- }
- }
-};
-
-/**
- * @deprecate since 1.8.0
- * Kept assertion helpers in root for backwards compatibility.
- */
-extend( QUnit, assert );
-
-/**
- * @deprecated since 1.9.0
- * Kept root "raises()" for backwards compatibility.
- * (Note that we don't introduce assert.raises).
- */
-QUnit.raises = assert[ "throws" ];
-
-/**
- * @deprecated since 1.0.0, replaced with error pushes since 1.3.0
- * Kept to avoid TypeErrors for undefined methods.
- */
-QUnit.equals = function() {
- QUnit.push( false, false, false, "QUnit.equals has been deprecated since 2009 (e88049a0), use QUnit.equal instead" );
-};
-QUnit.same = function() {
- QUnit.push( false, false, false, "QUnit.same has been deprecated since 2009 (e88049a0), use QUnit.deepEqual instead" );
-};
-
-// We want access to the constructor's prototype
-(function() {
- function F() {}
- F.prototype = QUnit;
- QUnit = new F();
- // Make F QUnit's constructor so that we can add to the prototype later
- QUnit.constructor = F;
-}());
-
-/**
- * Config object: Maintain internal state
- * Later exposed as QUnit.config
- * `config` initialized at top of scope
- */
-config = {
- // The queue of tests to run
- queue: [],
-
- // block until document ready
- blocking: true,
-
- // when enabled, show only failing tests
- // gets persisted through sessionStorage and can be changed in UI via checkbox
- hidepassed: false,
-
- // by default, run previously failed tests first
- // very useful in combination with "Hide passed tests" checked
- reorder: true,
-
- // by default, modify document.title when suite is done
- altertitle: true,
-
- // when enabled, all tests must call expect()
- requireExpects: false,
-
- // add checkboxes that are persisted in the query-string
- // when enabled, the id is set to `true` as a `QUnit.config` property
- urlConfig: [
- {
- id: "noglobals",
- label: "Check for Globals",
- tooltip: "Enabling this will test if any test introduces new properties on the `window` object. Stored as query-strings."
- },
- {
- id: "notrycatch",
- label: "No try-catch",
- tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging exceptions in IE reasonable. Stored as query-strings."
- }
- ],
-
- // Set of all modules.
- modules: {},
-
- // logging callback queues
- begin: [],
- done: [],
- log: [],
- testStart: [],
- testDone: [],
- moduleStart: [],
- moduleDone: []
-};
-
-// Export global variables, unless an 'exports' object exists,
-// in that case we assume we're in CommonJS (dealt with on the bottom of the script)
-if ( typeof exports === "undefined" ) {
- extend( window, QUnit );
-
- // Expose QUnit object
- window.QUnit = QUnit;
-}
-
-// Initialize more QUnit.config and QUnit.urlParams
-(function() {
- var i,
- location = window.location || { search: "", protocol: "file:" },
- params = location.search.slice( 1 ).split( "&" ),
- length = params.length,
- urlParams = {},
- current;
-
- if ( params[ 0 ] ) {
- for ( i = 0; i < length; i++ ) {
- current = params[ i ].split( "=" );
- current[ 0 ] = decodeURIComponent( current[ 0 ] );
- // allow just a key to turn on a flag, e.g., test.html?noglobals
- current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true;
- urlParams[ current[ 0 ] ] = current[ 1 ];
- }
- }
-
- QUnit.urlParams = urlParams;
-
- // String search anywhere in moduleName+testName
- config.filter = urlParams.filter;
-
- // Exact match of the module name
- config.module = urlParams.module;
-
- config.testNumber = parseInt( urlParams.testNumber, 10 ) || null;
-
- // Figure out if we're running the tests from a server or not
- QUnit.isLocal = location.protocol === "file:";
-}());
-
-// Extend QUnit object,
-// these after set here because they should not be exposed as global functions
-extend( QUnit, {
- assert: assert,
-
- config: config,
-
- // Initialize the configuration options
- init: function() {
- extend( config, {
- stats: { all: 0, bad: 0 },
- moduleStats: { all: 0, bad: 0 },
- started: +new Date(),
- updateRate: 1000,
- blocking: false,
- autostart: true,
- autorun: false,
- filter: "",
- queue: [],
- semaphore: 1
- });
-
- var tests, banner, result,
- qunit = id( "qunit" );
-
- if ( qunit ) {
- qunit.innerHTML =
- "" +
- "" +
- "" +
- "" +
- "
";
- }
-
- tests = id( "qunit-tests" );
- banner = id( "qunit-banner" );
- result = id( "qunit-testresult" );
-
- if ( tests ) {
- tests.innerHTML = "";
- }
-
- if ( banner ) {
- banner.className = "";
- }
-
- if ( result ) {
- result.parentNode.removeChild( result );
- }
-
- if ( tests ) {
- result = document.createElement( "p" );
- result.id = "qunit-testresult";
- result.className = "result";
- tests.parentNode.insertBefore( result, tests );
- result.innerHTML = "Running...
";
- }
- },
-
- // Resets the test setup. Useful for tests that modify the DOM.
- reset: function() {
- var fixture = id( "qunit-fixture" );
- if ( fixture ) {
- fixture.innerHTML = config.fixture;
- }
- },
-
- // Trigger an event on an element.
- // @example triggerEvent( document.body, "click" );
- triggerEvent: function( elem, type, event ) {
- if ( document.createEvent ) {
- event = document.createEvent( "MouseEvents" );
- event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView,
- 0, 0, 0, 0, 0, false, false, false, false, 0, null);
-
- elem.dispatchEvent( event );
- } else if ( elem.fireEvent ) {
- elem.fireEvent( "on" + type );
- }
- },
-
- // Safe object type checking
- is: function( type, obj ) {
- return QUnit.objectType( obj ) === type;
- },
-
- objectType: function( obj ) {
- if ( typeof obj === "undefined" ) {
- return "undefined";
- // consider: typeof null === object
- }
- if ( obj === null ) {
- return "null";
- }
-
- var match = toString.call( obj ).match(/^\[object\s(.*)\]$/),
- type = match && match[1] || "";
-
- switch ( type ) {
- case "Number":
- if ( isNaN(obj) ) {
- return "nan";
- }
- return "number";
- case "String":
- case "Boolean":
- case "Array":
- case "Date":
- case "RegExp":
- case "Function":
- return type.toLowerCase();
- }
- if ( typeof obj === "object" ) {
- return "object";
- }
- return undefined;
- },
-
- push: function( result, actual, expected, message ) {
- if ( !config.current ) {
- throw new Error( "assertion outside test context, was " + sourceFromStacktrace() );
- }
-
- var output, source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: message,
- actual: actual,
- expected: expected
- };
-
- message = escapeText( message ) || ( result ? "okay" : "failed" );
- message = "" + message + "";
- output = message;
-
- if ( !result ) {
- expected = escapeText( QUnit.jsDump.parse(expected) );
- actual = escapeText( QUnit.jsDump.parse(actual) );
- output += "Expected: | " + expected + " |
";
-
- if ( actual !== expected ) {
- output += "Result: | " + actual + " |
";
- output += "Diff: | " + QUnit.diff( expected, actual ) + " |
";
- }
-
- source = sourceFromStacktrace();
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
- }
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: !!result,
- message: output
- });
- },
-
- pushFailure: function( message, source, actual ) {
- if ( !config.current ) {
- throw new Error( "pushFailure() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
-
- var output,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: false,
- message: message
- };
-
- message = escapeText( message ) || "error";
- message = "" + message + "";
- output = message;
-
- output += "";
-
- if ( actual ) {
- output += "Result: | " + escapeText( actual ) + " |
";
- }
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: false,
- message: output
- });
- },
-
- url: function( params ) {
- params = extend( extend( {}, QUnit.urlParams ), params );
- var key,
- querystring = "?";
-
- for ( key in params ) {
- if ( !hasOwn.call( params, key ) ) {
- continue;
- }
- querystring += encodeURIComponent( key ) + "=" +
- encodeURIComponent( params[ key ] ) + "&";
- }
- return window.location.protocol + "//" + window.location.host +
- window.location.pathname + querystring.slice( 0, -1 );
- },
-
- extend: extend,
- id: id,
- addEvent: addEvent
- // load, equiv, jsDump, diff: Attached later
-});
-
-/**
- * @deprecated: Created for backwards compatibility with test runner that set the hook function
- * into QUnit.{hook}, instead of invoking it and passing the hook function.
- * QUnit.constructor is set to the empty F() above so that we can add to it's prototype here.
- * Doing this allows us to tell if the following methods have been overwritten on the actual
- * QUnit object.
- */
-extend( QUnit.constructor.prototype, {
-
- // Logging callbacks; all receive a single argument with the listed properties
- // run test/logs.html for any related changes
- begin: registerLoggingCallback( "begin" ),
-
- // done: { failed, passed, total, runtime }
- done: registerLoggingCallback( "done" ),
-
- // log: { result, actual, expected, message }
- log: registerLoggingCallback( "log" ),
-
- // testStart: { name }
- testStart: registerLoggingCallback( "testStart" ),
-
- // testDone: { name, failed, passed, total, duration }
- testDone: registerLoggingCallback( "testDone" ),
-
- // moduleStart: { name }
- moduleStart: registerLoggingCallback( "moduleStart" ),
-
- // moduleDone: { name, failed, passed, total }
- moduleDone: registerLoggingCallback( "moduleDone" )
-});
-
-if ( typeof document === "undefined" || document.readyState === "complete" ) {
- config.autorun = true;
-}
-
-QUnit.load = function() {
- runLoggingCallbacks( "begin", QUnit, {} );
-
- // Initialize the config, saving the execution queue
- var banner, filter, i, label, len, main, ol, toolbar, userAgent, val,
- urlConfigCheckboxesContainer, urlConfigCheckboxes, moduleFilter,
- numModules = 0,
- moduleFilterHtml = "",
- urlConfigHtml = "",
- oldconfig = extend( {}, config );
-
- QUnit.init();
- extend(config, oldconfig);
-
- config.blocking = false;
-
- len = config.urlConfig.length;
-
- for ( i = 0; i < len; i++ ) {
- val = config.urlConfig[i];
- if ( typeof val === "string" ) {
- val = {
- id: val,
- label: val,
- tooltip: "[no tooltip available]"
- };
- }
- config[ val.id ] = QUnit.urlParams[ val.id ];
- urlConfigHtml += "";
- }
-
- moduleFilterHtml += "";
-
- // `userAgent` initialized at top of scope
- userAgent = id( "qunit-userAgent" );
- if ( userAgent ) {
- userAgent.innerHTML = navigator.userAgent;
- }
-
- // `banner` initialized at top of scope
- banner = id( "qunit-header" );
- if ( banner ) {
- banner.innerHTML = "" + banner.innerHTML + " ";
- }
-
- // `toolbar` initialized at top of scope
- toolbar = id( "qunit-testrunner-toolbar" );
- if ( toolbar ) {
- // `filter` initialized at top of scope
- filter = document.createElement( "input" );
- filter.type = "checkbox";
- filter.id = "qunit-filter-pass";
-
- addEvent( filter, "click", function() {
- var tmp,
- ol = document.getElementById( "qunit-tests" );
-
- if ( filter.checked ) {
- ol.className = ol.className + " hidepass";
- } else {
- tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " ";
- ol.className = tmp.replace( / hidepass /, " " );
- }
- if ( defined.sessionStorage ) {
- if (filter.checked) {
- sessionStorage.setItem( "qunit-filter-passed-tests", "true" );
- } else {
- sessionStorage.removeItem( "qunit-filter-passed-tests" );
- }
- }
- });
-
- if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem( "qunit-filter-passed-tests" ) ) {
- filter.checked = true;
- // `ol` initialized at top of scope
- ol = document.getElementById( "qunit-tests" );
- ol.className = ol.className + " hidepass";
- }
- toolbar.appendChild( filter );
-
- // `label` initialized at top of scope
- label = document.createElement( "label" );
- label.setAttribute( "for", "qunit-filter-pass" );
- label.setAttribute( "title", "Only show tests and assertons that fail. Stored in sessionStorage." );
- label.innerHTML = "Hide passed tests";
- toolbar.appendChild( label );
-
- urlConfigCheckboxesContainer = document.createElement("span");
- urlConfigCheckboxesContainer.innerHTML = urlConfigHtml;
- urlConfigCheckboxes = urlConfigCheckboxesContainer.getElementsByTagName("input");
- // For oldIE support:
- // * Add handlers to the individual elements instead of the container
- // * Use "click" instead of "change"
- // * Fallback from event.target to event.srcElement
- addEvents( urlConfigCheckboxes, "click", function( event ) {
- var params = {},
- target = event.target || event.srcElement;
- params[ target.name ] = target.checked ? true : undefined;
- window.location = QUnit.url( params );
- });
- toolbar.appendChild( urlConfigCheckboxesContainer );
-
- if (numModules > 1) {
- moduleFilter = document.createElement( 'span' );
- moduleFilter.setAttribute( 'id', 'qunit-modulefilter-container' );
- moduleFilter.innerHTML = moduleFilterHtml;
- addEvent( moduleFilter.lastChild, "change", function() {
- var selectBox = moduleFilter.getElementsByTagName("select")[0],
- selectedModule = decodeURIComponent(selectBox.options[selectBox.selectedIndex].value);
-
- window.location = QUnit.url( { module: ( selectedModule === "" ) ? undefined : selectedModule } );
- });
- toolbar.appendChild(moduleFilter);
- }
- }
-
- // `main` initialized at top of scope
- main = id( "qunit-fixture" );
- if ( main ) {
- config.fixture = main.innerHTML;
- }
-
- if ( config.autostart ) {
- QUnit.start();
- }
-};
-
-addEvent( window, "load", QUnit.load );
-
-// `onErrorFnPrev` initialized at top of scope
-// Preserve other handlers
-onErrorFnPrev = window.onerror;
-
-// Cover uncaught exceptions
-// Returning true will surpress the default browser handler,
-// returning false will let it run.
-window.onerror = function ( error, filePath, linerNr ) {
- var ret = false;
- if ( onErrorFnPrev ) {
- ret = onErrorFnPrev( error, filePath, linerNr );
- }
-
- // Treat return value as window.onerror itself does,
- // Only do our handling if not surpressed.
- if ( ret !== true ) {
- if ( QUnit.config.current ) {
- if ( QUnit.config.current.ignoreGlobalErrors ) {
- return true;
- }
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- } else {
- QUnit.test( "global failure", extend( function() {
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- }, { validTest: validTest } ) );
- }
- return false;
- }
-
- return ret;
-};
-
-function done() {
- config.autorun = true;
-
- // Log the last module results
- if ( config.currentModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.currentModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
-
- var i, key,
- banner = id( "qunit-banner" ),
- tests = id( "qunit-tests" ),
- runtime = +new Date() - config.started,
- passed = config.stats.all - config.stats.bad,
- html = [
- "Tests completed in ",
- runtime,
- " milliseconds.
",
- "",
- passed,
- " assertions of ",
- config.stats.all,
- " passed, ",
- config.stats.bad,
- " failed."
- ].join( "" );
-
- if ( banner ) {
- banner.className = ( config.stats.bad ? "qunit-fail" : "qunit-pass" );
- }
-
- if ( tests ) {
- id( "qunit-testresult" ).innerHTML = html;
- }
-
- if ( config.altertitle && typeof document !== "undefined" && document.title ) {
- // show ✖ for good, ✔ for bad suite result in title
- // use escape sequences in case file gets loaded with non-utf-8-charset
- document.title = [
- ( config.stats.bad ? "\u2716" : "\u2714" ),
- document.title.replace( /^[\u2714\u2716] /i, "" )
- ].join( " " );
- }
-
- // clear own sessionStorage items if all tests passed
- if ( config.reorder && defined.sessionStorage && config.stats.bad === 0 ) {
- // `key` & `i` initialized at top of scope
- for ( i = 0; i < sessionStorage.length; i++ ) {
- key = sessionStorage.key( i++ );
- if ( key.indexOf( "qunit-test-" ) === 0 ) {
- sessionStorage.removeItem( key );
- }
- }
- }
-
- // scroll back to top to show results
- if ( window.scrollTo ) {
- window.scrollTo(0, 0);
- }
-
- runLoggingCallbacks( "done", QUnit, {
- failed: config.stats.bad,
- passed: passed,
- total: config.stats.all,
- runtime: runtime
- });
-}
-
-/** @return Boolean: true if this test should be ran */
-function validTest( test ) {
- var include,
- filter = config.filter && config.filter.toLowerCase(),
- module = config.module && config.module.toLowerCase(),
- fullName = (test.module + ": " + test.testName).toLowerCase();
-
- // Internally-generated tests are always valid
- if ( test.callback && test.callback.validTest === validTest ) {
- delete test.callback.validTest;
- return true;
- }
-
- if ( config.testNumber ) {
- return test.testNumber === config.testNumber;
- }
-
- if ( module && ( !test.module || test.module.toLowerCase() !== module ) ) {
- return false;
- }
-
- if ( !filter ) {
- return true;
- }
-
- include = filter.charAt( 0 ) !== "!";
- if ( !include ) {
- filter = filter.slice( 1 );
- }
-
- // If the filter matches, we need to honour include
- if ( fullName.indexOf( filter ) !== -1 ) {
- return include;
- }
-
- // Otherwise, do the opposite
- return !include;
-}
-
-// so far supports only Firefox, Chrome and Opera (buggy), Safari (for real exceptions)
-// Later Safari and IE10 are supposed to support error.stack as well
-// See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack
-function extractStacktrace( e, offset ) {
- offset = offset === undefined ? 3 : offset;
-
- var stack, include, i;
-
- if ( e.stacktrace ) {
- // Opera
- return e.stacktrace.split( "\n" )[ offset + 3 ];
- } else if ( e.stack ) {
- // Firefox, Chrome
- stack = e.stack.split( "\n" );
- if (/^error$/i.test( stack[0] ) ) {
- stack.shift();
- }
- if ( fileName ) {
- include = [];
- for ( i = offset; i < stack.length; i++ ) {
- if ( stack[ i ].indexOf( fileName ) !== -1 ) {
- break;
- }
- include.push( stack[ i ] );
- }
- if ( include.length ) {
- return include.join( "\n" );
- }
- }
- return stack[ offset ];
- } else if ( e.sourceURL ) {
- // Safari, PhantomJS
- // hopefully one day Safari provides actual stacktraces
- // exclude useless self-reference for generated Error objects
- if ( /qunit.js$/.test( e.sourceURL ) ) {
- return;
- }
- // for actual exceptions, this is useful
- return e.sourceURL + ":" + e.line;
- }
-}
-function sourceFromStacktrace( offset ) {
- try {
- throw new Error();
- } catch ( e ) {
- return extractStacktrace( e, offset );
- }
-}
-
-/**
- * Escape text for attribute or text content.
- */
-function escapeText( s ) {
- if ( !s ) {
- return "";
- }
- s = s + "";
- // Both single quotes and double quotes (for attributes)
- return s.replace( /['"<>&]/g, function( s ) {
- switch( s ) {
- case '\'':
- return ''';
- case '"':
- return '"';
- case '<':
- return '<';
- case '>':
- return '>';
- case '&':
- return '&';
- }
- });
-}
-
-function synchronize( callback, last ) {
- config.queue.push( callback );
-
- if ( config.autorun && !config.blocking ) {
- process( last );
- }
-}
-
-function process( last ) {
- function next() {
- process( last );
- }
- var start = new Date().getTime();
- config.depth = config.depth ? config.depth + 1 : 1;
-
- while ( config.queue.length && !config.blocking ) {
- if ( !defined.setTimeout || config.updateRate <= 0 || ( ( new Date().getTime() - start ) < config.updateRate ) ) {
- config.queue.shift()();
- } else {
- window.setTimeout( next, 13 );
- break;
- }
- }
- config.depth--;
- if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) {
- done();
- }
-}
-
-function saveGlobal() {
- config.pollution = [];
-
- if ( config.noglobals ) {
- for ( var key in window ) {
- // in Opera sometimes DOM element ids show up here, ignore them
- if ( !hasOwn.call( window, key ) || /^qunit-test-output/.test( key ) ) {
- continue;
- }
- config.pollution.push( key );
- }
- }
-}
-
-function checkPollution() {
- var newGlobals,
- deletedGlobals,
- old = config.pollution;
-
- saveGlobal();
-
- newGlobals = diff( config.pollution, old );
- if ( newGlobals.length > 0 ) {
- QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join(", ") );
- }
-
- deletedGlobals = diff( old, config.pollution );
- if ( deletedGlobals.length > 0 ) {
- QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join(", ") );
- }
-}
-
-// returns a new Array with the elements that are in a but not in b
-function diff( a, b ) {
- var i, j,
- result = a.slice();
-
- for ( i = 0; i < result.length; i++ ) {
- for ( j = 0; j < b.length; j++ ) {
- if ( result[i] === b[j] ) {
- result.splice( i, 1 );
- i--;
- break;
- }
- }
- }
- return result;
-}
-
-function extend( a, b ) {
- for ( var prop in b ) {
- if ( b[ prop ] === undefined ) {
- delete a[ prop ];
-
- // Avoid "Member not found" error in IE8 caused by setting window.constructor
- } else if ( prop !== "constructor" || a !== window ) {
- a[ prop ] = b[ prop ];
- }
- }
-
- return a;
-}
-
-/**
- * @param {HTMLElement} elem
- * @param {string} type
- * @param {Function} fn
- */
-function addEvent( elem, type, fn ) {
- // Standards-based browsers
- if ( elem.addEventListener ) {
- elem.addEventListener( type, fn, false );
- // IE
- } else {
- elem.attachEvent( "on" + type, fn );
- }
-}
-
-/**
- * @param {Array|NodeList} elems
- * @param {string} type
- * @param {Function} fn
- */
-function addEvents( elems, type, fn ) {
- var i = elems.length;
- while ( i-- ) {
- addEvent( elems[i], type, fn );
- }
-}
-
-function hasClass( elem, name ) {
- return (" " + elem.className + " ").indexOf(" " + name + " ") > -1;
-}
-
-function addClass( elem, name ) {
- if ( !hasClass( elem, name ) ) {
- elem.className += (elem.className ? " " : "") + name;
- }
-}
-
-function removeClass( elem, name ) {
- var set = " " + elem.className + " ";
- // Class name may appear multiple times
- while ( set.indexOf(" " + name + " ") > -1 ) {
- set = set.replace(" " + name + " " , " ");
- }
- // If possible, trim it for prettiness, but not neccecarily
- elem.className = window.jQuery ? jQuery.trim( set ) : ( set.trim ? set.trim() : set );
-}
-
-function id( name ) {
- return !!( typeof document !== "undefined" && document && document.getElementById ) &&
- document.getElementById( name );
-}
-
-function registerLoggingCallback( key ) {
- return function( callback ) {
- config[key].push( callback );
- };
-}
-
-// Supports deprecated method of completely overwriting logging callbacks
-function runLoggingCallbacks( key, scope, args ) {
- var i, callbacks;
- if ( QUnit.hasOwnProperty( key ) ) {
- QUnit[ key ].call(scope, args );
- } else {
- callbacks = config[ key ];
- for ( i = 0; i < callbacks.length; i++ ) {
- callbacks[ i ].call( scope, args );
- }
- }
-}
-
-// Test for equality any JavaScript type.
-// Author: Philippe Rathé
-QUnit.equiv = (function() {
-
- // Call the o related callback with the given arguments.
- function bindCallbacks( o, callbacks, args ) {
- var prop = QUnit.objectType( o );
- if ( prop ) {
- if ( QUnit.objectType( callbacks[ prop ] ) === "function" ) {
- return callbacks[ prop ].apply( callbacks, args );
- } else {
- return callbacks[ prop ]; // or undefined
- }
- }
- }
-
- // the real equiv function
- var innerEquiv,
- // stack to decide between skip/abort functions
- callers = [],
- // stack to avoiding loops from circular referencing
- parents = [],
-
- getProto = Object.getPrototypeOf || function ( obj ) {
- return obj.__proto__;
- },
- callbacks = (function () {
-
- // for string, boolean, number and null
- function useStrictEquality( b, a ) {
- /*jshint eqeqeq:false */
- if ( b instanceof a.constructor || a instanceof b.constructor ) {
- // to catch short annotaion VS 'new' annotation of a
- // declaration
- // e.g. var i = 1;
- // var j = new Number(1);
- return a == b;
- } else {
- return a === b;
- }
- }
-
- return {
- "string": useStrictEquality,
- "boolean": useStrictEquality,
- "number": useStrictEquality,
- "null": useStrictEquality,
- "undefined": useStrictEquality,
-
- "nan": function( b ) {
- return isNaN( b );
- },
-
- "date": function( b, a ) {
- return QUnit.objectType( b ) === "date" && a.valueOf() === b.valueOf();
- },
-
- "regexp": function( b, a ) {
- return QUnit.objectType( b ) === "regexp" &&
- // the regex itself
- a.source === b.source &&
- // and its modifers
- a.global === b.global &&
- // (gmi) ...
- a.ignoreCase === b.ignoreCase &&
- a.multiline === b.multiline &&
- a.sticky === b.sticky;
- },
-
- // - skip when the property is a method of an instance (OOP)
- // - abort otherwise,
- // initial === would have catch identical references anyway
- "function": function() {
- var caller = callers[callers.length - 1];
- return caller !== Object && typeof caller !== "undefined";
- },
-
- "array": function( b, a ) {
- var i, j, len, loop;
-
- // b could be an object literal here
- if ( QUnit.objectType( b ) !== "array" ) {
- return false;
- }
-
- len = a.length;
- if ( len !== b.length ) {
- // safe and faster
- return false;
- }
-
- // track reference to avoid circular references
- parents.push( a );
- for ( i = 0; i < len; i++ ) {
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- loop = true;// dont rewalk array
- }
- }
- if ( !loop && !innerEquiv(a[i], b[i]) ) {
- parents.pop();
- return false;
- }
- }
- parents.pop();
- return true;
- },
-
- "object": function( b, a ) {
- var i, j, loop,
- // Default to true
- eq = true,
- aProperties = [],
- bProperties = [];
-
- // comparing constructors is more strict than using
- // instanceof
- if ( a.constructor !== b.constructor ) {
- // Allow objects with no prototype to be equivalent to
- // objects with Object as their constructor.
- if ( !(( getProto(a) === null && getProto(b) === Object.prototype ) ||
- ( getProto(b) === null && getProto(a) === Object.prototype ) ) ) {
- return false;
- }
- }
-
- // stack constructor before traversing properties
- callers.push( a.constructor );
- // track reference to avoid circular references
- parents.push( a );
-
- for ( i in a ) { // be strict: don't ensures hasOwnProperty
- // and go deep
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- // don't go down the same path twice
- loop = true;
- }
- }
- aProperties.push(i); // collect a's properties
-
- if (!loop && !innerEquiv( a[i], b[i] ) ) {
- eq = false;
- break;
- }
- }
-
- callers.pop(); // unstack, we are done
- parents.pop();
-
- for ( i in b ) {
- bProperties.push( i ); // collect b's properties
- }
-
- // Ensures identical properties name
- return eq && innerEquiv( aProperties.sort(), bProperties.sort() );
- }
- };
- }());
-
- innerEquiv = function() { // can take multiple arguments
- var args = [].slice.apply( arguments );
- if ( args.length < 2 ) {
- return true; // end transition
- }
-
- return (function( a, b ) {
- if ( a === b ) {
- return true; // catch the most you can
- } else if ( a === null || b === null || typeof a === "undefined" ||
- typeof b === "undefined" ||
- QUnit.objectType(a) !== QUnit.objectType(b) ) {
- return false; // don't lose time with error prone cases
- } else {
- return bindCallbacks(a, callbacks, [ b, a ]);
- }
-
- // apply transition with (1..n) arguments
- }( args[0], args[1] ) && arguments.callee.apply( this, args.splice(1, args.length - 1 )) );
- };
-
- return innerEquiv;
-}());
-
-/**
- * jsDump Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com |
- * http://flesler.blogspot.com Licensed under BSD
- * (http://www.opensource.org/licenses/bsd-license.php) Date: 5/15/2008
- *
- * @projectDescription Advanced and extensible data dumping for Javascript.
- * @version 1.0.0
- * @author Ariel Flesler
- * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html}
- */
-QUnit.jsDump = (function() {
- function quote( str ) {
- return '"' + str.toString().replace( /"/g, '\\"' ) + '"';
- }
- function literal( o ) {
- return o + "";
- }
- function join( pre, arr, post ) {
- var s = jsDump.separator(),
- base = jsDump.indent(),
- inner = jsDump.indent(1);
- if ( arr.join ) {
- arr = arr.join( "," + s + inner );
- }
- if ( !arr ) {
- return pre + post;
- }
- return [ pre, inner + arr, base + post ].join(s);
- }
- function array( arr, stack ) {
- var i = arr.length, ret = new Array(i);
- this.up();
- while ( i-- ) {
- ret[i] = this.parse( arr[i] , undefined , stack);
- }
- this.down();
- return join( "[", ret, "]" );
- }
-
- var reName = /^function (\w+)/,
- jsDump = {
- // type is used mostly internally, you can fix a (custom)type in advance
- parse: function( obj, type, stack ) {
- stack = stack || [ ];
- var inStack, res,
- parser = this.parsers[ type || this.typeOf(obj) ];
-
- type = typeof parser;
- inStack = inArray( obj, stack );
-
- if ( inStack !== -1 ) {
- return "recursion(" + (inStack - stack.length) + ")";
- }
- if ( type === "function" ) {
- stack.push( obj );
- res = parser.call( this, obj, stack );
- stack.pop();
- return res;
- }
- return ( type === "string" ) ? parser : this.parsers.error;
- },
- typeOf: function( obj ) {
- var type;
- if ( obj === null ) {
- type = "null";
- } else if ( typeof obj === "undefined" ) {
- type = "undefined";
- } else if ( QUnit.is( "regexp", obj) ) {
- type = "regexp";
- } else if ( QUnit.is( "date", obj) ) {
- type = "date";
- } else if ( QUnit.is( "function", obj) ) {
- type = "function";
- } else if ( typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined" ) {
- type = "window";
- } else if ( obj.nodeType === 9 ) {
- type = "document";
- } else if ( obj.nodeType ) {
- type = "node";
- } else if (
- // native arrays
- toString.call( obj ) === "[object Array]" ||
- // NodeList objects
- ( typeof obj.length === "number" && typeof obj.item !== "undefined" && ( obj.length ? obj.item(0) === obj[0] : ( obj.item( 0 ) === null && typeof obj[0] === "undefined" ) ) )
- ) {
- type = "array";
- } else if ( obj.constructor === Error.prototype.constructor ) {
- type = "error";
- } else {
- type = typeof obj;
- }
- return type;
- },
- separator: function() {
- return this.multiline ? this.HTML ? "
" : "\n" : this.HTML ? " " : " ";
- },
- // extra can be a number, shortcut for increasing-calling-decreasing
- indent: function( extra ) {
- if ( !this.multiline ) {
- return "";
- }
- var chr = this.indentChar;
- if ( this.HTML ) {
- chr = chr.replace( /\t/g, " " ).replace( / /g, " " );
- }
- return new Array( this._depth_ + (extra||0) ).join(chr);
- },
- up: function( a ) {
- this._depth_ += a || 1;
- },
- down: function( a ) {
- this._depth_ -= a || 1;
- },
- setParser: function( name, parser ) {
- this.parsers[name] = parser;
- },
- // The next 3 are exposed so you can use them
- quote: quote,
- literal: literal,
- join: join,
- //
- _depth_: 1,
- // This is the list of parsers, to modify them, use jsDump.setParser
- parsers: {
- window: "[Window]",
- document: "[Document]",
- error: function(error) {
- return "Error(\"" + error.message + "\")";
- },
- unknown: "[Unknown]",
- "null": "null",
- "undefined": "undefined",
- "function": function( fn ) {
- var ret = "function",
- // functions never have name in IE
- name = "name" in fn ? fn.name : (reName.exec(fn) || [])[1];
-
- if ( name ) {
- ret += " " + name;
- }
- ret += "( ";
-
- ret = [ ret, QUnit.jsDump.parse( fn, "functionArgs" ), "){" ].join( "" );
- return join( ret, QUnit.jsDump.parse(fn,"functionCode" ), "}" );
- },
- array: array,
- nodelist: array,
- "arguments": array,
- object: function( map, stack ) {
- var ret = [ ], keys, key, val, i;
- QUnit.jsDump.up();
- keys = [];
- for ( key in map ) {
- keys.push( key );
- }
- keys.sort();
- for ( i = 0; i < keys.length; i++ ) {
- key = keys[ i ];
- val = map[ key ];
- ret.push( QUnit.jsDump.parse( key, "key" ) + ": " + QUnit.jsDump.parse( val, undefined, stack ) );
- }
- QUnit.jsDump.down();
- return join( "{", ret, "}" );
- },
- node: function( node ) {
- var len, i, val,
- open = QUnit.jsDump.HTML ? "<" : "<",
- close = QUnit.jsDump.HTML ? ">" : ">",
- tag = node.nodeName.toLowerCase(),
- ret = open + tag,
- attrs = node.attributes;
-
- if ( attrs ) {
- for ( i = 0, len = attrs.length; i < len; i++ ) {
- val = attrs[i].nodeValue;
- // IE6 includes all attributes in .attributes, even ones not explicitly set.
- // Those have values like undefined, null, 0, false, "" or "inherit".
- if ( val && val !== "inherit" ) {
- ret += " " + attrs[i].nodeName + "=" + QUnit.jsDump.parse( val, "attribute" );
- }
- }
- }
- ret += close;
-
- // Show content of TextNode or CDATASection
- if ( node.nodeType === 3 || node.nodeType === 4 ) {
- ret += node.nodeValue;
- }
-
- return ret + open + "/" + tag + close;
- },
- // function calls it internally, it's the arguments part of the function
- functionArgs: function( fn ) {
- var args,
- l = fn.length;
-
- if ( !l ) {
- return "";
- }
-
- args = new Array(l);
- while ( l-- ) {
- // 97 is 'a'
- args[l] = String.fromCharCode(97+l);
- }
- return " " + args.join( ", " ) + " ";
- },
- // object calls it internally, the key part of an item in a map
- key: quote,
- // function calls it internally, it's the content of the function
- functionCode: "[code]",
- // node calls it internally, it's an html attribute value
- attribute: quote,
- string: quote,
- date: quote,
- regexp: literal,
- number: literal,
- "boolean": literal
- },
- // if true, entities are escaped ( <, >, \t, space and \n )
- HTML: false,
- // indentation unit
- indentChar: " ",
- // if true, items in a collection, are separated by a \n, else just a space.
- multiline: true
- };
-
- return jsDump;
-}());
-
-// from jquery.js
-function inArray( elem, array ) {
- if ( array.indexOf ) {
- return array.indexOf( elem );
- }
-
- for ( var i = 0, length = array.length; i < length; i++ ) {
- if ( array[ i ] === elem ) {
- return i;
- }
- }
-
- return -1;
-}
-
-/*
- * Javascript Diff Algorithm
- * By John Resig (http://ejohn.org/)
- * Modified by Chu Alan "sprite"
- *
- * Released under the MIT license.
- *
- * More Info:
- * http://ejohn.org/projects/javascript-diff-algorithm/
- *
- * Usage: QUnit.diff(expected, actual)
- *
- * QUnit.diff( "the quick brown fox jumped over", "the quick fox jumps over" ) == "the quick brown fox jumped jumps over"
- */
-QUnit.diff = (function() {
- /*jshint eqeqeq:false, eqnull:true */
- function diff( o, n ) {
- var i,
- ns = {},
- os = {};
-
- for ( i = 0; i < n.length; i++ ) {
- if ( !hasOwn.call( ns, n[i] ) ) {
- ns[ n[i] ] = {
- rows: [],
- o: null
- };
- }
- ns[ n[i] ].rows.push( i );
- }
-
- for ( i = 0; i < o.length; i++ ) {
- if ( !hasOwn.call( os, o[i] ) ) {
- os[ o[i] ] = {
- rows: [],
- n: null
- };
- }
- os[ o[i] ].rows.push( i );
- }
-
- for ( i in ns ) {
- if ( !hasOwn.call( ns, i ) ) {
- continue;
- }
- if ( ns[i].rows.length === 1 && hasOwn.call( os, i ) && os[i].rows.length === 1 ) {
- n[ ns[i].rows[0] ] = {
- text: n[ ns[i].rows[0] ],
- row: os[i].rows[0]
- };
- o[ os[i].rows[0] ] = {
- text: o[ os[i].rows[0] ],
- row: ns[i].rows[0]
- };
- }
- }
-
- for ( i = 0; i < n.length - 1; i++ ) {
- if ( n[i].text != null && n[ i + 1 ].text == null && n[i].row + 1 < o.length && o[ n[i].row + 1 ].text == null &&
- n[ i + 1 ] == o[ n[i].row + 1 ] ) {
-
- n[ i + 1 ] = {
- text: n[ i + 1 ],
- row: n[i].row + 1
- };
- o[ n[i].row + 1 ] = {
- text: o[ n[i].row + 1 ],
- row: i + 1
- };
- }
- }
-
- for ( i = n.length - 1; i > 0; i-- ) {
- if ( n[i].text != null && n[ i - 1 ].text == null && n[i].row > 0 && o[ n[i].row - 1 ].text == null &&
- n[ i - 1 ] == o[ n[i].row - 1 ]) {
-
- n[ i - 1 ] = {
- text: n[ i - 1 ],
- row: n[i].row - 1
- };
- o[ n[i].row - 1 ] = {
- text: o[ n[i].row - 1 ],
- row: i - 1
- };
- }
- }
-
- return {
- o: o,
- n: n
- };
- }
-
- return function( o, n ) {
- o = o.replace( /\s+$/, "" );
- n = n.replace( /\s+$/, "" );
-
- var i, pre,
- str = "",
- out = diff( o === "" ? [] : o.split(/\s+/), n === "" ? [] : n.split(/\s+/) ),
- oSpace = o.match(/\s+/g),
- nSpace = n.match(/\s+/g);
-
- if ( oSpace == null ) {
- oSpace = [ " " ];
- }
- else {
- oSpace.push( " " );
- }
-
- if ( nSpace == null ) {
- nSpace = [ " " ];
- }
- else {
- nSpace.push( " " );
- }
-
- if ( out.n.length === 0 ) {
- for ( i = 0; i < out.o.length; i++ ) {
- str += "" + out.o[i] + oSpace[i] + "";
- }
- }
- else {
- if ( out.n[0].text == null ) {
- for ( n = 0; n < out.o.length && out.o[n].text == null; n++ ) {
- str += "" + out.o[n] + oSpace[n] + "";
- }
- }
-
- for ( i = 0; i < out.n.length; i++ ) {
- if (out.n[i].text == null) {
- str += "" + out.n[i] + nSpace[i] + "";
- }
- else {
- // `pre` initialized at top of scope
- pre = "";
-
- for ( n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++ ) {
- pre += "" + out.o[n] + oSpace[n] + "";
- }
- str += " " + out.n[i].text + nSpace[i] + pre;
- }
- }
- }
-
- return str;
- };
-}());
-
-// for CommonJS enviroments, export everything
-if ( typeof exports !== "undefined" ) {
- extend( exports, QUnit );
-}
-
-// get at whatever the global object is, like window in browsers
-}( (function() {return this;}.call()) ));
diff --git a/test/lib/require.js b/test/lib/require.js
deleted file mode 100644
index 987f865..0000000
--- a/test/lib/require.js
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- RequireJS 2.1.5 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.
- Available via the MIT or new BSD license.
- see: http://github.com/jrburke/requirejs for details
-*/
-var requirejs,require,define;
-(function(aa){function I(b){return"[object Function]"===L.call(b)}function J(b){return"[object Array]"===L.call(b)}function y(b,c){if(b){var d;for(d=0;dthis.depCount&&!this.defined){if(I(n)){if(this.events.error)try{e=i.execCb(c,n,b,e)}catch(d){a=d}else e=i.execCb(c,n,b,e);this.map.isDefine&&((b=this.module)&&void 0!==b.exports&&b.exports!==this.exports?e=b.exports:void 0===e&&this.usingExports&&(e=this.exports));if(a)return a.requireMap=this.map,a.requireModules=[this.map.id],a.requireType="define",v(this.error=
-a)}else e=n;this.exports=e;if(this.map.isDefine&&!this.ignore&&(q[c]=e,l.onResourceLoad))l.onResourceLoad(i,this.map,this.depMaps);x(c);this.defined=!0}this.defining=!1;this.defined&&!this.defineEmitted&&(this.defineEmitted=!0,this.emit("defined",this.exports),this.defineEmitComplete=!0)}}else this.fetch()}},callPlugin:function(){var a=this.map,b=a.id,d=j(a.prefix);this.depMaps.push(d);t(d,"defined",u(this,function(e){var n,d;d=this.map.name;var g=this.map.parentMap?this.map.parentMap.name:null,h=
-i.makeRequire(a.parentMap,{enableBuildCallback:!0});if(this.map.unnormalized){if(e.normalize&&(d=e.normalize(d,function(a){return c(a,g,!0)})||""),e=j(a.prefix+"!"+d,this.map.parentMap),t(e,"defined",u(this,function(a){this.init([],function(){return a},null,{enabled:!0,ignore:!0})})),d=m(p,e.id)){this.depMaps.push(e);if(this.events.error)d.on("error",u(this,function(a){this.emit("error",a)}));d.enable()}}else n=u(this,function(a){this.init([],function(){return a},null,{enabled:!0})}),n.error=u(this,
-function(a){this.inited=!0;this.error=a;a.requireModules=[b];G(p,function(a){0===a.map.id.indexOf(b+"_unnormalized")&&x(a.map.id)});v(a)}),n.fromText=u(this,function(e,c){var d=a.name,g=j(d),C=O;c&&(e=c);C&&(O=!1);r(g);s(k.config,b)&&(k.config[d]=k.config[b]);try{l.exec(e)}catch(ca){return v(B("fromtexteval","fromText eval for "+b+" failed: "+ca,ca,[b]))}C&&(O=!0);this.depMaps.push(g);i.completeLoad(d);h([d],n)}),e.load(a.name,h,n,k)}));i.enable(d,this);this.pluginMaps[d.id]=d},enable:function(){V[this.map.id]=
-this;this.enabling=this.enabled=!0;y(this.depMaps,u(this,function(a,b){var c,e;if("string"===typeof a){a=j(a,this.map.isDefine?this.map:this.map.parentMap,!1,!this.skipMap);this.depMaps[b]=a;if(c=m(N,a.id)){this.depExports[b]=c(this);return}this.depCount+=1;t(a,"defined",u(this,function(a){this.defineDep(b,a);this.check()}));this.errback&&t(a,"error",this.errback)}c=a.id;e=p[c];!s(N,c)&&(e&&!e.enabled)&&i.enable(a,this)}));G(this.pluginMaps,u(this,function(a){var b=m(p,a.id);b&&!b.enabled&&i.enable(a,
-this)}));this.enabling=!1;this.check()},on:function(a,b){var c=this.events[a];c||(c=this.events[a]=[]);c.push(b)},emit:function(a,b){y(this.events[a],function(a){a(b)});"error"===a&&delete this.events[a]}};i={config:k,contextName:b,registry:p,defined:q,urlFetched:U,defQueue:H,Module:Z,makeModuleMap:j,nextTick:l.nextTick,onError:v,configure:function(a){a.baseUrl&&"/"!==a.baseUrl.charAt(a.baseUrl.length-1)&&(a.baseUrl+="/");var b=k.pkgs,c=k.shim,e={paths:!0,config:!0,map:!0};G(a,function(a,b){e[b]?
-"map"===b?(k.map||(k.map={}),R(k[b],a,!0,!0)):R(k[b],a,!0):k[b]=a});a.shim&&(G(a.shim,function(a,b){J(a)&&(a={deps:a});if((a.exports||a.init)&&!a.exportsFn)a.exportsFn=i.makeShimExports(a);c[b]=a}),k.shim=c);a.packages&&(y(a.packages,function(a){a="string"===typeof a?{name:a}:a;b[a.name]={name:a.name,location:a.location||a.name,main:(a.main||"main").replace(ja,"").replace(ea,"")}}),k.pkgs=b);G(p,function(a,b){!a.inited&&!a.map.unnormalized&&(a.map=j(b))});if(a.deps||a.callback)i.require(a.deps||[],
-a.callback)},makeShimExports:function(a){return function(){var b;a.init&&(b=a.init.apply(aa,arguments));return b||a.exports&&ba(a.exports)}},makeRequire:function(a,f){function d(e,c,h){var g,k;f.enableBuildCallback&&(c&&I(c))&&(c.__requireJsBuild=!0);if("string"===typeof e){if(I(c))return v(B("requireargs","Invalid require call"),h);if(a&&s(N,e))return N[e](p[a.id]);if(l.get)return l.get(i,e,a,d);g=j(e,a,!1,!0);g=g.id;return!s(q,g)?v(B("notloaded",'Module name "'+g+'" has not been loaded yet for context: '+
-b+(a?"":". Use require([])"))):q[g]}L();i.nextTick(function(){L();k=r(j(null,a));k.skipMap=f.skipMap;k.init(e,c,h,{enabled:!0});D()});return d}f=f||{};R(d,{isBrowser:A,toUrl:function(b){var d,f=b.lastIndexOf("."),g=b.split("/")[0];if(-1!==f&&(!("."===g||".."===g)||1h.attachEvent.toString().indexOf("[native code"))&&!Y?(O=!0,h.attachEvent("onreadystatechange",b.onScriptLoad)):(h.addEventListener("load",b.onScriptLoad,!1),h.addEventListener("error",b.onScriptError,!1)),h.src=d,K=h,D?x.insertBefore(h,D):x.appendChild(h),K=null,h;if(da)try{importScripts(d),b.completeLoad(c)}catch(j){b.onError(B("importscripts","importScripts failed for "+c+" at "+d,j,[c]))}};A&&M(document.getElementsByTagName("script"),function(b){x||(x=
-b.parentNode);if(t=b.getAttribute("data-main"))return r.baseUrl||(E=t.split("/"),Q=E.pop(),fa=E.length?E.join("/")+"/":"./",r.baseUrl=fa,t=Q),t=t.replace(ea,""),r.deps=r.deps?r.deps.concat(t):[t],!0});define=function(b,c,d){var l,h;"string"!==typeof b&&(d=c,c=b,b=null);J(c)||(d=c,c=[]);!c.length&&I(d)&&d.length&&(d.toString().replace(la,"").replace(ma,function(b,d){c.push(d)}),c=(1===d.length?["require"]:["require","exports","module"]).concat(c));if(O){if(!(l=K))P&&"interactive"===P.readyState||M(document.getElementsByTagName("script"),
-function(b){if("interactive"===b.readyState)return P=b}),l=P;l&&(b||(b=l.getAttribute("data-requiremodule")),h=F[l.getAttribute("data-requirecontext")])}(h?h.defQueue:T).push([b,c,d])};define.amd={jQuery:!0};l.exec=function(b){return eval(b)};l(r)}})(this);
diff --git a/test/lib/resemble.js b/test/lib/resemble.js
new file mode 100644
index 0000000..1cb8c29
--- /dev/null
+++ b/test/lib/resemble.js
@@ -0,0 +1,535 @@
+/*
+Author: James Cryer
+Company: Huddle
+Last updated date: 21 Feb 2013
+URL: https://github.com/Huddle/Resemble.js
+*/
+
+(function(_this){
+ 'use strict';
+
+ _this['resemble'] = function( fileData ){
+
+ var data = {};
+ var images = [];
+ var updateCallbackArray = [];
+
+ var tolerance = { // between 0 and 255
+ red: 16,
+ green: 16,
+ blue: 16,
+ minBrightness: 16,
+ maxBrightness: 240
+ };
+
+ var ignoreAntialiasing = false;
+ var ignoreColors = false;
+
+ function triggerDataUpdate(){
+ var len = updateCallbackArray.length;
+ var i;
+ for(i=0;i tolerance.maxBrightness;
+ }
+
+ function getHue(r,g,b){
+
+ r = r / 255;
+ g = g / 255;
+ b = b / 255;
+ var max = Math.max(r, g, b), min = Math.min(r, g, b);
+ var h;
+ var d;
+
+ if (max == min){
+ h = 0; // achromatic
+ } else{
+ d = max - min;
+ switch(max){
+ case r: h = (g - b) / d + (g < b ? 6 : 0); break;
+ case g: h = (b - r) / d + 2; break;
+ case b: h = (r - g) / d + 4; break;
+ }
+ h /= 6;
+ }
+
+ return h;
+ }
+
+ function isAntialiased(sourcePix, data, cacheSet, verticalPos, horizontalPos, width){
+ var offset;
+ var targetPix;
+ var distance = 1;
+ var i;
+ var j;
+ var hasHighContrastSibling = 0;
+ var hasSiblingWithDifferentHue = 0;
+ var hasEquivilantSibling = 0;
+
+ addHueInfo(sourcePix);
+
+ for (i = distance*-1; i <= distance; i++){
+ for (j = distance*-1; j <= distance; j++){
+
+ if(i===0 && j===0){
+ // ignore source pixel
+ } else {
+
+ offset = ((verticalPos+j)*width + (horizontalPos+i)) * 4;
+ targetPix = getPixelInfo(data, offset, cacheSet);
+
+ if(targetPix === null){
+ continue;
+ }
+
+ addBrightnessInfo(targetPix);
+ addHueInfo(targetPix);
+
+ if( isContrasting(sourcePix, targetPix) ){
+ hasHighContrastSibling++;
+ }
+
+ if( isRGBSame(sourcePix,targetPix) ){
+ hasEquivilantSibling++;
+ }
+
+ if( Math.abs(targetPix.h - sourcePix.h) > 0.3 ){
+ hasSiblingWithDifferentHue++;
+ }
+
+ if( hasSiblingWithDifferentHue > 1 || hasHighContrastSibling > 1){
+ return true;
+ }
+ }
+ }
+ }
+
+ if(hasEquivilantSibling < 2){
+ return true;
+ }
+
+ return false;
+ }
+
+ function errorPixel(px, offset){
+ px[offset] = 255; //r
+ px[offset + 1] = 0; //g
+ px[offset + 2] = 255; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyPixel(px, offset, data){
+ px[offset] = data.r; //r
+ px[offset + 1] = data.g; //g
+ px[offset + 2] = data.b; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyGrayScalePixel(px, offset, data){
+ px[offset] = data.brightness; //r
+ px[offset + 1] = data.brightness; //g
+ px[offset + 2] = data.brightness; //b
+ px[offset + 3] = 255; //a
+ }
+
+
+ function getPixelInfo(data, offset, cacheSet){
+ var r;
+ var g;
+ var b;
+ var d;
+
+ if(typeof data[offset] !== 'undefined'){
+ r = data[offset];
+ g = data[offset+1];
+ b = data[offset+2];
+ d = {
+ r: r,
+ g: g,
+ b: b
+ };
+
+ return d;
+ } else {
+ return null;
+ }
+ }
+
+ function addBrightnessInfo(data){
+ data.brightness = getBrightness(data.r,data.g,data.b); // 'corrected' lightness
+ }
+
+ function addHueInfo(data){
+ data.h = getHue(data.r,data.g,data.b);
+ }
+
+ function analyseImages(img1, img2, width, height){
+
+ var hiddenCanvas = document.createElement('canvas');
+
+ var data1 = img1.data;
+ var data2 = img2.data;
+
+ hiddenCanvas.width = width;
+ hiddenCanvas.height = height;
+
+ var context = hiddenCanvas.getContext('2d');
+ var imgd = context.createImageData(width,height);
+ var targetPix = imgd.data;
+
+ var mismatchCount = 0;
+
+ var time = Date.now();
+
+ var skip;
+
+ if( (width > 1200 || height > 1200) && ignoreAntialiasing){
+ skip = 6;
+ }
+
+ loop(height, width, function(verticalPos, horizontalPos){
+
+ if(skip){ // only skip if the image isn't small
+ if(verticalPos % skip === 0 || horizontalPos % skip === 0){
+ return;
+ }
+ }
+
+ var offset = (verticalPos*width + horizontalPos) * 4;
+ var pixel1 = getPixelInfo(data1, offset, 1);
+ var pixel2 = getPixelInfo(data2, offset, 2);
+
+ if(pixel1 === null || pixel2 === null){
+ return;
+ }
+
+ if (ignoreColors){
+
+ addBrightnessInfo(pixel1);
+ addBrightnessInfo(pixel2);
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ return;
+ }
+
+ if( isRGBSimilar(pixel1, pixel2) ){
+ copyPixel(targetPix, offset, pixel2);
+
+ } else if( ignoreAntialiasing && (
+ addBrightnessInfo(pixel1), // jit pixel info augmentation looks a little weird, sorry.
+ addBrightnessInfo(pixel2),
+ isAntialiased(pixel1, data1, 1, verticalPos, horizontalPos, width) ||
+ isAntialiased(pixel2, data2, 2, verticalPos, horizontalPos, width)
+ )){
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+
+ });
+
+ data.misMatchPercentage = (mismatchCount / (height*width) * 100).toFixed(2);
+ data.analysisTime = Date.now() - time;
+
+ data.getImageDataUrl = function(text){
+ var barHeight = 0;
+
+ if(text){
+ barHeight = addLabel(text,context,hiddenCanvas);
+ }
+
+ context.putImageData(imgd, 0, barHeight);
+
+ return hiddenCanvas.toDataURL("image/png");
+ };
+ }
+
+ function addLabel(text, context, hiddenCanvas){
+ var textPadding = 2;
+
+ context.font = '12px sans-serif';
+
+ var textWidth = context.measureText(text).width + textPadding*2;
+ var barHeight = 22;
+
+ if(textWidth > hiddenCanvas.width){
+ hiddenCanvas.width = textWidth;
+ }
+
+ hiddenCanvas.height += barHeight;
+
+ context.fillStyle = "#666";
+ context.fillRect(0,0,hiddenCanvas.width,barHeight -4);
+ context.fillStyle = "#fff";
+ context.fillRect(0,barHeight -4,hiddenCanvas.width, 4);
+
+ context.fillStyle = "#fff";
+ context.textBaseline = "top";
+ context.font = '12px sans-serif';
+ context.fillText(text, textPadding, 1);
+
+ return barHeight;
+ }
+
+ function normalise(img, w, h){
+ var c;
+ var context;
+
+ if(img.height < h || img.width < w){
+ c = document.createElement('canvas');
+ c.width = w;
+ c.height = h;
+ context = c.getContext('2d');
+ context.putImageData(img, 0, 0);
+ return context.getImageData(0, 0, w, h);
+ }
+
+ return img;
+ }
+
+ function compare(one, two){
+
+ function onceWeHaveBoth(){
+ var width;
+ var height;
+ if(images.length === 2){
+ width = images[0].width > images[1].width ? images[0].width : images[1].width;
+ height = images[0].height > images[1].height ? images[0].height : images[1].height;
+
+ if( (images[0].width === images[1].width) && (images[0].height === images[1].height) ){
+ data.isSameDimensions = true;
+ } else {
+ data.isSameDimensions = false;
+ }
+
+ analyseImages( normalise(images[0],width, height), normalise(images[1],width, height), width, height);
+
+ triggerDataUpdate();
+ }
+ }
+
+ images = [];
+ loadImageData(one, onceWeHaveBoth);
+ loadImageData(two, onceWeHaveBoth);
+ }
+
+ function getCompareApi(param){
+
+ var secondFileData,
+ hasMethod = typeof param === 'function';
+
+ if( !hasMethod ){
+ // assume it's file data
+ secondFileData = param;
+ }
+
+ var self = {
+ ignoreNothing: function(){
+
+ tolerance.red = 16;
+ tolerance.green = 16;
+ tolerance.blue = 16;
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreAntialiasing: function(){
+
+ tolerance.red = 32;
+ tolerance.green = 32;
+ tolerance.blue = 32;
+ tolerance.minBrightness = 64;
+ tolerance.maxBrightness = 96;
+
+ ignoreAntialiasing = true;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreColors: function(){
+
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = true;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ onComplete: function( callback ){
+
+ updateCallbackArray.push(callback);
+
+ var wrapper = function(){
+ compare(fileData, secondFileData);
+ };
+
+ wrapper();
+
+ return getCompareApi(wrapper);
+ }
+ };
+
+ return self;
+ }
+
+ return {
+ onComplete: function( callback ){
+ updateCallbackArray.push(callback);
+ loadImageData(fileData, function(imageData, width, height){
+ parseImage(imageData.data, width, height);
+ });
+ },
+ compareTo: function(secondFileData){
+ return getCompareApi(secondFileData);
+ }
+ };
+
+ };
+}(this));
\ No newline at end of file
diff --git a/test/testsuite.js b/test/testsuite.js
deleted file mode 100644
index b486acb..0000000
--- a/test/testsuite.js
+++ /dev/null
@@ -1,36 +0,0 @@
-requirejs.config({
- baseUrl: '/test/unit/'
-});
-
-define(function(require) {
- var testModules = [
- 'Pixi',
- 'Point',
- 'Rectangle',
- 'DisplayObject',
- 'DisplayObjectContainer',
- 'Sprite',
- 'MovieClip',
- 'InteractionManager',
- 'Stage',
- 'utils/Utils',
- 'utils/EventTarget',
- 'utils/Matrix',
- 'utils/Detector',
- 'renderers/WebGLShaders',
- 'renderers/WebGLRenderer',
- 'renderers/WebGLBatch',
- 'renderers/CanvasRenderer',
- 'extras/Strip',
- 'extras/Rope',
- 'textures/BaseTexture',
- 'textures/Texture',
- 'loaders/SpriteSheetLoader',
- 'loaders/AssetLoader'
- ];
-
- // Resolve all testModules and then start the Test Runner.
- require(testModules, function() {
- QUnit.start();
- });
-});
\ No newline at end of file
diff --git a/test/textures/SpriteSheet-Aliens.png b/test/textures/SpriteSheet-Aliens.png
new file mode 100644
index 0000000..210acb1
--- /dev/null
+++ b/test/textures/SpriteSheet-Aliens.png
Binary files differ
diff --git a/test/textures/SpriteSheet-Explosion.png b/test/textures/SpriteSheet-Explosion.png
new file mode 100755
index 0000000..79e1a69
--- /dev/null
+++ b/test/textures/SpriteSheet-Explosion.png
Binary files differ
diff --git a/test/textures/bunny.png b/test/textures/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/textures/bunny.png
Binary files differ
diff --git a/test/unit/DisplayObject.js b/test/unit/DisplayObject.js
deleted file mode 100644
index 5e7e72f..0000000
--- a/test/unit/DisplayObject.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObject');
-});
diff --git a/.gitignore b/.gitignore
index 12e1b62..0b88317 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
node_modules
.DS_Store
-.project
\ No newline at end of file
+.project
+*.log
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..63e4d7c
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,8 @@
+language: node_js
+node_js:
+ - 0.10
+
+before_script:
+ - npm install -g grunt-cli
+ - export DISPLAY=:99.0
+ - sh -e /etc/init.d/xvfb start
diff --git a/Gruntfile.js b/Gruntfile.js
index b083b49..103938c 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -1,10 +1,12 @@
+'use strict';
+
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-connect');
- grunt.loadNpmTasks('grunt-contrib-qunit');
grunt.loadNpmTasks('grunt-contrib-yuidoc');
+ grunt.loadTasks('tasks');
var root = 'src/pixi/',
debug = 'bin/pixi.dev.js',
@@ -79,7 +81,7 @@
},
files: {
srcBlob: '<%= dirs.src %>/**/*.js',
- testBlob: '<%= dirs.test %>/unit/**/*.js',
+ testBlob: '<%= dirs.test %>/{functional,lib/pixi,unit}/**/*.js',
build: '<%= dirs.build %>/pixi.dev.js',
buildMin: '<%= dirs.build %>/pixi.js'
},
@@ -94,7 +96,12 @@
},
jshint: {
beforeconcat: srcFiles,
- test: ['<%= files.testBlob %>'],
+ test: {
+ src: ['<%= files.testBlob %>'],
+ options: {
+ expr: true
+ }
+ },
options: {
asi: true,
smarttabs: true
@@ -128,12 +135,6 @@
]
},
connect: {
- qunit: {
- options: {
- port: grunt.option('port-test') || 9002,
- base: './'
- }
- },
test: {
options: {
port: grunt.option('port-test') || 9002,
@@ -142,13 +143,6 @@
}
}
},
- qunit: {
- all: {
- options: {
- urls: ['http://localhost:' + (grunt.option('port-test') || 9002) + '/test/index.html']
- }
- }
- },
yuidoc: {
compile: {
name: '<%= pkg.name %>',
@@ -161,6 +155,13 @@
outdir: '<%= dirs.docs %>'
}
}
+ },
+ karma: {
+ unit: {
+ configFile: 'test/karma.conf.js',
+ // browsers: ['Chrome'],
+ singleRun: true
+ }
}
});
@@ -182,9 +183,10 @@
}
)
- grunt.registerTask('default', ['concat', 'uglify', 'distribute']);
grunt.registerTask('build', ['concat', 'uglify', 'distribute']);
- grunt.registerTask('test', ['build', 'connect:qunit', 'qunit']);
+ grunt.registerTask('test', ['concat', 'jshint:test', 'karma']);
grunt.registerTask('docs', ['yuidoc']);
-
-}
\ No newline at end of file
+ grunt.registerTask('default', ['test', 'uglify', 'distribute']);
+ // Travis CI task.
+ grunt.registerTask('travis', ['test']);
+}
diff --git a/README.md b/README.md
index c62ef86..690cfe4 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,8 @@

+[](http://travis-ci.org/drkibitz/pixi.js)
+
#### JavaScript 2D Renderer ####
The aim of this project is to provide a fast lightweight 2D library that works
diff --git a/package.json b/package.json
index b373240..1246a68 100644
--- a/package.json
+++ b/package.json
@@ -18,14 +18,21 @@
"main": "bin/pixi.js",
+ "scripts": {
+ "test": "grunt travis --verbose"
+ },
+
"dependencies": {},
"devDependencies": {
"grunt": "~0.4.x",
- "grunt-contrib-jshint": "0.3.x",
+ "grunt-contrib-jshint": "0.6.x",
"grunt-contrib-uglify": "0.2.x",
- "grunt-contrib-connect": "0.2.x",
- "grunt-contrib-qunit": "0.2.x",
+ "grunt-contrib-connect": "0.3.x",
"grunt-contrib-yuidoc": "0.4.x",
- "grunt-contrib-concat": "0.1.x"
+ "grunt-contrib-concat": "0.3.x",
+ "chai": "~1.7.0",
+ "karma": "0.11.0",
+ "karma-firefox-launcher": "0.1.0",
+ "karma-mocha": "0.1.0"
}
}
diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js
index a7c520e..ee82bbd 100644
--- a/src/pixi/InteractionManager.js
+++ b/src/pixi/InteractionManager.js
@@ -62,7 +62,6 @@
this.onTouchEnd = this.onTouchEnd.bind(this);
this.onTouchMove = this.onTouchMove.bind(this);
-
this.last = 0;
}
diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js
index 1a95d20..eef1059 100644
--- a/src/pixi/core/Ellipse.js
+++ b/src/pixi/core/Ellipse.js
@@ -78,7 +78,7 @@
return (normx + normy < 0.25);
}
-PIXI.Ellipse.getBounds = function()
+PIXI.Ellipse.prototype.getBounds = function()
{
return new PIXI.Rectangle(this.x, this.y, this.width, this.height);
}
diff --git a/tasks/karma.js b/tasks/karma.js
new file mode 100644
index 0000000..c340485
--- /dev/null
+++ b/tasks/karma.js
@@ -0,0 +1,27 @@
+'use strict';
+
+var path = require('path');
+var server = require('karma').server;
+
+module.exports = function (grunt) {
+ grunt.registerMultiTask('karma', 'run karma.', function() {
+ var done = this.async();
+ var options = this.options({
+ background: false
+ });
+ var data = this.data;
+
+ //merge options onto data, with data taking precedence
+ data = grunt.util._.merge(options, data);
+ data.configFile = path.resolve(data.configFile);
+ if (data.configFile) {
+ data.configFile = grunt.template.process(data.configFile);
+ }
+
+ server.start(
+ data,
+ function(code) {
+ done(!code);
+ });
+ });
+};
diff --git a/test/functional/example-1-basics/bunny.png b/test/functional/example-1-basics/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/functional/example-1-basics/bunny.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-30.png b/test/functional/example-1-basics/frame-30.png
new file mode 100644
index 0000000..96e3409
--- /dev/null
+++ b/test/functional/example-1-basics/frame-30.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-60.png b/test/functional/example-1-basics/frame-60.png
new file mode 100644
index 0000000..af3f4ce
--- /dev/null
+++ b/test/functional/example-1-basics/frame-60.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-90.png b/test/functional/example-1-basics/frame-90.png
new file mode 100644
index 0000000..099b823
--- /dev/null
+++ b/test/functional/example-1-basics/frame-90.png
Binary files differ
diff --git a/test/functional/example-1-basics/index.js b/test/functional/example-1-basics/index.js
new file mode 100644
index 0000000..7ae7a98
--- /dev/null
+++ b/test/functional/example-1-basics/index.js
@@ -0,0 +1,133 @@
+describe('Example 1 - Basics', function () {
+ 'use strict';
+
+ var baseUri = '/base/test/functional/example-1-basics';
+ var expect = chai.expect;
+ var currentFrame = 0;
+ var frameEvents = {};
+ var stage;
+ var renderer;
+ var bunny;
+
+ function onFrame(frame, callback) {
+ frameEvents[frame] = callback;
+ }
+
+ function animate() {
+ currentFrame += 1;
+
+ requestAnimFrame( animate );
+
+ // just for fun, lets rotate mr rabbit a little
+ bunny.rotation += 0.1;
+
+ // render the stage
+ renderer.render(stage);
+
+ if (frameEvents[currentFrame])
+ frameEvents[currentFrame](currentFrame);
+ }
+
+ function initScene() {
+ // create an new instance of a pixi stage
+ stage = new PIXI.Stage(0x66FF99);
+
+ // create a renderer instance
+ renderer = PIXI.autoDetectRenderer(400, 300);
+ console.log('Is PIXI.WebGLRenderer: ' + (renderer instanceof PIXI.WebGLRenderer));
+
+ // add the renderer view element to the DOM
+ document.body.appendChild(renderer.view);
+
+ requestAnimFrame( animate );
+
+ // create a texture from an image path
+ var texture = PIXI.Texture.fromImage(baseUri + "/bunny.png");
+ // create a new Sprite using the texture
+ bunny = new PIXI.Sprite(texture);
+
+ // center the sprites anchor point
+ bunny.anchor.x = 0.5;
+ bunny.anchor.y = 0.5;
+
+ // move the sprite t the center of the screen
+ bunny.position.x = 200;
+ bunny.position.y = 150;
+
+ stage.addChild(bunny);
+ }
+
+ it('assets loaded', function (done) {
+ var loader = new PIXI.AssetLoader([
+ baseUri + '/bunny.png',
+ baseUri + '/frame-30.png',
+ baseUri + '/frame-60.png',
+ baseUri + '/frame-90.png'
+ ]);
+ // loader.on('onProgress', function (event) {
+ // console.log(event.content);
+ // });
+ loader.on('onComplete', function (event) {
+ done();
+ initScene();
+ });
+ loader.load();
+ });
+
+ it('frame 30 should match', function (done) {
+ this.timeout(700);
+ onFrame(30, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-30.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 60 should match', function (done) {
+ this.timeout(1200);
+ onFrame(60, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-60.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 90 should match', function (done) {
+ this.timeout(1700);
+ onFrame(90, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-90.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ // it('capture something', function (done) {
+ // this.timeout(2000000);
+ // onFrame(30, function () {
+ // var img = new Image();
+ // img.src = renderer.view.toDataURL('image/png');
+ // document.body.appendChild(img);
+ // });
+ // });
+});
diff --git a/test/index.html b/test/index.html
deleted file mode 100644
index 9cbcac5..0000000
--- a/test/index.html
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
- Pixi.js Test Suite
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/test/karma.conf.js b/test/karma.conf.js
new file mode 100644
index 0000000..c66a696
--- /dev/null
+++ b/test/karma.conf.js
@@ -0,0 +1,82 @@
+module.exports = function(config) {
+ config.set({
+
+ // base path, that will be used to resolve files and exclude
+ basePath : '../',
+
+ frameworks : ['mocha'],
+
+ // list of files / patterns to load in the browser
+ files : [
+ 'node_modules/chai/chai.js',
+ 'bin/pixi.dev.js',
+ 'test/lib/**/*.js',
+ 'test/unit/**/*.js',
+ // 'test/functional/**/*.js',
+ {pattern: 'test/**/*.png', watched: false, included: false, served: true}
+ ],
+
+ // list of files to exclude
+ exclude : [],
+
+ // use dolts reporter, as travis terminal does not support escaping sequences
+ // possible values: 'dots', 'progress', 'junit', 'teamcity'
+ // CLI --reporters progress
+ reporters : ['progress'],
+
+ // web server port
+ // CLI --port 9876
+ port : 9876,
+
+ // cli runner port
+ // CLI --runner-port 9100
+ runnerPort : 9100,
+
+ // enable / disable colors in the output (reporters and logs)
+ // CLI --colors --no-colors
+ colors : true,
+
+ // level of logging
+ // possible values: karma.LOG_DISABLE || karma.LOG_ERROR || karma.LOG_WARN || karma.LOG_INFO || karma.LOG_DEBUG
+ // CLI --log-level debug
+ logLevel : config.LOG_DEBUG,
+
+ // enable / disable watching file and executing tests whenever any file changes
+ // CLI --auto-watch --no-auto-watch
+ autoWatch : false,
+
+ // Start these browsers, currently available:
+ // - Chrome
+ // - ChromeCanary
+ // - Firefox
+ // - Opera
+ // - Safari (only Mac)
+ // - PhantomJS
+ // - IE (only Windows)
+ // CLI --browsers Chrome,Firefox,Safari
+ browsers : ['Firefox'],
+
+ // If browser does not capture in given timeout [ms], kill it
+ // CLI --capture-timeout 5000
+ captureTimeout : 5000,
+
+ // Auto run tests on start (when browsers are captured) and exit
+ // CLI --single-run --no-single-run
+ singleRun : true,
+
+ // report which specs are slower than 500ms
+ // CLI --report-slower-than 500
+ reportSlowerThan : 1000,
+
+ preprocessors : {
+ // '**/client/js/*.js': 'coverage'
+ },
+
+ plugins : [
+ 'karma-mocha',
+ // 'karma-chrome-launcher',
+ 'karma-firefox-launcher',
+ // 'karma-phantomjs-launcher'
+ ]
+ });
+};
diff --git a/test/lib/pixi/core/Matrix.js b/test/lib/pixi/core/Matrix.js
new file mode 100644
index 0000000..d26386b
--- /dev/null
+++ b/test/lib/pixi/core/Matrix.js
@@ -0,0 +1,40 @@
+
+function pixi_core_Matrix_confirmNewMat3(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(1);
+ expect(matrix[5]).to.equal(0);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(1);
+}
+
+function pixi_core_Matrix_confirmNewMat4(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[0]).to.equal(1);
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(0);
+ expect(matrix[5]).to.equal(1);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(0);
+ expect(matrix[9]).to.equal(0);
+ expect(matrix[10]).to.equal(1);
+ expect(matrix[11]).to.equal(0);
+ expect(matrix[12]).to.equal(0);
+ expect(matrix[13]).to.equal(0);
+ expect(matrix[14]).to.equal(0);
+ expect(matrix[15]).to.equal(1);
+}
diff --git a/test/lib/pixi/core/Point.js b/test/lib/pixi/core/Point.js
new file mode 100644
index 0000000..e5df07b
--- /dev/null
+++ b/test/lib/pixi/core/Point.js
@@ -0,0 +1,10 @@
+
+function pixi_core_Point_confirm(obj, x, y) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Point);
+ expect(obj).to.respondTo('clone');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+}
diff --git a/test/lib/pixi/core/Rectangle.js b/test/lib/pixi/core/Rectangle.js
new file mode 100644
index 0000000..23f0d12
--- /dev/null
+++ b/test/lib/pixi/core/Rectangle.js
@@ -0,0 +1,13 @@
+
+function pixi_core_Rectangle_confirm(obj, x, y, width, height) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Rectangle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+ expect(obj).to.have.property('width', width);
+ expect(obj).to.have.property('height', height);
+}
diff --git a/test/lib/pixi/display/DisplayObject.js b/test/lib/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..1388a7f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObject.js
@@ -0,0 +1,43 @@
+
+function pixi_display_DisplayObject_confirmNew(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObject);
+ expect(obj).to.respondTo('setInteractive');
+ expect(obj).to.respondTo('addFilter');
+ expect(obj).to.respondTo('removeFilter');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.property('last', obj);
+ expect(obj).to.have.property('first', obj);
+
+ expect(obj).to.contain.property('position');
+ pixi_core_Point_confirm(obj.position, 0, 0);
+ expect(obj).to.contain.property('scale');
+ pixi_core_Point_confirm(obj.scale, 1, 1);
+ expect(obj).to.contain.property('pivot');
+ pixi_core_Point_confirm(obj.pivot, 0, 0);
+
+ expect(obj).to.have.property('rotation', 0);
+ expect(obj).to.have.property('alpha', 1);
+ expect(obj).to.have.property('visible', true);
+ expect(obj).to.have.property('buttonMode', false);
+ expect(obj).to.have.property('parent', null);
+ expect(obj).to.have.property('worldAlpha', 1);
+
+ expect(obj).to.have.property('hitArea');
+ expect(obj).to.have.property('interactive'); // TODO: Have a better default value
+ expect('mask' in obj).to.be.true; // TODO: Have a better default value
+ expect(obj.mask).to.be.undefined;
+
+ expect(obj).to.have.property('renderable');
+ expect(obj).to.have.property('stage');
+
+ expect(obj).to.have.deep.property('worldTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ expect(obj).to.have.deep.property('localTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.localTransform);
+
+ expect(obj).to.have.deep.property('color.length', 0);
+ expect(obj).to.have.property('dynamic', true);
+}
diff --git a/test/lib/pixi/display/DisplayObjectContainer.js b/test/lib/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..085c59f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,16 @@
+
+function pixi_display_DisplayObjectContainer_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObject_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObjectContainer);
+ expect(obj).to.respondTo('addChild');
+ expect(obj).to.respondTo('addChildAt');
+ expect(obj).to.respondTo('swapChildren');
+ expect(obj).to.respondTo('getChildAt');
+ expect(obj).to.respondTo('removeChild');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('children.length', 0);
+}
diff --git a/test/lib/pixi/display/Sprite.js b/test/lib/pixi/display/Sprite.js
new file mode 100644
index 0000000..cc7a2d6
--- /dev/null
+++ b/test/lib/pixi/display/Sprite.js
@@ -0,0 +1,28 @@
+
+function pixi_display_Sprite_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Sprite);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', true);
+ expect(obj).to.have.property('stage', null);
+
+ expect(obj).to.have.property('anchor');
+ pixi_core_Point_confirm(obj.anchor, 0, 0);
+
+ expect(obj).to.have.property('blendMode', PIXI.blendModes.NORMAL);
+ expect(obj).to.have.property('width', 1); // TODO: is 1 expected
+ expect(obj).to.have.property('height', 1); // TODO: is 1 expected
+
+ // FIXME: Just make this a boolean that is always there
+ expect(!!obj.updateFrame).to.equal(obj.texture.baseTexture.hasLoaded);
+
+ expect(obj).to.have.property('texture');
+ pixi_textures_Texture_confirmNew(obj.texture, done);
+}
diff --git a/test/lib/pixi/extras/Strip.js b/test/lib/pixi/extras/Strip.js
new file mode 100644
index 0000000..8927a8a
--- /dev/null
+++ b/test/lib/pixi/extras/Strip.js
@@ -0,0 +1,12 @@
+
+function pixi_extras_Strip_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Strip);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ // TODO: Test properties
+}
diff --git a/test/lib/pixi/textures/Texture.js b/test/lib/pixi/textures/Texture.js
new file mode 100644
index 0000000..d5867b6
--- /dev/null
+++ b/test/lib/pixi/textures/Texture.js
@@ -0,0 +1,31 @@
+
+function pixi_textures_Texture_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ function confirmFrameDone() {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, obj.baseTexture.width, obj.baseTexture.height);
+
+ expect(obj).to.have.property('width', obj.baseTexture.width);
+ expect(obj).to.have.property('height', obj.baseTexture.height);
+ done();
+ }
+
+ expect(obj).to.be.an.instanceof(PIXI.Texture);
+ pixi_utils_EventTarget_like(obj);
+
+ expect(obj).to.have.property('baseTexture')
+ .and.to.be.an.instanceof(PIXI.BaseTexture);
+
+ expect(obj).to.have.property('scope', obj);
+
+ expect(obj).to.have.property('trim');
+ pixi_core_Point_confirm(obj.trim, 0, 0);
+
+ expect(obj).to.have.property('frame');
+ if (obj.baseTexture.hasLoaded) {
+ confirmFrameDone();
+ } else {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, 1, 1);
+ obj.addEventListener('update', confirmFrameDone);
+ }
+}
diff --git a/test/lib/pixi/utils/EventTarget.js b/test/lib/pixi/utils/EventTarget.js
new file mode 100644
index 0000000..7b1dcfa
--- /dev/null
+++ b/test/lib/pixi/utils/EventTarget.js
@@ -0,0 +1,8 @@
+
+function pixi_utils_EventTarget_like(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.respondTo('addEventListener');
+ expect(obj).to.respondTo('dispatchEvent');
+ expect(obj).to.respondTo('removeEventListener');
+}
diff --git a/test/lib/qunit-1.11.0.css b/test/lib/qunit-1.11.0.css
deleted file mode 100644
index d7fc0c8..0000000
--- a/test/lib/qunit-1.11.0.css
+++ /dev/null
@@ -1,244 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-/** Font Family and Sizes */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
- font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
-}
-
-#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
-#qunit-tests { font-size: smaller; }
-
-
-/** Resets */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter {
- margin: 0;
- padding: 0;
-}
-
-
-/** Header */
-
-#qunit-header {
- padding: 0.5em 0 0.5em 1em;
-
- color: #8699a4;
- background-color: #0d3349;
-
- font-size: 1.5em;
- line-height: 1em;
- font-weight: normal;
-
- border-radius: 5px 5px 0 0;
- -moz-border-radius: 5px 5px 0 0;
- -webkit-border-top-right-radius: 5px;
- -webkit-border-top-left-radius: 5px;
-}
-
-#qunit-header a {
- text-decoration: none;
- color: #c2ccd1;
-}
-
-#qunit-header a:hover,
-#qunit-header a:focus {
- color: #fff;
-}
-
-#qunit-testrunner-toolbar label {
- display: inline-block;
- padding: 0 .5em 0 .1em;
-}
-
-#qunit-banner {
- height: 5px;
-}
-
-#qunit-testrunner-toolbar {
- padding: 0.5em 0 0.5em 2em;
- color: #5E740B;
- background-color: #eee;
- overflow: hidden;
-}
-
-#qunit-userAgent {
- padding: 0.5em 0 0.5em 2.5em;
- background-color: #2b81af;
- color: #fff;
- text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
-}
-
-#qunit-modulefilter-container {
- float: right;
-}
-
-/** Tests: Pass/Fail */
-
-#qunit-tests {
- list-style-position: inside;
-}
-
-#qunit-tests li {
- padding: 0.4em 0.5em 0.4em 2.5em;
- border-bottom: 1px solid #fff;
- list-style-position: inside;
-}
-
-#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running {
- display: none;
-}
-
-#qunit-tests li strong {
- cursor: pointer;
-}
-
-#qunit-tests li a {
- padding: 0.5em;
- color: #c2ccd1;
- text-decoration: none;
-}
-#qunit-tests li a:hover,
-#qunit-tests li a:focus {
- color: #000;
-}
-
-#qunit-tests li .runtime {
- float: right;
- font-size: smaller;
-}
-
-.qunit-assert-list {
- margin-top: 0.5em;
- padding: 0.5em;
-
- background-color: #fff;
-
- border-radius: 5px;
- -moz-border-radius: 5px;
- -webkit-border-radius: 5px;
-}
-
-.qunit-collapsed {
- display: none;
-}
-
-#qunit-tests table {
- border-collapse: collapse;
- margin-top: .2em;
-}
-
-#qunit-tests th {
- text-align: right;
- vertical-align: top;
- padding: 0 .5em 0 0;
-}
-
-#qunit-tests td {
- vertical-align: top;
-}
-
-#qunit-tests pre {
- margin: 0;
- white-space: pre-wrap;
- word-wrap: break-word;
-}
-
-#qunit-tests del {
- background-color: #e0f2be;
- color: #374e0c;
- text-decoration: none;
-}
-
-#qunit-tests ins {
- background-color: #ffcaca;
- color: #500;
- text-decoration: none;
-}
-
-/*** Test Counts */
-
-#qunit-tests b.counts { color: black; }
-#qunit-tests b.passed { color: #5E740B; }
-#qunit-tests b.failed { color: #710909; }
-
-#qunit-tests li li {
- padding: 5px;
- background-color: #fff;
- border-bottom: none;
- list-style-position: inside;
-}
-
-/*** Passing Styles */
-
-#qunit-tests li li.pass {
- color: #3c510c;
- background-color: #fff;
- border-left: 10px solid #C6E746;
-}
-
-#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
-#qunit-tests .pass .test-name { color: #366097; }
-
-#qunit-tests .pass .test-actual,
-#qunit-tests .pass .test-expected { color: #999999; }
-
-#qunit-banner.qunit-pass { background-color: #C6E746; }
-
-/*** Failing Styles */
-
-#qunit-tests li li.fail {
- color: #710909;
- background-color: #fff;
- border-left: 10px solid #EE5757;
- white-space: pre;
-}
-
-#qunit-tests > li:last-child {
- border-radius: 0 0 5px 5px;
- -moz-border-radius: 0 0 5px 5px;
- -webkit-border-bottom-right-radius: 5px;
- -webkit-border-bottom-left-radius: 5px;
-}
-
-#qunit-tests .fail { color: #000000; background-color: #EE5757; }
-#qunit-tests .fail .test-name,
-#qunit-tests .fail .module-name { color: #000000; }
-
-#qunit-tests .fail .test-actual { color: #EE5757; }
-#qunit-tests .fail .test-expected { color: green; }
-
-#qunit-banner.qunit-fail { background-color: #EE5757; }
-
-
-/** Result */
-
-#qunit-testresult {
- padding: 0.5em 0.5em 0.5em 2.5em;
-
- color: #2b81af;
- background-color: #D2E0E6;
-
- border-bottom: 1px solid white;
-}
-#qunit-testresult .module-name {
- font-weight: bold;
-}
-
-/** Fixture */
-
-#qunit-fixture {
- position: absolute;
- top: -10000px;
- left: -10000px;
- width: 1000px;
- height: 1000px;
-}
diff --git a/test/lib/qunit-1.11.0.js b/test/lib/qunit-1.11.0.js
deleted file mode 100644
index 302545f..0000000
--- a/test/lib/qunit-1.11.0.js
+++ /dev/null
@@ -1,2152 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-(function( window ) {
-
-var QUnit,
- assert,
- config,
- onErrorFnPrev,
- testId = 0,
- fileName = (sourceFromStacktrace( 0 ) || "" ).replace(/(:\d+)+\)?/, "").replace(/.+\//, ""),
- toString = Object.prototype.toString,
- hasOwn = Object.prototype.hasOwnProperty,
- // Keep a local reference to Date (GH-283)
- Date = window.Date,
- defined = {
- setTimeout: typeof window.setTimeout !== "undefined",
- sessionStorage: (function() {
- var x = "qunit-test-string";
- try {
- sessionStorage.setItem( x, x );
- sessionStorage.removeItem( x );
- return true;
- } catch( e ) {
- return false;
- }
- }())
- },
- /**
- * Provides a normalized error string, correcting an issue
- * with IE 7 (and prior) where Error.prototype.toString is
- * not properly implemented
- *
- * Based on http://es5.github.com/#x15.11.4.4
- *
- * @param {String|Error} error
- * @return {String} error message
- */
- errorString = function( error ) {
- var name, message,
- errorString = error.toString();
- if ( errorString.substring( 0, 7 ) === "[object" ) {
- name = error.name ? error.name.toString() : "Error";
- message = error.message ? error.message.toString() : "";
- if ( name && message ) {
- return name + ": " + message;
- } else if ( name ) {
- return name;
- } else if ( message ) {
- return message;
- } else {
- return "Error";
- }
- } else {
- return errorString;
- }
- },
- /**
- * Makes a clone of an object using only Array or Object as base,
- * and copies over the own enumerable properties.
- *
- * @param {Object} obj
- * @return {Object} New object with only the own properties (recursively).
- */
- objectValues = function( obj ) {
- // Grunt 0.3.x uses an older version of jshint that still has jshint/jshint#392.
- /*jshint newcap: false */
- var key, val,
- vals = QUnit.is( "array", obj ) ? [] : {};
- for ( key in obj ) {
- if ( hasOwn.call( obj, key ) ) {
- val = obj[key];
- vals[key] = val === Object(val) ? objectValues(val) : val;
- }
- }
- return vals;
- };
-
-function Test( settings ) {
- extend( this, settings );
- this.assertions = [];
- this.testNumber = ++Test.count;
-}
-
-Test.count = 0;
-
-Test.prototype = {
- init: function() {
- var a, b, li,
- tests = id( "qunit-tests" );
-
- if ( tests ) {
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml;
-
- // `a` initialized at top of scope
- a = document.createElement( "a" );
- a.innerHTML = "Rerun";
- a.href = QUnit.url({ testNumber: this.testNumber });
-
- li = document.createElement( "li" );
- li.appendChild( b );
- li.appendChild( a );
- li.className = "running";
- li.id = this.id = "qunit-test-output" + testId++;
-
- tests.appendChild( li );
- }
- },
- setup: function() {
- if ( this.module !== config.previousModule ) {
- if ( config.previousModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.previousModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
- config.previousModule = this.module;
- config.moduleStats = { all: 0, bad: 0 };
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- } else if ( config.autorun ) {
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- }
-
- config.current = this;
-
- this.testEnvironment = extend({
- setup: function() {},
- teardown: function() {}
- }, this.moduleTestEnvironment );
-
- this.started = +new Date();
- runLoggingCallbacks( "testStart", QUnit, {
- name: this.testName,
- module: this.module
- });
-
- // allow utility functions to access the current test environment
- // TODO why??
- QUnit.current_testEnvironment = this.testEnvironment;
-
- if ( !config.pollution ) {
- saveGlobal();
- }
- if ( config.notrycatch ) {
- this.testEnvironment.setup.call( this.testEnvironment );
- return;
- }
- try {
- this.testEnvironment.setup.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Setup failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- },
- run: function() {
- config.current = this;
-
- var running = id( "qunit-testresult" );
-
- if ( running ) {
- running.innerHTML = "Running:
" + this.nameHtml;
- }
-
- if ( this.async ) {
- QUnit.stop();
- }
-
- this.callbackStarted = +new Date();
-
- if ( config.notrycatch ) {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- return;
- }
-
- try {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- } catch( e ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
-
- QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + " " + this.stack + ": " + ( e.message || e ), extractStacktrace( e, 0 ) );
- // else next test will carry the responsibility
- saveGlobal();
-
- // Restart the tests if they're blocking
- if ( config.blocking ) {
- QUnit.start();
- }
- }
- },
- teardown: function() {
- config.current = this;
- if ( config.notrycatch ) {
- if ( typeof this.callbackRuntime === "undefined" ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
- }
- this.testEnvironment.teardown.call( this.testEnvironment );
- return;
- } else {
- try {
- this.testEnvironment.teardown.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Teardown failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- }
- checkPollution();
- },
- finish: function() {
- config.current = this;
- if ( config.requireExpects && this.expected === null ) {
- QUnit.pushFailure( "Expected number of assertions to be defined, but expect() was not called.", this.stack );
- } else if ( this.expected !== null && this.expected !== this.assertions.length ) {
- QUnit.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack );
- } else if ( this.expected === null && !this.assertions.length ) {
- QUnit.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions.", this.stack );
- }
-
- var i, assertion, a, b, time, li, ol,
- test = this,
- good = 0,
- bad = 0,
- tests = id( "qunit-tests" );
-
- this.runtime = +new Date() - this.started;
- config.stats.all += this.assertions.length;
- config.moduleStats.all += this.assertions.length;
-
- if ( tests ) {
- ol = document.createElement( "ol" );
- ol.className = "qunit-assert-list";
-
- for ( i = 0; i < this.assertions.length; i++ ) {
- assertion = this.assertions[i];
-
- li = document.createElement( "li" );
- li.className = assertion.result ? "pass" : "fail";
- li.innerHTML = assertion.message || ( assertion.result ? "okay" : "failed" );
- ol.appendChild( li );
-
- if ( assertion.result ) {
- good++;
- } else {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
-
- // store result when possible
- if ( QUnit.config.reorder && defined.sessionStorage ) {
- if ( bad ) {
- sessionStorage.setItem( "qunit-test-" + this.module + "-" + this.testName, bad );
- } else {
- sessionStorage.removeItem( "qunit-test-" + this.module + "-" + this.testName );
- }
- }
-
- if ( bad === 0 ) {
- addClass( ol, "qunit-collapsed" );
- }
-
- // `b` initialized at top of scope
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml + " (" + bad + ", " + good + ", " + this.assertions.length + ")";
-
- addEvent(b, "click", function() {
- var next = b.parentNode.lastChild,
- collapsed = hasClass( next, "qunit-collapsed" );
- ( collapsed ? removeClass : addClass )( next, "qunit-collapsed" );
- });
-
- addEvent(b, "dblclick", function( e ) {
- var target = e && e.target ? e.target : window.event.srcElement;
- if ( target.nodeName.toLowerCase() === "span" || target.nodeName.toLowerCase() === "b" ) {
- target = target.parentNode;
- }
- if ( window.location && target.nodeName.toLowerCase() === "strong" ) {
- window.location = QUnit.url({ testNumber: test.testNumber });
- }
- });
-
- // `time` initialized at top of scope
- time = document.createElement( "span" );
- time.className = "runtime";
- time.innerHTML = this.runtime + " ms";
-
- // `li` initialized at top of scope
- li = id( this.id );
- li.className = bad ? "fail" : "pass";
- li.removeChild( li.firstChild );
- a = li.firstChild;
- li.appendChild( b );
- li.appendChild( a );
- li.appendChild( time );
- li.appendChild( ol );
-
- } else {
- for ( i = 0; i < this.assertions.length; i++ ) {
- if ( !this.assertions[i].result ) {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
- }
-
- runLoggingCallbacks( "testDone", QUnit, {
- name: this.testName,
- module: this.module,
- failed: bad,
- passed: this.assertions.length - bad,
- total: this.assertions.length,
- duration: this.runtime
- });
-
- QUnit.reset();
-
- config.current = undefined;
- },
-
- queue: function() {
- var bad,
- test = this;
-
- synchronize(function() {
- test.init();
- });
- function run() {
- // each of these can by async
- synchronize(function() {
- test.setup();
- });
- synchronize(function() {
- test.run();
- });
- synchronize(function() {
- test.teardown();
- });
- synchronize(function() {
- test.finish();
- });
- }
-
- // `bad` initialized at top of scope
- // defer when previous test run passed, if storage is available
- bad = QUnit.config.reorder && defined.sessionStorage &&
- +sessionStorage.getItem( "qunit-test-" + this.module + "-" + this.testName );
-
- if ( bad ) {
- run();
- } else {
- synchronize( run, true );
- }
- }
-};
-
-// Root QUnit object.
-// `QUnit` initialized at top of scope
-QUnit = {
-
- // call on start of module test to prepend name to all tests
- module: function( name, testEnvironment ) {
- config.currentModule = name;
- config.currentModuleTestEnvironment = testEnvironment;
- config.modules[name] = true;
- },
-
- asyncTest: function( testName, expected, callback ) {
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- QUnit.test( testName, expected, callback, true );
- },
-
- test: function( testName, expected, callback, async ) {
- var test,
- nameHtml = "" + escapeText( testName ) + "";
-
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- if ( config.currentModule ) {
- nameHtml = "" + escapeText( config.currentModule ) + ": " + nameHtml;
- }
-
- test = new Test({
- nameHtml: nameHtml,
- testName: testName,
- expected: expected,
- async: async,
- callback: callback,
- module: config.currentModule,
- moduleTestEnvironment: config.currentModuleTestEnvironment,
- stack: sourceFromStacktrace( 2 )
- });
-
- if ( !validTest( test ) ) {
- return;
- }
-
- test.queue();
- },
-
- // Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through.
- expect: function( asserts ) {
- if (arguments.length === 1) {
- config.current.expected = asserts;
- } else {
- return config.current.expected;
- }
- },
-
- start: function( count ) {
- // QUnit hasn't been initialized yet.
- // Note: RequireJS (et al) may delay onLoad
- if ( config.semaphore === undefined ) {
- QUnit.begin(function() {
- // This is triggered at the top of QUnit.load, push start() to the event loop, to allow QUnit.load to finish first
- setTimeout(function() {
- QUnit.start( count );
- });
- });
- return;
- }
-
- config.semaphore -= count || 1;
- // don't start until equal number of stop-calls
- if ( config.semaphore > 0 ) {
- return;
- }
- // ignore if start is called more often then stop
- if ( config.semaphore < 0 ) {
- config.semaphore = 0;
- QUnit.pushFailure( "Called start() while already started (QUnit.config.semaphore was 0 already)", null, sourceFromStacktrace(2) );
- return;
- }
- // A slight delay, to avoid any current callbacks
- if ( defined.setTimeout ) {
- window.setTimeout(function() {
- if ( config.semaphore > 0 ) {
- return;
- }
- if ( config.timeout ) {
- clearTimeout( config.timeout );
- }
-
- config.blocking = false;
- process( true );
- }, 13);
- } else {
- config.blocking = false;
- process( true );
- }
- },
-
- stop: function( count ) {
- config.semaphore += count || 1;
- config.blocking = true;
-
- if ( config.testTimeout && defined.setTimeout ) {
- clearTimeout( config.timeout );
- config.timeout = window.setTimeout(function() {
- QUnit.ok( false, "Test timed out" );
- config.semaphore = 1;
- QUnit.start();
- }, config.testTimeout );
- }
- }
-};
-
-// `assert` initialized at top of scope
-// Asssert helpers
-// All of these must either call QUnit.push() or manually do:
-// - runLoggingCallbacks( "log", .. );
-// - config.current.assertions.push({ .. });
-// We attach it to the QUnit object *after* we expose the public API,
-// otherwise `assert` will become a global variable in browsers (#341).
-assert = {
- /**
- * Asserts rough true-ish result.
- * @name ok
- * @function
- * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" );
- */
- ok: function( result, msg ) {
- if ( !config.current ) {
- throw new Error( "ok() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
- result = !!result;
-
- var source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: msg
- };
-
- msg = escapeText( msg || (result ? "okay" : "failed" ) );
- msg = "" + msg + "";
-
- if ( !result ) {
- source = sourceFromStacktrace( 2 );
- if ( source ) {
- details.source = source;
- msg += "Source: | " + escapeText( source ) + " |
---|
";
- }
- }
- runLoggingCallbacks( "log", QUnit, details );
- config.current.assertions.push({
- result: result,
- message: msg
- });
- },
-
- /**
- * Assert that the first two arguments are equal, with an optional message.
- * Prints out both actual and expected values.
- * @name equal
- * @function
- * @example equal( format( "Received {0} bytes.", 2), "Received 2 bytes.", "format() replaces {0} with next argument" );
- */
- equal: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected == actual, actual, expected, message );
- },
-
- /**
- * @name notEqual
- * @function
- */
- notEqual: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected != actual, actual, expected, message );
- },
-
- /**
- * @name propEqual
- * @function
- */
- propEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notPropEqual
- * @function
- */
- notPropEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name deepEqual
- * @function
- */
- deepEqual: function( actual, expected, message ) {
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notDeepEqual
- * @function
- */
- notDeepEqual: function( actual, expected, message ) {
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name strictEqual
- * @function
- */
- strictEqual: function( actual, expected, message ) {
- QUnit.push( expected === actual, actual, expected, message );
- },
-
- /**
- * @name notStrictEqual
- * @function
- */
- notStrictEqual: function( actual, expected, message ) {
- QUnit.push( expected !== actual, actual, expected, message );
- },
-
- "throws": function( block, expected, message ) {
- var actual,
- expectedOutput = expected,
- ok = false;
-
- // 'expected' is optional
- if ( typeof expected === "string" ) {
- message = expected;
- expected = null;
- }
-
- config.current.ignoreGlobalErrors = true;
- try {
- block.call( config.current.testEnvironment );
- } catch (e) {
- actual = e;
- }
- config.current.ignoreGlobalErrors = false;
-
- if ( actual ) {
- // we don't want to validate thrown error
- if ( !expected ) {
- ok = true;
- expectedOutput = null;
- // expected is a regexp
- } else if ( QUnit.objectType( expected ) === "regexp" ) {
- ok = expected.test( errorString( actual ) );
- // expected is a constructor
- } else if ( actual instanceof expected ) {
- ok = true;
- // expected is a validation function which returns true is validation passed
- } else if ( expected.call( {}, actual ) === true ) {
- expectedOutput = null;
- ok = true;
- }
-
- QUnit.push( ok, actual, expectedOutput, message );
- } else {
- QUnit.pushFailure( message, null, 'No exception was thrown.' );
- }
- }
-};
-
-/**
- * @deprecate since 1.8.0
- * Kept assertion helpers in root for backwards compatibility.
- */
-extend( QUnit, assert );
-
-/**
- * @deprecated since 1.9.0
- * Kept root "raises()" for backwards compatibility.
- * (Note that we don't introduce assert.raises).
- */
-QUnit.raises = assert[ "throws" ];
-
-/**
- * @deprecated since 1.0.0, replaced with error pushes since 1.3.0
- * Kept to avoid TypeErrors for undefined methods.
- */
-QUnit.equals = function() {
- QUnit.push( false, false, false, "QUnit.equals has been deprecated since 2009 (e88049a0), use QUnit.equal instead" );
-};
-QUnit.same = function() {
- QUnit.push( false, false, false, "QUnit.same has been deprecated since 2009 (e88049a0), use QUnit.deepEqual instead" );
-};
-
-// We want access to the constructor's prototype
-(function() {
- function F() {}
- F.prototype = QUnit;
- QUnit = new F();
- // Make F QUnit's constructor so that we can add to the prototype later
- QUnit.constructor = F;
-}());
-
-/**
- * Config object: Maintain internal state
- * Later exposed as QUnit.config
- * `config` initialized at top of scope
- */
-config = {
- // The queue of tests to run
- queue: [],
-
- // block until document ready
- blocking: true,
-
- // when enabled, show only failing tests
- // gets persisted through sessionStorage and can be changed in UI via checkbox
- hidepassed: false,
-
- // by default, run previously failed tests first
- // very useful in combination with "Hide passed tests" checked
- reorder: true,
-
- // by default, modify document.title when suite is done
- altertitle: true,
-
- // when enabled, all tests must call expect()
- requireExpects: false,
-
- // add checkboxes that are persisted in the query-string
- // when enabled, the id is set to `true` as a `QUnit.config` property
- urlConfig: [
- {
- id: "noglobals",
- label: "Check for Globals",
- tooltip: "Enabling this will test if any test introduces new properties on the `window` object. Stored as query-strings."
- },
- {
- id: "notrycatch",
- label: "No try-catch",
- tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging exceptions in IE reasonable. Stored as query-strings."
- }
- ],
-
- // Set of all modules.
- modules: {},
-
- // logging callback queues
- begin: [],
- done: [],
- log: [],
- testStart: [],
- testDone: [],
- moduleStart: [],
- moduleDone: []
-};
-
-// Export global variables, unless an 'exports' object exists,
-// in that case we assume we're in CommonJS (dealt with on the bottom of the script)
-if ( typeof exports === "undefined" ) {
- extend( window, QUnit );
-
- // Expose QUnit object
- window.QUnit = QUnit;
-}
-
-// Initialize more QUnit.config and QUnit.urlParams
-(function() {
- var i,
- location = window.location || { search: "", protocol: "file:" },
- params = location.search.slice( 1 ).split( "&" ),
- length = params.length,
- urlParams = {},
- current;
-
- if ( params[ 0 ] ) {
- for ( i = 0; i < length; i++ ) {
- current = params[ i ].split( "=" );
- current[ 0 ] = decodeURIComponent( current[ 0 ] );
- // allow just a key to turn on a flag, e.g., test.html?noglobals
- current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true;
- urlParams[ current[ 0 ] ] = current[ 1 ];
- }
- }
-
- QUnit.urlParams = urlParams;
-
- // String search anywhere in moduleName+testName
- config.filter = urlParams.filter;
-
- // Exact match of the module name
- config.module = urlParams.module;
-
- config.testNumber = parseInt( urlParams.testNumber, 10 ) || null;
-
- // Figure out if we're running the tests from a server or not
- QUnit.isLocal = location.protocol === "file:";
-}());
-
-// Extend QUnit object,
-// these after set here because they should not be exposed as global functions
-extend( QUnit, {
- assert: assert,
-
- config: config,
-
- // Initialize the configuration options
- init: function() {
- extend( config, {
- stats: { all: 0, bad: 0 },
- moduleStats: { all: 0, bad: 0 },
- started: +new Date(),
- updateRate: 1000,
- blocking: false,
- autostart: true,
- autorun: false,
- filter: "",
- queue: [],
- semaphore: 1
- });
-
- var tests, banner, result,
- qunit = id( "qunit" );
-
- if ( qunit ) {
- qunit.innerHTML =
- "" +
- "" +
- "" +
- "" +
- "
";
- }
-
- tests = id( "qunit-tests" );
- banner = id( "qunit-banner" );
- result = id( "qunit-testresult" );
-
- if ( tests ) {
- tests.innerHTML = "";
- }
-
- if ( banner ) {
- banner.className = "";
- }
-
- if ( result ) {
- result.parentNode.removeChild( result );
- }
-
- if ( tests ) {
- result = document.createElement( "p" );
- result.id = "qunit-testresult";
- result.className = "result";
- tests.parentNode.insertBefore( result, tests );
- result.innerHTML = "Running...
";
- }
- },
-
- // Resets the test setup. Useful for tests that modify the DOM.
- reset: function() {
- var fixture = id( "qunit-fixture" );
- if ( fixture ) {
- fixture.innerHTML = config.fixture;
- }
- },
-
- // Trigger an event on an element.
- // @example triggerEvent( document.body, "click" );
- triggerEvent: function( elem, type, event ) {
- if ( document.createEvent ) {
- event = document.createEvent( "MouseEvents" );
- event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView,
- 0, 0, 0, 0, 0, false, false, false, false, 0, null);
-
- elem.dispatchEvent( event );
- } else if ( elem.fireEvent ) {
- elem.fireEvent( "on" + type );
- }
- },
-
- // Safe object type checking
- is: function( type, obj ) {
- return QUnit.objectType( obj ) === type;
- },
-
- objectType: function( obj ) {
- if ( typeof obj === "undefined" ) {
- return "undefined";
- // consider: typeof null === object
- }
- if ( obj === null ) {
- return "null";
- }
-
- var match = toString.call( obj ).match(/^\[object\s(.*)\]$/),
- type = match && match[1] || "";
-
- switch ( type ) {
- case "Number":
- if ( isNaN(obj) ) {
- return "nan";
- }
- return "number";
- case "String":
- case "Boolean":
- case "Array":
- case "Date":
- case "RegExp":
- case "Function":
- return type.toLowerCase();
- }
- if ( typeof obj === "object" ) {
- return "object";
- }
- return undefined;
- },
-
- push: function( result, actual, expected, message ) {
- if ( !config.current ) {
- throw new Error( "assertion outside test context, was " + sourceFromStacktrace() );
- }
-
- var output, source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: message,
- actual: actual,
- expected: expected
- };
-
- message = escapeText( message ) || ( result ? "okay" : "failed" );
- message = "" + message + "";
- output = message;
-
- if ( !result ) {
- expected = escapeText( QUnit.jsDump.parse(expected) );
- actual = escapeText( QUnit.jsDump.parse(actual) );
- output += "Expected: | " + expected + " |
";
-
- if ( actual !== expected ) {
- output += "Result: | " + actual + " |
";
- output += "Diff: | " + QUnit.diff( expected, actual ) + " |
";
- }
-
- source = sourceFromStacktrace();
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
- }
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: !!result,
- message: output
- });
- },
-
- pushFailure: function( message, source, actual ) {
- if ( !config.current ) {
- throw new Error( "pushFailure() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
-
- var output,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: false,
- message: message
- };
-
- message = escapeText( message ) || "error";
- message = "" + message + "";
- output = message;
-
- output += "";
-
- if ( actual ) {
- output += "Result: | " + escapeText( actual ) + " |
";
- }
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: false,
- message: output
- });
- },
-
- url: function( params ) {
- params = extend( extend( {}, QUnit.urlParams ), params );
- var key,
- querystring = "?";
-
- for ( key in params ) {
- if ( !hasOwn.call( params, key ) ) {
- continue;
- }
- querystring += encodeURIComponent( key ) + "=" +
- encodeURIComponent( params[ key ] ) + "&";
- }
- return window.location.protocol + "//" + window.location.host +
- window.location.pathname + querystring.slice( 0, -1 );
- },
-
- extend: extend,
- id: id,
- addEvent: addEvent
- // load, equiv, jsDump, diff: Attached later
-});
-
-/**
- * @deprecated: Created for backwards compatibility with test runner that set the hook function
- * into QUnit.{hook}, instead of invoking it and passing the hook function.
- * QUnit.constructor is set to the empty F() above so that we can add to it's prototype here.
- * Doing this allows us to tell if the following methods have been overwritten on the actual
- * QUnit object.
- */
-extend( QUnit.constructor.prototype, {
-
- // Logging callbacks; all receive a single argument with the listed properties
- // run test/logs.html for any related changes
- begin: registerLoggingCallback( "begin" ),
-
- // done: { failed, passed, total, runtime }
- done: registerLoggingCallback( "done" ),
-
- // log: { result, actual, expected, message }
- log: registerLoggingCallback( "log" ),
-
- // testStart: { name }
- testStart: registerLoggingCallback( "testStart" ),
-
- // testDone: { name, failed, passed, total, duration }
- testDone: registerLoggingCallback( "testDone" ),
-
- // moduleStart: { name }
- moduleStart: registerLoggingCallback( "moduleStart" ),
-
- // moduleDone: { name, failed, passed, total }
- moduleDone: registerLoggingCallback( "moduleDone" )
-});
-
-if ( typeof document === "undefined" || document.readyState === "complete" ) {
- config.autorun = true;
-}
-
-QUnit.load = function() {
- runLoggingCallbacks( "begin", QUnit, {} );
-
- // Initialize the config, saving the execution queue
- var banner, filter, i, label, len, main, ol, toolbar, userAgent, val,
- urlConfigCheckboxesContainer, urlConfigCheckboxes, moduleFilter,
- numModules = 0,
- moduleFilterHtml = "",
- urlConfigHtml = "",
- oldconfig = extend( {}, config );
-
- QUnit.init();
- extend(config, oldconfig);
-
- config.blocking = false;
-
- len = config.urlConfig.length;
-
- for ( i = 0; i < len; i++ ) {
- val = config.urlConfig[i];
- if ( typeof val === "string" ) {
- val = {
- id: val,
- label: val,
- tooltip: "[no tooltip available]"
- };
- }
- config[ val.id ] = QUnit.urlParams[ val.id ];
- urlConfigHtml += "";
- }
-
- moduleFilterHtml += "";
-
- // `userAgent` initialized at top of scope
- userAgent = id( "qunit-userAgent" );
- if ( userAgent ) {
- userAgent.innerHTML = navigator.userAgent;
- }
-
- // `banner` initialized at top of scope
- banner = id( "qunit-header" );
- if ( banner ) {
- banner.innerHTML = "" + banner.innerHTML + " ";
- }
-
- // `toolbar` initialized at top of scope
- toolbar = id( "qunit-testrunner-toolbar" );
- if ( toolbar ) {
- // `filter` initialized at top of scope
- filter = document.createElement( "input" );
- filter.type = "checkbox";
- filter.id = "qunit-filter-pass";
-
- addEvent( filter, "click", function() {
- var tmp,
- ol = document.getElementById( "qunit-tests" );
-
- if ( filter.checked ) {
- ol.className = ol.className + " hidepass";
- } else {
- tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " ";
- ol.className = tmp.replace( / hidepass /, " " );
- }
- if ( defined.sessionStorage ) {
- if (filter.checked) {
- sessionStorage.setItem( "qunit-filter-passed-tests", "true" );
- } else {
- sessionStorage.removeItem( "qunit-filter-passed-tests" );
- }
- }
- });
-
- if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem( "qunit-filter-passed-tests" ) ) {
- filter.checked = true;
- // `ol` initialized at top of scope
- ol = document.getElementById( "qunit-tests" );
- ol.className = ol.className + " hidepass";
- }
- toolbar.appendChild( filter );
-
- // `label` initialized at top of scope
- label = document.createElement( "label" );
- label.setAttribute( "for", "qunit-filter-pass" );
- label.setAttribute( "title", "Only show tests and assertons that fail. Stored in sessionStorage." );
- label.innerHTML = "Hide passed tests";
- toolbar.appendChild( label );
-
- urlConfigCheckboxesContainer = document.createElement("span");
- urlConfigCheckboxesContainer.innerHTML = urlConfigHtml;
- urlConfigCheckboxes = urlConfigCheckboxesContainer.getElementsByTagName("input");
- // For oldIE support:
- // * Add handlers to the individual elements instead of the container
- // * Use "click" instead of "change"
- // * Fallback from event.target to event.srcElement
- addEvents( urlConfigCheckboxes, "click", function( event ) {
- var params = {},
- target = event.target || event.srcElement;
- params[ target.name ] = target.checked ? true : undefined;
- window.location = QUnit.url( params );
- });
- toolbar.appendChild( urlConfigCheckboxesContainer );
-
- if (numModules > 1) {
- moduleFilter = document.createElement( 'span' );
- moduleFilter.setAttribute( 'id', 'qunit-modulefilter-container' );
- moduleFilter.innerHTML = moduleFilterHtml;
- addEvent( moduleFilter.lastChild, "change", function() {
- var selectBox = moduleFilter.getElementsByTagName("select")[0],
- selectedModule = decodeURIComponent(selectBox.options[selectBox.selectedIndex].value);
-
- window.location = QUnit.url( { module: ( selectedModule === "" ) ? undefined : selectedModule } );
- });
- toolbar.appendChild(moduleFilter);
- }
- }
-
- // `main` initialized at top of scope
- main = id( "qunit-fixture" );
- if ( main ) {
- config.fixture = main.innerHTML;
- }
-
- if ( config.autostart ) {
- QUnit.start();
- }
-};
-
-addEvent( window, "load", QUnit.load );
-
-// `onErrorFnPrev` initialized at top of scope
-// Preserve other handlers
-onErrorFnPrev = window.onerror;
-
-// Cover uncaught exceptions
-// Returning true will surpress the default browser handler,
-// returning false will let it run.
-window.onerror = function ( error, filePath, linerNr ) {
- var ret = false;
- if ( onErrorFnPrev ) {
- ret = onErrorFnPrev( error, filePath, linerNr );
- }
-
- // Treat return value as window.onerror itself does,
- // Only do our handling if not surpressed.
- if ( ret !== true ) {
- if ( QUnit.config.current ) {
- if ( QUnit.config.current.ignoreGlobalErrors ) {
- return true;
- }
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- } else {
- QUnit.test( "global failure", extend( function() {
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- }, { validTest: validTest } ) );
- }
- return false;
- }
-
- return ret;
-};
-
-function done() {
- config.autorun = true;
-
- // Log the last module results
- if ( config.currentModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.currentModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
-
- var i, key,
- banner = id( "qunit-banner" ),
- tests = id( "qunit-tests" ),
- runtime = +new Date() - config.started,
- passed = config.stats.all - config.stats.bad,
- html = [
- "Tests completed in ",
- runtime,
- " milliseconds.
",
- "",
- passed,
- " assertions of ",
- config.stats.all,
- " passed, ",
- config.stats.bad,
- " failed."
- ].join( "" );
-
- if ( banner ) {
- banner.className = ( config.stats.bad ? "qunit-fail" : "qunit-pass" );
- }
-
- if ( tests ) {
- id( "qunit-testresult" ).innerHTML = html;
- }
-
- if ( config.altertitle && typeof document !== "undefined" && document.title ) {
- // show ✖ for good, ✔ for bad suite result in title
- // use escape sequences in case file gets loaded with non-utf-8-charset
- document.title = [
- ( config.stats.bad ? "\u2716" : "\u2714" ),
- document.title.replace( /^[\u2714\u2716] /i, "" )
- ].join( " " );
- }
-
- // clear own sessionStorage items if all tests passed
- if ( config.reorder && defined.sessionStorage && config.stats.bad === 0 ) {
- // `key` & `i` initialized at top of scope
- for ( i = 0; i < sessionStorage.length; i++ ) {
- key = sessionStorage.key( i++ );
- if ( key.indexOf( "qunit-test-" ) === 0 ) {
- sessionStorage.removeItem( key );
- }
- }
- }
-
- // scroll back to top to show results
- if ( window.scrollTo ) {
- window.scrollTo(0, 0);
- }
-
- runLoggingCallbacks( "done", QUnit, {
- failed: config.stats.bad,
- passed: passed,
- total: config.stats.all,
- runtime: runtime
- });
-}
-
-/** @return Boolean: true if this test should be ran */
-function validTest( test ) {
- var include,
- filter = config.filter && config.filter.toLowerCase(),
- module = config.module && config.module.toLowerCase(),
- fullName = (test.module + ": " + test.testName).toLowerCase();
-
- // Internally-generated tests are always valid
- if ( test.callback && test.callback.validTest === validTest ) {
- delete test.callback.validTest;
- return true;
- }
-
- if ( config.testNumber ) {
- return test.testNumber === config.testNumber;
- }
-
- if ( module && ( !test.module || test.module.toLowerCase() !== module ) ) {
- return false;
- }
-
- if ( !filter ) {
- return true;
- }
-
- include = filter.charAt( 0 ) !== "!";
- if ( !include ) {
- filter = filter.slice( 1 );
- }
-
- // If the filter matches, we need to honour include
- if ( fullName.indexOf( filter ) !== -1 ) {
- return include;
- }
-
- // Otherwise, do the opposite
- return !include;
-}
-
-// so far supports only Firefox, Chrome and Opera (buggy), Safari (for real exceptions)
-// Later Safari and IE10 are supposed to support error.stack as well
-// See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack
-function extractStacktrace( e, offset ) {
- offset = offset === undefined ? 3 : offset;
-
- var stack, include, i;
-
- if ( e.stacktrace ) {
- // Opera
- return e.stacktrace.split( "\n" )[ offset + 3 ];
- } else if ( e.stack ) {
- // Firefox, Chrome
- stack = e.stack.split( "\n" );
- if (/^error$/i.test( stack[0] ) ) {
- stack.shift();
- }
- if ( fileName ) {
- include = [];
- for ( i = offset; i < stack.length; i++ ) {
- if ( stack[ i ].indexOf( fileName ) !== -1 ) {
- break;
- }
- include.push( stack[ i ] );
- }
- if ( include.length ) {
- return include.join( "\n" );
- }
- }
- return stack[ offset ];
- } else if ( e.sourceURL ) {
- // Safari, PhantomJS
- // hopefully one day Safari provides actual stacktraces
- // exclude useless self-reference for generated Error objects
- if ( /qunit.js$/.test( e.sourceURL ) ) {
- return;
- }
- // for actual exceptions, this is useful
- return e.sourceURL + ":" + e.line;
- }
-}
-function sourceFromStacktrace( offset ) {
- try {
- throw new Error();
- } catch ( e ) {
- return extractStacktrace( e, offset );
- }
-}
-
-/**
- * Escape text for attribute or text content.
- */
-function escapeText( s ) {
- if ( !s ) {
- return "";
- }
- s = s + "";
- // Both single quotes and double quotes (for attributes)
- return s.replace( /['"<>&]/g, function( s ) {
- switch( s ) {
- case '\'':
- return ''';
- case '"':
- return '"';
- case '<':
- return '<';
- case '>':
- return '>';
- case '&':
- return '&';
- }
- });
-}
-
-function synchronize( callback, last ) {
- config.queue.push( callback );
-
- if ( config.autorun && !config.blocking ) {
- process( last );
- }
-}
-
-function process( last ) {
- function next() {
- process( last );
- }
- var start = new Date().getTime();
- config.depth = config.depth ? config.depth + 1 : 1;
-
- while ( config.queue.length && !config.blocking ) {
- if ( !defined.setTimeout || config.updateRate <= 0 || ( ( new Date().getTime() - start ) < config.updateRate ) ) {
- config.queue.shift()();
- } else {
- window.setTimeout( next, 13 );
- break;
- }
- }
- config.depth--;
- if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) {
- done();
- }
-}
-
-function saveGlobal() {
- config.pollution = [];
-
- if ( config.noglobals ) {
- for ( var key in window ) {
- // in Opera sometimes DOM element ids show up here, ignore them
- if ( !hasOwn.call( window, key ) || /^qunit-test-output/.test( key ) ) {
- continue;
- }
- config.pollution.push( key );
- }
- }
-}
-
-function checkPollution() {
- var newGlobals,
- deletedGlobals,
- old = config.pollution;
-
- saveGlobal();
-
- newGlobals = diff( config.pollution, old );
- if ( newGlobals.length > 0 ) {
- QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join(", ") );
- }
-
- deletedGlobals = diff( old, config.pollution );
- if ( deletedGlobals.length > 0 ) {
- QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join(", ") );
- }
-}
-
-// returns a new Array with the elements that are in a but not in b
-function diff( a, b ) {
- var i, j,
- result = a.slice();
-
- for ( i = 0; i < result.length; i++ ) {
- for ( j = 0; j < b.length; j++ ) {
- if ( result[i] === b[j] ) {
- result.splice( i, 1 );
- i--;
- break;
- }
- }
- }
- return result;
-}
-
-function extend( a, b ) {
- for ( var prop in b ) {
- if ( b[ prop ] === undefined ) {
- delete a[ prop ];
-
- // Avoid "Member not found" error in IE8 caused by setting window.constructor
- } else if ( prop !== "constructor" || a !== window ) {
- a[ prop ] = b[ prop ];
- }
- }
-
- return a;
-}
-
-/**
- * @param {HTMLElement} elem
- * @param {string} type
- * @param {Function} fn
- */
-function addEvent( elem, type, fn ) {
- // Standards-based browsers
- if ( elem.addEventListener ) {
- elem.addEventListener( type, fn, false );
- // IE
- } else {
- elem.attachEvent( "on" + type, fn );
- }
-}
-
-/**
- * @param {Array|NodeList} elems
- * @param {string} type
- * @param {Function} fn
- */
-function addEvents( elems, type, fn ) {
- var i = elems.length;
- while ( i-- ) {
- addEvent( elems[i], type, fn );
- }
-}
-
-function hasClass( elem, name ) {
- return (" " + elem.className + " ").indexOf(" " + name + " ") > -1;
-}
-
-function addClass( elem, name ) {
- if ( !hasClass( elem, name ) ) {
- elem.className += (elem.className ? " " : "") + name;
- }
-}
-
-function removeClass( elem, name ) {
- var set = " " + elem.className + " ";
- // Class name may appear multiple times
- while ( set.indexOf(" " + name + " ") > -1 ) {
- set = set.replace(" " + name + " " , " ");
- }
- // If possible, trim it for prettiness, but not neccecarily
- elem.className = window.jQuery ? jQuery.trim( set ) : ( set.trim ? set.trim() : set );
-}
-
-function id( name ) {
- return !!( typeof document !== "undefined" && document && document.getElementById ) &&
- document.getElementById( name );
-}
-
-function registerLoggingCallback( key ) {
- return function( callback ) {
- config[key].push( callback );
- };
-}
-
-// Supports deprecated method of completely overwriting logging callbacks
-function runLoggingCallbacks( key, scope, args ) {
- var i, callbacks;
- if ( QUnit.hasOwnProperty( key ) ) {
- QUnit[ key ].call(scope, args );
- } else {
- callbacks = config[ key ];
- for ( i = 0; i < callbacks.length; i++ ) {
- callbacks[ i ].call( scope, args );
- }
- }
-}
-
-// Test for equality any JavaScript type.
-// Author: Philippe Rathé
-QUnit.equiv = (function() {
-
- // Call the o related callback with the given arguments.
- function bindCallbacks( o, callbacks, args ) {
- var prop = QUnit.objectType( o );
- if ( prop ) {
- if ( QUnit.objectType( callbacks[ prop ] ) === "function" ) {
- return callbacks[ prop ].apply( callbacks, args );
- } else {
- return callbacks[ prop ]; // or undefined
- }
- }
- }
-
- // the real equiv function
- var innerEquiv,
- // stack to decide between skip/abort functions
- callers = [],
- // stack to avoiding loops from circular referencing
- parents = [],
-
- getProto = Object.getPrototypeOf || function ( obj ) {
- return obj.__proto__;
- },
- callbacks = (function () {
-
- // for string, boolean, number and null
- function useStrictEquality( b, a ) {
- /*jshint eqeqeq:false */
- if ( b instanceof a.constructor || a instanceof b.constructor ) {
- // to catch short annotaion VS 'new' annotation of a
- // declaration
- // e.g. var i = 1;
- // var j = new Number(1);
- return a == b;
- } else {
- return a === b;
- }
- }
-
- return {
- "string": useStrictEquality,
- "boolean": useStrictEquality,
- "number": useStrictEquality,
- "null": useStrictEquality,
- "undefined": useStrictEquality,
-
- "nan": function( b ) {
- return isNaN( b );
- },
-
- "date": function( b, a ) {
- return QUnit.objectType( b ) === "date" && a.valueOf() === b.valueOf();
- },
-
- "regexp": function( b, a ) {
- return QUnit.objectType( b ) === "regexp" &&
- // the regex itself
- a.source === b.source &&
- // and its modifers
- a.global === b.global &&
- // (gmi) ...
- a.ignoreCase === b.ignoreCase &&
- a.multiline === b.multiline &&
- a.sticky === b.sticky;
- },
-
- // - skip when the property is a method of an instance (OOP)
- // - abort otherwise,
- // initial === would have catch identical references anyway
- "function": function() {
- var caller = callers[callers.length - 1];
- return caller !== Object && typeof caller !== "undefined";
- },
-
- "array": function( b, a ) {
- var i, j, len, loop;
-
- // b could be an object literal here
- if ( QUnit.objectType( b ) !== "array" ) {
- return false;
- }
-
- len = a.length;
- if ( len !== b.length ) {
- // safe and faster
- return false;
- }
-
- // track reference to avoid circular references
- parents.push( a );
- for ( i = 0; i < len; i++ ) {
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- loop = true;// dont rewalk array
- }
- }
- if ( !loop && !innerEquiv(a[i], b[i]) ) {
- parents.pop();
- return false;
- }
- }
- parents.pop();
- return true;
- },
-
- "object": function( b, a ) {
- var i, j, loop,
- // Default to true
- eq = true,
- aProperties = [],
- bProperties = [];
-
- // comparing constructors is more strict than using
- // instanceof
- if ( a.constructor !== b.constructor ) {
- // Allow objects with no prototype to be equivalent to
- // objects with Object as their constructor.
- if ( !(( getProto(a) === null && getProto(b) === Object.prototype ) ||
- ( getProto(b) === null && getProto(a) === Object.prototype ) ) ) {
- return false;
- }
- }
-
- // stack constructor before traversing properties
- callers.push( a.constructor );
- // track reference to avoid circular references
- parents.push( a );
-
- for ( i in a ) { // be strict: don't ensures hasOwnProperty
- // and go deep
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- // don't go down the same path twice
- loop = true;
- }
- }
- aProperties.push(i); // collect a's properties
-
- if (!loop && !innerEquiv( a[i], b[i] ) ) {
- eq = false;
- break;
- }
- }
-
- callers.pop(); // unstack, we are done
- parents.pop();
-
- for ( i in b ) {
- bProperties.push( i ); // collect b's properties
- }
-
- // Ensures identical properties name
- return eq && innerEquiv( aProperties.sort(), bProperties.sort() );
- }
- };
- }());
-
- innerEquiv = function() { // can take multiple arguments
- var args = [].slice.apply( arguments );
- if ( args.length < 2 ) {
- return true; // end transition
- }
-
- return (function( a, b ) {
- if ( a === b ) {
- return true; // catch the most you can
- } else if ( a === null || b === null || typeof a === "undefined" ||
- typeof b === "undefined" ||
- QUnit.objectType(a) !== QUnit.objectType(b) ) {
- return false; // don't lose time with error prone cases
- } else {
- return bindCallbacks(a, callbacks, [ b, a ]);
- }
-
- // apply transition with (1..n) arguments
- }( args[0], args[1] ) && arguments.callee.apply( this, args.splice(1, args.length - 1 )) );
- };
-
- return innerEquiv;
-}());
-
-/**
- * jsDump Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com |
- * http://flesler.blogspot.com Licensed under BSD
- * (http://www.opensource.org/licenses/bsd-license.php) Date: 5/15/2008
- *
- * @projectDescription Advanced and extensible data dumping for Javascript.
- * @version 1.0.0
- * @author Ariel Flesler
- * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html}
- */
-QUnit.jsDump = (function() {
- function quote( str ) {
- return '"' + str.toString().replace( /"/g, '\\"' ) + '"';
- }
- function literal( o ) {
- return o + "";
- }
- function join( pre, arr, post ) {
- var s = jsDump.separator(),
- base = jsDump.indent(),
- inner = jsDump.indent(1);
- if ( arr.join ) {
- arr = arr.join( "," + s + inner );
- }
- if ( !arr ) {
- return pre + post;
- }
- return [ pre, inner + arr, base + post ].join(s);
- }
- function array( arr, stack ) {
- var i = arr.length, ret = new Array(i);
- this.up();
- while ( i-- ) {
- ret[i] = this.parse( arr[i] , undefined , stack);
- }
- this.down();
- return join( "[", ret, "]" );
- }
-
- var reName = /^function (\w+)/,
- jsDump = {
- // type is used mostly internally, you can fix a (custom)type in advance
- parse: function( obj, type, stack ) {
- stack = stack || [ ];
- var inStack, res,
- parser = this.parsers[ type || this.typeOf(obj) ];
-
- type = typeof parser;
- inStack = inArray( obj, stack );
-
- if ( inStack !== -1 ) {
- return "recursion(" + (inStack - stack.length) + ")";
- }
- if ( type === "function" ) {
- stack.push( obj );
- res = parser.call( this, obj, stack );
- stack.pop();
- return res;
- }
- return ( type === "string" ) ? parser : this.parsers.error;
- },
- typeOf: function( obj ) {
- var type;
- if ( obj === null ) {
- type = "null";
- } else if ( typeof obj === "undefined" ) {
- type = "undefined";
- } else if ( QUnit.is( "regexp", obj) ) {
- type = "regexp";
- } else if ( QUnit.is( "date", obj) ) {
- type = "date";
- } else if ( QUnit.is( "function", obj) ) {
- type = "function";
- } else if ( typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined" ) {
- type = "window";
- } else if ( obj.nodeType === 9 ) {
- type = "document";
- } else if ( obj.nodeType ) {
- type = "node";
- } else if (
- // native arrays
- toString.call( obj ) === "[object Array]" ||
- // NodeList objects
- ( typeof obj.length === "number" && typeof obj.item !== "undefined" && ( obj.length ? obj.item(0) === obj[0] : ( obj.item( 0 ) === null && typeof obj[0] === "undefined" ) ) )
- ) {
- type = "array";
- } else if ( obj.constructor === Error.prototype.constructor ) {
- type = "error";
- } else {
- type = typeof obj;
- }
- return type;
- },
- separator: function() {
- return this.multiline ? this.HTML ? "
" : "\n" : this.HTML ? " " : " ";
- },
- // extra can be a number, shortcut for increasing-calling-decreasing
- indent: function( extra ) {
- if ( !this.multiline ) {
- return "";
- }
- var chr = this.indentChar;
- if ( this.HTML ) {
- chr = chr.replace( /\t/g, " " ).replace( / /g, " " );
- }
- return new Array( this._depth_ + (extra||0) ).join(chr);
- },
- up: function( a ) {
- this._depth_ += a || 1;
- },
- down: function( a ) {
- this._depth_ -= a || 1;
- },
- setParser: function( name, parser ) {
- this.parsers[name] = parser;
- },
- // The next 3 are exposed so you can use them
- quote: quote,
- literal: literal,
- join: join,
- //
- _depth_: 1,
- // This is the list of parsers, to modify them, use jsDump.setParser
- parsers: {
- window: "[Window]",
- document: "[Document]",
- error: function(error) {
- return "Error(\"" + error.message + "\")";
- },
- unknown: "[Unknown]",
- "null": "null",
- "undefined": "undefined",
- "function": function( fn ) {
- var ret = "function",
- // functions never have name in IE
- name = "name" in fn ? fn.name : (reName.exec(fn) || [])[1];
-
- if ( name ) {
- ret += " " + name;
- }
- ret += "( ";
-
- ret = [ ret, QUnit.jsDump.parse( fn, "functionArgs" ), "){" ].join( "" );
- return join( ret, QUnit.jsDump.parse(fn,"functionCode" ), "}" );
- },
- array: array,
- nodelist: array,
- "arguments": array,
- object: function( map, stack ) {
- var ret = [ ], keys, key, val, i;
- QUnit.jsDump.up();
- keys = [];
- for ( key in map ) {
- keys.push( key );
- }
- keys.sort();
- for ( i = 0; i < keys.length; i++ ) {
- key = keys[ i ];
- val = map[ key ];
- ret.push( QUnit.jsDump.parse( key, "key" ) + ": " + QUnit.jsDump.parse( val, undefined, stack ) );
- }
- QUnit.jsDump.down();
- return join( "{", ret, "}" );
- },
- node: function( node ) {
- var len, i, val,
- open = QUnit.jsDump.HTML ? "<" : "<",
- close = QUnit.jsDump.HTML ? ">" : ">",
- tag = node.nodeName.toLowerCase(),
- ret = open + tag,
- attrs = node.attributes;
-
- if ( attrs ) {
- for ( i = 0, len = attrs.length; i < len; i++ ) {
- val = attrs[i].nodeValue;
- // IE6 includes all attributes in .attributes, even ones not explicitly set.
- // Those have values like undefined, null, 0, false, "" or "inherit".
- if ( val && val !== "inherit" ) {
- ret += " " + attrs[i].nodeName + "=" + QUnit.jsDump.parse( val, "attribute" );
- }
- }
- }
- ret += close;
-
- // Show content of TextNode or CDATASection
- if ( node.nodeType === 3 || node.nodeType === 4 ) {
- ret += node.nodeValue;
- }
-
- return ret + open + "/" + tag + close;
- },
- // function calls it internally, it's the arguments part of the function
- functionArgs: function( fn ) {
- var args,
- l = fn.length;
-
- if ( !l ) {
- return "";
- }
-
- args = new Array(l);
- while ( l-- ) {
- // 97 is 'a'
- args[l] = String.fromCharCode(97+l);
- }
- return " " + args.join( ", " ) + " ";
- },
- // object calls it internally, the key part of an item in a map
- key: quote,
- // function calls it internally, it's the content of the function
- functionCode: "[code]",
- // node calls it internally, it's an html attribute value
- attribute: quote,
- string: quote,
- date: quote,
- regexp: literal,
- number: literal,
- "boolean": literal
- },
- // if true, entities are escaped ( <, >, \t, space and \n )
- HTML: false,
- // indentation unit
- indentChar: " ",
- // if true, items in a collection, are separated by a \n, else just a space.
- multiline: true
- };
-
- return jsDump;
-}());
-
-// from jquery.js
-function inArray( elem, array ) {
- if ( array.indexOf ) {
- return array.indexOf( elem );
- }
-
- for ( var i = 0, length = array.length; i < length; i++ ) {
- if ( array[ i ] === elem ) {
- return i;
- }
- }
-
- return -1;
-}
-
-/*
- * Javascript Diff Algorithm
- * By John Resig (http://ejohn.org/)
- * Modified by Chu Alan "sprite"
- *
- * Released under the MIT license.
- *
- * More Info:
- * http://ejohn.org/projects/javascript-diff-algorithm/
- *
- * Usage: QUnit.diff(expected, actual)
- *
- * QUnit.diff( "the quick brown fox jumped over", "the quick fox jumps over" ) == "the quick brown fox jumped jumps over"
- */
-QUnit.diff = (function() {
- /*jshint eqeqeq:false, eqnull:true */
- function diff( o, n ) {
- var i,
- ns = {},
- os = {};
-
- for ( i = 0; i < n.length; i++ ) {
- if ( !hasOwn.call( ns, n[i] ) ) {
- ns[ n[i] ] = {
- rows: [],
- o: null
- };
- }
- ns[ n[i] ].rows.push( i );
- }
-
- for ( i = 0; i < o.length; i++ ) {
- if ( !hasOwn.call( os, o[i] ) ) {
- os[ o[i] ] = {
- rows: [],
- n: null
- };
- }
- os[ o[i] ].rows.push( i );
- }
-
- for ( i in ns ) {
- if ( !hasOwn.call( ns, i ) ) {
- continue;
- }
- if ( ns[i].rows.length === 1 && hasOwn.call( os, i ) && os[i].rows.length === 1 ) {
- n[ ns[i].rows[0] ] = {
- text: n[ ns[i].rows[0] ],
- row: os[i].rows[0]
- };
- o[ os[i].rows[0] ] = {
- text: o[ os[i].rows[0] ],
- row: ns[i].rows[0]
- };
- }
- }
-
- for ( i = 0; i < n.length - 1; i++ ) {
- if ( n[i].text != null && n[ i + 1 ].text == null && n[i].row + 1 < o.length && o[ n[i].row + 1 ].text == null &&
- n[ i + 1 ] == o[ n[i].row + 1 ] ) {
-
- n[ i + 1 ] = {
- text: n[ i + 1 ],
- row: n[i].row + 1
- };
- o[ n[i].row + 1 ] = {
- text: o[ n[i].row + 1 ],
- row: i + 1
- };
- }
- }
-
- for ( i = n.length - 1; i > 0; i-- ) {
- if ( n[i].text != null && n[ i - 1 ].text == null && n[i].row > 0 && o[ n[i].row - 1 ].text == null &&
- n[ i - 1 ] == o[ n[i].row - 1 ]) {
-
- n[ i - 1 ] = {
- text: n[ i - 1 ],
- row: n[i].row - 1
- };
- o[ n[i].row - 1 ] = {
- text: o[ n[i].row - 1 ],
- row: i - 1
- };
- }
- }
-
- return {
- o: o,
- n: n
- };
- }
-
- return function( o, n ) {
- o = o.replace( /\s+$/, "" );
- n = n.replace( /\s+$/, "" );
-
- var i, pre,
- str = "",
- out = diff( o === "" ? [] : o.split(/\s+/), n === "" ? [] : n.split(/\s+/) ),
- oSpace = o.match(/\s+/g),
- nSpace = n.match(/\s+/g);
-
- if ( oSpace == null ) {
- oSpace = [ " " ];
- }
- else {
- oSpace.push( " " );
- }
-
- if ( nSpace == null ) {
- nSpace = [ " " ];
- }
- else {
- nSpace.push( " " );
- }
-
- if ( out.n.length === 0 ) {
- for ( i = 0; i < out.o.length; i++ ) {
- str += "" + out.o[i] + oSpace[i] + "";
- }
- }
- else {
- if ( out.n[0].text == null ) {
- for ( n = 0; n < out.o.length && out.o[n].text == null; n++ ) {
- str += "" + out.o[n] + oSpace[n] + "";
- }
- }
-
- for ( i = 0; i < out.n.length; i++ ) {
- if (out.n[i].text == null) {
- str += "" + out.n[i] + nSpace[i] + "";
- }
- else {
- // `pre` initialized at top of scope
- pre = "";
-
- for ( n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++ ) {
- pre += "" + out.o[n] + oSpace[n] + "";
- }
- str += " " + out.n[i].text + nSpace[i] + pre;
- }
- }
- }
-
- return str;
- };
-}());
-
-// for CommonJS enviroments, export everything
-if ( typeof exports !== "undefined" ) {
- extend( exports, QUnit );
-}
-
-// get at whatever the global object is, like window in browsers
-}( (function() {return this;}.call()) ));
diff --git a/test/lib/require.js b/test/lib/require.js
deleted file mode 100644
index 987f865..0000000
--- a/test/lib/require.js
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- RequireJS 2.1.5 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.
- Available via the MIT or new BSD license.
- see: http://github.com/jrburke/requirejs for details
-*/
-var requirejs,require,define;
-(function(aa){function I(b){return"[object Function]"===L.call(b)}function J(b){return"[object Array]"===L.call(b)}function y(b,c){if(b){var d;for(d=0;dthis.depCount&&!this.defined){if(I(n)){if(this.events.error)try{e=i.execCb(c,n,b,e)}catch(d){a=d}else e=i.execCb(c,n,b,e);this.map.isDefine&&((b=this.module)&&void 0!==b.exports&&b.exports!==this.exports?e=b.exports:void 0===e&&this.usingExports&&(e=this.exports));if(a)return a.requireMap=this.map,a.requireModules=[this.map.id],a.requireType="define",v(this.error=
-a)}else e=n;this.exports=e;if(this.map.isDefine&&!this.ignore&&(q[c]=e,l.onResourceLoad))l.onResourceLoad(i,this.map,this.depMaps);x(c);this.defined=!0}this.defining=!1;this.defined&&!this.defineEmitted&&(this.defineEmitted=!0,this.emit("defined",this.exports),this.defineEmitComplete=!0)}}else this.fetch()}},callPlugin:function(){var a=this.map,b=a.id,d=j(a.prefix);this.depMaps.push(d);t(d,"defined",u(this,function(e){var n,d;d=this.map.name;var g=this.map.parentMap?this.map.parentMap.name:null,h=
-i.makeRequire(a.parentMap,{enableBuildCallback:!0});if(this.map.unnormalized){if(e.normalize&&(d=e.normalize(d,function(a){return c(a,g,!0)})||""),e=j(a.prefix+"!"+d,this.map.parentMap),t(e,"defined",u(this,function(a){this.init([],function(){return a},null,{enabled:!0,ignore:!0})})),d=m(p,e.id)){this.depMaps.push(e);if(this.events.error)d.on("error",u(this,function(a){this.emit("error",a)}));d.enable()}}else n=u(this,function(a){this.init([],function(){return a},null,{enabled:!0})}),n.error=u(this,
-function(a){this.inited=!0;this.error=a;a.requireModules=[b];G(p,function(a){0===a.map.id.indexOf(b+"_unnormalized")&&x(a.map.id)});v(a)}),n.fromText=u(this,function(e,c){var d=a.name,g=j(d),C=O;c&&(e=c);C&&(O=!1);r(g);s(k.config,b)&&(k.config[d]=k.config[b]);try{l.exec(e)}catch(ca){return v(B("fromtexteval","fromText eval for "+b+" failed: "+ca,ca,[b]))}C&&(O=!0);this.depMaps.push(g);i.completeLoad(d);h([d],n)}),e.load(a.name,h,n,k)}));i.enable(d,this);this.pluginMaps[d.id]=d},enable:function(){V[this.map.id]=
-this;this.enabling=this.enabled=!0;y(this.depMaps,u(this,function(a,b){var c,e;if("string"===typeof a){a=j(a,this.map.isDefine?this.map:this.map.parentMap,!1,!this.skipMap);this.depMaps[b]=a;if(c=m(N,a.id)){this.depExports[b]=c(this);return}this.depCount+=1;t(a,"defined",u(this,function(a){this.defineDep(b,a);this.check()}));this.errback&&t(a,"error",this.errback)}c=a.id;e=p[c];!s(N,c)&&(e&&!e.enabled)&&i.enable(a,this)}));G(this.pluginMaps,u(this,function(a){var b=m(p,a.id);b&&!b.enabled&&i.enable(a,
-this)}));this.enabling=!1;this.check()},on:function(a,b){var c=this.events[a];c||(c=this.events[a]=[]);c.push(b)},emit:function(a,b){y(this.events[a],function(a){a(b)});"error"===a&&delete this.events[a]}};i={config:k,contextName:b,registry:p,defined:q,urlFetched:U,defQueue:H,Module:Z,makeModuleMap:j,nextTick:l.nextTick,onError:v,configure:function(a){a.baseUrl&&"/"!==a.baseUrl.charAt(a.baseUrl.length-1)&&(a.baseUrl+="/");var b=k.pkgs,c=k.shim,e={paths:!0,config:!0,map:!0};G(a,function(a,b){e[b]?
-"map"===b?(k.map||(k.map={}),R(k[b],a,!0,!0)):R(k[b],a,!0):k[b]=a});a.shim&&(G(a.shim,function(a,b){J(a)&&(a={deps:a});if((a.exports||a.init)&&!a.exportsFn)a.exportsFn=i.makeShimExports(a);c[b]=a}),k.shim=c);a.packages&&(y(a.packages,function(a){a="string"===typeof a?{name:a}:a;b[a.name]={name:a.name,location:a.location||a.name,main:(a.main||"main").replace(ja,"").replace(ea,"")}}),k.pkgs=b);G(p,function(a,b){!a.inited&&!a.map.unnormalized&&(a.map=j(b))});if(a.deps||a.callback)i.require(a.deps||[],
-a.callback)},makeShimExports:function(a){return function(){var b;a.init&&(b=a.init.apply(aa,arguments));return b||a.exports&&ba(a.exports)}},makeRequire:function(a,f){function d(e,c,h){var g,k;f.enableBuildCallback&&(c&&I(c))&&(c.__requireJsBuild=!0);if("string"===typeof e){if(I(c))return v(B("requireargs","Invalid require call"),h);if(a&&s(N,e))return N[e](p[a.id]);if(l.get)return l.get(i,e,a,d);g=j(e,a,!1,!0);g=g.id;return!s(q,g)?v(B("notloaded",'Module name "'+g+'" has not been loaded yet for context: '+
-b+(a?"":". Use require([])"))):q[g]}L();i.nextTick(function(){L();k=r(j(null,a));k.skipMap=f.skipMap;k.init(e,c,h,{enabled:!0});D()});return d}f=f||{};R(d,{isBrowser:A,toUrl:function(b){var d,f=b.lastIndexOf("."),g=b.split("/")[0];if(-1!==f&&(!("."===g||".."===g)||1h.attachEvent.toString().indexOf("[native code"))&&!Y?(O=!0,h.attachEvent("onreadystatechange",b.onScriptLoad)):(h.addEventListener("load",b.onScriptLoad,!1),h.addEventListener("error",b.onScriptError,!1)),h.src=d,K=h,D?x.insertBefore(h,D):x.appendChild(h),K=null,h;if(da)try{importScripts(d),b.completeLoad(c)}catch(j){b.onError(B("importscripts","importScripts failed for "+c+" at "+d,j,[c]))}};A&&M(document.getElementsByTagName("script"),function(b){x||(x=
-b.parentNode);if(t=b.getAttribute("data-main"))return r.baseUrl||(E=t.split("/"),Q=E.pop(),fa=E.length?E.join("/")+"/":"./",r.baseUrl=fa,t=Q),t=t.replace(ea,""),r.deps=r.deps?r.deps.concat(t):[t],!0});define=function(b,c,d){var l,h;"string"!==typeof b&&(d=c,c=b,b=null);J(c)||(d=c,c=[]);!c.length&&I(d)&&d.length&&(d.toString().replace(la,"").replace(ma,function(b,d){c.push(d)}),c=(1===d.length?["require"]:["require","exports","module"]).concat(c));if(O){if(!(l=K))P&&"interactive"===P.readyState||M(document.getElementsByTagName("script"),
-function(b){if("interactive"===b.readyState)return P=b}),l=P;l&&(b||(b=l.getAttribute("data-requiremodule")),h=F[l.getAttribute("data-requirecontext")])}(h?h.defQueue:T).push([b,c,d])};define.amd={jQuery:!0};l.exec=function(b){return eval(b)};l(r)}})(this);
diff --git a/test/lib/resemble.js b/test/lib/resemble.js
new file mode 100644
index 0000000..1cb8c29
--- /dev/null
+++ b/test/lib/resemble.js
@@ -0,0 +1,535 @@
+/*
+Author: James Cryer
+Company: Huddle
+Last updated date: 21 Feb 2013
+URL: https://github.com/Huddle/Resemble.js
+*/
+
+(function(_this){
+ 'use strict';
+
+ _this['resemble'] = function( fileData ){
+
+ var data = {};
+ var images = [];
+ var updateCallbackArray = [];
+
+ var tolerance = { // between 0 and 255
+ red: 16,
+ green: 16,
+ blue: 16,
+ minBrightness: 16,
+ maxBrightness: 240
+ };
+
+ var ignoreAntialiasing = false;
+ var ignoreColors = false;
+
+ function triggerDataUpdate(){
+ var len = updateCallbackArray.length;
+ var i;
+ for(i=0;i tolerance.maxBrightness;
+ }
+
+ function getHue(r,g,b){
+
+ r = r / 255;
+ g = g / 255;
+ b = b / 255;
+ var max = Math.max(r, g, b), min = Math.min(r, g, b);
+ var h;
+ var d;
+
+ if (max == min){
+ h = 0; // achromatic
+ } else{
+ d = max - min;
+ switch(max){
+ case r: h = (g - b) / d + (g < b ? 6 : 0); break;
+ case g: h = (b - r) / d + 2; break;
+ case b: h = (r - g) / d + 4; break;
+ }
+ h /= 6;
+ }
+
+ return h;
+ }
+
+ function isAntialiased(sourcePix, data, cacheSet, verticalPos, horizontalPos, width){
+ var offset;
+ var targetPix;
+ var distance = 1;
+ var i;
+ var j;
+ var hasHighContrastSibling = 0;
+ var hasSiblingWithDifferentHue = 0;
+ var hasEquivilantSibling = 0;
+
+ addHueInfo(sourcePix);
+
+ for (i = distance*-1; i <= distance; i++){
+ for (j = distance*-1; j <= distance; j++){
+
+ if(i===0 && j===0){
+ // ignore source pixel
+ } else {
+
+ offset = ((verticalPos+j)*width + (horizontalPos+i)) * 4;
+ targetPix = getPixelInfo(data, offset, cacheSet);
+
+ if(targetPix === null){
+ continue;
+ }
+
+ addBrightnessInfo(targetPix);
+ addHueInfo(targetPix);
+
+ if( isContrasting(sourcePix, targetPix) ){
+ hasHighContrastSibling++;
+ }
+
+ if( isRGBSame(sourcePix,targetPix) ){
+ hasEquivilantSibling++;
+ }
+
+ if( Math.abs(targetPix.h - sourcePix.h) > 0.3 ){
+ hasSiblingWithDifferentHue++;
+ }
+
+ if( hasSiblingWithDifferentHue > 1 || hasHighContrastSibling > 1){
+ return true;
+ }
+ }
+ }
+ }
+
+ if(hasEquivilantSibling < 2){
+ return true;
+ }
+
+ return false;
+ }
+
+ function errorPixel(px, offset){
+ px[offset] = 255; //r
+ px[offset + 1] = 0; //g
+ px[offset + 2] = 255; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyPixel(px, offset, data){
+ px[offset] = data.r; //r
+ px[offset + 1] = data.g; //g
+ px[offset + 2] = data.b; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyGrayScalePixel(px, offset, data){
+ px[offset] = data.brightness; //r
+ px[offset + 1] = data.brightness; //g
+ px[offset + 2] = data.brightness; //b
+ px[offset + 3] = 255; //a
+ }
+
+
+ function getPixelInfo(data, offset, cacheSet){
+ var r;
+ var g;
+ var b;
+ var d;
+
+ if(typeof data[offset] !== 'undefined'){
+ r = data[offset];
+ g = data[offset+1];
+ b = data[offset+2];
+ d = {
+ r: r,
+ g: g,
+ b: b
+ };
+
+ return d;
+ } else {
+ return null;
+ }
+ }
+
+ function addBrightnessInfo(data){
+ data.brightness = getBrightness(data.r,data.g,data.b); // 'corrected' lightness
+ }
+
+ function addHueInfo(data){
+ data.h = getHue(data.r,data.g,data.b);
+ }
+
+ function analyseImages(img1, img2, width, height){
+
+ var hiddenCanvas = document.createElement('canvas');
+
+ var data1 = img1.data;
+ var data2 = img2.data;
+
+ hiddenCanvas.width = width;
+ hiddenCanvas.height = height;
+
+ var context = hiddenCanvas.getContext('2d');
+ var imgd = context.createImageData(width,height);
+ var targetPix = imgd.data;
+
+ var mismatchCount = 0;
+
+ var time = Date.now();
+
+ var skip;
+
+ if( (width > 1200 || height > 1200) && ignoreAntialiasing){
+ skip = 6;
+ }
+
+ loop(height, width, function(verticalPos, horizontalPos){
+
+ if(skip){ // only skip if the image isn't small
+ if(verticalPos % skip === 0 || horizontalPos % skip === 0){
+ return;
+ }
+ }
+
+ var offset = (verticalPos*width + horizontalPos) * 4;
+ var pixel1 = getPixelInfo(data1, offset, 1);
+ var pixel2 = getPixelInfo(data2, offset, 2);
+
+ if(pixel1 === null || pixel2 === null){
+ return;
+ }
+
+ if (ignoreColors){
+
+ addBrightnessInfo(pixel1);
+ addBrightnessInfo(pixel2);
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ return;
+ }
+
+ if( isRGBSimilar(pixel1, pixel2) ){
+ copyPixel(targetPix, offset, pixel2);
+
+ } else if( ignoreAntialiasing && (
+ addBrightnessInfo(pixel1), // jit pixel info augmentation looks a little weird, sorry.
+ addBrightnessInfo(pixel2),
+ isAntialiased(pixel1, data1, 1, verticalPos, horizontalPos, width) ||
+ isAntialiased(pixel2, data2, 2, verticalPos, horizontalPos, width)
+ )){
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+
+ });
+
+ data.misMatchPercentage = (mismatchCount / (height*width) * 100).toFixed(2);
+ data.analysisTime = Date.now() - time;
+
+ data.getImageDataUrl = function(text){
+ var barHeight = 0;
+
+ if(text){
+ barHeight = addLabel(text,context,hiddenCanvas);
+ }
+
+ context.putImageData(imgd, 0, barHeight);
+
+ return hiddenCanvas.toDataURL("image/png");
+ };
+ }
+
+ function addLabel(text, context, hiddenCanvas){
+ var textPadding = 2;
+
+ context.font = '12px sans-serif';
+
+ var textWidth = context.measureText(text).width + textPadding*2;
+ var barHeight = 22;
+
+ if(textWidth > hiddenCanvas.width){
+ hiddenCanvas.width = textWidth;
+ }
+
+ hiddenCanvas.height += barHeight;
+
+ context.fillStyle = "#666";
+ context.fillRect(0,0,hiddenCanvas.width,barHeight -4);
+ context.fillStyle = "#fff";
+ context.fillRect(0,barHeight -4,hiddenCanvas.width, 4);
+
+ context.fillStyle = "#fff";
+ context.textBaseline = "top";
+ context.font = '12px sans-serif';
+ context.fillText(text, textPadding, 1);
+
+ return barHeight;
+ }
+
+ function normalise(img, w, h){
+ var c;
+ var context;
+
+ if(img.height < h || img.width < w){
+ c = document.createElement('canvas');
+ c.width = w;
+ c.height = h;
+ context = c.getContext('2d');
+ context.putImageData(img, 0, 0);
+ return context.getImageData(0, 0, w, h);
+ }
+
+ return img;
+ }
+
+ function compare(one, two){
+
+ function onceWeHaveBoth(){
+ var width;
+ var height;
+ if(images.length === 2){
+ width = images[0].width > images[1].width ? images[0].width : images[1].width;
+ height = images[0].height > images[1].height ? images[0].height : images[1].height;
+
+ if( (images[0].width === images[1].width) && (images[0].height === images[1].height) ){
+ data.isSameDimensions = true;
+ } else {
+ data.isSameDimensions = false;
+ }
+
+ analyseImages( normalise(images[0],width, height), normalise(images[1],width, height), width, height);
+
+ triggerDataUpdate();
+ }
+ }
+
+ images = [];
+ loadImageData(one, onceWeHaveBoth);
+ loadImageData(two, onceWeHaveBoth);
+ }
+
+ function getCompareApi(param){
+
+ var secondFileData,
+ hasMethod = typeof param === 'function';
+
+ if( !hasMethod ){
+ // assume it's file data
+ secondFileData = param;
+ }
+
+ var self = {
+ ignoreNothing: function(){
+
+ tolerance.red = 16;
+ tolerance.green = 16;
+ tolerance.blue = 16;
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreAntialiasing: function(){
+
+ tolerance.red = 32;
+ tolerance.green = 32;
+ tolerance.blue = 32;
+ tolerance.minBrightness = 64;
+ tolerance.maxBrightness = 96;
+
+ ignoreAntialiasing = true;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreColors: function(){
+
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = true;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ onComplete: function( callback ){
+
+ updateCallbackArray.push(callback);
+
+ var wrapper = function(){
+ compare(fileData, secondFileData);
+ };
+
+ wrapper();
+
+ return getCompareApi(wrapper);
+ }
+ };
+
+ return self;
+ }
+
+ return {
+ onComplete: function( callback ){
+ updateCallbackArray.push(callback);
+ loadImageData(fileData, function(imageData, width, height){
+ parseImage(imageData.data, width, height);
+ });
+ },
+ compareTo: function(secondFileData){
+ return getCompareApi(secondFileData);
+ }
+ };
+
+ };
+}(this));
\ No newline at end of file
diff --git a/test/testsuite.js b/test/testsuite.js
deleted file mode 100644
index b486acb..0000000
--- a/test/testsuite.js
+++ /dev/null
@@ -1,36 +0,0 @@
-requirejs.config({
- baseUrl: '/test/unit/'
-});
-
-define(function(require) {
- var testModules = [
- 'Pixi',
- 'Point',
- 'Rectangle',
- 'DisplayObject',
- 'DisplayObjectContainer',
- 'Sprite',
- 'MovieClip',
- 'InteractionManager',
- 'Stage',
- 'utils/Utils',
- 'utils/EventTarget',
- 'utils/Matrix',
- 'utils/Detector',
- 'renderers/WebGLShaders',
- 'renderers/WebGLRenderer',
- 'renderers/WebGLBatch',
- 'renderers/CanvasRenderer',
- 'extras/Strip',
- 'extras/Rope',
- 'textures/BaseTexture',
- 'textures/Texture',
- 'loaders/SpriteSheetLoader',
- 'loaders/AssetLoader'
- ];
-
- // Resolve all testModules and then start the Test Runner.
- require(testModules, function() {
- QUnit.start();
- });
-});
\ No newline at end of file
diff --git a/test/textures/SpriteSheet-Aliens.png b/test/textures/SpriteSheet-Aliens.png
new file mode 100644
index 0000000..210acb1
--- /dev/null
+++ b/test/textures/SpriteSheet-Aliens.png
Binary files differ
diff --git a/test/textures/SpriteSheet-Explosion.png b/test/textures/SpriteSheet-Explosion.png
new file mode 100755
index 0000000..79e1a69
--- /dev/null
+++ b/test/textures/SpriteSheet-Explosion.png
Binary files differ
diff --git a/test/textures/bunny.png b/test/textures/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/textures/bunny.png
Binary files differ
diff --git a/test/unit/DisplayObject.js b/test/unit/DisplayObject.js
deleted file mode 100644
index 5e7e72f..0000000
--- a/test/unit/DisplayObject.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObject');
-});
diff --git a/test/unit/DisplayObjectContainer.js b/test/unit/DisplayObjectContainer.js
deleted file mode 100644
index b323959..0000000
--- a/test/unit/DisplayObjectContainer.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObjectContainer');
-});
diff --git a/.gitignore b/.gitignore
index 12e1b62..0b88317 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
node_modules
.DS_Store
-.project
\ No newline at end of file
+.project
+*.log
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..63e4d7c
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,8 @@
+language: node_js
+node_js:
+ - 0.10
+
+before_script:
+ - npm install -g grunt-cli
+ - export DISPLAY=:99.0
+ - sh -e /etc/init.d/xvfb start
diff --git a/Gruntfile.js b/Gruntfile.js
index b083b49..103938c 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -1,10 +1,12 @@
+'use strict';
+
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-connect');
- grunt.loadNpmTasks('grunt-contrib-qunit');
grunt.loadNpmTasks('grunt-contrib-yuidoc');
+ grunt.loadTasks('tasks');
var root = 'src/pixi/',
debug = 'bin/pixi.dev.js',
@@ -79,7 +81,7 @@
},
files: {
srcBlob: '<%= dirs.src %>/**/*.js',
- testBlob: '<%= dirs.test %>/unit/**/*.js',
+ testBlob: '<%= dirs.test %>/{functional,lib/pixi,unit}/**/*.js',
build: '<%= dirs.build %>/pixi.dev.js',
buildMin: '<%= dirs.build %>/pixi.js'
},
@@ -94,7 +96,12 @@
},
jshint: {
beforeconcat: srcFiles,
- test: ['<%= files.testBlob %>'],
+ test: {
+ src: ['<%= files.testBlob %>'],
+ options: {
+ expr: true
+ }
+ },
options: {
asi: true,
smarttabs: true
@@ -128,12 +135,6 @@
]
},
connect: {
- qunit: {
- options: {
- port: grunt.option('port-test') || 9002,
- base: './'
- }
- },
test: {
options: {
port: grunt.option('port-test') || 9002,
@@ -142,13 +143,6 @@
}
}
},
- qunit: {
- all: {
- options: {
- urls: ['http://localhost:' + (grunt.option('port-test') || 9002) + '/test/index.html']
- }
- }
- },
yuidoc: {
compile: {
name: '<%= pkg.name %>',
@@ -161,6 +155,13 @@
outdir: '<%= dirs.docs %>'
}
}
+ },
+ karma: {
+ unit: {
+ configFile: 'test/karma.conf.js',
+ // browsers: ['Chrome'],
+ singleRun: true
+ }
}
});
@@ -182,9 +183,10 @@
}
)
- grunt.registerTask('default', ['concat', 'uglify', 'distribute']);
grunt.registerTask('build', ['concat', 'uglify', 'distribute']);
- grunt.registerTask('test', ['build', 'connect:qunit', 'qunit']);
+ grunt.registerTask('test', ['concat', 'jshint:test', 'karma']);
grunt.registerTask('docs', ['yuidoc']);
-
-}
\ No newline at end of file
+ grunt.registerTask('default', ['test', 'uglify', 'distribute']);
+ // Travis CI task.
+ grunt.registerTask('travis', ['test']);
+}
diff --git a/README.md b/README.md
index c62ef86..690cfe4 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,8 @@

+[](http://travis-ci.org/drkibitz/pixi.js)
+
#### JavaScript 2D Renderer ####
The aim of this project is to provide a fast lightweight 2D library that works
diff --git a/package.json b/package.json
index b373240..1246a68 100644
--- a/package.json
+++ b/package.json
@@ -18,14 +18,21 @@
"main": "bin/pixi.js",
+ "scripts": {
+ "test": "grunt travis --verbose"
+ },
+
"dependencies": {},
"devDependencies": {
"grunt": "~0.4.x",
- "grunt-contrib-jshint": "0.3.x",
+ "grunt-contrib-jshint": "0.6.x",
"grunt-contrib-uglify": "0.2.x",
- "grunt-contrib-connect": "0.2.x",
- "grunt-contrib-qunit": "0.2.x",
+ "grunt-contrib-connect": "0.3.x",
"grunt-contrib-yuidoc": "0.4.x",
- "grunt-contrib-concat": "0.1.x"
+ "grunt-contrib-concat": "0.3.x",
+ "chai": "~1.7.0",
+ "karma": "0.11.0",
+ "karma-firefox-launcher": "0.1.0",
+ "karma-mocha": "0.1.0"
}
}
diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js
index a7c520e..ee82bbd 100644
--- a/src/pixi/InteractionManager.js
+++ b/src/pixi/InteractionManager.js
@@ -62,7 +62,6 @@
this.onTouchEnd = this.onTouchEnd.bind(this);
this.onTouchMove = this.onTouchMove.bind(this);
-
this.last = 0;
}
diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js
index 1a95d20..eef1059 100644
--- a/src/pixi/core/Ellipse.js
+++ b/src/pixi/core/Ellipse.js
@@ -78,7 +78,7 @@
return (normx + normy < 0.25);
}
-PIXI.Ellipse.getBounds = function()
+PIXI.Ellipse.prototype.getBounds = function()
{
return new PIXI.Rectangle(this.x, this.y, this.width, this.height);
}
diff --git a/tasks/karma.js b/tasks/karma.js
new file mode 100644
index 0000000..c340485
--- /dev/null
+++ b/tasks/karma.js
@@ -0,0 +1,27 @@
+'use strict';
+
+var path = require('path');
+var server = require('karma').server;
+
+module.exports = function (grunt) {
+ grunt.registerMultiTask('karma', 'run karma.', function() {
+ var done = this.async();
+ var options = this.options({
+ background: false
+ });
+ var data = this.data;
+
+ //merge options onto data, with data taking precedence
+ data = grunt.util._.merge(options, data);
+ data.configFile = path.resolve(data.configFile);
+ if (data.configFile) {
+ data.configFile = grunt.template.process(data.configFile);
+ }
+
+ server.start(
+ data,
+ function(code) {
+ done(!code);
+ });
+ });
+};
diff --git a/test/functional/example-1-basics/bunny.png b/test/functional/example-1-basics/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/functional/example-1-basics/bunny.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-30.png b/test/functional/example-1-basics/frame-30.png
new file mode 100644
index 0000000..96e3409
--- /dev/null
+++ b/test/functional/example-1-basics/frame-30.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-60.png b/test/functional/example-1-basics/frame-60.png
new file mode 100644
index 0000000..af3f4ce
--- /dev/null
+++ b/test/functional/example-1-basics/frame-60.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-90.png b/test/functional/example-1-basics/frame-90.png
new file mode 100644
index 0000000..099b823
--- /dev/null
+++ b/test/functional/example-1-basics/frame-90.png
Binary files differ
diff --git a/test/functional/example-1-basics/index.js b/test/functional/example-1-basics/index.js
new file mode 100644
index 0000000..7ae7a98
--- /dev/null
+++ b/test/functional/example-1-basics/index.js
@@ -0,0 +1,133 @@
+describe('Example 1 - Basics', function () {
+ 'use strict';
+
+ var baseUri = '/base/test/functional/example-1-basics';
+ var expect = chai.expect;
+ var currentFrame = 0;
+ var frameEvents = {};
+ var stage;
+ var renderer;
+ var bunny;
+
+ function onFrame(frame, callback) {
+ frameEvents[frame] = callback;
+ }
+
+ function animate() {
+ currentFrame += 1;
+
+ requestAnimFrame( animate );
+
+ // just for fun, lets rotate mr rabbit a little
+ bunny.rotation += 0.1;
+
+ // render the stage
+ renderer.render(stage);
+
+ if (frameEvents[currentFrame])
+ frameEvents[currentFrame](currentFrame);
+ }
+
+ function initScene() {
+ // create an new instance of a pixi stage
+ stage = new PIXI.Stage(0x66FF99);
+
+ // create a renderer instance
+ renderer = PIXI.autoDetectRenderer(400, 300);
+ console.log('Is PIXI.WebGLRenderer: ' + (renderer instanceof PIXI.WebGLRenderer));
+
+ // add the renderer view element to the DOM
+ document.body.appendChild(renderer.view);
+
+ requestAnimFrame( animate );
+
+ // create a texture from an image path
+ var texture = PIXI.Texture.fromImage(baseUri + "/bunny.png");
+ // create a new Sprite using the texture
+ bunny = new PIXI.Sprite(texture);
+
+ // center the sprites anchor point
+ bunny.anchor.x = 0.5;
+ bunny.anchor.y = 0.5;
+
+ // move the sprite t the center of the screen
+ bunny.position.x = 200;
+ bunny.position.y = 150;
+
+ stage.addChild(bunny);
+ }
+
+ it('assets loaded', function (done) {
+ var loader = new PIXI.AssetLoader([
+ baseUri + '/bunny.png',
+ baseUri + '/frame-30.png',
+ baseUri + '/frame-60.png',
+ baseUri + '/frame-90.png'
+ ]);
+ // loader.on('onProgress', function (event) {
+ // console.log(event.content);
+ // });
+ loader.on('onComplete', function (event) {
+ done();
+ initScene();
+ });
+ loader.load();
+ });
+
+ it('frame 30 should match', function (done) {
+ this.timeout(700);
+ onFrame(30, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-30.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 60 should match', function (done) {
+ this.timeout(1200);
+ onFrame(60, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-60.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 90 should match', function (done) {
+ this.timeout(1700);
+ onFrame(90, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-90.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ // it('capture something', function (done) {
+ // this.timeout(2000000);
+ // onFrame(30, function () {
+ // var img = new Image();
+ // img.src = renderer.view.toDataURL('image/png');
+ // document.body.appendChild(img);
+ // });
+ // });
+});
diff --git a/test/index.html b/test/index.html
deleted file mode 100644
index 9cbcac5..0000000
--- a/test/index.html
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
- Pixi.js Test Suite
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/test/karma.conf.js b/test/karma.conf.js
new file mode 100644
index 0000000..c66a696
--- /dev/null
+++ b/test/karma.conf.js
@@ -0,0 +1,82 @@
+module.exports = function(config) {
+ config.set({
+
+ // base path, that will be used to resolve files and exclude
+ basePath : '../',
+
+ frameworks : ['mocha'],
+
+ // list of files / patterns to load in the browser
+ files : [
+ 'node_modules/chai/chai.js',
+ 'bin/pixi.dev.js',
+ 'test/lib/**/*.js',
+ 'test/unit/**/*.js',
+ // 'test/functional/**/*.js',
+ {pattern: 'test/**/*.png', watched: false, included: false, served: true}
+ ],
+
+ // list of files to exclude
+ exclude : [],
+
+ // use dolts reporter, as travis terminal does not support escaping sequences
+ // possible values: 'dots', 'progress', 'junit', 'teamcity'
+ // CLI --reporters progress
+ reporters : ['progress'],
+
+ // web server port
+ // CLI --port 9876
+ port : 9876,
+
+ // cli runner port
+ // CLI --runner-port 9100
+ runnerPort : 9100,
+
+ // enable / disable colors in the output (reporters and logs)
+ // CLI --colors --no-colors
+ colors : true,
+
+ // level of logging
+ // possible values: karma.LOG_DISABLE || karma.LOG_ERROR || karma.LOG_WARN || karma.LOG_INFO || karma.LOG_DEBUG
+ // CLI --log-level debug
+ logLevel : config.LOG_DEBUG,
+
+ // enable / disable watching file and executing tests whenever any file changes
+ // CLI --auto-watch --no-auto-watch
+ autoWatch : false,
+
+ // Start these browsers, currently available:
+ // - Chrome
+ // - ChromeCanary
+ // - Firefox
+ // - Opera
+ // - Safari (only Mac)
+ // - PhantomJS
+ // - IE (only Windows)
+ // CLI --browsers Chrome,Firefox,Safari
+ browsers : ['Firefox'],
+
+ // If browser does not capture in given timeout [ms], kill it
+ // CLI --capture-timeout 5000
+ captureTimeout : 5000,
+
+ // Auto run tests on start (when browsers are captured) and exit
+ // CLI --single-run --no-single-run
+ singleRun : true,
+
+ // report which specs are slower than 500ms
+ // CLI --report-slower-than 500
+ reportSlowerThan : 1000,
+
+ preprocessors : {
+ // '**/client/js/*.js': 'coverage'
+ },
+
+ plugins : [
+ 'karma-mocha',
+ // 'karma-chrome-launcher',
+ 'karma-firefox-launcher',
+ // 'karma-phantomjs-launcher'
+ ]
+ });
+};
diff --git a/test/lib/pixi/core/Matrix.js b/test/lib/pixi/core/Matrix.js
new file mode 100644
index 0000000..d26386b
--- /dev/null
+++ b/test/lib/pixi/core/Matrix.js
@@ -0,0 +1,40 @@
+
+function pixi_core_Matrix_confirmNewMat3(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(1);
+ expect(matrix[5]).to.equal(0);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(1);
+}
+
+function pixi_core_Matrix_confirmNewMat4(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[0]).to.equal(1);
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(0);
+ expect(matrix[5]).to.equal(1);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(0);
+ expect(matrix[9]).to.equal(0);
+ expect(matrix[10]).to.equal(1);
+ expect(matrix[11]).to.equal(0);
+ expect(matrix[12]).to.equal(0);
+ expect(matrix[13]).to.equal(0);
+ expect(matrix[14]).to.equal(0);
+ expect(matrix[15]).to.equal(1);
+}
diff --git a/test/lib/pixi/core/Point.js b/test/lib/pixi/core/Point.js
new file mode 100644
index 0000000..e5df07b
--- /dev/null
+++ b/test/lib/pixi/core/Point.js
@@ -0,0 +1,10 @@
+
+function pixi_core_Point_confirm(obj, x, y) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Point);
+ expect(obj).to.respondTo('clone');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+}
diff --git a/test/lib/pixi/core/Rectangle.js b/test/lib/pixi/core/Rectangle.js
new file mode 100644
index 0000000..23f0d12
--- /dev/null
+++ b/test/lib/pixi/core/Rectangle.js
@@ -0,0 +1,13 @@
+
+function pixi_core_Rectangle_confirm(obj, x, y, width, height) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Rectangle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+ expect(obj).to.have.property('width', width);
+ expect(obj).to.have.property('height', height);
+}
diff --git a/test/lib/pixi/display/DisplayObject.js b/test/lib/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..1388a7f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObject.js
@@ -0,0 +1,43 @@
+
+function pixi_display_DisplayObject_confirmNew(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObject);
+ expect(obj).to.respondTo('setInteractive');
+ expect(obj).to.respondTo('addFilter');
+ expect(obj).to.respondTo('removeFilter');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.property('last', obj);
+ expect(obj).to.have.property('first', obj);
+
+ expect(obj).to.contain.property('position');
+ pixi_core_Point_confirm(obj.position, 0, 0);
+ expect(obj).to.contain.property('scale');
+ pixi_core_Point_confirm(obj.scale, 1, 1);
+ expect(obj).to.contain.property('pivot');
+ pixi_core_Point_confirm(obj.pivot, 0, 0);
+
+ expect(obj).to.have.property('rotation', 0);
+ expect(obj).to.have.property('alpha', 1);
+ expect(obj).to.have.property('visible', true);
+ expect(obj).to.have.property('buttonMode', false);
+ expect(obj).to.have.property('parent', null);
+ expect(obj).to.have.property('worldAlpha', 1);
+
+ expect(obj).to.have.property('hitArea');
+ expect(obj).to.have.property('interactive'); // TODO: Have a better default value
+ expect('mask' in obj).to.be.true; // TODO: Have a better default value
+ expect(obj.mask).to.be.undefined;
+
+ expect(obj).to.have.property('renderable');
+ expect(obj).to.have.property('stage');
+
+ expect(obj).to.have.deep.property('worldTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ expect(obj).to.have.deep.property('localTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.localTransform);
+
+ expect(obj).to.have.deep.property('color.length', 0);
+ expect(obj).to.have.property('dynamic', true);
+}
diff --git a/test/lib/pixi/display/DisplayObjectContainer.js b/test/lib/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..085c59f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,16 @@
+
+function pixi_display_DisplayObjectContainer_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObject_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObjectContainer);
+ expect(obj).to.respondTo('addChild');
+ expect(obj).to.respondTo('addChildAt');
+ expect(obj).to.respondTo('swapChildren');
+ expect(obj).to.respondTo('getChildAt');
+ expect(obj).to.respondTo('removeChild');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('children.length', 0);
+}
diff --git a/test/lib/pixi/display/Sprite.js b/test/lib/pixi/display/Sprite.js
new file mode 100644
index 0000000..cc7a2d6
--- /dev/null
+++ b/test/lib/pixi/display/Sprite.js
@@ -0,0 +1,28 @@
+
+function pixi_display_Sprite_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Sprite);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', true);
+ expect(obj).to.have.property('stage', null);
+
+ expect(obj).to.have.property('anchor');
+ pixi_core_Point_confirm(obj.anchor, 0, 0);
+
+ expect(obj).to.have.property('blendMode', PIXI.blendModes.NORMAL);
+ expect(obj).to.have.property('width', 1); // TODO: is 1 expected
+ expect(obj).to.have.property('height', 1); // TODO: is 1 expected
+
+ // FIXME: Just make this a boolean that is always there
+ expect(!!obj.updateFrame).to.equal(obj.texture.baseTexture.hasLoaded);
+
+ expect(obj).to.have.property('texture');
+ pixi_textures_Texture_confirmNew(obj.texture, done);
+}
diff --git a/test/lib/pixi/extras/Strip.js b/test/lib/pixi/extras/Strip.js
new file mode 100644
index 0000000..8927a8a
--- /dev/null
+++ b/test/lib/pixi/extras/Strip.js
@@ -0,0 +1,12 @@
+
+function pixi_extras_Strip_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Strip);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ // TODO: Test properties
+}
diff --git a/test/lib/pixi/textures/Texture.js b/test/lib/pixi/textures/Texture.js
new file mode 100644
index 0000000..d5867b6
--- /dev/null
+++ b/test/lib/pixi/textures/Texture.js
@@ -0,0 +1,31 @@
+
+function pixi_textures_Texture_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ function confirmFrameDone() {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, obj.baseTexture.width, obj.baseTexture.height);
+
+ expect(obj).to.have.property('width', obj.baseTexture.width);
+ expect(obj).to.have.property('height', obj.baseTexture.height);
+ done();
+ }
+
+ expect(obj).to.be.an.instanceof(PIXI.Texture);
+ pixi_utils_EventTarget_like(obj);
+
+ expect(obj).to.have.property('baseTexture')
+ .and.to.be.an.instanceof(PIXI.BaseTexture);
+
+ expect(obj).to.have.property('scope', obj);
+
+ expect(obj).to.have.property('trim');
+ pixi_core_Point_confirm(obj.trim, 0, 0);
+
+ expect(obj).to.have.property('frame');
+ if (obj.baseTexture.hasLoaded) {
+ confirmFrameDone();
+ } else {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, 1, 1);
+ obj.addEventListener('update', confirmFrameDone);
+ }
+}
diff --git a/test/lib/pixi/utils/EventTarget.js b/test/lib/pixi/utils/EventTarget.js
new file mode 100644
index 0000000..7b1dcfa
--- /dev/null
+++ b/test/lib/pixi/utils/EventTarget.js
@@ -0,0 +1,8 @@
+
+function pixi_utils_EventTarget_like(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.respondTo('addEventListener');
+ expect(obj).to.respondTo('dispatchEvent');
+ expect(obj).to.respondTo('removeEventListener');
+}
diff --git a/test/lib/qunit-1.11.0.css b/test/lib/qunit-1.11.0.css
deleted file mode 100644
index d7fc0c8..0000000
--- a/test/lib/qunit-1.11.0.css
+++ /dev/null
@@ -1,244 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-/** Font Family and Sizes */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
- font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
-}
-
-#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
-#qunit-tests { font-size: smaller; }
-
-
-/** Resets */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter {
- margin: 0;
- padding: 0;
-}
-
-
-/** Header */
-
-#qunit-header {
- padding: 0.5em 0 0.5em 1em;
-
- color: #8699a4;
- background-color: #0d3349;
-
- font-size: 1.5em;
- line-height: 1em;
- font-weight: normal;
-
- border-radius: 5px 5px 0 0;
- -moz-border-radius: 5px 5px 0 0;
- -webkit-border-top-right-radius: 5px;
- -webkit-border-top-left-radius: 5px;
-}
-
-#qunit-header a {
- text-decoration: none;
- color: #c2ccd1;
-}
-
-#qunit-header a:hover,
-#qunit-header a:focus {
- color: #fff;
-}
-
-#qunit-testrunner-toolbar label {
- display: inline-block;
- padding: 0 .5em 0 .1em;
-}
-
-#qunit-banner {
- height: 5px;
-}
-
-#qunit-testrunner-toolbar {
- padding: 0.5em 0 0.5em 2em;
- color: #5E740B;
- background-color: #eee;
- overflow: hidden;
-}
-
-#qunit-userAgent {
- padding: 0.5em 0 0.5em 2.5em;
- background-color: #2b81af;
- color: #fff;
- text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
-}
-
-#qunit-modulefilter-container {
- float: right;
-}
-
-/** Tests: Pass/Fail */
-
-#qunit-tests {
- list-style-position: inside;
-}
-
-#qunit-tests li {
- padding: 0.4em 0.5em 0.4em 2.5em;
- border-bottom: 1px solid #fff;
- list-style-position: inside;
-}
-
-#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running {
- display: none;
-}
-
-#qunit-tests li strong {
- cursor: pointer;
-}
-
-#qunit-tests li a {
- padding: 0.5em;
- color: #c2ccd1;
- text-decoration: none;
-}
-#qunit-tests li a:hover,
-#qunit-tests li a:focus {
- color: #000;
-}
-
-#qunit-tests li .runtime {
- float: right;
- font-size: smaller;
-}
-
-.qunit-assert-list {
- margin-top: 0.5em;
- padding: 0.5em;
-
- background-color: #fff;
-
- border-radius: 5px;
- -moz-border-radius: 5px;
- -webkit-border-radius: 5px;
-}
-
-.qunit-collapsed {
- display: none;
-}
-
-#qunit-tests table {
- border-collapse: collapse;
- margin-top: .2em;
-}
-
-#qunit-tests th {
- text-align: right;
- vertical-align: top;
- padding: 0 .5em 0 0;
-}
-
-#qunit-tests td {
- vertical-align: top;
-}
-
-#qunit-tests pre {
- margin: 0;
- white-space: pre-wrap;
- word-wrap: break-word;
-}
-
-#qunit-tests del {
- background-color: #e0f2be;
- color: #374e0c;
- text-decoration: none;
-}
-
-#qunit-tests ins {
- background-color: #ffcaca;
- color: #500;
- text-decoration: none;
-}
-
-/*** Test Counts */
-
-#qunit-tests b.counts { color: black; }
-#qunit-tests b.passed { color: #5E740B; }
-#qunit-tests b.failed { color: #710909; }
-
-#qunit-tests li li {
- padding: 5px;
- background-color: #fff;
- border-bottom: none;
- list-style-position: inside;
-}
-
-/*** Passing Styles */
-
-#qunit-tests li li.pass {
- color: #3c510c;
- background-color: #fff;
- border-left: 10px solid #C6E746;
-}
-
-#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
-#qunit-tests .pass .test-name { color: #366097; }
-
-#qunit-tests .pass .test-actual,
-#qunit-tests .pass .test-expected { color: #999999; }
-
-#qunit-banner.qunit-pass { background-color: #C6E746; }
-
-/*** Failing Styles */
-
-#qunit-tests li li.fail {
- color: #710909;
- background-color: #fff;
- border-left: 10px solid #EE5757;
- white-space: pre;
-}
-
-#qunit-tests > li:last-child {
- border-radius: 0 0 5px 5px;
- -moz-border-radius: 0 0 5px 5px;
- -webkit-border-bottom-right-radius: 5px;
- -webkit-border-bottom-left-radius: 5px;
-}
-
-#qunit-tests .fail { color: #000000; background-color: #EE5757; }
-#qunit-tests .fail .test-name,
-#qunit-tests .fail .module-name { color: #000000; }
-
-#qunit-tests .fail .test-actual { color: #EE5757; }
-#qunit-tests .fail .test-expected { color: green; }
-
-#qunit-banner.qunit-fail { background-color: #EE5757; }
-
-
-/** Result */
-
-#qunit-testresult {
- padding: 0.5em 0.5em 0.5em 2.5em;
-
- color: #2b81af;
- background-color: #D2E0E6;
-
- border-bottom: 1px solid white;
-}
-#qunit-testresult .module-name {
- font-weight: bold;
-}
-
-/** Fixture */
-
-#qunit-fixture {
- position: absolute;
- top: -10000px;
- left: -10000px;
- width: 1000px;
- height: 1000px;
-}
diff --git a/test/lib/qunit-1.11.0.js b/test/lib/qunit-1.11.0.js
deleted file mode 100644
index 302545f..0000000
--- a/test/lib/qunit-1.11.0.js
+++ /dev/null
@@ -1,2152 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-(function( window ) {
-
-var QUnit,
- assert,
- config,
- onErrorFnPrev,
- testId = 0,
- fileName = (sourceFromStacktrace( 0 ) || "" ).replace(/(:\d+)+\)?/, "").replace(/.+\//, ""),
- toString = Object.prototype.toString,
- hasOwn = Object.prototype.hasOwnProperty,
- // Keep a local reference to Date (GH-283)
- Date = window.Date,
- defined = {
- setTimeout: typeof window.setTimeout !== "undefined",
- sessionStorage: (function() {
- var x = "qunit-test-string";
- try {
- sessionStorage.setItem( x, x );
- sessionStorage.removeItem( x );
- return true;
- } catch( e ) {
- return false;
- }
- }())
- },
- /**
- * Provides a normalized error string, correcting an issue
- * with IE 7 (and prior) where Error.prototype.toString is
- * not properly implemented
- *
- * Based on http://es5.github.com/#x15.11.4.4
- *
- * @param {String|Error} error
- * @return {String} error message
- */
- errorString = function( error ) {
- var name, message,
- errorString = error.toString();
- if ( errorString.substring( 0, 7 ) === "[object" ) {
- name = error.name ? error.name.toString() : "Error";
- message = error.message ? error.message.toString() : "";
- if ( name && message ) {
- return name + ": " + message;
- } else if ( name ) {
- return name;
- } else if ( message ) {
- return message;
- } else {
- return "Error";
- }
- } else {
- return errorString;
- }
- },
- /**
- * Makes a clone of an object using only Array or Object as base,
- * and copies over the own enumerable properties.
- *
- * @param {Object} obj
- * @return {Object} New object with only the own properties (recursively).
- */
- objectValues = function( obj ) {
- // Grunt 0.3.x uses an older version of jshint that still has jshint/jshint#392.
- /*jshint newcap: false */
- var key, val,
- vals = QUnit.is( "array", obj ) ? [] : {};
- for ( key in obj ) {
- if ( hasOwn.call( obj, key ) ) {
- val = obj[key];
- vals[key] = val === Object(val) ? objectValues(val) : val;
- }
- }
- return vals;
- };
-
-function Test( settings ) {
- extend( this, settings );
- this.assertions = [];
- this.testNumber = ++Test.count;
-}
-
-Test.count = 0;
-
-Test.prototype = {
- init: function() {
- var a, b, li,
- tests = id( "qunit-tests" );
-
- if ( tests ) {
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml;
-
- // `a` initialized at top of scope
- a = document.createElement( "a" );
- a.innerHTML = "Rerun";
- a.href = QUnit.url({ testNumber: this.testNumber });
-
- li = document.createElement( "li" );
- li.appendChild( b );
- li.appendChild( a );
- li.className = "running";
- li.id = this.id = "qunit-test-output" + testId++;
-
- tests.appendChild( li );
- }
- },
- setup: function() {
- if ( this.module !== config.previousModule ) {
- if ( config.previousModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.previousModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
- config.previousModule = this.module;
- config.moduleStats = { all: 0, bad: 0 };
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- } else if ( config.autorun ) {
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- }
-
- config.current = this;
-
- this.testEnvironment = extend({
- setup: function() {},
- teardown: function() {}
- }, this.moduleTestEnvironment );
-
- this.started = +new Date();
- runLoggingCallbacks( "testStart", QUnit, {
- name: this.testName,
- module: this.module
- });
-
- // allow utility functions to access the current test environment
- // TODO why??
- QUnit.current_testEnvironment = this.testEnvironment;
-
- if ( !config.pollution ) {
- saveGlobal();
- }
- if ( config.notrycatch ) {
- this.testEnvironment.setup.call( this.testEnvironment );
- return;
- }
- try {
- this.testEnvironment.setup.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Setup failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- },
- run: function() {
- config.current = this;
-
- var running = id( "qunit-testresult" );
-
- if ( running ) {
- running.innerHTML = "Running:
" + this.nameHtml;
- }
-
- if ( this.async ) {
- QUnit.stop();
- }
-
- this.callbackStarted = +new Date();
-
- if ( config.notrycatch ) {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- return;
- }
-
- try {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- } catch( e ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
-
- QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + " " + this.stack + ": " + ( e.message || e ), extractStacktrace( e, 0 ) );
- // else next test will carry the responsibility
- saveGlobal();
-
- // Restart the tests if they're blocking
- if ( config.blocking ) {
- QUnit.start();
- }
- }
- },
- teardown: function() {
- config.current = this;
- if ( config.notrycatch ) {
- if ( typeof this.callbackRuntime === "undefined" ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
- }
- this.testEnvironment.teardown.call( this.testEnvironment );
- return;
- } else {
- try {
- this.testEnvironment.teardown.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Teardown failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- }
- checkPollution();
- },
- finish: function() {
- config.current = this;
- if ( config.requireExpects && this.expected === null ) {
- QUnit.pushFailure( "Expected number of assertions to be defined, but expect() was not called.", this.stack );
- } else if ( this.expected !== null && this.expected !== this.assertions.length ) {
- QUnit.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack );
- } else if ( this.expected === null && !this.assertions.length ) {
- QUnit.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions.", this.stack );
- }
-
- var i, assertion, a, b, time, li, ol,
- test = this,
- good = 0,
- bad = 0,
- tests = id( "qunit-tests" );
-
- this.runtime = +new Date() - this.started;
- config.stats.all += this.assertions.length;
- config.moduleStats.all += this.assertions.length;
-
- if ( tests ) {
- ol = document.createElement( "ol" );
- ol.className = "qunit-assert-list";
-
- for ( i = 0; i < this.assertions.length; i++ ) {
- assertion = this.assertions[i];
-
- li = document.createElement( "li" );
- li.className = assertion.result ? "pass" : "fail";
- li.innerHTML = assertion.message || ( assertion.result ? "okay" : "failed" );
- ol.appendChild( li );
-
- if ( assertion.result ) {
- good++;
- } else {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
-
- // store result when possible
- if ( QUnit.config.reorder && defined.sessionStorage ) {
- if ( bad ) {
- sessionStorage.setItem( "qunit-test-" + this.module + "-" + this.testName, bad );
- } else {
- sessionStorage.removeItem( "qunit-test-" + this.module + "-" + this.testName );
- }
- }
-
- if ( bad === 0 ) {
- addClass( ol, "qunit-collapsed" );
- }
-
- // `b` initialized at top of scope
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml + " (" + bad + ", " + good + ", " + this.assertions.length + ")";
-
- addEvent(b, "click", function() {
- var next = b.parentNode.lastChild,
- collapsed = hasClass( next, "qunit-collapsed" );
- ( collapsed ? removeClass : addClass )( next, "qunit-collapsed" );
- });
-
- addEvent(b, "dblclick", function( e ) {
- var target = e && e.target ? e.target : window.event.srcElement;
- if ( target.nodeName.toLowerCase() === "span" || target.nodeName.toLowerCase() === "b" ) {
- target = target.parentNode;
- }
- if ( window.location && target.nodeName.toLowerCase() === "strong" ) {
- window.location = QUnit.url({ testNumber: test.testNumber });
- }
- });
-
- // `time` initialized at top of scope
- time = document.createElement( "span" );
- time.className = "runtime";
- time.innerHTML = this.runtime + " ms";
-
- // `li` initialized at top of scope
- li = id( this.id );
- li.className = bad ? "fail" : "pass";
- li.removeChild( li.firstChild );
- a = li.firstChild;
- li.appendChild( b );
- li.appendChild( a );
- li.appendChild( time );
- li.appendChild( ol );
-
- } else {
- for ( i = 0; i < this.assertions.length; i++ ) {
- if ( !this.assertions[i].result ) {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
- }
-
- runLoggingCallbacks( "testDone", QUnit, {
- name: this.testName,
- module: this.module,
- failed: bad,
- passed: this.assertions.length - bad,
- total: this.assertions.length,
- duration: this.runtime
- });
-
- QUnit.reset();
-
- config.current = undefined;
- },
-
- queue: function() {
- var bad,
- test = this;
-
- synchronize(function() {
- test.init();
- });
- function run() {
- // each of these can by async
- synchronize(function() {
- test.setup();
- });
- synchronize(function() {
- test.run();
- });
- synchronize(function() {
- test.teardown();
- });
- synchronize(function() {
- test.finish();
- });
- }
-
- // `bad` initialized at top of scope
- // defer when previous test run passed, if storage is available
- bad = QUnit.config.reorder && defined.sessionStorage &&
- +sessionStorage.getItem( "qunit-test-" + this.module + "-" + this.testName );
-
- if ( bad ) {
- run();
- } else {
- synchronize( run, true );
- }
- }
-};
-
-// Root QUnit object.
-// `QUnit` initialized at top of scope
-QUnit = {
-
- // call on start of module test to prepend name to all tests
- module: function( name, testEnvironment ) {
- config.currentModule = name;
- config.currentModuleTestEnvironment = testEnvironment;
- config.modules[name] = true;
- },
-
- asyncTest: function( testName, expected, callback ) {
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- QUnit.test( testName, expected, callback, true );
- },
-
- test: function( testName, expected, callback, async ) {
- var test,
- nameHtml = "" + escapeText( testName ) + "";
-
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- if ( config.currentModule ) {
- nameHtml = "" + escapeText( config.currentModule ) + ": " + nameHtml;
- }
-
- test = new Test({
- nameHtml: nameHtml,
- testName: testName,
- expected: expected,
- async: async,
- callback: callback,
- module: config.currentModule,
- moduleTestEnvironment: config.currentModuleTestEnvironment,
- stack: sourceFromStacktrace( 2 )
- });
-
- if ( !validTest( test ) ) {
- return;
- }
-
- test.queue();
- },
-
- // Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through.
- expect: function( asserts ) {
- if (arguments.length === 1) {
- config.current.expected = asserts;
- } else {
- return config.current.expected;
- }
- },
-
- start: function( count ) {
- // QUnit hasn't been initialized yet.
- // Note: RequireJS (et al) may delay onLoad
- if ( config.semaphore === undefined ) {
- QUnit.begin(function() {
- // This is triggered at the top of QUnit.load, push start() to the event loop, to allow QUnit.load to finish first
- setTimeout(function() {
- QUnit.start( count );
- });
- });
- return;
- }
-
- config.semaphore -= count || 1;
- // don't start until equal number of stop-calls
- if ( config.semaphore > 0 ) {
- return;
- }
- // ignore if start is called more often then stop
- if ( config.semaphore < 0 ) {
- config.semaphore = 0;
- QUnit.pushFailure( "Called start() while already started (QUnit.config.semaphore was 0 already)", null, sourceFromStacktrace(2) );
- return;
- }
- // A slight delay, to avoid any current callbacks
- if ( defined.setTimeout ) {
- window.setTimeout(function() {
- if ( config.semaphore > 0 ) {
- return;
- }
- if ( config.timeout ) {
- clearTimeout( config.timeout );
- }
-
- config.blocking = false;
- process( true );
- }, 13);
- } else {
- config.blocking = false;
- process( true );
- }
- },
-
- stop: function( count ) {
- config.semaphore += count || 1;
- config.blocking = true;
-
- if ( config.testTimeout && defined.setTimeout ) {
- clearTimeout( config.timeout );
- config.timeout = window.setTimeout(function() {
- QUnit.ok( false, "Test timed out" );
- config.semaphore = 1;
- QUnit.start();
- }, config.testTimeout );
- }
- }
-};
-
-// `assert` initialized at top of scope
-// Asssert helpers
-// All of these must either call QUnit.push() or manually do:
-// - runLoggingCallbacks( "log", .. );
-// - config.current.assertions.push({ .. });
-// We attach it to the QUnit object *after* we expose the public API,
-// otherwise `assert` will become a global variable in browsers (#341).
-assert = {
- /**
- * Asserts rough true-ish result.
- * @name ok
- * @function
- * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" );
- */
- ok: function( result, msg ) {
- if ( !config.current ) {
- throw new Error( "ok() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
- result = !!result;
-
- var source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: msg
- };
-
- msg = escapeText( msg || (result ? "okay" : "failed" ) );
- msg = "" + msg + "";
-
- if ( !result ) {
- source = sourceFromStacktrace( 2 );
- if ( source ) {
- details.source = source;
- msg += "Source: | " + escapeText( source ) + " |
---|
";
- }
- }
- runLoggingCallbacks( "log", QUnit, details );
- config.current.assertions.push({
- result: result,
- message: msg
- });
- },
-
- /**
- * Assert that the first two arguments are equal, with an optional message.
- * Prints out both actual and expected values.
- * @name equal
- * @function
- * @example equal( format( "Received {0} bytes.", 2), "Received 2 bytes.", "format() replaces {0} with next argument" );
- */
- equal: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected == actual, actual, expected, message );
- },
-
- /**
- * @name notEqual
- * @function
- */
- notEqual: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected != actual, actual, expected, message );
- },
-
- /**
- * @name propEqual
- * @function
- */
- propEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notPropEqual
- * @function
- */
- notPropEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name deepEqual
- * @function
- */
- deepEqual: function( actual, expected, message ) {
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notDeepEqual
- * @function
- */
- notDeepEqual: function( actual, expected, message ) {
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name strictEqual
- * @function
- */
- strictEqual: function( actual, expected, message ) {
- QUnit.push( expected === actual, actual, expected, message );
- },
-
- /**
- * @name notStrictEqual
- * @function
- */
- notStrictEqual: function( actual, expected, message ) {
- QUnit.push( expected !== actual, actual, expected, message );
- },
-
- "throws": function( block, expected, message ) {
- var actual,
- expectedOutput = expected,
- ok = false;
-
- // 'expected' is optional
- if ( typeof expected === "string" ) {
- message = expected;
- expected = null;
- }
-
- config.current.ignoreGlobalErrors = true;
- try {
- block.call( config.current.testEnvironment );
- } catch (e) {
- actual = e;
- }
- config.current.ignoreGlobalErrors = false;
-
- if ( actual ) {
- // we don't want to validate thrown error
- if ( !expected ) {
- ok = true;
- expectedOutput = null;
- // expected is a regexp
- } else if ( QUnit.objectType( expected ) === "regexp" ) {
- ok = expected.test( errorString( actual ) );
- // expected is a constructor
- } else if ( actual instanceof expected ) {
- ok = true;
- // expected is a validation function which returns true is validation passed
- } else if ( expected.call( {}, actual ) === true ) {
- expectedOutput = null;
- ok = true;
- }
-
- QUnit.push( ok, actual, expectedOutput, message );
- } else {
- QUnit.pushFailure( message, null, 'No exception was thrown.' );
- }
- }
-};
-
-/**
- * @deprecate since 1.8.0
- * Kept assertion helpers in root for backwards compatibility.
- */
-extend( QUnit, assert );
-
-/**
- * @deprecated since 1.9.0
- * Kept root "raises()" for backwards compatibility.
- * (Note that we don't introduce assert.raises).
- */
-QUnit.raises = assert[ "throws" ];
-
-/**
- * @deprecated since 1.0.0, replaced with error pushes since 1.3.0
- * Kept to avoid TypeErrors for undefined methods.
- */
-QUnit.equals = function() {
- QUnit.push( false, false, false, "QUnit.equals has been deprecated since 2009 (e88049a0), use QUnit.equal instead" );
-};
-QUnit.same = function() {
- QUnit.push( false, false, false, "QUnit.same has been deprecated since 2009 (e88049a0), use QUnit.deepEqual instead" );
-};
-
-// We want access to the constructor's prototype
-(function() {
- function F() {}
- F.prototype = QUnit;
- QUnit = new F();
- // Make F QUnit's constructor so that we can add to the prototype later
- QUnit.constructor = F;
-}());
-
-/**
- * Config object: Maintain internal state
- * Later exposed as QUnit.config
- * `config` initialized at top of scope
- */
-config = {
- // The queue of tests to run
- queue: [],
-
- // block until document ready
- blocking: true,
-
- // when enabled, show only failing tests
- // gets persisted through sessionStorage and can be changed in UI via checkbox
- hidepassed: false,
-
- // by default, run previously failed tests first
- // very useful in combination with "Hide passed tests" checked
- reorder: true,
-
- // by default, modify document.title when suite is done
- altertitle: true,
-
- // when enabled, all tests must call expect()
- requireExpects: false,
-
- // add checkboxes that are persisted in the query-string
- // when enabled, the id is set to `true` as a `QUnit.config` property
- urlConfig: [
- {
- id: "noglobals",
- label: "Check for Globals",
- tooltip: "Enabling this will test if any test introduces new properties on the `window` object. Stored as query-strings."
- },
- {
- id: "notrycatch",
- label: "No try-catch",
- tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging exceptions in IE reasonable. Stored as query-strings."
- }
- ],
-
- // Set of all modules.
- modules: {},
-
- // logging callback queues
- begin: [],
- done: [],
- log: [],
- testStart: [],
- testDone: [],
- moduleStart: [],
- moduleDone: []
-};
-
-// Export global variables, unless an 'exports' object exists,
-// in that case we assume we're in CommonJS (dealt with on the bottom of the script)
-if ( typeof exports === "undefined" ) {
- extend( window, QUnit );
-
- // Expose QUnit object
- window.QUnit = QUnit;
-}
-
-// Initialize more QUnit.config and QUnit.urlParams
-(function() {
- var i,
- location = window.location || { search: "", protocol: "file:" },
- params = location.search.slice( 1 ).split( "&" ),
- length = params.length,
- urlParams = {},
- current;
-
- if ( params[ 0 ] ) {
- for ( i = 0; i < length; i++ ) {
- current = params[ i ].split( "=" );
- current[ 0 ] = decodeURIComponent( current[ 0 ] );
- // allow just a key to turn on a flag, e.g., test.html?noglobals
- current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true;
- urlParams[ current[ 0 ] ] = current[ 1 ];
- }
- }
-
- QUnit.urlParams = urlParams;
-
- // String search anywhere in moduleName+testName
- config.filter = urlParams.filter;
-
- // Exact match of the module name
- config.module = urlParams.module;
-
- config.testNumber = parseInt( urlParams.testNumber, 10 ) || null;
-
- // Figure out if we're running the tests from a server or not
- QUnit.isLocal = location.protocol === "file:";
-}());
-
-// Extend QUnit object,
-// these after set here because they should not be exposed as global functions
-extend( QUnit, {
- assert: assert,
-
- config: config,
-
- // Initialize the configuration options
- init: function() {
- extend( config, {
- stats: { all: 0, bad: 0 },
- moduleStats: { all: 0, bad: 0 },
- started: +new Date(),
- updateRate: 1000,
- blocking: false,
- autostart: true,
- autorun: false,
- filter: "",
- queue: [],
- semaphore: 1
- });
-
- var tests, banner, result,
- qunit = id( "qunit" );
-
- if ( qunit ) {
- qunit.innerHTML =
- "" +
- "" +
- "" +
- "" +
- "
";
- }
-
- tests = id( "qunit-tests" );
- banner = id( "qunit-banner" );
- result = id( "qunit-testresult" );
-
- if ( tests ) {
- tests.innerHTML = "";
- }
-
- if ( banner ) {
- banner.className = "";
- }
-
- if ( result ) {
- result.parentNode.removeChild( result );
- }
-
- if ( tests ) {
- result = document.createElement( "p" );
- result.id = "qunit-testresult";
- result.className = "result";
- tests.parentNode.insertBefore( result, tests );
- result.innerHTML = "Running...
";
- }
- },
-
- // Resets the test setup. Useful for tests that modify the DOM.
- reset: function() {
- var fixture = id( "qunit-fixture" );
- if ( fixture ) {
- fixture.innerHTML = config.fixture;
- }
- },
-
- // Trigger an event on an element.
- // @example triggerEvent( document.body, "click" );
- triggerEvent: function( elem, type, event ) {
- if ( document.createEvent ) {
- event = document.createEvent( "MouseEvents" );
- event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView,
- 0, 0, 0, 0, 0, false, false, false, false, 0, null);
-
- elem.dispatchEvent( event );
- } else if ( elem.fireEvent ) {
- elem.fireEvent( "on" + type );
- }
- },
-
- // Safe object type checking
- is: function( type, obj ) {
- return QUnit.objectType( obj ) === type;
- },
-
- objectType: function( obj ) {
- if ( typeof obj === "undefined" ) {
- return "undefined";
- // consider: typeof null === object
- }
- if ( obj === null ) {
- return "null";
- }
-
- var match = toString.call( obj ).match(/^\[object\s(.*)\]$/),
- type = match && match[1] || "";
-
- switch ( type ) {
- case "Number":
- if ( isNaN(obj) ) {
- return "nan";
- }
- return "number";
- case "String":
- case "Boolean":
- case "Array":
- case "Date":
- case "RegExp":
- case "Function":
- return type.toLowerCase();
- }
- if ( typeof obj === "object" ) {
- return "object";
- }
- return undefined;
- },
-
- push: function( result, actual, expected, message ) {
- if ( !config.current ) {
- throw new Error( "assertion outside test context, was " + sourceFromStacktrace() );
- }
-
- var output, source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: message,
- actual: actual,
- expected: expected
- };
-
- message = escapeText( message ) || ( result ? "okay" : "failed" );
- message = "" + message + "";
- output = message;
-
- if ( !result ) {
- expected = escapeText( QUnit.jsDump.parse(expected) );
- actual = escapeText( QUnit.jsDump.parse(actual) );
- output += "Expected: | " + expected + " |
";
-
- if ( actual !== expected ) {
- output += "Result: | " + actual + " |
";
- output += "Diff: | " + QUnit.diff( expected, actual ) + " |
";
- }
-
- source = sourceFromStacktrace();
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
- }
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: !!result,
- message: output
- });
- },
-
- pushFailure: function( message, source, actual ) {
- if ( !config.current ) {
- throw new Error( "pushFailure() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
-
- var output,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: false,
- message: message
- };
-
- message = escapeText( message ) || "error";
- message = "" + message + "";
- output = message;
-
- output += "";
-
- if ( actual ) {
- output += "Result: | " + escapeText( actual ) + " |
";
- }
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: false,
- message: output
- });
- },
-
- url: function( params ) {
- params = extend( extend( {}, QUnit.urlParams ), params );
- var key,
- querystring = "?";
-
- for ( key in params ) {
- if ( !hasOwn.call( params, key ) ) {
- continue;
- }
- querystring += encodeURIComponent( key ) + "=" +
- encodeURIComponent( params[ key ] ) + "&";
- }
- return window.location.protocol + "//" + window.location.host +
- window.location.pathname + querystring.slice( 0, -1 );
- },
-
- extend: extend,
- id: id,
- addEvent: addEvent
- // load, equiv, jsDump, diff: Attached later
-});
-
-/**
- * @deprecated: Created for backwards compatibility with test runner that set the hook function
- * into QUnit.{hook}, instead of invoking it and passing the hook function.
- * QUnit.constructor is set to the empty F() above so that we can add to it's prototype here.
- * Doing this allows us to tell if the following methods have been overwritten on the actual
- * QUnit object.
- */
-extend( QUnit.constructor.prototype, {
-
- // Logging callbacks; all receive a single argument with the listed properties
- // run test/logs.html for any related changes
- begin: registerLoggingCallback( "begin" ),
-
- // done: { failed, passed, total, runtime }
- done: registerLoggingCallback( "done" ),
-
- // log: { result, actual, expected, message }
- log: registerLoggingCallback( "log" ),
-
- // testStart: { name }
- testStart: registerLoggingCallback( "testStart" ),
-
- // testDone: { name, failed, passed, total, duration }
- testDone: registerLoggingCallback( "testDone" ),
-
- // moduleStart: { name }
- moduleStart: registerLoggingCallback( "moduleStart" ),
-
- // moduleDone: { name, failed, passed, total }
- moduleDone: registerLoggingCallback( "moduleDone" )
-});
-
-if ( typeof document === "undefined" || document.readyState === "complete" ) {
- config.autorun = true;
-}
-
-QUnit.load = function() {
- runLoggingCallbacks( "begin", QUnit, {} );
-
- // Initialize the config, saving the execution queue
- var banner, filter, i, label, len, main, ol, toolbar, userAgent, val,
- urlConfigCheckboxesContainer, urlConfigCheckboxes, moduleFilter,
- numModules = 0,
- moduleFilterHtml = "",
- urlConfigHtml = "",
- oldconfig = extend( {}, config );
-
- QUnit.init();
- extend(config, oldconfig);
-
- config.blocking = false;
-
- len = config.urlConfig.length;
-
- for ( i = 0; i < len; i++ ) {
- val = config.urlConfig[i];
- if ( typeof val === "string" ) {
- val = {
- id: val,
- label: val,
- tooltip: "[no tooltip available]"
- };
- }
- config[ val.id ] = QUnit.urlParams[ val.id ];
- urlConfigHtml += "";
- }
-
- moduleFilterHtml += "";
-
- // `userAgent` initialized at top of scope
- userAgent = id( "qunit-userAgent" );
- if ( userAgent ) {
- userAgent.innerHTML = navigator.userAgent;
- }
-
- // `banner` initialized at top of scope
- banner = id( "qunit-header" );
- if ( banner ) {
- banner.innerHTML = "" + banner.innerHTML + " ";
- }
-
- // `toolbar` initialized at top of scope
- toolbar = id( "qunit-testrunner-toolbar" );
- if ( toolbar ) {
- // `filter` initialized at top of scope
- filter = document.createElement( "input" );
- filter.type = "checkbox";
- filter.id = "qunit-filter-pass";
-
- addEvent( filter, "click", function() {
- var tmp,
- ol = document.getElementById( "qunit-tests" );
-
- if ( filter.checked ) {
- ol.className = ol.className + " hidepass";
- } else {
- tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " ";
- ol.className = tmp.replace( / hidepass /, " " );
- }
- if ( defined.sessionStorage ) {
- if (filter.checked) {
- sessionStorage.setItem( "qunit-filter-passed-tests", "true" );
- } else {
- sessionStorage.removeItem( "qunit-filter-passed-tests" );
- }
- }
- });
-
- if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem( "qunit-filter-passed-tests" ) ) {
- filter.checked = true;
- // `ol` initialized at top of scope
- ol = document.getElementById( "qunit-tests" );
- ol.className = ol.className + " hidepass";
- }
- toolbar.appendChild( filter );
-
- // `label` initialized at top of scope
- label = document.createElement( "label" );
- label.setAttribute( "for", "qunit-filter-pass" );
- label.setAttribute( "title", "Only show tests and assertons that fail. Stored in sessionStorage." );
- label.innerHTML = "Hide passed tests";
- toolbar.appendChild( label );
-
- urlConfigCheckboxesContainer = document.createElement("span");
- urlConfigCheckboxesContainer.innerHTML = urlConfigHtml;
- urlConfigCheckboxes = urlConfigCheckboxesContainer.getElementsByTagName("input");
- // For oldIE support:
- // * Add handlers to the individual elements instead of the container
- // * Use "click" instead of "change"
- // * Fallback from event.target to event.srcElement
- addEvents( urlConfigCheckboxes, "click", function( event ) {
- var params = {},
- target = event.target || event.srcElement;
- params[ target.name ] = target.checked ? true : undefined;
- window.location = QUnit.url( params );
- });
- toolbar.appendChild( urlConfigCheckboxesContainer );
-
- if (numModules > 1) {
- moduleFilter = document.createElement( 'span' );
- moduleFilter.setAttribute( 'id', 'qunit-modulefilter-container' );
- moduleFilter.innerHTML = moduleFilterHtml;
- addEvent( moduleFilter.lastChild, "change", function() {
- var selectBox = moduleFilter.getElementsByTagName("select")[0],
- selectedModule = decodeURIComponent(selectBox.options[selectBox.selectedIndex].value);
-
- window.location = QUnit.url( { module: ( selectedModule === "" ) ? undefined : selectedModule } );
- });
- toolbar.appendChild(moduleFilter);
- }
- }
-
- // `main` initialized at top of scope
- main = id( "qunit-fixture" );
- if ( main ) {
- config.fixture = main.innerHTML;
- }
-
- if ( config.autostart ) {
- QUnit.start();
- }
-};
-
-addEvent( window, "load", QUnit.load );
-
-// `onErrorFnPrev` initialized at top of scope
-// Preserve other handlers
-onErrorFnPrev = window.onerror;
-
-// Cover uncaught exceptions
-// Returning true will surpress the default browser handler,
-// returning false will let it run.
-window.onerror = function ( error, filePath, linerNr ) {
- var ret = false;
- if ( onErrorFnPrev ) {
- ret = onErrorFnPrev( error, filePath, linerNr );
- }
-
- // Treat return value as window.onerror itself does,
- // Only do our handling if not surpressed.
- if ( ret !== true ) {
- if ( QUnit.config.current ) {
- if ( QUnit.config.current.ignoreGlobalErrors ) {
- return true;
- }
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- } else {
- QUnit.test( "global failure", extend( function() {
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- }, { validTest: validTest } ) );
- }
- return false;
- }
-
- return ret;
-};
-
-function done() {
- config.autorun = true;
-
- // Log the last module results
- if ( config.currentModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.currentModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
-
- var i, key,
- banner = id( "qunit-banner" ),
- tests = id( "qunit-tests" ),
- runtime = +new Date() - config.started,
- passed = config.stats.all - config.stats.bad,
- html = [
- "Tests completed in ",
- runtime,
- " milliseconds.
",
- "",
- passed,
- " assertions of ",
- config.stats.all,
- " passed, ",
- config.stats.bad,
- " failed."
- ].join( "" );
-
- if ( banner ) {
- banner.className = ( config.stats.bad ? "qunit-fail" : "qunit-pass" );
- }
-
- if ( tests ) {
- id( "qunit-testresult" ).innerHTML = html;
- }
-
- if ( config.altertitle && typeof document !== "undefined" && document.title ) {
- // show ✖ for good, ✔ for bad suite result in title
- // use escape sequences in case file gets loaded with non-utf-8-charset
- document.title = [
- ( config.stats.bad ? "\u2716" : "\u2714" ),
- document.title.replace( /^[\u2714\u2716] /i, "" )
- ].join( " " );
- }
-
- // clear own sessionStorage items if all tests passed
- if ( config.reorder && defined.sessionStorage && config.stats.bad === 0 ) {
- // `key` & `i` initialized at top of scope
- for ( i = 0; i < sessionStorage.length; i++ ) {
- key = sessionStorage.key( i++ );
- if ( key.indexOf( "qunit-test-" ) === 0 ) {
- sessionStorage.removeItem( key );
- }
- }
- }
-
- // scroll back to top to show results
- if ( window.scrollTo ) {
- window.scrollTo(0, 0);
- }
-
- runLoggingCallbacks( "done", QUnit, {
- failed: config.stats.bad,
- passed: passed,
- total: config.stats.all,
- runtime: runtime
- });
-}
-
-/** @return Boolean: true if this test should be ran */
-function validTest( test ) {
- var include,
- filter = config.filter && config.filter.toLowerCase(),
- module = config.module && config.module.toLowerCase(),
- fullName = (test.module + ": " + test.testName).toLowerCase();
-
- // Internally-generated tests are always valid
- if ( test.callback && test.callback.validTest === validTest ) {
- delete test.callback.validTest;
- return true;
- }
-
- if ( config.testNumber ) {
- return test.testNumber === config.testNumber;
- }
-
- if ( module && ( !test.module || test.module.toLowerCase() !== module ) ) {
- return false;
- }
-
- if ( !filter ) {
- return true;
- }
-
- include = filter.charAt( 0 ) !== "!";
- if ( !include ) {
- filter = filter.slice( 1 );
- }
-
- // If the filter matches, we need to honour include
- if ( fullName.indexOf( filter ) !== -1 ) {
- return include;
- }
-
- // Otherwise, do the opposite
- return !include;
-}
-
-// so far supports only Firefox, Chrome and Opera (buggy), Safari (for real exceptions)
-// Later Safari and IE10 are supposed to support error.stack as well
-// See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack
-function extractStacktrace( e, offset ) {
- offset = offset === undefined ? 3 : offset;
-
- var stack, include, i;
-
- if ( e.stacktrace ) {
- // Opera
- return e.stacktrace.split( "\n" )[ offset + 3 ];
- } else if ( e.stack ) {
- // Firefox, Chrome
- stack = e.stack.split( "\n" );
- if (/^error$/i.test( stack[0] ) ) {
- stack.shift();
- }
- if ( fileName ) {
- include = [];
- for ( i = offset; i < stack.length; i++ ) {
- if ( stack[ i ].indexOf( fileName ) !== -1 ) {
- break;
- }
- include.push( stack[ i ] );
- }
- if ( include.length ) {
- return include.join( "\n" );
- }
- }
- return stack[ offset ];
- } else if ( e.sourceURL ) {
- // Safari, PhantomJS
- // hopefully one day Safari provides actual stacktraces
- // exclude useless self-reference for generated Error objects
- if ( /qunit.js$/.test( e.sourceURL ) ) {
- return;
- }
- // for actual exceptions, this is useful
- return e.sourceURL + ":" + e.line;
- }
-}
-function sourceFromStacktrace( offset ) {
- try {
- throw new Error();
- } catch ( e ) {
- return extractStacktrace( e, offset );
- }
-}
-
-/**
- * Escape text for attribute or text content.
- */
-function escapeText( s ) {
- if ( !s ) {
- return "";
- }
- s = s + "";
- // Both single quotes and double quotes (for attributes)
- return s.replace( /['"<>&]/g, function( s ) {
- switch( s ) {
- case '\'':
- return ''';
- case '"':
- return '"';
- case '<':
- return '<';
- case '>':
- return '>';
- case '&':
- return '&';
- }
- });
-}
-
-function synchronize( callback, last ) {
- config.queue.push( callback );
-
- if ( config.autorun && !config.blocking ) {
- process( last );
- }
-}
-
-function process( last ) {
- function next() {
- process( last );
- }
- var start = new Date().getTime();
- config.depth = config.depth ? config.depth + 1 : 1;
-
- while ( config.queue.length && !config.blocking ) {
- if ( !defined.setTimeout || config.updateRate <= 0 || ( ( new Date().getTime() - start ) < config.updateRate ) ) {
- config.queue.shift()();
- } else {
- window.setTimeout( next, 13 );
- break;
- }
- }
- config.depth--;
- if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) {
- done();
- }
-}
-
-function saveGlobal() {
- config.pollution = [];
-
- if ( config.noglobals ) {
- for ( var key in window ) {
- // in Opera sometimes DOM element ids show up here, ignore them
- if ( !hasOwn.call( window, key ) || /^qunit-test-output/.test( key ) ) {
- continue;
- }
- config.pollution.push( key );
- }
- }
-}
-
-function checkPollution() {
- var newGlobals,
- deletedGlobals,
- old = config.pollution;
-
- saveGlobal();
-
- newGlobals = diff( config.pollution, old );
- if ( newGlobals.length > 0 ) {
- QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join(", ") );
- }
-
- deletedGlobals = diff( old, config.pollution );
- if ( deletedGlobals.length > 0 ) {
- QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join(", ") );
- }
-}
-
-// returns a new Array with the elements that are in a but not in b
-function diff( a, b ) {
- var i, j,
- result = a.slice();
-
- for ( i = 0; i < result.length; i++ ) {
- for ( j = 0; j < b.length; j++ ) {
- if ( result[i] === b[j] ) {
- result.splice( i, 1 );
- i--;
- break;
- }
- }
- }
- return result;
-}
-
-function extend( a, b ) {
- for ( var prop in b ) {
- if ( b[ prop ] === undefined ) {
- delete a[ prop ];
-
- // Avoid "Member not found" error in IE8 caused by setting window.constructor
- } else if ( prop !== "constructor" || a !== window ) {
- a[ prop ] = b[ prop ];
- }
- }
-
- return a;
-}
-
-/**
- * @param {HTMLElement} elem
- * @param {string} type
- * @param {Function} fn
- */
-function addEvent( elem, type, fn ) {
- // Standards-based browsers
- if ( elem.addEventListener ) {
- elem.addEventListener( type, fn, false );
- // IE
- } else {
- elem.attachEvent( "on" + type, fn );
- }
-}
-
-/**
- * @param {Array|NodeList} elems
- * @param {string} type
- * @param {Function} fn
- */
-function addEvents( elems, type, fn ) {
- var i = elems.length;
- while ( i-- ) {
- addEvent( elems[i], type, fn );
- }
-}
-
-function hasClass( elem, name ) {
- return (" " + elem.className + " ").indexOf(" " + name + " ") > -1;
-}
-
-function addClass( elem, name ) {
- if ( !hasClass( elem, name ) ) {
- elem.className += (elem.className ? " " : "") + name;
- }
-}
-
-function removeClass( elem, name ) {
- var set = " " + elem.className + " ";
- // Class name may appear multiple times
- while ( set.indexOf(" " + name + " ") > -1 ) {
- set = set.replace(" " + name + " " , " ");
- }
- // If possible, trim it for prettiness, but not neccecarily
- elem.className = window.jQuery ? jQuery.trim( set ) : ( set.trim ? set.trim() : set );
-}
-
-function id( name ) {
- return !!( typeof document !== "undefined" && document && document.getElementById ) &&
- document.getElementById( name );
-}
-
-function registerLoggingCallback( key ) {
- return function( callback ) {
- config[key].push( callback );
- };
-}
-
-// Supports deprecated method of completely overwriting logging callbacks
-function runLoggingCallbacks( key, scope, args ) {
- var i, callbacks;
- if ( QUnit.hasOwnProperty( key ) ) {
- QUnit[ key ].call(scope, args );
- } else {
- callbacks = config[ key ];
- for ( i = 0; i < callbacks.length; i++ ) {
- callbacks[ i ].call( scope, args );
- }
- }
-}
-
-// Test for equality any JavaScript type.
-// Author: Philippe Rathé
-QUnit.equiv = (function() {
-
- // Call the o related callback with the given arguments.
- function bindCallbacks( o, callbacks, args ) {
- var prop = QUnit.objectType( o );
- if ( prop ) {
- if ( QUnit.objectType( callbacks[ prop ] ) === "function" ) {
- return callbacks[ prop ].apply( callbacks, args );
- } else {
- return callbacks[ prop ]; // or undefined
- }
- }
- }
-
- // the real equiv function
- var innerEquiv,
- // stack to decide between skip/abort functions
- callers = [],
- // stack to avoiding loops from circular referencing
- parents = [],
-
- getProto = Object.getPrototypeOf || function ( obj ) {
- return obj.__proto__;
- },
- callbacks = (function () {
-
- // for string, boolean, number and null
- function useStrictEquality( b, a ) {
- /*jshint eqeqeq:false */
- if ( b instanceof a.constructor || a instanceof b.constructor ) {
- // to catch short annotaion VS 'new' annotation of a
- // declaration
- // e.g. var i = 1;
- // var j = new Number(1);
- return a == b;
- } else {
- return a === b;
- }
- }
-
- return {
- "string": useStrictEquality,
- "boolean": useStrictEquality,
- "number": useStrictEquality,
- "null": useStrictEquality,
- "undefined": useStrictEquality,
-
- "nan": function( b ) {
- return isNaN( b );
- },
-
- "date": function( b, a ) {
- return QUnit.objectType( b ) === "date" && a.valueOf() === b.valueOf();
- },
-
- "regexp": function( b, a ) {
- return QUnit.objectType( b ) === "regexp" &&
- // the regex itself
- a.source === b.source &&
- // and its modifers
- a.global === b.global &&
- // (gmi) ...
- a.ignoreCase === b.ignoreCase &&
- a.multiline === b.multiline &&
- a.sticky === b.sticky;
- },
-
- // - skip when the property is a method of an instance (OOP)
- // - abort otherwise,
- // initial === would have catch identical references anyway
- "function": function() {
- var caller = callers[callers.length - 1];
- return caller !== Object && typeof caller !== "undefined";
- },
-
- "array": function( b, a ) {
- var i, j, len, loop;
-
- // b could be an object literal here
- if ( QUnit.objectType( b ) !== "array" ) {
- return false;
- }
-
- len = a.length;
- if ( len !== b.length ) {
- // safe and faster
- return false;
- }
-
- // track reference to avoid circular references
- parents.push( a );
- for ( i = 0; i < len; i++ ) {
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- loop = true;// dont rewalk array
- }
- }
- if ( !loop && !innerEquiv(a[i], b[i]) ) {
- parents.pop();
- return false;
- }
- }
- parents.pop();
- return true;
- },
-
- "object": function( b, a ) {
- var i, j, loop,
- // Default to true
- eq = true,
- aProperties = [],
- bProperties = [];
-
- // comparing constructors is more strict than using
- // instanceof
- if ( a.constructor !== b.constructor ) {
- // Allow objects with no prototype to be equivalent to
- // objects with Object as their constructor.
- if ( !(( getProto(a) === null && getProto(b) === Object.prototype ) ||
- ( getProto(b) === null && getProto(a) === Object.prototype ) ) ) {
- return false;
- }
- }
-
- // stack constructor before traversing properties
- callers.push( a.constructor );
- // track reference to avoid circular references
- parents.push( a );
-
- for ( i in a ) { // be strict: don't ensures hasOwnProperty
- // and go deep
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- // don't go down the same path twice
- loop = true;
- }
- }
- aProperties.push(i); // collect a's properties
-
- if (!loop && !innerEquiv( a[i], b[i] ) ) {
- eq = false;
- break;
- }
- }
-
- callers.pop(); // unstack, we are done
- parents.pop();
-
- for ( i in b ) {
- bProperties.push( i ); // collect b's properties
- }
-
- // Ensures identical properties name
- return eq && innerEquiv( aProperties.sort(), bProperties.sort() );
- }
- };
- }());
-
- innerEquiv = function() { // can take multiple arguments
- var args = [].slice.apply( arguments );
- if ( args.length < 2 ) {
- return true; // end transition
- }
-
- return (function( a, b ) {
- if ( a === b ) {
- return true; // catch the most you can
- } else if ( a === null || b === null || typeof a === "undefined" ||
- typeof b === "undefined" ||
- QUnit.objectType(a) !== QUnit.objectType(b) ) {
- return false; // don't lose time with error prone cases
- } else {
- return bindCallbacks(a, callbacks, [ b, a ]);
- }
-
- // apply transition with (1..n) arguments
- }( args[0], args[1] ) && arguments.callee.apply( this, args.splice(1, args.length - 1 )) );
- };
-
- return innerEquiv;
-}());
-
-/**
- * jsDump Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com |
- * http://flesler.blogspot.com Licensed under BSD
- * (http://www.opensource.org/licenses/bsd-license.php) Date: 5/15/2008
- *
- * @projectDescription Advanced and extensible data dumping for Javascript.
- * @version 1.0.0
- * @author Ariel Flesler
- * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html}
- */
-QUnit.jsDump = (function() {
- function quote( str ) {
- return '"' + str.toString().replace( /"/g, '\\"' ) + '"';
- }
- function literal( o ) {
- return o + "";
- }
- function join( pre, arr, post ) {
- var s = jsDump.separator(),
- base = jsDump.indent(),
- inner = jsDump.indent(1);
- if ( arr.join ) {
- arr = arr.join( "," + s + inner );
- }
- if ( !arr ) {
- return pre + post;
- }
- return [ pre, inner + arr, base + post ].join(s);
- }
- function array( arr, stack ) {
- var i = arr.length, ret = new Array(i);
- this.up();
- while ( i-- ) {
- ret[i] = this.parse( arr[i] , undefined , stack);
- }
- this.down();
- return join( "[", ret, "]" );
- }
-
- var reName = /^function (\w+)/,
- jsDump = {
- // type is used mostly internally, you can fix a (custom)type in advance
- parse: function( obj, type, stack ) {
- stack = stack || [ ];
- var inStack, res,
- parser = this.parsers[ type || this.typeOf(obj) ];
-
- type = typeof parser;
- inStack = inArray( obj, stack );
-
- if ( inStack !== -1 ) {
- return "recursion(" + (inStack - stack.length) + ")";
- }
- if ( type === "function" ) {
- stack.push( obj );
- res = parser.call( this, obj, stack );
- stack.pop();
- return res;
- }
- return ( type === "string" ) ? parser : this.parsers.error;
- },
- typeOf: function( obj ) {
- var type;
- if ( obj === null ) {
- type = "null";
- } else if ( typeof obj === "undefined" ) {
- type = "undefined";
- } else if ( QUnit.is( "regexp", obj) ) {
- type = "regexp";
- } else if ( QUnit.is( "date", obj) ) {
- type = "date";
- } else if ( QUnit.is( "function", obj) ) {
- type = "function";
- } else if ( typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined" ) {
- type = "window";
- } else if ( obj.nodeType === 9 ) {
- type = "document";
- } else if ( obj.nodeType ) {
- type = "node";
- } else if (
- // native arrays
- toString.call( obj ) === "[object Array]" ||
- // NodeList objects
- ( typeof obj.length === "number" && typeof obj.item !== "undefined" && ( obj.length ? obj.item(0) === obj[0] : ( obj.item( 0 ) === null && typeof obj[0] === "undefined" ) ) )
- ) {
- type = "array";
- } else if ( obj.constructor === Error.prototype.constructor ) {
- type = "error";
- } else {
- type = typeof obj;
- }
- return type;
- },
- separator: function() {
- return this.multiline ? this.HTML ? "
" : "\n" : this.HTML ? " " : " ";
- },
- // extra can be a number, shortcut for increasing-calling-decreasing
- indent: function( extra ) {
- if ( !this.multiline ) {
- return "";
- }
- var chr = this.indentChar;
- if ( this.HTML ) {
- chr = chr.replace( /\t/g, " " ).replace( / /g, " " );
- }
- return new Array( this._depth_ + (extra||0) ).join(chr);
- },
- up: function( a ) {
- this._depth_ += a || 1;
- },
- down: function( a ) {
- this._depth_ -= a || 1;
- },
- setParser: function( name, parser ) {
- this.parsers[name] = parser;
- },
- // The next 3 are exposed so you can use them
- quote: quote,
- literal: literal,
- join: join,
- //
- _depth_: 1,
- // This is the list of parsers, to modify them, use jsDump.setParser
- parsers: {
- window: "[Window]",
- document: "[Document]",
- error: function(error) {
- return "Error(\"" + error.message + "\")";
- },
- unknown: "[Unknown]",
- "null": "null",
- "undefined": "undefined",
- "function": function( fn ) {
- var ret = "function",
- // functions never have name in IE
- name = "name" in fn ? fn.name : (reName.exec(fn) || [])[1];
-
- if ( name ) {
- ret += " " + name;
- }
- ret += "( ";
-
- ret = [ ret, QUnit.jsDump.parse( fn, "functionArgs" ), "){" ].join( "" );
- return join( ret, QUnit.jsDump.parse(fn,"functionCode" ), "}" );
- },
- array: array,
- nodelist: array,
- "arguments": array,
- object: function( map, stack ) {
- var ret = [ ], keys, key, val, i;
- QUnit.jsDump.up();
- keys = [];
- for ( key in map ) {
- keys.push( key );
- }
- keys.sort();
- for ( i = 0; i < keys.length; i++ ) {
- key = keys[ i ];
- val = map[ key ];
- ret.push( QUnit.jsDump.parse( key, "key" ) + ": " + QUnit.jsDump.parse( val, undefined, stack ) );
- }
- QUnit.jsDump.down();
- return join( "{", ret, "}" );
- },
- node: function( node ) {
- var len, i, val,
- open = QUnit.jsDump.HTML ? "<" : "<",
- close = QUnit.jsDump.HTML ? ">" : ">",
- tag = node.nodeName.toLowerCase(),
- ret = open + tag,
- attrs = node.attributes;
-
- if ( attrs ) {
- for ( i = 0, len = attrs.length; i < len; i++ ) {
- val = attrs[i].nodeValue;
- // IE6 includes all attributes in .attributes, even ones not explicitly set.
- // Those have values like undefined, null, 0, false, "" or "inherit".
- if ( val && val !== "inherit" ) {
- ret += " " + attrs[i].nodeName + "=" + QUnit.jsDump.parse( val, "attribute" );
- }
- }
- }
- ret += close;
-
- // Show content of TextNode or CDATASection
- if ( node.nodeType === 3 || node.nodeType === 4 ) {
- ret += node.nodeValue;
- }
-
- return ret + open + "/" + tag + close;
- },
- // function calls it internally, it's the arguments part of the function
- functionArgs: function( fn ) {
- var args,
- l = fn.length;
-
- if ( !l ) {
- return "";
- }
-
- args = new Array(l);
- while ( l-- ) {
- // 97 is 'a'
- args[l] = String.fromCharCode(97+l);
- }
- return " " + args.join( ", " ) + " ";
- },
- // object calls it internally, the key part of an item in a map
- key: quote,
- // function calls it internally, it's the content of the function
- functionCode: "[code]",
- // node calls it internally, it's an html attribute value
- attribute: quote,
- string: quote,
- date: quote,
- regexp: literal,
- number: literal,
- "boolean": literal
- },
- // if true, entities are escaped ( <, >, \t, space and \n )
- HTML: false,
- // indentation unit
- indentChar: " ",
- // if true, items in a collection, are separated by a \n, else just a space.
- multiline: true
- };
-
- return jsDump;
-}());
-
-// from jquery.js
-function inArray( elem, array ) {
- if ( array.indexOf ) {
- return array.indexOf( elem );
- }
-
- for ( var i = 0, length = array.length; i < length; i++ ) {
- if ( array[ i ] === elem ) {
- return i;
- }
- }
-
- return -1;
-}
-
-/*
- * Javascript Diff Algorithm
- * By John Resig (http://ejohn.org/)
- * Modified by Chu Alan "sprite"
- *
- * Released under the MIT license.
- *
- * More Info:
- * http://ejohn.org/projects/javascript-diff-algorithm/
- *
- * Usage: QUnit.diff(expected, actual)
- *
- * QUnit.diff( "the quick brown fox jumped over", "the quick fox jumps over" ) == "the quick brown fox jumped jumps over"
- */
-QUnit.diff = (function() {
- /*jshint eqeqeq:false, eqnull:true */
- function diff( o, n ) {
- var i,
- ns = {},
- os = {};
-
- for ( i = 0; i < n.length; i++ ) {
- if ( !hasOwn.call( ns, n[i] ) ) {
- ns[ n[i] ] = {
- rows: [],
- o: null
- };
- }
- ns[ n[i] ].rows.push( i );
- }
-
- for ( i = 0; i < o.length; i++ ) {
- if ( !hasOwn.call( os, o[i] ) ) {
- os[ o[i] ] = {
- rows: [],
- n: null
- };
- }
- os[ o[i] ].rows.push( i );
- }
-
- for ( i in ns ) {
- if ( !hasOwn.call( ns, i ) ) {
- continue;
- }
- if ( ns[i].rows.length === 1 && hasOwn.call( os, i ) && os[i].rows.length === 1 ) {
- n[ ns[i].rows[0] ] = {
- text: n[ ns[i].rows[0] ],
- row: os[i].rows[0]
- };
- o[ os[i].rows[0] ] = {
- text: o[ os[i].rows[0] ],
- row: ns[i].rows[0]
- };
- }
- }
-
- for ( i = 0; i < n.length - 1; i++ ) {
- if ( n[i].text != null && n[ i + 1 ].text == null && n[i].row + 1 < o.length && o[ n[i].row + 1 ].text == null &&
- n[ i + 1 ] == o[ n[i].row + 1 ] ) {
-
- n[ i + 1 ] = {
- text: n[ i + 1 ],
- row: n[i].row + 1
- };
- o[ n[i].row + 1 ] = {
- text: o[ n[i].row + 1 ],
- row: i + 1
- };
- }
- }
-
- for ( i = n.length - 1; i > 0; i-- ) {
- if ( n[i].text != null && n[ i - 1 ].text == null && n[i].row > 0 && o[ n[i].row - 1 ].text == null &&
- n[ i - 1 ] == o[ n[i].row - 1 ]) {
-
- n[ i - 1 ] = {
- text: n[ i - 1 ],
- row: n[i].row - 1
- };
- o[ n[i].row - 1 ] = {
- text: o[ n[i].row - 1 ],
- row: i - 1
- };
- }
- }
-
- return {
- o: o,
- n: n
- };
- }
-
- return function( o, n ) {
- o = o.replace( /\s+$/, "" );
- n = n.replace( /\s+$/, "" );
-
- var i, pre,
- str = "",
- out = diff( o === "" ? [] : o.split(/\s+/), n === "" ? [] : n.split(/\s+/) ),
- oSpace = o.match(/\s+/g),
- nSpace = n.match(/\s+/g);
-
- if ( oSpace == null ) {
- oSpace = [ " " ];
- }
- else {
- oSpace.push( " " );
- }
-
- if ( nSpace == null ) {
- nSpace = [ " " ];
- }
- else {
- nSpace.push( " " );
- }
-
- if ( out.n.length === 0 ) {
- for ( i = 0; i < out.o.length; i++ ) {
- str += "" + out.o[i] + oSpace[i] + "";
- }
- }
- else {
- if ( out.n[0].text == null ) {
- for ( n = 0; n < out.o.length && out.o[n].text == null; n++ ) {
- str += "" + out.o[n] + oSpace[n] + "";
- }
- }
-
- for ( i = 0; i < out.n.length; i++ ) {
- if (out.n[i].text == null) {
- str += "" + out.n[i] + nSpace[i] + "";
- }
- else {
- // `pre` initialized at top of scope
- pre = "";
-
- for ( n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++ ) {
- pre += "" + out.o[n] + oSpace[n] + "";
- }
- str += " " + out.n[i].text + nSpace[i] + pre;
- }
- }
- }
-
- return str;
- };
-}());
-
-// for CommonJS enviroments, export everything
-if ( typeof exports !== "undefined" ) {
- extend( exports, QUnit );
-}
-
-// get at whatever the global object is, like window in browsers
-}( (function() {return this;}.call()) ));
diff --git a/test/lib/require.js b/test/lib/require.js
deleted file mode 100644
index 987f865..0000000
--- a/test/lib/require.js
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- RequireJS 2.1.5 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.
- Available via the MIT or new BSD license.
- see: http://github.com/jrburke/requirejs for details
-*/
-var requirejs,require,define;
-(function(aa){function I(b){return"[object Function]"===L.call(b)}function J(b){return"[object Array]"===L.call(b)}function y(b,c){if(b){var d;for(d=0;dthis.depCount&&!this.defined){if(I(n)){if(this.events.error)try{e=i.execCb(c,n,b,e)}catch(d){a=d}else e=i.execCb(c,n,b,e);this.map.isDefine&&((b=this.module)&&void 0!==b.exports&&b.exports!==this.exports?e=b.exports:void 0===e&&this.usingExports&&(e=this.exports));if(a)return a.requireMap=this.map,a.requireModules=[this.map.id],a.requireType="define",v(this.error=
-a)}else e=n;this.exports=e;if(this.map.isDefine&&!this.ignore&&(q[c]=e,l.onResourceLoad))l.onResourceLoad(i,this.map,this.depMaps);x(c);this.defined=!0}this.defining=!1;this.defined&&!this.defineEmitted&&(this.defineEmitted=!0,this.emit("defined",this.exports),this.defineEmitComplete=!0)}}else this.fetch()}},callPlugin:function(){var a=this.map,b=a.id,d=j(a.prefix);this.depMaps.push(d);t(d,"defined",u(this,function(e){var n,d;d=this.map.name;var g=this.map.parentMap?this.map.parentMap.name:null,h=
-i.makeRequire(a.parentMap,{enableBuildCallback:!0});if(this.map.unnormalized){if(e.normalize&&(d=e.normalize(d,function(a){return c(a,g,!0)})||""),e=j(a.prefix+"!"+d,this.map.parentMap),t(e,"defined",u(this,function(a){this.init([],function(){return a},null,{enabled:!0,ignore:!0})})),d=m(p,e.id)){this.depMaps.push(e);if(this.events.error)d.on("error",u(this,function(a){this.emit("error",a)}));d.enable()}}else n=u(this,function(a){this.init([],function(){return a},null,{enabled:!0})}),n.error=u(this,
-function(a){this.inited=!0;this.error=a;a.requireModules=[b];G(p,function(a){0===a.map.id.indexOf(b+"_unnormalized")&&x(a.map.id)});v(a)}),n.fromText=u(this,function(e,c){var d=a.name,g=j(d),C=O;c&&(e=c);C&&(O=!1);r(g);s(k.config,b)&&(k.config[d]=k.config[b]);try{l.exec(e)}catch(ca){return v(B("fromtexteval","fromText eval for "+b+" failed: "+ca,ca,[b]))}C&&(O=!0);this.depMaps.push(g);i.completeLoad(d);h([d],n)}),e.load(a.name,h,n,k)}));i.enable(d,this);this.pluginMaps[d.id]=d},enable:function(){V[this.map.id]=
-this;this.enabling=this.enabled=!0;y(this.depMaps,u(this,function(a,b){var c,e;if("string"===typeof a){a=j(a,this.map.isDefine?this.map:this.map.parentMap,!1,!this.skipMap);this.depMaps[b]=a;if(c=m(N,a.id)){this.depExports[b]=c(this);return}this.depCount+=1;t(a,"defined",u(this,function(a){this.defineDep(b,a);this.check()}));this.errback&&t(a,"error",this.errback)}c=a.id;e=p[c];!s(N,c)&&(e&&!e.enabled)&&i.enable(a,this)}));G(this.pluginMaps,u(this,function(a){var b=m(p,a.id);b&&!b.enabled&&i.enable(a,
-this)}));this.enabling=!1;this.check()},on:function(a,b){var c=this.events[a];c||(c=this.events[a]=[]);c.push(b)},emit:function(a,b){y(this.events[a],function(a){a(b)});"error"===a&&delete this.events[a]}};i={config:k,contextName:b,registry:p,defined:q,urlFetched:U,defQueue:H,Module:Z,makeModuleMap:j,nextTick:l.nextTick,onError:v,configure:function(a){a.baseUrl&&"/"!==a.baseUrl.charAt(a.baseUrl.length-1)&&(a.baseUrl+="/");var b=k.pkgs,c=k.shim,e={paths:!0,config:!0,map:!0};G(a,function(a,b){e[b]?
-"map"===b?(k.map||(k.map={}),R(k[b],a,!0,!0)):R(k[b],a,!0):k[b]=a});a.shim&&(G(a.shim,function(a,b){J(a)&&(a={deps:a});if((a.exports||a.init)&&!a.exportsFn)a.exportsFn=i.makeShimExports(a);c[b]=a}),k.shim=c);a.packages&&(y(a.packages,function(a){a="string"===typeof a?{name:a}:a;b[a.name]={name:a.name,location:a.location||a.name,main:(a.main||"main").replace(ja,"").replace(ea,"")}}),k.pkgs=b);G(p,function(a,b){!a.inited&&!a.map.unnormalized&&(a.map=j(b))});if(a.deps||a.callback)i.require(a.deps||[],
-a.callback)},makeShimExports:function(a){return function(){var b;a.init&&(b=a.init.apply(aa,arguments));return b||a.exports&&ba(a.exports)}},makeRequire:function(a,f){function d(e,c,h){var g,k;f.enableBuildCallback&&(c&&I(c))&&(c.__requireJsBuild=!0);if("string"===typeof e){if(I(c))return v(B("requireargs","Invalid require call"),h);if(a&&s(N,e))return N[e](p[a.id]);if(l.get)return l.get(i,e,a,d);g=j(e,a,!1,!0);g=g.id;return!s(q,g)?v(B("notloaded",'Module name "'+g+'" has not been loaded yet for context: '+
-b+(a?"":". Use require([])"))):q[g]}L();i.nextTick(function(){L();k=r(j(null,a));k.skipMap=f.skipMap;k.init(e,c,h,{enabled:!0});D()});return d}f=f||{};R(d,{isBrowser:A,toUrl:function(b){var d,f=b.lastIndexOf("."),g=b.split("/")[0];if(-1!==f&&(!("."===g||".."===g)||1h.attachEvent.toString().indexOf("[native code"))&&!Y?(O=!0,h.attachEvent("onreadystatechange",b.onScriptLoad)):(h.addEventListener("load",b.onScriptLoad,!1),h.addEventListener("error",b.onScriptError,!1)),h.src=d,K=h,D?x.insertBefore(h,D):x.appendChild(h),K=null,h;if(da)try{importScripts(d),b.completeLoad(c)}catch(j){b.onError(B("importscripts","importScripts failed for "+c+" at "+d,j,[c]))}};A&&M(document.getElementsByTagName("script"),function(b){x||(x=
-b.parentNode);if(t=b.getAttribute("data-main"))return r.baseUrl||(E=t.split("/"),Q=E.pop(),fa=E.length?E.join("/")+"/":"./",r.baseUrl=fa,t=Q),t=t.replace(ea,""),r.deps=r.deps?r.deps.concat(t):[t],!0});define=function(b,c,d){var l,h;"string"!==typeof b&&(d=c,c=b,b=null);J(c)||(d=c,c=[]);!c.length&&I(d)&&d.length&&(d.toString().replace(la,"").replace(ma,function(b,d){c.push(d)}),c=(1===d.length?["require"]:["require","exports","module"]).concat(c));if(O){if(!(l=K))P&&"interactive"===P.readyState||M(document.getElementsByTagName("script"),
-function(b){if("interactive"===b.readyState)return P=b}),l=P;l&&(b||(b=l.getAttribute("data-requiremodule")),h=F[l.getAttribute("data-requirecontext")])}(h?h.defQueue:T).push([b,c,d])};define.amd={jQuery:!0};l.exec=function(b){return eval(b)};l(r)}})(this);
diff --git a/test/lib/resemble.js b/test/lib/resemble.js
new file mode 100644
index 0000000..1cb8c29
--- /dev/null
+++ b/test/lib/resemble.js
@@ -0,0 +1,535 @@
+/*
+Author: James Cryer
+Company: Huddle
+Last updated date: 21 Feb 2013
+URL: https://github.com/Huddle/Resemble.js
+*/
+
+(function(_this){
+ 'use strict';
+
+ _this['resemble'] = function( fileData ){
+
+ var data = {};
+ var images = [];
+ var updateCallbackArray = [];
+
+ var tolerance = { // between 0 and 255
+ red: 16,
+ green: 16,
+ blue: 16,
+ minBrightness: 16,
+ maxBrightness: 240
+ };
+
+ var ignoreAntialiasing = false;
+ var ignoreColors = false;
+
+ function triggerDataUpdate(){
+ var len = updateCallbackArray.length;
+ var i;
+ for(i=0;i tolerance.maxBrightness;
+ }
+
+ function getHue(r,g,b){
+
+ r = r / 255;
+ g = g / 255;
+ b = b / 255;
+ var max = Math.max(r, g, b), min = Math.min(r, g, b);
+ var h;
+ var d;
+
+ if (max == min){
+ h = 0; // achromatic
+ } else{
+ d = max - min;
+ switch(max){
+ case r: h = (g - b) / d + (g < b ? 6 : 0); break;
+ case g: h = (b - r) / d + 2; break;
+ case b: h = (r - g) / d + 4; break;
+ }
+ h /= 6;
+ }
+
+ return h;
+ }
+
+ function isAntialiased(sourcePix, data, cacheSet, verticalPos, horizontalPos, width){
+ var offset;
+ var targetPix;
+ var distance = 1;
+ var i;
+ var j;
+ var hasHighContrastSibling = 0;
+ var hasSiblingWithDifferentHue = 0;
+ var hasEquivilantSibling = 0;
+
+ addHueInfo(sourcePix);
+
+ for (i = distance*-1; i <= distance; i++){
+ for (j = distance*-1; j <= distance; j++){
+
+ if(i===0 && j===0){
+ // ignore source pixel
+ } else {
+
+ offset = ((verticalPos+j)*width + (horizontalPos+i)) * 4;
+ targetPix = getPixelInfo(data, offset, cacheSet);
+
+ if(targetPix === null){
+ continue;
+ }
+
+ addBrightnessInfo(targetPix);
+ addHueInfo(targetPix);
+
+ if( isContrasting(sourcePix, targetPix) ){
+ hasHighContrastSibling++;
+ }
+
+ if( isRGBSame(sourcePix,targetPix) ){
+ hasEquivilantSibling++;
+ }
+
+ if( Math.abs(targetPix.h - sourcePix.h) > 0.3 ){
+ hasSiblingWithDifferentHue++;
+ }
+
+ if( hasSiblingWithDifferentHue > 1 || hasHighContrastSibling > 1){
+ return true;
+ }
+ }
+ }
+ }
+
+ if(hasEquivilantSibling < 2){
+ return true;
+ }
+
+ return false;
+ }
+
+ function errorPixel(px, offset){
+ px[offset] = 255; //r
+ px[offset + 1] = 0; //g
+ px[offset + 2] = 255; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyPixel(px, offset, data){
+ px[offset] = data.r; //r
+ px[offset + 1] = data.g; //g
+ px[offset + 2] = data.b; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyGrayScalePixel(px, offset, data){
+ px[offset] = data.brightness; //r
+ px[offset + 1] = data.brightness; //g
+ px[offset + 2] = data.brightness; //b
+ px[offset + 3] = 255; //a
+ }
+
+
+ function getPixelInfo(data, offset, cacheSet){
+ var r;
+ var g;
+ var b;
+ var d;
+
+ if(typeof data[offset] !== 'undefined'){
+ r = data[offset];
+ g = data[offset+1];
+ b = data[offset+2];
+ d = {
+ r: r,
+ g: g,
+ b: b
+ };
+
+ return d;
+ } else {
+ return null;
+ }
+ }
+
+ function addBrightnessInfo(data){
+ data.brightness = getBrightness(data.r,data.g,data.b); // 'corrected' lightness
+ }
+
+ function addHueInfo(data){
+ data.h = getHue(data.r,data.g,data.b);
+ }
+
+ function analyseImages(img1, img2, width, height){
+
+ var hiddenCanvas = document.createElement('canvas');
+
+ var data1 = img1.data;
+ var data2 = img2.data;
+
+ hiddenCanvas.width = width;
+ hiddenCanvas.height = height;
+
+ var context = hiddenCanvas.getContext('2d');
+ var imgd = context.createImageData(width,height);
+ var targetPix = imgd.data;
+
+ var mismatchCount = 0;
+
+ var time = Date.now();
+
+ var skip;
+
+ if( (width > 1200 || height > 1200) && ignoreAntialiasing){
+ skip = 6;
+ }
+
+ loop(height, width, function(verticalPos, horizontalPos){
+
+ if(skip){ // only skip if the image isn't small
+ if(verticalPos % skip === 0 || horizontalPos % skip === 0){
+ return;
+ }
+ }
+
+ var offset = (verticalPos*width + horizontalPos) * 4;
+ var pixel1 = getPixelInfo(data1, offset, 1);
+ var pixel2 = getPixelInfo(data2, offset, 2);
+
+ if(pixel1 === null || pixel2 === null){
+ return;
+ }
+
+ if (ignoreColors){
+
+ addBrightnessInfo(pixel1);
+ addBrightnessInfo(pixel2);
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ return;
+ }
+
+ if( isRGBSimilar(pixel1, pixel2) ){
+ copyPixel(targetPix, offset, pixel2);
+
+ } else if( ignoreAntialiasing && (
+ addBrightnessInfo(pixel1), // jit pixel info augmentation looks a little weird, sorry.
+ addBrightnessInfo(pixel2),
+ isAntialiased(pixel1, data1, 1, verticalPos, horizontalPos, width) ||
+ isAntialiased(pixel2, data2, 2, verticalPos, horizontalPos, width)
+ )){
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+
+ });
+
+ data.misMatchPercentage = (mismatchCount / (height*width) * 100).toFixed(2);
+ data.analysisTime = Date.now() - time;
+
+ data.getImageDataUrl = function(text){
+ var barHeight = 0;
+
+ if(text){
+ barHeight = addLabel(text,context,hiddenCanvas);
+ }
+
+ context.putImageData(imgd, 0, barHeight);
+
+ return hiddenCanvas.toDataURL("image/png");
+ };
+ }
+
+ function addLabel(text, context, hiddenCanvas){
+ var textPadding = 2;
+
+ context.font = '12px sans-serif';
+
+ var textWidth = context.measureText(text).width + textPadding*2;
+ var barHeight = 22;
+
+ if(textWidth > hiddenCanvas.width){
+ hiddenCanvas.width = textWidth;
+ }
+
+ hiddenCanvas.height += barHeight;
+
+ context.fillStyle = "#666";
+ context.fillRect(0,0,hiddenCanvas.width,barHeight -4);
+ context.fillStyle = "#fff";
+ context.fillRect(0,barHeight -4,hiddenCanvas.width, 4);
+
+ context.fillStyle = "#fff";
+ context.textBaseline = "top";
+ context.font = '12px sans-serif';
+ context.fillText(text, textPadding, 1);
+
+ return barHeight;
+ }
+
+ function normalise(img, w, h){
+ var c;
+ var context;
+
+ if(img.height < h || img.width < w){
+ c = document.createElement('canvas');
+ c.width = w;
+ c.height = h;
+ context = c.getContext('2d');
+ context.putImageData(img, 0, 0);
+ return context.getImageData(0, 0, w, h);
+ }
+
+ return img;
+ }
+
+ function compare(one, two){
+
+ function onceWeHaveBoth(){
+ var width;
+ var height;
+ if(images.length === 2){
+ width = images[0].width > images[1].width ? images[0].width : images[1].width;
+ height = images[0].height > images[1].height ? images[0].height : images[1].height;
+
+ if( (images[0].width === images[1].width) && (images[0].height === images[1].height) ){
+ data.isSameDimensions = true;
+ } else {
+ data.isSameDimensions = false;
+ }
+
+ analyseImages( normalise(images[0],width, height), normalise(images[1],width, height), width, height);
+
+ triggerDataUpdate();
+ }
+ }
+
+ images = [];
+ loadImageData(one, onceWeHaveBoth);
+ loadImageData(two, onceWeHaveBoth);
+ }
+
+ function getCompareApi(param){
+
+ var secondFileData,
+ hasMethod = typeof param === 'function';
+
+ if( !hasMethod ){
+ // assume it's file data
+ secondFileData = param;
+ }
+
+ var self = {
+ ignoreNothing: function(){
+
+ tolerance.red = 16;
+ tolerance.green = 16;
+ tolerance.blue = 16;
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreAntialiasing: function(){
+
+ tolerance.red = 32;
+ tolerance.green = 32;
+ tolerance.blue = 32;
+ tolerance.minBrightness = 64;
+ tolerance.maxBrightness = 96;
+
+ ignoreAntialiasing = true;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreColors: function(){
+
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = true;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ onComplete: function( callback ){
+
+ updateCallbackArray.push(callback);
+
+ var wrapper = function(){
+ compare(fileData, secondFileData);
+ };
+
+ wrapper();
+
+ return getCompareApi(wrapper);
+ }
+ };
+
+ return self;
+ }
+
+ return {
+ onComplete: function( callback ){
+ updateCallbackArray.push(callback);
+ loadImageData(fileData, function(imageData, width, height){
+ parseImage(imageData.data, width, height);
+ });
+ },
+ compareTo: function(secondFileData){
+ return getCompareApi(secondFileData);
+ }
+ };
+
+ };
+}(this));
\ No newline at end of file
diff --git a/test/testsuite.js b/test/testsuite.js
deleted file mode 100644
index b486acb..0000000
--- a/test/testsuite.js
+++ /dev/null
@@ -1,36 +0,0 @@
-requirejs.config({
- baseUrl: '/test/unit/'
-});
-
-define(function(require) {
- var testModules = [
- 'Pixi',
- 'Point',
- 'Rectangle',
- 'DisplayObject',
- 'DisplayObjectContainer',
- 'Sprite',
- 'MovieClip',
- 'InteractionManager',
- 'Stage',
- 'utils/Utils',
- 'utils/EventTarget',
- 'utils/Matrix',
- 'utils/Detector',
- 'renderers/WebGLShaders',
- 'renderers/WebGLRenderer',
- 'renderers/WebGLBatch',
- 'renderers/CanvasRenderer',
- 'extras/Strip',
- 'extras/Rope',
- 'textures/BaseTexture',
- 'textures/Texture',
- 'loaders/SpriteSheetLoader',
- 'loaders/AssetLoader'
- ];
-
- // Resolve all testModules and then start the Test Runner.
- require(testModules, function() {
- QUnit.start();
- });
-});
\ No newline at end of file
diff --git a/test/textures/SpriteSheet-Aliens.png b/test/textures/SpriteSheet-Aliens.png
new file mode 100644
index 0000000..210acb1
--- /dev/null
+++ b/test/textures/SpriteSheet-Aliens.png
Binary files differ
diff --git a/test/textures/SpriteSheet-Explosion.png b/test/textures/SpriteSheet-Explosion.png
new file mode 100755
index 0000000..79e1a69
--- /dev/null
+++ b/test/textures/SpriteSheet-Explosion.png
Binary files differ
diff --git a/test/textures/bunny.png b/test/textures/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/textures/bunny.png
Binary files differ
diff --git a/test/unit/DisplayObject.js b/test/unit/DisplayObject.js
deleted file mode 100644
index 5e7e72f..0000000
--- a/test/unit/DisplayObject.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObject');
-});
diff --git a/test/unit/DisplayObjectContainer.js b/test/unit/DisplayObjectContainer.js
deleted file mode 100644
index b323959..0000000
--- a/test/unit/DisplayObjectContainer.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObjectContainer');
-});
diff --git a/test/unit/InteractionManager.js b/test/unit/InteractionManager.js
deleted file mode 100644
index e751f52..0000000
--- a/test/unit/InteractionManager.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('InteractionManager');
-});
diff --git a/.gitignore b/.gitignore
index 12e1b62..0b88317 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
node_modules
.DS_Store
-.project
\ No newline at end of file
+.project
+*.log
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..63e4d7c
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,8 @@
+language: node_js
+node_js:
+ - 0.10
+
+before_script:
+ - npm install -g grunt-cli
+ - export DISPLAY=:99.0
+ - sh -e /etc/init.d/xvfb start
diff --git a/Gruntfile.js b/Gruntfile.js
index b083b49..103938c 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -1,10 +1,12 @@
+'use strict';
+
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-connect');
- grunt.loadNpmTasks('grunt-contrib-qunit');
grunt.loadNpmTasks('grunt-contrib-yuidoc');
+ grunt.loadTasks('tasks');
var root = 'src/pixi/',
debug = 'bin/pixi.dev.js',
@@ -79,7 +81,7 @@
},
files: {
srcBlob: '<%= dirs.src %>/**/*.js',
- testBlob: '<%= dirs.test %>/unit/**/*.js',
+ testBlob: '<%= dirs.test %>/{functional,lib/pixi,unit}/**/*.js',
build: '<%= dirs.build %>/pixi.dev.js',
buildMin: '<%= dirs.build %>/pixi.js'
},
@@ -94,7 +96,12 @@
},
jshint: {
beforeconcat: srcFiles,
- test: ['<%= files.testBlob %>'],
+ test: {
+ src: ['<%= files.testBlob %>'],
+ options: {
+ expr: true
+ }
+ },
options: {
asi: true,
smarttabs: true
@@ -128,12 +135,6 @@
]
},
connect: {
- qunit: {
- options: {
- port: grunt.option('port-test') || 9002,
- base: './'
- }
- },
test: {
options: {
port: grunt.option('port-test') || 9002,
@@ -142,13 +143,6 @@
}
}
},
- qunit: {
- all: {
- options: {
- urls: ['http://localhost:' + (grunt.option('port-test') || 9002) + '/test/index.html']
- }
- }
- },
yuidoc: {
compile: {
name: '<%= pkg.name %>',
@@ -161,6 +155,13 @@
outdir: '<%= dirs.docs %>'
}
}
+ },
+ karma: {
+ unit: {
+ configFile: 'test/karma.conf.js',
+ // browsers: ['Chrome'],
+ singleRun: true
+ }
}
});
@@ -182,9 +183,10 @@
}
)
- grunt.registerTask('default', ['concat', 'uglify', 'distribute']);
grunt.registerTask('build', ['concat', 'uglify', 'distribute']);
- grunt.registerTask('test', ['build', 'connect:qunit', 'qunit']);
+ grunt.registerTask('test', ['concat', 'jshint:test', 'karma']);
grunt.registerTask('docs', ['yuidoc']);
-
-}
\ No newline at end of file
+ grunt.registerTask('default', ['test', 'uglify', 'distribute']);
+ // Travis CI task.
+ grunt.registerTask('travis', ['test']);
+}
diff --git a/README.md b/README.md
index c62ef86..690cfe4 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,8 @@

+[](http://travis-ci.org/drkibitz/pixi.js)
+
#### JavaScript 2D Renderer ####
The aim of this project is to provide a fast lightweight 2D library that works
diff --git a/package.json b/package.json
index b373240..1246a68 100644
--- a/package.json
+++ b/package.json
@@ -18,14 +18,21 @@
"main": "bin/pixi.js",
+ "scripts": {
+ "test": "grunt travis --verbose"
+ },
+
"dependencies": {},
"devDependencies": {
"grunt": "~0.4.x",
- "grunt-contrib-jshint": "0.3.x",
+ "grunt-contrib-jshint": "0.6.x",
"grunt-contrib-uglify": "0.2.x",
- "grunt-contrib-connect": "0.2.x",
- "grunt-contrib-qunit": "0.2.x",
+ "grunt-contrib-connect": "0.3.x",
"grunt-contrib-yuidoc": "0.4.x",
- "grunt-contrib-concat": "0.1.x"
+ "grunt-contrib-concat": "0.3.x",
+ "chai": "~1.7.0",
+ "karma": "0.11.0",
+ "karma-firefox-launcher": "0.1.0",
+ "karma-mocha": "0.1.0"
}
}
diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js
index a7c520e..ee82bbd 100644
--- a/src/pixi/InteractionManager.js
+++ b/src/pixi/InteractionManager.js
@@ -62,7 +62,6 @@
this.onTouchEnd = this.onTouchEnd.bind(this);
this.onTouchMove = this.onTouchMove.bind(this);
-
this.last = 0;
}
diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js
index 1a95d20..eef1059 100644
--- a/src/pixi/core/Ellipse.js
+++ b/src/pixi/core/Ellipse.js
@@ -78,7 +78,7 @@
return (normx + normy < 0.25);
}
-PIXI.Ellipse.getBounds = function()
+PIXI.Ellipse.prototype.getBounds = function()
{
return new PIXI.Rectangle(this.x, this.y, this.width, this.height);
}
diff --git a/tasks/karma.js b/tasks/karma.js
new file mode 100644
index 0000000..c340485
--- /dev/null
+++ b/tasks/karma.js
@@ -0,0 +1,27 @@
+'use strict';
+
+var path = require('path');
+var server = require('karma').server;
+
+module.exports = function (grunt) {
+ grunt.registerMultiTask('karma', 'run karma.', function() {
+ var done = this.async();
+ var options = this.options({
+ background: false
+ });
+ var data = this.data;
+
+ //merge options onto data, with data taking precedence
+ data = grunt.util._.merge(options, data);
+ data.configFile = path.resolve(data.configFile);
+ if (data.configFile) {
+ data.configFile = grunt.template.process(data.configFile);
+ }
+
+ server.start(
+ data,
+ function(code) {
+ done(!code);
+ });
+ });
+};
diff --git a/test/functional/example-1-basics/bunny.png b/test/functional/example-1-basics/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/functional/example-1-basics/bunny.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-30.png b/test/functional/example-1-basics/frame-30.png
new file mode 100644
index 0000000..96e3409
--- /dev/null
+++ b/test/functional/example-1-basics/frame-30.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-60.png b/test/functional/example-1-basics/frame-60.png
new file mode 100644
index 0000000..af3f4ce
--- /dev/null
+++ b/test/functional/example-1-basics/frame-60.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-90.png b/test/functional/example-1-basics/frame-90.png
new file mode 100644
index 0000000..099b823
--- /dev/null
+++ b/test/functional/example-1-basics/frame-90.png
Binary files differ
diff --git a/test/functional/example-1-basics/index.js b/test/functional/example-1-basics/index.js
new file mode 100644
index 0000000..7ae7a98
--- /dev/null
+++ b/test/functional/example-1-basics/index.js
@@ -0,0 +1,133 @@
+describe('Example 1 - Basics', function () {
+ 'use strict';
+
+ var baseUri = '/base/test/functional/example-1-basics';
+ var expect = chai.expect;
+ var currentFrame = 0;
+ var frameEvents = {};
+ var stage;
+ var renderer;
+ var bunny;
+
+ function onFrame(frame, callback) {
+ frameEvents[frame] = callback;
+ }
+
+ function animate() {
+ currentFrame += 1;
+
+ requestAnimFrame( animate );
+
+ // just for fun, lets rotate mr rabbit a little
+ bunny.rotation += 0.1;
+
+ // render the stage
+ renderer.render(stage);
+
+ if (frameEvents[currentFrame])
+ frameEvents[currentFrame](currentFrame);
+ }
+
+ function initScene() {
+ // create an new instance of a pixi stage
+ stage = new PIXI.Stage(0x66FF99);
+
+ // create a renderer instance
+ renderer = PIXI.autoDetectRenderer(400, 300);
+ console.log('Is PIXI.WebGLRenderer: ' + (renderer instanceof PIXI.WebGLRenderer));
+
+ // add the renderer view element to the DOM
+ document.body.appendChild(renderer.view);
+
+ requestAnimFrame( animate );
+
+ // create a texture from an image path
+ var texture = PIXI.Texture.fromImage(baseUri + "/bunny.png");
+ // create a new Sprite using the texture
+ bunny = new PIXI.Sprite(texture);
+
+ // center the sprites anchor point
+ bunny.anchor.x = 0.5;
+ bunny.anchor.y = 0.5;
+
+ // move the sprite t the center of the screen
+ bunny.position.x = 200;
+ bunny.position.y = 150;
+
+ stage.addChild(bunny);
+ }
+
+ it('assets loaded', function (done) {
+ var loader = new PIXI.AssetLoader([
+ baseUri + '/bunny.png',
+ baseUri + '/frame-30.png',
+ baseUri + '/frame-60.png',
+ baseUri + '/frame-90.png'
+ ]);
+ // loader.on('onProgress', function (event) {
+ // console.log(event.content);
+ // });
+ loader.on('onComplete', function (event) {
+ done();
+ initScene();
+ });
+ loader.load();
+ });
+
+ it('frame 30 should match', function (done) {
+ this.timeout(700);
+ onFrame(30, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-30.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 60 should match', function (done) {
+ this.timeout(1200);
+ onFrame(60, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-60.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 90 should match', function (done) {
+ this.timeout(1700);
+ onFrame(90, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-90.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ // it('capture something', function (done) {
+ // this.timeout(2000000);
+ // onFrame(30, function () {
+ // var img = new Image();
+ // img.src = renderer.view.toDataURL('image/png');
+ // document.body.appendChild(img);
+ // });
+ // });
+});
diff --git a/test/index.html b/test/index.html
deleted file mode 100644
index 9cbcac5..0000000
--- a/test/index.html
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
- Pixi.js Test Suite
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/test/karma.conf.js b/test/karma.conf.js
new file mode 100644
index 0000000..c66a696
--- /dev/null
+++ b/test/karma.conf.js
@@ -0,0 +1,82 @@
+module.exports = function(config) {
+ config.set({
+
+ // base path, that will be used to resolve files and exclude
+ basePath : '../',
+
+ frameworks : ['mocha'],
+
+ // list of files / patterns to load in the browser
+ files : [
+ 'node_modules/chai/chai.js',
+ 'bin/pixi.dev.js',
+ 'test/lib/**/*.js',
+ 'test/unit/**/*.js',
+ // 'test/functional/**/*.js',
+ {pattern: 'test/**/*.png', watched: false, included: false, served: true}
+ ],
+
+ // list of files to exclude
+ exclude : [],
+
+ // use dolts reporter, as travis terminal does not support escaping sequences
+ // possible values: 'dots', 'progress', 'junit', 'teamcity'
+ // CLI --reporters progress
+ reporters : ['progress'],
+
+ // web server port
+ // CLI --port 9876
+ port : 9876,
+
+ // cli runner port
+ // CLI --runner-port 9100
+ runnerPort : 9100,
+
+ // enable / disable colors in the output (reporters and logs)
+ // CLI --colors --no-colors
+ colors : true,
+
+ // level of logging
+ // possible values: karma.LOG_DISABLE || karma.LOG_ERROR || karma.LOG_WARN || karma.LOG_INFO || karma.LOG_DEBUG
+ // CLI --log-level debug
+ logLevel : config.LOG_DEBUG,
+
+ // enable / disable watching file and executing tests whenever any file changes
+ // CLI --auto-watch --no-auto-watch
+ autoWatch : false,
+
+ // Start these browsers, currently available:
+ // - Chrome
+ // - ChromeCanary
+ // - Firefox
+ // - Opera
+ // - Safari (only Mac)
+ // - PhantomJS
+ // - IE (only Windows)
+ // CLI --browsers Chrome,Firefox,Safari
+ browsers : ['Firefox'],
+
+ // If browser does not capture in given timeout [ms], kill it
+ // CLI --capture-timeout 5000
+ captureTimeout : 5000,
+
+ // Auto run tests on start (when browsers are captured) and exit
+ // CLI --single-run --no-single-run
+ singleRun : true,
+
+ // report which specs are slower than 500ms
+ // CLI --report-slower-than 500
+ reportSlowerThan : 1000,
+
+ preprocessors : {
+ // '**/client/js/*.js': 'coverage'
+ },
+
+ plugins : [
+ 'karma-mocha',
+ // 'karma-chrome-launcher',
+ 'karma-firefox-launcher',
+ // 'karma-phantomjs-launcher'
+ ]
+ });
+};
diff --git a/test/lib/pixi/core/Matrix.js b/test/lib/pixi/core/Matrix.js
new file mode 100644
index 0000000..d26386b
--- /dev/null
+++ b/test/lib/pixi/core/Matrix.js
@@ -0,0 +1,40 @@
+
+function pixi_core_Matrix_confirmNewMat3(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(1);
+ expect(matrix[5]).to.equal(0);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(1);
+}
+
+function pixi_core_Matrix_confirmNewMat4(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[0]).to.equal(1);
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(0);
+ expect(matrix[5]).to.equal(1);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(0);
+ expect(matrix[9]).to.equal(0);
+ expect(matrix[10]).to.equal(1);
+ expect(matrix[11]).to.equal(0);
+ expect(matrix[12]).to.equal(0);
+ expect(matrix[13]).to.equal(0);
+ expect(matrix[14]).to.equal(0);
+ expect(matrix[15]).to.equal(1);
+}
diff --git a/test/lib/pixi/core/Point.js b/test/lib/pixi/core/Point.js
new file mode 100644
index 0000000..e5df07b
--- /dev/null
+++ b/test/lib/pixi/core/Point.js
@@ -0,0 +1,10 @@
+
+function pixi_core_Point_confirm(obj, x, y) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Point);
+ expect(obj).to.respondTo('clone');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+}
diff --git a/test/lib/pixi/core/Rectangle.js b/test/lib/pixi/core/Rectangle.js
new file mode 100644
index 0000000..23f0d12
--- /dev/null
+++ b/test/lib/pixi/core/Rectangle.js
@@ -0,0 +1,13 @@
+
+function pixi_core_Rectangle_confirm(obj, x, y, width, height) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Rectangle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+ expect(obj).to.have.property('width', width);
+ expect(obj).to.have.property('height', height);
+}
diff --git a/test/lib/pixi/display/DisplayObject.js b/test/lib/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..1388a7f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObject.js
@@ -0,0 +1,43 @@
+
+function pixi_display_DisplayObject_confirmNew(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObject);
+ expect(obj).to.respondTo('setInteractive');
+ expect(obj).to.respondTo('addFilter');
+ expect(obj).to.respondTo('removeFilter');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.property('last', obj);
+ expect(obj).to.have.property('first', obj);
+
+ expect(obj).to.contain.property('position');
+ pixi_core_Point_confirm(obj.position, 0, 0);
+ expect(obj).to.contain.property('scale');
+ pixi_core_Point_confirm(obj.scale, 1, 1);
+ expect(obj).to.contain.property('pivot');
+ pixi_core_Point_confirm(obj.pivot, 0, 0);
+
+ expect(obj).to.have.property('rotation', 0);
+ expect(obj).to.have.property('alpha', 1);
+ expect(obj).to.have.property('visible', true);
+ expect(obj).to.have.property('buttonMode', false);
+ expect(obj).to.have.property('parent', null);
+ expect(obj).to.have.property('worldAlpha', 1);
+
+ expect(obj).to.have.property('hitArea');
+ expect(obj).to.have.property('interactive'); // TODO: Have a better default value
+ expect('mask' in obj).to.be.true; // TODO: Have a better default value
+ expect(obj.mask).to.be.undefined;
+
+ expect(obj).to.have.property('renderable');
+ expect(obj).to.have.property('stage');
+
+ expect(obj).to.have.deep.property('worldTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ expect(obj).to.have.deep.property('localTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.localTransform);
+
+ expect(obj).to.have.deep.property('color.length', 0);
+ expect(obj).to.have.property('dynamic', true);
+}
diff --git a/test/lib/pixi/display/DisplayObjectContainer.js b/test/lib/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..085c59f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,16 @@
+
+function pixi_display_DisplayObjectContainer_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObject_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObjectContainer);
+ expect(obj).to.respondTo('addChild');
+ expect(obj).to.respondTo('addChildAt');
+ expect(obj).to.respondTo('swapChildren');
+ expect(obj).to.respondTo('getChildAt');
+ expect(obj).to.respondTo('removeChild');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('children.length', 0);
+}
diff --git a/test/lib/pixi/display/Sprite.js b/test/lib/pixi/display/Sprite.js
new file mode 100644
index 0000000..cc7a2d6
--- /dev/null
+++ b/test/lib/pixi/display/Sprite.js
@@ -0,0 +1,28 @@
+
+function pixi_display_Sprite_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Sprite);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', true);
+ expect(obj).to.have.property('stage', null);
+
+ expect(obj).to.have.property('anchor');
+ pixi_core_Point_confirm(obj.anchor, 0, 0);
+
+ expect(obj).to.have.property('blendMode', PIXI.blendModes.NORMAL);
+ expect(obj).to.have.property('width', 1); // TODO: is 1 expected
+ expect(obj).to.have.property('height', 1); // TODO: is 1 expected
+
+ // FIXME: Just make this a boolean that is always there
+ expect(!!obj.updateFrame).to.equal(obj.texture.baseTexture.hasLoaded);
+
+ expect(obj).to.have.property('texture');
+ pixi_textures_Texture_confirmNew(obj.texture, done);
+}
diff --git a/test/lib/pixi/extras/Strip.js b/test/lib/pixi/extras/Strip.js
new file mode 100644
index 0000000..8927a8a
--- /dev/null
+++ b/test/lib/pixi/extras/Strip.js
@@ -0,0 +1,12 @@
+
+function pixi_extras_Strip_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Strip);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ // TODO: Test properties
+}
diff --git a/test/lib/pixi/textures/Texture.js b/test/lib/pixi/textures/Texture.js
new file mode 100644
index 0000000..d5867b6
--- /dev/null
+++ b/test/lib/pixi/textures/Texture.js
@@ -0,0 +1,31 @@
+
+function pixi_textures_Texture_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ function confirmFrameDone() {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, obj.baseTexture.width, obj.baseTexture.height);
+
+ expect(obj).to.have.property('width', obj.baseTexture.width);
+ expect(obj).to.have.property('height', obj.baseTexture.height);
+ done();
+ }
+
+ expect(obj).to.be.an.instanceof(PIXI.Texture);
+ pixi_utils_EventTarget_like(obj);
+
+ expect(obj).to.have.property('baseTexture')
+ .and.to.be.an.instanceof(PIXI.BaseTexture);
+
+ expect(obj).to.have.property('scope', obj);
+
+ expect(obj).to.have.property('trim');
+ pixi_core_Point_confirm(obj.trim, 0, 0);
+
+ expect(obj).to.have.property('frame');
+ if (obj.baseTexture.hasLoaded) {
+ confirmFrameDone();
+ } else {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, 1, 1);
+ obj.addEventListener('update', confirmFrameDone);
+ }
+}
diff --git a/test/lib/pixi/utils/EventTarget.js b/test/lib/pixi/utils/EventTarget.js
new file mode 100644
index 0000000..7b1dcfa
--- /dev/null
+++ b/test/lib/pixi/utils/EventTarget.js
@@ -0,0 +1,8 @@
+
+function pixi_utils_EventTarget_like(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.respondTo('addEventListener');
+ expect(obj).to.respondTo('dispatchEvent');
+ expect(obj).to.respondTo('removeEventListener');
+}
diff --git a/test/lib/qunit-1.11.0.css b/test/lib/qunit-1.11.0.css
deleted file mode 100644
index d7fc0c8..0000000
--- a/test/lib/qunit-1.11.0.css
+++ /dev/null
@@ -1,244 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-/** Font Family and Sizes */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
- font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
-}
-
-#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
-#qunit-tests { font-size: smaller; }
-
-
-/** Resets */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter {
- margin: 0;
- padding: 0;
-}
-
-
-/** Header */
-
-#qunit-header {
- padding: 0.5em 0 0.5em 1em;
-
- color: #8699a4;
- background-color: #0d3349;
-
- font-size: 1.5em;
- line-height: 1em;
- font-weight: normal;
-
- border-radius: 5px 5px 0 0;
- -moz-border-radius: 5px 5px 0 0;
- -webkit-border-top-right-radius: 5px;
- -webkit-border-top-left-radius: 5px;
-}
-
-#qunit-header a {
- text-decoration: none;
- color: #c2ccd1;
-}
-
-#qunit-header a:hover,
-#qunit-header a:focus {
- color: #fff;
-}
-
-#qunit-testrunner-toolbar label {
- display: inline-block;
- padding: 0 .5em 0 .1em;
-}
-
-#qunit-banner {
- height: 5px;
-}
-
-#qunit-testrunner-toolbar {
- padding: 0.5em 0 0.5em 2em;
- color: #5E740B;
- background-color: #eee;
- overflow: hidden;
-}
-
-#qunit-userAgent {
- padding: 0.5em 0 0.5em 2.5em;
- background-color: #2b81af;
- color: #fff;
- text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
-}
-
-#qunit-modulefilter-container {
- float: right;
-}
-
-/** Tests: Pass/Fail */
-
-#qunit-tests {
- list-style-position: inside;
-}
-
-#qunit-tests li {
- padding: 0.4em 0.5em 0.4em 2.5em;
- border-bottom: 1px solid #fff;
- list-style-position: inside;
-}
-
-#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running {
- display: none;
-}
-
-#qunit-tests li strong {
- cursor: pointer;
-}
-
-#qunit-tests li a {
- padding: 0.5em;
- color: #c2ccd1;
- text-decoration: none;
-}
-#qunit-tests li a:hover,
-#qunit-tests li a:focus {
- color: #000;
-}
-
-#qunit-tests li .runtime {
- float: right;
- font-size: smaller;
-}
-
-.qunit-assert-list {
- margin-top: 0.5em;
- padding: 0.5em;
-
- background-color: #fff;
-
- border-radius: 5px;
- -moz-border-radius: 5px;
- -webkit-border-radius: 5px;
-}
-
-.qunit-collapsed {
- display: none;
-}
-
-#qunit-tests table {
- border-collapse: collapse;
- margin-top: .2em;
-}
-
-#qunit-tests th {
- text-align: right;
- vertical-align: top;
- padding: 0 .5em 0 0;
-}
-
-#qunit-tests td {
- vertical-align: top;
-}
-
-#qunit-tests pre {
- margin: 0;
- white-space: pre-wrap;
- word-wrap: break-word;
-}
-
-#qunit-tests del {
- background-color: #e0f2be;
- color: #374e0c;
- text-decoration: none;
-}
-
-#qunit-tests ins {
- background-color: #ffcaca;
- color: #500;
- text-decoration: none;
-}
-
-/*** Test Counts */
-
-#qunit-tests b.counts { color: black; }
-#qunit-tests b.passed { color: #5E740B; }
-#qunit-tests b.failed { color: #710909; }
-
-#qunit-tests li li {
- padding: 5px;
- background-color: #fff;
- border-bottom: none;
- list-style-position: inside;
-}
-
-/*** Passing Styles */
-
-#qunit-tests li li.pass {
- color: #3c510c;
- background-color: #fff;
- border-left: 10px solid #C6E746;
-}
-
-#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
-#qunit-tests .pass .test-name { color: #366097; }
-
-#qunit-tests .pass .test-actual,
-#qunit-tests .pass .test-expected { color: #999999; }
-
-#qunit-banner.qunit-pass { background-color: #C6E746; }
-
-/*** Failing Styles */
-
-#qunit-tests li li.fail {
- color: #710909;
- background-color: #fff;
- border-left: 10px solid #EE5757;
- white-space: pre;
-}
-
-#qunit-tests > li:last-child {
- border-radius: 0 0 5px 5px;
- -moz-border-radius: 0 0 5px 5px;
- -webkit-border-bottom-right-radius: 5px;
- -webkit-border-bottom-left-radius: 5px;
-}
-
-#qunit-tests .fail { color: #000000; background-color: #EE5757; }
-#qunit-tests .fail .test-name,
-#qunit-tests .fail .module-name { color: #000000; }
-
-#qunit-tests .fail .test-actual { color: #EE5757; }
-#qunit-tests .fail .test-expected { color: green; }
-
-#qunit-banner.qunit-fail { background-color: #EE5757; }
-
-
-/** Result */
-
-#qunit-testresult {
- padding: 0.5em 0.5em 0.5em 2.5em;
-
- color: #2b81af;
- background-color: #D2E0E6;
-
- border-bottom: 1px solid white;
-}
-#qunit-testresult .module-name {
- font-weight: bold;
-}
-
-/** Fixture */
-
-#qunit-fixture {
- position: absolute;
- top: -10000px;
- left: -10000px;
- width: 1000px;
- height: 1000px;
-}
diff --git a/test/lib/qunit-1.11.0.js b/test/lib/qunit-1.11.0.js
deleted file mode 100644
index 302545f..0000000
--- a/test/lib/qunit-1.11.0.js
+++ /dev/null
@@ -1,2152 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-(function( window ) {
-
-var QUnit,
- assert,
- config,
- onErrorFnPrev,
- testId = 0,
- fileName = (sourceFromStacktrace( 0 ) || "" ).replace(/(:\d+)+\)?/, "").replace(/.+\//, ""),
- toString = Object.prototype.toString,
- hasOwn = Object.prototype.hasOwnProperty,
- // Keep a local reference to Date (GH-283)
- Date = window.Date,
- defined = {
- setTimeout: typeof window.setTimeout !== "undefined",
- sessionStorage: (function() {
- var x = "qunit-test-string";
- try {
- sessionStorage.setItem( x, x );
- sessionStorage.removeItem( x );
- return true;
- } catch( e ) {
- return false;
- }
- }())
- },
- /**
- * Provides a normalized error string, correcting an issue
- * with IE 7 (and prior) where Error.prototype.toString is
- * not properly implemented
- *
- * Based on http://es5.github.com/#x15.11.4.4
- *
- * @param {String|Error} error
- * @return {String} error message
- */
- errorString = function( error ) {
- var name, message,
- errorString = error.toString();
- if ( errorString.substring( 0, 7 ) === "[object" ) {
- name = error.name ? error.name.toString() : "Error";
- message = error.message ? error.message.toString() : "";
- if ( name && message ) {
- return name + ": " + message;
- } else if ( name ) {
- return name;
- } else if ( message ) {
- return message;
- } else {
- return "Error";
- }
- } else {
- return errorString;
- }
- },
- /**
- * Makes a clone of an object using only Array or Object as base,
- * and copies over the own enumerable properties.
- *
- * @param {Object} obj
- * @return {Object} New object with only the own properties (recursively).
- */
- objectValues = function( obj ) {
- // Grunt 0.3.x uses an older version of jshint that still has jshint/jshint#392.
- /*jshint newcap: false */
- var key, val,
- vals = QUnit.is( "array", obj ) ? [] : {};
- for ( key in obj ) {
- if ( hasOwn.call( obj, key ) ) {
- val = obj[key];
- vals[key] = val === Object(val) ? objectValues(val) : val;
- }
- }
- return vals;
- };
-
-function Test( settings ) {
- extend( this, settings );
- this.assertions = [];
- this.testNumber = ++Test.count;
-}
-
-Test.count = 0;
-
-Test.prototype = {
- init: function() {
- var a, b, li,
- tests = id( "qunit-tests" );
-
- if ( tests ) {
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml;
-
- // `a` initialized at top of scope
- a = document.createElement( "a" );
- a.innerHTML = "Rerun";
- a.href = QUnit.url({ testNumber: this.testNumber });
-
- li = document.createElement( "li" );
- li.appendChild( b );
- li.appendChild( a );
- li.className = "running";
- li.id = this.id = "qunit-test-output" + testId++;
-
- tests.appendChild( li );
- }
- },
- setup: function() {
- if ( this.module !== config.previousModule ) {
- if ( config.previousModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.previousModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
- config.previousModule = this.module;
- config.moduleStats = { all: 0, bad: 0 };
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- } else if ( config.autorun ) {
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- }
-
- config.current = this;
-
- this.testEnvironment = extend({
- setup: function() {},
- teardown: function() {}
- }, this.moduleTestEnvironment );
-
- this.started = +new Date();
- runLoggingCallbacks( "testStart", QUnit, {
- name: this.testName,
- module: this.module
- });
-
- // allow utility functions to access the current test environment
- // TODO why??
- QUnit.current_testEnvironment = this.testEnvironment;
-
- if ( !config.pollution ) {
- saveGlobal();
- }
- if ( config.notrycatch ) {
- this.testEnvironment.setup.call( this.testEnvironment );
- return;
- }
- try {
- this.testEnvironment.setup.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Setup failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- },
- run: function() {
- config.current = this;
-
- var running = id( "qunit-testresult" );
-
- if ( running ) {
- running.innerHTML = "Running:
" + this.nameHtml;
- }
-
- if ( this.async ) {
- QUnit.stop();
- }
-
- this.callbackStarted = +new Date();
-
- if ( config.notrycatch ) {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- return;
- }
-
- try {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- } catch( e ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
-
- QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + " " + this.stack + ": " + ( e.message || e ), extractStacktrace( e, 0 ) );
- // else next test will carry the responsibility
- saveGlobal();
-
- // Restart the tests if they're blocking
- if ( config.blocking ) {
- QUnit.start();
- }
- }
- },
- teardown: function() {
- config.current = this;
- if ( config.notrycatch ) {
- if ( typeof this.callbackRuntime === "undefined" ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
- }
- this.testEnvironment.teardown.call( this.testEnvironment );
- return;
- } else {
- try {
- this.testEnvironment.teardown.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Teardown failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- }
- checkPollution();
- },
- finish: function() {
- config.current = this;
- if ( config.requireExpects && this.expected === null ) {
- QUnit.pushFailure( "Expected number of assertions to be defined, but expect() was not called.", this.stack );
- } else if ( this.expected !== null && this.expected !== this.assertions.length ) {
- QUnit.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack );
- } else if ( this.expected === null && !this.assertions.length ) {
- QUnit.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions.", this.stack );
- }
-
- var i, assertion, a, b, time, li, ol,
- test = this,
- good = 0,
- bad = 0,
- tests = id( "qunit-tests" );
-
- this.runtime = +new Date() - this.started;
- config.stats.all += this.assertions.length;
- config.moduleStats.all += this.assertions.length;
-
- if ( tests ) {
- ol = document.createElement( "ol" );
- ol.className = "qunit-assert-list";
-
- for ( i = 0; i < this.assertions.length; i++ ) {
- assertion = this.assertions[i];
-
- li = document.createElement( "li" );
- li.className = assertion.result ? "pass" : "fail";
- li.innerHTML = assertion.message || ( assertion.result ? "okay" : "failed" );
- ol.appendChild( li );
-
- if ( assertion.result ) {
- good++;
- } else {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
-
- // store result when possible
- if ( QUnit.config.reorder && defined.sessionStorage ) {
- if ( bad ) {
- sessionStorage.setItem( "qunit-test-" + this.module + "-" + this.testName, bad );
- } else {
- sessionStorage.removeItem( "qunit-test-" + this.module + "-" + this.testName );
- }
- }
-
- if ( bad === 0 ) {
- addClass( ol, "qunit-collapsed" );
- }
-
- // `b` initialized at top of scope
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml + " (" + bad + ", " + good + ", " + this.assertions.length + ")";
-
- addEvent(b, "click", function() {
- var next = b.parentNode.lastChild,
- collapsed = hasClass( next, "qunit-collapsed" );
- ( collapsed ? removeClass : addClass )( next, "qunit-collapsed" );
- });
-
- addEvent(b, "dblclick", function( e ) {
- var target = e && e.target ? e.target : window.event.srcElement;
- if ( target.nodeName.toLowerCase() === "span" || target.nodeName.toLowerCase() === "b" ) {
- target = target.parentNode;
- }
- if ( window.location && target.nodeName.toLowerCase() === "strong" ) {
- window.location = QUnit.url({ testNumber: test.testNumber });
- }
- });
-
- // `time` initialized at top of scope
- time = document.createElement( "span" );
- time.className = "runtime";
- time.innerHTML = this.runtime + " ms";
-
- // `li` initialized at top of scope
- li = id( this.id );
- li.className = bad ? "fail" : "pass";
- li.removeChild( li.firstChild );
- a = li.firstChild;
- li.appendChild( b );
- li.appendChild( a );
- li.appendChild( time );
- li.appendChild( ol );
-
- } else {
- for ( i = 0; i < this.assertions.length; i++ ) {
- if ( !this.assertions[i].result ) {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
- }
-
- runLoggingCallbacks( "testDone", QUnit, {
- name: this.testName,
- module: this.module,
- failed: bad,
- passed: this.assertions.length - bad,
- total: this.assertions.length,
- duration: this.runtime
- });
-
- QUnit.reset();
-
- config.current = undefined;
- },
-
- queue: function() {
- var bad,
- test = this;
-
- synchronize(function() {
- test.init();
- });
- function run() {
- // each of these can by async
- synchronize(function() {
- test.setup();
- });
- synchronize(function() {
- test.run();
- });
- synchronize(function() {
- test.teardown();
- });
- synchronize(function() {
- test.finish();
- });
- }
-
- // `bad` initialized at top of scope
- // defer when previous test run passed, if storage is available
- bad = QUnit.config.reorder && defined.sessionStorage &&
- +sessionStorage.getItem( "qunit-test-" + this.module + "-" + this.testName );
-
- if ( bad ) {
- run();
- } else {
- synchronize( run, true );
- }
- }
-};
-
-// Root QUnit object.
-// `QUnit` initialized at top of scope
-QUnit = {
-
- // call on start of module test to prepend name to all tests
- module: function( name, testEnvironment ) {
- config.currentModule = name;
- config.currentModuleTestEnvironment = testEnvironment;
- config.modules[name] = true;
- },
-
- asyncTest: function( testName, expected, callback ) {
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- QUnit.test( testName, expected, callback, true );
- },
-
- test: function( testName, expected, callback, async ) {
- var test,
- nameHtml = "" + escapeText( testName ) + "";
-
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- if ( config.currentModule ) {
- nameHtml = "" + escapeText( config.currentModule ) + ": " + nameHtml;
- }
-
- test = new Test({
- nameHtml: nameHtml,
- testName: testName,
- expected: expected,
- async: async,
- callback: callback,
- module: config.currentModule,
- moduleTestEnvironment: config.currentModuleTestEnvironment,
- stack: sourceFromStacktrace( 2 )
- });
-
- if ( !validTest( test ) ) {
- return;
- }
-
- test.queue();
- },
-
- // Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through.
- expect: function( asserts ) {
- if (arguments.length === 1) {
- config.current.expected = asserts;
- } else {
- return config.current.expected;
- }
- },
-
- start: function( count ) {
- // QUnit hasn't been initialized yet.
- // Note: RequireJS (et al) may delay onLoad
- if ( config.semaphore === undefined ) {
- QUnit.begin(function() {
- // This is triggered at the top of QUnit.load, push start() to the event loop, to allow QUnit.load to finish first
- setTimeout(function() {
- QUnit.start( count );
- });
- });
- return;
- }
-
- config.semaphore -= count || 1;
- // don't start until equal number of stop-calls
- if ( config.semaphore > 0 ) {
- return;
- }
- // ignore if start is called more often then stop
- if ( config.semaphore < 0 ) {
- config.semaphore = 0;
- QUnit.pushFailure( "Called start() while already started (QUnit.config.semaphore was 0 already)", null, sourceFromStacktrace(2) );
- return;
- }
- // A slight delay, to avoid any current callbacks
- if ( defined.setTimeout ) {
- window.setTimeout(function() {
- if ( config.semaphore > 0 ) {
- return;
- }
- if ( config.timeout ) {
- clearTimeout( config.timeout );
- }
-
- config.blocking = false;
- process( true );
- }, 13);
- } else {
- config.blocking = false;
- process( true );
- }
- },
-
- stop: function( count ) {
- config.semaphore += count || 1;
- config.blocking = true;
-
- if ( config.testTimeout && defined.setTimeout ) {
- clearTimeout( config.timeout );
- config.timeout = window.setTimeout(function() {
- QUnit.ok( false, "Test timed out" );
- config.semaphore = 1;
- QUnit.start();
- }, config.testTimeout );
- }
- }
-};
-
-// `assert` initialized at top of scope
-// Asssert helpers
-// All of these must either call QUnit.push() or manually do:
-// - runLoggingCallbacks( "log", .. );
-// - config.current.assertions.push({ .. });
-// We attach it to the QUnit object *after* we expose the public API,
-// otherwise `assert` will become a global variable in browsers (#341).
-assert = {
- /**
- * Asserts rough true-ish result.
- * @name ok
- * @function
- * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" );
- */
- ok: function( result, msg ) {
- if ( !config.current ) {
- throw new Error( "ok() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
- result = !!result;
-
- var source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: msg
- };
-
- msg = escapeText( msg || (result ? "okay" : "failed" ) );
- msg = "" + msg + "";
-
- if ( !result ) {
- source = sourceFromStacktrace( 2 );
- if ( source ) {
- details.source = source;
- msg += "Source: | " + escapeText( source ) + " |
---|
";
- }
- }
- runLoggingCallbacks( "log", QUnit, details );
- config.current.assertions.push({
- result: result,
- message: msg
- });
- },
-
- /**
- * Assert that the first two arguments are equal, with an optional message.
- * Prints out both actual and expected values.
- * @name equal
- * @function
- * @example equal( format( "Received {0} bytes.", 2), "Received 2 bytes.", "format() replaces {0} with next argument" );
- */
- equal: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected == actual, actual, expected, message );
- },
-
- /**
- * @name notEqual
- * @function
- */
- notEqual: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected != actual, actual, expected, message );
- },
-
- /**
- * @name propEqual
- * @function
- */
- propEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notPropEqual
- * @function
- */
- notPropEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name deepEqual
- * @function
- */
- deepEqual: function( actual, expected, message ) {
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notDeepEqual
- * @function
- */
- notDeepEqual: function( actual, expected, message ) {
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name strictEqual
- * @function
- */
- strictEqual: function( actual, expected, message ) {
- QUnit.push( expected === actual, actual, expected, message );
- },
-
- /**
- * @name notStrictEqual
- * @function
- */
- notStrictEqual: function( actual, expected, message ) {
- QUnit.push( expected !== actual, actual, expected, message );
- },
-
- "throws": function( block, expected, message ) {
- var actual,
- expectedOutput = expected,
- ok = false;
-
- // 'expected' is optional
- if ( typeof expected === "string" ) {
- message = expected;
- expected = null;
- }
-
- config.current.ignoreGlobalErrors = true;
- try {
- block.call( config.current.testEnvironment );
- } catch (e) {
- actual = e;
- }
- config.current.ignoreGlobalErrors = false;
-
- if ( actual ) {
- // we don't want to validate thrown error
- if ( !expected ) {
- ok = true;
- expectedOutput = null;
- // expected is a regexp
- } else if ( QUnit.objectType( expected ) === "regexp" ) {
- ok = expected.test( errorString( actual ) );
- // expected is a constructor
- } else if ( actual instanceof expected ) {
- ok = true;
- // expected is a validation function which returns true is validation passed
- } else if ( expected.call( {}, actual ) === true ) {
- expectedOutput = null;
- ok = true;
- }
-
- QUnit.push( ok, actual, expectedOutput, message );
- } else {
- QUnit.pushFailure( message, null, 'No exception was thrown.' );
- }
- }
-};
-
-/**
- * @deprecate since 1.8.0
- * Kept assertion helpers in root for backwards compatibility.
- */
-extend( QUnit, assert );
-
-/**
- * @deprecated since 1.9.0
- * Kept root "raises()" for backwards compatibility.
- * (Note that we don't introduce assert.raises).
- */
-QUnit.raises = assert[ "throws" ];
-
-/**
- * @deprecated since 1.0.0, replaced with error pushes since 1.3.0
- * Kept to avoid TypeErrors for undefined methods.
- */
-QUnit.equals = function() {
- QUnit.push( false, false, false, "QUnit.equals has been deprecated since 2009 (e88049a0), use QUnit.equal instead" );
-};
-QUnit.same = function() {
- QUnit.push( false, false, false, "QUnit.same has been deprecated since 2009 (e88049a0), use QUnit.deepEqual instead" );
-};
-
-// We want access to the constructor's prototype
-(function() {
- function F() {}
- F.prototype = QUnit;
- QUnit = new F();
- // Make F QUnit's constructor so that we can add to the prototype later
- QUnit.constructor = F;
-}());
-
-/**
- * Config object: Maintain internal state
- * Later exposed as QUnit.config
- * `config` initialized at top of scope
- */
-config = {
- // The queue of tests to run
- queue: [],
-
- // block until document ready
- blocking: true,
-
- // when enabled, show only failing tests
- // gets persisted through sessionStorage and can be changed in UI via checkbox
- hidepassed: false,
-
- // by default, run previously failed tests first
- // very useful in combination with "Hide passed tests" checked
- reorder: true,
-
- // by default, modify document.title when suite is done
- altertitle: true,
-
- // when enabled, all tests must call expect()
- requireExpects: false,
-
- // add checkboxes that are persisted in the query-string
- // when enabled, the id is set to `true` as a `QUnit.config` property
- urlConfig: [
- {
- id: "noglobals",
- label: "Check for Globals",
- tooltip: "Enabling this will test if any test introduces new properties on the `window` object. Stored as query-strings."
- },
- {
- id: "notrycatch",
- label: "No try-catch",
- tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging exceptions in IE reasonable. Stored as query-strings."
- }
- ],
-
- // Set of all modules.
- modules: {},
-
- // logging callback queues
- begin: [],
- done: [],
- log: [],
- testStart: [],
- testDone: [],
- moduleStart: [],
- moduleDone: []
-};
-
-// Export global variables, unless an 'exports' object exists,
-// in that case we assume we're in CommonJS (dealt with on the bottom of the script)
-if ( typeof exports === "undefined" ) {
- extend( window, QUnit );
-
- // Expose QUnit object
- window.QUnit = QUnit;
-}
-
-// Initialize more QUnit.config and QUnit.urlParams
-(function() {
- var i,
- location = window.location || { search: "", protocol: "file:" },
- params = location.search.slice( 1 ).split( "&" ),
- length = params.length,
- urlParams = {},
- current;
-
- if ( params[ 0 ] ) {
- for ( i = 0; i < length; i++ ) {
- current = params[ i ].split( "=" );
- current[ 0 ] = decodeURIComponent( current[ 0 ] );
- // allow just a key to turn on a flag, e.g., test.html?noglobals
- current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true;
- urlParams[ current[ 0 ] ] = current[ 1 ];
- }
- }
-
- QUnit.urlParams = urlParams;
-
- // String search anywhere in moduleName+testName
- config.filter = urlParams.filter;
-
- // Exact match of the module name
- config.module = urlParams.module;
-
- config.testNumber = parseInt( urlParams.testNumber, 10 ) || null;
-
- // Figure out if we're running the tests from a server or not
- QUnit.isLocal = location.protocol === "file:";
-}());
-
-// Extend QUnit object,
-// these after set here because they should not be exposed as global functions
-extend( QUnit, {
- assert: assert,
-
- config: config,
-
- // Initialize the configuration options
- init: function() {
- extend( config, {
- stats: { all: 0, bad: 0 },
- moduleStats: { all: 0, bad: 0 },
- started: +new Date(),
- updateRate: 1000,
- blocking: false,
- autostart: true,
- autorun: false,
- filter: "",
- queue: [],
- semaphore: 1
- });
-
- var tests, banner, result,
- qunit = id( "qunit" );
-
- if ( qunit ) {
- qunit.innerHTML =
- "" +
- "" +
- "" +
- "" +
- "
";
- }
-
- tests = id( "qunit-tests" );
- banner = id( "qunit-banner" );
- result = id( "qunit-testresult" );
-
- if ( tests ) {
- tests.innerHTML = "";
- }
-
- if ( banner ) {
- banner.className = "";
- }
-
- if ( result ) {
- result.parentNode.removeChild( result );
- }
-
- if ( tests ) {
- result = document.createElement( "p" );
- result.id = "qunit-testresult";
- result.className = "result";
- tests.parentNode.insertBefore( result, tests );
- result.innerHTML = "Running...
";
- }
- },
-
- // Resets the test setup. Useful for tests that modify the DOM.
- reset: function() {
- var fixture = id( "qunit-fixture" );
- if ( fixture ) {
- fixture.innerHTML = config.fixture;
- }
- },
-
- // Trigger an event on an element.
- // @example triggerEvent( document.body, "click" );
- triggerEvent: function( elem, type, event ) {
- if ( document.createEvent ) {
- event = document.createEvent( "MouseEvents" );
- event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView,
- 0, 0, 0, 0, 0, false, false, false, false, 0, null);
-
- elem.dispatchEvent( event );
- } else if ( elem.fireEvent ) {
- elem.fireEvent( "on" + type );
- }
- },
-
- // Safe object type checking
- is: function( type, obj ) {
- return QUnit.objectType( obj ) === type;
- },
-
- objectType: function( obj ) {
- if ( typeof obj === "undefined" ) {
- return "undefined";
- // consider: typeof null === object
- }
- if ( obj === null ) {
- return "null";
- }
-
- var match = toString.call( obj ).match(/^\[object\s(.*)\]$/),
- type = match && match[1] || "";
-
- switch ( type ) {
- case "Number":
- if ( isNaN(obj) ) {
- return "nan";
- }
- return "number";
- case "String":
- case "Boolean":
- case "Array":
- case "Date":
- case "RegExp":
- case "Function":
- return type.toLowerCase();
- }
- if ( typeof obj === "object" ) {
- return "object";
- }
- return undefined;
- },
-
- push: function( result, actual, expected, message ) {
- if ( !config.current ) {
- throw new Error( "assertion outside test context, was " + sourceFromStacktrace() );
- }
-
- var output, source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: message,
- actual: actual,
- expected: expected
- };
-
- message = escapeText( message ) || ( result ? "okay" : "failed" );
- message = "" + message + "";
- output = message;
-
- if ( !result ) {
- expected = escapeText( QUnit.jsDump.parse(expected) );
- actual = escapeText( QUnit.jsDump.parse(actual) );
- output += "Expected: | " + expected + " |
";
-
- if ( actual !== expected ) {
- output += "Result: | " + actual + " |
";
- output += "Diff: | " + QUnit.diff( expected, actual ) + " |
";
- }
-
- source = sourceFromStacktrace();
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
- }
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: !!result,
- message: output
- });
- },
-
- pushFailure: function( message, source, actual ) {
- if ( !config.current ) {
- throw new Error( "pushFailure() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
-
- var output,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: false,
- message: message
- };
-
- message = escapeText( message ) || "error";
- message = "" + message + "";
- output = message;
-
- output += "";
-
- if ( actual ) {
- output += "Result: | " + escapeText( actual ) + " |
";
- }
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: false,
- message: output
- });
- },
-
- url: function( params ) {
- params = extend( extend( {}, QUnit.urlParams ), params );
- var key,
- querystring = "?";
-
- for ( key in params ) {
- if ( !hasOwn.call( params, key ) ) {
- continue;
- }
- querystring += encodeURIComponent( key ) + "=" +
- encodeURIComponent( params[ key ] ) + "&";
- }
- return window.location.protocol + "//" + window.location.host +
- window.location.pathname + querystring.slice( 0, -1 );
- },
-
- extend: extend,
- id: id,
- addEvent: addEvent
- // load, equiv, jsDump, diff: Attached later
-});
-
-/**
- * @deprecated: Created for backwards compatibility with test runner that set the hook function
- * into QUnit.{hook}, instead of invoking it and passing the hook function.
- * QUnit.constructor is set to the empty F() above so that we can add to it's prototype here.
- * Doing this allows us to tell if the following methods have been overwritten on the actual
- * QUnit object.
- */
-extend( QUnit.constructor.prototype, {
-
- // Logging callbacks; all receive a single argument with the listed properties
- // run test/logs.html for any related changes
- begin: registerLoggingCallback( "begin" ),
-
- // done: { failed, passed, total, runtime }
- done: registerLoggingCallback( "done" ),
-
- // log: { result, actual, expected, message }
- log: registerLoggingCallback( "log" ),
-
- // testStart: { name }
- testStart: registerLoggingCallback( "testStart" ),
-
- // testDone: { name, failed, passed, total, duration }
- testDone: registerLoggingCallback( "testDone" ),
-
- // moduleStart: { name }
- moduleStart: registerLoggingCallback( "moduleStart" ),
-
- // moduleDone: { name, failed, passed, total }
- moduleDone: registerLoggingCallback( "moduleDone" )
-});
-
-if ( typeof document === "undefined" || document.readyState === "complete" ) {
- config.autorun = true;
-}
-
-QUnit.load = function() {
- runLoggingCallbacks( "begin", QUnit, {} );
-
- // Initialize the config, saving the execution queue
- var banner, filter, i, label, len, main, ol, toolbar, userAgent, val,
- urlConfigCheckboxesContainer, urlConfigCheckboxes, moduleFilter,
- numModules = 0,
- moduleFilterHtml = "",
- urlConfigHtml = "",
- oldconfig = extend( {}, config );
-
- QUnit.init();
- extend(config, oldconfig);
-
- config.blocking = false;
-
- len = config.urlConfig.length;
-
- for ( i = 0; i < len; i++ ) {
- val = config.urlConfig[i];
- if ( typeof val === "string" ) {
- val = {
- id: val,
- label: val,
- tooltip: "[no tooltip available]"
- };
- }
- config[ val.id ] = QUnit.urlParams[ val.id ];
- urlConfigHtml += "";
- }
-
- moduleFilterHtml += "";
-
- // `userAgent` initialized at top of scope
- userAgent = id( "qunit-userAgent" );
- if ( userAgent ) {
- userAgent.innerHTML = navigator.userAgent;
- }
-
- // `banner` initialized at top of scope
- banner = id( "qunit-header" );
- if ( banner ) {
- banner.innerHTML = "" + banner.innerHTML + " ";
- }
-
- // `toolbar` initialized at top of scope
- toolbar = id( "qunit-testrunner-toolbar" );
- if ( toolbar ) {
- // `filter` initialized at top of scope
- filter = document.createElement( "input" );
- filter.type = "checkbox";
- filter.id = "qunit-filter-pass";
-
- addEvent( filter, "click", function() {
- var tmp,
- ol = document.getElementById( "qunit-tests" );
-
- if ( filter.checked ) {
- ol.className = ol.className + " hidepass";
- } else {
- tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " ";
- ol.className = tmp.replace( / hidepass /, " " );
- }
- if ( defined.sessionStorage ) {
- if (filter.checked) {
- sessionStorage.setItem( "qunit-filter-passed-tests", "true" );
- } else {
- sessionStorage.removeItem( "qunit-filter-passed-tests" );
- }
- }
- });
-
- if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem( "qunit-filter-passed-tests" ) ) {
- filter.checked = true;
- // `ol` initialized at top of scope
- ol = document.getElementById( "qunit-tests" );
- ol.className = ol.className + " hidepass";
- }
- toolbar.appendChild( filter );
-
- // `label` initialized at top of scope
- label = document.createElement( "label" );
- label.setAttribute( "for", "qunit-filter-pass" );
- label.setAttribute( "title", "Only show tests and assertons that fail. Stored in sessionStorage." );
- label.innerHTML = "Hide passed tests";
- toolbar.appendChild( label );
-
- urlConfigCheckboxesContainer = document.createElement("span");
- urlConfigCheckboxesContainer.innerHTML = urlConfigHtml;
- urlConfigCheckboxes = urlConfigCheckboxesContainer.getElementsByTagName("input");
- // For oldIE support:
- // * Add handlers to the individual elements instead of the container
- // * Use "click" instead of "change"
- // * Fallback from event.target to event.srcElement
- addEvents( urlConfigCheckboxes, "click", function( event ) {
- var params = {},
- target = event.target || event.srcElement;
- params[ target.name ] = target.checked ? true : undefined;
- window.location = QUnit.url( params );
- });
- toolbar.appendChild( urlConfigCheckboxesContainer );
-
- if (numModules > 1) {
- moduleFilter = document.createElement( 'span' );
- moduleFilter.setAttribute( 'id', 'qunit-modulefilter-container' );
- moduleFilter.innerHTML = moduleFilterHtml;
- addEvent( moduleFilter.lastChild, "change", function() {
- var selectBox = moduleFilter.getElementsByTagName("select")[0],
- selectedModule = decodeURIComponent(selectBox.options[selectBox.selectedIndex].value);
-
- window.location = QUnit.url( { module: ( selectedModule === "" ) ? undefined : selectedModule } );
- });
- toolbar.appendChild(moduleFilter);
- }
- }
-
- // `main` initialized at top of scope
- main = id( "qunit-fixture" );
- if ( main ) {
- config.fixture = main.innerHTML;
- }
-
- if ( config.autostart ) {
- QUnit.start();
- }
-};
-
-addEvent( window, "load", QUnit.load );
-
-// `onErrorFnPrev` initialized at top of scope
-// Preserve other handlers
-onErrorFnPrev = window.onerror;
-
-// Cover uncaught exceptions
-// Returning true will surpress the default browser handler,
-// returning false will let it run.
-window.onerror = function ( error, filePath, linerNr ) {
- var ret = false;
- if ( onErrorFnPrev ) {
- ret = onErrorFnPrev( error, filePath, linerNr );
- }
-
- // Treat return value as window.onerror itself does,
- // Only do our handling if not surpressed.
- if ( ret !== true ) {
- if ( QUnit.config.current ) {
- if ( QUnit.config.current.ignoreGlobalErrors ) {
- return true;
- }
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- } else {
- QUnit.test( "global failure", extend( function() {
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- }, { validTest: validTest } ) );
- }
- return false;
- }
-
- return ret;
-};
-
-function done() {
- config.autorun = true;
-
- // Log the last module results
- if ( config.currentModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.currentModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
-
- var i, key,
- banner = id( "qunit-banner" ),
- tests = id( "qunit-tests" ),
- runtime = +new Date() - config.started,
- passed = config.stats.all - config.stats.bad,
- html = [
- "Tests completed in ",
- runtime,
- " milliseconds.
",
- "",
- passed,
- " assertions of ",
- config.stats.all,
- " passed, ",
- config.stats.bad,
- " failed."
- ].join( "" );
-
- if ( banner ) {
- banner.className = ( config.stats.bad ? "qunit-fail" : "qunit-pass" );
- }
-
- if ( tests ) {
- id( "qunit-testresult" ).innerHTML = html;
- }
-
- if ( config.altertitle && typeof document !== "undefined" && document.title ) {
- // show ✖ for good, ✔ for bad suite result in title
- // use escape sequences in case file gets loaded with non-utf-8-charset
- document.title = [
- ( config.stats.bad ? "\u2716" : "\u2714" ),
- document.title.replace( /^[\u2714\u2716] /i, "" )
- ].join( " " );
- }
-
- // clear own sessionStorage items if all tests passed
- if ( config.reorder && defined.sessionStorage && config.stats.bad === 0 ) {
- // `key` & `i` initialized at top of scope
- for ( i = 0; i < sessionStorage.length; i++ ) {
- key = sessionStorage.key( i++ );
- if ( key.indexOf( "qunit-test-" ) === 0 ) {
- sessionStorage.removeItem( key );
- }
- }
- }
-
- // scroll back to top to show results
- if ( window.scrollTo ) {
- window.scrollTo(0, 0);
- }
-
- runLoggingCallbacks( "done", QUnit, {
- failed: config.stats.bad,
- passed: passed,
- total: config.stats.all,
- runtime: runtime
- });
-}
-
-/** @return Boolean: true if this test should be ran */
-function validTest( test ) {
- var include,
- filter = config.filter && config.filter.toLowerCase(),
- module = config.module && config.module.toLowerCase(),
- fullName = (test.module + ": " + test.testName).toLowerCase();
-
- // Internally-generated tests are always valid
- if ( test.callback && test.callback.validTest === validTest ) {
- delete test.callback.validTest;
- return true;
- }
-
- if ( config.testNumber ) {
- return test.testNumber === config.testNumber;
- }
-
- if ( module && ( !test.module || test.module.toLowerCase() !== module ) ) {
- return false;
- }
-
- if ( !filter ) {
- return true;
- }
-
- include = filter.charAt( 0 ) !== "!";
- if ( !include ) {
- filter = filter.slice( 1 );
- }
-
- // If the filter matches, we need to honour include
- if ( fullName.indexOf( filter ) !== -1 ) {
- return include;
- }
-
- // Otherwise, do the opposite
- return !include;
-}
-
-// so far supports only Firefox, Chrome and Opera (buggy), Safari (for real exceptions)
-// Later Safari and IE10 are supposed to support error.stack as well
-// See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack
-function extractStacktrace( e, offset ) {
- offset = offset === undefined ? 3 : offset;
-
- var stack, include, i;
-
- if ( e.stacktrace ) {
- // Opera
- return e.stacktrace.split( "\n" )[ offset + 3 ];
- } else if ( e.stack ) {
- // Firefox, Chrome
- stack = e.stack.split( "\n" );
- if (/^error$/i.test( stack[0] ) ) {
- stack.shift();
- }
- if ( fileName ) {
- include = [];
- for ( i = offset; i < stack.length; i++ ) {
- if ( stack[ i ].indexOf( fileName ) !== -1 ) {
- break;
- }
- include.push( stack[ i ] );
- }
- if ( include.length ) {
- return include.join( "\n" );
- }
- }
- return stack[ offset ];
- } else if ( e.sourceURL ) {
- // Safari, PhantomJS
- // hopefully one day Safari provides actual stacktraces
- // exclude useless self-reference for generated Error objects
- if ( /qunit.js$/.test( e.sourceURL ) ) {
- return;
- }
- // for actual exceptions, this is useful
- return e.sourceURL + ":" + e.line;
- }
-}
-function sourceFromStacktrace( offset ) {
- try {
- throw new Error();
- } catch ( e ) {
- return extractStacktrace( e, offset );
- }
-}
-
-/**
- * Escape text for attribute or text content.
- */
-function escapeText( s ) {
- if ( !s ) {
- return "";
- }
- s = s + "";
- // Both single quotes and double quotes (for attributes)
- return s.replace( /['"<>&]/g, function( s ) {
- switch( s ) {
- case '\'':
- return ''';
- case '"':
- return '"';
- case '<':
- return '<';
- case '>':
- return '>';
- case '&':
- return '&';
- }
- });
-}
-
-function synchronize( callback, last ) {
- config.queue.push( callback );
-
- if ( config.autorun && !config.blocking ) {
- process( last );
- }
-}
-
-function process( last ) {
- function next() {
- process( last );
- }
- var start = new Date().getTime();
- config.depth = config.depth ? config.depth + 1 : 1;
-
- while ( config.queue.length && !config.blocking ) {
- if ( !defined.setTimeout || config.updateRate <= 0 || ( ( new Date().getTime() - start ) < config.updateRate ) ) {
- config.queue.shift()();
- } else {
- window.setTimeout( next, 13 );
- break;
- }
- }
- config.depth--;
- if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) {
- done();
- }
-}
-
-function saveGlobal() {
- config.pollution = [];
-
- if ( config.noglobals ) {
- for ( var key in window ) {
- // in Opera sometimes DOM element ids show up here, ignore them
- if ( !hasOwn.call( window, key ) || /^qunit-test-output/.test( key ) ) {
- continue;
- }
- config.pollution.push( key );
- }
- }
-}
-
-function checkPollution() {
- var newGlobals,
- deletedGlobals,
- old = config.pollution;
-
- saveGlobal();
-
- newGlobals = diff( config.pollution, old );
- if ( newGlobals.length > 0 ) {
- QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join(", ") );
- }
-
- deletedGlobals = diff( old, config.pollution );
- if ( deletedGlobals.length > 0 ) {
- QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join(", ") );
- }
-}
-
-// returns a new Array with the elements that are in a but not in b
-function diff( a, b ) {
- var i, j,
- result = a.slice();
-
- for ( i = 0; i < result.length; i++ ) {
- for ( j = 0; j < b.length; j++ ) {
- if ( result[i] === b[j] ) {
- result.splice( i, 1 );
- i--;
- break;
- }
- }
- }
- return result;
-}
-
-function extend( a, b ) {
- for ( var prop in b ) {
- if ( b[ prop ] === undefined ) {
- delete a[ prop ];
-
- // Avoid "Member not found" error in IE8 caused by setting window.constructor
- } else if ( prop !== "constructor" || a !== window ) {
- a[ prop ] = b[ prop ];
- }
- }
-
- return a;
-}
-
-/**
- * @param {HTMLElement} elem
- * @param {string} type
- * @param {Function} fn
- */
-function addEvent( elem, type, fn ) {
- // Standards-based browsers
- if ( elem.addEventListener ) {
- elem.addEventListener( type, fn, false );
- // IE
- } else {
- elem.attachEvent( "on" + type, fn );
- }
-}
-
-/**
- * @param {Array|NodeList} elems
- * @param {string} type
- * @param {Function} fn
- */
-function addEvents( elems, type, fn ) {
- var i = elems.length;
- while ( i-- ) {
- addEvent( elems[i], type, fn );
- }
-}
-
-function hasClass( elem, name ) {
- return (" " + elem.className + " ").indexOf(" " + name + " ") > -1;
-}
-
-function addClass( elem, name ) {
- if ( !hasClass( elem, name ) ) {
- elem.className += (elem.className ? " " : "") + name;
- }
-}
-
-function removeClass( elem, name ) {
- var set = " " + elem.className + " ";
- // Class name may appear multiple times
- while ( set.indexOf(" " + name + " ") > -1 ) {
- set = set.replace(" " + name + " " , " ");
- }
- // If possible, trim it for prettiness, but not neccecarily
- elem.className = window.jQuery ? jQuery.trim( set ) : ( set.trim ? set.trim() : set );
-}
-
-function id( name ) {
- return !!( typeof document !== "undefined" && document && document.getElementById ) &&
- document.getElementById( name );
-}
-
-function registerLoggingCallback( key ) {
- return function( callback ) {
- config[key].push( callback );
- };
-}
-
-// Supports deprecated method of completely overwriting logging callbacks
-function runLoggingCallbacks( key, scope, args ) {
- var i, callbacks;
- if ( QUnit.hasOwnProperty( key ) ) {
- QUnit[ key ].call(scope, args );
- } else {
- callbacks = config[ key ];
- for ( i = 0; i < callbacks.length; i++ ) {
- callbacks[ i ].call( scope, args );
- }
- }
-}
-
-// Test for equality any JavaScript type.
-// Author: Philippe Rathé
-QUnit.equiv = (function() {
-
- // Call the o related callback with the given arguments.
- function bindCallbacks( o, callbacks, args ) {
- var prop = QUnit.objectType( o );
- if ( prop ) {
- if ( QUnit.objectType( callbacks[ prop ] ) === "function" ) {
- return callbacks[ prop ].apply( callbacks, args );
- } else {
- return callbacks[ prop ]; // or undefined
- }
- }
- }
-
- // the real equiv function
- var innerEquiv,
- // stack to decide between skip/abort functions
- callers = [],
- // stack to avoiding loops from circular referencing
- parents = [],
-
- getProto = Object.getPrototypeOf || function ( obj ) {
- return obj.__proto__;
- },
- callbacks = (function () {
-
- // for string, boolean, number and null
- function useStrictEquality( b, a ) {
- /*jshint eqeqeq:false */
- if ( b instanceof a.constructor || a instanceof b.constructor ) {
- // to catch short annotaion VS 'new' annotation of a
- // declaration
- // e.g. var i = 1;
- // var j = new Number(1);
- return a == b;
- } else {
- return a === b;
- }
- }
-
- return {
- "string": useStrictEquality,
- "boolean": useStrictEquality,
- "number": useStrictEquality,
- "null": useStrictEquality,
- "undefined": useStrictEquality,
-
- "nan": function( b ) {
- return isNaN( b );
- },
-
- "date": function( b, a ) {
- return QUnit.objectType( b ) === "date" && a.valueOf() === b.valueOf();
- },
-
- "regexp": function( b, a ) {
- return QUnit.objectType( b ) === "regexp" &&
- // the regex itself
- a.source === b.source &&
- // and its modifers
- a.global === b.global &&
- // (gmi) ...
- a.ignoreCase === b.ignoreCase &&
- a.multiline === b.multiline &&
- a.sticky === b.sticky;
- },
-
- // - skip when the property is a method of an instance (OOP)
- // - abort otherwise,
- // initial === would have catch identical references anyway
- "function": function() {
- var caller = callers[callers.length - 1];
- return caller !== Object && typeof caller !== "undefined";
- },
-
- "array": function( b, a ) {
- var i, j, len, loop;
-
- // b could be an object literal here
- if ( QUnit.objectType( b ) !== "array" ) {
- return false;
- }
-
- len = a.length;
- if ( len !== b.length ) {
- // safe and faster
- return false;
- }
-
- // track reference to avoid circular references
- parents.push( a );
- for ( i = 0; i < len; i++ ) {
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- loop = true;// dont rewalk array
- }
- }
- if ( !loop && !innerEquiv(a[i], b[i]) ) {
- parents.pop();
- return false;
- }
- }
- parents.pop();
- return true;
- },
-
- "object": function( b, a ) {
- var i, j, loop,
- // Default to true
- eq = true,
- aProperties = [],
- bProperties = [];
-
- // comparing constructors is more strict than using
- // instanceof
- if ( a.constructor !== b.constructor ) {
- // Allow objects with no prototype to be equivalent to
- // objects with Object as their constructor.
- if ( !(( getProto(a) === null && getProto(b) === Object.prototype ) ||
- ( getProto(b) === null && getProto(a) === Object.prototype ) ) ) {
- return false;
- }
- }
-
- // stack constructor before traversing properties
- callers.push( a.constructor );
- // track reference to avoid circular references
- parents.push( a );
-
- for ( i in a ) { // be strict: don't ensures hasOwnProperty
- // and go deep
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- // don't go down the same path twice
- loop = true;
- }
- }
- aProperties.push(i); // collect a's properties
-
- if (!loop && !innerEquiv( a[i], b[i] ) ) {
- eq = false;
- break;
- }
- }
-
- callers.pop(); // unstack, we are done
- parents.pop();
-
- for ( i in b ) {
- bProperties.push( i ); // collect b's properties
- }
-
- // Ensures identical properties name
- return eq && innerEquiv( aProperties.sort(), bProperties.sort() );
- }
- };
- }());
-
- innerEquiv = function() { // can take multiple arguments
- var args = [].slice.apply( arguments );
- if ( args.length < 2 ) {
- return true; // end transition
- }
-
- return (function( a, b ) {
- if ( a === b ) {
- return true; // catch the most you can
- } else if ( a === null || b === null || typeof a === "undefined" ||
- typeof b === "undefined" ||
- QUnit.objectType(a) !== QUnit.objectType(b) ) {
- return false; // don't lose time with error prone cases
- } else {
- return bindCallbacks(a, callbacks, [ b, a ]);
- }
-
- // apply transition with (1..n) arguments
- }( args[0], args[1] ) && arguments.callee.apply( this, args.splice(1, args.length - 1 )) );
- };
-
- return innerEquiv;
-}());
-
-/**
- * jsDump Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com |
- * http://flesler.blogspot.com Licensed under BSD
- * (http://www.opensource.org/licenses/bsd-license.php) Date: 5/15/2008
- *
- * @projectDescription Advanced and extensible data dumping for Javascript.
- * @version 1.0.0
- * @author Ariel Flesler
- * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html}
- */
-QUnit.jsDump = (function() {
- function quote( str ) {
- return '"' + str.toString().replace( /"/g, '\\"' ) + '"';
- }
- function literal( o ) {
- return o + "";
- }
- function join( pre, arr, post ) {
- var s = jsDump.separator(),
- base = jsDump.indent(),
- inner = jsDump.indent(1);
- if ( arr.join ) {
- arr = arr.join( "," + s + inner );
- }
- if ( !arr ) {
- return pre + post;
- }
- return [ pre, inner + arr, base + post ].join(s);
- }
- function array( arr, stack ) {
- var i = arr.length, ret = new Array(i);
- this.up();
- while ( i-- ) {
- ret[i] = this.parse( arr[i] , undefined , stack);
- }
- this.down();
- return join( "[", ret, "]" );
- }
-
- var reName = /^function (\w+)/,
- jsDump = {
- // type is used mostly internally, you can fix a (custom)type in advance
- parse: function( obj, type, stack ) {
- stack = stack || [ ];
- var inStack, res,
- parser = this.parsers[ type || this.typeOf(obj) ];
-
- type = typeof parser;
- inStack = inArray( obj, stack );
-
- if ( inStack !== -1 ) {
- return "recursion(" + (inStack - stack.length) + ")";
- }
- if ( type === "function" ) {
- stack.push( obj );
- res = parser.call( this, obj, stack );
- stack.pop();
- return res;
- }
- return ( type === "string" ) ? parser : this.parsers.error;
- },
- typeOf: function( obj ) {
- var type;
- if ( obj === null ) {
- type = "null";
- } else if ( typeof obj === "undefined" ) {
- type = "undefined";
- } else if ( QUnit.is( "regexp", obj) ) {
- type = "regexp";
- } else if ( QUnit.is( "date", obj) ) {
- type = "date";
- } else if ( QUnit.is( "function", obj) ) {
- type = "function";
- } else if ( typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined" ) {
- type = "window";
- } else if ( obj.nodeType === 9 ) {
- type = "document";
- } else if ( obj.nodeType ) {
- type = "node";
- } else if (
- // native arrays
- toString.call( obj ) === "[object Array]" ||
- // NodeList objects
- ( typeof obj.length === "number" && typeof obj.item !== "undefined" && ( obj.length ? obj.item(0) === obj[0] : ( obj.item( 0 ) === null && typeof obj[0] === "undefined" ) ) )
- ) {
- type = "array";
- } else if ( obj.constructor === Error.prototype.constructor ) {
- type = "error";
- } else {
- type = typeof obj;
- }
- return type;
- },
- separator: function() {
- return this.multiline ? this.HTML ? "
" : "\n" : this.HTML ? " " : " ";
- },
- // extra can be a number, shortcut for increasing-calling-decreasing
- indent: function( extra ) {
- if ( !this.multiline ) {
- return "";
- }
- var chr = this.indentChar;
- if ( this.HTML ) {
- chr = chr.replace( /\t/g, " " ).replace( / /g, " " );
- }
- return new Array( this._depth_ + (extra||0) ).join(chr);
- },
- up: function( a ) {
- this._depth_ += a || 1;
- },
- down: function( a ) {
- this._depth_ -= a || 1;
- },
- setParser: function( name, parser ) {
- this.parsers[name] = parser;
- },
- // The next 3 are exposed so you can use them
- quote: quote,
- literal: literal,
- join: join,
- //
- _depth_: 1,
- // This is the list of parsers, to modify them, use jsDump.setParser
- parsers: {
- window: "[Window]",
- document: "[Document]",
- error: function(error) {
- return "Error(\"" + error.message + "\")";
- },
- unknown: "[Unknown]",
- "null": "null",
- "undefined": "undefined",
- "function": function( fn ) {
- var ret = "function",
- // functions never have name in IE
- name = "name" in fn ? fn.name : (reName.exec(fn) || [])[1];
-
- if ( name ) {
- ret += " " + name;
- }
- ret += "( ";
-
- ret = [ ret, QUnit.jsDump.parse( fn, "functionArgs" ), "){" ].join( "" );
- return join( ret, QUnit.jsDump.parse(fn,"functionCode" ), "}" );
- },
- array: array,
- nodelist: array,
- "arguments": array,
- object: function( map, stack ) {
- var ret = [ ], keys, key, val, i;
- QUnit.jsDump.up();
- keys = [];
- for ( key in map ) {
- keys.push( key );
- }
- keys.sort();
- for ( i = 0; i < keys.length; i++ ) {
- key = keys[ i ];
- val = map[ key ];
- ret.push( QUnit.jsDump.parse( key, "key" ) + ": " + QUnit.jsDump.parse( val, undefined, stack ) );
- }
- QUnit.jsDump.down();
- return join( "{", ret, "}" );
- },
- node: function( node ) {
- var len, i, val,
- open = QUnit.jsDump.HTML ? "<" : "<",
- close = QUnit.jsDump.HTML ? ">" : ">",
- tag = node.nodeName.toLowerCase(),
- ret = open + tag,
- attrs = node.attributes;
-
- if ( attrs ) {
- for ( i = 0, len = attrs.length; i < len; i++ ) {
- val = attrs[i].nodeValue;
- // IE6 includes all attributes in .attributes, even ones not explicitly set.
- // Those have values like undefined, null, 0, false, "" or "inherit".
- if ( val && val !== "inherit" ) {
- ret += " " + attrs[i].nodeName + "=" + QUnit.jsDump.parse( val, "attribute" );
- }
- }
- }
- ret += close;
-
- // Show content of TextNode or CDATASection
- if ( node.nodeType === 3 || node.nodeType === 4 ) {
- ret += node.nodeValue;
- }
-
- return ret + open + "/" + tag + close;
- },
- // function calls it internally, it's the arguments part of the function
- functionArgs: function( fn ) {
- var args,
- l = fn.length;
-
- if ( !l ) {
- return "";
- }
-
- args = new Array(l);
- while ( l-- ) {
- // 97 is 'a'
- args[l] = String.fromCharCode(97+l);
- }
- return " " + args.join( ", " ) + " ";
- },
- // object calls it internally, the key part of an item in a map
- key: quote,
- // function calls it internally, it's the content of the function
- functionCode: "[code]",
- // node calls it internally, it's an html attribute value
- attribute: quote,
- string: quote,
- date: quote,
- regexp: literal,
- number: literal,
- "boolean": literal
- },
- // if true, entities are escaped ( <, >, \t, space and \n )
- HTML: false,
- // indentation unit
- indentChar: " ",
- // if true, items in a collection, are separated by a \n, else just a space.
- multiline: true
- };
-
- return jsDump;
-}());
-
-// from jquery.js
-function inArray( elem, array ) {
- if ( array.indexOf ) {
- return array.indexOf( elem );
- }
-
- for ( var i = 0, length = array.length; i < length; i++ ) {
- if ( array[ i ] === elem ) {
- return i;
- }
- }
-
- return -1;
-}
-
-/*
- * Javascript Diff Algorithm
- * By John Resig (http://ejohn.org/)
- * Modified by Chu Alan "sprite"
- *
- * Released under the MIT license.
- *
- * More Info:
- * http://ejohn.org/projects/javascript-diff-algorithm/
- *
- * Usage: QUnit.diff(expected, actual)
- *
- * QUnit.diff( "the quick brown fox jumped over", "the quick fox jumps over" ) == "the quick brown fox jumped jumps over"
- */
-QUnit.diff = (function() {
- /*jshint eqeqeq:false, eqnull:true */
- function diff( o, n ) {
- var i,
- ns = {},
- os = {};
-
- for ( i = 0; i < n.length; i++ ) {
- if ( !hasOwn.call( ns, n[i] ) ) {
- ns[ n[i] ] = {
- rows: [],
- o: null
- };
- }
- ns[ n[i] ].rows.push( i );
- }
-
- for ( i = 0; i < o.length; i++ ) {
- if ( !hasOwn.call( os, o[i] ) ) {
- os[ o[i] ] = {
- rows: [],
- n: null
- };
- }
- os[ o[i] ].rows.push( i );
- }
-
- for ( i in ns ) {
- if ( !hasOwn.call( ns, i ) ) {
- continue;
- }
- if ( ns[i].rows.length === 1 && hasOwn.call( os, i ) && os[i].rows.length === 1 ) {
- n[ ns[i].rows[0] ] = {
- text: n[ ns[i].rows[0] ],
- row: os[i].rows[0]
- };
- o[ os[i].rows[0] ] = {
- text: o[ os[i].rows[0] ],
- row: ns[i].rows[0]
- };
- }
- }
-
- for ( i = 0; i < n.length - 1; i++ ) {
- if ( n[i].text != null && n[ i + 1 ].text == null && n[i].row + 1 < o.length && o[ n[i].row + 1 ].text == null &&
- n[ i + 1 ] == o[ n[i].row + 1 ] ) {
-
- n[ i + 1 ] = {
- text: n[ i + 1 ],
- row: n[i].row + 1
- };
- o[ n[i].row + 1 ] = {
- text: o[ n[i].row + 1 ],
- row: i + 1
- };
- }
- }
-
- for ( i = n.length - 1; i > 0; i-- ) {
- if ( n[i].text != null && n[ i - 1 ].text == null && n[i].row > 0 && o[ n[i].row - 1 ].text == null &&
- n[ i - 1 ] == o[ n[i].row - 1 ]) {
-
- n[ i - 1 ] = {
- text: n[ i - 1 ],
- row: n[i].row - 1
- };
- o[ n[i].row - 1 ] = {
- text: o[ n[i].row - 1 ],
- row: i - 1
- };
- }
- }
-
- return {
- o: o,
- n: n
- };
- }
-
- return function( o, n ) {
- o = o.replace( /\s+$/, "" );
- n = n.replace( /\s+$/, "" );
-
- var i, pre,
- str = "",
- out = diff( o === "" ? [] : o.split(/\s+/), n === "" ? [] : n.split(/\s+/) ),
- oSpace = o.match(/\s+/g),
- nSpace = n.match(/\s+/g);
-
- if ( oSpace == null ) {
- oSpace = [ " " ];
- }
- else {
- oSpace.push( " " );
- }
-
- if ( nSpace == null ) {
- nSpace = [ " " ];
- }
- else {
- nSpace.push( " " );
- }
-
- if ( out.n.length === 0 ) {
- for ( i = 0; i < out.o.length; i++ ) {
- str += "" + out.o[i] + oSpace[i] + "";
- }
- }
- else {
- if ( out.n[0].text == null ) {
- for ( n = 0; n < out.o.length && out.o[n].text == null; n++ ) {
- str += "" + out.o[n] + oSpace[n] + "";
- }
- }
-
- for ( i = 0; i < out.n.length; i++ ) {
- if (out.n[i].text == null) {
- str += "" + out.n[i] + nSpace[i] + "";
- }
- else {
- // `pre` initialized at top of scope
- pre = "";
-
- for ( n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++ ) {
- pre += "" + out.o[n] + oSpace[n] + "";
- }
- str += " " + out.n[i].text + nSpace[i] + pre;
- }
- }
- }
-
- return str;
- };
-}());
-
-// for CommonJS enviroments, export everything
-if ( typeof exports !== "undefined" ) {
- extend( exports, QUnit );
-}
-
-// get at whatever the global object is, like window in browsers
-}( (function() {return this;}.call()) ));
diff --git a/test/lib/require.js b/test/lib/require.js
deleted file mode 100644
index 987f865..0000000
--- a/test/lib/require.js
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- RequireJS 2.1.5 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.
- Available via the MIT or new BSD license.
- see: http://github.com/jrburke/requirejs for details
-*/
-var requirejs,require,define;
-(function(aa){function I(b){return"[object Function]"===L.call(b)}function J(b){return"[object Array]"===L.call(b)}function y(b,c){if(b){var d;for(d=0;dthis.depCount&&!this.defined){if(I(n)){if(this.events.error)try{e=i.execCb(c,n,b,e)}catch(d){a=d}else e=i.execCb(c,n,b,e);this.map.isDefine&&((b=this.module)&&void 0!==b.exports&&b.exports!==this.exports?e=b.exports:void 0===e&&this.usingExports&&(e=this.exports));if(a)return a.requireMap=this.map,a.requireModules=[this.map.id],a.requireType="define",v(this.error=
-a)}else e=n;this.exports=e;if(this.map.isDefine&&!this.ignore&&(q[c]=e,l.onResourceLoad))l.onResourceLoad(i,this.map,this.depMaps);x(c);this.defined=!0}this.defining=!1;this.defined&&!this.defineEmitted&&(this.defineEmitted=!0,this.emit("defined",this.exports),this.defineEmitComplete=!0)}}else this.fetch()}},callPlugin:function(){var a=this.map,b=a.id,d=j(a.prefix);this.depMaps.push(d);t(d,"defined",u(this,function(e){var n,d;d=this.map.name;var g=this.map.parentMap?this.map.parentMap.name:null,h=
-i.makeRequire(a.parentMap,{enableBuildCallback:!0});if(this.map.unnormalized){if(e.normalize&&(d=e.normalize(d,function(a){return c(a,g,!0)})||""),e=j(a.prefix+"!"+d,this.map.parentMap),t(e,"defined",u(this,function(a){this.init([],function(){return a},null,{enabled:!0,ignore:!0})})),d=m(p,e.id)){this.depMaps.push(e);if(this.events.error)d.on("error",u(this,function(a){this.emit("error",a)}));d.enable()}}else n=u(this,function(a){this.init([],function(){return a},null,{enabled:!0})}),n.error=u(this,
-function(a){this.inited=!0;this.error=a;a.requireModules=[b];G(p,function(a){0===a.map.id.indexOf(b+"_unnormalized")&&x(a.map.id)});v(a)}),n.fromText=u(this,function(e,c){var d=a.name,g=j(d),C=O;c&&(e=c);C&&(O=!1);r(g);s(k.config,b)&&(k.config[d]=k.config[b]);try{l.exec(e)}catch(ca){return v(B("fromtexteval","fromText eval for "+b+" failed: "+ca,ca,[b]))}C&&(O=!0);this.depMaps.push(g);i.completeLoad(d);h([d],n)}),e.load(a.name,h,n,k)}));i.enable(d,this);this.pluginMaps[d.id]=d},enable:function(){V[this.map.id]=
-this;this.enabling=this.enabled=!0;y(this.depMaps,u(this,function(a,b){var c,e;if("string"===typeof a){a=j(a,this.map.isDefine?this.map:this.map.parentMap,!1,!this.skipMap);this.depMaps[b]=a;if(c=m(N,a.id)){this.depExports[b]=c(this);return}this.depCount+=1;t(a,"defined",u(this,function(a){this.defineDep(b,a);this.check()}));this.errback&&t(a,"error",this.errback)}c=a.id;e=p[c];!s(N,c)&&(e&&!e.enabled)&&i.enable(a,this)}));G(this.pluginMaps,u(this,function(a){var b=m(p,a.id);b&&!b.enabled&&i.enable(a,
-this)}));this.enabling=!1;this.check()},on:function(a,b){var c=this.events[a];c||(c=this.events[a]=[]);c.push(b)},emit:function(a,b){y(this.events[a],function(a){a(b)});"error"===a&&delete this.events[a]}};i={config:k,contextName:b,registry:p,defined:q,urlFetched:U,defQueue:H,Module:Z,makeModuleMap:j,nextTick:l.nextTick,onError:v,configure:function(a){a.baseUrl&&"/"!==a.baseUrl.charAt(a.baseUrl.length-1)&&(a.baseUrl+="/");var b=k.pkgs,c=k.shim,e={paths:!0,config:!0,map:!0};G(a,function(a,b){e[b]?
-"map"===b?(k.map||(k.map={}),R(k[b],a,!0,!0)):R(k[b],a,!0):k[b]=a});a.shim&&(G(a.shim,function(a,b){J(a)&&(a={deps:a});if((a.exports||a.init)&&!a.exportsFn)a.exportsFn=i.makeShimExports(a);c[b]=a}),k.shim=c);a.packages&&(y(a.packages,function(a){a="string"===typeof a?{name:a}:a;b[a.name]={name:a.name,location:a.location||a.name,main:(a.main||"main").replace(ja,"").replace(ea,"")}}),k.pkgs=b);G(p,function(a,b){!a.inited&&!a.map.unnormalized&&(a.map=j(b))});if(a.deps||a.callback)i.require(a.deps||[],
-a.callback)},makeShimExports:function(a){return function(){var b;a.init&&(b=a.init.apply(aa,arguments));return b||a.exports&&ba(a.exports)}},makeRequire:function(a,f){function d(e,c,h){var g,k;f.enableBuildCallback&&(c&&I(c))&&(c.__requireJsBuild=!0);if("string"===typeof e){if(I(c))return v(B("requireargs","Invalid require call"),h);if(a&&s(N,e))return N[e](p[a.id]);if(l.get)return l.get(i,e,a,d);g=j(e,a,!1,!0);g=g.id;return!s(q,g)?v(B("notloaded",'Module name "'+g+'" has not been loaded yet for context: '+
-b+(a?"":". Use require([])"))):q[g]}L();i.nextTick(function(){L();k=r(j(null,a));k.skipMap=f.skipMap;k.init(e,c,h,{enabled:!0});D()});return d}f=f||{};R(d,{isBrowser:A,toUrl:function(b){var d,f=b.lastIndexOf("."),g=b.split("/")[0];if(-1!==f&&(!("."===g||".."===g)||1h.attachEvent.toString().indexOf("[native code"))&&!Y?(O=!0,h.attachEvent("onreadystatechange",b.onScriptLoad)):(h.addEventListener("load",b.onScriptLoad,!1),h.addEventListener("error",b.onScriptError,!1)),h.src=d,K=h,D?x.insertBefore(h,D):x.appendChild(h),K=null,h;if(da)try{importScripts(d),b.completeLoad(c)}catch(j){b.onError(B("importscripts","importScripts failed for "+c+" at "+d,j,[c]))}};A&&M(document.getElementsByTagName("script"),function(b){x||(x=
-b.parentNode);if(t=b.getAttribute("data-main"))return r.baseUrl||(E=t.split("/"),Q=E.pop(),fa=E.length?E.join("/")+"/":"./",r.baseUrl=fa,t=Q),t=t.replace(ea,""),r.deps=r.deps?r.deps.concat(t):[t],!0});define=function(b,c,d){var l,h;"string"!==typeof b&&(d=c,c=b,b=null);J(c)||(d=c,c=[]);!c.length&&I(d)&&d.length&&(d.toString().replace(la,"").replace(ma,function(b,d){c.push(d)}),c=(1===d.length?["require"]:["require","exports","module"]).concat(c));if(O){if(!(l=K))P&&"interactive"===P.readyState||M(document.getElementsByTagName("script"),
-function(b){if("interactive"===b.readyState)return P=b}),l=P;l&&(b||(b=l.getAttribute("data-requiremodule")),h=F[l.getAttribute("data-requirecontext")])}(h?h.defQueue:T).push([b,c,d])};define.amd={jQuery:!0};l.exec=function(b){return eval(b)};l(r)}})(this);
diff --git a/test/lib/resemble.js b/test/lib/resemble.js
new file mode 100644
index 0000000..1cb8c29
--- /dev/null
+++ b/test/lib/resemble.js
@@ -0,0 +1,535 @@
+/*
+Author: James Cryer
+Company: Huddle
+Last updated date: 21 Feb 2013
+URL: https://github.com/Huddle/Resemble.js
+*/
+
+(function(_this){
+ 'use strict';
+
+ _this['resemble'] = function( fileData ){
+
+ var data = {};
+ var images = [];
+ var updateCallbackArray = [];
+
+ var tolerance = { // between 0 and 255
+ red: 16,
+ green: 16,
+ blue: 16,
+ minBrightness: 16,
+ maxBrightness: 240
+ };
+
+ var ignoreAntialiasing = false;
+ var ignoreColors = false;
+
+ function triggerDataUpdate(){
+ var len = updateCallbackArray.length;
+ var i;
+ for(i=0;i tolerance.maxBrightness;
+ }
+
+ function getHue(r,g,b){
+
+ r = r / 255;
+ g = g / 255;
+ b = b / 255;
+ var max = Math.max(r, g, b), min = Math.min(r, g, b);
+ var h;
+ var d;
+
+ if (max == min){
+ h = 0; // achromatic
+ } else{
+ d = max - min;
+ switch(max){
+ case r: h = (g - b) / d + (g < b ? 6 : 0); break;
+ case g: h = (b - r) / d + 2; break;
+ case b: h = (r - g) / d + 4; break;
+ }
+ h /= 6;
+ }
+
+ return h;
+ }
+
+ function isAntialiased(sourcePix, data, cacheSet, verticalPos, horizontalPos, width){
+ var offset;
+ var targetPix;
+ var distance = 1;
+ var i;
+ var j;
+ var hasHighContrastSibling = 0;
+ var hasSiblingWithDifferentHue = 0;
+ var hasEquivilantSibling = 0;
+
+ addHueInfo(sourcePix);
+
+ for (i = distance*-1; i <= distance; i++){
+ for (j = distance*-1; j <= distance; j++){
+
+ if(i===0 && j===0){
+ // ignore source pixel
+ } else {
+
+ offset = ((verticalPos+j)*width + (horizontalPos+i)) * 4;
+ targetPix = getPixelInfo(data, offset, cacheSet);
+
+ if(targetPix === null){
+ continue;
+ }
+
+ addBrightnessInfo(targetPix);
+ addHueInfo(targetPix);
+
+ if( isContrasting(sourcePix, targetPix) ){
+ hasHighContrastSibling++;
+ }
+
+ if( isRGBSame(sourcePix,targetPix) ){
+ hasEquivilantSibling++;
+ }
+
+ if( Math.abs(targetPix.h - sourcePix.h) > 0.3 ){
+ hasSiblingWithDifferentHue++;
+ }
+
+ if( hasSiblingWithDifferentHue > 1 || hasHighContrastSibling > 1){
+ return true;
+ }
+ }
+ }
+ }
+
+ if(hasEquivilantSibling < 2){
+ return true;
+ }
+
+ return false;
+ }
+
+ function errorPixel(px, offset){
+ px[offset] = 255; //r
+ px[offset + 1] = 0; //g
+ px[offset + 2] = 255; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyPixel(px, offset, data){
+ px[offset] = data.r; //r
+ px[offset + 1] = data.g; //g
+ px[offset + 2] = data.b; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyGrayScalePixel(px, offset, data){
+ px[offset] = data.brightness; //r
+ px[offset + 1] = data.brightness; //g
+ px[offset + 2] = data.brightness; //b
+ px[offset + 3] = 255; //a
+ }
+
+
+ function getPixelInfo(data, offset, cacheSet){
+ var r;
+ var g;
+ var b;
+ var d;
+
+ if(typeof data[offset] !== 'undefined'){
+ r = data[offset];
+ g = data[offset+1];
+ b = data[offset+2];
+ d = {
+ r: r,
+ g: g,
+ b: b
+ };
+
+ return d;
+ } else {
+ return null;
+ }
+ }
+
+ function addBrightnessInfo(data){
+ data.brightness = getBrightness(data.r,data.g,data.b); // 'corrected' lightness
+ }
+
+ function addHueInfo(data){
+ data.h = getHue(data.r,data.g,data.b);
+ }
+
+ function analyseImages(img1, img2, width, height){
+
+ var hiddenCanvas = document.createElement('canvas');
+
+ var data1 = img1.data;
+ var data2 = img2.data;
+
+ hiddenCanvas.width = width;
+ hiddenCanvas.height = height;
+
+ var context = hiddenCanvas.getContext('2d');
+ var imgd = context.createImageData(width,height);
+ var targetPix = imgd.data;
+
+ var mismatchCount = 0;
+
+ var time = Date.now();
+
+ var skip;
+
+ if( (width > 1200 || height > 1200) && ignoreAntialiasing){
+ skip = 6;
+ }
+
+ loop(height, width, function(verticalPos, horizontalPos){
+
+ if(skip){ // only skip if the image isn't small
+ if(verticalPos % skip === 0 || horizontalPos % skip === 0){
+ return;
+ }
+ }
+
+ var offset = (verticalPos*width + horizontalPos) * 4;
+ var pixel1 = getPixelInfo(data1, offset, 1);
+ var pixel2 = getPixelInfo(data2, offset, 2);
+
+ if(pixel1 === null || pixel2 === null){
+ return;
+ }
+
+ if (ignoreColors){
+
+ addBrightnessInfo(pixel1);
+ addBrightnessInfo(pixel2);
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ return;
+ }
+
+ if( isRGBSimilar(pixel1, pixel2) ){
+ copyPixel(targetPix, offset, pixel2);
+
+ } else if( ignoreAntialiasing && (
+ addBrightnessInfo(pixel1), // jit pixel info augmentation looks a little weird, sorry.
+ addBrightnessInfo(pixel2),
+ isAntialiased(pixel1, data1, 1, verticalPos, horizontalPos, width) ||
+ isAntialiased(pixel2, data2, 2, verticalPos, horizontalPos, width)
+ )){
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+
+ });
+
+ data.misMatchPercentage = (mismatchCount / (height*width) * 100).toFixed(2);
+ data.analysisTime = Date.now() - time;
+
+ data.getImageDataUrl = function(text){
+ var barHeight = 0;
+
+ if(text){
+ barHeight = addLabel(text,context,hiddenCanvas);
+ }
+
+ context.putImageData(imgd, 0, barHeight);
+
+ return hiddenCanvas.toDataURL("image/png");
+ };
+ }
+
+ function addLabel(text, context, hiddenCanvas){
+ var textPadding = 2;
+
+ context.font = '12px sans-serif';
+
+ var textWidth = context.measureText(text).width + textPadding*2;
+ var barHeight = 22;
+
+ if(textWidth > hiddenCanvas.width){
+ hiddenCanvas.width = textWidth;
+ }
+
+ hiddenCanvas.height += barHeight;
+
+ context.fillStyle = "#666";
+ context.fillRect(0,0,hiddenCanvas.width,barHeight -4);
+ context.fillStyle = "#fff";
+ context.fillRect(0,barHeight -4,hiddenCanvas.width, 4);
+
+ context.fillStyle = "#fff";
+ context.textBaseline = "top";
+ context.font = '12px sans-serif';
+ context.fillText(text, textPadding, 1);
+
+ return barHeight;
+ }
+
+ function normalise(img, w, h){
+ var c;
+ var context;
+
+ if(img.height < h || img.width < w){
+ c = document.createElement('canvas');
+ c.width = w;
+ c.height = h;
+ context = c.getContext('2d');
+ context.putImageData(img, 0, 0);
+ return context.getImageData(0, 0, w, h);
+ }
+
+ return img;
+ }
+
+ function compare(one, two){
+
+ function onceWeHaveBoth(){
+ var width;
+ var height;
+ if(images.length === 2){
+ width = images[0].width > images[1].width ? images[0].width : images[1].width;
+ height = images[0].height > images[1].height ? images[0].height : images[1].height;
+
+ if( (images[0].width === images[1].width) && (images[0].height === images[1].height) ){
+ data.isSameDimensions = true;
+ } else {
+ data.isSameDimensions = false;
+ }
+
+ analyseImages( normalise(images[0],width, height), normalise(images[1],width, height), width, height);
+
+ triggerDataUpdate();
+ }
+ }
+
+ images = [];
+ loadImageData(one, onceWeHaveBoth);
+ loadImageData(two, onceWeHaveBoth);
+ }
+
+ function getCompareApi(param){
+
+ var secondFileData,
+ hasMethod = typeof param === 'function';
+
+ if( !hasMethod ){
+ // assume it's file data
+ secondFileData = param;
+ }
+
+ var self = {
+ ignoreNothing: function(){
+
+ tolerance.red = 16;
+ tolerance.green = 16;
+ tolerance.blue = 16;
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreAntialiasing: function(){
+
+ tolerance.red = 32;
+ tolerance.green = 32;
+ tolerance.blue = 32;
+ tolerance.minBrightness = 64;
+ tolerance.maxBrightness = 96;
+
+ ignoreAntialiasing = true;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreColors: function(){
+
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = true;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ onComplete: function( callback ){
+
+ updateCallbackArray.push(callback);
+
+ var wrapper = function(){
+ compare(fileData, secondFileData);
+ };
+
+ wrapper();
+
+ return getCompareApi(wrapper);
+ }
+ };
+
+ return self;
+ }
+
+ return {
+ onComplete: function( callback ){
+ updateCallbackArray.push(callback);
+ loadImageData(fileData, function(imageData, width, height){
+ parseImage(imageData.data, width, height);
+ });
+ },
+ compareTo: function(secondFileData){
+ return getCompareApi(secondFileData);
+ }
+ };
+
+ };
+}(this));
\ No newline at end of file
diff --git a/test/testsuite.js b/test/testsuite.js
deleted file mode 100644
index b486acb..0000000
--- a/test/testsuite.js
+++ /dev/null
@@ -1,36 +0,0 @@
-requirejs.config({
- baseUrl: '/test/unit/'
-});
-
-define(function(require) {
- var testModules = [
- 'Pixi',
- 'Point',
- 'Rectangle',
- 'DisplayObject',
- 'DisplayObjectContainer',
- 'Sprite',
- 'MovieClip',
- 'InteractionManager',
- 'Stage',
- 'utils/Utils',
- 'utils/EventTarget',
- 'utils/Matrix',
- 'utils/Detector',
- 'renderers/WebGLShaders',
- 'renderers/WebGLRenderer',
- 'renderers/WebGLBatch',
- 'renderers/CanvasRenderer',
- 'extras/Strip',
- 'extras/Rope',
- 'textures/BaseTexture',
- 'textures/Texture',
- 'loaders/SpriteSheetLoader',
- 'loaders/AssetLoader'
- ];
-
- // Resolve all testModules and then start the Test Runner.
- require(testModules, function() {
- QUnit.start();
- });
-});
\ No newline at end of file
diff --git a/test/textures/SpriteSheet-Aliens.png b/test/textures/SpriteSheet-Aliens.png
new file mode 100644
index 0000000..210acb1
--- /dev/null
+++ b/test/textures/SpriteSheet-Aliens.png
Binary files differ
diff --git a/test/textures/SpriteSheet-Explosion.png b/test/textures/SpriteSheet-Explosion.png
new file mode 100755
index 0000000..79e1a69
--- /dev/null
+++ b/test/textures/SpriteSheet-Explosion.png
Binary files differ
diff --git a/test/textures/bunny.png b/test/textures/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/textures/bunny.png
Binary files differ
diff --git a/test/unit/DisplayObject.js b/test/unit/DisplayObject.js
deleted file mode 100644
index 5e7e72f..0000000
--- a/test/unit/DisplayObject.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObject');
-});
diff --git a/test/unit/DisplayObjectContainer.js b/test/unit/DisplayObjectContainer.js
deleted file mode 100644
index b323959..0000000
--- a/test/unit/DisplayObjectContainer.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObjectContainer');
-});
diff --git a/test/unit/InteractionManager.js b/test/unit/InteractionManager.js
deleted file mode 100644
index e751f52..0000000
--- a/test/unit/InteractionManager.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('InteractionManager');
-});
diff --git a/test/unit/MovieClip.js b/test/unit/MovieClip.js
deleted file mode 100644
index 37d9446..0000000
--- a/test/unit/MovieClip.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('MovieClip');
-});
diff --git a/.gitignore b/.gitignore
index 12e1b62..0b88317 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
node_modules
.DS_Store
-.project
\ No newline at end of file
+.project
+*.log
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..63e4d7c
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,8 @@
+language: node_js
+node_js:
+ - 0.10
+
+before_script:
+ - npm install -g grunt-cli
+ - export DISPLAY=:99.0
+ - sh -e /etc/init.d/xvfb start
diff --git a/Gruntfile.js b/Gruntfile.js
index b083b49..103938c 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -1,10 +1,12 @@
+'use strict';
+
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-connect');
- grunt.loadNpmTasks('grunt-contrib-qunit');
grunt.loadNpmTasks('grunt-contrib-yuidoc');
+ grunt.loadTasks('tasks');
var root = 'src/pixi/',
debug = 'bin/pixi.dev.js',
@@ -79,7 +81,7 @@
},
files: {
srcBlob: '<%= dirs.src %>/**/*.js',
- testBlob: '<%= dirs.test %>/unit/**/*.js',
+ testBlob: '<%= dirs.test %>/{functional,lib/pixi,unit}/**/*.js',
build: '<%= dirs.build %>/pixi.dev.js',
buildMin: '<%= dirs.build %>/pixi.js'
},
@@ -94,7 +96,12 @@
},
jshint: {
beforeconcat: srcFiles,
- test: ['<%= files.testBlob %>'],
+ test: {
+ src: ['<%= files.testBlob %>'],
+ options: {
+ expr: true
+ }
+ },
options: {
asi: true,
smarttabs: true
@@ -128,12 +135,6 @@
]
},
connect: {
- qunit: {
- options: {
- port: grunt.option('port-test') || 9002,
- base: './'
- }
- },
test: {
options: {
port: grunt.option('port-test') || 9002,
@@ -142,13 +143,6 @@
}
}
},
- qunit: {
- all: {
- options: {
- urls: ['http://localhost:' + (grunt.option('port-test') || 9002) + '/test/index.html']
- }
- }
- },
yuidoc: {
compile: {
name: '<%= pkg.name %>',
@@ -161,6 +155,13 @@
outdir: '<%= dirs.docs %>'
}
}
+ },
+ karma: {
+ unit: {
+ configFile: 'test/karma.conf.js',
+ // browsers: ['Chrome'],
+ singleRun: true
+ }
}
});
@@ -182,9 +183,10 @@
}
)
- grunt.registerTask('default', ['concat', 'uglify', 'distribute']);
grunt.registerTask('build', ['concat', 'uglify', 'distribute']);
- grunt.registerTask('test', ['build', 'connect:qunit', 'qunit']);
+ grunt.registerTask('test', ['concat', 'jshint:test', 'karma']);
grunt.registerTask('docs', ['yuidoc']);
-
-}
\ No newline at end of file
+ grunt.registerTask('default', ['test', 'uglify', 'distribute']);
+ // Travis CI task.
+ grunt.registerTask('travis', ['test']);
+}
diff --git a/README.md b/README.md
index c62ef86..690cfe4 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,8 @@

+[](http://travis-ci.org/drkibitz/pixi.js)
+
#### JavaScript 2D Renderer ####
The aim of this project is to provide a fast lightweight 2D library that works
diff --git a/package.json b/package.json
index b373240..1246a68 100644
--- a/package.json
+++ b/package.json
@@ -18,14 +18,21 @@
"main": "bin/pixi.js",
+ "scripts": {
+ "test": "grunt travis --verbose"
+ },
+
"dependencies": {},
"devDependencies": {
"grunt": "~0.4.x",
- "grunt-contrib-jshint": "0.3.x",
+ "grunt-contrib-jshint": "0.6.x",
"grunt-contrib-uglify": "0.2.x",
- "grunt-contrib-connect": "0.2.x",
- "grunt-contrib-qunit": "0.2.x",
+ "grunt-contrib-connect": "0.3.x",
"grunt-contrib-yuidoc": "0.4.x",
- "grunt-contrib-concat": "0.1.x"
+ "grunt-contrib-concat": "0.3.x",
+ "chai": "~1.7.0",
+ "karma": "0.11.0",
+ "karma-firefox-launcher": "0.1.0",
+ "karma-mocha": "0.1.0"
}
}
diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js
index a7c520e..ee82bbd 100644
--- a/src/pixi/InteractionManager.js
+++ b/src/pixi/InteractionManager.js
@@ -62,7 +62,6 @@
this.onTouchEnd = this.onTouchEnd.bind(this);
this.onTouchMove = this.onTouchMove.bind(this);
-
this.last = 0;
}
diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js
index 1a95d20..eef1059 100644
--- a/src/pixi/core/Ellipse.js
+++ b/src/pixi/core/Ellipse.js
@@ -78,7 +78,7 @@
return (normx + normy < 0.25);
}
-PIXI.Ellipse.getBounds = function()
+PIXI.Ellipse.prototype.getBounds = function()
{
return new PIXI.Rectangle(this.x, this.y, this.width, this.height);
}
diff --git a/tasks/karma.js b/tasks/karma.js
new file mode 100644
index 0000000..c340485
--- /dev/null
+++ b/tasks/karma.js
@@ -0,0 +1,27 @@
+'use strict';
+
+var path = require('path');
+var server = require('karma').server;
+
+module.exports = function (grunt) {
+ grunt.registerMultiTask('karma', 'run karma.', function() {
+ var done = this.async();
+ var options = this.options({
+ background: false
+ });
+ var data = this.data;
+
+ //merge options onto data, with data taking precedence
+ data = grunt.util._.merge(options, data);
+ data.configFile = path.resolve(data.configFile);
+ if (data.configFile) {
+ data.configFile = grunt.template.process(data.configFile);
+ }
+
+ server.start(
+ data,
+ function(code) {
+ done(!code);
+ });
+ });
+};
diff --git a/test/functional/example-1-basics/bunny.png b/test/functional/example-1-basics/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/functional/example-1-basics/bunny.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-30.png b/test/functional/example-1-basics/frame-30.png
new file mode 100644
index 0000000..96e3409
--- /dev/null
+++ b/test/functional/example-1-basics/frame-30.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-60.png b/test/functional/example-1-basics/frame-60.png
new file mode 100644
index 0000000..af3f4ce
--- /dev/null
+++ b/test/functional/example-1-basics/frame-60.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-90.png b/test/functional/example-1-basics/frame-90.png
new file mode 100644
index 0000000..099b823
--- /dev/null
+++ b/test/functional/example-1-basics/frame-90.png
Binary files differ
diff --git a/test/functional/example-1-basics/index.js b/test/functional/example-1-basics/index.js
new file mode 100644
index 0000000..7ae7a98
--- /dev/null
+++ b/test/functional/example-1-basics/index.js
@@ -0,0 +1,133 @@
+describe('Example 1 - Basics', function () {
+ 'use strict';
+
+ var baseUri = '/base/test/functional/example-1-basics';
+ var expect = chai.expect;
+ var currentFrame = 0;
+ var frameEvents = {};
+ var stage;
+ var renderer;
+ var bunny;
+
+ function onFrame(frame, callback) {
+ frameEvents[frame] = callback;
+ }
+
+ function animate() {
+ currentFrame += 1;
+
+ requestAnimFrame( animate );
+
+ // just for fun, lets rotate mr rabbit a little
+ bunny.rotation += 0.1;
+
+ // render the stage
+ renderer.render(stage);
+
+ if (frameEvents[currentFrame])
+ frameEvents[currentFrame](currentFrame);
+ }
+
+ function initScene() {
+ // create an new instance of a pixi stage
+ stage = new PIXI.Stage(0x66FF99);
+
+ // create a renderer instance
+ renderer = PIXI.autoDetectRenderer(400, 300);
+ console.log('Is PIXI.WebGLRenderer: ' + (renderer instanceof PIXI.WebGLRenderer));
+
+ // add the renderer view element to the DOM
+ document.body.appendChild(renderer.view);
+
+ requestAnimFrame( animate );
+
+ // create a texture from an image path
+ var texture = PIXI.Texture.fromImage(baseUri + "/bunny.png");
+ // create a new Sprite using the texture
+ bunny = new PIXI.Sprite(texture);
+
+ // center the sprites anchor point
+ bunny.anchor.x = 0.5;
+ bunny.anchor.y = 0.5;
+
+ // move the sprite t the center of the screen
+ bunny.position.x = 200;
+ bunny.position.y = 150;
+
+ stage.addChild(bunny);
+ }
+
+ it('assets loaded', function (done) {
+ var loader = new PIXI.AssetLoader([
+ baseUri + '/bunny.png',
+ baseUri + '/frame-30.png',
+ baseUri + '/frame-60.png',
+ baseUri + '/frame-90.png'
+ ]);
+ // loader.on('onProgress', function (event) {
+ // console.log(event.content);
+ // });
+ loader.on('onComplete', function (event) {
+ done();
+ initScene();
+ });
+ loader.load();
+ });
+
+ it('frame 30 should match', function (done) {
+ this.timeout(700);
+ onFrame(30, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-30.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 60 should match', function (done) {
+ this.timeout(1200);
+ onFrame(60, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-60.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 90 should match', function (done) {
+ this.timeout(1700);
+ onFrame(90, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-90.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ // it('capture something', function (done) {
+ // this.timeout(2000000);
+ // onFrame(30, function () {
+ // var img = new Image();
+ // img.src = renderer.view.toDataURL('image/png');
+ // document.body.appendChild(img);
+ // });
+ // });
+});
diff --git a/test/index.html b/test/index.html
deleted file mode 100644
index 9cbcac5..0000000
--- a/test/index.html
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
- Pixi.js Test Suite
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/test/karma.conf.js b/test/karma.conf.js
new file mode 100644
index 0000000..c66a696
--- /dev/null
+++ b/test/karma.conf.js
@@ -0,0 +1,82 @@
+module.exports = function(config) {
+ config.set({
+
+ // base path, that will be used to resolve files and exclude
+ basePath : '../',
+
+ frameworks : ['mocha'],
+
+ // list of files / patterns to load in the browser
+ files : [
+ 'node_modules/chai/chai.js',
+ 'bin/pixi.dev.js',
+ 'test/lib/**/*.js',
+ 'test/unit/**/*.js',
+ // 'test/functional/**/*.js',
+ {pattern: 'test/**/*.png', watched: false, included: false, served: true}
+ ],
+
+ // list of files to exclude
+ exclude : [],
+
+ // use dolts reporter, as travis terminal does not support escaping sequences
+ // possible values: 'dots', 'progress', 'junit', 'teamcity'
+ // CLI --reporters progress
+ reporters : ['progress'],
+
+ // web server port
+ // CLI --port 9876
+ port : 9876,
+
+ // cli runner port
+ // CLI --runner-port 9100
+ runnerPort : 9100,
+
+ // enable / disable colors in the output (reporters and logs)
+ // CLI --colors --no-colors
+ colors : true,
+
+ // level of logging
+ // possible values: karma.LOG_DISABLE || karma.LOG_ERROR || karma.LOG_WARN || karma.LOG_INFO || karma.LOG_DEBUG
+ // CLI --log-level debug
+ logLevel : config.LOG_DEBUG,
+
+ // enable / disable watching file and executing tests whenever any file changes
+ // CLI --auto-watch --no-auto-watch
+ autoWatch : false,
+
+ // Start these browsers, currently available:
+ // - Chrome
+ // - ChromeCanary
+ // - Firefox
+ // - Opera
+ // - Safari (only Mac)
+ // - PhantomJS
+ // - IE (only Windows)
+ // CLI --browsers Chrome,Firefox,Safari
+ browsers : ['Firefox'],
+
+ // If browser does not capture in given timeout [ms], kill it
+ // CLI --capture-timeout 5000
+ captureTimeout : 5000,
+
+ // Auto run tests on start (when browsers are captured) and exit
+ // CLI --single-run --no-single-run
+ singleRun : true,
+
+ // report which specs are slower than 500ms
+ // CLI --report-slower-than 500
+ reportSlowerThan : 1000,
+
+ preprocessors : {
+ // '**/client/js/*.js': 'coverage'
+ },
+
+ plugins : [
+ 'karma-mocha',
+ // 'karma-chrome-launcher',
+ 'karma-firefox-launcher',
+ // 'karma-phantomjs-launcher'
+ ]
+ });
+};
diff --git a/test/lib/pixi/core/Matrix.js b/test/lib/pixi/core/Matrix.js
new file mode 100644
index 0000000..d26386b
--- /dev/null
+++ b/test/lib/pixi/core/Matrix.js
@@ -0,0 +1,40 @@
+
+function pixi_core_Matrix_confirmNewMat3(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(1);
+ expect(matrix[5]).to.equal(0);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(1);
+}
+
+function pixi_core_Matrix_confirmNewMat4(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[0]).to.equal(1);
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(0);
+ expect(matrix[5]).to.equal(1);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(0);
+ expect(matrix[9]).to.equal(0);
+ expect(matrix[10]).to.equal(1);
+ expect(matrix[11]).to.equal(0);
+ expect(matrix[12]).to.equal(0);
+ expect(matrix[13]).to.equal(0);
+ expect(matrix[14]).to.equal(0);
+ expect(matrix[15]).to.equal(1);
+}
diff --git a/test/lib/pixi/core/Point.js b/test/lib/pixi/core/Point.js
new file mode 100644
index 0000000..e5df07b
--- /dev/null
+++ b/test/lib/pixi/core/Point.js
@@ -0,0 +1,10 @@
+
+function pixi_core_Point_confirm(obj, x, y) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Point);
+ expect(obj).to.respondTo('clone');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+}
diff --git a/test/lib/pixi/core/Rectangle.js b/test/lib/pixi/core/Rectangle.js
new file mode 100644
index 0000000..23f0d12
--- /dev/null
+++ b/test/lib/pixi/core/Rectangle.js
@@ -0,0 +1,13 @@
+
+function pixi_core_Rectangle_confirm(obj, x, y, width, height) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Rectangle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+ expect(obj).to.have.property('width', width);
+ expect(obj).to.have.property('height', height);
+}
diff --git a/test/lib/pixi/display/DisplayObject.js b/test/lib/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..1388a7f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObject.js
@@ -0,0 +1,43 @@
+
+function pixi_display_DisplayObject_confirmNew(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObject);
+ expect(obj).to.respondTo('setInteractive');
+ expect(obj).to.respondTo('addFilter');
+ expect(obj).to.respondTo('removeFilter');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.property('last', obj);
+ expect(obj).to.have.property('first', obj);
+
+ expect(obj).to.contain.property('position');
+ pixi_core_Point_confirm(obj.position, 0, 0);
+ expect(obj).to.contain.property('scale');
+ pixi_core_Point_confirm(obj.scale, 1, 1);
+ expect(obj).to.contain.property('pivot');
+ pixi_core_Point_confirm(obj.pivot, 0, 0);
+
+ expect(obj).to.have.property('rotation', 0);
+ expect(obj).to.have.property('alpha', 1);
+ expect(obj).to.have.property('visible', true);
+ expect(obj).to.have.property('buttonMode', false);
+ expect(obj).to.have.property('parent', null);
+ expect(obj).to.have.property('worldAlpha', 1);
+
+ expect(obj).to.have.property('hitArea');
+ expect(obj).to.have.property('interactive'); // TODO: Have a better default value
+ expect('mask' in obj).to.be.true; // TODO: Have a better default value
+ expect(obj.mask).to.be.undefined;
+
+ expect(obj).to.have.property('renderable');
+ expect(obj).to.have.property('stage');
+
+ expect(obj).to.have.deep.property('worldTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ expect(obj).to.have.deep.property('localTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.localTransform);
+
+ expect(obj).to.have.deep.property('color.length', 0);
+ expect(obj).to.have.property('dynamic', true);
+}
diff --git a/test/lib/pixi/display/DisplayObjectContainer.js b/test/lib/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..085c59f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,16 @@
+
+function pixi_display_DisplayObjectContainer_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObject_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObjectContainer);
+ expect(obj).to.respondTo('addChild');
+ expect(obj).to.respondTo('addChildAt');
+ expect(obj).to.respondTo('swapChildren');
+ expect(obj).to.respondTo('getChildAt');
+ expect(obj).to.respondTo('removeChild');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('children.length', 0);
+}
diff --git a/test/lib/pixi/display/Sprite.js b/test/lib/pixi/display/Sprite.js
new file mode 100644
index 0000000..cc7a2d6
--- /dev/null
+++ b/test/lib/pixi/display/Sprite.js
@@ -0,0 +1,28 @@
+
+function pixi_display_Sprite_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Sprite);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', true);
+ expect(obj).to.have.property('stage', null);
+
+ expect(obj).to.have.property('anchor');
+ pixi_core_Point_confirm(obj.anchor, 0, 0);
+
+ expect(obj).to.have.property('blendMode', PIXI.blendModes.NORMAL);
+ expect(obj).to.have.property('width', 1); // TODO: is 1 expected
+ expect(obj).to.have.property('height', 1); // TODO: is 1 expected
+
+ // FIXME: Just make this a boolean that is always there
+ expect(!!obj.updateFrame).to.equal(obj.texture.baseTexture.hasLoaded);
+
+ expect(obj).to.have.property('texture');
+ pixi_textures_Texture_confirmNew(obj.texture, done);
+}
diff --git a/test/lib/pixi/extras/Strip.js b/test/lib/pixi/extras/Strip.js
new file mode 100644
index 0000000..8927a8a
--- /dev/null
+++ b/test/lib/pixi/extras/Strip.js
@@ -0,0 +1,12 @@
+
+function pixi_extras_Strip_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Strip);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ // TODO: Test properties
+}
diff --git a/test/lib/pixi/textures/Texture.js b/test/lib/pixi/textures/Texture.js
new file mode 100644
index 0000000..d5867b6
--- /dev/null
+++ b/test/lib/pixi/textures/Texture.js
@@ -0,0 +1,31 @@
+
+function pixi_textures_Texture_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ function confirmFrameDone() {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, obj.baseTexture.width, obj.baseTexture.height);
+
+ expect(obj).to.have.property('width', obj.baseTexture.width);
+ expect(obj).to.have.property('height', obj.baseTexture.height);
+ done();
+ }
+
+ expect(obj).to.be.an.instanceof(PIXI.Texture);
+ pixi_utils_EventTarget_like(obj);
+
+ expect(obj).to.have.property('baseTexture')
+ .and.to.be.an.instanceof(PIXI.BaseTexture);
+
+ expect(obj).to.have.property('scope', obj);
+
+ expect(obj).to.have.property('trim');
+ pixi_core_Point_confirm(obj.trim, 0, 0);
+
+ expect(obj).to.have.property('frame');
+ if (obj.baseTexture.hasLoaded) {
+ confirmFrameDone();
+ } else {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, 1, 1);
+ obj.addEventListener('update', confirmFrameDone);
+ }
+}
diff --git a/test/lib/pixi/utils/EventTarget.js b/test/lib/pixi/utils/EventTarget.js
new file mode 100644
index 0000000..7b1dcfa
--- /dev/null
+++ b/test/lib/pixi/utils/EventTarget.js
@@ -0,0 +1,8 @@
+
+function pixi_utils_EventTarget_like(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.respondTo('addEventListener');
+ expect(obj).to.respondTo('dispatchEvent');
+ expect(obj).to.respondTo('removeEventListener');
+}
diff --git a/test/lib/qunit-1.11.0.css b/test/lib/qunit-1.11.0.css
deleted file mode 100644
index d7fc0c8..0000000
--- a/test/lib/qunit-1.11.0.css
+++ /dev/null
@@ -1,244 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-/** Font Family and Sizes */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
- font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
-}
-
-#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
-#qunit-tests { font-size: smaller; }
-
-
-/** Resets */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter {
- margin: 0;
- padding: 0;
-}
-
-
-/** Header */
-
-#qunit-header {
- padding: 0.5em 0 0.5em 1em;
-
- color: #8699a4;
- background-color: #0d3349;
-
- font-size: 1.5em;
- line-height: 1em;
- font-weight: normal;
-
- border-radius: 5px 5px 0 0;
- -moz-border-radius: 5px 5px 0 0;
- -webkit-border-top-right-radius: 5px;
- -webkit-border-top-left-radius: 5px;
-}
-
-#qunit-header a {
- text-decoration: none;
- color: #c2ccd1;
-}
-
-#qunit-header a:hover,
-#qunit-header a:focus {
- color: #fff;
-}
-
-#qunit-testrunner-toolbar label {
- display: inline-block;
- padding: 0 .5em 0 .1em;
-}
-
-#qunit-banner {
- height: 5px;
-}
-
-#qunit-testrunner-toolbar {
- padding: 0.5em 0 0.5em 2em;
- color: #5E740B;
- background-color: #eee;
- overflow: hidden;
-}
-
-#qunit-userAgent {
- padding: 0.5em 0 0.5em 2.5em;
- background-color: #2b81af;
- color: #fff;
- text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
-}
-
-#qunit-modulefilter-container {
- float: right;
-}
-
-/** Tests: Pass/Fail */
-
-#qunit-tests {
- list-style-position: inside;
-}
-
-#qunit-tests li {
- padding: 0.4em 0.5em 0.4em 2.5em;
- border-bottom: 1px solid #fff;
- list-style-position: inside;
-}
-
-#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running {
- display: none;
-}
-
-#qunit-tests li strong {
- cursor: pointer;
-}
-
-#qunit-tests li a {
- padding: 0.5em;
- color: #c2ccd1;
- text-decoration: none;
-}
-#qunit-tests li a:hover,
-#qunit-tests li a:focus {
- color: #000;
-}
-
-#qunit-tests li .runtime {
- float: right;
- font-size: smaller;
-}
-
-.qunit-assert-list {
- margin-top: 0.5em;
- padding: 0.5em;
-
- background-color: #fff;
-
- border-radius: 5px;
- -moz-border-radius: 5px;
- -webkit-border-radius: 5px;
-}
-
-.qunit-collapsed {
- display: none;
-}
-
-#qunit-tests table {
- border-collapse: collapse;
- margin-top: .2em;
-}
-
-#qunit-tests th {
- text-align: right;
- vertical-align: top;
- padding: 0 .5em 0 0;
-}
-
-#qunit-tests td {
- vertical-align: top;
-}
-
-#qunit-tests pre {
- margin: 0;
- white-space: pre-wrap;
- word-wrap: break-word;
-}
-
-#qunit-tests del {
- background-color: #e0f2be;
- color: #374e0c;
- text-decoration: none;
-}
-
-#qunit-tests ins {
- background-color: #ffcaca;
- color: #500;
- text-decoration: none;
-}
-
-/*** Test Counts */
-
-#qunit-tests b.counts { color: black; }
-#qunit-tests b.passed { color: #5E740B; }
-#qunit-tests b.failed { color: #710909; }
-
-#qunit-tests li li {
- padding: 5px;
- background-color: #fff;
- border-bottom: none;
- list-style-position: inside;
-}
-
-/*** Passing Styles */
-
-#qunit-tests li li.pass {
- color: #3c510c;
- background-color: #fff;
- border-left: 10px solid #C6E746;
-}
-
-#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
-#qunit-tests .pass .test-name { color: #366097; }
-
-#qunit-tests .pass .test-actual,
-#qunit-tests .pass .test-expected { color: #999999; }
-
-#qunit-banner.qunit-pass { background-color: #C6E746; }
-
-/*** Failing Styles */
-
-#qunit-tests li li.fail {
- color: #710909;
- background-color: #fff;
- border-left: 10px solid #EE5757;
- white-space: pre;
-}
-
-#qunit-tests > li:last-child {
- border-radius: 0 0 5px 5px;
- -moz-border-radius: 0 0 5px 5px;
- -webkit-border-bottom-right-radius: 5px;
- -webkit-border-bottom-left-radius: 5px;
-}
-
-#qunit-tests .fail { color: #000000; background-color: #EE5757; }
-#qunit-tests .fail .test-name,
-#qunit-tests .fail .module-name { color: #000000; }
-
-#qunit-tests .fail .test-actual { color: #EE5757; }
-#qunit-tests .fail .test-expected { color: green; }
-
-#qunit-banner.qunit-fail { background-color: #EE5757; }
-
-
-/** Result */
-
-#qunit-testresult {
- padding: 0.5em 0.5em 0.5em 2.5em;
-
- color: #2b81af;
- background-color: #D2E0E6;
-
- border-bottom: 1px solid white;
-}
-#qunit-testresult .module-name {
- font-weight: bold;
-}
-
-/** Fixture */
-
-#qunit-fixture {
- position: absolute;
- top: -10000px;
- left: -10000px;
- width: 1000px;
- height: 1000px;
-}
diff --git a/test/lib/qunit-1.11.0.js b/test/lib/qunit-1.11.0.js
deleted file mode 100644
index 302545f..0000000
--- a/test/lib/qunit-1.11.0.js
+++ /dev/null
@@ -1,2152 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-(function( window ) {
-
-var QUnit,
- assert,
- config,
- onErrorFnPrev,
- testId = 0,
- fileName = (sourceFromStacktrace( 0 ) || "" ).replace(/(:\d+)+\)?/, "").replace(/.+\//, ""),
- toString = Object.prototype.toString,
- hasOwn = Object.prototype.hasOwnProperty,
- // Keep a local reference to Date (GH-283)
- Date = window.Date,
- defined = {
- setTimeout: typeof window.setTimeout !== "undefined",
- sessionStorage: (function() {
- var x = "qunit-test-string";
- try {
- sessionStorage.setItem( x, x );
- sessionStorage.removeItem( x );
- return true;
- } catch( e ) {
- return false;
- }
- }())
- },
- /**
- * Provides a normalized error string, correcting an issue
- * with IE 7 (and prior) where Error.prototype.toString is
- * not properly implemented
- *
- * Based on http://es5.github.com/#x15.11.4.4
- *
- * @param {String|Error} error
- * @return {String} error message
- */
- errorString = function( error ) {
- var name, message,
- errorString = error.toString();
- if ( errorString.substring( 0, 7 ) === "[object" ) {
- name = error.name ? error.name.toString() : "Error";
- message = error.message ? error.message.toString() : "";
- if ( name && message ) {
- return name + ": " + message;
- } else if ( name ) {
- return name;
- } else if ( message ) {
- return message;
- } else {
- return "Error";
- }
- } else {
- return errorString;
- }
- },
- /**
- * Makes a clone of an object using only Array or Object as base,
- * and copies over the own enumerable properties.
- *
- * @param {Object} obj
- * @return {Object} New object with only the own properties (recursively).
- */
- objectValues = function( obj ) {
- // Grunt 0.3.x uses an older version of jshint that still has jshint/jshint#392.
- /*jshint newcap: false */
- var key, val,
- vals = QUnit.is( "array", obj ) ? [] : {};
- for ( key in obj ) {
- if ( hasOwn.call( obj, key ) ) {
- val = obj[key];
- vals[key] = val === Object(val) ? objectValues(val) : val;
- }
- }
- return vals;
- };
-
-function Test( settings ) {
- extend( this, settings );
- this.assertions = [];
- this.testNumber = ++Test.count;
-}
-
-Test.count = 0;
-
-Test.prototype = {
- init: function() {
- var a, b, li,
- tests = id( "qunit-tests" );
-
- if ( tests ) {
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml;
-
- // `a` initialized at top of scope
- a = document.createElement( "a" );
- a.innerHTML = "Rerun";
- a.href = QUnit.url({ testNumber: this.testNumber });
-
- li = document.createElement( "li" );
- li.appendChild( b );
- li.appendChild( a );
- li.className = "running";
- li.id = this.id = "qunit-test-output" + testId++;
-
- tests.appendChild( li );
- }
- },
- setup: function() {
- if ( this.module !== config.previousModule ) {
- if ( config.previousModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.previousModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
- config.previousModule = this.module;
- config.moduleStats = { all: 0, bad: 0 };
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- } else if ( config.autorun ) {
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- }
-
- config.current = this;
-
- this.testEnvironment = extend({
- setup: function() {},
- teardown: function() {}
- }, this.moduleTestEnvironment );
-
- this.started = +new Date();
- runLoggingCallbacks( "testStart", QUnit, {
- name: this.testName,
- module: this.module
- });
-
- // allow utility functions to access the current test environment
- // TODO why??
- QUnit.current_testEnvironment = this.testEnvironment;
-
- if ( !config.pollution ) {
- saveGlobal();
- }
- if ( config.notrycatch ) {
- this.testEnvironment.setup.call( this.testEnvironment );
- return;
- }
- try {
- this.testEnvironment.setup.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Setup failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- },
- run: function() {
- config.current = this;
-
- var running = id( "qunit-testresult" );
-
- if ( running ) {
- running.innerHTML = "Running:
" + this.nameHtml;
- }
-
- if ( this.async ) {
- QUnit.stop();
- }
-
- this.callbackStarted = +new Date();
-
- if ( config.notrycatch ) {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- return;
- }
-
- try {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- } catch( e ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
-
- QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + " " + this.stack + ": " + ( e.message || e ), extractStacktrace( e, 0 ) );
- // else next test will carry the responsibility
- saveGlobal();
-
- // Restart the tests if they're blocking
- if ( config.blocking ) {
- QUnit.start();
- }
- }
- },
- teardown: function() {
- config.current = this;
- if ( config.notrycatch ) {
- if ( typeof this.callbackRuntime === "undefined" ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
- }
- this.testEnvironment.teardown.call( this.testEnvironment );
- return;
- } else {
- try {
- this.testEnvironment.teardown.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Teardown failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- }
- checkPollution();
- },
- finish: function() {
- config.current = this;
- if ( config.requireExpects && this.expected === null ) {
- QUnit.pushFailure( "Expected number of assertions to be defined, but expect() was not called.", this.stack );
- } else if ( this.expected !== null && this.expected !== this.assertions.length ) {
- QUnit.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack );
- } else if ( this.expected === null && !this.assertions.length ) {
- QUnit.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions.", this.stack );
- }
-
- var i, assertion, a, b, time, li, ol,
- test = this,
- good = 0,
- bad = 0,
- tests = id( "qunit-tests" );
-
- this.runtime = +new Date() - this.started;
- config.stats.all += this.assertions.length;
- config.moduleStats.all += this.assertions.length;
-
- if ( tests ) {
- ol = document.createElement( "ol" );
- ol.className = "qunit-assert-list";
-
- for ( i = 0; i < this.assertions.length; i++ ) {
- assertion = this.assertions[i];
-
- li = document.createElement( "li" );
- li.className = assertion.result ? "pass" : "fail";
- li.innerHTML = assertion.message || ( assertion.result ? "okay" : "failed" );
- ol.appendChild( li );
-
- if ( assertion.result ) {
- good++;
- } else {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
-
- // store result when possible
- if ( QUnit.config.reorder && defined.sessionStorage ) {
- if ( bad ) {
- sessionStorage.setItem( "qunit-test-" + this.module + "-" + this.testName, bad );
- } else {
- sessionStorage.removeItem( "qunit-test-" + this.module + "-" + this.testName );
- }
- }
-
- if ( bad === 0 ) {
- addClass( ol, "qunit-collapsed" );
- }
-
- // `b` initialized at top of scope
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml + " (" + bad + ", " + good + ", " + this.assertions.length + ")";
-
- addEvent(b, "click", function() {
- var next = b.parentNode.lastChild,
- collapsed = hasClass( next, "qunit-collapsed" );
- ( collapsed ? removeClass : addClass )( next, "qunit-collapsed" );
- });
-
- addEvent(b, "dblclick", function( e ) {
- var target = e && e.target ? e.target : window.event.srcElement;
- if ( target.nodeName.toLowerCase() === "span" || target.nodeName.toLowerCase() === "b" ) {
- target = target.parentNode;
- }
- if ( window.location && target.nodeName.toLowerCase() === "strong" ) {
- window.location = QUnit.url({ testNumber: test.testNumber });
- }
- });
-
- // `time` initialized at top of scope
- time = document.createElement( "span" );
- time.className = "runtime";
- time.innerHTML = this.runtime + " ms";
-
- // `li` initialized at top of scope
- li = id( this.id );
- li.className = bad ? "fail" : "pass";
- li.removeChild( li.firstChild );
- a = li.firstChild;
- li.appendChild( b );
- li.appendChild( a );
- li.appendChild( time );
- li.appendChild( ol );
-
- } else {
- for ( i = 0; i < this.assertions.length; i++ ) {
- if ( !this.assertions[i].result ) {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
- }
-
- runLoggingCallbacks( "testDone", QUnit, {
- name: this.testName,
- module: this.module,
- failed: bad,
- passed: this.assertions.length - bad,
- total: this.assertions.length,
- duration: this.runtime
- });
-
- QUnit.reset();
-
- config.current = undefined;
- },
-
- queue: function() {
- var bad,
- test = this;
-
- synchronize(function() {
- test.init();
- });
- function run() {
- // each of these can by async
- synchronize(function() {
- test.setup();
- });
- synchronize(function() {
- test.run();
- });
- synchronize(function() {
- test.teardown();
- });
- synchronize(function() {
- test.finish();
- });
- }
-
- // `bad` initialized at top of scope
- // defer when previous test run passed, if storage is available
- bad = QUnit.config.reorder && defined.sessionStorage &&
- +sessionStorage.getItem( "qunit-test-" + this.module + "-" + this.testName );
-
- if ( bad ) {
- run();
- } else {
- synchronize( run, true );
- }
- }
-};
-
-// Root QUnit object.
-// `QUnit` initialized at top of scope
-QUnit = {
-
- // call on start of module test to prepend name to all tests
- module: function( name, testEnvironment ) {
- config.currentModule = name;
- config.currentModuleTestEnvironment = testEnvironment;
- config.modules[name] = true;
- },
-
- asyncTest: function( testName, expected, callback ) {
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- QUnit.test( testName, expected, callback, true );
- },
-
- test: function( testName, expected, callback, async ) {
- var test,
- nameHtml = "" + escapeText( testName ) + "";
-
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- if ( config.currentModule ) {
- nameHtml = "" + escapeText( config.currentModule ) + ": " + nameHtml;
- }
-
- test = new Test({
- nameHtml: nameHtml,
- testName: testName,
- expected: expected,
- async: async,
- callback: callback,
- module: config.currentModule,
- moduleTestEnvironment: config.currentModuleTestEnvironment,
- stack: sourceFromStacktrace( 2 )
- });
-
- if ( !validTest( test ) ) {
- return;
- }
-
- test.queue();
- },
-
- // Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through.
- expect: function( asserts ) {
- if (arguments.length === 1) {
- config.current.expected = asserts;
- } else {
- return config.current.expected;
- }
- },
-
- start: function( count ) {
- // QUnit hasn't been initialized yet.
- // Note: RequireJS (et al) may delay onLoad
- if ( config.semaphore === undefined ) {
- QUnit.begin(function() {
- // This is triggered at the top of QUnit.load, push start() to the event loop, to allow QUnit.load to finish first
- setTimeout(function() {
- QUnit.start( count );
- });
- });
- return;
- }
-
- config.semaphore -= count || 1;
- // don't start until equal number of stop-calls
- if ( config.semaphore > 0 ) {
- return;
- }
- // ignore if start is called more often then stop
- if ( config.semaphore < 0 ) {
- config.semaphore = 0;
- QUnit.pushFailure( "Called start() while already started (QUnit.config.semaphore was 0 already)", null, sourceFromStacktrace(2) );
- return;
- }
- // A slight delay, to avoid any current callbacks
- if ( defined.setTimeout ) {
- window.setTimeout(function() {
- if ( config.semaphore > 0 ) {
- return;
- }
- if ( config.timeout ) {
- clearTimeout( config.timeout );
- }
-
- config.blocking = false;
- process( true );
- }, 13);
- } else {
- config.blocking = false;
- process( true );
- }
- },
-
- stop: function( count ) {
- config.semaphore += count || 1;
- config.blocking = true;
-
- if ( config.testTimeout && defined.setTimeout ) {
- clearTimeout( config.timeout );
- config.timeout = window.setTimeout(function() {
- QUnit.ok( false, "Test timed out" );
- config.semaphore = 1;
- QUnit.start();
- }, config.testTimeout );
- }
- }
-};
-
-// `assert` initialized at top of scope
-// Asssert helpers
-// All of these must either call QUnit.push() or manually do:
-// - runLoggingCallbacks( "log", .. );
-// - config.current.assertions.push({ .. });
-// We attach it to the QUnit object *after* we expose the public API,
-// otherwise `assert` will become a global variable in browsers (#341).
-assert = {
- /**
- * Asserts rough true-ish result.
- * @name ok
- * @function
- * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" );
- */
- ok: function( result, msg ) {
- if ( !config.current ) {
- throw new Error( "ok() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
- result = !!result;
-
- var source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: msg
- };
-
- msg = escapeText( msg || (result ? "okay" : "failed" ) );
- msg = "" + msg + "";
-
- if ( !result ) {
- source = sourceFromStacktrace( 2 );
- if ( source ) {
- details.source = source;
- msg += "Source: | " + escapeText( source ) + " |
---|
";
- }
- }
- runLoggingCallbacks( "log", QUnit, details );
- config.current.assertions.push({
- result: result,
- message: msg
- });
- },
-
- /**
- * Assert that the first two arguments are equal, with an optional message.
- * Prints out both actual and expected values.
- * @name equal
- * @function
- * @example equal( format( "Received {0} bytes.", 2), "Received 2 bytes.", "format() replaces {0} with next argument" );
- */
- equal: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected == actual, actual, expected, message );
- },
-
- /**
- * @name notEqual
- * @function
- */
- notEqual: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected != actual, actual, expected, message );
- },
-
- /**
- * @name propEqual
- * @function
- */
- propEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notPropEqual
- * @function
- */
- notPropEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name deepEqual
- * @function
- */
- deepEqual: function( actual, expected, message ) {
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notDeepEqual
- * @function
- */
- notDeepEqual: function( actual, expected, message ) {
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name strictEqual
- * @function
- */
- strictEqual: function( actual, expected, message ) {
- QUnit.push( expected === actual, actual, expected, message );
- },
-
- /**
- * @name notStrictEqual
- * @function
- */
- notStrictEqual: function( actual, expected, message ) {
- QUnit.push( expected !== actual, actual, expected, message );
- },
-
- "throws": function( block, expected, message ) {
- var actual,
- expectedOutput = expected,
- ok = false;
-
- // 'expected' is optional
- if ( typeof expected === "string" ) {
- message = expected;
- expected = null;
- }
-
- config.current.ignoreGlobalErrors = true;
- try {
- block.call( config.current.testEnvironment );
- } catch (e) {
- actual = e;
- }
- config.current.ignoreGlobalErrors = false;
-
- if ( actual ) {
- // we don't want to validate thrown error
- if ( !expected ) {
- ok = true;
- expectedOutput = null;
- // expected is a regexp
- } else if ( QUnit.objectType( expected ) === "regexp" ) {
- ok = expected.test( errorString( actual ) );
- // expected is a constructor
- } else if ( actual instanceof expected ) {
- ok = true;
- // expected is a validation function which returns true is validation passed
- } else if ( expected.call( {}, actual ) === true ) {
- expectedOutput = null;
- ok = true;
- }
-
- QUnit.push( ok, actual, expectedOutput, message );
- } else {
- QUnit.pushFailure( message, null, 'No exception was thrown.' );
- }
- }
-};
-
-/**
- * @deprecate since 1.8.0
- * Kept assertion helpers in root for backwards compatibility.
- */
-extend( QUnit, assert );
-
-/**
- * @deprecated since 1.9.0
- * Kept root "raises()" for backwards compatibility.
- * (Note that we don't introduce assert.raises).
- */
-QUnit.raises = assert[ "throws" ];
-
-/**
- * @deprecated since 1.0.0, replaced with error pushes since 1.3.0
- * Kept to avoid TypeErrors for undefined methods.
- */
-QUnit.equals = function() {
- QUnit.push( false, false, false, "QUnit.equals has been deprecated since 2009 (e88049a0), use QUnit.equal instead" );
-};
-QUnit.same = function() {
- QUnit.push( false, false, false, "QUnit.same has been deprecated since 2009 (e88049a0), use QUnit.deepEqual instead" );
-};
-
-// We want access to the constructor's prototype
-(function() {
- function F() {}
- F.prototype = QUnit;
- QUnit = new F();
- // Make F QUnit's constructor so that we can add to the prototype later
- QUnit.constructor = F;
-}());
-
-/**
- * Config object: Maintain internal state
- * Later exposed as QUnit.config
- * `config` initialized at top of scope
- */
-config = {
- // The queue of tests to run
- queue: [],
-
- // block until document ready
- blocking: true,
-
- // when enabled, show only failing tests
- // gets persisted through sessionStorage and can be changed in UI via checkbox
- hidepassed: false,
-
- // by default, run previously failed tests first
- // very useful in combination with "Hide passed tests" checked
- reorder: true,
-
- // by default, modify document.title when suite is done
- altertitle: true,
-
- // when enabled, all tests must call expect()
- requireExpects: false,
-
- // add checkboxes that are persisted in the query-string
- // when enabled, the id is set to `true` as a `QUnit.config` property
- urlConfig: [
- {
- id: "noglobals",
- label: "Check for Globals",
- tooltip: "Enabling this will test if any test introduces new properties on the `window` object. Stored as query-strings."
- },
- {
- id: "notrycatch",
- label: "No try-catch",
- tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging exceptions in IE reasonable. Stored as query-strings."
- }
- ],
-
- // Set of all modules.
- modules: {},
-
- // logging callback queues
- begin: [],
- done: [],
- log: [],
- testStart: [],
- testDone: [],
- moduleStart: [],
- moduleDone: []
-};
-
-// Export global variables, unless an 'exports' object exists,
-// in that case we assume we're in CommonJS (dealt with on the bottom of the script)
-if ( typeof exports === "undefined" ) {
- extend( window, QUnit );
-
- // Expose QUnit object
- window.QUnit = QUnit;
-}
-
-// Initialize more QUnit.config and QUnit.urlParams
-(function() {
- var i,
- location = window.location || { search: "", protocol: "file:" },
- params = location.search.slice( 1 ).split( "&" ),
- length = params.length,
- urlParams = {},
- current;
-
- if ( params[ 0 ] ) {
- for ( i = 0; i < length; i++ ) {
- current = params[ i ].split( "=" );
- current[ 0 ] = decodeURIComponent( current[ 0 ] );
- // allow just a key to turn on a flag, e.g., test.html?noglobals
- current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true;
- urlParams[ current[ 0 ] ] = current[ 1 ];
- }
- }
-
- QUnit.urlParams = urlParams;
-
- // String search anywhere in moduleName+testName
- config.filter = urlParams.filter;
-
- // Exact match of the module name
- config.module = urlParams.module;
-
- config.testNumber = parseInt( urlParams.testNumber, 10 ) || null;
-
- // Figure out if we're running the tests from a server or not
- QUnit.isLocal = location.protocol === "file:";
-}());
-
-// Extend QUnit object,
-// these after set here because they should not be exposed as global functions
-extend( QUnit, {
- assert: assert,
-
- config: config,
-
- // Initialize the configuration options
- init: function() {
- extend( config, {
- stats: { all: 0, bad: 0 },
- moduleStats: { all: 0, bad: 0 },
- started: +new Date(),
- updateRate: 1000,
- blocking: false,
- autostart: true,
- autorun: false,
- filter: "",
- queue: [],
- semaphore: 1
- });
-
- var tests, banner, result,
- qunit = id( "qunit" );
-
- if ( qunit ) {
- qunit.innerHTML =
- "" +
- "" +
- "" +
- "" +
- "
";
- }
-
- tests = id( "qunit-tests" );
- banner = id( "qunit-banner" );
- result = id( "qunit-testresult" );
-
- if ( tests ) {
- tests.innerHTML = "";
- }
-
- if ( banner ) {
- banner.className = "";
- }
-
- if ( result ) {
- result.parentNode.removeChild( result );
- }
-
- if ( tests ) {
- result = document.createElement( "p" );
- result.id = "qunit-testresult";
- result.className = "result";
- tests.parentNode.insertBefore( result, tests );
- result.innerHTML = "Running...
";
- }
- },
-
- // Resets the test setup. Useful for tests that modify the DOM.
- reset: function() {
- var fixture = id( "qunit-fixture" );
- if ( fixture ) {
- fixture.innerHTML = config.fixture;
- }
- },
-
- // Trigger an event on an element.
- // @example triggerEvent( document.body, "click" );
- triggerEvent: function( elem, type, event ) {
- if ( document.createEvent ) {
- event = document.createEvent( "MouseEvents" );
- event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView,
- 0, 0, 0, 0, 0, false, false, false, false, 0, null);
-
- elem.dispatchEvent( event );
- } else if ( elem.fireEvent ) {
- elem.fireEvent( "on" + type );
- }
- },
-
- // Safe object type checking
- is: function( type, obj ) {
- return QUnit.objectType( obj ) === type;
- },
-
- objectType: function( obj ) {
- if ( typeof obj === "undefined" ) {
- return "undefined";
- // consider: typeof null === object
- }
- if ( obj === null ) {
- return "null";
- }
-
- var match = toString.call( obj ).match(/^\[object\s(.*)\]$/),
- type = match && match[1] || "";
-
- switch ( type ) {
- case "Number":
- if ( isNaN(obj) ) {
- return "nan";
- }
- return "number";
- case "String":
- case "Boolean":
- case "Array":
- case "Date":
- case "RegExp":
- case "Function":
- return type.toLowerCase();
- }
- if ( typeof obj === "object" ) {
- return "object";
- }
- return undefined;
- },
-
- push: function( result, actual, expected, message ) {
- if ( !config.current ) {
- throw new Error( "assertion outside test context, was " + sourceFromStacktrace() );
- }
-
- var output, source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: message,
- actual: actual,
- expected: expected
- };
-
- message = escapeText( message ) || ( result ? "okay" : "failed" );
- message = "" + message + "";
- output = message;
-
- if ( !result ) {
- expected = escapeText( QUnit.jsDump.parse(expected) );
- actual = escapeText( QUnit.jsDump.parse(actual) );
- output += "Expected: | " + expected + " |
";
-
- if ( actual !== expected ) {
- output += "Result: | " + actual + " |
";
- output += "Diff: | " + QUnit.diff( expected, actual ) + " |
";
- }
-
- source = sourceFromStacktrace();
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
- }
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: !!result,
- message: output
- });
- },
-
- pushFailure: function( message, source, actual ) {
- if ( !config.current ) {
- throw new Error( "pushFailure() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
-
- var output,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: false,
- message: message
- };
-
- message = escapeText( message ) || "error";
- message = "" + message + "";
- output = message;
-
- output += "";
-
- if ( actual ) {
- output += "Result: | " + escapeText( actual ) + " |
";
- }
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: false,
- message: output
- });
- },
-
- url: function( params ) {
- params = extend( extend( {}, QUnit.urlParams ), params );
- var key,
- querystring = "?";
-
- for ( key in params ) {
- if ( !hasOwn.call( params, key ) ) {
- continue;
- }
- querystring += encodeURIComponent( key ) + "=" +
- encodeURIComponent( params[ key ] ) + "&";
- }
- return window.location.protocol + "//" + window.location.host +
- window.location.pathname + querystring.slice( 0, -1 );
- },
-
- extend: extend,
- id: id,
- addEvent: addEvent
- // load, equiv, jsDump, diff: Attached later
-});
-
-/**
- * @deprecated: Created for backwards compatibility with test runner that set the hook function
- * into QUnit.{hook}, instead of invoking it and passing the hook function.
- * QUnit.constructor is set to the empty F() above so that we can add to it's prototype here.
- * Doing this allows us to tell if the following methods have been overwritten on the actual
- * QUnit object.
- */
-extend( QUnit.constructor.prototype, {
-
- // Logging callbacks; all receive a single argument with the listed properties
- // run test/logs.html for any related changes
- begin: registerLoggingCallback( "begin" ),
-
- // done: { failed, passed, total, runtime }
- done: registerLoggingCallback( "done" ),
-
- // log: { result, actual, expected, message }
- log: registerLoggingCallback( "log" ),
-
- // testStart: { name }
- testStart: registerLoggingCallback( "testStart" ),
-
- // testDone: { name, failed, passed, total, duration }
- testDone: registerLoggingCallback( "testDone" ),
-
- // moduleStart: { name }
- moduleStart: registerLoggingCallback( "moduleStart" ),
-
- // moduleDone: { name, failed, passed, total }
- moduleDone: registerLoggingCallback( "moduleDone" )
-});
-
-if ( typeof document === "undefined" || document.readyState === "complete" ) {
- config.autorun = true;
-}
-
-QUnit.load = function() {
- runLoggingCallbacks( "begin", QUnit, {} );
-
- // Initialize the config, saving the execution queue
- var banner, filter, i, label, len, main, ol, toolbar, userAgent, val,
- urlConfigCheckboxesContainer, urlConfigCheckboxes, moduleFilter,
- numModules = 0,
- moduleFilterHtml = "",
- urlConfigHtml = "",
- oldconfig = extend( {}, config );
-
- QUnit.init();
- extend(config, oldconfig);
-
- config.blocking = false;
-
- len = config.urlConfig.length;
-
- for ( i = 0; i < len; i++ ) {
- val = config.urlConfig[i];
- if ( typeof val === "string" ) {
- val = {
- id: val,
- label: val,
- tooltip: "[no tooltip available]"
- };
- }
- config[ val.id ] = QUnit.urlParams[ val.id ];
- urlConfigHtml += "";
- }
-
- moduleFilterHtml += "";
-
- // `userAgent` initialized at top of scope
- userAgent = id( "qunit-userAgent" );
- if ( userAgent ) {
- userAgent.innerHTML = navigator.userAgent;
- }
-
- // `banner` initialized at top of scope
- banner = id( "qunit-header" );
- if ( banner ) {
- banner.innerHTML = "" + banner.innerHTML + " ";
- }
-
- // `toolbar` initialized at top of scope
- toolbar = id( "qunit-testrunner-toolbar" );
- if ( toolbar ) {
- // `filter` initialized at top of scope
- filter = document.createElement( "input" );
- filter.type = "checkbox";
- filter.id = "qunit-filter-pass";
-
- addEvent( filter, "click", function() {
- var tmp,
- ol = document.getElementById( "qunit-tests" );
-
- if ( filter.checked ) {
- ol.className = ol.className + " hidepass";
- } else {
- tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " ";
- ol.className = tmp.replace( / hidepass /, " " );
- }
- if ( defined.sessionStorage ) {
- if (filter.checked) {
- sessionStorage.setItem( "qunit-filter-passed-tests", "true" );
- } else {
- sessionStorage.removeItem( "qunit-filter-passed-tests" );
- }
- }
- });
-
- if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem( "qunit-filter-passed-tests" ) ) {
- filter.checked = true;
- // `ol` initialized at top of scope
- ol = document.getElementById( "qunit-tests" );
- ol.className = ol.className + " hidepass";
- }
- toolbar.appendChild( filter );
-
- // `label` initialized at top of scope
- label = document.createElement( "label" );
- label.setAttribute( "for", "qunit-filter-pass" );
- label.setAttribute( "title", "Only show tests and assertons that fail. Stored in sessionStorage." );
- label.innerHTML = "Hide passed tests";
- toolbar.appendChild( label );
-
- urlConfigCheckboxesContainer = document.createElement("span");
- urlConfigCheckboxesContainer.innerHTML = urlConfigHtml;
- urlConfigCheckboxes = urlConfigCheckboxesContainer.getElementsByTagName("input");
- // For oldIE support:
- // * Add handlers to the individual elements instead of the container
- // * Use "click" instead of "change"
- // * Fallback from event.target to event.srcElement
- addEvents( urlConfigCheckboxes, "click", function( event ) {
- var params = {},
- target = event.target || event.srcElement;
- params[ target.name ] = target.checked ? true : undefined;
- window.location = QUnit.url( params );
- });
- toolbar.appendChild( urlConfigCheckboxesContainer );
-
- if (numModules > 1) {
- moduleFilter = document.createElement( 'span' );
- moduleFilter.setAttribute( 'id', 'qunit-modulefilter-container' );
- moduleFilter.innerHTML = moduleFilterHtml;
- addEvent( moduleFilter.lastChild, "change", function() {
- var selectBox = moduleFilter.getElementsByTagName("select")[0],
- selectedModule = decodeURIComponent(selectBox.options[selectBox.selectedIndex].value);
-
- window.location = QUnit.url( { module: ( selectedModule === "" ) ? undefined : selectedModule } );
- });
- toolbar.appendChild(moduleFilter);
- }
- }
-
- // `main` initialized at top of scope
- main = id( "qunit-fixture" );
- if ( main ) {
- config.fixture = main.innerHTML;
- }
-
- if ( config.autostart ) {
- QUnit.start();
- }
-};
-
-addEvent( window, "load", QUnit.load );
-
-// `onErrorFnPrev` initialized at top of scope
-// Preserve other handlers
-onErrorFnPrev = window.onerror;
-
-// Cover uncaught exceptions
-// Returning true will surpress the default browser handler,
-// returning false will let it run.
-window.onerror = function ( error, filePath, linerNr ) {
- var ret = false;
- if ( onErrorFnPrev ) {
- ret = onErrorFnPrev( error, filePath, linerNr );
- }
-
- // Treat return value as window.onerror itself does,
- // Only do our handling if not surpressed.
- if ( ret !== true ) {
- if ( QUnit.config.current ) {
- if ( QUnit.config.current.ignoreGlobalErrors ) {
- return true;
- }
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- } else {
- QUnit.test( "global failure", extend( function() {
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- }, { validTest: validTest } ) );
- }
- return false;
- }
-
- return ret;
-};
-
-function done() {
- config.autorun = true;
-
- // Log the last module results
- if ( config.currentModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.currentModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
-
- var i, key,
- banner = id( "qunit-banner" ),
- tests = id( "qunit-tests" ),
- runtime = +new Date() - config.started,
- passed = config.stats.all - config.stats.bad,
- html = [
- "Tests completed in ",
- runtime,
- " milliseconds.
",
- "",
- passed,
- " assertions of ",
- config.stats.all,
- " passed, ",
- config.stats.bad,
- " failed."
- ].join( "" );
-
- if ( banner ) {
- banner.className = ( config.stats.bad ? "qunit-fail" : "qunit-pass" );
- }
-
- if ( tests ) {
- id( "qunit-testresult" ).innerHTML = html;
- }
-
- if ( config.altertitle && typeof document !== "undefined" && document.title ) {
- // show ✖ for good, ✔ for bad suite result in title
- // use escape sequences in case file gets loaded with non-utf-8-charset
- document.title = [
- ( config.stats.bad ? "\u2716" : "\u2714" ),
- document.title.replace( /^[\u2714\u2716] /i, "" )
- ].join( " " );
- }
-
- // clear own sessionStorage items if all tests passed
- if ( config.reorder && defined.sessionStorage && config.stats.bad === 0 ) {
- // `key` & `i` initialized at top of scope
- for ( i = 0; i < sessionStorage.length; i++ ) {
- key = sessionStorage.key( i++ );
- if ( key.indexOf( "qunit-test-" ) === 0 ) {
- sessionStorage.removeItem( key );
- }
- }
- }
-
- // scroll back to top to show results
- if ( window.scrollTo ) {
- window.scrollTo(0, 0);
- }
-
- runLoggingCallbacks( "done", QUnit, {
- failed: config.stats.bad,
- passed: passed,
- total: config.stats.all,
- runtime: runtime
- });
-}
-
-/** @return Boolean: true if this test should be ran */
-function validTest( test ) {
- var include,
- filter = config.filter && config.filter.toLowerCase(),
- module = config.module && config.module.toLowerCase(),
- fullName = (test.module + ": " + test.testName).toLowerCase();
-
- // Internally-generated tests are always valid
- if ( test.callback && test.callback.validTest === validTest ) {
- delete test.callback.validTest;
- return true;
- }
-
- if ( config.testNumber ) {
- return test.testNumber === config.testNumber;
- }
-
- if ( module && ( !test.module || test.module.toLowerCase() !== module ) ) {
- return false;
- }
-
- if ( !filter ) {
- return true;
- }
-
- include = filter.charAt( 0 ) !== "!";
- if ( !include ) {
- filter = filter.slice( 1 );
- }
-
- // If the filter matches, we need to honour include
- if ( fullName.indexOf( filter ) !== -1 ) {
- return include;
- }
-
- // Otherwise, do the opposite
- return !include;
-}
-
-// so far supports only Firefox, Chrome and Opera (buggy), Safari (for real exceptions)
-// Later Safari and IE10 are supposed to support error.stack as well
-// See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack
-function extractStacktrace( e, offset ) {
- offset = offset === undefined ? 3 : offset;
-
- var stack, include, i;
-
- if ( e.stacktrace ) {
- // Opera
- return e.stacktrace.split( "\n" )[ offset + 3 ];
- } else if ( e.stack ) {
- // Firefox, Chrome
- stack = e.stack.split( "\n" );
- if (/^error$/i.test( stack[0] ) ) {
- stack.shift();
- }
- if ( fileName ) {
- include = [];
- for ( i = offset; i < stack.length; i++ ) {
- if ( stack[ i ].indexOf( fileName ) !== -1 ) {
- break;
- }
- include.push( stack[ i ] );
- }
- if ( include.length ) {
- return include.join( "\n" );
- }
- }
- return stack[ offset ];
- } else if ( e.sourceURL ) {
- // Safari, PhantomJS
- // hopefully one day Safari provides actual stacktraces
- // exclude useless self-reference for generated Error objects
- if ( /qunit.js$/.test( e.sourceURL ) ) {
- return;
- }
- // for actual exceptions, this is useful
- return e.sourceURL + ":" + e.line;
- }
-}
-function sourceFromStacktrace( offset ) {
- try {
- throw new Error();
- } catch ( e ) {
- return extractStacktrace( e, offset );
- }
-}
-
-/**
- * Escape text for attribute or text content.
- */
-function escapeText( s ) {
- if ( !s ) {
- return "";
- }
- s = s + "";
- // Both single quotes and double quotes (for attributes)
- return s.replace( /['"<>&]/g, function( s ) {
- switch( s ) {
- case '\'':
- return ''';
- case '"':
- return '"';
- case '<':
- return '<';
- case '>':
- return '>';
- case '&':
- return '&';
- }
- });
-}
-
-function synchronize( callback, last ) {
- config.queue.push( callback );
-
- if ( config.autorun && !config.blocking ) {
- process( last );
- }
-}
-
-function process( last ) {
- function next() {
- process( last );
- }
- var start = new Date().getTime();
- config.depth = config.depth ? config.depth + 1 : 1;
-
- while ( config.queue.length && !config.blocking ) {
- if ( !defined.setTimeout || config.updateRate <= 0 || ( ( new Date().getTime() - start ) < config.updateRate ) ) {
- config.queue.shift()();
- } else {
- window.setTimeout( next, 13 );
- break;
- }
- }
- config.depth--;
- if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) {
- done();
- }
-}
-
-function saveGlobal() {
- config.pollution = [];
-
- if ( config.noglobals ) {
- for ( var key in window ) {
- // in Opera sometimes DOM element ids show up here, ignore them
- if ( !hasOwn.call( window, key ) || /^qunit-test-output/.test( key ) ) {
- continue;
- }
- config.pollution.push( key );
- }
- }
-}
-
-function checkPollution() {
- var newGlobals,
- deletedGlobals,
- old = config.pollution;
-
- saveGlobal();
-
- newGlobals = diff( config.pollution, old );
- if ( newGlobals.length > 0 ) {
- QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join(", ") );
- }
-
- deletedGlobals = diff( old, config.pollution );
- if ( deletedGlobals.length > 0 ) {
- QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join(", ") );
- }
-}
-
-// returns a new Array with the elements that are in a but not in b
-function diff( a, b ) {
- var i, j,
- result = a.slice();
-
- for ( i = 0; i < result.length; i++ ) {
- for ( j = 0; j < b.length; j++ ) {
- if ( result[i] === b[j] ) {
- result.splice( i, 1 );
- i--;
- break;
- }
- }
- }
- return result;
-}
-
-function extend( a, b ) {
- for ( var prop in b ) {
- if ( b[ prop ] === undefined ) {
- delete a[ prop ];
-
- // Avoid "Member not found" error in IE8 caused by setting window.constructor
- } else if ( prop !== "constructor" || a !== window ) {
- a[ prop ] = b[ prop ];
- }
- }
-
- return a;
-}
-
-/**
- * @param {HTMLElement} elem
- * @param {string} type
- * @param {Function} fn
- */
-function addEvent( elem, type, fn ) {
- // Standards-based browsers
- if ( elem.addEventListener ) {
- elem.addEventListener( type, fn, false );
- // IE
- } else {
- elem.attachEvent( "on" + type, fn );
- }
-}
-
-/**
- * @param {Array|NodeList} elems
- * @param {string} type
- * @param {Function} fn
- */
-function addEvents( elems, type, fn ) {
- var i = elems.length;
- while ( i-- ) {
- addEvent( elems[i], type, fn );
- }
-}
-
-function hasClass( elem, name ) {
- return (" " + elem.className + " ").indexOf(" " + name + " ") > -1;
-}
-
-function addClass( elem, name ) {
- if ( !hasClass( elem, name ) ) {
- elem.className += (elem.className ? " " : "") + name;
- }
-}
-
-function removeClass( elem, name ) {
- var set = " " + elem.className + " ";
- // Class name may appear multiple times
- while ( set.indexOf(" " + name + " ") > -1 ) {
- set = set.replace(" " + name + " " , " ");
- }
- // If possible, trim it for prettiness, but not neccecarily
- elem.className = window.jQuery ? jQuery.trim( set ) : ( set.trim ? set.trim() : set );
-}
-
-function id( name ) {
- return !!( typeof document !== "undefined" && document && document.getElementById ) &&
- document.getElementById( name );
-}
-
-function registerLoggingCallback( key ) {
- return function( callback ) {
- config[key].push( callback );
- };
-}
-
-// Supports deprecated method of completely overwriting logging callbacks
-function runLoggingCallbacks( key, scope, args ) {
- var i, callbacks;
- if ( QUnit.hasOwnProperty( key ) ) {
- QUnit[ key ].call(scope, args );
- } else {
- callbacks = config[ key ];
- for ( i = 0; i < callbacks.length; i++ ) {
- callbacks[ i ].call( scope, args );
- }
- }
-}
-
-// Test for equality any JavaScript type.
-// Author: Philippe Rathé
-QUnit.equiv = (function() {
-
- // Call the o related callback with the given arguments.
- function bindCallbacks( o, callbacks, args ) {
- var prop = QUnit.objectType( o );
- if ( prop ) {
- if ( QUnit.objectType( callbacks[ prop ] ) === "function" ) {
- return callbacks[ prop ].apply( callbacks, args );
- } else {
- return callbacks[ prop ]; // or undefined
- }
- }
- }
-
- // the real equiv function
- var innerEquiv,
- // stack to decide between skip/abort functions
- callers = [],
- // stack to avoiding loops from circular referencing
- parents = [],
-
- getProto = Object.getPrototypeOf || function ( obj ) {
- return obj.__proto__;
- },
- callbacks = (function () {
-
- // for string, boolean, number and null
- function useStrictEquality( b, a ) {
- /*jshint eqeqeq:false */
- if ( b instanceof a.constructor || a instanceof b.constructor ) {
- // to catch short annotaion VS 'new' annotation of a
- // declaration
- // e.g. var i = 1;
- // var j = new Number(1);
- return a == b;
- } else {
- return a === b;
- }
- }
-
- return {
- "string": useStrictEquality,
- "boolean": useStrictEquality,
- "number": useStrictEquality,
- "null": useStrictEquality,
- "undefined": useStrictEquality,
-
- "nan": function( b ) {
- return isNaN( b );
- },
-
- "date": function( b, a ) {
- return QUnit.objectType( b ) === "date" && a.valueOf() === b.valueOf();
- },
-
- "regexp": function( b, a ) {
- return QUnit.objectType( b ) === "regexp" &&
- // the regex itself
- a.source === b.source &&
- // and its modifers
- a.global === b.global &&
- // (gmi) ...
- a.ignoreCase === b.ignoreCase &&
- a.multiline === b.multiline &&
- a.sticky === b.sticky;
- },
-
- // - skip when the property is a method of an instance (OOP)
- // - abort otherwise,
- // initial === would have catch identical references anyway
- "function": function() {
- var caller = callers[callers.length - 1];
- return caller !== Object && typeof caller !== "undefined";
- },
-
- "array": function( b, a ) {
- var i, j, len, loop;
-
- // b could be an object literal here
- if ( QUnit.objectType( b ) !== "array" ) {
- return false;
- }
-
- len = a.length;
- if ( len !== b.length ) {
- // safe and faster
- return false;
- }
-
- // track reference to avoid circular references
- parents.push( a );
- for ( i = 0; i < len; i++ ) {
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- loop = true;// dont rewalk array
- }
- }
- if ( !loop && !innerEquiv(a[i], b[i]) ) {
- parents.pop();
- return false;
- }
- }
- parents.pop();
- return true;
- },
-
- "object": function( b, a ) {
- var i, j, loop,
- // Default to true
- eq = true,
- aProperties = [],
- bProperties = [];
-
- // comparing constructors is more strict than using
- // instanceof
- if ( a.constructor !== b.constructor ) {
- // Allow objects with no prototype to be equivalent to
- // objects with Object as their constructor.
- if ( !(( getProto(a) === null && getProto(b) === Object.prototype ) ||
- ( getProto(b) === null && getProto(a) === Object.prototype ) ) ) {
- return false;
- }
- }
-
- // stack constructor before traversing properties
- callers.push( a.constructor );
- // track reference to avoid circular references
- parents.push( a );
-
- for ( i in a ) { // be strict: don't ensures hasOwnProperty
- // and go deep
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- // don't go down the same path twice
- loop = true;
- }
- }
- aProperties.push(i); // collect a's properties
-
- if (!loop && !innerEquiv( a[i], b[i] ) ) {
- eq = false;
- break;
- }
- }
-
- callers.pop(); // unstack, we are done
- parents.pop();
-
- for ( i in b ) {
- bProperties.push( i ); // collect b's properties
- }
-
- // Ensures identical properties name
- return eq && innerEquiv( aProperties.sort(), bProperties.sort() );
- }
- };
- }());
-
- innerEquiv = function() { // can take multiple arguments
- var args = [].slice.apply( arguments );
- if ( args.length < 2 ) {
- return true; // end transition
- }
-
- return (function( a, b ) {
- if ( a === b ) {
- return true; // catch the most you can
- } else if ( a === null || b === null || typeof a === "undefined" ||
- typeof b === "undefined" ||
- QUnit.objectType(a) !== QUnit.objectType(b) ) {
- return false; // don't lose time with error prone cases
- } else {
- return bindCallbacks(a, callbacks, [ b, a ]);
- }
-
- // apply transition with (1..n) arguments
- }( args[0], args[1] ) && arguments.callee.apply( this, args.splice(1, args.length - 1 )) );
- };
-
- return innerEquiv;
-}());
-
-/**
- * jsDump Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com |
- * http://flesler.blogspot.com Licensed under BSD
- * (http://www.opensource.org/licenses/bsd-license.php) Date: 5/15/2008
- *
- * @projectDescription Advanced and extensible data dumping for Javascript.
- * @version 1.0.0
- * @author Ariel Flesler
- * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html}
- */
-QUnit.jsDump = (function() {
- function quote( str ) {
- return '"' + str.toString().replace( /"/g, '\\"' ) + '"';
- }
- function literal( o ) {
- return o + "";
- }
- function join( pre, arr, post ) {
- var s = jsDump.separator(),
- base = jsDump.indent(),
- inner = jsDump.indent(1);
- if ( arr.join ) {
- arr = arr.join( "," + s + inner );
- }
- if ( !arr ) {
- return pre + post;
- }
- return [ pre, inner + arr, base + post ].join(s);
- }
- function array( arr, stack ) {
- var i = arr.length, ret = new Array(i);
- this.up();
- while ( i-- ) {
- ret[i] = this.parse( arr[i] , undefined , stack);
- }
- this.down();
- return join( "[", ret, "]" );
- }
-
- var reName = /^function (\w+)/,
- jsDump = {
- // type is used mostly internally, you can fix a (custom)type in advance
- parse: function( obj, type, stack ) {
- stack = stack || [ ];
- var inStack, res,
- parser = this.parsers[ type || this.typeOf(obj) ];
-
- type = typeof parser;
- inStack = inArray( obj, stack );
-
- if ( inStack !== -1 ) {
- return "recursion(" + (inStack - stack.length) + ")";
- }
- if ( type === "function" ) {
- stack.push( obj );
- res = parser.call( this, obj, stack );
- stack.pop();
- return res;
- }
- return ( type === "string" ) ? parser : this.parsers.error;
- },
- typeOf: function( obj ) {
- var type;
- if ( obj === null ) {
- type = "null";
- } else if ( typeof obj === "undefined" ) {
- type = "undefined";
- } else if ( QUnit.is( "regexp", obj) ) {
- type = "regexp";
- } else if ( QUnit.is( "date", obj) ) {
- type = "date";
- } else if ( QUnit.is( "function", obj) ) {
- type = "function";
- } else if ( typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined" ) {
- type = "window";
- } else if ( obj.nodeType === 9 ) {
- type = "document";
- } else if ( obj.nodeType ) {
- type = "node";
- } else if (
- // native arrays
- toString.call( obj ) === "[object Array]" ||
- // NodeList objects
- ( typeof obj.length === "number" && typeof obj.item !== "undefined" && ( obj.length ? obj.item(0) === obj[0] : ( obj.item( 0 ) === null && typeof obj[0] === "undefined" ) ) )
- ) {
- type = "array";
- } else if ( obj.constructor === Error.prototype.constructor ) {
- type = "error";
- } else {
- type = typeof obj;
- }
- return type;
- },
- separator: function() {
- return this.multiline ? this.HTML ? "
" : "\n" : this.HTML ? " " : " ";
- },
- // extra can be a number, shortcut for increasing-calling-decreasing
- indent: function( extra ) {
- if ( !this.multiline ) {
- return "";
- }
- var chr = this.indentChar;
- if ( this.HTML ) {
- chr = chr.replace( /\t/g, " " ).replace( / /g, " " );
- }
- return new Array( this._depth_ + (extra||0) ).join(chr);
- },
- up: function( a ) {
- this._depth_ += a || 1;
- },
- down: function( a ) {
- this._depth_ -= a || 1;
- },
- setParser: function( name, parser ) {
- this.parsers[name] = parser;
- },
- // The next 3 are exposed so you can use them
- quote: quote,
- literal: literal,
- join: join,
- //
- _depth_: 1,
- // This is the list of parsers, to modify them, use jsDump.setParser
- parsers: {
- window: "[Window]",
- document: "[Document]",
- error: function(error) {
- return "Error(\"" + error.message + "\")";
- },
- unknown: "[Unknown]",
- "null": "null",
- "undefined": "undefined",
- "function": function( fn ) {
- var ret = "function",
- // functions never have name in IE
- name = "name" in fn ? fn.name : (reName.exec(fn) || [])[1];
-
- if ( name ) {
- ret += " " + name;
- }
- ret += "( ";
-
- ret = [ ret, QUnit.jsDump.parse( fn, "functionArgs" ), "){" ].join( "" );
- return join( ret, QUnit.jsDump.parse(fn,"functionCode" ), "}" );
- },
- array: array,
- nodelist: array,
- "arguments": array,
- object: function( map, stack ) {
- var ret = [ ], keys, key, val, i;
- QUnit.jsDump.up();
- keys = [];
- for ( key in map ) {
- keys.push( key );
- }
- keys.sort();
- for ( i = 0; i < keys.length; i++ ) {
- key = keys[ i ];
- val = map[ key ];
- ret.push( QUnit.jsDump.parse( key, "key" ) + ": " + QUnit.jsDump.parse( val, undefined, stack ) );
- }
- QUnit.jsDump.down();
- return join( "{", ret, "}" );
- },
- node: function( node ) {
- var len, i, val,
- open = QUnit.jsDump.HTML ? "<" : "<",
- close = QUnit.jsDump.HTML ? ">" : ">",
- tag = node.nodeName.toLowerCase(),
- ret = open + tag,
- attrs = node.attributes;
-
- if ( attrs ) {
- for ( i = 0, len = attrs.length; i < len; i++ ) {
- val = attrs[i].nodeValue;
- // IE6 includes all attributes in .attributes, even ones not explicitly set.
- // Those have values like undefined, null, 0, false, "" or "inherit".
- if ( val && val !== "inherit" ) {
- ret += " " + attrs[i].nodeName + "=" + QUnit.jsDump.parse( val, "attribute" );
- }
- }
- }
- ret += close;
-
- // Show content of TextNode or CDATASection
- if ( node.nodeType === 3 || node.nodeType === 4 ) {
- ret += node.nodeValue;
- }
-
- return ret + open + "/" + tag + close;
- },
- // function calls it internally, it's the arguments part of the function
- functionArgs: function( fn ) {
- var args,
- l = fn.length;
-
- if ( !l ) {
- return "";
- }
-
- args = new Array(l);
- while ( l-- ) {
- // 97 is 'a'
- args[l] = String.fromCharCode(97+l);
- }
- return " " + args.join( ", " ) + " ";
- },
- // object calls it internally, the key part of an item in a map
- key: quote,
- // function calls it internally, it's the content of the function
- functionCode: "[code]",
- // node calls it internally, it's an html attribute value
- attribute: quote,
- string: quote,
- date: quote,
- regexp: literal,
- number: literal,
- "boolean": literal
- },
- // if true, entities are escaped ( <, >, \t, space and \n )
- HTML: false,
- // indentation unit
- indentChar: " ",
- // if true, items in a collection, are separated by a \n, else just a space.
- multiline: true
- };
-
- return jsDump;
-}());
-
-// from jquery.js
-function inArray( elem, array ) {
- if ( array.indexOf ) {
- return array.indexOf( elem );
- }
-
- for ( var i = 0, length = array.length; i < length; i++ ) {
- if ( array[ i ] === elem ) {
- return i;
- }
- }
-
- return -1;
-}
-
-/*
- * Javascript Diff Algorithm
- * By John Resig (http://ejohn.org/)
- * Modified by Chu Alan "sprite"
- *
- * Released under the MIT license.
- *
- * More Info:
- * http://ejohn.org/projects/javascript-diff-algorithm/
- *
- * Usage: QUnit.diff(expected, actual)
- *
- * QUnit.diff( "the quick brown fox jumped over", "the quick fox jumps over" ) == "the quick brown fox jumped jumps over"
- */
-QUnit.diff = (function() {
- /*jshint eqeqeq:false, eqnull:true */
- function diff( o, n ) {
- var i,
- ns = {},
- os = {};
-
- for ( i = 0; i < n.length; i++ ) {
- if ( !hasOwn.call( ns, n[i] ) ) {
- ns[ n[i] ] = {
- rows: [],
- o: null
- };
- }
- ns[ n[i] ].rows.push( i );
- }
-
- for ( i = 0; i < o.length; i++ ) {
- if ( !hasOwn.call( os, o[i] ) ) {
- os[ o[i] ] = {
- rows: [],
- n: null
- };
- }
- os[ o[i] ].rows.push( i );
- }
-
- for ( i in ns ) {
- if ( !hasOwn.call( ns, i ) ) {
- continue;
- }
- if ( ns[i].rows.length === 1 && hasOwn.call( os, i ) && os[i].rows.length === 1 ) {
- n[ ns[i].rows[0] ] = {
- text: n[ ns[i].rows[0] ],
- row: os[i].rows[0]
- };
- o[ os[i].rows[0] ] = {
- text: o[ os[i].rows[0] ],
- row: ns[i].rows[0]
- };
- }
- }
-
- for ( i = 0; i < n.length - 1; i++ ) {
- if ( n[i].text != null && n[ i + 1 ].text == null && n[i].row + 1 < o.length && o[ n[i].row + 1 ].text == null &&
- n[ i + 1 ] == o[ n[i].row + 1 ] ) {
-
- n[ i + 1 ] = {
- text: n[ i + 1 ],
- row: n[i].row + 1
- };
- o[ n[i].row + 1 ] = {
- text: o[ n[i].row + 1 ],
- row: i + 1
- };
- }
- }
-
- for ( i = n.length - 1; i > 0; i-- ) {
- if ( n[i].text != null && n[ i - 1 ].text == null && n[i].row > 0 && o[ n[i].row - 1 ].text == null &&
- n[ i - 1 ] == o[ n[i].row - 1 ]) {
-
- n[ i - 1 ] = {
- text: n[ i - 1 ],
- row: n[i].row - 1
- };
- o[ n[i].row - 1 ] = {
- text: o[ n[i].row - 1 ],
- row: i - 1
- };
- }
- }
-
- return {
- o: o,
- n: n
- };
- }
-
- return function( o, n ) {
- o = o.replace( /\s+$/, "" );
- n = n.replace( /\s+$/, "" );
-
- var i, pre,
- str = "",
- out = diff( o === "" ? [] : o.split(/\s+/), n === "" ? [] : n.split(/\s+/) ),
- oSpace = o.match(/\s+/g),
- nSpace = n.match(/\s+/g);
-
- if ( oSpace == null ) {
- oSpace = [ " " ];
- }
- else {
- oSpace.push( " " );
- }
-
- if ( nSpace == null ) {
- nSpace = [ " " ];
- }
- else {
- nSpace.push( " " );
- }
-
- if ( out.n.length === 0 ) {
- for ( i = 0; i < out.o.length; i++ ) {
- str += "" + out.o[i] + oSpace[i] + "";
- }
- }
- else {
- if ( out.n[0].text == null ) {
- for ( n = 0; n < out.o.length && out.o[n].text == null; n++ ) {
- str += "" + out.o[n] + oSpace[n] + "";
- }
- }
-
- for ( i = 0; i < out.n.length; i++ ) {
- if (out.n[i].text == null) {
- str += "" + out.n[i] + nSpace[i] + "";
- }
- else {
- // `pre` initialized at top of scope
- pre = "";
-
- for ( n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++ ) {
- pre += "" + out.o[n] + oSpace[n] + "";
- }
- str += " " + out.n[i].text + nSpace[i] + pre;
- }
- }
- }
-
- return str;
- };
-}());
-
-// for CommonJS enviroments, export everything
-if ( typeof exports !== "undefined" ) {
- extend( exports, QUnit );
-}
-
-// get at whatever the global object is, like window in browsers
-}( (function() {return this;}.call()) ));
diff --git a/test/lib/require.js b/test/lib/require.js
deleted file mode 100644
index 987f865..0000000
--- a/test/lib/require.js
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- RequireJS 2.1.5 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.
- Available via the MIT or new BSD license.
- see: http://github.com/jrburke/requirejs for details
-*/
-var requirejs,require,define;
-(function(aa){function I(b){return"[object Function]"===L.call(b)}function J(b){return"[object Array]"===L.call(b)}function y(b,c){if(b){var d;for(d=0;dthis.depCount&&!this.defined){if(I(n)){if(this.events.error)try{e=i.execCb(c,n,b,e)}catch(d){a=d}else e=i.execCb(c,n,b,e);this.map.isDefine&&((b=this.module)&&void 0!==b.exports&&b.exports!==this.exports?e=b.exports:void 0===e&&this.usingExports&&(e=this.exports));if(a)return a.requireMap=this.map,a.requireModules=[this.map.id],a.requireType="define",v(this.error=
-a)}else e=n;this.exports=e;if(this.map.isDefine&&!this.ignore&&(q[c]=e,l.onResourceLoad))l.onResourceLoad(i,this.map,this.depMaps);x(c);this.defined=!0}this.defining=!1;this.defined&&!this.defineEmitted&&(this.defineEmitted=!0,this.emit("defined",this.exports),this.defineEmitComplete=!0)}}else this.fetch()}},callPlugin:function(){var a=this.map,b=a.id,d=j(a.prefix);this.depMaps.push(d);t(d,"defined",u(this,function(e){var n,d;d=this.map.name;var g=this.map.parentMap?this.map.parentMap.name:null,h=
-i.makeRequire(a.parentMap,{enableBuildCallback:!0});if(this.map.unnormalized){if(e.normalize&&(d=e.normalize(d,function(a){return c(a,g,!0)})||""),e=j(a.prefix+"!"+d,this.map.parentMap),t(e,"defined",u(this,function(a){this.init([],function(){return a},null,{enabled:!0,ignore:!0})})),d=m(p,e.id)){this.depMaps.push(e);if(this.events.error)d.on("error",u(this,function(a){this.emit("error",a)}));d.enable()}}else n=u(this,function(a){this.init([],function(){return a},null,{enabled:!0})}),n.error=u(this,
-function(a){this.inited=!0;this.error=a;a.requireModules=[b];G(p,function(a){0===a.map.id.indexOf(b+"_unnormalized")&&x(a.map.id)});v(a)}),n.fromText=u(this,function(e,c){var d=a.name,g=j(d),C=O;c&&(e=c);C&&(O=!1);r(g);s(k.config,b)&&(k.config[d]=k.config[b]);try{l.exec(e)}catch(ca){return v(B("fromtexteval","fromText eval for "+b+" failed: "+ca,ca,[b]))}C&&(O=!0);this.depMaps.push(g);i.completeLoad(d);h([d],n)}),e.load(a.name,h,n,k)}));i.enable(d,this);this.pluginMaps[d.id]=d},enable:function(){V[this.map.id]=
-this;this.enabling=this.enabled=!0;y(this.depMaps,u(this,function(a,b){var c,e;if("string"===typeof a){a=j(a,this.map.isDefine?this.map:this.map.parentMap,!1,!this.skipMap);this.depMaps[b]=a;if(c=m(N,a.id)){this.depExports[b]=c(this);return}this.depCount+=1;t(a,"defined",u(this,function(a){this.defineDep(b,a);this.check()}));this.errback&&t(a,"error",this.errback)}c=a.id;e=p[c];!s(N,c)&&(e&&!e.enabled)&&i.enable(a,this)}));G(this.pluginMaps,u(this,function(a){var b=m(p,a.id);b&&!b.enabled&&i.enable(a,
-this)}));this.enabling=!1;this.check()},on:function(a,b){var c=this.events[a];c||(c=this.events[a]=[]);c.push(b)},emit:function(a,b){y(this.events[a],function(a){a(b)});"error"===a&&delete this.events[a]}};i={config:k,contextName:b,registry:p,defined:q,urlFetched:U,defQueue:H,Module:Z,makeModuleMap:j,nextTick:l.nextTick,onError:v,configure:function(a){a.baseUrl&&"/"!==a.baseUrl.charAt(a.baseUrl.length-1)&&(a.baseUrl+="/");var b=k.pkgs,c=k.shim,e={paths:!0,config:!0,map:!0};G(a,function(a,b){e[b]?
-"map"===b?(k.map||(k.map={}),R(k[b],a,!0,!0)):R(k[b],a,!0):k[b]=a});a.shim&&(G(a.shim,function(a,b){J(a)&&(a={deps:a});if((a.exports||a.init)&&!a.exportsFn)a.exportsFn=i.makeShimExports(a);c[b]=a}),k.shim=c);a.packages&&(y(a.packages,function(a){a="string"===typeof a?{name:a}:a;b[a.name]={name:a.name,location:a.location||a.name,main:(a.main||"main").replace(ja,"").replace(ea,"")}}),k.pkgs=b);G(p,function(a,b){!a.inited&&!a.map.unnormalized&&(a.map=j(b))});if(a.deps||a.callback)i.require(a.deps||[],
-a.callback)},makeShimExports:function(a){return function(){var b;a.init&&(b=a.init.apply(aa,arguments));return b||a.exports&&ba(a.exports)}},makeRequire:function(a,f){function d(e,c,h){var g,k;f.enableBuildCallback&&(c&&I(c))&&(c.__requireJsBuild=!0);if("string"===typeof e){if(I(c))return v(B("requireargs","Invalid require call"),h);if(a&&s(N,e))return N[e](p[a.id]);if(l.get)return l.get(i,e,a,d);g=j(e,a,!1,!0);g=g.id;return!s(q,g)?v(B("notloaded",'Module name "'+g+'" has not been loaded yet for context: '+
-b+(a?"":". Use require([])"))):q[g]}L();i.nextTick(function(){L();k=r(j(null,a));k.skipMap=f.skipMap;k.init(e,c,h,{enabled:!0});D()});return d}f=f||{};R(d,{isBrowser:A,toUrl:function(b){var d,f=b.lastIndexOf("."),g=b.split("/")[0];if(-1!==f&&(!("."===g||".."===g)||1h.attachEvent.toString().indexOf("[native code"))&&!Y?(O=!0,h.attachEvent("onreadystatechange",b.onScriptLoad)):(h.addEventListener("load",b.onScriptLoad,!1),h.addEventListener("error",b.onScriptError,!1)),h.src=d,K=h,D?x.insertBefore(h,D):x.appendChild(h),K=null,h;if(da)try{importScripts(d),b.completeLoad(c)}catch(j){b.onError(B("importscripts","importScripts failed for "+c+" at "+d,j,[c]))}};A&&M(document.getElementsByTagName("script"),function(b){x||(x=
-b.parentNode);if(t=b.getAttribute("data-main"))return r.baseUrl||(E=t.split("/"),Q=E.pop(),fa=E.length?E.join("/")+"/":"./",r.baseUrl=fa,t=Q),t=t.replace(ea,""),r.deps=r.deps?r.deps.concat(t):[t],!0});define=function(b,c,d){var l,h;"string"!==typeof b&&(d=c,c=b,b=null);J(c)||(d=c,c=[]);!c.length&&I(d)&&d.length&&(d.toString().replace(la,"").replace(ma,function(b,d){c.push(d)}),c=(1===d.length?["require"]:["require","exports","module"]).concat(c));if(O){if(!(l=K))P&&"interactive"===P.readyState||M(document.getElementsByTagName("script"),
-function(b){if("interactive"===b.readyState)return P=b}),l=P;l&&(b||(b=l.getAttribute("data-requiremodule")),h=F[l.getAttribute("data-requirecontext")])}(h?h.defQueue:T).push([b,c,d])};define.amd={jQuery:!0};l.exec=function(b){return eval(b)};l(r)}})(this);
diff --git a/test/lib/resemble.js b/test/lib/resemble.js
new file mode 100644
index 0000000..1cb8c29
--- /dev/null
+++ b/test/lib/resemble.js
@@ -0,0 +1,535 @@
+/*
+Author: James Cryer
+Company: Huddle
+Last updated date: 21 Feb 2013
+URL: https://github.com/Huddle/Resemble.js
+*/
+
+(function(_this){
+ 'use strict';
+
+ _this['resemble'] = function( fileData ){
+
+ var data = {};
+ var images = [];
+ var updateCallbackArray = [];
+
+ var tolerance = { // between 0 and 255
+ red: 16,
+ green: 16,
+ blue: 16,
+ minBrightness: 16,
+ maxBrightness: 240
+ };
+
+ var ignoreAntialiasing = false;
+ var ignoreColors = false;
+
+ function triggerDataUpdate(){
+ var len = updateCallbackArray.length;
+ var i;
+ for(i=0;i tolerance.maxBrightness;
+ }
+
+ function getHue(r,g,b){
+
+ r = r / 255;
+ g = g / 255;
+ b = b / 255;
+ var max = Math.max(r, g, b), min = Math.min(r, g, b);
+ var h;
+ var d;
+
+ if (max == min){
+ h = 0; // achromatic
+ } else{
+ d = max - min;
+ switch(max){
+ case r: h = (g - b) / d + (g < b ? 6 : 0); break;
+ case g: h = (b - r) / d + 2; break;
+ case b: h = (r - g) / d + 4; break;
+ }
+ h /= 6;
+ }
+
+ return h;
+ }
+
+ function isAntialiased(sourcePix, data, cacheSet, verticalPos, horizontalPos, width){
+ var offset;
+ var targetPix;
+ var distance = 1;
+ var i;
+ var j;
+ var hasHighContrastSibling = 0;
+ var hasSiblingWithDifferentHue = 0;
+ var hasEquivilantSibling = 0;
+
+ addHueInfo(sourcePix);
+
+ for (i = distance*-1; i <= distance; i++){
+ for (j = distance*-1; j <= distance; j++){
+
+ if(i===0 && j===0){
+ // ignore source pixel
+ } else {
+
+ offset = ((verticalPos+j)*width + (horizontalPos+i)) * 4;
+ targetPix = getPixelInfo(data, offset, cacheSet);
+
+ if(targetPix === null){
+ continue;
+ }
+
+ addBrightnessInfo(targetPix);
+ addHueInfo(targetPix);
+
+ if( isContrasting(sourcePix, targetPix) ){
+ hasHighContrastSibling++;
+ }
+
+ if( isRGBSame(sourcePix,targetPix) ){
+ hasEquivilantSibling++;
+ }
+
+ if( Math.abs(targetPix.h - sourcePix.h) > 0.3 ){
+ hasSiblingWithDifferentHue++;
+ }
+
+ if( hasSiblingWithDifferentHue > 1 || hasHighContrastSibling > 1){
+ return true;
+ }
+ }
+ }
+ }
+
+ if(hasEquivilantSibling < 2){
+ return true;
+ }
+
+ return false;
+ }
+
+ function errorPixel(px, offset){
+ px[offset] = 255; //r
+ px[offset + 1] = 0; //g
+ px[offset + 2] = 255; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyPixel(px, offset, data){
+ px[offset] = data.r; //r
+ px[offset + 1] = data.g; //g
+ px[offset + 2] = data.b; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyGrayScalePixel(px, offset, data){
+ px[offset] = data.brightness; //r
+ px[offset + 1] = data.brightness; //g
+ px[offset + 2] = data.brightness; //b
+ px[offset + 3] = 255; //a
+ }
+
+
+ function getPixelInfo(data, offset, cacheSet){
+ var r;
+ var g;
+ var b;
+ var d;
+
+ if(typeof data[offset] !== 'undefined'){
+ r = data[offset];
+ g = data[offset+1];
+ b = data[offset+2];
+ d = {
+ r: r,
+ g: g,
+ b: b
+ };
+
+ return d;
+ } else {
+ return null;
+ }
+ }
+
+ function addBrightnessInfo(data){
+ data.brightness = getBrightness(data.r,data.g,data.b); // 'corrected' lightness
+ }
+
+ function addHueInfo(data){
+ data.h = getHue(data.r,data.g,data.b);
+ }
+
+ function analyseImages(img1, img2, width, height){
+
+ var hiddenCanvas = document.createElement('canvas');
+
+ var data1 = img1.data;
+ var data2 = img2.data;
+
+ hiddenCanvas.width = width;
+ hiddenCanvas.height = height;
+
+ var context = hiddenCanvas.getContext('2d');
+ var imgd = context.createImageData(width,height);
+ var targetPix = imgd.data;
+
+ var mismatchCount = 0;
+
+ var time = Date.now();
+
+ var skip;
+
+ if( (width > 1200 || height > 1200) && ignoreAntialiasing){
+ skip = 6;
+ }
+
+ loop(height, width, function(verticalPos, horizontalPos){
+
+ if(skip){ // only skip if the image isn't small
+ if(verticalPos % skip === 0 || horizontalPos % skip === 0){
+ return;
+ }
+ }
+
+ var offset = (verticalPos*width + horizontalPos) * 4;
+ var pixel1 = getPixelInfo(data1, offset, 1);
+ var pixel2 = getPixelInfo(data2, offset, 2);
+
+ if(pixel1 === null || pixel2 === null){
+ return;
+ }
+
+ if (ignoreColors){
+
+ addBrightnessInfo(pixel1);
+ addBrightnessInfo(pixel2);
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ return;
+ }
+
+ if( isRGBSimilar(pixel1, pixel2) ){
+ copyPixel(targetPix, offset, pixel2);
+
+ } else if( ignoreAntialiasing && (
+ addBrightnessInfo(pixel1), // jit pixel info augmentation looks a little weird, sorry.
+ addBrightnessInfo(pixel2),
+ isAntialiased(pixel1, data1, 1, verticalPos, horizontalPos, width) ||
+ isAntialiased(pixel2, data2, 2, verticalPos, horizontalPos, width)
+ )){
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+
+ });
+
+ data.misMatchPercentage = (mismatchCount / (height*width) * 100).toFixed(2);
+ data.analysisTime = Date.now() - time;
+
+ data.getImageDataUrl = function(text){
+ var barHeight = 0;
+
+ if(text){
+ barHeight = addLabel(text,context,hiddenCanvas);
+ }
+
+ context.putImageData(imgd, 0, barHeight);
+
+ return hiddenCanvas.toDataURL("image/png");
+ };
+ }
+
+ function addLabel(text, context, hiddenCanvas){
+ var textPadding = 2;
+
+ context.font = '12px sans-serif';
+
+ var textWidth = context.measureText(text).width + textPadding*2;
+ var barHeight = 22;
+
+ if(textWidth > hiddenCanvas.width){
+ hiddenCanvas.width = textWidth;
+ }
+
+ hiddenCanvas.height += barHeight;
+
+ context.fillStyle = "#666";
+ context.fillRect(0,0,hiddenCanvas.width,barHeight -4);
+ context.fillStyle = "#fff";
+ context.fillRect(0,barHeight -4,hiddenCanvas.width, 4);
+
+ context.fillStyle = "#fff";
+ context.textBaseline = "top";
+ context.font = '12px sans-serif';
+ context.fillText(text, textPadding, 1);
+
+ return barHeight;
+ }
+
+ function normalise(img, w, h){
+ var c;
+ var context;
+
+ if(img.height < h || img.width < w){
+ c = document.createElement('canvas');
+ c.width = w;
+ c.height = h;
+ context = c.getContext('2d');
+ context.putImageData(img, 0, 0);
+ return context.getImageData(0, 0, w, h);
+ }
+
+ return img;
+ }
+
+ function compare(one, two){
+
+ function onceWeHaveBoth(){
+ var width;
+ var height;
+ if(images.length === 2){
+ width = images[0].width > images[1].width ? images[0].width : images[1].width;
+ height = images[0].height > images[1].height ? images[0].height : images[1].height;
+
+ if( (images[0].width === images[1].width) && (images[0].height === images[1].height) ){
+ data.isSameDimensions = true;
+ } else {
+ data.isSameDimensions = false;
+ }
+
+ analyseImages( normalise(images[0],width, height), normalise(images[1],width, height), width, height);
+
+ triggerDataUpdate();
+ }
+ }
+
+ images = [];
+ loadImageData(one, onceWeHaveBoth);
+ loadImageData(two, onceWeHaveBoth);
+ }
+
+ function getCompareApi(param){
+
+ var secondFileData,
+ hasMethod = typeof param === 'function';
+
+ if( !hasMethod ){
+ // assume it's file data
+ secondFileData = param;
+ }
+
+ var self = {
+ ignoreNothing: function(){
+
+ tolerance.red = 16;
+ tolerance.green = 16;
+ tolerance.blue = 16;
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreAntialiasing: function(){
+
+ tolerance.red = 32;
+ tolerance.green = 32;
+ tolerance.blue = 32;
+ tolerance.minBrightness = 64;
+ tolerance.maxBrightness = 96;
+
+ ignoreAntialiasing = true;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreColors: function(){
+
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = true;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ onComplete: function( callback ){
+
+ updateCallbackArray.push(callback);
+
+ var wrapper = function(){
+ compare(fileData, secondFileData);
+ };
+
+ wrapper();
+
+ return getCompareApi(wrapper);
+ }
+ };
+
+ return self;
+ }
+
+ return {
+ onComplete: function( callback ){
+ updateCallbackArray.push(callback);
+ loadImageData(fileData, function(imageData, width, height){
+ parseImage(imageData.data, width, height);
+ });
+ },
+ compareTo: function(secondFileData){
+ return getCompareApi(secondFileData);
+ }
+ };
+
+ };
+}(this));
\ No newline at end of file
diff --git a/test/testsuite.js b/test/testsuite.js
deleted file mode 100644
index b486acb..0000000
--- a/test/testsuite.js
+++ /dev/null
@@ -1,36 +0,0 @@
-requirejs.config({
- baseUrl: '/test/unit/'
-});
-
-define(function(require) {
- var testModules = [
- 'Pixi',
- 'Point',
- 'Rectangle',
- 'DisplayObject',
- 'DisplayObjectContainer',
- 'Sprite',
- 'MovieClip',
- 'InteractionManager',
- 'Stage',
- 'utils/Utils',
- 'utils/EventTarget',
- 'utils/Matrix',
- 'utils/Detector',
- 'renderers/WebGLShaders',
- 'renderers/WebGLRenderer',
- 'renderers/WebGLBatch',
- 'renderers/CanvasRenderer',
- 'extras/Strip',
- 'extras/Rope',
- 'textures/BaseTexture',
- 'textures/Texture',
- 'loaders/SpriteSheetLoader',
- 'loaders/AssetLoader'
- ];
-
- // Resolve all testModules and then start the Test Runner.
- require(testModules, function() {
- QUnit.start();
- });
-});
\ No newline at end of file
diff --git a/test/textures/SpriteSheet-Aliens.png b/test/textures/SpriteSheet-Aliens.png
new file mode 100644
index 0000000..210acb1
--- /dev/null
+++ b/test/textures/SpriteSheet-Aliens.png
Binary files differ
diff --git a/test/textures/SpriteSheet-Explosion.png b/test/textures/SpriteSheet-Explosion.png
new file mode 100755
index 0000000..79e1a69
--- /dev/null
+++ b/test/textures/SpriteSheet-Explosion.png
Binary files differ
diff --git a/test/textures/bunny.png b/test/textures/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/textures/bunny.png
Binary files differ
diff --git a/test/unit/DisplayObject.js b/test/unit/DisplayObject.js
deleted file mode 100644
index 5e7e72f..0000000
--- a/test/unit/DisplayObject.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObject');
-});
diff --git a/test/unit/DisplayObjectContainer.js b/test/unit/DisplayObjectContainer.js
deleted file mode 100644
index b323959..0000000
--- a/test/unit/DisplayObjectContainer.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObjectContainer');
-});
diff --git a/test/unit/InteractionManager.js b/test/unit/InteractionManager.js
deleted file mode 100644
index e751f52..0000000
--- a/test/unit/InteractionManager.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('InteractionManager');
-});
diff --git a/test/unit/MovieClip.js b/test/unit/MovieClip.js
deleted file mode 100644
index 37d9446..0000000
--- a/test/unit/MovieClip.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('MovieClip');
-});
diff --git a/test/unit/Pixi.js b/test/unit/Pixi.js
deleted file mode 100644
index 36eee73..0000000
--- a/test/unit/Pixi.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Pixi');
-});
diff --git a/.gitignore b/.gitignore
index 12e1b62..0b88317 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
node_modules
.DS_Store
-.project
\ No newline at end of file
+.project
+*.log
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..63e4d7c
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,8 @@
+language: node_js
+node_js:
+ - 0.10
+
+before_script:
+ - npm install -g grunt-cli
+ - export DISPLAY=:99.0
+ - sh -e /etc/init.d/xvfb start
diff --git a/Gruntfile.js b/Gruntfile.js
index b083b49..103938c 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -1,10 +1,12 @@
+'use strict';
+
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-connect');
- grunt.loadNpmTasks('grunt-contrib-qunit');
grunt.loadNpmTasks('grunt-contrib-yuidoc');
+ grunt.loadTasks('tasks');
var root = 'src/pixi/',
debug = 'bin/pixi.dev.js',
@@ -79,7 +81,7 @@
},
files: {
srcBlob: '<%= dirs.src %>/**/*.js',
- testBlob: '<%= dirs.test %>/unit/**/*.js',
+ testBlob: '<%= dirs.test %>/{functional,lib/pixi,unit}/**/*.js',
build: '<%= dirs.build %>/pixi.dev.js',
buildMin: '<%= dirs.build %>/pixi.js'
},
@@ -94,7 +96,12 @@
},
jshint: {
beforeconcat: srcFiles,
- test: ['<%= files.testBlob %>'],
+ test: {
+ src: ['<%= files.testBlob %>'],
+ options: {
+ expr: true
+ }
+ },
options: {
asi: true,
smarttabs: true
@@ -128,12 +135,6 @@
]
},
connect: {
- qunit: {
- options: {
- port: grunt.option('port-test') || 9002,
- base: './'
- }
- },
test: {
options: {
port: grunt.option('port-test') || 9002,
@@ -142,13 +143,6 @@
}
}
},
- qunit: {
- all: {
- options: {
- urls: ['http://localhost:' + (grunt.option('port-test') || 9002) + '/test/index.html']
- }
- }
- },
yuidoc: {
compile: {
name: '<%= pkg.name %>',
@@ -161,6 +155,13 @@
outdir: '<%= dirs.docs %>'
}
}
+ },
+ karma: {
+ unit: {
+ configFile: 'test/karma.conf.js',
+ // browsers: ['Chrome'],
+ singleRun: true
+ }
}
});
@@ -182,9 +183,10 @@
}
)
- grunt.registerTask('default', ['concat', 'uglify', 'distribute']);
grunt.registerTask('build', ['concat', 'uglify', 'distribute']);
- grunt.registerTask('test', ['build', 'connect:qunit', 'qunit']);
+ grunt.registerTask('test', ['concat', 'jshint:test', 'karma']);
grunt.registerTask('docs', ['yuidoc']);
-
-}
\ No newline at end of file
+ grunt.registerTask('default', ['test', 'uglify', 'distribute']);
+ // Travis CI task.
+ grunt.registerTask('travis', ['test']);
+}
diff --git a/README.md b/README.md
index c62ef86..690cfe4 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,8 @@

+[](http://travis-ci.org/drkibitz/pixi.js)
+
#### JavaScript 2D Renderer ####
The aim of this project is to provide a fast lightweight 2D library that works
diff --git a/package.json b/package.json
index b373240..1246a68 100644
--- a/package.json
+++ b/package.json
@@ -18,14 +18,21 @@
"main": "bin/pixi.js",
+ "scripts": {
+ "test": "grunt travis --verbose"
+ },
+
"dependencies": {},
"devDependencies": {
"grunt": "~0.4.x",
- "grunt-contrib-jshint": "0.3.x",
+ "grunt-contrib-jshint": "0.6.x",
"grunt-contrib-uglify": "0.2.x",
- "grunt-contrib-connect": "0.2.x",
- "grunt-contrib-qunit": "0.2.x",
+ "grunt-contrib-connect": "0.3.x",
"grunt-contrib-yuidoc": "0.4.x",
- "grunt-contrib-concat": "0.1.x"
+ "grunt-contrib-concat": "0.3.x",
+ "chai": "~1.7.0",
+ "karma": "0.11.0",
+ "karma-firefox-launcher": "0.1.0",
+ "karma-mocha": "0.1.0"
}
}
diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js
index a7c520e..ee82bbd 100644
--- a/src/pixi/InteractionManager.js
+++ b/src/pixi/InteractionManager.js
@@ -62,7 +62,6 @@
this.onTouchEnd = this.onTouchEnd.bind(this);
this.onTouchMove = this.onTouchMove.bind(this);
-
this.last = 0;
}
diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js
index 1a95d20..eef1059 100644
--- a/src/pixi/core/Ellipse.js
+++ b/src/pixi/core/Ellipse.js
@@ -78,7 +78,7 @@
return (normx + normy < 0.25);
}
-PIXI.Ellipse.getBounds = function()
+PIXI.Ellipse.prototype.getBounds = function()
{
return new PIXI.Rectangle(this.x, this.y, this.width, this.height);
}
diff --git a/tasks/karma.js b/tasks/karma.js
new file mode 100644
index 0000000..c340485
--- /dev/null
+++ b/tasks/karma.js
@@ -0,0 +1,27 @@
+'use strict';
+
+var path = require('path');
+var server = require('karma').server;
+
+module.exports = function (grunt) {
+ grunt.registerMultiTask('karma', 'run karma.', function() {
+ var done = this.async();
+ var options = this.options({
+ background: false
+ });
+ var data = this.data;
+
+ //merge options onto data, with data taking precedence
+ data = grunt.util._.merge(options, data);
+ data.configFile = path.resolve(data.configFile);
+ if (data.configFile) {
+ data.configFile = grunt.template.process(data.configFile);
+ }
+
+ server.start(
+ data,
+ function(code) {
+ done(!code);
+ });
+ });
+};
diff --git a/test/functional/example-1-basics/bunny.png b/test/functional/example-1-basics/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/functional/example-1-basics/bunny.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-30.png b/test/functional/example-1-basics/frame-30.png
new file mode 100644
index 0000000..96e3409
--- /dev/null
+++ b/test/functional/example-1-basics/frame-30.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-60.png b/test/functional/example-1-basics/frame-60.png
new file mode 100644
index 0000000..af3f4ce
--- /dev/null
+++ b/test/functional/example-1-basics/frame-60.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-90.png b/test/functional/example-1-basics/frame-90.png
new file mode 100644
index 0000000..099b823
--- /dev/null
+++ b/test/functional/example-1-basics/frame-90.png
Binary files differ
diff --git a/test/functional/example-1-basics/index.js b/test/functional/example-1-basics/index.js
new file mode 100644
index 0000000..7ae7a98
--- /dev/null
+++ b/test/functional/example-1-basics/index.js
@@ -0,0 +1,133 @@
+describe('Example 1 - Basics', function () {
+ 'use strict';
+
+ var baseUri = '/base/test/functional/example-1-basics';
+ var expect = chai.expect;
+ var currentFrame = 0;
+ var frameEvents = {};
+ var stage;
+ var renderer;
+ var bunny;
+
+ function onFrame(frame, callback) {
+ frameEvents[frame] = callback;
+ }
+
+ function animate() {
+ currentFrame += 1;
+
+ requestAnimFrame( animate );
+
+ // just for fun, lets rotate mr rabbit a little
+ bunny.rotation += 0.1;
+
+ // render the stage
+ renderer.render(stage);
+
+ if (frameEvents[currentFrame])
+ frameEvents[currentFrame](currentFrame);
+ }
+
+ function initScene() {
+ // create an new instance of a pixi stage
+ stage = new PIXI.Stage(0x66FF99);
+
+ // create a renderer instance
+ renderer = PIXI.autoDetectRenderer(400, 300);
+ console.log('Is PIXI.WebGLRenderer: ' + (renderer instanceof PIXI.WebGLRenderer));
+
+ // add the renderer view element to the DOM
+ document.body.appendChild(renderer.view);
+
+ requestAnimFrame( animate );
+
+ // create a texture from an image path
+ var texture = PIXI.Texture.fromImage(baseUri + "/bunny.png");
+ // create a new Sprite using the texture
+ bunny = new PIXI.Sprite(texture);
+
+ // center the sprites anchor point
+ bunny.anchor.x = 0.5;
+ bunny.anchor.y = 0.5;
+
+ // move the sprite t the center of the screen
+ bunny.position.x = 200;
+ bunny.position.y = 150;
+
+ stage.addChild(bunny);
+ }
+
+ it('assets loaded', function (done) {
+ var loader = new PIXI.AssetLoader([
+ baseUri + '/bunny.png',
+ baseUri + '/frame-30.png',
+ baseUri + '/frame-60.png',
+ baseUri + '/frame-90.png'
+ ]);
+ // loader.on('onProgress', function (event) {
+ // console.log(event.content);
+ // });
+ loader.on('onComplete', function (event) {
+ done();
+ initScene();
+ });
+ loader.load();
+ });
+
+ it('frame 30 should match', function (done) {
+ this.timeout(700);
+ onFrame(30, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-30.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 60 should match', function (done) {
+ this.timeout(1200);
+ onFrame(60, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-60.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 90 should match', function (done) {
+ this.timeout(1700);
+ onFrame(90, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-90.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ // it('capture something', function (done) {
+ // this.timeout(2000000);
+ // onFrame(30, function () {
+ // var img = new Image();
+ // img.src = renderer.view.toDataURL('image/png');
+ // document.body.appendChild(img);
+ // });
+ // });
+});
diff --git a/test/index.html b/test/index.html
deleted file mode 100644
index 9cbcac5..0000000
--- a/test/index.html
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
- Pixi.js Test Suite
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/test/karma.conf.js b/test/karma.conf.js
new file mode 100644
index 0000000..c66a696
--- /dev/null
+++ b/test/karma.conf.js
@@ -0,0 +1,82 @@
+module.exports = function(config) {
+ config.set({
+
+ // base path, that will be used to resolve files and exclude
+ basePath : '../',
+
+ frameworks : ['mocha'],
+
+ // list of files / patterns to load in the browser
+ files : [
+ 'node_modules/chai/chai.js',
+ 'bin/pixi.dev.js',
+ 'test/lib/**/*.js',
+ 'test/unit/**/*.js',
+ // 'test/functional/**/*.js',
+ {pattern: 'test/**/*.png', watched: false, included: false, served: true}
+ ],
+
+ // list of files to exclude
+ exclude : [],
+
+ // use dolts reporter, as travis terminal does not support escaping sequences
+ // possible values: 'dots', 'progress', 'junit', 'teamcity'
+ // CLI --reporters progress
+ reporters : ['progress'],
+
+ // web server port
+ // CLI --port 9876
+ port : 9876,
+
+ // cli runner port
+ // CLI --runner-port 9100
+ runnerPort : 9100,
+
+ // enable / disable colors in the output (reporters and logs)
+ // CLI --colors --no-colors
+ colors : true,
+
+ // level of logging
+ // possible values: karma.LOG_DISABLE || karma.LOG_ERROR || karma.LOG_WARN || karma.LOG_INFO || karma.LOG_DEBUG
+ // CLI --log-level debug
+ logLevel : config.LOG_DEBUG,
+
+ // enable / disable watching file and executing tests whenever any file changes
+ // CLI --auto-watch --no-auto-watch
+ autoWatch : false,
+
+ // Start these browsers, currently available:
+ // - Chrome
+ // - ChromeCanary
+ // - Firefox
+ // - Opera
+ // - Safari (only Mac)
+ // - PhantomJS
+ // - IE (only Windows)
+ // CLI --browsers Chrome,Firefox,Safari
+ browsers : ['Firefox'],
+
+ // If browser does not capture in given timeout [ms], kill it
+ // CLI --capture-timeout 5000
+ captureTimeout : 5000,
+
+ // Auto run tests on start (when browsers are captured) and exit
+ // CLI --single-run --no-single-run
+ singleRun : true,
+
+ // report which specs are slower than 500ms
+ // CLI --report-slower-than 500
+ reportSlowerThan : 1000,
+
+ preprocessors : {
+ // '**/client/js/*.js': 'coverage'
+ },
+
+ plugins : [
+ 'karma-mocha',
+ // 'karma-chrome-launcher',
+ 'karma-firefox-launcher',
+ // 'karma-phantomjs-launcher'
+ ]
+ });
+};
diff --git a/test/lib/pixi/core/Matrix.js b/test/lib/pixi/core/Matrix.js
new file mode 100644
index 0000000..d26386b
--- /dev/null
+++ b/test/lib/pixi/core/Matrix.js
@@ -0,0 +1,40 @@
+
+function pixi_core_Matrix_confirmNewMat3(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(1);
+ expect(matrix[5]).to.equal(0);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(1);
+}
+
+function pixi_core_Matrix_confirmNewMat4(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[0]).to.equal(1);
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(0);
+ expect(matrix[5]).to.equal(1);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(0);
+ expect(matrix[9]).to.equal(0);
+ expect(matrix[10]).to.equal(1);
+ expect(matrix[11]).to.equal(0);
+ expect(matrix[12]).to.equal(0);
+ expect(matrix[13]).to.equal(0);
+ expect(matrix[14]).to.equal(0);
+ expect(matrix[15]).to.equal(1);
+}
diff --git a/test/lib/pixi/core/Point.js b/test/lib/pixi/core/Point.js
new file mode 100644
index 0000000..e5df07b
--- /dev/null
+++ b/test/lib/pixi/core/Point.js
@@ -0,0 +1,10 @@
+
+function pixi_core_Point_confirm(obj, x, y) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Point);
+ expect(obj).to.respondTo('clone');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+}
diff --git a/test/lib/pixi/core/Rectangle.js b/test/lib/pixi/core/Rectangle.js
new file mode 100644
index 0000000..23f0d12
--- /dev/null
+++ b/test/lib/pixi/core/Rectangle.js
@@ -0,0 +1,13 @@
+
+function pixi_core_Rectangle_confirm(obj, x, y, width, height) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Rectangle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+ expect(obj).to.have.property('width', width);
+ expect(obj).to.have.property('height', height);
+}
diff --git a/test/lib/pixi/display/DisplayObject.js b/test/lib/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..1388a7f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObject.js
@@ -0,0 +1,43 @@
+
+function pixi_display_DisplayObject_confirmNew(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObject);
+ expect(obj).to.respondTo('setInteractive');
+ expect(obj).to.respondTo('addFilter');
+ expect(obj).to.respondTo('removeFilter');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.property('last', obj);
+ expect(obj).to.have.property('first', obj);
+
+ expect(obj).to.contain.property('position');
+ pixi_core_Point_confirm(obj.position, 0, 0);
+ expect(obj).to.contain.property('scale');
+ pixi_core_Point_confirm(obj.scale, 1, 1);
+ expect(obj).to.contain.property('pivot');
+ pixi_core_Point_confirm(obj.pivot, 0, 0);
+
+ expect(obj).to.have.property('rotation', 0);
+ expect(obj).to.have.property('alpha', 1);
+ expect(obj).to.have.property('visible', true);
+ expect(obj).to.have.property('buttonMode', false);
+ expect(obj).to.have.property('parent', null);
+ expect(obj).to.have.property('worldAlpha', 1);
+
+ expect(obj).to.have.property('hitArea');
+ expect(obj).to.have.property('interactive'); // TODO: Have a better default value
+ expect('mask' in obj).to.be.true; // TODO: Have a better default value
+ expect(obj.mask).to.be.undefined;
+
+ expect(obj).to.have.property('renderable');
+ expect(obj).to.have.property('stage');
+
+ expect(obj).to.have.deep.property('worldTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ expect(obj).to.have.deep.property('localTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.localTransform);
+
+ expect(obj).to.have.deep.property('color.length', 0);
+ expect(obj).to.have.property('dynamic', true);
+}
diff --git a/test/lib/pixi/display/DisplayObjectContainer.js b/test/lib/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..085c59f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,16 @@
+
+function pixi_display_DisplayObjectContainer_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObject_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObjectContainer);
+ expect(obj).to.respondTo('addChild');
+ expect(obj).to.respondTo('addChildAt');
+ expect(obj).to.respondTo('swapChildren');
+ expect(obj).to.respondTo('getChildAt');
+ expect(obj).to.respondTo('removeChild');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('children.length', 0);
+}
diff --git a/test/lib/pixi/display/Sprite.js b/test/lib/pixi/display/Sprite.js
new file mode 100644
index 0000000..cc7a2d6
--- /dev/null
+++ b/test/lib/pixi/display/Sprite.js
@@ -0,0 +1,28 @@
+
+function pixi_display_Sprite_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Sprite);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', true);
+ expect(obj).to.have.property('stage', null);
+
+ expect(obj).to.have.property('anchor');
+ pixi_core_Point_confirm(obj.anchor, 0, 0);
+
+ expect(obj).to.have.property('blendMode', PIXI.blendModes.NORMAL);
+ expect(obj).to.have.property('width', 1); // TODO: is 1 expected
+ expect(obj).to.have.property('height', 1); // TODO: is 1 expected
+
+ // FIXME: Just make this a boolean that is always there
+ expect(!!obj.updateFrame).to.equal(obj.texture.baseTexture.hasLoaded);
+
+ expect(obj).to.have.property('texture');
+ pixi_textures_Texture_confirmNew(obj.texture, done);
+}
diff --git a/test/lib/pixi/extras/Strip.js b/test/lib/pixi/extras/Strip.js
new file mode 100644
index 0000000..8927a8a
--- /dev/null
+++ b/test/lib/pixi/extras/Strip.js
@@ -0,0 +1,12 @@
+
+function pixi_extras_Strip_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Strip);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ // TODO: Test properties
+}
diff --git a/test/lib/pixi/textures/Texture.js b/test/lib/pixi/textures/Texture.js
new file mode 100644
index 0000000..d5867b6
--- /dev/null
+++ b/test/lib/pixi/textures/Texture.js
@@ -0,0 +1,31 @@
+
+function pixi_textures_Texture_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ function confirmFrameDone() {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, obj.baseTexture.width, obj.baseTexture.height);
+
+ expect(obj).to.have.property('width', obj.baseTexture.width);
+ expect(obj).to.have.property('height', obj.baseTexture.height);
+ done();
+ }
+
+ expect(obj).to.be.an.instanceof(PIXI.Texture);
+ pixi_utils_EventTarget_like(obj);
+
+ expect(obj).to.have.property('baseTexture')
+ .and.to.be.an.instanceof(PIXI.BaseTexture);
+
+ expect(obj).to.have.property('scope', obj);
+
+ expect(obj).to.have.property('trim');
+ pixi_core_Point_confirm(obj.trim, 0, 0);
+
+ expect(obj).to.have.property('frame');
+ if (obj.baseTexture.hasLoaded) {
+ confirmFrameDone();
+ } else {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, 1, 1);
+ obj.addEventListener('update', confirmFrameDone);
+ }
+}
diff --git a/test/lib/pixi/utils/EventTarget.js b/test/lib/pixi/utils/EventTarget.js
new file mode 100644
index 0000000..7b1dcfa
--- /dev/null
+++ b/test/lib/pixi/utils/EventTarget.js
@@ -0,0 +1,8 @@
+
+function pixi_utils_EventTarget_like(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.respondTo('addEventListener');
+ expect(obj).to.respondTo('dispatchEvent');
+ expect(obj).to.respondTo('removeEventListener');
+}
diff --git a/test/lib/qunit-1.11.0.css b/test/lib/qunit-1.11.0.css
deleted file mode 100644
index d7fc0c8..0000000
--- a/test/lib/qunit-1.11.0.css
+++ /dev/null
@@ -1,244 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-/** Font Family and Sizes */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
- font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
-}
-
-#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
-#qunit-tests { font-size: smaller; }
-
-
-/** Resets */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter {
- margin: 0;
- padding: 0;
-}
-
-
-/** Header */
-
-#qunit-header {
- padding: 0.5em 0 0.5em 1em;
-
- color: #8699a4;
- background-color: #0d3349;
-
- font-size: 1.5em;
- line-height: 1em;
- font-weight: normal;
-
- border-radius: 5px 5px 0 0;
- -moz-border-radius: 5px 5px 0 0;
- -webkit-border-top-right-radius: 5px;
- -webkit-border-top-left-radius: 5px;
-}
-
-#qunit-header a {
- text-decoration: none;
- color: #c2ccd1;
-}
-
-#qunit-header a:hover,
-#qunit-header a:focus {
- color: #fff;
-}
-
-#qunit-testrunner-toolbar label {
- display: inline-block;
- padding: 0 .5em 0 .1em;
-}
-
-#qunit-banner {
- height: 5px;
-}
-
-#qunit-testrunner-toolbar {
- padding: 0.5em 0 0.5em 2em;
- color: #5E740B;
- background-color: #eee;
- overflow: hidden;
-}
-
-#qunit-userAgent {
- padding: 0.5em 0 0.5em 2.5em;
- background-color: #2b81af;
- color: #fff;
- text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
-}
-
-#qunit-modulefilter-container {
- float: right;
-}
-
-/** Tests: Pass/Fail */
-
-#qunit-tests {
- list-style-position: inside;
-}
-
-#qunit-tests li {
- padding: 0.4em 0.5em 0.4em 2.5em;
- border-bottom: 1px solid #fff;
- list-style-position: inside;
-}
-
-#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running {
- display: none;
-}
-
-#qunit-tests li strong {
- cursor: pointer;
-}
-
-#qunit-tests li a {
- padding: 0.5em;
- color: #c2ccd1;
- text-decoration: none;
-}
-#qunit-tests li a:hover,
-#qunit-tests li a:focus {
- color: #000;
-}
-
-#qunit-tests li .runtime {
- float: right;
- font-size: smaller;
-}
-
-.qunit-assert-list {
- margin-top: 0.5em;
- padding: 0.5em;
-
- background-color: #fff;
-
- border-radius: 5px;
- -moz-border-radius: 5px;
- -webkit-border-radius: 5px;
-}
-
-.qunit-collapsed {
- display: none;
-}
-
-#qunit-tests table {
- border-collapse: collapse;
- margin-top: .2em;
-}
-
-#qunit-tests th {
- text-align: right;
- vertical-align: top;
- padding: 0 .5em 0 0;
-}
-
-#qunit-tests td {
- vertical-align: top;
-}
-
-#qunit-tests pre {
- margin: 0;
- white-space: pre-wrap;
- word-wrap: break-word;
-}
-
-#qunit-tests del {
- background-color: #e0f2be;
- color: #374e0c;
- text-decoration: none;
-}
-
-#qunit-tests ins {
- background-color: #ffcaca;
- color: #500;
- text-decoration: none;
-}
-
-/*** Test Counts */
-
-#qunit-tests b.counts { color: black; }
-#qunit-tests b.passed { color: #5E740B; }
-#qunit-tests b.failed { color: #710909; }
-
-#qunit-tests li li {
- padding: 5px;
- background-color: #fff;
- border-bottom: none;
- list-style-position: inside;
-}
-
-/*** Passing Styles */
-
-#qunit-tests li li.pass {
- color: #3c510c;
- background-color: #fff;
- border-left: 10px solid #C6E746;
-}
-
-#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
-#qunit-tests .pass .test-name { color: #366097; }
-
-#qunit-tests .pass .test-actual,
-#qunit-tests .pass .test-expected { color: #999999; }
-
-#qunit-banner.qunit-pass { background-color: #C6E746; }
-
-/*** Failing Styles */
-
-#qunit-tests li li.fail {
- color: #710909;
- background-color: #fff;
- border-left: 10px solid #EE5757;
- white-space: pre;
-}
-
-#qunit-tests > li:last-child {
- border-radius: 0 0 5px 5px;
- -moz-border-radius: 0 0 5px 5px;
- -webkit-border-bottom-right-radius: 5px;
- -webkit-border-bottom-left-radius: 5px;
-}
-
-#qunit-tests .fail { color: #000000; background-color: #EE5757; }
-#qunit-tests .fail .test-name,
-#qunit-tests .fail .module-name { color: #000000; }
-
-#qunit-tests .fail .test-actual { color: #EE5757; }
-#qunit-tests .fail .test-expected { color: green; }
-
-#qunit-banner.qunit-fail { background-color: #EE5757; }
-
-
-/** Result */
-
-#qunit-testresult {
- padding: 0.5em 0.5em 0.5em 2.5em;
-
- color: #2b81af;
- background-color: #D2E0E6;
-
- border-bottom: 1px solid white;
-}
-#qunit-testresult .module-name {
- font-weight: bold;
-}
-
-/** Fixture */
-
-#qunit-fixture {
- position: absolute;
- top: -10000px;
- left: -10000px;
- width: 1000px;
- height: 1000px;
-}
diff --git a/test/lib/qunit-1.11.0.js b/test/lib/qunit-1.11.0.js
deleted file mode 100644
index 302545f..0000000
--- a/test/lib/qunit-1.11.0.js
+++ /dev/null
@@ -1,2152 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-(function( window ) {
-
-var QUnit,
- assert,
- config,
- onErrorFnPrev,
- testId = 0,
- fileName = (sourceFromStacktrace( 0 ) || "" ).replace(/(:\d+)+\)?/, "").replace(/.+\//, ""),
- toString = Object.prototype.toString,
- hasOwn = Object.prototype.hasOwnProperty,
- // Keep a local reference to Date (GH-283)
- Date = window.Date,
- defined = {
- setTimeout: typeof window.setTimeout !== "undefined",
- sessionStorage: (function() {
- var x = "qunit-test-string";
- try {
- sessionStorage.setItem( x, x );
- sessionStorage.removeItem( x );
- return true;
- } catch( e ) {
- return false;
- }
- }())
- },
- /**
- * Provides a normalized error string, correcting an issue
- * with IE 7 (and prior) where Error.prototype.toString is
- * not properly implemented
- *
- * Based on http://es5.github.com/#x15.11.4.4
- *
- * @param {String|Error} error
- * @return {String} error message
- */
- errorString = function( error ) {
- var name, message,
- errorString = error.toString();
- if ( errorString.substring( 0, 7 ) === "[object" ) {
- name = error.name ? error.name.toString() : "Error";
- message = error.message ? error.message.toString() : "";
- if ( name && message ) {
- return name + ": " + message;
- } else if ( name ) {
- return name;
- } else if ( message ) {
- return message;
- } else {
- return "Error";
- }
- } else {
- return errorString;
- }
- },
- /**
- * Makes a clone of an object using only Array or Object as base,
- * and copies over the own enumerable properties.
- *
- * @param {Object} obj
- * @return {Object} New object with only the own properties (recursively).
- */
- objectValues = function( obj ) {
- // Grunt 0.3.x uses an older version of jshint that still has jshint/jshint#392.
- /*jshint newcap: false */
- var key, val,
- vals = QUnit.is( "array", obj ) ? [] : {};
- for ( key in obj ) {
- if ( hasOwn.call( obj, key ) ) {
- val = obj[key];
- vals[key] = val === Object(val) ? objectValues(val) : val;
- }
- }
- return vals;
- };
-
-function Test( settings ) {
- extend( this, settings );
- this.assertions = [];
- this.testNumber = ++Test.count;
-}
-
-Test.count = 0;
-
-Test.prototype = {
- init: function() {
- var a, b, li,
- tests = id( "qunit-tests" );
-
- if ( tests ) {
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml;
-
- // `a` initialized at top of scope
- a = document.createElement( "a" );
- a.innerHTML = "Rerun";
- a.href = QUnit.url({ testNumber: this.testNumber });
-
- li = document.createElement( "li" );
- li.appendChild( b );
- li.appendChild( a );
- li.className = "running";
- li.id = this.id = "qunit-test-output" + testId++;
-
- tests.appendChild( li );
- }
- },
- setup: function() {
- if ( this.module !== config.previousModule ) {
- if ( config.previousModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.previousModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
- config.previousModule = this.module;
- config.moduleStats = { all: 0, bad: 0 };
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- } else if ( config.autorun ) {
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- }
-
- config.current = this;
-
- this.testEnvironment = extend({
- setup: function() {},
- teardown: function() {}
- }, this.moduleTestEnvironment );
-
- this.started = +new Date();
- runLoggingCallbacks( "testStart", QUnit, {
- name: this.testName,
- module: this.module
- });
-
- // allow utility functions to access the current test environment
- // TODO why??
- QUnit.current_testEnvironment = this.testEnvironment;
-
- if ( !config.pollution ) {
- saveGlobal();
- }
- if ( config.notrycatch ) {
- this.testEnvironment.setup.call( this.testEnvironment );
- return;
- }
- try {
- this.testEnvironment.setup.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Setup failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- },
- run: function() {
- config.current = this;
-
- var running = id( "qunit-testresult" );
-
- if ( running ) {
- running.innerHTML = "Running:
" + this.nameHtml;
- }
-
- if ( this.async ) {
- QUnit.stop();
- }
-
- this.callbackStarted = +new Date();
-
- if ( config.notrycatch ) {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- return;
- }
-
- try {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- } catch( e ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
-
- QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + " " + this.stack + ": " + ( e.message || e ), extractStacktrace( e, 0 ) );
- // else next test will carry the responsibility
- saveGlobal();
-
- // Restart the tests if they're blocking
- if ( config.blocking ) {
- QUnit.start();
- }
- }
- },
- teardown: function() {
- config.current = this;
- if ( config.notrycatch ) {
- if ( typeof this.callbackRuntime === "undefined" ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
- }
- this.testEnvironment.teardown.call( this.testEnvironment );
- return;
- } else {
- try {
- this.testEnvironment.teardown.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Teardown failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- }
- checkPollution();
- },
- finish: function() {
- config.current = this;
- if ( config.requireExpects && this.expected === null ) {
- QUnit.pushFailure( "Expected number of assertions to be defined, but expect() was not called.", this.stack );
- } else if ( this.expected !== null && this.expected !== this.assertions.length ) {
- QUnit.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack );
- } else if ( this.expected === null && !this.assertions.length ) {
- QUnit.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions.", this.stack );
- }
-
- var i, assertion, a, b, time, li, ol,
- test = this,
- good = 0,
- bad = 0,
- tests = id( "qunit-tests" );
-
- this.runtime = +new Date() - this.started;
- config.stats.all += this.assertions.length;
- config.moduleStats.all += this.assertions.length;
-
- if ( tests ) {
- ol = document.createElement( "ol" );
- ol.className = "qunit-assert-list";
-
- for ( i = 0; i < this.assertions.length; i++ ) {
- assertion = this.assertions[i];
-
- li = document.createElement( "li" );
- li.className = assertion.result ? "pass" : "fail";
- li.innerHTML = assertion.message || ( assertion.result ? "okay" : "failed" );
- ol.appendChild( li );
-
- if ( assertion.result ) {
- good++;
- } else {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
-
- // store result when possible
- if ( QUnit.config.reorder && defined.sessionStorage ) {
- if ( bad ) {
- sessionStorage.setItem( "qunit-test-" + this.module + "-" + this.testName, bad );
- } else {
- sessionStorage.removeItem( "qunit-test-" + this.module + "-" + this.testName );
- }
- }
-
- if ( bad === 0 ) {
- addClass( ol, "qunit-collapsed" );
- }
-
- // `b` initialized at top of scope
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml + " (" + bad + ", " + good + ", " + this.assertions.length + ")";
-
- addEvent(b, "click", function() {
- var next = b.parentNode.lastChild,
- collapsed = hasClass( next, "qunit-collapsed" );
- ( collapsed ? removeClass : addClass )( next, "qunit-collapsed" );
- });
-
- addEvent(b, "dblclick", function( e ) {
- var target = e && e.target ? e.target : window.event.srcElement;
- if ( target.nodeName.toLowerCase() === "span" || target.nodeName.toLowerCase() === "b" ) {
- target = target.parentNode;
- }
- if ( window.location && target.nodeName.toLowerCase() === "strong" ) {
- window.location = QUnit.url({ testNumber: test.testNumber });
- }
- });
-
- // `time` initialized at top of scope
- time = document.createElement( "span" );
- time.className = "runtime";
- time.innerHTML = this.runtime + " ms";
-
- // `li` initialized at top of scope
- li = id( this.id );
- li.className = bad ? "fail" : "pass";
- li.removeChild( li.firstChild );
- a = li.firstChild;
- li.appendChild( b );
- li.appendChild( a );
- li.appendChild( time );
- li.appendChild( ol );
-
- } else {
- for ( i = 0; i < this.assertions.length; i++ ) {
- if ( !this.assertions[i].result ) {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
- }
-
- runLoggingCallbacks( "testDone", QUnit, {
- name: this.testName,
- module: this.module,
- failed: bad,
- passed: this.assertions.length - bad,
- total: this.assertions.length,
- duration: this.runtime
- });
-
- QUnit.reset();
-
- config.current = undefined;
- },
-
- queue: function() {
- var bad,
- test = this;
-
- synchronize(function() {
- test.init();
- });
- function run() {
- // each of these can by async
- synchronize(function() {
- test.setup();
- });
- synchronize(function() {
- test.run();
- });
- synchronize(function() {
- test.teardown();
- });
- synchronize(function() {
- test.finish();
- });
- }
-
- // `bad` initialized at top of scope
- // defer when previous test run passed, if storage is available
- bad = QUnit.config.reorder && defined.sessionStorage &&
- +sessionStorage.getItem( "qunit-test-" + this.module + "-" + this.testName );
-
- if ( bad ) {
- run();
- } else {
- synchronize( run, true );
- }
- }
-};
-
-// Root QUnit object.
-// `QUnit` initialized at top of scope
-QUnit = {
-
- // call on start of module test to prepend name to all tests
- module: function( name, testEnvironment ) {
- config.currentModule = name;
- config.currentModuleTestEnvironment = testEnvironment;
- config.modules[name] = true;
- },
-
- asyncTest: function( testName, expected, callback ) {
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- QUnit.test( testName, expected, callback, true );
- },
-
- test: function( testName, expected, callback, async ) {
- var test,
- nameHtml = "" + escapeText( testName ) + "";
-
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- if ( config.currentModule ) {
- nameHtml = "" + escapeText( config.currentModule ) + ": " + nameHtml;
- }
-
- test = new Test({
- nameHtml: nameHtml,
- testName: testName,
- expected: expected,
- async: async,
- callback: callback,
- module: config.currentModule,
- moduleTestEnvironment: config.currentModuleTestEnvironment,
- stack: sourceFromStacktrace( 2 )
- });
-
- if ( !validTest( test ) ) {
- return;
- }
-
- test.queue();
- },
-
- // Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through.
- expect: function( asserts ) {
- if (arguments.length === 1) {
- config.current.expected = asserts;
- } else {
- return config.current.expected;
- }
- },
-
- start: function( count ) {
- // QUnit hasn't been initialized yet.
- // Note: RequireJS (et al) may delay onLoad
- if ( config.semaphore === undefined ) {
- QUnit.begin(function() {
- // This is triggered at the top of QUnit.load, push start() to the event loop, to allow QUnit.load to finish first
- setTimeout(function() {
- QUnit.start( count );
- });
- });
- return;
- }
-
- config.semaphore -= count || 1;
- // don't start until equal number of stop-calls
- if ( config.semaphore > 0 ) {
- return;
- }
- // ignore if start is called more often then stop
- if ( config.semaphore < 0 ) {
- config.semaphore = 0;
- QUnit.pushFailure( "Called start() while already started (QUnit.config.semaphore was 0 already)", null, sourceFromStacktrace(2) );
- return;
- }
- // A slight delay, to avoid any current callbacks
- if ( defined.setTimeout ) {
- window.setTimeout(function() {
- if ( config.semaphore > 0 ) {
- return;
- }
- if ( config.timeout ) {
- clearTimeout( config.timeout );
- }
-
- config.blocking = false;
- process( true );
- }, 13);
- } else {
- config.blocking = false;
- process( true );
- }
- },
-
- stop: function( count ) {
- config.semaphore += count || 1;
- config.blocking = true;
-
- if ( config.testTimeout && defined.setTimeout ) {
- clearTimeout( config.timeout );
- config.timeout = window.setTimeout(function() {
- QUnit.ok( false, "Test timed out" );
- config.semaphore = 1;
- QUnit.start();
- }, config.testTimeout );
- }
- }
-};
-
-// `assert` initialized at top of scope
-// Asssert helpers
-// All of these must either call QUnit.push() or manually do:
-// - runLoggingCallbacks( "log", .. );
-// - config.current.assertions.push({ .. });
-// We attach it to the QUnit object *after* we expose the public API,
-// otherwise `assert` will become a global variable in browsers (#341).
-assert = {
- /**
- * Asserts rough true-ish result.
- * @name ok
- * @function
- * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" );
- */
- ok: function( result, msg ) {
- if ( !config.current ) {
- throw new Error( "ok() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
- result = !!result;
-
- var source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: msg
- };
-
- msg = escapeText( msg || (result ? "okay" : "failed" ) );
- msg = "" + msg + "";
-
- if ( !result ) {
- source = sourceFromStacktrace( 2 );
- if ( source ) {
- details.source = source;
- msg += "Source: | " + escapeText( source ) + " |
---|
";
- }
- }
- runLoggingCallbacks( "log", QUnit, details );
- config.current.assertions.push({
- result: result,
- message: msg
- });
- },
-
- /**
- * Assert that the first two arguments are equal, with an optional message.
- * Prints out both actual and expected values.
- * @name equal
- * @function
- * @example equal( format( "Received {0} bytes.", 2), "Received 2 bytes.", "format() replaces {0} with next argument" );
- */
- equal: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected == actual, actual, expected, message );
- },
-
- /**
- * @name notEqual
- * @function
- */
- notEqual: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected != actual, actual, expected, message );
- },
-
- /**
- * @name propEqual
- * @function
- */
- propEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notPropEqual
- * @function
- */
- notPropEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name deepEqual
- * @function
- */
- deepEqual: function( actual, expected, message ) {
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notDeepEqual
- * @function
- */
- notDeepEqual: function( actual, expected, message ) {
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name strictEqual
- * @function
- */
- strictEqual: function( actual, expected, message ) {
- QUnit.push( expected === actual, actual, expected, message );
- },
-
- /**
- * @name notStrictEqual
- * @function
- */
- notStrictEqual: function( actual, expected, message ) {
- QUnit.push( expected !== actual, actual, expected, message );
- },
-
- "throws": function( block, expected, message ) {
- var actual,
- expectedOutput = expected,
- ok = false;
-
- // 'expected' is optional
- if ( typeof expected === "string" ) {
- message = expected;
- expected = null;
- }
-
- config.current.ignoreGlobalErrors = true;
- try {
- block.call( config.current.testEnvironment );
- } catch (e) {
- actual = e;
- }
- config.current.ignoreGlobalErrors = false;
-
- if ( actual ) {
- // we don't want to validate thrown error
- if ( !expected ) {
- ok = true;
- expectedOutput = null;
- // expected is a regexp
- } else if ( QUnit.objectType( expected ) === "regexp" ) {
- ok = expected.test( errorString( actual ) );
- // expected is a constructor
- } else if ( actual instanceof expected ) {
- ok = true;
- // expected is a validation function which returns true is validation passed
- } else if ( expected.call( {}, actual ) === true ) {
- expectedOutput = null;
- ok = true;
- }
-
- QUnit.push( ok, actual, expectedOutput, message );
- } else {
- QUnit.pushFailure( message, null, 'No exception was thrown.' );
- }
- }
-};
-
-/**
- * @deprecate since 1.8.0
- * Kept assertion helpers in root for backwards compatibility.
- */
-extend( QUnit, assert );
-
-/**
- * @deprecated since 1.9.0
- * Kept root "raises()" for backwards compatibility.
- * (Note that we don't introduce assert.raises).
- */
-QUnit.raises = assert[ "throws" ];
-
-/**
- * @deprecated since 1.0.0, replaced with error pushes since 1.3.0
- * Kept to avoid TypeErrors for undefined methods.
- */
-QUnit.equals = function() {
- QUnit.push( false, false, false, "QUnit.equals has been deprecated since 2009 (e88049a0), use QUnit.equal instead" );
-};
-QUnit.same = function() {
- QUnit.push( false, false, false, "QUnit.same has been deprecated since 2009 (e88049a0), use QUnit.deepEqual instead" );
-};
-
-// We want access to the constructor's prototype
-(function() {
- function F() {}
- F.prototype = QUnit;
- QUnit = new F();
- // Make F QUnit's constructor so that we can add to the prototype later
- QUnit.constructor = F;
-}());
-
-/**
- * Config object: Maintain internal state
- * Later exposed as QUnit.config
- * `config` initialized at top of scope
- */
-config = {
- // The queue of tests to run
- queue: [],
-
- // block until document ready
- blocking: true,
-
- // when enabled, show only failing tests
- // gets persisted through sessionStorage and can be changed in UI via checkbox
- hidepassed: false,
-
- // by default, run previously failed tests first
- // very useful in combination with "Hide passed tests" checked
- reorder: true,
-
- // by default, modify document.title when suite is done
- altertitle: true,
-
- // when enabled, all tests must call expect()
- requireExpects: false,
-
- // add checkboxes that are persisted in the query-string
- // when enabled, the id is set to `true` as a `QUnit.config` property
- urlConfig: [
- {
- id: "noglobals",
- label: "Check for Globals",
- tooltip: "Enabling this will test if any test introduces new properties on the `window` object. Stored as query-strings."
- },
- {
- id: "notrycatch",
- label: "No try-catch",
- tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging exceptions in IE reasonable. Stored as query-strings."
- }
- ],
-
- // Set of all modules.
- modules: {},
-
- // logging callback queues
- begin: [],
- done: [],
- log: [],
- testStart: [],
- testDone: [],
- moduleStart: [],
- moduleDone: []
-};
-
-// Export global variables, unless an 'exports' object exists,
-// in that case we assume we're in CommonJS (dealt with on the bottom of the script)
-if ( typeof exports === "undefined" ) {
- extend( window, QUnit );
-
- // Expose QUnit object
- window.QUnit = QUnit;
-}
-
-// Initialize more QUnit.config and QUnit.urlParams
-(function() {
- var i,
- location = window.location || { search: "", protocol: "file:" },
- params = location.search.slice( 1 ).split( "&" ),
- length = params.length,
- urlParams = {},
- current;
-
- if ( params[ 0 ] ) {
- for ( i = 0; i < length; i++ ) {
- current = params[ i ].split( "=" );
- current[ 0 ] = decodeURIComponent( current[ 0 ] );
- // allow just a key to turn on a flag, e.g., test.html?noglobals
- current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true;
- urlParams[ current[ 0 ] ] = current[ 1 ];
- }
- }
-
- QUnit.urlParams = urlParams;
-
- // String search anywhere in moduleName+testName
- config.filter = urlParams.filter;
-
- // Exact match of the module name
- config.module = urlParams.module;
-
- config.testNumber = parseInt( urlParams.testNumber, 10 ) || null;
-
- // Figure out if we're running the tests from a server or not
- QUnit.isLocal = location.protocol === "file:";
-}());
-
-// Extend QUnit object,
-// these after set here because they should not be exposed as global functions
-extend( QUnit, {
- assert: assert,
-
- config: config,
-
- // Initialize the configuration options
- init: function() {
- extend( config, {
- stats: { all: 0, bad: 0 },
- moduleStats: { all: 0, bad: 0 },
- started: +new Date(),
- updateRate: 1000,
- blocking: false,
- autostart: true,
- autorun: false,
- filter: "",
- queue: [],
- semaphore: 1
- });
-
- var tests, banner, result,
- qunit = id( "qunit" );
-
- if ( qunit ) {
- qunit.innerHTML =
- "" +
- "" +
- "" +
- "" +
- "
";
- }
-
- tests = id( "qunit-tests" );
- banner = id( "qunit-banner" );
- result = id( "qunit-testresult" );
-
- if ( tests ) {
- tests.innerHTML = "";
- }
-
- if ( banner ) {
- banner.className = "";
- }
-
- if ( result ) {
- result.parentNode.removeChild( result );
- }
-
- if ( tests ) {
- result = document.createElement( "p" );
- result.id = "qunit-testresult";
- result.className = "result";
- tests.parentNode.insertBefore( result, tests );
- result.innerHTML = "Running...
";
- }
- },
-
- // Resets the test setup. Useful for tests that modify the DOM.
- reset: function() {
- var fixture = id( "qunit-fixture" );
- if ( fixture ) {
- fixture.innerHTML = config.fixture;
- }
- },
-
- // Trigger an event on an element.
- // @example triggerEvent( document.body, "click" );
- triggerEvent: function( elem, type, event ) {
- if ( document.createEvent ) {
- event = document.createEvent( "MouseEvents" );
- event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView,
- 0, 0, 0, 0, 0, false, false, false, false, 0, null);
-
- elem.dispatchEvent( event );
- } else if ( elem.fireEvent ) {
- elem.fireEvent( "on" + type );
- }
- },
-
- // Safe object type checking
- is: function( type, obj ) {
- return QUnit.objectType( obj ) === type;
- },
-
- objectType: function( obj ) {
- if ( typeof obj === "undefined" ) {
- return "undefined";
- // consider: typeof null === object
- }
- if ( obj === null ) {
- return "null";
- }
-
- var match = toString.call( obj ).match(/^\[object\s(.*)\]$/),
- type = match && match[1] || "";
-
- switch ( type ) {
- case "Number":
- if ( isNaN(obj) ) {
- return "nan";
- }
- return "number";
- case "String":
- case "Boolean":
- case "Array":
- case "Date":
- case "RegExp":
- case "Function":
- return type.toLowerCase();
- }
- if ( typeof obj === "object" ) {
- return "object";
- }
- return undefined;
- },
-
- push: function( result, actual, expected, message ) {
- if ( !config.current ) {
- throw new Error( "assertion outside test context, was " + sourceFromStacktrace() );
- }
-
- var output, source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: message,
- actual: actual,
- expected: expected
- };
-
- message = escapeText( message ) || ( result ? "okay" : "failed" );
- message = "" + message + "";
- output = message;
-
- if ( !result ) {
- expected = escapeText( QUnit.jsDump.parse(expected) );
- actual = escapeText( QUnit.jsDump.parse(actual) );
- output += "Expected: | " + expected + " |
";
-
- if ( actual !== expected ) {
- output += "Result: | " + actual + " |
";
- output += "Diff: | " + QUnit.diff( expected, actual ) + " |
";
- }
-
- source = sourceFromStacktrace();
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
- }
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: !!result,
- message: output
- });
- },
-
- pushFailure: function( message, source, actual ) {
- if ( !config.current ) {
- throw new Error( "pushFailure() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
-
- var output,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: false,
- message: message
- };
-
- message = escapeText( message ) || "error";
- message = "" + message + "";
- output = message;
-
- output += "";
-
- if ( actual ) {
- output += "Result: | " + escapeText( actual ) + " |
";
- }
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: false,
- message: output
- });
- },
-
- url: function( params ) {
- params = extend( extend( {}, QUnit.urlParams ), params );
- var key,
- querystring = "?";
-
- for ( key in params ) {
- if ( !hasOwn.call( params, key ) ) {
- continue;
- }
- querystring += encodeURIComponent( key ) + "=" +
- encodeURIComponent( params[ key ] ) + "&";
- }
- return window.location.protocol + "//" + window.location.host +
- window.location.pathname + querystring.slice( 0, -1 );
- },
-
- extend: extend,
- id: id,
- addEvent: addEvent
- // load, equiv, jsDump, diff: Attached later
-});
-
-/**
- * @deprecated: Created for backwards compatibility with test runner that set the hook function
- * into QUnit.{hook}, instead of invoking it and passing the hook function.
- * QUnit.constructor is set to the empty F() above so that we can add to it's prototype here.
- * Doing this allows us to tell if the following methods have been overwritten on the actual
- * QUnit object.
- */
-extend( QUnit.constructor.prototype, {
-
- // Logging callbacks; all receive a single argument with the listed properties
- // run test/logs.html for any related changes
- begin: registerLoggingCallback( "begin" ),
-
- // done: { failed, passed, total, runtime }
- done: registerLoggingCallback( "done" ),
-
- // log: { result, actual, expected, message }
- log: registerLoggingCallback( "log" ),
-
- // testStart: { name }
- testStart: registerLoggingCallback( "testStart" ),
-
- // testDone: { name, failed, passed, total, duration }
- testDone: registerLoggingCallback( "testDone" ),
-
- // moduleStart: { name }
- moduleStart: registerLoggingCallback( "moduleStart" ),
-
- // moduleDone: { name, failed, passed, total }
- moduleDone: registerLoggingCallback( "moduleDone" )
-});
-
-if ( typeof document === "undefined" || document.readyState === "complete" ) {
- config.autorun = true;
-}
-
-QUnit.load = function() {
- runLoggingCallbacks( "begin", QUnit, {} );
-
- // Initialize the config, saving the execution queue
- var banner, filter, i, label, len, main, ol, toolbar, userAgent, val,
- urlConfigCheckboxesContainer, urlConfigCheckboxes, moduleFilter,
- numModules = 0,
- moduleFilterHtml = "",
- urlConfigHtml = "",
- oldconfig = extend( {}, config );
-
- QUnit.init();
- extend(config, oldconfig);
-
- config.blocking = false;
-
- len = config.urlConfig.length;
-
- for ( i = 0; i < len; i++ ) {
- val = config.urlConfig[i];
- if ( typeof val === "string" ) {
- val = {
- id: val,
- label: val,
- tooltip: "[no tooltip available]"
- };
- }
- config[ val.id ] = QUnit.urlParams[ val.id ];
- urlConfigHtml += "";
- }
-
- moduleFilterHtml += "";
-
- // `userAgent` initialized at top of scope
- userAgent = id( "qunit-userAgent" );
- if ( userAgent ) {
- userAgent.innerHTML = navigator.userAgent;
- }
-
- // `banner` initialized at top of scope
- banner = id( "qunit-header" );
- if ( banner ) {
- banner.innerHTML = "" + banner.innerHTML + " ";
- }
-
- // `toolbar` initialized at top of scope
- toolbar = id( "qunit-testrunner-toolbar" );
- if ( toolbar ) {
- // `filter` initialized at top of scope
- filter = document.createElement( "input" );
- filter.type = "checkbox";
- filter.id = "qunit-filter-pass";
-
- addEvent( filter, "click", function() {
- var tmp,
- ol = document.getElementById( "qunit-tests" );
-
- if ( filter.checked ) {
- ol.className = ol.className + " hidepass";
- } else {
- tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " ";
- ol.className = tmp.replace( / hidepass /, " " );
- }
- if ( defined.sessionStorage ) {
- if (filter.checked) {
- sessionStorage.setItem( "qunit-filter-passed-tests", "true" );
- } else {
- sessionStorage.removeItem( "qunit-filter-passed-tests" );
- }
- }
- });
-
- if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem( "qunit-filter-passed-tests" ) ) {
- filter.checked = true;
- // `ol` initialized at top of scope
- ol = document.getElementById( "qunit-tests" );
- ol.className = ol.className + " hidepass";
- }
- toolbar.appendChild( filter );
-
- // `label` initialized at top of scope
- label = document.createElement( "label" );
- label.setAttribute( "for", "qunit-filter-pass" );
- label.setAttribute( "title", "Only show tests and assertons that fail. Stored in sessionStorage." );
- label.innerHTML = "Hide passed tests";
- toolbar.appendChild( label );
-
- urlConfigCheckboxesContainer = document.createElement("span");
- urlConfigCheckboxesContainer.innerHTML = urlConfigHtml;
- urlConfigCheckboxes = urlConfigCheckboxesContainer.getElementsByTagName("input");
- // For oldIE support:
- // * Add handlers to the individual elements instead of the container
- // * Use "click" instead of "change"
- // * Fallback from event.target to event.srcElement
- addEvents( urlConfigCheckboxes, "click", function( event ) {
- var params = {},
- target = event.target || event.srcElement;
- params[ target.name ] = target.checked ? true : undefined;
- window.location = QUnit.url( params );
- });
- toolbar.appendChild( urlConfigCheckboxesContainer );
-
- if (numModules > 1) {
- moduleFilter = document.createElement( 'span' );
- moduleFilter.setAttribute( 'id', 'qunit-modulefilter-container' );
- moduleFilter.innerHTML = moduleFilterHtml;
- addEvent( moduleFilter.lastChild, "change", function() {
- var selectBox = moduleFilter.getElementsByTagName("select")[0],
- selectedModule = decodeURIComponent(selectBox.options[selectBox.selectedIndex].value);
-
- window.location = QUnit.url( { module: ( selectedModule === "" ) ? undefined : selectedModule } );
- });
- toolbar.appendChild(moduleFilter);
- }
- }
-
- // `main` initialized at top of scope
- main = id( "qunit-fixture" );
- if ( main ) {
- config.fixture = main.innerHTML;
- }
-
- if ( config.autostart ) {
- QUnit.start();
- }
-};
-
-addEvent( window, "load", QUnit.load );
-
-// `onErrorFnPrev` initialized at top of scope
-// Preserve other handlers
-onErrorFnPrev = window.onerror;
-
-// Cover uncaught exceptions
-// Returning true will surpress the default browser handler,
-// returning false will let it run.
-window.onerror = function ( error, filePath, linerNr ) {
- var ret = false;
- if ( onErrorFnPrev ) {
- ret = onErrorFnPrev( error, filePath, linerNr );
- }
-
- // Treat return value as window.onerror itself does,
- // Only do our handling if not surpressed.
- if ( ret !== true ) {
- if ( QUnit.config.current ) {
- if ( QUnit.config.current.ignoreGlobalErrors ) {
- return true;
- }
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- } else {
- QUnit.test( "global failure", extend( function() {
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- }, { validTest: validTest } ) );
- }
- return false;
- }
-
- return ret;
-};
-
-function done() {
- config.autorun = true;
-
- // Log the last module results
- if ( config.currentModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.currentModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
-
- var i, key,
- banner = id( "qunit-banner" ),
- tests = id( "qunit-tests" ),
- runtime = +new Date() - config.started,
- passed = config.stats.all - config.stats.bad,
- html = [
- "Tests completed in ",
- runtime,
- " milliseconds.
",
- "",
- passed,
- " assertions of ",
- config.stats.all,
- " passed, ",
- config.stats.bad,
- " failed."
- ].join( "" );
-
- if ( banner ) {
- banner.className = ( config.stats.bad ? "qunit-fail" : "qunit-pass" );
- }
-
- if ( tests ) {
- id( "qunit-testresult" ).innerHTML = html;
- }
-
- if ( config.altertitle && typeof document !== "undefined" && document.title ) {
- // show ✖ for good, ✔ for bad suite result in title
- // use escape sequences in case file gets loaded with non-utf-8-charset
- document.title = [
- ( config.stats.bad ? "\u2716" : "\u2714" ),
- document.title.replace( /^[\u2714\u2716] /i, "" )
- ].join( " " );
- }
-
- // clear own sessionStorage items if all tests passed
- if ( config.reorder && defined.sessionStorage && config.stats.bad === 0 ) {
- // `key` & `i` initialized at top of scope
- for ( i = 0; i < sessionStorage.length; i++ ) {
- key = sessionStorage.key( i++ );
- if ( key.indexOf( "qunit-test-" ) === 0 ) {
- sessionStorage.removeItem( key );
- }
- }
- }
-
- // scroll back to top to show results
- if ( window.scrollTo ) {
- window.scrollTo(0, 0);
- }
-
- runLoggingCallbacks( "done", QUnit, {
- failed: config.stats.bad,
- passed: passed,
- total: config.stats.all,
- runtime: runtime
- });
-}
-
-/** @return Boolean: true if this test should be ran */
-function validTest( test ) {
- var include,
- filter = config.filter && config.filter.toLowerCase(),
- module = config.module && config.module.toLowerCase(),
- fullName = (test.module + ": " + test.testName).toLowerCase();
-
- // Internally-generated tests are always valid
- if ( test.callback && test.callback.validTest === validTest ) {
- delete test.callback.validTest;
- return true;
- }
-
- if ( config.testNumber ) {
- return test.testNumber === config.testNumber;
- }
-
- if ( module && ( !test.module || test.module.toLowerCase() !== module ) ) {
- return false;
- }
-
- if ( !filter ) {
- return true;
- }
-
- include = filter.charAt( 0 ) !== "!";
- if ( !include ) {
- filter = filter.slice( 1 );
- }
-
- // If the filter matches, we need to honour include
- if ( fullName.indexOf( filter ) !== -1 ) {
- return include;
- }
-
- // Otherwise, do the opposite
- return !include;
-}
-
-// so far supports only Firefox, Chrome and Opera (buggy), Safari (for real exceptions)
-// Later Safari and IE10 are supposed to support error.stack as well
-// See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack
-function extractStacktrace( e, offset ) {
- offset = offset === undefined ? 3 : offset;
-
- var stack, include, i;
-
- if ( e.stacktrace ) {
- // Opera
- return e.stacktrace.split( "\n" )[ offset + 3 ];
- } else if ( e.stack ) {
- // Firefox, Chrome
- stack = e.stack.split( "\n" );
- if (/^error$/i.test( stack[0] ) ) {
- stack.shift();
- }
- if ( fileName ) {
- include = [];
- for ( i = offset; i < stack.length; i++ ) {
- if ( stack[ i ].indexOf( fileName ) !== -1 ) {
- break;
- }
- include.push( stack[ i ] );
- }
- if ( include.length ) {
- return include.join( "\n" );
- }
- }
- return stack[ offset ];
- } else if ( e.sourceURL ) {
- // Safari, PhantomJS
- // hopefully one day Safari provides actual stacktraces
- // exclude useless self-reference for generated Error objects
- if ( /qunit.js$/.test( e.sourceURL ) ) {
- return;
- }
- // for actual exceptions, this is useful
- return e.sourceURL + ":" + e.line;
- }
-}
-function sourceFromStacktrace( offset ) {
- try {
- throw new Error();
- } catch ( e ) {
- return extractStacktrace( e, offset );
- }
-}
-
-/**
- * Escape text for attribute or text content.
- */
-function escapeText( s ) {
- if ( !s ) {
- return "";
- }
- s = s + "";
- // Both single quotes and double quotes (for attributes)
- return s.replace( /['"<>&]/g, function( s ) {
- switch( s ) {
- case '\'':
- return ''';
- case '"':
- return '"';
- case '<':
- return '<';
- case '>':
- return '>';
- case '&':
- return '&';
- }
- });
-}
-
-function synchronize( callback, last ) {
- config.queue.push( callback );
-
- if ( config.autorun && !config.blocking ) {
- process( last );
- }
-}
-
-function process( last ) {
- function next() {
- process( last );
- }
- var start = new Date().getTime();
- config.depth = config.depth ? config.depth + 1 : 1;
-
- while ( config.queue.length && !config.blocking ) {
- if ( !defined.setTimeout || config.updateRate <= 0 || ( ( new Date().getTime() - start ) < config.updateRate ) ) {
- config.queue.shift()();
- } else {
- window.setTimeout( next, 13 );
- break;
- }
- }
- config.depth--;
- if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) {
- done();
- }
-}
-
-function saveGlobal() {
- config.pollution = [];
-
- if ( config.noglobals ) {
- for ( var key in window ) {
- // in Opera sometimes DOM element ids show up here, ignore them
- if ( !hasOwn.call( window, key ) || /^qunit-test-output/.test( key ) ) {
- continue;
- }
- config.pollution.push( key );
- }
- }
-}
-
-function checkPollution() {
- var newGlobals,
- deletedGlobals,
- old = config.pollution;
-
- saveGlobal();
-
- newGlobals = diff( config.pollution, old );
- if ( newGlobals.length > 0 ) {
- QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join(", ") );
- }
-
- deletedGlobals = diff( old, config.pollution );
- if ( deletedGlobals.length > 0 ) {
- QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join(", ") );
- }
-}
-
-// returns a new Array with the elements that are in a but not in b
-function diff( a, b ) {
- var i, j,
- result = a.slice();
-
- for ( i = 0; i < result.length; i++ ) {
- for ( j = 0; j < b.length; j++ ) {
- if ( result[i] === b[j] ) {
- result.splice( i, 1 );
- i--;
- break;
- }
- }
- }
- return result;
-}
-
-function extend( a, b ) {
- for ( var prop in b ) {
- if ( b[ prop ] === undefined ) {
- delete a[ prop ];
-
- // Avoid "Member not found" error in IE8 caused by setting window.constructor
- } else if ( prop !== "constructor" || a !== window ) {
- a[ prop ] = b[ prop ];
- }
- }
-
- return a;
-}
-
-/**
- * @param {HTMLElement} elem
- * @param {string} type
- * @param {Function} fn
- */
-function addEvent( elem, type, fn ) {
- // Standards-based browsers
- if ( elem.addEventListener ) {
- elem.addEventListener( type, fn, false );
- // IE
- } else {
- elem.attachEvent( "on" + type, fn );
- }
-}
-
-/**
- * @param {Array|NodeList} elems
- * @param {string} type
- * @param {Function} fn
- */
-function addEvents( elems, type, fn ) {
- var i = elems.length;
- while ( i-- ) {
- addEvent( elems[i], type, fn );
- }
-}
-
-function hasClass( elem, name ) {
- return (" " + elem.className + " ").indexOf(" " + name + " ") > -1;
-}
-
-function addClass( elem, name ) {
- if ( !hasClass( elem, name ) ) {
- elem.className += (elem.className ? " " : "") + name;
- }
-}
-
-function removeClass( elem, name ) {
- var set = " " + elem.className + " ";
- // Class name may appear multiple times
- while ( set.indexOf(" " + name + " ") > -1 ) {
- set = set.replace(" " + name + " " , " ");
- }
- // If possible, trim it for prettiness, but not neccecarily
- elem.className = window.jQuery ? jQuery.trim( set ) : ( set.trim ? set.trim() : set );
-}
-
-function id( name ) {
- return !!( typeof document !== "undefined" && document && document.getElementById ) &&
- document.getElementById( name );
-}
-
-function registerLoggingCallback( key ) {
- return function( callback ) {
- config[key].push( callback );
- };
-}
-
-// Supports deprecated method of completely overwriting logging callbacks
-function runLoggingCallbacks( key, scope, args ) {
- var i, callbacks;
- if ( QUnit.hasOwnProperty( key ) ) {
- QUnit[ key ].call(scope, args );
- } else {
- callbacks = config[ key ];
- for ( i = 0; i < callbacks.length; i++ ) {
- callbacks[ i ].call( scope, args );
- }
- }
-}
-
-// Test for equality any JavaScript type.
-// Author: Philippe Rathé
-QUnit.equiv = (function() {
-
- // Call the o related callback with the given arguments.
- function bindCallbacks( o, callbacks, args ) {
- var prop = QUnit.objectType( o );
- if ( prop ) {
- if ( QUnit.objectType( callbacks[ prop ] ) === "function" ) {
- return callbacks[ prop ].apply( callbacks, args );
- } else {
- return callbacks[ prop ]; // or undefined
- }
- }
- }
-
- // the real equiv function
- var innerEquiv,
- // stack to decide between skip/abort functions
- callers = [],
- // stack to avoiding loops from circular referencing
- parents = [],
-
- getProto = Object.getPrototypeOf || function ( obj ) {
- return obj.__proto__;
- },
- callbacks = (function () {
-
- // for string, boolean, number and null
- function useStrictEquality( b, a ) {
- /*jshint eqeqeq:false */
- if ( b instanceof a.constructor || a instanceof b.constructor ) {
- // to catch short annotaion VS 'new' annotation of a
- // declaration
- // e.g. var i = 1;
- // var j = new Number(1);
- return a == b;
- } else {
- return a === b;
- }
- }
-
- return {
- "string": useStrictEquality,
- "boolean": useStrictEquality,
- "number": useStrictEquality,
- "null": useStrictEquality,
- "undefined": useStrictEquality,
-
- "nan": function( b ) {
- return isNaN( b );
- },
-
- "date": function( b, a ) {
- return QUnit.objectType( b ) === "date" && a.valueOf() === b.valueOf();
- },
-
- "regexp": function( b, a ) {
- return QUnit.objectType( b ) === "regexp" &&
- // the regex itself
- a.source === b.source &&
- // and its modifers
- a.global === b.global &&
- // (gmi) ...
- a.ignoreCase === b.ignoreCase &&
- a.multiline === b.multiline &&
- a.sticky === b.sticky;
- },
-
- // - skip when the property is a method of an instance (OOP)
- // - abort otherwise,
- // initial === would have catch identical references anyway
- "function": function() {
- var caller = callers[callers.length - 1];
- return caller !== Object && typeof caller !== "undefined";
- },
-
- "array": function( b, a ) {
- var i, j, len, loop;
-
- // b could be an object literal here
- if ( QUnit.objectType( b ) !== "array" ) {
- return false;
- }
-
- len = a.length;
- if ( len !== b.length ) {
- // safe and faster
- return false;
- }
-
- // track reference to avoid circular references
- parents.push( a );
- for ( i = 0; i < len; i++ ) {
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- loop = true;// dont rewalk array
- }
- }
- if ( !loop && !innerEquiv(a[i], b[i]) ) {
- parents.pop();
- return false;
- }
- }
- parents.pop();
- return true;
- },
-
- "object": function( b, a ) {
- var i, j, loop,
- // Default to true
- eq = true,
- aProperties = [],
- bProperties = [];
-
- // comparing constructors is more strict than using
- // instanceof
- if ( a.constructor !== b.constructor ) {
- // Allow objects with no prototype to be equivalent to
- // objects with Object as their constructor.
- if ( !(( getProto(a) === null && getProto(b) === Object.prototype ) ||
- ( getProto(b) === null && getProto(a) === Object.prototype ) ) ) {
- return false;
- }
- }
-
- // stack constructor before traversing properties
- callers.push( a.constructor );
- // track reference to avoid circular references
- parents.push( a );
-
- for ( i in a ) { // be strict: don't ensures hasOwnProperty
- // and go deep
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- // don't go down the same path twice
- loop = true;
- }
- }
- aProperties.push(i); // collect a's properties
-
- if (!loop && !innerEquiv( a[i], b[i] ) ) {
- eq = false;
- break;
- }
- }
-
- callers.pop(); // unstack, we are done
- parents.pop();
-
- for ( i in b ) {
- bProperties.push( i ); // collect b's properties
- }
-
- // Ensures identical properties name
- return eq && innerEquiv( aProperties.sort(), bProperties.sort() );
- }
- };
- }());
-
- innerEquiv = function() { // can take multiple arguments
- var args = [].slice.apply( arguments );
- if ( args.length < 2 ) {
- return true; // end transition
- }
-
- return (function( a, b ) {
- if ( a === b ) {
- return true; // catch the most you can
- } else if ( a === null || b === null || typeof a === "undefined" ||
- typeof b === "undefined" ||
- QUnit.objectType(a) !== QUnit.objectType(b) ) {
- return false; // don't lose time with error prone cases
- } else {
- return bindCallbacks(a, callbacks, [ b, a ]);
- }
-
- // apply transition with (1..n) arguments
- }( args[0], args[1] ) && arguments.callee.apply( this, args.splice(1, args.length - 1 )) );
- };
-
- return innerEquiv;
-}());
-
-/**
- * jsDump Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com |
- * http://flesler.blogspot.com Licensed under BSD
- * (http://www.opensource.org/licenses/bsd-license.php) Date: 5/15/2008
- *
- * @projectDescription Advanced and extensible data dumping for Javascript.
- * @version 1.0.0
- * @author Ariel Flesler
- * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html}
- */
-QUnit.jsDump = (function() {
- function quote( str ) {
- return '"' + str.toString().replace( /"/g, '\\"' ) + '"';
- }
- function literal( o ) {
- return o + "";
- }
- function join( pre, arr, post ) {
- var s = jsDump.separator(),
- base = jsDump.indent(),
- inner = jsDump.indent(1);
- if ( arr.join ) {
- arr = arr.join( "," + s + inner );
- }
- if ( !arr ) {
- return pre + post;
- }
- return [ pre, inner + arr, base + post ].join(s);
- }
- function array( arr, stack ) {
- var i = arr.length, ret = new Array(i);
- this.up();
- while ( i-- ) {
- ret[i] = this.parse( arr[i] , undefined , stack);
- }
- this.down();
- return join( "[", ret, "]" );
- }
-
- var reName = /^function (\w+)/,
- jsDump = {
- // type is used mostly internally, you can fix a (custom)type in advance
- parse: function( obj, type, stack ) {
- stack = stack || [ ];
- var inStack, res,
- parser = this.parsers[ type || this.typeOf(obj) ];
-
- type = typeof parser;
- inStack = inArray( obj, stack );
-
- if ( inStack !== -1 ) {
- return "recursion(" + (inStack - stack.length) + ")";
- }
- if ( type === "function" ) {
- stack.push( obj );
- res = parser.call( this, obj, stack );
- stack.pop();
- return res;
- }
- return ( type === "string" ) ? parser : this.parsers.error;
- },
- typeOf: function( obj ) {
- var type;
- if ( obj === null ) {
- type = "null";
- } else if ( typeof obj === "undefined" ) {
- type = "undefined";
- } else if ( QUnit.is( "regexp", obj) ) {
- type = "regexp";
- } else if ( QUnit.is( "date", obj) ) {
- type = "date";
- } else if ( QUnit.is( "function", obj) ) {
- type = "function";
- } else if ( typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined" ) {
- type = "window";
- } else if ( obj.nodeType === 9 ) {
- type = "document";
- } else if ( obj.nodeType ) {
- type = "node";
- } else if (
- // native arrays
- toString.call( obj ) === "[object Array]" ||
- // NodeList objects
- ( typeof obj.length === "number" && typeof obj.item !== "undefined" && ( obj.length ? obj.item(0) === obj[0] : ( obj.item( 0 ) === null && typeof obj[0] === "undefined" ) ) )
- ) {
- type = "array";
- } else if ( obj.constructor === Error.prototype.constructor ) {
- type = "error";
- } else {
- type = typeof obj;
- }
- return type;
- },
- separator: function() {
- return this.multiline ? this.HTML ? "
" : "\n" : this.HTML ? " " : " ";
- },
- // extra can be a number, shortcut for increasing-calling-decreasing
- indent: function( extra ) {
- if ( !this.multiline ) {
- return "";
- }
- var chr = this.indentChar;
- if ( this.HTML ) {
- chr = chr.replace( /\t/g, " " ).replace( / /g, " " );
- }
- return new Array( this._depth_ + (extra||0) ).join(chr);
- },
- up: function( a ) {
- this._depth_ += a || 1;
- },
- down: function( a ) {
- this._depth_ -= a || 1;
- },
- setParser: function( name, parser ) {
- this.parsers[name] = parser;
- },
- // The next 3 are exposed so you can use them
- quote: quote,
- literal: literal,
- join: join,
- //
- _depth_: 1,
- // This is the list of parsers, to modify them, use jsDump.setParser
- parsers: {
- window: "[Window]",
- document: "[Document]",
- error: function(error) {
- return "Error(\"" + error.message + "\")";
- },
- unknown: "[Unknown]",
- "null": "null",
- "undefined": "undefined",
- "function": function( fn ) {
- var ret = "function",
- // functions never have name in IE
- name = "name" in fn ? fn.name : (reName.exec(fn) || [])[1];
-
- if ( name ) {
- ret += " " + name;
- }
- ret += "( ";
-
- ret = [ ret, QUnit.jsDump.parse( fn, "functionArgs" ), "){" ].join( "" );
- return join( ret, QUnit.jsDump.parse(fn,"functionCode" ), "}" );
- },
- array: array,
- nodelist: array,
- "arguments": array,
- object: function( map, stack ) {
- var ret = [ ], keys, key, val, i;
- QUnit.jsDump.up();
- keys = [];
- for ( key in map ) {
- keys.push( key );
- }
- keys.sort();
- for ( i = 0; i < keys.length; i++ ) {
- key = keys[ i ];
- val = map[ key ];
- ret.push( QUnit.jsDump.parse( key, "key" ) + ": " + QUnit.jsDump.parse( val, undefined, stack ) );
- }
- QUnit.jsDump.down();
- return join( "{", ret, "}" );
- },
- node: function( node ) {
- var len, i, val,
- open = QUnit.jsDump.HTML ? "<" : "<",
- close = QUnit.jsDump.HTML ? ">" : ">",
- tag = node.nodeName.toLowerCase(),
- ret = open + tag,
- attrs = node.attributes;
-
- if ( attrs ) {
- for ( i = 0, len = attrs.length; i < len; i++ ) {
- val = attrs[i].nodeValue;
- // IE6 includes all attributes in .attributes, even ones not explicitly set.
- // Those have values like undefined, null, 0, false, "" or "inherit".
- if ( val && val !== "inherit" ) {
- ret += " " + attrs[i].nodeName + "=" + QUnit.jsDump.parse( val, "attribute" );
- }
- }
- }
- ret += close;
-
- // Show content of TextNode or CDATASection
- if ( node.nodeType === 3 || node.nodeType === 4 ) {
- ret += node.nodeValue;
- }
-
- return ret + open + "/" + tag + close;
- },
- // function calls it internally, it's the arguments part of the function
- functionArgs: function( fn ) {
- var args,
- l = fn.length;
-
- if ( !l ) {
- return "";
- }
-
- args = new Array(l);
- while ( l-- ) {
- // 97 is 'a'
- args[l] = String.fromCharCode(97+l);
- }
- return " " + args.join( ", " ) + " ";
- },
- // object calls it internally, the key part of an item in a map
- key: quote,
- // function calls it internally, it's the content of the function
- functionCode: "[code]",
- // node calls it internally, it's an html attribute value
- attribute: quote,
- string: quote,
- date: quote,
- regexp: literal,
- number: literal,
- "boolean": literal
- },
- // if true, entities are escaped ( <, >, \t, space and \n )
- HTML: false,
- // indentation unit
- indentChar: " ",
- // if true, items in a collection, are separated by a \n, else just a space.
- multiline: true
- };
-
- return jsDump;
-}());
-
-// from jquery.js
-function inArray( elem, array ) {
- if ( array.indexOf ) {
- return array.indexOf( elem );
- }
-
- for ( var i = 0, length = array.length; i < length; i++ ) {
- if ( array[ i ] === elem ) {
- return i;
- }
- }
-
- return -1;
-}
-
-/*
- * Javascript Diff Algorithm
- * By John Resig (http://ejohn.org/)
- * Modified by Chu Alan "sprite"
- *
- * Released under the MIT license.
- *
- * More Info:
- * http://ejohn.org/projects/javascript-diff-algorithm/
- *
- * Usage: QUnit.diff(expected, actual)
- *
- * QUnit.diff( "the quick brown fox jumped over", "the quick fox jumps over" ) == "the quick brown fox jumped jumps over"
- */
-QUnit.diff = (function() {
- /*jshint eqeqeq:false, eqnull:true */
- function diff( o, n ) {
- var i,
- ns = {},
- os = {};
-
- for ( i = 0; i < n.length; i++ ) {
- if ( !hasOwn.call( ns, n[i] ) ) {
- ns[ n[i] ] = {
- rows: [],
- o: null
- };
- }
- ns[ n[i] ].rows.push( i );
- }
-
- for ( i = 0; i < o.length; i++ ) {
- if ( !hasOwn.call( os, o[i] ) ) {
- os[ o[i] ] = {
- rows: [],
- n: null
- };
- }
- os[ o[i] ].rows.push( i );
- }
-
- for ( i in ns ) {
- if ( !hasOwn.call( ns, i ) ) {
- continue;
- }
- if ( ns[i].rows.length === 1 && hasOwn.call( os, i ) && os[i].rows.length === 1 ) {
- n[ ns[i].rows[0] ] = {
- text: n[ ns[i].rows[0] ],
- row: os[i].rows[0]
- };
- o[ os[i].rows[0] ] = {
- text: o[ os[i].rows[0] ],
- row: ns[i].rows[0]
- };
- }
- }
-
- for ( i = 0; i < n.length - 1; i++ ) {
- if ( n[i].text != null && n[ i + 1 ].text == null && n[i].row + 1 < o.length && o[ n[i].row + 1 ].text == null &&
- n[ i + 1 ] == o[ n[i].row + 1 ] ) {
-
- n[ i + 1 ] = {
- text: n[ i + 1 ],
- row: n[i].row + 1
- };
- o[ n[i].row + 1 ] = {
- text: o[ n[i].row + 1 ],
- row: i + 1
- };
- }
- }
-
- for ( i = n.length - 1; i > 0; i-- ) {
- if ( n[i].text != null && n[ i - 1 ].text == null && n[i].row > 0 && o[ n[i].row - 1 ].text == null &&
- n[ i - 1 ] == o[ n[i].row - 1 ]) {
-
- n[ i - 1 ] = {
- text: n[ i - 1 ],
- row: n[i].row - 1
- };
- o[ n[i].row - 1 ] = {
- text: o[ n[i].row - 1 ],
- row: i - 1
- };
- }
- }
-
- return {
- o: o,
- n: n
- };
- }
-
- return function( o, n ) {
- o = o.replace( /\s+$/, "" );
- n = n.replace( /\s+$/, "" );
-
- var i, pre,
- str = "",
- out = diff( o === "" ? [] : o.split(/\s+/), n === "" ? [] : n.split(/\s+/) ),
- oSpace = o.match(/\s+/g),
- nSpace = n.match(/\s+/g);
-
- if ( oSpace == null ) {
- oSpace = [ " " ];
- }
- else {
- oSpace.push( " " );
- }
-
- if ( nSpace == null ) {
- nSpace = [ " " ];
- }
- else {
- nSpace.push( " " );
- }
-
- if ( out.n.length === 0 ) {
- for ( i = 0; i < out.o.length; i++ ) {
- str += "" + out.o[i] + oSpace[i] + "";
- }
- }
- else {
- if ( out.n[0].text == null ) {
- for ( n = 0; n < out.o.length && out.o[n].text == null; n++ ) {
- str += "" + out.o[n] + oSpace[n] + "";
- }
- }
-
- for ( i = 0; i < out.n.length; i++ ) {
- if (out.n[i].text == null) {
- str += "" + out.n[i] + nSpace[i] + "";
- }
- else {
- // `pre` initialized at top of scope
- pre = "";
-
- for ( n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++ ) {
- pre += "" + out.o[n] + oSpace[n] + "";
- }
- str += " " + out.n[i].text + nSpace[i] + pre;
- }
- }
- }
-
- return str;
- };
-}());
-
-// for CommonJS enviroments, export everything
-if ( typeof exports !== "undefined" ) {
- extend( exports, QUnit );
-}
-
-// get at whatever the global object is, like window in browsers
-}( (function() {return this;}.call()) ));
diff --git a/test/lib/require.js b/test/lib/require.js
deleted file mode 100644
index 987f865..0000000
--- a/test/lib/require.js
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- RequireJS 2.1.5 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.
- Available via the MIT or new BSD license.
- see: http://github.com/jrburke/requirejs for details
-*/
-var requirejs,require,define;
-(function(aa){function I(b){return"[object Function]"===L.call(b)}function J(b){return"[object Array]"===L.call(b)}function y(b,c){if(b){var d;for(d=0;dthis.depCount&&!this.defined){if(I(n)){if(this.events.error)try{e=i.execCb(c,n,b,e)}catch(d){a=d}else e=i.execCb(c,n,b,e);this.map.isDefine&&((b=this.module)&&void 0!==b.exports&&b.exports!==this.exports?e=b.exports:void 0===e&&this.usingExports&&(e=this.exports));if(a)return a.requireMap=this.map,a.requireModules=[this.map.id],a.requireType="define",v(this.error=
-a)}else e=n;this.exports=e;if(this.map.isDefine&&!this.ignore&&(q[c]=e,l.onResourceLoad))l.onResourceLoad(i,this.map,this.depMaps);x(c);this.defined=!0}this.defining=!1;this.defined&&!this.defineEmitted&&(this.defineEmitted=!0,this.emit("defined",this.exports),this.defineEmitComplete=!0)}}else this.fetch()}},callPlugin:function(){var a=this.map,b=a.id,d=j(a.prefix);this.depMaps.push(d);t(d,"defined",u(this,function(e){var n,d;d=this.map.name;var g=this.map.parentMap?this.map.parentMap.name:null,h=
-i.makeRequire(a.parentMap,{enableBuildCallback:!0});if(this.map.unnormalized){if(e.normalize&&(d=e.normalize(d,function(a){return c(a,g,!0)})||""),e=j(a.prefix+"!"+d,this.map.parentMap),t(e,"defined",u(this,function(a){this.init([],function(){return a},null,{enabled:!0,ignore:!0})})),d=m(p,e.id)){this.depMaps.push(e);if(this.events.error)d.on("error",u(this,function(a){this.emit("error",a)}));d.enable()}}else n=u(this,function(a){this.init([],function(){return a},null,{enabled:!0})}),n.error=u(this,
-function(a){this.inited=!0;this.error=a;a.requireModules=[b];G(p,function(a){0===a.map.id.indexOf(b+"_unnormalized")&&x(a.map.id)});v(a)}),n.fromText=u(this,function(e,c){var d=a.name,g=j(d),C=O;c&&(e=c);C&&(O=!1);r(g);s(k.config,b)&&(k.config[d]=k.config[b]);try{l.exec(e)}catch(ca){return v(B("fromtexteval","fromText eval for "+b+" failed: "+ca,ca,[b]))}C&&(O=!0);this.depMaps.push(g);i.completeLoad(d);h([d],n)}),e.load(a.name,h,n,k)}));i.enable(d,this);this.pluginMaps[d.id]=d},enable:function(){V[this.map.id]=
-this;this.enabling=this.enabled=!0;y(this.depMaps,u(this,function(a,b){var c,e;if("string"===typeof a){a=j(a,this.map.isDefine?this.map:this.map.parentMap,!1,!this.skipMap);this.depMaps[b]=a;if(c=m(N,a.id)){this.depExports[b]=c(this);return}this.depCount+=1;t(a,"defined",u(this,function(a){this.defineDep(b,a);this.check()}));this.errback&&t(a,"error",this.errback)}c=a.id;e=p[c];!s(N,c)&&(e&&!e.enabled)&&i.enable(a,this)}));G(this.pluginMaps,u(this,function(a){var b=m(p,a.id);b&&!b.enabled&&i.enable(a,
-this)}));this.enabling=!1;this.check()},on:function(a,b){var c=this.events[a];c||(c=this.events[a]=[]);c.push(b)},emit:function(a,b){y(this.events[a],function(a){a(b)});"error"===a&&delete this.events[a]}};i={config:k,contextName:b,registry:p,defined:q,urlFetched:U,defQueue:H,Module:Z,makeModuleMap:j,nextTick:l.nextTick,onError:v,configure:function(a){a.baseUrl&&"/"!==a.baseUrl.charAt(a.baseUrl.length-1)&&(a.baseUrl+="/");var b=k.pkgs,c=k.shim,e={paths:!0,config:!0,map:!0};G(a,function(a,b){e[b]?
-"map"===b?(k.map||(k.map={}),R(k[b],a,!0,!0)):R(k[b],a,!0):k[b]=a});a.shim&&(G(a.shim,function(a,b){J(a)&&(a={deps:a});if((a.exports||a.init)&&!a.exportsFn)a.exportsFn=i.makeShimExports(a);c[b]=a}),k.shim=c);a.packages&&(y(a.packages,function(a){a="string"===typeof a?{name:a}:a;b[a.name]={name:a.name,location:a.location||a.name,main:(a.main||"main").replace(ja,"").replace(ea,"")}}),k.pkgs=b);G(p,function(a,b){!a.inited&&!a.map.unnormalized&&(a.map=j(b))});if(a.deps||a.callback)i.require(a.deps||[],
-a.callback)},makeShimExports:function(a){return function(){var b;a.init&&(b=a.init.apply(aa,arguments));return b||a.exports&&ba(a.exports)}},makeRequire:function(a,f){function d(e,c,h){var g,k;f.enableBuildCallback&&(c&&I(c))&&(c.__requireJsBuild=!0);if("string"===typeof e){if(I(c))return v(B("requireargs","Invalid require call"),h);if(a&&s(N,e))return N[e](p[a.id]);if(l.get)return l.get(i,e,a,d);g=j(e,a,!1,!0);g=g.id;return!s(q,g)?v(B("notloaded",'Module name "'+g+'" has not been loaded yet for context: '+
-b+(a?"":". Use require([])"))):q[g]}L();i.nextTick(function(){L();k=r(j(null,a));k.skipMap=f.skipMap;k.init(e,c,h,{enabled:!0});D()});return d}f=f||{};R(d,{isBrowser:A,toUrl:function(b){var d,f=b.lastIndexOf("."),g=b.split("/")[0];if(-1!==f&&(!("."===g||".."===g)||1h.attachEvent.toString().indexOf("[native code"))&&!Y?(O=!0,h.attachEvent("onreadystatechange",b.onScriptLoad)):(h.addEventListener("load",b.onScriptLoad,!1),h.addEventListener("error",b.onScriptError,!1)),h.src=d,K=h,D?x.insertBefore(h,D):x.appendChild(h),K=null,h;if(da)try{importScripts(d),b.completeLoad(c)}catch(j){b.onError(B("importscripts","importScripts failed for "+c+" at "+d,j,[c]))}};A&&M(document.getElementsByTagName("script"),function(b){x||(x=
-b.parentNode);if(t=b.getAttribute("data-main"))return r.baseUrl||(E=t.split("/"),Q=E.pop(),fa=E.length?E.join("/")+"/":"./",r.baseUrl=fa,t=Q),t=t.replace(ea,""),r.deps=r.deps?r.deps.concat(t):[t],!0});define=function(b,c,d){var l,h;"string"!==typeof b&&(d=c,c=b,b=null);J(c)||(d=c,c=[]);!c.length&&I(d)&&d.length&&(d.toString().replace(la,"").replace(ma,function(b,d){c.push(d)}),c=(1===d.length?["require"]:["require","exports","module"]).concat(c));if(O){if(!(l=K))P&&"interactive"===P.readyState||M(document.getElementsByTagName("script"),
-function(b){if("interactive"===b.readyState)return P=b}),l=P;l&&(b||(b=l.getAttribute("data-requiremodule")),h=F[l.getAttribute("data-requirecontext")])}(h?h.defQueue:T).push([b,c,d])};define.amd={jQuery:!0};l.exec=function(b){return eval(b)};l(r)}})(this);
diff --git a/test/lib/resemble.js b/test/lib/resemble.js
new file mode 100644
index 0000000..1cb8c29
--- /dev/null
+++ b/test/lib/resemble.js
@@ -0,0 +1,535 @@
+/*
+Author: James Cryer
+Company: Huddle
+Last updated date: 21 Feb 2013
+URL: https://github.com/Huddle/Resemble.js
+*/
+
+(function(_this){
+ 'use strict';
+
+ _this['resemble'] = function( fileData ){
+
+ var data = {};
+ var images = [];
+ var updateCallbackArray = [];
+
+ var tolerance = { // between 0 and 255
+ red: 16,
+ green: 16,
+ blue: 16,
+ minBrightness: 16,
+ maxBrightness: 240
+ };
+
+ var ignoreAntialiasing = false;
+ var ignoreColors = false;
+
+ function triggerDataUpdate(){
+ var len = updateCallbackArray.length;
+ var i;
+ for(i=0;i tolerance.maxBrightness;
+ }
+
+ function getHue(r,g,b){
+
+ r = r / 255;
+ g = g / 255;
+ b = b / 255;
+ var max = Math.max(r, g, b), min = Math.min(r, g, b);
+ var h;
+ var d;
+
+ if (max == min){
+ h = 0; // achromatic
+ } else{
+ d = max - min;
+ switch(max){
+ case r: h = (g - b) / d + (g < b ? 6 : 0); break;
+ case g: h = (b - r) / d + 2; break;
+ case b: h = (r - g) / d + 4; break;
+ }
+ h /= 6;
+ }
+
+ return h;
+ }
+
+ function isAntialiased(sourcePix, data, cacheSet, verticalPos, horizontalPos, width){
+ var offset;
+ var targetPix;
+ var distance = 1;
+ var i;
+ var j;
+ var hasHighContrastSibling = 0;
+ var hasSiblingWithDifferentHue = 0;
+ var hasEquivilantSibling = 0;
+
+ addHueInfo(sourcePix);
+
+ for (i = distance*-1; i <= distance; i++){
+ for (j = distance*-1; j <= distance; j++){
+
+ if(i===0 && j===0){
+ // ignore source pixel
+ } else {
+
+ offset = ((verticalPos+j)*width + (horizontalPos+i)) * 4;
+ targetPix = getPixelInfo(data, offset, cacheSet);
+
+ if(targetPix === null){
+ continue;
+ }
+
+ addBrightnessInfo(targetPix);
+ addHueInfo(targetPix);
+
+ if( isContrasting(sourcePix, targetPix) ){
+ hasHighContrastSibling++;
+ }
+
+ if( isRGBSame(sourcePix,targetPix) ){
+ hasEquivilantSibling++;
+ }
+
+ if( Math.abs(targetPix.h - sourcePix.h) > 0.3 ){
+ hasSiblingWithDifferentHue++;
+ }
+
+ if( hasSiblingWithDifferentHue > 1 || hasHighContrastSibling > 1){
+ return true;
+ }
+ }
+ }
+ }
+
+ if(hasEquivilantSibling < 2){
+ return true;
+ }
+
+ return false;
+ }
+
+ function errorPixel(px, offset){
+ px[offset] = 255; //r
+ px[offset + 1] = 0; //g
+ px[offset + 2] = 255; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyPixel(px, offset, data){
+ px[offset] = data.r; //r
+ px[offset + 1] = data.g; //g
+ px[offset + 2] = data.b; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyGrayScalePixel(px, offset, data){
+ px[offset] = data.brightness; //r
+ px[offset + 1] = data.brightness; //g
+ px[offset + 2] = data.brightness; //b
+ px[offset + 3] = 255; //a
+ }
+
+
+ function getPixelInfo(data, offset, cacheSet){
+ var r;
+ var g;
+ var b;
+ var d;
+
+ if(typeof data[offset] !== 'undefined'){
+ r = data[offset];
+ g = data[offset+1];
+ b = data[offset+2];
+ d = {
+ r: r,
+ g: g,
+ b: b
+ };
+
+ return d;
+ } else {
+ return null;
+ }
+ }
+
+ function addBrightnessInfo(data){
+ data.brightness = getBrightness(data.r,data.g,data.b); // 'corrected' lightness
+ }
+
+ function addHueInfo(data){
+ data.h = getHue(data.r,data.g,data.b);
+ }
+
+ function analyseImages(img1, img2, width, height){
+
+ var hiddenCanvas = document.createElement('canvas');
+
+ var data1 = img1.data;
+ var data2 = img2.data;
+
+ hiddenCanvas.width = width;
+ hiddenCanvas.height = height;
+
+ var context = hiddenCanvas.getContext('2d');
+ var imgd = context.createImageData(width,height);
+ var targetPix = imgd.data;
+
+ var mismatchCount = 0;
+
+ var time = Date.now();
+
+ var skip;
+
+ if( (width > 1200 || height > 1200) && ignoreAntialiasing){
+ skip = 6;
+ }
+
+ loop(height, width, function(verticalPos, horizontalPos){
+
+ if(skip){ // only skip if the image isn't small
+ if(verticalPos % skip === 0 || horizontalPos % skip === 0){
+ return;
+ }
+ }
+
+ var offset = (verticalPos*width + horizontalPos) * 4;
+ var pixel1 = getPixelInfo(data1, offset, 1);
+ var pixel2 = getPixelInfo(data2, offset, 2);
+
+ if(pixel1 === null || pixel2 === null){
+ return;
+ }
+
+ if (ignoreColors){
+
+ addBrightnessInfo(pixel1);
+ addBrightnessInfo(pixel2);
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ return;
+ }
+
+ if( isRGBSimilar(pixel1, pixel2) ){
+ copyPixel(targetPix, offset, pixel2);
+
+ } else if( ignoreAntialiasing && (
+ addBrightnessInfo(pixel1), // jit pixel info augmentation looks a little weird, sorry.
+ addBrightnessInfo(pixel2),
+ isAntialiased(pixel1, data1, 1, verticalPos, horizontalPos, width) ||
+ isAntialiased(pixel2, data2, 2, verticalPos, horizontalPos, width)
+ )){
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+
+ });
+
+ data.misMatchPercentage = (mismatchCount / (height*width) * 100).toFixed(2);
+ data.analysisTime = Date.now() - time;
+
+ data.getImageDataUrl = function(text){
+ var barHeight = 0;
+
+ if(text){
+ barHeight = addLabel(text,context,hiddenCanvas);
+ }
+
+ context.putImageData(imgd, 0, barHeight);
+
+ return hiddenCanvas.toDataURL("image/png");
+ };
+ }
+
+ function addLabel(text, context, hiddenCanvas){
+ var textPadding = 2;
+
+ context.font = '12px sans-serif';
+
+ var textWidth = context.measureText(text).width + textPadding*2;
+ var barHeight = 22;
+
+ if(textWidth > hiddenCanvas.width){
+ hiddenCanvas.width = textWidth;
+ }
+
+ hiddenCanvas.height += barHeight;
+
+ context.fillStyle = "#666";
+ context.fillRect(0,0,hiddenCanvas.width,barHeight -4);
+ context.fillStyle = "#fff";
+ context.fillRect(0,barHeight -4,hiddenCanvas.width, 4);
+
+ context.fillStyle = "#fff";
+ context.textBaseline = "top";
+ context.font = '12px sans-serif';
+ context.fillText(text, textPadding, 1);
+
+ return barHeight;
+ }
+
+ function normalise(img, w, h){
+ var c;
+ var context;
+
+ if(img.height < h || img.width < w){
+ c = document.createElement('canvas');
+ c.width = w;
+ c.height = h;
+ context = c.getContext('2d');
+ context.putImageData(img, 0, 0);
+ return context.getImageData(0, 0, w, h);
+ }
+
+ return img;
+ }
+
+ function compare(one, two){
+
+ function onceWeHaveBoth(){
+ var width;
+ var height;
+ if(images.length === 2){
+ width = images[0].width > images[1].width ? images[0].width : images[1].width;
+ height = images[0].height > images[1].height ? images[0].height : images[1].height;
+
+ if( (images[0].width === images[1].width) && (images[0].height === images[1].height) ){
+ data.isSameDimensions = true;
+ } else {
+ data.isSameDimensions = false;
+ }
+
+ analyseImages( normalise(images[0],width, height), normalise(images[1],width, height), width, height);
+
+ triggerDataUpdate();
+ }
+ }
+
+ images = [];
+ loadImageData(one, onceWeHaveBoth);
+ loadImageData(two, onceWeHaveBoth);
+ }
+
+ function getCompareApi(param){
+
+ var secondFileData,
+ hasMethod = typeof param === 'function';
+
+ if( !hasMethod ){
+ // assume it's file data
+ secondFileData = param;
+ }
+
+ var self = {
+ ignoreNothing: function(){
+
+ tolerance.red = 16;
+ tolerance.green = 16;
+ tolerance.blue = 16;
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreAntialiasing: function(){
+
+ tolerance.red = 32;
+ tolerance.green = 32;
+ tolerance.blue = 32;
+ tolerance.minBrightness = 64;
+ tolerance.maxBrightness = 96;
+
+ ignoreAntialiasing = true;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreColors: function(){
+
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = true;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ onComplete: function( callback ){
+
+ updateCallbackArray.push(callback);
+
+ var wrapper = function(){
+ compare(fileData, secondFileData);
+ };
+
+ wrapper();
+
+ return getCompareApi(wrapper);
+ }
+ };
+
+ return self;
+ }
+
+ return {
+ onComplete: function( callback ){
+ updateCallbackArray.push(callback);
+ loadImageData(fileData, function(imageData, width, height){
+ parseImage(imageData.data, width, height);
+ });
+ },
+ compareTo: function(secondFileData){
+ return getCompareApi(secondFileData);
+ }
+ };
+
+ };
+}(this));
\ No newline at end of file
diff --git a/test/testsuite.js b/test/testsuite.js
deleted file mode 100644
index b486acb..0000000
--- a/test/testsuite.js
+++ /dev/null
@@ -1,36 +0,0 @@
-requirejs.config({
- baseUrl: '/test/unit/'
-});
-
-define(function(require) {
- var testModules = [
- 'Pixi',
- 'Point',
- 'Rectangle',
- 'DisplayObject',
- 'DisplayObjectContainer',
- 'Sprite',
- 'MovieClip',
- 'InteractionManager',
- 'Stage',
- 'utils/Utils',
- 'utils/EventTarget',
- 'utils/Matrix',
- 'utils/Detector',
- 'renderers/WebGLShaders',
- 'renderers/WebGLRenderer',
- 'renderers/WebGLBatch',
- 'renderers/CanvasRenderer',
- 'extras/Strip',
- 'extras/Rope',
- 'textures/BaseTexture',
- 'textures/Texture',
- 'loaders/SpriteSheetLoader',
- 'loaders/AssetLoader'
- ];
-
- // Resolve all testModules and then start the Test Runner.
- require(testModules, function() {
- QUnit.start();
- });
-});
\ No newline at end of file
diff --git a/test/textures/SpriteSheet-Aliens.png b/test/textures/SpriteSheet-Aliens.png
new file mode 100644
index 0000000..210acb1
--- /dev/null
+++ b/test/textures/SpriteSheet-Aliens.png
Binary files differ
diff --git a/test/textures/SpriteSheet-Explosion.png b/test/textures/SpriteSheet-Explosion.png
new file mode 100755
index 0000000..79e1a69
--- /dev/null
+++ b/test/textures/SpriteSheet-Explosion.png
Binary files differ
diff --git a/test/textures/bunny.png b/test/textures/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/textures/bunny.png
Binary files differ
diff --git a/test/unit/DisplayObject.js b/test/unit/DisplayObject.js
deleted file mode 100644
index 5e7e72f..0000000
--- a/test/unit/DisplayObject.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObject');
-});
diff --git a/test/unit/DisplayObjectContainer.js b/test/unit/DisplayObjectContainer.js
deleted file mode 100644
index b323959..0000000
--- a/test/unit/DisplayObjectContainer.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObjectContainer');
-});
diff --git a/test/unit/InteractionManager.js b/test/unit/InteractionManager.js
deleted file mode 100644
index e751f52..0000000
--- a/test/unit/InteractionManager.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('InteractionManager');
-});
diff --git a/test/unit/MovieClip.js b/test/unit/MovieClip.js
deleted file mode 100644
index 37d9446..0000000
--- a/test/unit/MovieClip.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('MovieClip');
-});
diff --git a/test/unit/Pixi.js b/test/unit/Pixi.js
deleted file mode 100644
index 36eee73..0000000
--- a/test/unit/Pixi.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Pixi');
-});
diff --git a/test/unit/Point.js b/test/unit/Point.js
deleted file mode 100644
index 983ff6e..0000000
--- a/test/unit/Point.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Point');
-});
diff --git a/.gitignore b/.gitignore
index 12e1b62..0b88317 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
node_modules
.DS_Store
-.project
\ No newline at end of file
+.project
+*.log
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..63e4d7c
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,8 @@
+language: node_js
+node_js:
+ - 0.10
+
+before_script:
+ - npm install -g grunt-cli
+ - export DISPLAY=:99.0
+ - sh -e /etc/init.d/xvfb start
diff --git a/Gruntfile.js b/Gruntfile.js
index b083b49..103938c 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -1,10 +1,12 @@
+'use strict';
+
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-connect');
- grunt.loadNpmTasks('grunt-contrib-qunit');
grunt.loadNpmTasks('grunt-contrib-yuidoc');
+ grunt.loadTasks('tasks');
var root = 'src/pixi/',
debug = 'bin/pixi.dev.js',
@@ -79,7 +81,7 @@
},
files: {
srcBlob: '<%= dirs.src %>/**/*.js',
- testBlob: '<%= dirs.test %>/unit/**/*.js',
+ testBlob: '<%= dirs.test %>/{functional,lib/pixi,unit}/**/*.js',
build: '<%= dirs.build %>/pixi.dev.js',
buildMin: '<%= dirs.build %>/pixi.js'
},
@@ -94,7 +96,12 @@
},
jshint: {
beforeconcat: srcFiles,
- test: ['<%= files.testBlob %>'],
+ test: {
+ src: ['<%= files.testBlob %>'],
+ options: {
+ expr: true
+ }
+ },
options: {
asi: true,
smarttabs: true
@@ -128,12 +135,6 @@
]
},
connect: {
- qunit: {
- options: {
- port: grunt.option('port-test') || 9002,
- base: './'
- }
- },
test: {
options: {
port: grunt.option('port-test') || 9002,
@@ -142,13 +143,6 @@
}
}
},
- qunit: {
- all: {
- options: {
- urls: ['http://localhost:' + (grunt.option('port-test') || 9002) + '/test/index.html']
- }
- }
- },
yuidoc: {
compile: {
name: '<%= pkg.name %>',
@@ -161,6 +155,13 @@
outdir: '<%= dirs.docs %>'
}
}
+ },
+ karma: {
+ unit: {
+ configFile: 'test/karma.conf.js',
+ // browsers: ['Chrome'],
+ singleRun: true
+ }
}
});
@@ -182,9 +183,10 @@
}
)
- grunt.registerTask('default', ['concat', 'uglify', 'distribute']);
grunt.registerTask('build', ['concat', 'uglify', 'distribute']);
- grunt.registerTask('test', ['build', 'connect:qunit', 'qunit']);
+ grunt.registerTask('test', ['concat', 'jshint:test', 'karma']);
grunt.registerTask('docs', ['yuidoc']);
-
-}
\ No newline at end of file
+ grunt.registerTask('default', ['test', 'uglify', 'distribute']);
+ // Travis CI task.
+ grunt.registerTask('travis', ['test']);
+}
diff --git a/README.md b/README.md
index c62ef86..690cfe4 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,8 @@

+[](http://travis-ci.org/drkibitz/pixi.js)
+
#### JavaScript 2D Renderer ####
The aim of this project is to provide a fast lightweight 2D library that works
diff --git a/package.json b/package.json
index b373240..1246a68 100644
--- a/package.json
+++ b/package.json
@@ -18,14 +18,21 @@
"main": "bin/pixi.js",
+ "scripts": {
+ "test": "grunt travis --verbose"
+ },
+
"dependencies": {},
"devDependencies": {
"grunt": "~0.4.x",
- "grunt-contrib-jshint": "0.3.x",
+ "grunt-contrib-jshint": "0.6.x",
"grunt-contrib-uglify": "0.2.x",
- "grunt-contrib-connect": "0.2.x",
- "grunt-contrib-qunit": "0.2.x",
+ "grunt-contrib-connect": "0.3.x",
"grunt-contrib-yuidoc": "0.4.x",
- "grunt-contrib-concat": "0.1.x"
+ "grunt-contrib-concat": "0.3.x",
+ "chai": "~1.7.0",
+ "karma": "0.11.0",
+ "karma-firefox-launcher": "0.1.0",
+ "karma-mocha": "0.1.0"
}
}
diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js
index a7c520e..ee82bbd 100644
--- a/src/pixi/InteractionManager.js
+++ b/src/pixi/InteractionManager.js
@@ -62,7 +62,6 @@
this.onTouchEnd = this.onTouchEnd.bind(this);
this.onTouchMove = this.onTouchMove.bind(this);
-
this.last = 0;
}
diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js
index 1a95d20..eef1059 100644
--- a/src/pixi/core/Ellipse.js
+++ b/src/pixi/core/Ellipse.js
@@ -78,7 +78,7 @@
return (normx + normy < 0.25);
}
-PIXI.Ellipse.getBounds = function()
+PIXI.Ellipse.prototype.getBounds = function()
{
return new PIXI.Rectangle(this.x, this.y, this.width, this.height);
}
diff --git a/tasks/karma.js b/tasks/karma.js
new file mode 100644
index 0000000..c340485
--- /dev/null
+++ b/tasks/karma.js
@@ -0,0 +1,27 @@
+'use strict';
+
+var path = require('path');
+var server = require('karma').server;
+
+module.exports = function (grunt) {
+ grunt.registerMultiTask('karma', 'run karma.', function() {
+ var done = this.async();
+ var options = this.options({
+ background: false
+ });
+ var data = this.data;
+
+ //merge options onto data, with data taking precedence
+ data = grunt.util._.merge(options, data);
+ data.configFile = path.resolve(data.configFile);
+ if (data.configFile) {
+ data.configFile = grunt.template.process(data.configFile);
+ }
+
+ server.start(
+ data,
+ function(code) {
+ done(!code);
+ });
+ });
+};
diff --git a/test/functional/example-1-basics/bunny.png b/test/functional/example-1-basics/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/functional/example-1-basics/bunny.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-30.png b/test/functional/example-1-basics/frame-30.png
new file mode 100644
index 0000000..96e3409
--- /dev/null
+++ b/test/functional/example-1-basics/frame-30.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-60.png b/test/functional/example-1-basics/frame-60.png
new file mode 100644
index 0000000..af3f4ce
--- /dev/null
+++ b/test/functional/example-1-basics/frame-60.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-90.png b/test/functional/example-1-basics/frame-90.png
new file mode 100644
index 0000000..099b823
--- /dev/null
+++ b/test/functional/example-1-basics/frame-90.png
Binary files differ
diff --git a/test/functional/example-1-basics/index.js b/test/functional/example-1-basics/index.js
new file mode 100644
index 0000000..7ae7a98
--- /dev/null
+++ b/test/functional/example-1-basics/index.js
@@ -0,0 +1,133 @@
+describe('Example 1 - Basics', function () {
+ 'use strict';
+
+ var baseUri = '/base/test/functional/example-1-basics';
+ var expect = chai.expect;
+ var currentFrame = 0;
+ var frameEvents = {};
+ var stage;
+ var renderer;
+ var bunny;
+
+ function onFrame(frame, callback) {
+ frameEvents[frame] = callback;
+ }
+
+ function animate() {
+ currentFrame += 1;
+
+ requestAnimFrame( animate );
+
+ // just for fun, lets rotate mr rabbit a little
+ bunny.rotation += 0.1;
+
+ // render the stage
+ renderer.render(stage);
+
+ if (frameEvents[currentFrame])
+ frameEvents[currentFrame](currentFrame);
+ }
+
+ function initScene() {
+ // create an new instance of a pixi stage
+ stage = new PIXI.Stage(0x66FF99);
+
+ // create a renderer instance
+ renderer = PIXI.autoDetectRenderer(400, 300);
+ console.log('Is PIXI.WebGLRenderer: ' + (renderer instanceof PIXI.WebGLRenderer));
+
+ // add the renderer view element to the DOM
+ document.body.appendChild(renderer.view);
+
+ requestAnimFrame( animate );
+
+ // create a texture from an image path
+ var texture = PIXI.Texture.fromImage(baseUri + "/bunny.png");
+ // create a new Sprite using the texture
+ bunny = new PIXI.Sprite(texture);
+
+ // center the sprites anchor point
+ bunny.anchor.x = 0.5;
+ bunny.anchor.y = 0.5;
+
+ // move the sprite t the center of the screen
+ bunny.position.x = 200;
+ bunny.position.y = 150;
+
+ stage.addChild(bunny);
+ }
+
+ it('assets loaded', function (done) {
+ var loader = new PIXI.AssetLoader([
+ baseUri + '/bunny.png',
+ baseUri + '/frame-30.png',
+ baseUri + '/frame-60.png',
+ baseUri + '/frame-90.png'
+ ]);
+ // loader.on('onProgress', function (event) {
+ // console.log(event.content);
+ // });
+ loader.on('onComplete', function (event) {
+ done();
+ initScene();
+ });
+ loader.load();
+ });
+
+ it('frame 30 should match', function (done) {
+ this.timeout(700);
+ onFrame(30, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-30.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 60 should match', function (done) {
+ this.timeout(1200);
+ onFrame(60, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-60.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 90 should match', function (done) {
+ this.timeout(1700);
+ onFrame(90, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-90.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ // it('capture something', function (done) {
+ // this.timeout(2000000);
+ // onFrame(30, function () {
+ // var img = new Image();
+ // img.src = renderer.view.toDataURL('image/png');
+ // document.body.appendChild(img);
+ // });
+ // });
+});
diff --git a/test/index.html b/test/index.html
deleted file mode 100644
index 9cbcac5..0000000
--- a/test/index.html
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
- Pixi.js Test Suite
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/test/karma.conf.js b/test/karma.conf.js
new file mode 100644
index 0000000..c66a696
--- /dev/null
+++ b/test/karma.conf.js
@@ -0,0 +1,82 @@
+module.exports = function(config) {
+ config.set({
+
+ // base path, that will be used to resolve files and exclude
+ basePath : '../',
+
+ frameworks : ['mocha'],
+
+ // list of files / patterns to load in the browser
+ files : [
+ 'node_modules/chai/chai.js',
+ 'bin/pixi.dev.js',
+ 'test/lib/**/*.js',
+ 'test/unit/**/*.js',
+ // 'test/functional/**/*.js',
+ {pattern: 'test/**/*.png', watched: false, included: false, served: true}
+ ],
+
+ // list of files to exclude
+ exclude : [],
+
+ // use dolts reporter, as travis terminal does not support escaping sequences
+ // possible values: 'dots', 'progress', 'junit', 'teamcity'
+ // CLI --reporters progress
+ reporters : ['progress'],
+
+ // web server port
+ // CLI --port 9876
+ port : 9876,
+
+ // cli runner port
+ // CLI --runner-port 9100
+ runnerPort : 9100,
+
+ // enable / disable colors in the output (reporters and logs)
+ // CLI --colors --no-colors
+ colors : true,
+
+ // level of logging
+ // possible values: karma.LOG_DISABLE || karma.LOG_ERROR || karma.LOG_WARN || karma.LOG_INFO || karma.LOG_DEBUG
+ // CLI --log-level debug
+ logLevel : config.LOG_DEBUG,
+
+ // enable / disable watching file and executing tests whenever any file changes
+ // CLI --auto-watch --no-auto-watch
+ autoWatch : false,
+
+ // Start these browsers, currently available:
+ // - Chrome
+ // - ChromeCanary
+ // - Firefox
+ // - Opera
+ // - Safari (only Mac)
+ // - PhantomJS
+ // - IE (only Windows)
+ // CLI --browsers Chrome,Firefox,Safari
+ browsers : ['Firefox'],
+
+ // If browser does not capture in given timeout [ms], kill it
+ // CLI --capture-timeout 5000
+ captureTimeout : 5000,
+
+ // Auto run tests on start (when browsers are captured) and exit
+ // CLI --single-run --no-single-run
+ singleRun : true,
+
+ // report which specs are slower than 500ms
+ // CLI --report-slower-than 500
+ reportSlowerThan : 1000,
+
+ preprocessors : {
+ // '**/client/js/*.js': 'coverage'
+ },
+
+ plugins : [
+ 'karma-mocha',
+ // 'karma-chrome-launcher',
+ 'karma-firefox-launcher',
+ // 'karma-phantomjs-launcher'
+ ]
+ });
+};
diff --git a/test/lib/pixi/core/Matrix.js b/test/lib/pixi/core/Matrix.js
new file mode 100644
index 0000000..d26386b
--- /dev/null
+++ b/test/lib/pixi/core/Matrix.js
@@ -0,0 +1,40 @@
+
+function pixi_core_Matrix_confirmNewMat3(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(1);
+ expect(matrix[5]).to.equal(0);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(1);
+}
+
+function pixi_core_Matrix_confirmNewMat4(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[0]).to.equal(1);
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(0);
+ expect(matrix[5]).to.equal(1);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(0);
+ expect(matrix[9]).to.equal(0);
+ expect(matrix[10]).to.equal(1);
+ expect(matrix[11]).to.equal(0);
+ expect(matrix[12]).to.equal(0);
+ expect(matrix[13]).to.equal(0);
+ expect(matrix[14]).to.equal(0);
+ expect(matrix[15]).to.equal(1);
+}
diff --git a/test/lib/pixi/core/Point.js b/test/lib/pixi/core/Point.js
new file mode 100644
index 0000000..e5df07b
--- /dev/null
+++ b/test/lib/pixi/core/Point.js
@@ -0,0 +1,10 @@
+
+function pixi_core_Point_confirm(obj, x, y) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Point);
+ expect(obj).to.respondTo('clone');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+}
diff --git a/test/lib/pixi/core/Rectangle.js b/test/lib/pixi/core/Rectangle.js
new file mode 100644
index 0000000..23f0d12
--- /dev/null
+++ b/test/lib/pixi/core/Rectangle.js
@@ -0,0 +1,13 @@
+
+function pixi_core_Rectangle_confirm(obj, x, y, width, height) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Rectangle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+ expect(obj).to.have.property('width', width);
+ expect(obj).to.have.property('height', height);
+}
diff --git a/test/lib/pixi/display/DisplayObject.js b/test/lib/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..1388a7f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObject.js
@@ -0,0 +1,43 @@
+
+function pixi_display_DisplayObject_confirmNew(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObject);
+ expect(obj).to.respondTo('setInteractive');
+ expect(obj).to.respondTo('addFilter');
+ expect(obj).to.respondTo('removeFilter');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.property('last', obj);
+ expect(obj).to.have.property('first', obj);
+
+ expect(obj).to.contain.property('position');
+ pixi_core_Point_confirm(obj.position, 0, 0);
+ expect(obj).to.contain.property('scale');
+ pixi_core_Point_confirm(obj.scale, 1, 1);
+ expect(obj).to.contain.property('pivot');
+ pixi_core_Point_confirm(obj.pivot, 0, 0);
+
+ expect(obj).to.have.property('rotation', 0);
+ expect(obj).to.have.property('alpha', 1);
+ expect(obj).to.have.property('visible', true);
+ expect(obj).to.have.property('buttonMode', false);
+ expect(obj).to.have.property('parent', null);
+ expect(obj).to.have.property('worldAlpha', 1);
+
+ expect(obj).to.have.property('hitArea');
+ expect(obj).to.have.property('interactive'); // TODO: Have a better default value
+ expect('mask' in obj).to.be.true; // TODO: Have a better default value
+ expect(obj.mask).to.be.undefined;
+
+ expect(obj).to.have.property('renderable');
+ expect(obj).to.have.property('stage');
+
+ expect(obj).to.have.deep.property('worldTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ expect(obj).to.have.deep.property('localTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.localTransform);
+
+ expect(obj).to.have.deep.property('color.length', 0);
+ expect(obj).to.have.property('dynamic', true);
+}
diff --git a/test/lib/pixi/display/DisplayObjectContainer.js b/test/lib/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..085c59f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,16 @@
+
+function pixi_display_DisplayObjectContainer_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObject_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObjectContainer);
+ expect(obj).to.respondTo('addChild');
+ expect(obj).to.respondTo('addChildAt');
+ expect(obj).to.respondTo('swapChildren');
+ expect(obj).to.respondTo('getChildAt');
+ expect(obj).to.respondTo('removeChild');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('children.length', 0);
+}
diff --git a/test/lib/pixi/display/Sprite.js b/test/lib/pixi/display/Sprite.js
new file mode 100644
index 0000000..cc7a2d6
--- /dev/null
+++ b/test/lib/pixi/display/Sprite.js
@@ -0,0 +1,28 @@
+
+function pixi_display_Sprite_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Sprite);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', true);
+ expect(obj).to.have.property('stage', null);
+
+ expect(obj).to.have.property('anchor');
+ pixi_core_Point_confirm(obj.anchor, 0, 0);
+
+ expect(obj).to.have.property('blendMode', PIXI.blendModes.NORMAL);
+ expect(obj).to.have.property('width', 1); // TODO: is 1 expected
+ expect(obj).to.have.property('height', 1); // TODO: is 1 expected
+
+ // FIXME: Just make this a boolean that is always there
+ expect(!!obj.updateFrame).to.equal(obj.texture.baseTexture.hasLoaded);
+
+ expect(obj).to.have.property('texture');
+ pixi_textures_Texture_confirmNew(obj.texture, done);
+}
diff --git a/test/lib/pixi/extras/Strip.js b/test/lib/pixi/extras/Strip.js
new file mode 100644
index 0000000..8927a8a
--- /dev/null
+++ b/test/lib/pixi/extras/Strip.js
@@ -0,0 +1,12 @@
+
+function pixi_extras_Strip_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Strip);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ // TODO: Test properties
+}
diff --git a/test/lib/pixi/textures/Texture.js b/test/lib/pixi/textures/Texture.js
new file mode 100644
index 0000000..d5867b6
--- /dev/null
+++ b/test/lib/pixi/textures/Texture.js
@@ -0,0 +1,31 @@
+
+function pixi_textures_Texture_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ function confirmFrameDone() {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, obj.baseTexture.width, obj.baseTexture.height);
+
+ expect(obj).to.have.property('width', obj.baseTexture.width);
+ expect(obj).to.have.property('height', obj.baseTexture.height);
+ done();
+ }
+
+ expect(obj).to.be.an.instanceof(PIXI.Texture);
+ pixi_utils_EventTarget_like(obj);
+
+ expect(obj).to.have.property('baseTexture')
+ .and.to.be.an.instanceof(PIXI.BaseTexture);
+
+ expect(obj).to.have.property('scope', obj);
+
+ expect(obj).to.have.property('trim');
+ pixi_core_Point_confirm(obj.trim, 0, 0);
+
+ expect(obj).to.have.property('frame');
+ if (obj.baseTexture.hasLoaded) {
+ confirmFrameDone();
+ } else {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, 1, 1);
+ obj.addEventListener('update', confirmFrameDone);
+ }
+}
diff --git a/test/lib/pixi/utils/EventTarget.js b/test/lib/pixi/utils/EventTarget.js
new file mode 100644
index 0000000..7b1dcfa
--- /dev/null
+++ b/test/lib/pixi/utils/EventTarget.js
@@ -0,0 +1,8 @@
+
+function pixi_utils_EventTarget_like(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.respondTo('addEventListener');
+ expect(obj).to.respondTo('dispatchEvent');
+ expect(obj).to.respondTo('removeEventListener');
+}
diff --git a/test/lib/qunit-1.11.0.css b/test/lib/qunit-1.11.0.css
deleted file mode 100644
index d7fc0c8..0000000
--- a/test/lib/qunit-1.11.0.css
+++ /dev/null
@@ -1,244 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-/** Font Family and Sizes */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
- font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
-}
-
-#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
-#qunit-tests { font-size: smaller; }
-
-
-/** Resets */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter {
- margin: 0;
- padding: 0;
-}
-
-
-/** Header */
-
-#qunit-header {
- padding: 0.5em 0 0.5em 1em;
-
- color: #8699a4;
- background-color: #0d3349;
-
- font-size: 1.5em;
- line-height: 1em;
- font-weight: normal;
-
- border-radius: 5px 5px 0 0;
- -moz-border-radius: 5px 5px 0 0;
- -webkit-border-top-right-radius: 5px;
- -webkit-border-top-left-radius: 5px;
-}
-
-#qunit-header a {
- text-decoration: none;
- color: #c2ccd1;
-}
-
-#qunit-header a:hover,
-#qunit-header a:focus {
- color: #fff;
-}
-
-#qunit-testrunner-toolbar label {
- display: inline-block;
- padding: 0 .5em 0 .1em;
-}
-
-#qunit-banner {
- height: 5px;
-}
-
-#qunit-testrunner-toolbar {
- padding: 0.5em 0 0.5em 2em;
- color: #5E740B;
- background-color: #eee;
- overflow: hidden;
-}
-
-#qunit-userAgent {
- padding: 0.5em 0 0.5em 2.5em;
- background-color: #2b81af;
- color: #fff;
- text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
-}
-
-#qunit-modulefilter-container {
- float: right;
-}
-
-/** Tests: Pass/Fail */
-
-#qunit-tests {
- list-style-position: inside;
-}
-
-#qunit-tests li {
- padding: 0.4em 0.5em 0.4em 2.5em;
- border-bottom: 1px solid #fff;
- list-style-position: inside;
-}
-
-#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running {
- display: none;
-}
-
-#qunit-tests li strong {
- cursor: pointer;
-}
-
-#qunit-tests li a {
- padding: 0.5em;
- color: #c2ccd1;
- text-decoration: none;
-}
-#qunit-tests li a:hover,
-#qunit-tests li a:focus {
- color: #000;
-}
-
-#qunit-tests li .runtime {
- float: right;
- font-size: smaller;
-}
-
-.qunit-assert-list {
- margin-top: 0.5em;
- padding: 0.5em;
-
- background-color: #fff;
-
- border-radius: 5px;
- -moz-border-radius: 5px;
- -webkit-border-radius: 5px;
-}
-
-.qunit-collapsed {
- display: none;
-}
-
-#qunit-tests table {
- border-collapse: collapse;
- margin-top: .2em;
-}
-
-#qunit-tests th {
- text-align: right;
- vertical-align: top;
- padding: 0 .5em 0 0;
-}
-
-#qunit-tests td {
- vertical-align: top;
-}
-
-#qunit-tests pre {
- margin: 0;
- white-space: pre-wrap;
- word-wrap: break-word;
-}
-
-#qunit-tests del {
- background-color: #e0f2be;
- color: #374e0c;
- text-decoration: none;
-}
-
-#qunit-tests ins {
- background-color: #ffcaca;
- color: #500;
- text-decoration: none;
-}
-
-/*** Test Counts */
-
-#qunit-tests b.counts { color: black; }
-#qunit-tests b.passed { color: #5E740B; }
-#qunit-tests b.failed { color: #710909; }
-
-#qunit-tests li li {
- padding: 5px;
- background-color: #fff;
- border-bottom: none;
- list-style-position: inside;
-}
-
-/*** Passing Styles */
-
-#qunit-tests li li.pass {
- color: #3c510c;
- background-color: #fff;
- border-left: 10px solid #C6E746;
-}
-
-#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
-#qunit-tests .pass .test-name { color: #366097; }
-
-#qunit-tests .pass .test-actual,
-#qunit-tests .pass .test-expected { color: #999999; }
-
-#qunit-banner.qunit-pass { background-color: #C6E746; }
-
-/*** Failing Styles */
-
-#qunit-tests li li.fail {
- color: #710909;
- background-color: #fff;
- border-left: 10px solid #EE5757;
- white-space: pre;
-}
-
-#qunit-tests > li:last-child {
- border-radius: 0 0 5px 5px;
- -moz-border-radius: 0 0 5px 5px;
- -webkit-border-bottom-right-radius: 5px;
- -webkit-border-bottom-left-radius: 5px;
-}
-
-#qunit-tests .fail { color: #000000; background-color: #EE5757; }
-#qunit-tests .fail .test-name,
-#qunit-tests .fail .module-name { color: #000000; }
-
-#qunit-tests .fail .test-actual { color: #EE5757; }
-#qunit-tests .fail .test-expected { color: green; }
-
-#qunit-banner.qunit-fail { background-color: #EE5757; }
-
-
-/** Result */
-
-#qunit-testresult {
- padding: 0.5em 0.5em 0.5em 2.5em;
-
- color: #2b81af;
- background-color: #D2E0E6;
-
- border-bottom: 1px solid white;
-}
-#qunit-testresult .module-name {
- font-weight: bold;
-}
-
-/** Fixture */
-
-#qunit-fixture {
- position: absolute;
- top: -10000px;
- left: -10000px;
- width: 1000px;
- height: 1000px;
-}
diff --git a/test/lib/qunit-1.11.0.js b/test/lib/qunit-1.11.0.js
deleted file mode 100644
index 302545f..0000000
--- a/test/lib/qunit-1.11.0.js
+++ /dev/null
@@ -1,2152 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-(function( window ) {
-
-var QUnit,
- assert,
- config,
- onErrorFnPrev,
- testId = 0,
- fileName = (sourceFromStacktrace( 0 ) || "" ).replace(/(:\d+)+\)?/, "").replace(/.+\//, ""),
- toString = Object.prototype.toString,
- hasOwn = Object.prototype.hasOwnProperty,
- // Keep a local reference to Date (GH-283)
- Date = window.Date,
- defined = {
- setTimeout: typeof window.setTimeout !== "undefined",
- sessionStorage: (function() {
- var x = "qunit-test-string";
- try {
- sessionStorage.setItem( x, x );
- sessionStorage.removeItem( x );
- return true;
- } catch( e ) {
- return false;
- }
- }())
- },
- /**
- * Provides a normalized error string, correcting an issue
- * with IE 7 (and prior) where Error.prototype.toString is
- * not properly implemented
- *
- * Based on http://es5.github.com/#x15.11.4.4
- *
- * @param {String|Error} error
- * @return {String} error message
- */
- errorString = function( error ) {
- var name, message,
- errorString = error.toString();
- if ( errorString.substring( 0, 7 ) === "[object" ) {
- name = error.name ? error.name.toString() : "Error";
- message = error.message ? error.message.toString() : "";
- if ( name && message ) {
- return name + ": " + message;
- } else if ( name ) {
- return name;
- } else if ( message ) {
- return message;
- } else {
- return "Error";
- }
- } else {
- return errorString;
- }
- },
- /**
- * Makes a clone of an object using only Array or Object as base,
- * and copies over the own enumerable properties.
- *
- * @param {Object} obj
- * @return {Object} New object with only the own properties (recursively).
- */
- objectValues = function( obj ) {
- // Grunt 0.3.x uses an older version of jshint that still has jshint/jshint#392.
- /*jshint newcap: false */
- var key, val,
- vals = QUnit.is( "array", obj ) ? [] : {};
- for ( key in obj ) {
- if ( hasOwn.call( obj, key ) ) {
- val = obj[key];
- vals[key] = val === Object(val) ? objectValues(val) : val;
- }
- }
- return vals;
- };
-
-function Test( settings ) {
- extend( this, settings );
- this.assertions = [];
- this.testNumber = ++Test.count;
-}
-
-Test.count = 0;
-
-Test.prototype = {
- init: function() {
- var a, b, li,
- tests = id( "qunit-tests" );
-
- if ( tests ) {
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml;
-
- // `a` initialized at top of scope
- a = document.createElement( "a" );
- a.innerHTML = "Rerun";
- a.href = QUnit.url({ testNumber: this.testNumber });
-
- li = document.createElement( "li" );
- li.appendChild( b );
- li.appendChild( a );
- li.className = "running";
- li.id = this.id = "qunit-test-output" + testId++;
-
- tests.appendChild( li );
- }
- },
- setup: function() {
- if ( this.module !== config.previousModule ) {
- if ( config.previousModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.previousModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
- config.previousModule = this.module;
- config.moduleStats = { all: 0, bad: 0 };
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- } else if ( config.autorun ) {
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- }
-
- config.current = this;
-
- this.testEnvironment = extend({
- setup: function() {},
- teardown: function() {}
- }, this.moduleTestEnvironment );
-
- this.started = +new Date();
- runLoggingCallbacks( "testStart", QUnit, {
- name: this.testName,
- module: this.module
- });
-
- // allow utility functions to access the current test environment
- // TODO why??
- QUnit.current_testEnvironment = this.testEnvironment;
-
- if ( !config.pollution ) {
- saveGlobal();
- }
- if ( config.notrycatch ) {
- this.testEnvironment.setup.call( this.testEnvironment );
- return;
- }
- try {
- this.testEnvironment.setup.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Setup failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- },
- run: function() {
- config.current = this;
-
- var running = id( "qunit-testresult" );
-
- if ( running ) {
- running.innerHTML = "Running:
" + this.nameHtml;
- }
-
- if ( this.async ) {
- QUnit.stop();
- }
-
- this.callbackStarted = +new Date();
-
- if ( config.notrycatch ) {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- return;
- }
-
- try {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- } catch( e ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
-
- QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + " " + this.stack + ": " + ( e.message || e ), extractStacktrace( e, 0 ) );
- // else next test will carry the responsibility
- saveGlobal();
-
- // Restart the tests if they're blocking
- if ( config.blocking ) {
- QUnit.start();
- }
- }
- },
- teardown: function() {
- config.current = this;
- if ( config.notrycatch ) {
- if ( typeof this.callbackRuntime === "undefined" ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
- }
- this.testEnvironment.teardown.call( this.testEnvironment );
- return;
- } else {
- try {
- this.testEnvironment.teardown.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Teardown failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- }
- checkPollution();
- },
- finish: function() {
- config.current = this;
- if ( config.requireExpects && this.expected === null ) {
- QUnit.pushFailure( "Expected number of assertions to be defined, but expect() was not called.", this.stack );
- } else if ( this.expected !== null && this.expected !== this.assertions.length ) {
- QUnit.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack );
- } else if ( this.expected === null && !this.assertions.length ) {
- QUnit.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions.", this.stack );
- }
-
- var i, assertion, a, b, time, li, ol,
- test = this,
- good = 0,
- bad = 0,
- tests = id( "qunit-tests" );
-
- this.runtime = +new Date() - this.started;
- config.stats.all += this.assertions.length;
- config.moduleStats.all += this.assertions.length;
-
- if ( tests ) {
- ol = document.createElement( "ol" );
- ol.className = "qunit-assert-list";
-
- for ( i = 0; i < this.assertions.length; i++ ) {
- assertion = this.assertions[i];
-
- li = document.createElement( "li" );
- li.className = assertion.result ? "pass" : "fail";
- li.innerHTML = assertion.message || ( assertion.result ? "okay" : "failed" );
- ol.appendChild( li );
-
- if ( assertion.result ) {
- good++;
- } else {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
-
- // store result when possible
- if ( QUnit.config.reorder && defined.sessionStorage ) {
- if ( bad ) {
- sessionStorage.setItem( "qunit-test-" + this.module + "-" + this.testName, bad );
- } else {
- sessionStorage.removeItem( "qunit-test-" + this.module + "-" + this.testName );
- }
- }
-
- if ( bad === 0 ) {
- addClass( ol, "qunit-collapsed" );
- }
-
- // `b` initialized at top of scope
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml + " (" + bad + ", " + good + ", " + this.assertions.length + ")";
-
- addEvent(b, "click", function() {
- var next = b.parentNode.lastChild,
- collapsed = hasClass( next, "qunit-collapsed" );
- ( collapsed ? removeClass : addClass )( next, "qunit-collapsed" );
- });
-
- addEvent(b, "dblclick", function( e ) {
- var target = e && e.target ? e.target : window.event.srcElement;
- if ( target.nodeName.toLowerCase() === "span" || target.nodeName.toLowerCase() === "b" ) {
- target = target.parentNode;
- }
- if ( window.location && target.nodeName.toLowerCase() === "strong" ) {
- window.location = QUnit.url({ testNumber: test.testNumber });
- }
- });
-
- // `time` initialized at top of scope
- time = document.createElement( "span" );
- time.className = "runtime";
- time.innerHTML = this.runtime + " ms";
-
- // `li` initialized at top of scope
- li = id( this.id );
- li.className = bad ? "fail" : "pass";
- li.removeChild( li.firstChild );
- a = li.firstChild;
- li.appendChild( b );
- li.appendChild( a );
- li.appendChild( time );
- li.appendChild( ol );
-
- } else {
- for ( i = 0; i < this.assertions.length; i++ ) {
- if ( !this.assertions[i].result ) {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
- }
-
- runLoggingCallbacks( "testDone", QUnit, {
- name: this.testName,
- module: this.module,
- failed: bad,
- passed: this.assertions.length - bad,
- total: this.assertions.length,
- duration: this.runtime
- });
-
- QUnit.reset();
-
- config.current = undefined;
- },
-
- queue: function() {
- var bad,
- test = this;
-
- synchronize(function() {
- test.init();
- });
- function run() {
- // each of these can by async
- synchronize(function() {
- test.setup();
- });
- synchronize(function() {
- test.run();
- });
- synchronize(function() {
- test.teardown();
- });
- synchronize(function() {
- test.finish();
- });
- }
-
- // `bad` initialized at top of scope
- // defer when previous test run passed, if storage is available
- bad = QUnit.config.reorder && defined.sessionStorage &&
- +sessionStorage.getItem( "qunit-test-" + this.module + "-" + this.testName );
-
- if ( bad ) {
- run();
- } else {
- synchronize( run, true );
- }
- }
-};
-
-// Root QUnit object.
-// `QUnit` initialized at top of scope
-QUnit = {
-
- // call on start of module test to prepend name to all tests
- module: function( name, testEnvironment ) {
- config.currentModule = name;
- config.currentModuleTestEnvironment = testEnvironment;
- config.modules[name] = true;
- },
-
- asyncTest: function( testName, expected, callback ) {
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- QUnit.test( testName, expected, callback, true );
- },
-
- test: function( testName, expected, callback, async ) {
- var test,
- nameHtml = "" + escapeText( testName ) + "";
-
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- if ( config.currentModule ) {
- nameHtml = "" + escapeText( config.currentModule ) + ": " + nameHtml;
- }
-
- test = new Test({
- nameHtml: nameHtml,
- testName: testName,
- expected: expected,
- async: async,
- callback: callback,
- module: config.currentModule,
- moduleTestEnvironment: config.currentModuleTestEnvironment,
- stack: sourceFromStacktrace( 2 )
- });
-
- if ( !validTest( test ) ) {
- return;
- }
-
- test.queue();
- },
-
- // Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through.
- expect: function( asserts ) {
- if (arguments.length === 1) {
- config.current.expected = asserts;
- } else {
- return config.current.expected;
- }
- },
-
- start: function( count ) {
- // QUnit hasn't been initialized yet.
- // Note: RequireJS (et al) may delay onLoad
- if ( config.semaphore === undefined ) {
- QUnit.begin(function() {
- // This is triggered at the top of QUnit.load, push start() to the event loop, to allow QUnit.load to finish first
- setTimeout(function() {
- QUnit.start( count );
- });
- });
- return;
- }
-
- config.semaphore -= count || 1;
- // don't start until equal number of stop-calls
- if ( config.semaphore > 0 ) {
- return;
- }
- // ignore if start is called more often then stop
- if ( config.semaphore < 0 ) {
- config.semaphore = 0;
- QUnit.pushFailure( "Called start() while already started (QUnit.config.semaphore was 0 already)", null, sourceFromStacktrace(2) );
- return;
- }
- // A slight delay, to avoid any current callbacks
- if ( defined.setTimeout ) {
- window.setTimeout(function() {
- if ( config.semaphore > 0 ) {
- return;
- }
- if ( config.timeout ) {
- clearTimeout( config.timeout );
- }
-
- config.blocking = false;
- process( true );
- }, 13);
- } else {
- config.blocking = false;
- process( true );
- }
- },
-
- stop: function( count ) {
- config.semaphore += count || 1;
- config.blocking = true;
-
- if ( config.testTimeout && defined.setTimeout ) {
- clearTimeout( config.timeout );
- config.timeout = window.setTimeout(function() {
- QUnit.ok( false, "Test timed out" );
- config.semaphore = 1;
- QUnit.start();
- }, config.testTimeout );
- }
- }
-};
-
-// `assert` initialized at top of scope
-// Asssert helpers
-// All of these must either call QUnit.push() or manually do:
-// - runLoggingCallbacks( "log", .. );
-// - config.current.assertions.push({ .. });
-// We attach it to the QUnit object *after* we expose the public API,
-// otherwise `assert` will become a global variable in browsers (#341).
-assert = {
- /**
- * Asserts rough true-ish result.
- * @name ok
- * @function
- * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" );
- */
- ok: function( result, msg ) {
- if ( !config.current ) {
- throw new Error( "ok() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
- result = !!result;
-
- var source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: msg
- };
-
- msg = escapeText( msg || (result ? "okay" : "failed" ) );
- msg = "" + msg + "";
-
- if ( !result ) {
- source = sourceFromStacktrace( 2 );
- if ( source ) {
- details.source = source;
- msg += "Source: | " + escapeText( source ) + " |
---|
";
- }
- }
- runLoggingCallbacks( "log", QUnit, details );
- config.current.assertions.push({
- result: result,
- message: msg
- });
- },
-
- /**
- * Assert that the first two arguments are equal, with an optional message.
- * Prints out both actual and expected values.
- * @name equal
- * @function
- * @example equal( format( "Received {0} bytes.", 2), "Received 2 bytes.", "format() replaces {0} with next argument" );
- */
- equal: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected == actual, actual, expected, message );
- },
-
- /**
- * @name notEqual
- * @function
- */
- notEqual: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected != actual, actual, expected, message );
- },
-
- /**
- * @name propEqual
- * @function
- */
- propEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notPropEqual
- * @function
- */
- notPropEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name deepEqual
- * @function
- */
- deepEqual: function( actual, expected, message ) {
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notDeepEqual
- * @function
- */
- notDeepEqual: function( actual, expected, message ) {
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name strictEqual
- * @function
- */
- strictEqual: function( actual, expected, message ) {
- QUnit.push( expected === actual, actual, expected, message );
- },
-
- /**
- * @name notStrictEqual
- * @function
- */
- notStrictEqual: function( actual, expected, message ) {
- QUnit.push( expected !== actual, actual, expected, message );
- },
-
- "throws": function( block, expected, message ) {
- var actual,
- expectedOutput = expected,
- ok = false;
-
- // 'expected' is optional
- if ( typeof expected === "string" ) {
- message = expected;
- expected = null;
- }
-
- config.current.ignoreGlobalErrors = true;
- try {
- block.call( config.current.testEnvironment );
- } catch (e) {
- actual = e;
- }
- config.current.ignoreGlobalErrors = false;
-
- if ( actual ) {
- // we don't want to validate thrown error
- if ( !expected ) {
- ok = true;
- expectedOutput = null;
- // expected is a regexp
- } else if ( QUnit.objectType( expected ) === "regexp" ) {
- ok = expected.test( errorString( actual ) );
- // expected is a constructor
- } else if ( actual instanceof expected ) {
- ok = true;
- // expected is a validation function which returns true is validation passed
- } else if ( expected.call( {}, actual ) === true ) {
- expectedOutput = null;
- ok = true;
- }
-
- QUnit.push( ok, actual, expectedOutput, message );
- } else {
- QUnit.pushFailure( message, null, 'No exception was thrown.' );
- }
- }
-};
-
-/**
- * @deprecate since 1.8.0
- * Kept assertion helpers in root for backwards compatibility.
- */
-extend( QUnit, assert );
-
-/**
- * @deprecated since 1.9.0
- * Kept root "raises()" for backwards compatibility.
- * (Note that we don't introduce assert.raises).
- */
-QUnit.raises = assert[ "throws" ];
-
-/**
- * @deprecated since 1.0.0, replaced with error pushes since 1.3.0
- * Kept to avoid TypeErrors for undefined methods.
- */
-QUnit.equals = function() {
- QUnit.push( false, false, false, "QUnit.equals has been deprecated since 2009 (e88049a0), use QUnit.equal instead" );
-};
-QUnit.same = function() {
- QUnit.push( false, false, false, "QUnit.same has been deprecated since 2009 (e88049a0), use QUnit.deepEqual instead" );
-};
-
-// We want access to the constructor's prototype
-(function() {
- function F() {}
- F.prototype = QUnit;
- QUnit = new F();
- // Make F QUnit's constructor so that we can add to the prototype later
- QUnit.constructor = F;
-}());
-
-/**
- * Config object: Maintain internal state
- * Later exposed as QUnit.config
- * `config` initialized at top of scope
- */
-config = {
- // The queue of tests to run
- queue: [],
-
- // block until document ready
- blocking: true,
-
- // when enabled, show only failing tests
- // gets persisted through sessionStorage and can be changed in UI via checkbox
- hidepassed: false,
-
- // by default, run previously failed tests first
- // very useful in combination with "Hide passed tests" checked
- reorder: true,
-
- // by default, modify document.title when suite is done
- altertitle: true,
-
- // when enabled, all tests must call expect()
- requireExpects: false,
-
- // add checkboxes that are persisted in the query-string
- // when enabled, the id is set to `true` as a `QUnit.config` property
- urlConfig: [
- {
- id: "noglobals",
- label: "Check for Globals",
- tooltip: "Enabling this will test if any test introduces new properties on the `window` object. Stored as query-strings."
- },
- {
- id: "notrycatch",
- label: "No try-catch",
- tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging exceptions in IE reasonable. Stored as query-strings."
- }
- ],
-
- // Set of all modules.
- modules: {},
-
- // logging callback queues
- begin: [],
- done: [],
- log: [],
- testStart: [],
- testDone: [],
- moduleStart: [],
- moduleDone: []
-};
-
-// Export global variables, unless an 'exports' object exists,
-// in that case we assume we're in CommonJS (dealt with on the bottom of the script)
-if ( typeof exports === "undefined" ) {
- extend( window, QUnit );
-
- // Expose QUnit object
- window.QUnit = QUnit;
-}
-
-// Initialize more QUnit.config and QUnit.urlParams
-(function() {
- var i,
- location = window.location || { search: "", protocol: "file:" },
- params = location.search.slice( 1 ).split( "&" ),
- length = params.length,
- urlParams = {},
- current;
-
- if ( params[ 0 ] ) {
- for ( i = 0; i < length; i++ ) {
- current = params[ i ].split( "=" );
- current[ 0 ] = decodeURIComponent( current[ 0 ] );
- // allow just a key to turn on a flag, e.g., test.html?noglobals
- current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true;
- urlParams[ current[ 0 ] ] = current[ 1 ];
- }
- }
-
- QUnit.urlParams = urlParams;
-
- // String search anywhere in moduleName+testName
- config.filter = urlParams.filter;
-
- // Exact match of the module name
- config.module = urlParams.module;
-
- config.testNumber = parseInt( urlParams.testNumber, 10 ) || null;
-
- // Figure out if we're running the tests from a server or not
- QUnit.isLocal = location.protocol === "file:";
-}());
-
-// Extend QUnit object,
-// these after set here because they should not be exposed as global functions
-extend( QUnit, {
- assert: assert,
-
- config: config,
-
- // Initialize the configuration options
- init: function() {
- extend( config, {
- stats: { all: 0, bad: 0 },
- moduleStats: { all: 0, bad: 0 },
- started: +new Date(),
- updateRate: 1000,
- blocking: false,
- autostart: true,
- autorun: false,
- filter: "",
- queue: [],
- semaphore: 1
- });
-
- var tests, banner, result,
- qunit = id( "qunit" );
-
- if ( qunit ) {
- qunit.innerHTML =
- "" +
- "" +
- "" +
- "" +
- "
";
- }
-
- tests = id( "qunit-tests" );
- banner = id( "qunit-banner" );
- result = id( "qunit-testresult" );
-
- if ( tests ) {
- tests.innerHTML = "";
- }
-
- if ( banner ) {
- banner.className = "";
- }
-
- if ( result ) {
- result.parentNode.removeChild( result );
- }
-
- if ( tests ) {
- result = document.createElement( "p" );
- result.id = "qunit-testresult";
- result.className = "result";
- tests.parentNode.insertBefore( result, tests );
- result.innerHTML = "Running...
";
- }
- },
-
- // Resets the test setup. Useful for tests that modify the DOM.
- reset: function() {
- var fixture = id( "qunit-fixture" );
- if ( fixture ) {
- fixture.innerHTML = config.fixture;
- }
- },
-
- // Trigger an event on an element.
- // @example triggerEvent( document.body, "click" );
- triggerEvent: function( elem, type, event ) {
- if ( document.createEvent ) {
- event = document.createEvent( "MouseEvents" );
- event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView,
- 0, 0, 0, 0, 0, false, false, false, false, 0, null);
-
- elem.dispatchEvent( event );
- } else if ( elem.fireEvent ) {
- elem.fireEvent( "on" + type );
- }
- },
-
- // Safe object type checking
- is: function( type, obj ) {
- return QUnit.objectType( obj ) === type;
- },
-
- objectType: function( obj ) {
- if ( typeof obj === "undefined" ) {
- return "undefined";
- // consider: typeof null === object
- }
- if ( obj === null ) {
- return "null";
- }
-
- var match = toString.call( obj ).match(/^\[object\s(.*)\]$/),
- type = match && match[1] || "";
-
- switch ( type ) {
- case "Number":
- if ( isNaN(obj) ) {
- return "nan";
- }
- return "number";
- case "String":
- case "Boolean":
- case "Array":
- case "Date":
- case "RegExp":
- case "Function":
- return type.toLowerCase();
- }
- if ( typeof obj === "object" ) {
- return "object";
- }
- return undefined;
- },
-
- push: function( result, actual, expected, message ) {
- if ( !config.current ) {
- throw new Error( "assertion outside test context, was " + sourceFromStacktrace() );
- }
-
- var output, source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: message,
- actual: actual,
- expected: expected
- };
-
- message = escapeText( message ) || ( result ? "okay" : "failed" );
- message = "" + message + "";
- output = message;
-
- if ( !result ) {
- expected = escapeText( QUnit.jsDump.parse(expected) );
- actual = escapeText( QUnit.jsDump.parse(actual) );
- output += "Expected: | " + expected + " |
";
-
- if ( actual !== expected ) {
- output += "Result: | " + actual + " |
";
- output += "Diff: | " + QUnit.diff( expected, actual ) + " |
";
- }
-
- source = sourceFromStacktrace();
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
- }
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: !!result,
- message: output
- });
- },
-
- pushFailure: function( message, source, actual ) {
- if ( !config.current ) {
- throw new Error( "pushFailure() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
-
- var output,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: false,
- message: message
- };
-
- message = escapeText( message ) || "error";
- message = "" + message + "";
- output = message;
-
- output += "";
-
- if ( actual ) {
- output += "Result: | " + escapeText( actual ) + " |
";
- }
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: false,
- message: output
- });
- },
-
- url: function( params ) {
- params = extend( extend( {}, QUnit.urlParams ), params );
- var key,
- querystring = "?";
-
- for ( key in params ) {
- if ( !hasOwn.call( params, key ) ) {
- continue;
- }
- querystring += encodeURIComponent( key ) + "=" +
- encodeURIComponent( params[ key ] ) + "&";
- }
- return window.location.protocol + "//" + window.location.host +
- window.location.pathname + querystring.slice( 0, -1 );
- },
-
- extend: extend,
- id: id,
- addEvent: addEvent
- // load, equiv, jsDump, diff: Attached later
-});
-
-/**
- * @deprecated: Created for backwards compatibility with test runner that set the hook function
- * into QUnit.{hook}, instead of invoking it and passing the hook function.
- * QUnit.constructor is set to the empty F() above so that we can add to it's prototype here.
- * Doing this allows us to tell if the following methods have been overwritten on the actual
- * QUnit object.
- */
-extend( QUnit.constructor.prototype, {
-
- // Logging callbacks; all receive a single argument with the listed properties
- // run test/logs.html for any related changes
- begin: registerLoggingCallback( "begin" ),
-
- // done: { failed, passed, total, runtime }
- done: registerLoggingCallback( "done" ),
-
- // log: { result, actual, expected, message }
- log: registerLoggingCallback( "log" ),
-
- // testStart: { name }
- testStart: registerLoggingCallback( "testStart" ),
-
- // testDone: { name, failed, passed, total, duration }
- testDone: registerLoggingCallback( "testDone" ),
-
- // moduleStart: { name }
- moduleStart: registerLoggingCallback( "moduleStart" ),
-
- // moduleDone: { name, failed, passed, total }
- moduleDone: registerLoggingCallback( "moduleDone" )
-});
-
-if ( typeof document === "undefined" || document.readyState === "complete" ) {
- config.autorun = true;
-}
-
-QUnit.load = function() {
- runLoggingCallbacks( "begin", QUnit, {} );
-
- // Initialize the config, saving the execution queue
- var banner, filter, i, label, len, main, ol, toolbar, userAgent, val,
- urlConfigCheckboxesContainer, urlConfigCheckboxes, moduleFilter,
- numModules = 0,
- moduleFilterHtml = "",
- urlConfigHtml = "",
- oldconfig = extend( {}, config );
-
- QUnit.init();
- extend(config, oldconfig);
-
- config.blocking = false;
-
- len = config.urlConfig.length;
-
- for ( i = 0; i < len; i++ ) {
- val = config.urlConfig[i];
- if ( typeof val === "string" ) {
- val = {
- id: val,
- label: val,
- tooltip: "[no tooltip available]"
- };
- }
- config[ val.id ] = QUnit.urlParams[ val.id ];
- urlConfigHtml += "";
- }
-
- moduleFilterHtml += "";
-
- // `userAgent` initialized at top of scope
- userAgent = id( "qunit-userAgent" );
- if ( userAgent ) {
- userAgent.innerHTML = navigator.userAgent;
- }
-
- // `banner` initialized at top of scope
- banner = id( "qunit-header" );
- if ( banner ) {
- banner.innerHTML = "" + banner.innerHTML + " ";
- }
-
- // `toolbar` initialized at top of scope
- toolbar = id( "qunit-testrunner-toolbar" );
- if ( toolbar ) {
- // `filter` initialized at top of scope
- filter = document.createElement( "input" );
- filter.type = "checkbox";
- filter.id = "qunit-filter-pass";
-
- addEvent( filter, "click", function() {
- var tmp,
- ol = document.getElementById( "qunit-tests" );
-
- if ( filter.checked ) {
- ol.className = ol.className + " hidepass";
- } else {
- tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " ";
- ol.className = tmp.replace( / hidepass /, " " );
- }
- if ( defined.sessionStorage ) {
- if (filter.checked) {
- sessionStorage.setItem( "qunit-filter-passed-tests", "true" );
- } else {
- sessionStorage.removeItem( "qunit-filter-passed-tests" );
- }
- }
- });
-
- if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem( "qunit-filter-passed-tests" ) ) {
- filter.checked = true;
- // `ol` initialized at top of scope
- ol = document.getElementById( "qunit-tests" );
- ol.className = ol.className + " hidepass";
- }
- toolbar.appendChild( filter );
-
- // `label` initialized at top of scope
- label = document.createElement( "label" );
- label.setAttribute( "for", "qunit-filter-pass" );
- label.setAttribute( "title", "Only show tests and assertons that fail. Stored in sessionStorage." );
- label.innerHTML = "Hide passed tests";
- toolbar.appendChild( label );
-
- urlConfigCheckboxesContainer = document.createElement("span");
- urlConfigCheckboxesContainer.innerHTML = urlConfigHtml;
- urlConfigCheckboxes = urlConfigCheckboxesContainer.getElementsByTagName("input");
- // For oldIE support:
- // * Add handlers to the individual elements instead of the container
- // * Use "click" instead of "change"
- // * Fallback from event.target to event.srcElement
- addEvents( urlConfigCheckboxes, "click", function( event ) {
- var params = {},
- target = event.target || event.srcElement;
- params[ target.name ] = target.checked ? true : undefined;
- window.location = QUnit.url( params );
- });
- toolbar.appendChild( urlConfigCheckboxesContainer );
-
- if (numModules > 1) {
- moduleFilter = document.createElement( 'span' );
- moduleFilter.setAttribute( 'id', 'qunit-modulefilter-container' );
- moduleFilter.innerHTML = moduleFilterHtml;
- addEvent( moduleFilter.lastChild, "change", function() {
- var selectBox = moduleFilter.getElementsByTagName("select")[0],
- selectedModule = decodeURIComponent(selectBox.options[selectBox.selectedIndex].value);
-
- window.location = QUnit.url( { module: ( selectedModule === "" ) ? undefined : selectedModule } );
- });
- toolbar.appendChild(moduleFilter);
- }
- }
-
- // `main` initialized at top of scope
- main = id( "qunit-fixture" );
- if ( main ) {
- config.fixture = main.innerHTML;
- }
-
- if ( config.autostart ) {
- QUnit.start();
- }
-};
-
-addEvent( window, "load", QUnit.load );
-
-// `onErrorFnPrev` initialized at top of scope
-// Preserve other handlers
-onErrorFnPrev = window.onerror;
-
-// Cover uncaught exceptions
-// Returning true will surpress the default browser handler,
-// returning false will let it run.
-window.onerror = function ( error, filePath, linerNr ) {
- var ret = false;
- if ( onErrorFnPrev ) {
- ret = onErrorFnPrev( error, filePath, linerNr );
- }
-
- // Treat return value as window.onerror itself does,
- // Only do our handling if not surpressed.
- if ( ret !== true ) {
- if ( QUnit.config.current ) {
- if ( QUnit.config.current.ignoreGlobalErrors ) {
- return true;
- }
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- } else {
- QUnit.test( "global failure", extend( function() {
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- }, { validTest: validTest } ) );
- }
- return false;
- }
-
- return ret;
-};
-
-function done() {
- config.autorun = true;
-
- // Log the last module results
- if ( config.currentModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.currentModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
-
- var i, key,
- banner = id( "qunit-banner" ),
- tests = id( "qunit-tests" ),
- runtime = +new Date() - config.started,
- passed = config.stats.all - config.stats.bad,
- html = [
- "Tests completed in ",
- runtime,
- " milliseconds.
",
- "",
- passed,
- " assertions of ",
- config.stats.all,
- " passed, ",
- config.stats.bad,
- " failed."
- ].join( "" );
-
- if ( banner ) {
- banner.className = ( config.stats.bad ? "qunit-fail" : "qunit-pass" );
- }
-
- if ( tests ) {
- id( "qunit-testresult" ).innerHTML = html;
- }
-
- if ( config.altertitle && typeof document !== "undefined" && document.title ) {
- // show ✖ for good, ✔ for bad suite result in title
- // use escape sequences in case file gets loaded with non-utf-8-charset
- document.title = [
- ( config.stats.bad ? "\u2716" : "\u2714" ),
- document.title.replace( /^[\u2714\u2716] /i, "" )
- ].join( " " );
- }
-
- // clear own sessionStorage items if all tests passed
- if ( config.reorder && defined.sessionStorage && config.stats.bad === 0 ) {
- // `key` & `i` initialized at top of scope
- for ( i = 0; i < sessionStorage.length; i++ ) {
- key = sessionStorage.key( i++ );
- if ( key.indexOf( "qunit-test-" ) === 0 ) {
- sessionStorage.removeItem( key );
- }
- }
- }
-
- // scroll back to top to show results
- if ( window.scrollTo ) {
- window.scrollTo(0, 0);
- }
-
- runLoggingCallbacks( "done", QUnit, {
- failed: config.stats.bad,
- passed: passed,
- total: config.stats.all,
- runtime: runtime
- });
-}
-
-/** @return Boolean: true if this test should be ran */
-function validTest( test ) {
- var include,
- filter = config.filter && config.filter.toLowerCase(),
- module = config.module && config.module.toLowerCase(),
- fullName = (test.module + ": " + test.testName).toLowerCase();
-
- // Internally-generated tests are always valid
- if ( test.callback && test.callback.validTest === validTest ) {
- delete test.callback.validTest;
- return true;
- }
-
- if ( config.testNumber ) {
- return test.testNumber === config.testNumber;
- }
-
- if ( module && ( !test.module || test.module.toLowerCase() !== module ) ) {
- return false;
- }
-
- if ( !filter ) {
- return true;
- }
-
- include = filter.charAt( 0 ) !== "!";
- if ( !include ) {
- filter = filter.slice( 1 );
- }
-
- // If the filter matches, we need to honour include
- if ( fullName.indexOf( filter ) !== -1 ) {
- return include;
- }
-
- // Otherwise, do the opposite
- return !include;
-}
-
-// so far supports only Firefox, Chrome and Opera (buggy), Safari (for real exceptions)
-// Later Safari and IE10 are supposed to support error.stack as well
-// See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack
-function extractStacktrace( e, offset ) {
- offset = offset === undefined ? 3 : offset;
-
- var stack, include, i;
-
- if ( e.stacktrace ) {
- // Opera
- return e.stacktrace.split( "\n" )[ offset + 3 ];
- } else if ( e.stack ) {
- // Firefox, Chrome
- stack = e.stack.split( "\n" );
- if (/^error$/i.test( stack[0] ) ) {
- stack.shift();
- }
- if ( fileName ) {
- include = [];
- for ( i = offset; i < stack.length; i++ ) {
- if ( stack[ i ].indexOf( fileName ) !== -1 ) {
- break;
- }
- include.push( stack[ i ] );
- }
- if ( include.length ) {
- return include.join( "\n" );
- }
- }
- return stack[ offset ];
- } else if ( e.sourceURL ) {
- // Safari, PhantomJS
- // hopefully one day Safari provides actual stacktraces
- // exclude useless self-reference for generated Error objects
- if ( /qunit.js$/.test( e.sourceURL ) ) {
- return;
- }
- // for actual exceptions, this is useful
- return e.sourceURL + ":" + e.line;
- }
-}
-function sourceFromStacktrace( offset ) {
- try {
- throw new Error();
- } catch ( e ) {
- return extractStacktrace( e, offset );
- }
-}
-
-/**
- * Escape text for attribute or text content.
- */
-function escapeText( s ) {
- if ( !s ) {
- return "";
- }
- s = s + "";
- // Both single quotes and double quotes (for attributes)
- return s.replace( /['"<>&]/g, function( s ) {
- switch( s ) {
- case '\'':
- return ''';
- case '"':
- return '"';
- case '<':
- return '<';
- case '>':
- return '>';
- case '&':
- return '&';
- }
- });
-}
-
-function synchronize( callback, last ) {
- config.queue.push( callback );
-
- if ( config.autorun && !config.blocking ) {
- process( last );
- }
-}
-
-function process( last ) {
- function next() {
- process( last );
- }
- var start = new Date().getTime();
- config.depth = config.depth ? config.depth + 1 : 1;
-
- while ( config.queue.length && !config.blocking ) {
- if ( !defined.setTimeout || config.updateRate <= 0 || ( ( new Date().getTime() - start ) < config.updateRate ) ) {
- config.queue.shift()();
- } else {
- window.setTimeout( next, 13 );
- break;
- }
- }
- config.depth--;
- if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) {
- done();
- }
-}
-
-function saveGlobal() {
- config.pollution = [];
-
- if ( config.noglobals ) {
- for ( var key in window ) {
- // in Opera sometimes DOM element ids show up here, ignore them
- if ( !hasOwn.call( window, key ) || /^qunit-test-output/.test( key ) ) {
- continue;
- }
- config.pollution.push( key );
- }
- }
-}
-
-function checkPollution() {
- var newGlobals,
- deletedGlobals,
- old = config.pollution;
-
- saveGlobal();
-
- newGlobals = diff( config.pollution, old );
- if ( newGlobals.length > 0 ) {
- QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join(", ") );
- }
-
- deletedGlobals = diff( old, config.pollution );
- if ( deletedGlobals.length > 0 ) {
- QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join(", ") );
- }
-}
-
-// returns a new Array with the elements that are in a but not in b
-function diff( a, b ) {
- var i, j,
- result = a.slice();
-
- for ( i = 0; i < result.length; i++ ) {
- for ( j = 0; j < b.length; j++ ) {
- if ( result[i] === b[j] ) {
- result.splice( i, 1 );
- i--;
- break;
- }
- }
- }
- return result;
-}
-
-function extend( a, b ) {
- for ( var prop in b ) {
- if ( b[ prop ] === undefined ) {
- delete a[ prop ];
-
- // Avoid "Member not found" error in IE8 caused by setting window.constructor
- } else if ( prop !== "constructor" || a !== window ) {
- a[ prop ] = b[ prop ];
- }
- }
-
- return a;
-}
-
-/**
- * @param {HTMLElement} elem
- * @param {string} type
- * @param {Function} fn
- */
-function addEvent( elem, type, fn ) {
- // Standards-based browsers
- if ( elem.addEventListener ) {
- elem.addEventListener( type, fn, false );
- // IE
- } else {
- elem.attachEvent( "on" + type, fn );
- }
-}
-
-/**
- * @param {Array|NodeList} elems
- * @param {string} type
- * @param {Function} fn
- */
-function addEvents( elems, type, fn ) {
- var i = elems.length;
- while ( i-- ) {
- addEvent( elems[i], type, fn );
- }
-}
-
-function hasClass( elem, name ) {
- return (" " + elem.className + " ").indexOf(" " + name + " ") > -1;
-}
-
-function addClass( elem, name ) {
- if ( !hasClass( elem, name ) ) {
- elem.className += (elem.className ? " " : "") + name;
- }
-}
-
-function removeClass( elem, name ) {
- var set = " " + elem.className + " ";
- // Class name may appear multiple times
- while ( set.indexOf(" " + name + " ") > -1 ) {
- set = set.replace(" " + name + " " , " ");
- }
- // If possible, trim it for prettiness, but not neccecarily
- elem.className = window.jQuery ? jQuery.trim( set ) : ( set.trim ? set.trim() : set );
-}
-
-function id( name ) {
- return !!( typeof document !== "undefined" && document && document.getElementById ) &&
- document.getElementById( name );
-}
-
-function registerLoggingCallback( key ) {
- return function( callback ) {
- config[key].push( callback );
- };
-}
-
-// Supports deprecated method of completely overwriting logging callbacks
-function runLoggingCallbacks( key, scope, args ) {
- var i, callbacks;
- if ( QUnit.hasOwnProperty( key ) ) {
- QUnit[ key ].call(scope, args );
- } else {
- callbacks = config[ key ];
- for ( i = 0; i < callbacks.length; i++ ) {
- callbacks[ i ].call( scope, args );
- }
- }
-}
-
-// Test for equality any JavaScript type.
-// Author: Philippe Rathé
-QUnit.equiv = (function() {
-
- // Call the o related callback with the given arguments.
- function bindCallbacks( o, callbacks, args ) {
- var prop = QUnit.objectType( o );
- if ( prop ) {
- if ( QUnit.objectType( callbacks[ prop ] ) === "function" ) {
- return callbacks[ prop ].apply( callbacks, args );
- } else {
- return callbacks[ prop ]; // or undefined
- }
- }
- }
-
- // the real equiv function
- var innerEquiv,
- // stack to decide between skip/abort functions
- callers = [],
- // stack to avoiding loops from circular referencing
- parents = [],
-
- getProto = Object.getPrototypeOf || function ( obj ) {
- return obj.__proto__;
- },
- callbacks = (function () {
-
- // for string, boolean, number and null
- function useStrictEquality( b, a ) {
- /*jshint eqeqeq:false */
- if ( b instanceof a.constructor || a instanceof b.constructor ) {
- // to catch short annotaion VS 'new' annotation of a
- // declaration
- // e.g. var i = 1;
- // var j = new Number(1);
- return a == b;
- } else {
- return a === b;
- }
- }
-
- return {
- "string": useStrictEquality,
- "boolean": useStrictEquality,
- "number": useStrictEquality,
- "null": useStrictEquality,
- "undefined": useStrictEquality,
-
- "nan": function( b ) {
- return isNaN( b );
- },
-
- "date": function( b, a ) {
- return QUnit.objectType( b ) === "date" && a.valueOf() === b.valueOf();
- },
-
- "regexp": function( b, a ) {
- return QUnit.objectType( b ) === "regexp" &&
- // the regex itself
- a.source === b.source &&
- // and its modifers
- a.global === b.global &&
- // (gmi) ...
- a.ignoreCase === b.ignoreCase &&
- a.multiline === b.multiline &&
- a.sticky === b.sticky;
- },
-
- // - skip when the property is a method of an instance (OOP)
- // - abort otherwise,
- // initial === would have catch identical references anyway
- "function": function() {
- var caller = callers[callers.length - 1];
- return caller !== Object && typeof caller !== "undefined";
- },
-
- "array": function( b, a ) {
- var i, j, len, loop;
-
- // b could be an object literal here
- if ( QUnit.objectType( b ) !== "array" ) {
- return false;
- }
-
- len = a.length;
- if ( len !== b.length ) {
- // safe and faster
- return false;
- }
-
- // track reference to avoid circular references
- parents.push( a );
- for ( i = 0; i < len; i++ ) {
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- loop = true;// dont rewalk array
- }
- }
- if ( !loop && !innerEquiv(a[i], b[i]) ) {
- parents.pop();
- return false;
- }
- }
- parents.pop();
- return true;
- },
-
- "object": function( b, a ) {
- var i, j, loop,
- // Default to true
- eq = true,
- aProperties = [],
- bProperties = [];
-
- // comparing constructors is more strict than using
- // instanceof
- if ( a.constructor !== b.constructor ) {
- // Allow objects with no prototype to be equivalent to
- // objects with Object as their constructor.
- if ( !(( getProto(a) === null && getProto(b) === Object.prototype ) ||
- ( getProto(b) === null && getProto(a) === Object.prototype ) ) ) {
- return false;
- }
- }
-
- // stack constructor before traversing properties
- callers.push( a.constructor );
- // track reference to avoid circular references
- parents.push( a );
-
- for ( i in a ) { // be strict: don't ensures hasOwnProperty
- // and go deep
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- // don't go down the same path twice
- loop = true;
- }
- }
- aProperties.push(i); // collect a's properties
-
- if (!loop && !innerEquiv( a[i], b[i] ) ) {
- eq = false;
- break;
- }
- }
-
- callers.pop(); // unstack, we are done
- parents.pop();
-
- for ( i in b ) {
- bProperties.push( i ); // collect b's properties
- }
-
- // Ensures identical properties name
- return eq && innerEquiv( aProperties.sort(), bProperties.sort() );
- }
- };
- }());
-
- innerEquiv = function() { // can take multiple arguments
- var args = [].slice.apply( arguments );
- if ( args.length < 2 ) {
- return true; // end transition
- }
-
- return (function( a, b ) {
- if ( a === b ) {
- return true; // catch the most you can
- } else if ( a === null || b === null || typeof a === "undefined" ||
- typeof b === "undefined" ||
- QUnit.objectType(a) !== QUnit.objectType(b) ) {
- return false; // don't lose time with error prone cases
- } else {
- return bindCallbacks(a, callbacks, [ b, a ]);
- }
-
- // apply transition with (1..n) arguments
- }( args[0], args[1] ) && arguments.callee.apply( this, args.splice(1, args.length - 1 )) );
- };
-
- return innerEquiv;
-}());
-
-/**
- * jsDump Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com |
- * http://flesler.blogspot.com Licensed under BSD
- * (http://www.opensource.org/licenses/bsd-license.php) Date: 5/15/2008
- *
- * @projectDescription Advanced and extensible data dumping for Javascript.
- * @version 1.0.0
- * @author Ariel Flesler
- * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html}
- */
-QUnit.jsDump = (function() {
- function quote( str ) {
- return '"' + str.toString().replace( /"/g, '\\"' ) + '"';
- }
- function literal( o ) {
- return o + "";
- }
- function join( pre, arr, post ) {
- var s = jsDump.separator(),
- base = jsDump.indent(),
- inner = jsDump.indent(1);
- if ( arr.join ) {
- arr = arr.join( "," + s + inner );
- }
- if ( !arr ) {
- return pre + post;
- }
- return [ pre, inner + arr, base + post ].join(s);
- }
- function array( arr, stack ) {
- var i = arr.length, ret = new Array(i);
- this.up();
- while ( i-- ) {
- ret[i] = this.parse( arr[i] , undefined , stack);
- }
- this.down();
- return join( "[", ret, "]" );
- }
-
- var reName = /^function (\w+)/,
- jsDump = {
- // type is used mostly internally, you can fix a (custom)type in advance
- parse: function( obj, type, stack ) {
- stack = stack || [ ];
- var inStack, res,
- parser = this.parsers[ type || this.typeOf(obj) ];
-
- type = typeof parser;
- inStack = inArray( obj, stack );
-
- if ( inStack !== -1 ) {
- return "recursion(" + (inStack - stack.length) + ")";
- }
- if ( type === "function" ) {
- stack.push( obj );
- res = parser.call( this, obj, stack );
- stack.pop();
- return res;
- }
- return ( type === "string" ) ? parser : this.parsers.error;
- },
- typeOf: function( obj ) {
- var type;
- if ( obj === null ) {
- type = "null";
- } else if ( typeof obj === "undefined" ) {
- type = "undefined";
- } else if ( QUnit.is( "regexp", obj) ) {
- type = "regexp";
- } else if ( QUnit.is( "date", obj) ) {
- type = "date";
- } else if ( QUnit.is( "function", obj) ) {
- type = "function";
- } else if ( typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined" ) {
- type = "window";
- } else if ( obj.nodeType === 9 ) {
- type = "document";
- } else if ( obj.nodeType ) {
- type = "node";
- } else if (
- // native arrays
- toString.call( obj ) === "[object Array]" ||
- // NodeList objects
- ( typeof obj.length === "number" && typeof obj.item !== "undefined" && ( obj.length ? obj.item(0) === obj[0] : ( obj.item( 0 ) === null && typeof obj[0] === "undefined" ) ) )
- ) {
- type = "array";
- } else if ( obj.constructor === Error.prototype.constructor ) {
- type = "error";
- } else {
- type = typeof obj;
- }
- return type;
- },
- separator: function() {
- return this.multiline ? this.HTML ? "
" : "\n" : this.HTML ? " " : " ";
- },
- // extra can be a number, shortcut for increasing-calling-decreasing
- indent: function( extra ) {
- if ( !this.multiline ) {
- return "";
- }
- var chr = this.indentChar;
- if ( this.HTML ) {
- chr = chr.replace( /\t/g, " " ).replace( / /g, " " );
- }
- return new Array( this._depth_ + (extra||0) ).join(chr);
- },
- up: function( a ) {
- this._depth_ += a || 1;
- },
- down: function( a ) {
- this._depth_ -= a || 1;
- },
- setParser: function( name, parser ) {
- this.parsers[name] = parser;
- },
- // The next 3 are exposed so you can use them
- quote: quote,
- literal: literal,
- join: join,
- //
- _depth_: 1,
- // This is the list of parsers, to modify them, use jsDump.setParser
- parsers: {
- window: "[Window]",
- document: "[Document]",
- error: function(error) {
- return "Error(\"" + error.message + "\")";
- },
- unknown: "[Unknown]",
- "null": "null",
- "undefined": "undefined",
- "function": function( fn ) {
- var ret = "function",
- // functions never have name in IE
- name = "name" in fn ? fn.name : (reName.exec(fn) || [])[1];
-
- if ( name ) {
- ret += " " + name;
- }
- ret += "( ";
-
- ret = [ ret, QUnit.jsDump.parse( fn, "functionArgs" ), "){" ].join( "" );
- return join( ret, QUnit.jsDump.parse(fn,"functionCode" ), "}" );
- },
- array: array,
- nodelist: array,
- "arguments": array,
- object: function( map, stack ) {
- var ret = [ ], keys, key, val, i;
- QUnit.jsDump.up();
- keys = [];
- for ( key in map ) {
- keys.push( key );
- }
- keys.sort();
- for ( i = 0; i < keys.length; i++ ) {
- key = keys[ i ];
- val = map[ key ];
- ret.push( QUnit.jsDump.parse( key, "key" ) + ": " + QUnit.jsDump.parse( val, undefined, stack ) );
- }
- QUnit.jsDump.down();
- return join( "{", ret, "}" );
- },
- node: function( node ) {
- var len, i, val,
- open = QUnit.jsDump.HTML ? "<" : "<",
- close = QUnit.jsDump.HTML ? ">" : ">",
- tag = node.nodeName.toLowerCase(),
- ret = open + tag,
- attrs = node.attributes;
-
- if ( attrs ) {
- for ( i = 0, len = attrs.length; i < len; i++ ) {
- val = attrs[i].nodeValue;
- // IE6 includes all attributes in .attributes, even ones not explicitly set.
- // Those have values like undefined, null, 0, false, "" or "inherit".
- if ( val && val !== "inherit" ) {
- ret += " " + attrs[i].nodeName + "=" + QUnit.jsDump.parse( val, "attribute" );
- }
- }
- }
- ret += close;
-
- // Show content of TextNode or CDATASection
- if ( node.nodeType === 3 || node.nodeType === 4 ) {
- ret += node.nodeValue;
- }
-
- return ret + open + "/" + tag + close;
- },
- // function calls it internally, it's the arguments part of the function
- functionArgs: function( fn ) {
- var args,
- l = fn.length;
-
- if ( !l ) {
- return "";
- }
-
- args = new Array(l);
- while ( l-- ) {
- // 97 is 'a'
- args[l] = String.fromCharCode(97+l);
- }
- return " " + args.join( ", " ) + " ";
- },
- // object calls it internally, the key part of an item in a map
- key: quote,
- // function calls it internally, it's the content of the function
- functionCode: "[code]",
- // node calls it internally, it's an html attribute value
- attribute: quote,
- string: quote,
- date: quote,
- regexp: literal,
- number: literal,
- "boolean": literal
- },
- // if true, entities are escaped ( <, >, \t, space and \n )
- HTML: false,
- // indentation unit
- indentChar: " ",
- // if true, items in a collection, are separated by a \n, else just a space.
- multiline: true
- };
-
- return jsDump;
-}());
-
-// from jquery.js
-function inArray( elem, array ) {
- if ( array.indexOf ) {
- return array.indexOf( elem );
- }
-
- for ( var i = 0, length = array.length; i < length; i++ ) {
- if ( array[ i ] === elem ) {
- return i;
- }
- }
-
- return -1;
-}
-
-/*
- * Javascript Diff Algorithm
- * By John Resig (http://ejohn.org/)
- * Modified by Chu Alan "sprite"
- *
- * Released under the MIT license.
- *
- * More Info:
- * http://ejohn.org/projects/javascript-diff-algorithm/
- *
- * Usage: QUnit.diff(expected, actual)
- *
- * QUnit.diff( "the quick brown fox jumped over", "the quick fox jumps over" ) == "the quick brown fox jumped jumps over"
- */
-QUnit.diff = (function() {
- /*jshint eqeqeq:false, eqnull:true */
- function diff( o, n ) {
- var i,
- ns = {},
- os = {};
-
- for ( i = 0; i < n.length; i++ ) {
- if ( !hasOwn.call( ns, n[i] ) ) {
- ns[ n[i] ] = {
- rows: [],
- o: null
- };
- }
- ns[ n[i] ].rows.push( i );
- }
-
- for ( i = 0; i < o.length; i++ ) {
- if ( !hasOwn.call( os, o[i] ) ) {
- os[ o[i] ] = {
- rows: [],
- n: null
- };
- }
- os[ o[i] ].rows.push( i );
- }
-
- for ( i in ns ) {
- if ( !hasOwn.call( ns, i ) ) {
- continue;
- }
- if ( ns[i].rows.length === 1 && hasOwn.call( os, i ) && os[i].rows.length === 1 ) {
- n[ ns[i].rows[0] ] = {
- text: n[ ns[i].rows[0] ],
- row: os[i].rows[0]
- };
- o[ os[i].rows[0] ] = {
- text: o[ os[i].rows[0] ],
- row: ns[i].rows[0]
- };
- }
- }
-
- for ( i = 0; i < n.length - 1; i++ ) {
- if ( n[i].text != null && n[ i + 1 ].text == null && n[i].row + 1 < o.length && o[ n[i].row + 1 ].text == null &&
- n[ i + 1 ] == o[ n[i].row + 1 ] ) {
-
- n[ i + 1 ] = {
- text: n[ i + 1 ],
- row: n[i].row + 1
- };
- o[ n[i].row + 1 ] = {
- text: o[ n[i].row + 1 ],
- row: i + 1
- };
- }
- }
-
- for ( i = n.length - 1; i > 0; i-- ) {
- if ( n[i].text != null && n[ i - 1 ].text == null && n[i].row > 0 && o[ n[i].row - 1 ].text == null &&
- n[ i - 1 ] == o[ n[i].row - 1 ]) {
-
- n[ i - 1 ] = {
- text: n[ i - 1 ],
- row: n[i].row - 1
- };
- o[ n[i].row - 1 ] = {
- text: o[ n[i].row - 1 ],
- row: i - 1
- };
- }
- }
-
- return {
- o: o,
- n: n
- };
- }
-
- return function( o, n ) {
- o = o.replace( /\s+$/, "" );
- n = n.replace( /\s+$/, "" );
-
- var i, pre,
- str = "",
- out = diff( o === "" ? [] : o.split(/\s+/), n === "" ? [] : n.split(/\s+/) ),
- oSpace = o.match(/\s+/g),
- nSpace = n.match(/\s+/g);
-
- if ( oSpace == null ) {
- oSpace = [ " " ];
- }
- else {
- oSpace.push( " " );
- }
-
- if ( nSpace == null ) {
- nSpace = [ " " ];
- }
- else {
- nSpace.push( " " );
- }
-
- if ( out.n.length === 0 ) {
- for ( i = 0; i < out.o.length; i++ ) {
- str += "" + out.o[i] + oSpace[i] + "";
- }
- }
- else {
- if ( out.n[0].text == null ) {
- for ( n = 0; n < out.o.length && out.o[n].text == null; n++ ) {
- str += "" + out.o[n] + oSpace[n] + "";
- }
- }
-
- for ( i = 0; i < out.n.length; i++ ) {
- if (out.n[i].text == null) {
- str += "" + out.n[i] + nSpace[i] + "";
- }
- else {
- // `pre` initialized at top of scope
- pre = "";
-
- for ( n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++ ) {
- pre += "" + out.o[n] + oSpace[n] + "";
- }
- str += " " + out.n[i].text + nSpace[i] + pre;
- }
- }
- }
-
- return str;
- };
-}());
-
-// for CommonJS enviroments, export everything
-if ( typeof exports !== "undefined" ) {
- extend( exports, QUnit );
-}
-
-// get at whatever the global object is, like window in browsers
-}( (function() {return this;}.call()) ));
diff --git a/test/lib/require.js b/test/lib/require.js
deleted file mode 100644
index 987f865..0000000
--- a/test/lib/require.js
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- RequireJS 2.1.5 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.
- Available via the MIT or new BSD license.
- see: http://github.com/jrburke/requirejs for details
-*/
-var requirejs,require,define;
-(function(aa){function I(b){return"[object Function]"===L.call(b)}function J(b){return"[object Array]"===L.call(b)}function y(b,c){if(b){var d;for(d=0;dthis.depCount&&!this.defined){if(I(n)){if(this.events.error)try{e=i.execCb(c,n,b,e)}catch(d){a=d}else e=i.execCb(c,n,b,e);this.map.isDefine&&((b=this.module)&&void 0!==b.exports&&b.exports!==this.exports?e=b.exports:void 0===e&&this.usingExports&&(e=this.exports));if(a)return a.requireMap=this.map,a.requireModules=[this.map.id],a.requireType="define",v(this.error=
-a)}else e=n;this.exports=e;if(this.map.isDefine&&!this.ignore&&(q[c]=e,l.onResourceLoad))l.onResourceLoad(i,this.map,this.depMaps);x(c);this.defined=!0}this.defining=!1;this.defined&&!this.defineEmitted&&(this.defineEmitted=!0,this.emit("defined",this.exports),this.defineEmitComplete=!0)}}else this.fetch()}},callPlugin:function(){var a=this.map,b=a.id,d=j(a.prefix);this.depMaps.push(d);t(d,"defined",u(this,function(e){var n,d;d=this.map.name;var g=this.map.parentMap?this.map.parentMap.name:null,h=
-i.makeRequire(a.parentMap,{enableBuildCallback:!0});if(this.map.unnormalized){if(e.normalize&&(d=e.normalize(d,function(a){return c(a,g,!0)})||""),e=j(a.prefix+"!"+d,this.map.parentMap),t(e,"defined",u(this,function(a){this.init([],function(){return a},null,{enabled:!0,ignore:!0})})),d=m(p,e.id)){this.depMaps.push(e);if(this.events.error)d.on("error",u(this,function(a){this.emit("error",a)}));d.enable()}}else n=u(this,function(a){this.init([],function(){return a},null,{enabled:!0})}),n.error=u(this,
-function(a){this.inited=!0;this.error=a;a.requireModules=[b];G(p,function(a){0===a.map.id.indexOf(b+"_unnormalized")&&x(a.map.id)});v(a)}),n.fromText=u(this,function(e,c){var d=a.name,g=j(d),C=O;c&&(e=c);C&&(O=!1);r(g);s(k.config,b)&&(k.config[d]=k.config[b]);try{l.exec(e)}catch(ca){return v(B("fromtexteval","fromText eval for "+b+" failed: "+ca,ca,[b]))}C&&(O=!0);this.depMaps.push(g);i.completeLoad(d);h([d],n)}),e.load(a.name,h,n,k)}));i.enable(d,this);this.pluginMaps[d.id]=d},enable:function(){V[this.map.id]=
-this;this.enabling=this.enabled=!0;y(this.depMaps,u(this,function(a,b){var c,e;if("string"===typeof a){a=j(a,this.map.isDefine?this.map:this.map.parentMap,!1,!this.skipMap);this.depMaps[b]=a;if(c=m(N,a.id)){this.depExports[b]=c(this);return}this.depCount+=1;t(a,"defined",u(this,function(a){this.defineDep(b,a);this.check()}));this.errback&&t(a,"error",this.errback)}c=a.id;e=p[c];!s(N,c)&&(e&&!e.enabled)&&i.enable(a,this)}));G(this.pluginMaps,u(this,function(a){var b=m(p,a.id);b&&!b.enabled&&i.enable(a,
-this)}));this.enabling=!1;this.check()},on:function(a,b){var c=this.events[a];c||(c=this.events[a]=[]);c.push(b)},emit:function(a,b){y(this.events[a],function(a){a(b)});"error"===a&&delete this.events[a]}};i={config:k,contextName:b,registry:p,defined:q,urlFetched:U,defQueue:H,Module:Z,makeModuleMap:j,nextTick:l.nextTick,onError:v,configure:function(a){a.baseUrl&&"/"!==a.baseUrl.charAt(a.baseUrl.length-1)&&(a.baseUrl+="/");var b=k.pkgs,c=k.shim,e={paths:!0,config:!0,map:!0};G(a,function(a,b){e[b]?
-"map"===b?(k.map||(k.map={}),R(k[b],a,!0,!0)):R(k[b],a,!0):k[b]=a});a.shim&&(G(a.shim,function(a,b){J(a)&&(a={deps:a});if((a.exports||a.init)&&!a.exportsFn)a.exportsFn=i.makeShimExports(a);c[b]=a}),k.shim=c);a.packages&&(y(a.packages,function(a){a="string"===typeof a?{name:a}:a;b[a.name]={name:a.name,location:a.location||a.name,main:(a.main||"main").replace(ja,"").replace(ea,"")}}),k.pkgs=b);G(p,function(a,b){!a.inited&&!a.map.unnormalized&&(a.map=j(b))});if(a.deps||a.callback)i.require(a.deps||[],
-a.callback)},makeShimExports:function(a){return function(){var b;a.init&&(b=a.init.apply(aa,arguments));return b||a.exports&&ba(a.exports)}},makeRequire:function(a,f){function d(e,c,h){var g,k;f.enableBuildCallback&&(c&&I(c))&&(c.__requireJsBuild=!0);if("string"===typeof e){if(I(c))return v(B("requireargs","Invalid require call"),h);if(a&&s(N,e))return N[e](p[a.id]);if(l.get)return l.get(i,e,a,d);g=j(e,a,!1,!0);g=g.id;return!s(q,g)?v(B("notloaded",'Module name "'+g+'" has not been loaded yet for context: '+
-b+(a?"":". Use require([])"))):q[g]}L();i.nextTick(function(){L();k=r(j(null,a));k.skipMap=f.skipMap;k.init(e,c,h,{enabled:!0});D()});return d}f=f||{};R(d,{isBrowser:A,toUrl:function(b){var d,f=b.lastIndexOf("."),g=b.split("/")[0];if(-1!==f&&(!("."===g||".."===g)||1h.attachEvent.toString().indexOf("[native code"))&&!Y?(O=!0,h.attachEvent("onreadystatechange",b.onScriptLoad)):(h.addEventListener("load",b.onScriptLoad,!1),h.addEventListener("error",b.onScriptError,!1)),h.src=d,K=h,D?x.insertBefore(h,D):x.appendChild(h),K=null,h;if(da)try{importScripts(d),b.completeLoad(c)}catch(j){b.onError(B("importscripts","importScripts failed for "+c+" at "+d,j,[c]))}};A&&M(document.getElementsByTagName("script"),function(b){x||(x=
-b.parentNode);if(t=b.getAttribute("data-main"))return r.baseUrl||(E=t.split("/"),Q=E.pop(),fa=E.length?E.join("/")+"/":"./",r.baseUrl=fa,t=Q),t=t.replace(ea,""),r.deps=r.deps?r.deps.concat(t):[t],!0});define=function(b,c,d){var l,h;"string"!==typeof b&&(d=c,c=b,b=null);J(c)||(d=c,c=[]);!c.length&&I(d)&&d.length&&(d.toString().replace(la,"").replace(ma,function(b,d){c.push(d)}),c=(1===d.length?["require"]:["require","exports","module"]).concat(c));if(O){if(!(l=K))P&&"interactive"===P.readyState||M(document.getElementsByTagName("script"),
-function(b){if("interactive"===b.readyState)return P=b}),l=P;l&&(b||(b=l.getAttribute("data-requiremodule")),h=F[l.getAttribute("data-requirecontext")])}(h?h.defQueue:T).push([b,c,d])};define.amd={jQuery:!0};l.exec=function(b){return eval(b)};l(r)}})(this);
diff --git a/test/lib/resemble.js b/test/lib/resemble.js
new file mode 100644
index 0000000..1cb8c29
--- /dev/null
+++ b/test/lib/resemble.js
@@ -0,0 +1,535 @@
+/*
+Author: James Cryer
+Company: Huddle
+Last updated date: 21 Feb 2013
+URL: https://github.com/Huddle/Resemble.js
+*/
+
+(function(_this){
+ 'use strict';
+
+ _this['resemble'] = function( fileData ){
+
+ var data = {};
+ var images = [];
+ var updateCallbackArray = [];
+
+ var tolerance = { // between 0 and 255
+ red: 16,
+ green: 16,
+ blue: 16,
+ minBrightness: 16,
+ maxBrightness: 240
+ };
+
+ var ignoreAntialiasing = false;
+ var ignoreColors = false;
+
+ function triggerDataUpdate(){
+ var len = updateCallbackArray.length;
+ var i;
+ for(i=0;i tolerance.maxBrightness;
+ }
+
+ function getHue(r,g,b){
+
+ r = r / 255;
+ g = g / 255;
+ b = b / 255;
+ var max = Math.max(r, g, b), min = Math.min(r, g, b);
+ var h;
+ var d;
+
+ if (max == min){
+ h = 0; // achromatic
+ } else{
+ d = max - min;
+ switch(max){
+ case r: h = (g - b) / d + (g < b ? 6 : 0); break;
+ case g: h = (b - r) / d + 2; break;
+ case b: h = (r - g) / d + 4; break;
+ }
+ h /= 6;
+ }
+
+ return h;
+ }
+
+ function isAntialiased(sourcePix, data, cacheSet, verticalPos, horizontalPos, width){
+ var offset;
+ var targetPix;
+ var distance = 1;
+ var i;
+ var j;
+ var hasHighContrastSibling = 0;
+ var hasSiblingWithDifferentHue = 0;
+ var hasEquivilantSibling = 0;
+
+ addHueInfo(sourcePix);
+
+ for (i = distance*-1; i <= distance; i++){
+ for (j = distance*-1; j <= distance; j++){
+
+ if(i===0 && j===0){
+ // ignore source pixel
+ } else {
+
+ offset = ((verticalPos+j)*width + (horizontalPos+i)) * 4;
+ targetPix = getPixelInfo(data, offset, cacheSet);
+
+ if(targetPix === null){
+ continue;
+ }
+
+ addBrightnessInfo(targetPix);
+ addHueInfo(targetPix);
+
+ if( isContrasting(sourcePix, targetPix) ){
+ hasHighContrastSibling++;
+ }
+
+ if( isRGBSame(sourcePix,targetPix) ){
+ hasEquivilantSibling++;
+ }
+
+ if( Math.abs(targetPix.h - sourcePix.h) > 0.3 ){
+ hasSiblingWithDifferentHue++;
+ }
+
+ if( hasSiblingWithDifferentHue > 1 || hasHighContrastSibling > 1){
+ return true;
+ }
+ }
+ }
+ }
+
+ if(hasEquivilantSibling < 2){
+ return true;
+ }
+
+ return false;
+ }
+
+ function errorPixel(px, offset){
+ px[offset] = 255; //r
+ px[offset + 1] = 0; //g
+ px[offset + 2] = 255; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyPixel(px, offset, data){
+ px[offset] = data.r; //r
+ px[offset + 1] = data.g; //g
+ px[offset + 2] = data.b; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyGrayScalePixel(px, offset, data){
+ px[offset] = data.brightness; //r
+ px[offset + 1] = data.brightness; //g
+ px[offset + 2] = data.brightness; //b
+ px[offset + 3] = 255; //a
+ }
+
+
+ function getPixelInfo(data, offset, cacheSet){
+ var r;
+ var g;
+ var b;
+ var d;
+
+ if(typeof data[offset] !== 'undefined'){
+ r = data[offset];
+ g = data[offset+1];
+ b = data[offset+2];
+ d = {
+ r: r,
+ g: g,
+ b: b
+ };
+
+ return d;
+ } else {
+ return null;
+ }
+ }
+
+ function addBrightnessInfo(data){
+ data.brightness = getBrightness(data.r,data.g,data.b); // 'corrected' lightness
+ }
+
+ function addHueInfo(data){
+ data.h = getHue(data.r,data.g,data.b);
+ }
+
+ function analyseImages(img1, img2, width, height){
+
+ var hiddenCanvas = document.createElement('canvas');
+
+ var data1 = img1.data;
+ var data2 = img2.data;
+
+ hiddenCanvas.width = width;
+ hiddenCanvas.height = height;
+
+ var context = hiddenCanvas.getContext('2d');
+ var imgd = context.createImageData(width,height);
+ var targetPix = imgd.data;
+
+ var mismatchCount = 0;
+
+ var time = Date.now();
+
+ var skip;
+
+ if( (width > 1200 || height > 1200) && ignoreAntialiasing){
+ skip = 6;
+ }
+
+ loop(height, width, function(verticalPos, horizontalPos){
+
+ if(skip){ // only skip if the image isn't small
+ if(verticalPos % skip === 0 || horizontalPos % skip === 0){
+ return;
+ }
+ }
+
+ var offset = (verticalPos*width + horizontalPos) * 4;
+ var pixel1 = getPixelInfo(data1, offset, 1);
+ var pixel2 = getPixelInfo(data2, offset, 2);
+
+ if(pixel1 === null || pixel2 === null){
+ return;
+ }
+
+ if (ignoreColors){
+
+ addBrightnessInfo(pixel1);
+ addBrightnessInfo(pixel2);
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ return;
+ }
+
+ if( isRGBSimilar(pixel1, pixel2) ){
+ copyPixel(targetPix, offset, pixel2);
+
+ } else if( ignoreAntialiasing && (
+ addBrightnessInfo(pixel1), // jit pixel info augmentation looks a little weird, sorry.
+ addBrightnessInfo(pixel2),
+ isAntialiased(pixel1, data1, 1, verticalPos, horizontalPos, width) ||
+ isAntialiased(pixel2, data2, 2, verticalPos, horizontalPos, width)
+ )){
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+
+ });
+
+ data.misMatchPercentage = (mismatchCount / (height*width) * 100).toFixed(2);
+ data.analysisTime = Date.now() - time;
+
+ data.getImageDataUrl = function(text){
+ var barHeight = 0;
+
+ if(text){
+ barHeight = addLabel(text,context,hiddenCanvas);
+ }
+
+ context.putImageData(imgd, 0, barHeight);
+
+ return hiddenCanvas.toDataURL("image/png");
+ };
+ }
+
+ function addLabel(text, context, hiddenCanvas){
+ var textPadding = 2;
+
+ context.font = '12px sans-serif';
+
+ var textWidth = context.measureText(text).width + textPadding*2;
+ var barHeight = 22;
+
+ if(textWidth > hiddenCanvas.width){
+ hiddenCanvas.width = textWidth;
+ }
+
+ hiddenCanvas.height += barHeight;
+
+ context.fillStyle = "#666";
+ context.fillRect(0,0,hiddenCanvas.width,barHeight -4);
+ context.fillStyle = "#fff";
+ context.fillRect(0,barHeight -4,hiddenCanvas.width, 4);
+
+ context.fillStyle = "#fff";
+ context.textBaseline = "top";
+ context.font = '12px sans-serif';
+ context.fillText(text, textPadding, 1);
+
+ return barHeight;
+ }
+
+ function normalise(img, w, h){
+ var c;
+ var context;
+
+ if(img.height < h || img.width < w){
+ c = document.createElement('canvas');
+ c.width = w;
+ c.height = h;
+ context = c.getContext('2d');
+ context.putImageData(img, 0, 0);
+ return context.getImageData(0, 0, w, h);
+ }
+
+ return img;
+ }
+
+ function compare(one, two){
+
+ function onceWeHaveBoth(){
+ var width;
+ var height;
+ if(images.length === 2){
+ width = images[0].width > images[1].width ? images[0].width : images[1].width;
+ height = images[0].height > images[1].height ? images[0].height : images[1].height;
+
+ if( (images[0].width === images[1].width) && (images[0].height === images[1].height) ){
+ data.isSameDimensions = true;
+ } else {
+ data.isSameDimensions = false;
+ }
+
+ analyseImages( normalise(images[0],width, height), normalise(images[1],width, height), width, height);
+
+ triggerDataUpdate();
+ }
+ }
+
+ images = [];
+ loadImageData(one, onceWeHaveBoth);
+ loadImageData(two, onceWeHaveBoth);
+ }
+
+ function getCompareApi(param){
+
+ var secondFileData,
+ hasMethod = typeof param === 'function';
+
+ if( !hasMethod ){
+ // assume it's file data
+ secondFileData = param;
+ }
+
+ var self = {
+ ignoreNothing: function(){
+
+ tolerance.red = 16;
+ tolerance.green = 16;
+ tolerance.blue = 16;
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreAntialiasing: function(){
+
+ tolerance.red = 32;
+ tolerance.green = 32;
+ tolerance.blue = 32;
+ tolerance.minBrightness = 64;
+ tolerance.maxBrightness = 96;
+
+ ignoreAntialiasing = true;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreColors: function(){
+
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = true;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ onComplete: function( callback ){
+
+ updateCallbackArray.push(callback);
+
+ var wrapper = function(){
+ compare(fileData, secondFileData);
+ };
+
+ wrapper();
+
+ return getCompareApi(wrapper);
+ }
+ };
+
+ return self;
+ }
+
+ return {
+ onComplete: function( callback ){
+ updateCallbackArray.push(callback);
+ loadImageData(fileData, function(imageData, width, height){
+ parseImage(imageData.data, width, height);
+ });
+ },
+ compareTo: function(secondFileData){
+ return getCompareApi(secondFileData);
+ }
+ };
+
+ };
+}(this));
\ No newline at end of file
diff --git a/test/testsuite.js b/test/testsuite.js
deleted file mode 100644
index b486acb..0000000
--- a/test/testsuite.js
+++ /dev/null
@@ -1,36 +0,0 @@
-requirejs.config({
- baseUrl: '/test/unit/'
-});
-
-define(function(require) {
- var testModules = [
- 'Pixi',
- 'Point',
- 'Rectangle',
- 'DisplayObject',
- 'DisplayObjectContainer',
- 'Sprite',
- 'MovieClip',
- 'InteractionManager',
- 'Stage',
- 'utils/Utils',
- 'utils/EventTarget',
- 'utils/Matrix',
- 'utils/Detector',
- 'renderers/WebGLShaders',
- 'renderers/WebGLRenderer',
- 'renderers/WebGLBatch',
- 'renderers/CanvasRenderer',
- 'extras/Strip',
- 'extras/Rope',
- 'textures/BaseTexture',
- 'textures/Texture',
- 'loaders/SpriteSheetLoader',
- 'loaders/AssetLoader'
- ];
-
- // Resolve all testModules and then start the Test Runner.
- require(testModules, function() {
- QUnit.start();
- });
-});
\ No newline at end of file
diff --git a/test/textures/SpriteSheet-Aliens.png b/test/textures/SpriteSheet-Aliens.png
new file mode 100644
index 0000000..210acb1
--- /dev/null
+++ b/test/textures/SpriteSheet-Aliens.png
Binary files differ
diff --git a/test/textures/SpriteSheet-Explosion.png b/test/textures/SpriteSheet-Explosion.png
new file mode 100755
index 0000000..79e1a69
--- /dev/null
+++ b/test/textures/SpriteSheet-Explosion.png
Binary files differ
diff --git a/test/textures/bunny.png b/test/textures/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/textures/bunny.png
Binary files differ
diff --git a/test/unit/DisplayObject.js b/test/unit/DisplayObject.js
deleted file mode 100644
index 5e7e72f..0000000
--- a/test/unit/DisplayObject.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObject');
-});
diff --git a/test/unit/DisplayObjectContainer.js b/test/unit/DisplayObjectContainer.js
deleted file mode 100644
index b323959..0000000
--- a/test/unit/DisplayObjectContainer.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObjectContainer');
-});
diff --git a/test/unit/InteractionManager.js b/test/unit/InteractionManager.js
deleted file mode 100644
index e751f52..0000000
--- a/test/unit/InteractionManager.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('InteractionManager');
-});
diff --git a/test/unit/MovieClip.js b/test/unit/MovieClip.js
deleted file mode 100644
index 37d9446..0000000
--- a/test/unit/MovieClip.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('MovieClip');
-});
diff --git a/test/unit/Pixi.js b/test/unit/Pixi.js
deleted file mode 100644
index 36eee73..0000000
--- a/test/unit/Pixi.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Pixi');
-});
diff --git a/test/unit/Point.js b/test/unit/Point.js
deleted file mode 100644
index 983ff6e..0000000
--- a/test/unit/Point.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Point');
-});
diff --git a/test/unit/Rectangle.js b/test/unit/Rectangle.js
deleted file mode 100644
index 3b439ba..0000000
--- a/test/unit/Rectangle.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Rectangle');
-});
diff --git a/.gitignore b/.gitignore
index 12e1b62..0b88317 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
node_modules
.DS_Store
-.project
\ No newline at end of file
+.project
+*.log
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..63e4d7c
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,8 @@
+language: node_js
+node_js:
+ - 0.10
+
+before_script:
+ - npm install -g grunt-cli
+ - export DISPLAY=:99.0
+ - sh -e /etc/init.d/xvfb start
diff --git a/Gruntfile.js b/Gruntfile.js
index b083b49..103938c 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -1,10 +1,12 @@
+'use strict';
+
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-connect');
- grunt.loadNpmTasks('grunt-contrib-qunit');
grunt.loadNpmTasks('grunt-contrib-yuidoc');
+ grunt.loadTasks('tasks');
var root = 'src/pixi/',
debug = 'bin/pixi.dev.js',
@@ -79,7 +81,7 @@
},
files: {
srcBlob: '<%= dirs.src %>/**/*.js',
- testBlob: '<%= dirs.test %>/unit/**/*.js',
+ testBlob: '<%= dirs.test %>/{functional,lib/pixi,unit}/**/*.js',
build: '<%= dirs.build %>/pixi.dev.js',
buildMin: '<%= dirs.build %>/pixi.js'
},
@@ -94,7 +96,12 @@
},
jshint: {
beforeconcat: srcFiles,
- test: ['<%= files.testBlob %>'],
+ test: {
+ src: ['<%= files.testBlob %>'],
+ options: {
+ expr: true
+ }
+ },
options: {
asi: true,
smarttabs: true
@@ -128,12 +135,6 @@
]
},
connect: {
- qunit: {
- options: {
- port: grunt.option('port-test') || 9002,
- base: './'
- }
- },
test: {
options: {
port: grunt.option('port-test') || 9002,
@@ -142,13 +143,6 @@
}
}
},
- qunit: {
- all: {
- options: {
- urls: ['http://localhost:' + (grunt.option('port-test') || 9002) + '/test/index.html']
- }
- }
- },
yuidoc: {
compile: {
name: '<%= pkg.name %>',
@@ -161,6 +155,13 @@
outdir: '<%= dirs.docs %>'
}
}
+ },
+ karma: {
+ unit: {
+ configFile: 'test/karma.conf.js',
+ // browsers: ['Chrome'],
+ singleRun: true
+ }
}
});
@@ -182,9 +183,10 @@
}
)
- grunt.registerTask('default', ['concat', 'uglify', 'distribute']);
grunt.registerTask('build', ['concat', 'uglify', 'distribute']);
- grunt.registerTask('test', ['build', 'connect:qunit', 'qunit']);
+ grunt.registerTask('test', ['concat', 'jshint:test', 'karma']);
grunt.registerTask('docs', ['yuidoc']);
-
-}
\ No newline at end of file
+ grunt.registerTask('default', ['test', 'uglify', 'distribute']);
+ // Travis CI task.
+ grunt.registerTask('travis', ['test']);
+}
diff --git a/README.md b/README.md
index c62ef86..690cfe4 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,8 @@

+[](http://travis-ci.org/drkibitz/pixi.js)
+
#### JavaScript 2D Renderer ####
The aim of this project is to provide a fast lightweight 2D library that works
diff --git a/package.json b/package.json
index b373240..1246a68 100644
--- a/package.json
+++ b/package.json
@@ -18,14 +18,21 @@
"main": "bin/pixi.js",
+ "scripts": {
+ "test": "grunt travis --verbose"
+ },
+
"dependencies": {},
"devDependencies": {
"grunt": "~0.4.x",
- "grunt-contrib-jshint": "0.3.x",
+ "grunt-contrib-jshint": "0.6.x",
"grunt-contrib-uglify": "0.2.x",
- "grunt-contrib-connect": "0.2.x",
- "grunt-contrib-qunit": "0.2.x",
+ "grunt-contrib-connect": "0.3.x",
"grunt-contrib-yuidoc": "0.4.x",
- "grunt-contrib-concat": "0.1.x"
+ "grunt-contrib-concat": "0.3.x",
+ "chai": "~1.7.0",
+ "karma": "0.11.0",
+ "karma-firefox-launcher": "0.1.0",
+ "karma-mocha": "0.1.0"
}
}
diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js
index a7c520e..ee82bbd 100644
--- a/src/pixi/InteractionManager.js
+++ b/src/pixi/InteractionManager.js
@@ -62,7 +62,6 @@
this.onTouchEnd = this.onTouchEnd.bind(this);
this.onTouchMove = this.onTouchMove.bind(this);
-
this.last = 0;
}
diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js
index 1a95d20..eef1059 100644
--- a/src/pixi/core/Ellipse.js
+++ b/src/pixi/core/Ellipse.js
@@ -78,7 +78,7 @@
return (normx + normy < 0.25);
}
-PIXI.Ellipse.getBounds = function()
+PIXI.Ellipse.prototype.getBounds = function()
{
return new PIXI.Rectangle(this.x, this.y, this.width, this.height);
}
diff --git a/tasks/karma.js b/tasks/karma.js
new file mode 100644
index 0000000..c340485
--- /dev/null
+++ b/tasks/karma.js
@@ -0,0 +1,27 @@
+'use strict';
+
+var path = require('path');
+var server = require('karma').server;
+
+module.exports = function (grunt) {
+ grunt.registerMultiTask('karma', 'run karma.', function() {
+ var done = this.async();
+ var options = this.options({
+ background: false
+ });
+ var data = this.data;
+
+ //merge options onto data, with data taking precedence
+ data = grunt.util._.merge(options, data);
+ data.configFile = path.resolve(data.configFile);
+ if (data.configFile) {
+ data.configFile = grunt.template.process(data.configFile);
+ }
+
+ server.start(
+ data,
+ function(code) {
+ done(!code);
+ });
+ });
+};
diff --git a/test/functional/example-1-basics/bunny.png b/test/functional/example-1-basics/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/functional/example-1-basics/bunny.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-30.png b/test/functional/example-1-basics/frame-30.png
new file mode 100644
index 0000000..96e3409
--- /dev/null
+++ b/test/functional/example-1-basics/frame-30.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-60.png b/test/functional/example-1-basics/frame-60.png
new file mode 100644
index 0000000..af3f4ce
--- /dev/null
+++ b/test/functional/example-1-basics/frame-60.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-90.png b/test/functional/example-1-basics/frame-90.png
new file mode 100644
index 0000000..099b823
--- /dev/null
+++ b/test/functional/example-1-basics/frame-90.png
Binary files differ
diff --git a/test/functional/example-1-basics/index.js b/test/functional/example-1-basics/index.js
new file mode 100644
index 0000000..7ae7a98
--- /dev/null
+++ b/test/functional/example-1-basics/index.js
@@ -0,0 +1,133 @@
+describe('Example 1 - Basics', function () {
+ 'use strict';
+
+ var baseUri = '/base/test/functional/example-1-basics';
+ var expect = chai.expect;
+ var currentFrame = 0;
+ var frameEvents = {};
+ var stage;
+ var renderer;
+ var bunny;
+
+ function onFrame(frame, callback) {
+ frameEvents[frame] = callback;
+ }
+
+ function animate() {
+ currentFrame += 1;
+
+ requestAnimFrame( animate );
+
+ // just for fun, lets rotate mr rabbit a little
+ bunny.rotation += 0.1;
+
+ // render the stage
+ renderer.render(stage);
+
+ if (frameEvents[currentFrame])
+ frameEvents[currentFrame](currentFrame);
+ }
+
+ function initScene() {
+ // create an new instance of a pixi stage
+ stage = new PIXI.Stage(0x66FF99);
+
+ // create a renderer instance
+ renderer = PIXI.autoDetectRenderer(400, 300);
+ console.log('Is PIXI.WebGLRenderer: ' + (renderer instanceof PIXI.WebGLRenderer));
+
+ // add the renderer view element to the DOM
+ document.body.appendChild(renderer.view);
+
+ requestAnimFrame( animate );
+
+ // create a texture from an image path
+ var texture = PIXI.Texture.fromImage(baseUri + "/bunny.png");
+ // create a new Sprite using the texture
+ bunny = new PIXI.Sprite(texture);
+
+ // center the sprites anchor point
+ bunny.anchor.x = 0.5;
+ bunny.anchor.y = 0.5;
+
+ // move the sprite t the center of the screen
+ bunny.position.x = 200;
+ bunny.position.y = 150;
+
+ stage.addChild(bunny);
+ }
+
+ it('assets loaded', function (done) {
+ var loader = new PIXI.AssetLoader([
+ baseUri + '/bunny.png',
+ baseUri + '/frame-30.png',
+ baseUri + '/frame-60.png',
+ baseUri + '/frame-90.png'
+ ]);
+ // loader.on('onProgress', function (event) {
+ // console.log(event.content);
+ // });
+ loader.on('onComplete', function (event) {
+ done();
+ initScene();
+ });
+ loader.load();
+ });
+
+ it('frame 30 should match', function (done) {
+ this.timeout(700);
+ onFrame(30, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-30.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 60 should match', function (done) {
+ this.timeout(1200);
+ onFrame(60, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-60.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 90 should match', function (done) {
+ this.timeout(1700);
+ onFrame(90, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-90.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ // it('capture something', function (done) {
+ // this.timeout(2000000);
+ // onFrame(30, function () {
+ // var img = new Image();
+ // img.src = renderer.view.toDataURL('image/png');
+ // document.body.appendChild(img);
+ // });
+ // });
+});
diff --git a/test/index.html b/test/index.html
deleted file mode 100644
index 9cbcac5..0000000
--- a/test/index.html
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
- Pixi.js Test Suite
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/test/karma.conf.js b/test/karma.conf.js
new file mode 100644
index 0000000..c66a696
--- /dev/null
+++ b/test/karma.conf.js
@@ -0,0 +1,82 @@
+module.exports = function(config) {
+ config.set({
+
+ // base path, that will be used to resolve files and exclude
+ basePath : '../',
+
+ frameworks : ['mocha'],
+
+ // list of files / patterns to load in the browser
+ files : [
+ 'node_modules/chai/chai.js',
+ 'bin/pixi.dev.js',
+ 'test/lib/**/*.js',
+ 'test/unit/**/*.js',
+ // 'test/functional/**/*.js',
+ {pattern: 'test/**/*.png', watched: false, included: false, served: true}
+ ],
+
+ // list of files to exclude
+ exclude : [],
+
+ // use dolts reporter, as travis terminal does not support escaping sequences
+ // possible values: 'dots', 'progress', 'junit', 'teamcity'
+ // CLI --reporters progress
+ reporters : ['progress'],
+
+ // web server port
+ // CLI --port 9876
+ port : 9876,
+
+ // cli runner port
+ // CLI --runner-port 9100
+ runnerPort : 9100,
+
+ // enable / disable colors in the output (reporters and logs)
+ // CLI --colors --no-colors
+ colors : true,
+
+ // level of logging
+ // possible values: karma.LOG_DISABLE || karma.LOG_ERROR || karma.LOG_WARN || karma.LOG_INFO || karma.LOG_DEBUG
+ // CLI --log-level debug
+ logLevel : config.LOG_DEBUG,
+
+ // enable / disable watching file and executing tests whenever any file changes
+ // CLI --auto-watch --no-auto-watch
+ autoWatch : false,
+
+ // Start these browsers, currently available:
+ // - Chrome
+ // - ChromeCanary
+ // - Firefox
+ // - Opera
+ // - Safari (only Mac)
+ // - PhantomJS
+ // - IE (only Windows)
+ // CLI --browsers Chrome,Firefox,Safari
+ browsers : ['Firefox'],
+
+ // If browser does not capture in given timeout [ms], kill it
+ // CLI --capture-timeout 5000
+ captureTimeout : 5000,
+
+ // Auto run tests on start (when browsers are captured) and exit
+ // CLI --single-run --no-single-run
+ singleRun : true,
+
+ // report which specs are slower than 500ms
+ // CLI --report-slower-than 500
+ reportSlowerThan : 1000,
+
+ preprocessors : {
+ // '**/client/js/*.js': 'coverage'
+ },
+
+ plugins : [
+ 'karma-mocha',
+ // 'karma-chrome-launcher',
+ 'karma-firefox-launcher',
+ // 'karma-phantomjs-launcher'
+ ]
+ });
+};
diff --git a/test/lib/pixi/core/Matrix.js b/test/lib/pixi/core/Matrix.js
new file mode 100644
index 0000000..d26386b
--- /dev/null
+++ b/test/lib/pixi/core/Matrix.js
@@ -0,0 +1,40 @@
+
+function pixi_core_Matrix_confirmNewMat3(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(1);
+ expect(matrix[5]).to.equal(0);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(1);
+}
+
+function pixi_core_Matrix_confirmNewMat4(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[0]).to.equal(1);
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(0);
+ expect(matrix[5]).to.equal(1);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(0);
+ expect(matrix[9]).to.equal(0);
+ expect(matrix[10]).to.equal(1);
+ expect(matrix[11]).to.equal(0);
+ expect(matrix[12]).to.equal(0);
+ expect(matrix[13]).to.equal(0);
+ expect(matrix[14]).to.equal(0);
+ expect(matrix[15]).to.equal(1);
+}
diff --git a/test/lib/pixi/core/Point.js b/test/lib/pixi/core/Point.js
new file mode 100644
index 0000000..e5df07b
--- /dev/null
+++ b/test/lib/pixi/core/Point.js
@@ -0,0 +1,10 @@
+
+function pixi_core_Point_confirm(obj, x, y) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Point);
+ expect(obj).to.respondTo('clone');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+}
diff --git a/test/lib/pixi/core/Rectangle.js b/test/lib/pixi/core/Rectangle.js
new file mode 100644
index 0000000..23f0d12
--- /dev/null
+++ b/test/lib/pixi/core/Rectangle.js
@@ -0,0 +1,13 @@
+
+function pixi_core_Rectangle_confirm(obj, x, y, width, height) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Rectangle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+ expect(obj).to.have.property('width', width);
+ expect(obj).to.have.property('height', height);
+}
diff --git a/test/lib/pixi/display/DisplayObject.js b/test/lib/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..1388a7f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObject.js
@@ -0,0 +1,43 @@
+
+function pixi_display_DisplayObject_confirmNew(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObject);
+ expect(obj).to.respondTo('setInteractive');
+ expect(obj).to.respondTo('addFilter');
+ expect(obj).to.respondTo('removeFilter');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.property('last', obj);
+ expect(obj).to.have.property('first', obj);
+
+ expect(obj).to.contain.property('position');
+ pixi_core_Point_confirm(obj.position, 0, 0);
+ expect(obj).to.contain.property('scale');
+ pixi_core_Point_confirm(obj.scale, 1, 1);
+ expect(obj).to.contain.property('pivot');
+ pixi_core_Point_confirm(obj.pivot, 0, 0);
+
+ expect(obj).to.have.property('rotation', 0);
+ expect(obj).to.have.property('alpha', 1);
+ expect(obj).to.have.property('visible', true);
+ expect(obj).to.have.property('buttonMode', false);
+ expect(obj).to.have.property('parent', null);
+ expect(obj).to.have.property('worldAlpha', 1);
+
+ expect(obj).to.have.property('hitArea');
+ expect(obj).to.have.property('interactive'); // TODO: Have a better default value
+ expect('mask' in obj).to.be.true; // TODO: Have a better default value
+ expect(obj.mask).to.be.undefined;
+
+ expect(obj).to.have.property('renderable');
+ expect(obj).to.have.property('stage');
+
+ expect(obj).to.have.deep.property('worldTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ expect(obj).to.have.deep.property('localTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.localTransform);
+
+ expect(obj).to.have.deep.property('color.length', 0);
+ expect(obj).to.have.property('dynamic', true);
+}
diff --git a/test/lib/pixi/display/DisplayObjectContainer.js b/test/lib/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..085c59f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,16 @@
+
+function pixi_display_DisplayObjectContainer_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObject_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObjectContainer);
+ expect(obj).to.respondTo('addChild');
+ expect(obj).to.respondTo('addChildAt');
+ expect(obj).to.respondTo('swapChildren');
+ expect(obj).to.respondTo('getChildAt');
+ expect(obj).to.respondTo('removeChild');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('children.length', 0);
+}
diff --git a/test/lib/pixi/display/Sprite.js b/test/lib/pixi/display/Sprite.js
new file mode 100644
index 0000000..cc7a2d6
--- /dev/null
+++ b/test/lib/pixi/display/Sprite.js
@@ -0,0 +1,28 @@
+
+function pixi_display_Sprite_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Sprite);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', true);
+ expect(obj).to.have.property('stage', null);
+
+ expect(obj).to.have.property('anchor');
+ pixi_core_Point_confirm(obj.anchor, 0, 0);
+
+ expect(obj).to.have.property('blendMode', PIXI.blendModes.NORMAL);
+ expect(obj).to.have.property('width', 1); // TODO: is 1 expected
+ expect(obj).to.have.property('height', 1); // TODO: is 1 expected
+
+ // FIXME: Just make this a boolean that is always there
+ expect(!!obj.updateFrame).to.equal(obj.texture.baseTexture.hasLoaded);
+
+ expect(obj).to.have.property('texture');
+ pixi_textures_Texture_confirmNew(obj.texture, done);
+}
diff --git a/test/lib/pixi/extras/Strip.js b/test/lib/pixi/extras/Strip.js
new file mode 100644
index 0000000..8927a8a
--- /dev/null
+++ b/test/lib/pixi/extras/Strip.js
@@ -0,0 +1,12 @@
+
+function pixi_extras_Strip_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Strip);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ // TODO: Test properties
+}
diff --git a/test/lib/pixi/textures/Texture.js b/test/lib/pixi/textures/Texture.js
new file mode 100644
index 0000000..d5867b6
--- /dev/null
+++ b/test/lib/pixi/textures/Texture.js
@@ -0,0 +1,31 @@
+
+function pixi_textures_Texture_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ function confirmFrameDone() {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, obj.baseTexture.width, obj.baseTexture.height);
+
+ expect(obj).to.have.property('width', obj.baseTexture.width);
+ expect(obj).to.have.property('height', obj.baseTexture.height);
+ done();
+ }
+
+ expect(obj).to.be.an.instanceof(PIXI.Texture);
+ pixi_utils_EventTarget_like(obj);
+
+ expect(obj).to.have.property('baseTexture')
+ .and.to.be.an.instanceof(PIXI.BaseTexture);
+
+ expect(obj).to.have.property('scope', obj);
+
+ expect(obj).to.have.property('trim');
+ pixi_core_Point_confirm(obj.trim, 0, 0);
+
+ expect(obj).to.have.property('frame');
+ if (obj.baseTexture.hasLoaded) {
+ confirmFrameDone();
+ } else {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, 1, 1);
+ obj.addEventListener('update', confirmFrameDone);
+ }
+}
diff --git a/test/lib/pixi/utils/EventTarget.js b/test/lib/pixi/utils/EventTarget.js
new file mode 100644
index 0000000..7b1dcfa
--- /dev/null
+++ b/test/lib/pixi/utils/EventTarget.js
@@ -0,0 +1,8 @@
+
+function pixi_utils_EventTarget_like(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.respondTo('addEventListener');
+ expect(obj).to.respondTo('dispatchEvent');
+ expect(obj).to.respondTo('removeEventListener');
+}
diff --git a/test/lib/qunit-1.11.0.css b/test/lib/qunit-1.11.0.css
deleted file mode 100644
index d7fc0c8..0000000
--- a/test/lib/qunit-1.11.0.css
+++ /dev/null
@@ -1,244 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-/** Font Family and Sizes */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
- font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
-}
-
-#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
-#qunit-tests { font-size: smaller; }
-
-
-/** Resets */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter {
- margin: 0;
- padding: 0;
-}
-
-
-/** Header */
-
-#qunit-header {
- padding: 0.5em 0 0.5em 1em;
-
- color: #8699a4;
- background-color: #0d3349;
-
- font-size: 1.5em;
- line-height: 1em;
- font-weight: normal;
-
- border-radius: 5px 5px 0 0;
- -moz-border-radius: 5px 5px 0 0;
- -webkit-border-top-right-radius: 5px;
- -webkit-border-top-left-radius: 5px;
-}
-
-#qunit-header a {
- text-decoration: none;
- color: #c2ccd1;
-}
-
-#qunit-header a:hover,
-#qunit-header a:focus {
- color: #fff;
-}
-
-#qunit-testrunner-toolbar label {
- display: inline-block;
- padding: 0 .5em 0 .1em;
-}
-
-#qunit-banner {
- height: 5px;
-}
-
-#qunit-testrunner-toolbar {
- padding: 0.5em 0 0.5em 2em;
- color: #5E740B;
- background-color: #eee;
- overflow: hidden;
-}
-
-#qunit-userAgent {
- padding: 0.5em 0 0.5em 2.5em;
- background-color: #2b81af;
- color: #fff;
- text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
-}
-
-#qunit-modulefilter-container {
- float: right;
-}
-
-/** Tests: Pass/Fail */
-
-#qunit-tests {
- list-style-position: inside;
-}
-
-#qunit-tests li {
- padding: 0.4em 0.5em 0.4em 2.5em;
- border-bottom: 1px solid #fff;
- list-style-position: inside;
-}
-
-#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running {
- display: none;
-}
-
-#qunit-tests li strong {
- cursor: pointer;
-}
-
-#qunit-tests li a {
- padding: 0.5em;
- color: #c2ccd1;
- text-decoration: none;
-}
-#qunit-tests li a:hover,
-#qunit-tests li a:focus {
- color: #000;
-}
-
-#qunit-tests li .runtime {
- float: right;
- font-size: smaller;
-}
-
-.qunit-assert-list {
- margin-top: 0.5em;
- padding: 0.5em;
-
- background-color: #fff;
-
- border-radius: 5px;
- -moz-border-radius: 5px;
- -webkit-border-radius: 5px;
-}
-
-.qunit-collapsed {
- display: none;
-}
-
-#qunit-tests table {
- border-collapse: collapse;
- margin-top: .2em;
-}
-
-#qunit-tests th {
- text-align: right;
- vertical-align: top;
- padding: 0 .5em 0 0;
-}
-
-#qunit-tests td {
- vertical-align: top;
-}
-
-#qunit-tests pre {
- margin: 0;
- white-space: pre-wrap;
- word-wrap: break-word;
-}
-
-#qunit-tests del {
- background-color: #e0f2be;
- color: #374e0c;
- text-decoration: none;
-}
-
-#qunit-tests ins {
- background-color: #ffcaca;
- color: #500;
- text-decoration: none;
-}
-
-/*** Test Counts */
-
-#qunit-tests b.counts { color: black; }
-#qunit-tests b.passed { color: #5E740B; }
-#qunit-tests b.failed { color: #710909; }
-
-#qunit-tests li li {
- padding: 5px;
- background-color: #fff;
- border-bottom: none;
- list-style-position: inside;
-}
-
-/*** Passing Styles */
-
-#qunit-tests li li.pass {
- color: #3c510c;
- background-color: #fff;
- border-left: 10px solid #C6E746;
-}
-
-#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
-#qunit-tests .pass .test-name { color: #366097; }
-
-#qunit-tests .pass .test-actual,
-#qunit-tests .pass .test-expected { color: #999999; }
-
-#qunit-banner.qunit-pass { background-color: #C6E746; }
-
-/*** Failing Styles */
-
-#qunit-tests li li.fail {
- color: #710909;
- background-color: #fff;
- border-left: 10px solid #EE5757;
- white-space: pre;
-}
-
-#qunit-tests > li:last-child {
- border-radius: 0 0 5px 5px;
- -moz-border-radius: 0 0 5px 5px;
- -webkit-border-bottom-right-radius: 5px;
- -webkit-border-bottom-left-radius: 5px;
-}
-
-#qunit-tests .fail { color: #000000; background-color: #EE5757; }
-#qunit-tests .fail .test-name,
-#qunit-tests .fail .module-name { color: #000000; }
-
-#qunit-tests .fail .test-actual { color: #EE5757; }
-#qunit-tests .fail .test-expected { color: green; }
-
-#qunit-banner.qunit-fail { background-color: #EE5757; }
-
-
-/** Result */
-
-#qunit-testresult {
- padding: 0.5em 0.5em 0.5em 2.5em;
-
- color: #2b81af;
- background-color: #D2E0E6;
-
- border-bottom: 1px solid white;
-}
-#qunit-testresult .module-name {
- font-weight: bold;
-}
-
-/** Fixture */
-
-#qunit-fixture {
- position: absolute;
- top: -10000px;
- left: -10000px;
- width: 1000px;
- height: 1000px;
-}
diff --git a/test/lib/qunit-1.11.0.js b/test/lib/qunit-1.11.0.js
deleted file mode 100644
index 302545f..0000000
--- a/test/lib/qunit-1.11.0.js
+++ /dev/null
@@ -1,2152 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-(function( window ) {
-
-var QUnit,
- assert,
- config,
- onErrorFnPrev,
- testId = 0,
- fileName = (sourceFromStacktrace( 0 ) || "" ).replace(/(:\d+)+\)?/, "").replace(/.+\//, ""),
- toString = Object.prototype.toString,
- hasOwn = Object.prototype.hasOwnProperty,
- // Keep a local reference to Date (GH-283)
- Date = window.Date,
- defined = {
- setTimeout: typeof window.setTimeout !== "undefined",
- sessionStorage: (function() {
- var x = "qunit-test-string";
- try {
- sessionStorage.setItem( x, x );
- sessionStorage.removeItem( x );
- return true;
- } catch( e ) {
- return false;
- }
- }())
- },
- /**
- * Provides a normalized error string, correcting an issue
- * with IE 7 (and prior) where Error.prototype.toString is
- * not properly implemented
- *
- * Based on http://es5.github.com/#x15.11.4.4
- *
- * @param {String|Error} error
- * @return {String} error message
- */
- errorString = function( error ) {
- var name, message,
- errorString = error.toString();
- if ( errorString.substring( 0, 7 ) === "[object" ) {
- name = error.name ? error.name.toString() : "Error";
- message = error.message ? error.message.toString() : "";
- if ( name && message ) {
- return name + ": " + message;
- } else if ( name ) {
- return name;
- } else if ( message ) {
- return message;
- } else {
- return "Error";
- }
- } else {
- return errorString;
- }
- },
- /**
- * Makes a clone of an object using only Array or Object as base,
- * and copies over the own enumerable properties.
- *
- * @param {Object} obj
- * @return {Object} New object with only the own properties (recursively).
- */
- objectValues = function( obj ) {
- // Grunt 0.3.x uses an older version of jshint that still has jshint/jshint#392.
- /*jshint newcap: false */
- var key, val,
- vals = QUnit.is( "array", obj ) ? [] : {};
- for ( key in obj ) {
- if ( hasOwn.call( obj, key ) ) {
- val = obj[key];
- vals[key] = val === Object(val) ? objectValues(val) : val;
- }
- }
- return vals;
- };
-
-function Test( settings ) {
- extend( this, settings );
- this.assertions = [];
- this.testNumber = ++Test.count;
-}
-
-Test.count = 0;
-
-Test.prototype = {
- init: function() {
- var a, b, li,
- tests = id( "qunit-tests" );
-
- if ( tests ) {
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml;
-
- // `a` initialized at top of scope
- a = document.createElement( "a" );
- a.innerHTML = "Rerun";
- a.href = QUnit.url({ testNumber: this.testNumber });
-
- li = document.createElement( "li" );
- li.appendChild( b );
- li.appendChild( a );
- li.className = "running";
- li.id = this.id = "qunit-test-output" + testId++;
-
- tests.appendChild( li );
- }
- },
- setup: function() {
- if ( this.module !== config.previousModule ) {
- if ( config.previousModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.previousModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
- config.previousModule = this.module;
- config.moduleStats = { all: 0, bad: 0 };
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- } else if ( config.autorun ) {
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- }
-
- config.current = this;
-
- this.testEnvironment = extend({
- setup: function() {},
- teardown: function() {}
- }, this.moduleTestEnvironment );
-
- this.started = +new Date();
- runLoggingCallbacks( "testStart", QUnit, {
- name: this.testName,
- module: this.module
- });
-
- // allow utility functions to access the current test environment
- // TODO why??
- QUnit.current_testEnvironment = this.testEnvironment;
-
- if ( !config.pollution ) {
- saveGlobal();
- }
- if ( config.notrycatch ) {
- this.testEnvironment.setup.call( this.testEnvironment );
- return;
- }
- try {
- this.testEnvironment.setup.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Setup failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- },
- run: function() {
- config.current = this;
-
- var running = id( "qunit-testresult" );
-
- if ( running ) {
- running.innerHTML = "Running:
" + this.nameHtml;
- }
-
- if ( this.async ) {
- QUnit.stop();
- }
-
- this.callbackStarted = +new Date();
-
- if ( config.notrycatch ) {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- return;
- }
-
- try {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- } catch( e ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
-
- QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + " " + this.stack + ": " + ( e.message || e ), extractStacktrace( e, 0 ) );
- // else next test will carry the responsibility
- saveGlobal();
-
- // Restart the tests if they're blocking
- if ( config.blocking ) {
- QUnit.start();
- }
- }
- },
- teardown: function() {
- config.current = this;
- if ( config.notrycatch ) {
- if ( typeof this.callbackRuntime === "undefined" ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
- }
- this.testEnvironment.teardown.call( this.testEnvironment );
- return;
- } else {
- try {
- this.testEnvironment.teardown.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Teardown failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- }
- checkPollution();
- },
- finish: function() {
- config.current = this;
- if ( config.requireExpects && this.expected === null ) {
- QUnit.pushFailure( "Expected number of assertions to be defined, but expect() was not called.", this.stack );
- } else if ( this.expected !== null && this.expected !== this.assertions.length ) {
- QUnit.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack );
- } else if ( this.expected === null && !this.assertions.length ) {
- QUnit.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions.", this.stack );
- }
-
- var i, assertion, a, b, time, li, ol,
- test = this,
- good = 0,
- bad = 0,
- tests = id( "qunit-tests" );
-
- this.runtime = +new Date() - this.started;
- config.stats.all += this.assertions.length;
- config.moduleStats.all += this.assertions.length;
-
- if ( tests ) {
- ol = document.createElement( "ol" );
- ol.className = "qunit-assert-list";
-
- for ( i = 0; i < this.assertions.length; i++ ) {
- assertion = this.assertions[i];
-
- li = document.createElement( "li" );
- li.className = assertion.result ? "pass" : "fail";
- li.innerHTML = assertion.message || ( assertion.result ? "okay" : "failed" );
- ol.appendChild( li );
-
- if ( assertion.result ) {
- good++;
- } else {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
-
- // store result when possible
- if ( QUnit.config.reorder && defined.sessionStorage ) {
- if ( bad ) {
- sessionStorage.setItem( "qunit-test-" + this.module + "-" + this.testName, bad );
- } else {
- sessionStorage.removeItem( "qunit-test-" + this.module + "-" + this.testName );
- }
- }
-
- if ( bad === 0 ) {
- addClass( ol, "qunit-collapsed" );
- }
-
- // `b` initialized at top of scope
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml + " (" + bad + ", " + good + ", " + this.assertions.length + ")";
-
- addEvent(b, "click", function() {
- var next = b.parentNode.lastChild,
- collapsed = hasClass( next, "qunit-collapsed" );
- ( collapsed ? removeClass : addClass )( next, "qunit-collapsed" );
- });
-
- addEvent(b, "dblclick", function( e ) {
- var target = e && e.target ? e.target : window.event.srcElement;
- if ( target.nodeName.toLowerCase() === "span" || target.nodeName.toLowerCase() === "b" ) {
- target = target.parentNode;
- }
- if ( window.location && target.nodeName.toLowerCase() === "strong" ) {
- window.location = QUnit.url({ testNumber: test.testNumber });
- }
- });
-
- // `time` initialized at top of scope
- time = document.createElement( "span" );
- time.className = "runtime";
- time.innerHTML = this.runtime + " ms";
-
- // `li` initialized at top of scope
- li = id( this.id );
- li.className = bad ? "fail" : "pass";
- li.removeChild( li.firstChild );
- a = li.firstChild;
- li.appendChild( b );
- li.appendChild( a );
- li.appendChild( time );
- li.appendChild( ol );
-
- } else {
- for ( i = 0; i < this.assertions.length; i++ ) {
- if ( !this.assertions[i].result ) {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
- }
-
- runLoggingCallbacks( "testDone", QUnit, {
- name: this.testName,
- module: this.module,
- failed: bad,
- passed: this.assertions.length - bad,
- total: this.assertions.length,
- duration: this.runtime
- });
-
- QUnit.reset();
-
- config.current = undefined;
- },
-
- queue: function() {
- var bad,
- test = this;
-
- synchronize(function() {
- test.init();
- });
- function run() {
- // each of these can by async
- synchronize(function() {
- test.setup();
- });
- synchronize(function() {
- test.run();
- });
- synchronize(function() {
- test.teardown();
- });
- synchronize(function() {
- test.finish();
- });
- }
-
- // `bad` initialized at top of scope
- // defer when previous test run passed, if storage is available
- bad = QUnit.config.reorder && defined.sessionStorage &&
- +sessionStorage.getItem( "qunit-test-" + this.module + "-" + this.testName );
-
- if ( bad ) {
- run();
- } else {
- synchronize( run, true );
- }
- }
-};
-
-// Root QUnit object.
-// `QUnit` initialized at top of scope
-QUnit = {
-
- // call on start of module test to prepend name to all tests
- module: function( name, testEnvironment ) {
- config.currentModule = name;
- config.currentModuleTestEnvironment = testEnvironment;
- config.modules[name] = true;
- },
-
- asyncTest: function( testName, expected, callback ) {
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- QUnit.test( testName, expected, callback, true );
- },
-
- test: function( testName, expected, callback, async ) {
- var test,
- nameHtml = "" + escapeText( testName ) + "";
-
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- if ( config.currentModule ) {
- nameHtml = "" + escapeText( config.currentModule ) + ": " + nameHtml;
- }
-
- test = new Test({
- nameHtml: nameHtml,
- testName: testName,
- expected: expected,
- async: async,
- callback: callback,
- module: config.currentModule,
- moduleTestEnvironment: config.currentModuleTestEnvironment,
- stack: sourceFromStacktrace( 2 )
- });
-
- if ( !validTest( test ) ) {
- return;
- }
-
- test.queue();
- },
-
- // Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through.
- expect: function( asserts ) {
- if (arguments.length === 1) {
- config.current.expected = asserts;
- } else {
- return config.current.expected;
- }
- },
-
- start: function( count ) {
- // QUnit hasn't been initialized yet.
- // Note: RequireJS (et al) may delay onLoad
- if ( config.semaphore === undefined ) {
- QUnit.begin(function() {
- // This is triggered at the top of QUnit.load, push start() to the event loop, to allow QUnit.load to finish first
- setTimeout(function() {
- QUnit.start( count );
- });
- });
- return;
- }
-
- config.semaphore -= count || 1;
- // don't start until equal number of stop-calls
- if ( config.semaphore > 0 ) {
- return;
- }
- // ignore if start is called more often then stop
- if ( config.semaphore < 0 ) {
- config.semaphore = 0;
- QUnit.pushFailure( "Called start() while already started (QUnit.config.semaphore was 0 already)", null, sourceFromStacktrace(2) );
- return;
- }
- // A slight delay, to avoid any current callbacks
- if ( defined.setTimeout ) {
- window.setTimeout(function() {
- if ( config.semaphore > 0 ) {
- return;
- }
- if ( config.timeout ) {
- clearTimeout( config.timeout );
- }
-
- config.blocking = false;
- process( true );
- }, 13);
- } else {
- config.blocking = false;
- process( true );
- }
- },
-
- stop: function( count ) {
- config.semaphore += count || 1;
- config.blocking = true;
-
- if ( config.testTimeout && defined.setTimeout ) {
- clearTimeout( config.timeout );
- config.timeout = window.setTimeout(function() {
- QUnit.ok( false, "Test timed out" );
- config.semaphore = 1;
- QUnit.start();
- }, config.testTimeout );
- }
- }
-};
-
-// `assert` initialized at top of scope
-// Asssert helpers
-// All of these must either call QUnit.push() or manually do:
-// - runLoggingCallbacks( "log", .. );
-// - config.current.assertions.push({ .. });
-// We attach it to the QUnit object *after* we expose the public API,
-// otherwise `assert` will become a global variable in browsers (#341).
-assert = {
- /**
- * Asserts rough true-ish result.
- * @name ok
- * @function
- * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" );
- */
- ok: function( result, msg ) {
- if ( !config.current ) {
- throw new Error( "ok() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
- result = !!result;
-
- var source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: msg
- };
-
- msg = escapeText( msg || (result ? "okay" : "failed" ) );
- msg = "" + msg + "";
-
- if ( !result ) {
- source = sourceFromStacktrace( 2 );
- if ( source ) {
- details.source = source;
- msg += "Source: | " + escapeText( source ) + " |
---|
";
- }
- }
- runLoggingCallbacks( "log", QUnit, details );
- config.current.assertions.push({
- result: result,
- message: msg
- });
- },
-
- /**
- * Assert that the first two arguments are equal, with an optional message.
- * Prints out both actual and expected values.
- * @name equal
- * @function
- * @example equal( format( "Received {0} bytes.", 2), "Received 2 bytes.", "format() replaces {0} with next argument" );
- */
- equal: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected == actual, actual, expected, message );
- },
-
- /**
- * @name notEqual
- * @function
- */
- notEqual: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected != actual, actual, expected, message );
- },
-
- /**
- * @name propEqual
- * @function
- */
- propEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notPropEqual
- * @function
- */
- notPropEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name deepEqual
- * @function
- */
- deepEqual: function( actual, expected, message ) {
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notDeepEqual
- * @function
- */
- notDeepEqual: function( actual, expected, message ) {
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name strictEqual
- * @function
- */
- strictEqual: function( actual, expected, message ) {
- QUnit.push( expected === actual, actual, expected, message );
- },
-
- /**
- * @name notStrictEqual
- * @function
- */
- notStrictEqual: function( actual, expected, message ) {
- QUnit.push( expected !== actual, actual, expected, message );
- },
-
- "throws": function( block, expected, message ) {
- var actual,
- expectedOutput = expected,
- ok = false;
-
- // 'expected' is optional
- if ( typeof expected === "string" ) {
- message = expected;
- expected = null;
- }
-
- config.current.ignoreGlobalErrors = true;
- try {
- block.call( config.current.testEnvironment );
- } catch (e) {
- actual = e;
- }
- config.current.ignoreGlobalErrors = false;
-
- if ( actual ) {
- // we don't want to validate thrown error
- if ( !expected ) {
- ok = true;
- expectedOutput = null;
- // expected is a regexp
- } else if ( QUnit.objectType( expected ) === "regexp" ) {
- ok = expected.test( errorString( actual ) );
- // expected is a constructor
- } else if ( actual instanceof expected ) {
- ok = true;
- // expected is a validation function which returns true is validation passed
- } else if ( expected.call( {}, actual ) === true ) {
- expectedOutput = null;
- ok = true;
- }
-
- QUnit.push( ok, actual, expectedOutput, message );
- } else {
- QUnit.pushFailure( message, null, 'No exception was thrown.' );
- }
- }
-};
-
-/**
- * @deprecate since 1.8.0
- * Kept assertion helpers in root for backwards compatibility.
- */
-extend( QUnit, assert );
-
-/**
- * @deprecated since 1.9.0
- * Kept root "raises()" for backwards compatibility.
- * (Note that we don't introduce assert.raises).
- */
-QUnit.raises = assert[ "throws" ];
-
-/**
- * @deprecated since 1.0.0, replaced with error pushes since 1.3.0
- * Kept to avoid TypeErrors for undefined methods.
- */
-QUnit.equals = function() {
- QUnit.push( false, false, false, "QUnit.equals has been deprecated since 2009 (e88049a0), use QUnit.equal instead" );
-};
-QUnit.same = function() {
- QUnit.push( false, false, false, "QUnit.same has been deprecated since 2009 (e88049a0), use QUnit.deepEqual instead" );
-};
-
-// We want access to the constructor's prototype
-(function() {
- function F() {}
- F.prototype = QUnit;
- QUnit = new F();
- // Make F QUnit's constructor so that we can add to the prototype later
- QUnit.constructor = F;
-}());
-
-/**
- * Config object: Maintain internal state
- * Later exposed as QUnit.config
- * `config` initialized at top of scope
- */
-config = {
- // The queue of tests to run
- queue: [],
-
- // block until document ready
- blocking: true,
-
- // when enabled, show only failing tests
- // gets persisted through sessionStorage and can be changed in UI via checkbox
- hidepassed: false,
-
- // by default, run previously failed tests first
- // very useful in combination with "Hide passed tests" checked
- reorder: true,
-
- // by default, modify document.title when suite is done
- altertitle: true,
-
- // when enabled, all tests must call expect()
- requireExpects: false,
-
- // add checkboxes that are persisted in the query-string
- // when enabled, the id is set to `true` as a `QUnit.config` property
- urlConfig: [
- {
- id: "noglobals",
- label: "Check for Globals",
- tooltip: "Enabling this will test if any test introduces new properties on the `window` object. Stored as query-strings."
- },
- {
- id: "notrycatch",
- label: "No try-catch",
- tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging exceptions in IE reasonable. Stored as query-strings."
- }
- ],
-
- // Set of all modules.
- modules: {},
-
- // logging callback queues
- begin: [],
- done: [],
- log: [],
- testStart: [],
- testDone: [],
- moduleStart: [],
- moduleDone: []
-};
-
-// Export global variables, unless an 'exports' object exists,
-// in that case we assume we're in CommonJS (dealt with on the bottom of the script)
-if ( typeof exports === "undefined" ) {
- extend( window, QUnit );
-
- // Expose QUnit object
- window.QUnit = QUnit;
-}
-
-// Initialize more QUnit.config and QUnit.urlParams
-(function() {
- var i,
- location = window.location || { search: "", protocol: "file:" },
- params = location.search.slice( 1 ).split( "&" ),
- length = params.length,
- urlParams = {},
- current;
-
- if ( params[ 0 ] ) {
- for ( i = 0; i < length; i++ ) {
- current = params[ i ].split( "=" );
- current[ 0 ] = decodeURIComponent( current[ 0 ] );
- // allow just a key to turn on a flag, e.g., test.html?noglobals
- current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true;
- urlParams[ current[ 0 ] ] = current[ 1 ];
- }
- }
-
- QUnit.urlParams = urlParams;
-
- // String search anywhere in moduleName+testName
- config.filter = urlParams.filter;
-
- // Exact match of the module name
- config.module = urlParams.module;
-
- config.testNumber = parseInt( urlParams.testNumber, 10 ) || null;
-
- // Figure out if we're running the tests from a server or not
- QUnit.isLocal = location.protocol === "file:";
-}());
-
-// Extend QUnit object,
-// these after set here because they should not be exposed as global functions
-extend( QUnit, {
- assert: assert,
-
- config: config,
-
- // Initialize the configuration options
- init: function() {
- extend( config, {
- stats: { all: 0, bad: 0 },
- moduleStats: { all: 0, bad: 0 },
- started: +new Date(),
- updateRate: 1000,
- blocking: false,
- autostart: true,
- autorun: false,
- filter: "",
- queue: [],
- semaphore: 1
- });
-
- var tests, banner, result,
- qunit = id( "qunit" );
-
- if ( qunit ) {
- qunit.innerHTML =
- "" +
- "" +
- "" +
- "" +
- "
";
- }
-
- tests = id( "qunit-tests" );
- banner = id( "qunit-banner" );
- result = id( "qunit-testresult" );
-
- if ( tests ) {
- tests.innerHTML = "";
- }
-
- if ( banner ) {
- banner.className = "";
- }
-
- if ( result ) {
- result.parentNode.removeChild( result );
- }
-
- if ( tests ) {
- result = document.createElement( "p" );
- result.id = "qunit-testresult";
- result.className = "result";
- tests.parentNode.insertBefore( result, tests );
- result.innerHTML = "Running...
";
- }
- },
-
- // Resets the test setup. Useful for tests that modify the DOM.
- reset: function() {
- var fixture = id( "qunit-fixture" );
- if ( fixture ) {
- fixture.innerHTML = config.fixture;
- }
- },
-
- // Trigger an event on an element.
- // @example triggerEvent( document.body, "click" );
- triggerEvent: function( elem, type, event ) {
- if ( document.createEvent ) {
- event = document.createEvent( "MouseEvents" );
- event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView,
- 0, 0, 0, 0, 0, false, false, false, false, 0, null);
-
- elem.dispatchEvent( event );
- } else if ( elem.fireEvent ) {
- elem.fireEvent( "on" + type );
- }
- },
-
- // Safe object type checking
- is: function( type, obj ) {
- return QUnit.objectType( obj ) === type;
- },
-
- objectType: function( obj ) {
- if ( typeof obj === "undefined" ) {
- return "undefined";
- // consider: typeof null === object
- }
- if ( obj === null ) {
- return "null";
- }
-
- var match = toString.call( obj ).match(/^\[object\s(.*)\]$/),
- type = match && match[1] || "";
-
- switch ( type ) {
- case "Number":
- if ( isNaN(obj) ) {
- return "nan";
- }
- return "number";
- case "String":
- case "Boolean":
- case "Array":
- case "Date":
- case "RegExp":
- case "Function":
- return type.toLowerCase();
- }
- if ( typeof obj === "object" ) {
- return "object";
- }
- return undefined;
- },
-
- push: function( result, actual, expected, message ) {
- if ( !config.current ) {
- throw new Error( "assertion outside test context, was " + sourceFromStacktrace() );
- }
-
- var output, source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: message,
- actual: actual,
- expected: expected
- };
-
- message = escapeText( message ) || ( result ? "okay" : "failed" );
- message = "" + message + "";
- output = message;
-
- if ( !result ) {
- expected = escapeText( QUnit.jsDump.parse(expected) );
- actual = escapeText( QUnit.jsDump.parse(actual) );
- output += "Expected: | " + expected + " |
";
-
- if ( actual !== expected ) {
- output += "Result: | " + actual + " |
";
- output += "Diff: | " + QUnit.diff( expected, actual ) + " |
";
- }
-
- source = sourceFromStacktrace();
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
- }
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: !!result,
- message: output
- });
- },
-
- pushFailure: function( message, source, actual ) {
- if ( !config.current ) {
- throw new Error( "pushFailure() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
-
- var output,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: false,
- message: message
- };
-
- message = escapeText( message ) || "error";
- message = "" + message + "";
- output = message;
-
- output += "";
-
- if ( actual ) {
- output += "Result: | " + escapeText( actual ) + " |
";
- }
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: false,
- message: output
- });
- },
-
- url: function( params ) {
- params = extend( extend( {}, QUnit.urlParams ), params );
- var key,
- querystring = "?";
-
- for ( key in params ) {
- if ( !hasOwn.call( params, key ) ) {
- continue;
- }
- querystring += encodeURIComponent( key ) + "=" +
- encodeURIComponent( params[ key ] ) + "&";
- }
- return window.location.protocol + "//" + window.location.host +
- window.location.pathname + querystring.slice( 0, -1 );
- },
-
- extend: extend,
- id: id,
- addEvent: addEvent
- // load, equiv, jsDump, diff: Attached later
-});
-
-/**
- * @deprecated: Created for backwards compatibility with test runner that set the hook function
- * into QUnit.{hook}, instead of invoking it and passing the hook function.
- * QUnit.constructor is set to the empty F() above so that we can add to it's prototype here.
- * Doing this allows us to tell if the following methods have been overwritten on the actual
- * QUnit object.
- */
-extend( QUnit.constructor.prototype, {
-
- // Logging callbacks; all receive a single argument with the listed properties
- // run test/logs.html for any related changes
- begin: registerLoggingCallback( "begin" ),
-
- // done: { failed, passed, total, runtime }
- done: registerLoggingCallback( "done" ),
-
- // log: { result, actual, expected, message }
- log: registerLoggingCallback( "log" ),
-
- // testStart: { name }
- testStart: registerLoggingCallback( "testStart" ),
-
- // testDone: { name, failed, passed, total, duration }
- testDone: registerLoggingCallback( "testDone" ),
-
- // moduleStart: { name }
- moduleStart: registerLoggingCallback( "moduleStart" ),
-
- // moduleDone: { name, failed, passed, total }
- moduleDone: registerLoggingCallback( "moduleDone" )
-});
-
-if ( typeof document === "undefined" || document.readyState === "complete" ) {
- config.autorun = true;
-}
-
-QUnit.load = function() {
- runLoggingCallbacks( "begin", QUnit, {} );
-
- // Initialize the config, saving the execution queue
- var banner, filter, i, label, len, main, ol, toolbar, userAgent, val,
- urlConfigCheckboxesContainer, urlConfigCheckboxes, moduleFilter,
- numModules = 0,
- moduleFilterHtml = "",
- urlConfigHtml = "",
- oldconfig = extend( {}, config );
-
- QUnit.init();
- extend(config, oldconfig);
-
- config.blocking = false;
-
- len = config.urlConfig.length;
-
- for ( i = 0; i < len; i++ ) {
- val = config.urlConfig[i];
- if ( typeof val === "string" ) {
- val = {
- id: val,
- label: val,
- tooltip: "[no tooltip available]"
- };
- }
- config[ val.id ] = QUnit.urlParams[ val.id ];
- urlConfigHtml += "";
- }
-
- moduleFilterHtml += "";
-
- // `userAgent` initialized at top of scope
- userAgent = id( "qunit-userAgent" );
- if ( userAgent ) {
- userAgent.innerHTML = navigator.userAgent;
- }
-
- // `banner` initialized at top of scope
- banner = id( "qunit-header" );
- if ( banner ) {
- banner.innerHTML = "" + banner.innerHTML + " ";
- }
-
- // `toolbar` initialized at top of scope
- toolbar = id( "qunit-testrunner-toolbar" );
- if ( toolbar ) {
- // `filter` initialized at top of scope
- filter = document.createElement( "input" );
- filter.type = "checkbox";
- filter.id = "qunit-filter-pass";
-
- addEvent( filter, "click", function() {
- var tmp,
- ol = document.getElementById( "qunit-tests" );
-
- if ( filter.checked ) {
- ol.className = ol.className + " hidepass";
- } else {
- tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " ";
- ol.className = tmp.replace( / hidepass /, " " );
- }
- if ( defined.sessionStorage ) {
- if (filter.checked) {
- sessionStorage.setItem( "qunit-filter-passed-tests", "true" );
- } else {
- sessionStorage.removeItem( "qunit-filter-passed-tests" );
- }
- }
- });
-
- if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem( "qunit-filter-passed-tests" ) ) {
- filter.checked = true;
- // `ol` initialized at top of scope
- ol = document.getElementById( "qunit-tests" );
- ol.className = ol.className + " hidepass";
- }
- toolbar.appendChild( filter );
-
- // `label` initialized at top of scope
- label = document.createElement( "label" );
- label.setAttribute( "for", "qunit-filter-pass" );
- label.setAttribute( "title", "Only show tests and assertons that fail. Stored in sessionStorage." );
- label.innerHTML = "Hide passed tests";
- toolbar.appendChild( label );
-
- urlConfigCheckboxesContainer = document.createElement("span");
- urlConfigCheckboxesContainer.innerHTML = urlConfigHtml;
- urlConfigCheckboxes = urlConfigCheckboxesContainer.getElementsByTagName("input");
- // For oldIE support:
- // * Add handlers to the individual elements instead of the container
- // * Use "click" instead of "change"
- // * Fallback from event.target to event.srcElement
- addEvents( urlConfigCheckboxes, "click", function( event ) {
- var params = {},
- target = event.target || event.srcElement;
- params[ target.name ] = target.checked ? true : undefined;
- window.location = QUnit.url( params );
- });
- toolbar.appendChild( urlConfigCheckboxesContainer );
-
- if (numModules > 1) {
- moduleFilter = document.createElement( 'span' );
- moduleFilter.setAttribute( 'id', 'qunit-modulefilter-container' );
- moduleFilter.innerHTML = moduleFilterHtml;
- addEvent( moduleFilter.lastChild, "change", function() {
- var selectBox = moduleFilter.getElementsByTagName("select")[0],
- selectedModule = decodeURIComponent(selectBox.options[selectBox.selectedIndex].value);
-
- window.location = QUnit.url( { module: ( selectedModule === "" ) ? undefined : selectedModule } );
- });
- toolbar.appendChild(moduleFilter);
- }
- }
-
- // `main` initialized at top of scope
- main = id( "qunit-fixture" );
- if ( main ) {
- config.fixture = main.innerHTML;
- }
-
- if ( config.autostart ) {
- QUnit.start();
- }
-};
-
-addEvent( window, "load", QUnit.load );
-
-// `onErrorFnPrev` initialized at top of scope
-// Preserve other handlers
-onErrorFnPrev = window.onerror;
-
-// Cover uncaught exceptions
-// Returning true will surpress the default browser handler,
-// returning false will let it run.
-window.onerror = function ( error, filePath, linerNr ) {
- var ret = false;
- if ( onErrorFnPrev ) {
- ret = onErrorFnPrev( error, filePath, linerNr );
- }
-
- // Treat return value as window.onerror itself does,
- // Only do our handling if not surpressed.
- if ( ret !== true ) {
- if ( QUnit.config.current ) {
- if ( QUnit.config.current.ignoreGlobalErrors ) {
- return true;
- }
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- } else {
- QUnit.test( "global failure", extend( function() {
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- }, { validTest: validTest } ) );
- }
- return false;
- }
-
- return ret;
-};
-
-function done() {
- config.autorun = true;
-
- // Log the last module results
- if ( config.currentModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.currentModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
-
- var i, key,
- banner = id( "qunit-banner" ),
- tests = id( "qunit-tests" ),
- runtime = +new Date() - config.started,
- passed = config.stats.all - config.stats.bad,
- html = [
- "Tests completed in ",
- runtime,
- " milliseconds.
",
- "",
- passed,
- " assertions of ",
- config.stats.all,
- " passed, ",
- config.stats.bad,
- " failed."
- ].join( "" );
-
- if ( banner ) {
- banner.className = ( config.stats.bad ? "qunit-fail" : "qunit-pass" );
- }
-
- if ( tests ) {
- id( "qunit-testresult" ).innerHTML = html;
- }
-
- if ( config.altertitle && typeof document !== "undefined" && document.title ) {
- // show ✖ for good, ✔ for bad suite result in title
- // use escape sequences in case file gets loaded with non-utf-8-charset
- document.title = [
- ( config.stats.bad ? "\u2716" : "\u2714" ),
- document.title.replace( /^[\u2714\u2716] /i, "" )
- ].join( " " );
- }
-
- // clear own sessionStorage items if all tests passed
- if ( config.reorder && defined.sessionStorage && config.stats.bad === 0 ) {
- // `key` & `i` initialized at top of scope
- for ( i = 0; i < sessionStorage.length; i++ ) {
- key = sessionStorage.key( i++ );
- if ( key.indexOf( "qunit-test-" ) === 0 ) {
- sessionStorage.removeItem( key );
- }
- }
- }
-
- // scroll back to top to show results
- if ( window.scrollTo ) {
- window.scrollTo(0, 0);
- }
-
- runLoggingCallbacks( "done", QUnit, {
- failed: config.stats.bad,
- passed: passed,
- total: config.stats.all,
- runtime: runtime
- });
-}
-
-/** @return Boolean: true if this test should be ran */
-function validTest( test ) {
- var include,
- filter = config.filter && config.filter.toLowerCase(),
- module = config.module && config.module.toLowerCase(),
- fullName = (test.module + ": " + test.testName).toLowerCase();
-
- // Internally-generated tests are always valid
- if ( test.callback && test.callback.validTest === validTest ) {
- delete test.callback.validTest;
- return true;
- }
-
- if ( config.testNumber ) {
- return test.testNumber === config.testNumber;
- }
-
- if ( module && ( !test.module || test.module.toLowerCase() !== module ) ) {
- return false;
- }
-
- if ( !filter ) {
- return true;
- }
-
- include = filter.charAt( 0 ) !== "!";
- if ( !include ) {
- filter = filter.slice( 1 );
- }
-
- // If the filter matches, we need to honour include
- if ( fullName.indexOf( filter ) !== -1 ) {
- return include;
- }
-
- // Otherwise, do the opposite
- return !include;
-}
-
-// so far supports only Firefox, Chrome and Opera (buggy), Safari (for real exceptions)
-// Later Safari and IE10 are supposed to support error.stack as well
-// See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack
-function extractStacktrace( e, offset ) {
- offset = offset === undefined ? 3 : offset;
-
- var stack, include, i;
-
- if ( e.stacktrace ) {
- // Opera
- return e.stacktrace.split( "\n" )[ offset + 3 ];
- } else if ( e.stack ) {
- // Firefox, Chrome
- stack = e.stack.split( "\n" );
- if (/^error$/i.test( stack[0] ) ) {
- stack.shift();
- }
- if ( fileName ) {
- include = [];
- for ( i = offset; i < stack.length; i++ ) {
- if ( stack[ i ].indexOf( fileName ) !== -1 ) {
- break;
- }
- include.push( stack[ i ] );
- }
- if ( include.length ) {
- return include.join( "\n" );
- }
- }
- return stack[ offset ];
- } else if ( e.sourceURL ) {
- // Safari, PhantomJS
- // hopefully one day Safari provides actual stacktraces
- // exclude useless self-reference for generated Error objects
- if ( /qunit.js$/.test( e.sourceURL ) ) {
- return;
- }
- // for actual exceptions, this is useful
- return e.sourceURL + ":" + e.line;
- }
-}
-function sourceFromStacktrace( offset ) {
- try {
- throw new Error();
- } catch ( e ) {
- return extractStacktrace( e, offset );
- }
-}
-
-/**
- * Escape text for attribute or text content.
- */
-function escapeText( s ) {
- if ( !s ) {
- return "";
- }
- s = s + "";
- // Both single quotes and double quotes (for attributes)
- return s.replace( /['"<>&]/g, function( s ) {
- switch( s ) {
- case '\'':
- return ''';
- case '"':
- return '"';
- case '<':
- return '<';
- case '>':
- return '>';
- case '&':
- return '&';
- }
- });
-}
-
-function synchronize( callback, last ) {
- config.queue.push( callback );
-
- if ( config.autorun && !config.blocking ) {
- process( last );
- }
-}
-
-function process( last ) {
- function next() {
- process( last );
- }
- var start = new Date().getTime();
- config.depth = config.depth ? config.depth + 1 : 1;
-
- while ( config.queue.length && !config.blocking ) {
- if ( !defined.setTimeout || config.updateRate <= 0 || ( ( new Date().getTime() - start ) < config.updateRate ) ) {
- config.queue.shift()();
- } else {
- window.setTimeout( next, 13 );
- break;
- }
- }
- config.depth--;
- if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) {
- done();
- }
-}
-
-function saveGlobal() {
- config.pollution = [];
-
- if ( config.noglobals ) {
- for ( var key in window ) {
- // in Opera sometimes DOM element ids show up here, ignore them
- if ( !hasOwn.call( window, key ) || /^qunit-test-output/.test( key ) ) {
- continue;
- }
- config.pollution.push( key );
- }
- }
-}
-
-function checkPollution() {
- var newGlobals,
- deletedGlobals,
- old = config.pollution;
-
- saveGlobal();
-
- newGlobals = diff( config.pollution, old );
- if ( newGlobals.length > 0 ) {
- QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join(", ") );
- }
-
- deletedGlobals = diff( old, config.pollution );
- if ( deletedGlobals.length > 0 ) {
- QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join(", ") );
- }
-}
-
-// returns a new Array with the elements that are in a but not in b
-function diff( a, b ) {
- var i, j,
- result = a.slice();
-
- for ( i = 0; i < result.length; i++ ) {
- for ( j = 0; j < b.length; j++ ) {
- if ( result[i] === b[j] ) {
- result.splice( i, 1 );
- i--;
- break;
- }
- }
- }
- return result;
-}
-
-function extend( a, b ) {
- for ( var prop in b ) {
- if ( b[ prop ] === undefined ) {
- delete a[ prop ];
-
- // Avoid "Member not found" error in IE8 caused by setting window.constructor
- } else if ( prop !== "constructor" || a !== window ) {
- a[ prop ] = b[ prop ];
- }
- }
-
- return a;
-}
-
-/**
- * @param {HTMLElement} elem
- * @param {string} type
- * @param {Function} fn
- */
-function addEvent( elem, type, fn ) {
- // Standards-based browsers
- if ( elem.addEventListener ) {
- elem.addEventListener( type, fn, false );
- // IE
- } else {
- elem.attachEvent( "on" + type, fn );
- }
-}
-
-/**
- * @param {Array|NodeList} elems
- * @param {string} type
- * @param {Function} fn
- */
-function addEvents( elems, type, fn ) {
- var i = elems.length;
- while ( i-- ) {
- addEvent( elems[i], type, fn );
- }
-}
-
-function hasClass( elem, name ) {
- return (" " + elem.className + " ").indexOf(" " + name + " ") > -1;
-}
-
-function addClass( elem, name ) {
- if ( !hasClass( elem, name ) ) {
- elem.className += (elem.className ? " " : "") + name;
- }
-}
-
-function removeClass( elem, name ) {
- var set = " " + elem.className + " ";
- // Class name may appear multiple times
- while ( set.indexOf(" " + name + " ") > -1 ) {
- set = set.replace(" " + name + " " , " ");
- }
- // If possible, trim it for prettiness, but not neccecarily
- elem.className = window.jQuery ? jQuery.trim( set ) : ( set.trim ? set.trim() : set );
-}
-
-function id( name ) {
- return !!( typeof document !== "undefined" && document && document.getElementById ) &&
- document.getElementById( name );
-}
-
-function registerLoggingCallback( key ) {
- return function( callback ) {
- config[key].push( callback );
- };
-}
-
-// Supports deprecated method of completely overwriting logging callbacks
-function runLoggingCallbacks( key, scope, args ) {
- var i, callbacks;
- if ( QUnit.hasOwnProperty( key ) ) {
- QUnit[ key ].call(scope, args );
- } else {
- callbacks = config[ key ];
- for ( i = 0; i < callbacks.length; i++ ) {
- callbacks[ i ].call( scope, args );
- }
- }
-}
-
-// Test for equality any JavaScript type.
-// Author: Philippe Rathé
-QUnit.equiv = (function() {
-
- // Call the o related callback with the given arguments.
- function bindCallbacks( o, callbacks, args ) {
- var prop = QUnit.objectType( o );
- if ( prop ) {
- if ( QUnit.objectType( callbacks[ prop ] ) === "function" ) {
- return callbacks[ prop ].apply( callbacks, args );
- } else {
- return callbacks[ prop ]; // or undefined
- }
- }
- }
-
- // the real equiv function
- var innerEquiv,
- // stack to decide between skip/abort functions
- callers = [],
- // stack to avoiding loops from circular referencing
- parents = [],
-
- getProto = Object.getPrototypeOf || function ( obj ) {
- return obj.__proto__;
- },
- callbacks = (function () {
-
- // for string, boolean, number and null
- function useStrictEquality( b, a ) {
- /*jshint eqeqeq:false */
- if ( b instanceof a.constructor || a instanceof b.constructor ) {
- // to catch short annotaion VS 'new' annotation of a
- // declaration
- // e.g. var i = 1;
- // var j = new Number(1);
- return a == b;
- } else {
- return a === b;
- }
- }
-
- return {
- "string": useStrictEquality,
- "boolean": useStrictEquality,
- "number": useStrictEquality,
- "null": useStrictEquality,
- "undefined": useStrictEquality,
-
- "nan": function( b ) {
- return isNaN( b );
- },
-
- "date": function( b, a ) {
- return QUnit.objectType( b ) === "date" && a.valueOf() === b.valueOf();
- },
-
- "regexp": function( b, a ) {
- return QUnit.objectType( b ) === "regexp" &&
- // the regex itself
- a.source === b.source &&
- // and its modifers
- a.global === b.global &&
- // (gmi) ...
- a.ignoreCase === b.ignoreCase &&
- a.multiline === b.multiline &&
- a.sticky === b.sticky;
- },
-
- // - skip when the property is a method of an instance (OOP)
- // - abort otherwise,
- // initial === would have catch identical references anyway
- "function": function() {
- var caller = callers[callers.length - 1];
- return caller !== Object && typeof caller !== "undefined";
- },
-
- "array": function( b, a ) {
- var i, j, len, loop;
-
- // b could be an object literal here
- if ( QUnit.objectType( b ) !== "array" ) {
- return false;
- }
-
- len = a.length;
- if ( len !== b.length ) {
- // safe and faster
- return false;
- }
-
- // track reference to avoid circular references
- parents.push( a );
- for ( i = 0; i < len; i++ ) {
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- loop = true;// dont rewalk array
- }
- }
- if ( !loop && !innerEquiv(a[i], b[i]) ) {
- parents.pop();
- return false;
- }
- }
- parents.pop();
- return true;
- },
-
- "object": function( b, a ) {
- var i, j, loop,
- // Default to true
- eq = true,
- aProperties = [],
- bProperties = [];
-
- // comparing constructors is more strict than using
- // instanceof
- if ( a.constructor !== b.constructor ) {
- // Allow objects with no prototype to be equivalent to
- // objects with Object as their constructor.
- if ( !(( getProto(a) === null && getProto(b) === Object.prototype ) ||
- ( getProto(b) === null && getProto(a) === Object.prototype ) ) ) {
- return false;
- }
- }
-
- // stack constructor before traversing properties
- callers.push( a.constructor );
- // track reference to avoid circular references
- parents.push( a );
-
- for ( i in a ) { // be strict: don't ensures hasOwnProperty
- // and go deep
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- // don't go down the same path twice
- loop = true;
- }
- }
- aProperties.push(i); // collect a's properties
-
- if (!loop && !innerEquiv( a[i], b[i] ) ) {
- eq = false;
- break;
- }
- }
-
- callers.pop(); // unstack, we are done
- parents.pop();
-
- for ( i in b ) {
- bProperties.push( i ); // collect b's properties
- }
-
- // Ensures identical properties name
- return eq && innerEquiv( aProperties.sort(), bProperties.sort() );
- }
- };
- }());
-
- innerEquiv = function() { // can take multiple arguments
- var args = [].slice.apply( arguments );
- if ( args.length < 2 ) {
- return true; // end transition
- }
-
- return (function( a, b ) {
- if ( a === b ) {
- return true; // catch the most you can
- } else if ( a === null || b === null || typeof a === "undefined" ||
- typeof b === "undefined" ||
- QUnit.objectType(a) !== QUnit.objectType(b) ) {
- return false; // don't lose time with error prone cases
- } else {
- return bindCallbacks(a, callbacks, [ b, a ]);
- }
-
- // apply transition with (1..n) arguments
- }( args[0], args[1] ) && arguments.callee.apply( this, args.splice(1, args.length - 1 )) );
- };
-
- return innerEquiv;
-}());
-
-/**
- * jsDump Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com |
- * http://flesler.blogspot.com Licensed under BSD
- * (http://www.opensource.org/licenses/bsd-license.php) Date: 5/15/2008
- *
- * @projectDescription Advanced and extensible data dumping for Javascript.
- * @version 1.0.0
- * @author Ariel Flesler
- * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html}
- */
-QUnit.jsDump = (function() {
- function quote( str ) {
- return '"' + str.toString().replace( /"/g, '\\"' ) + '"';
- }
- function literal( o ) {
- return o + "";
- }
- function join( pre, arr, post ) {
- var s = jsDump.separator(),
- base = jsDump.indent(),
- inner = jsDump.indent(1);
- if ( arr.join ) {
- arr = arr.join( "," + s + inner );
- }
- if ( !arr ) {
- return pre + post;
- }
- return [ pre, inner + arr, base + post ].join(s);
- }
- function array( arr, stack ) {
- var i = arr.length, ret = new Array(i);
- this.up();
- while ( i-- ) {
- ret[i] = this.parse( arr[i] , undefined , stack);
- }
- this.down();
- return join( "[", ret, "]" );
- }
-
- var reName = /^function (\w+)/,
- jsDump = {
- // type is used mostly internally, you can fix a (custom)type in advance
- parse: function( obj, type, stack ) {
- stack = stack || [ ];
- var inStack, res,
- parser = this.parsers[ type || this.typeOf(obj) ];
-
- type = typeof parser;
- inStack = inArray( obj, stack );
-
- if ( inStack !== -1 ) {
- return "recursion(" + (inStack - stack.length) + ")";
- }
- if ( type === "function" ) {
- stack.push( obj );
- res = parser.call( this, obj, stack );
- stack.pop();
- return res;
- }
- return ( type === "string" ) ? parser : this.parsers.error;
- },
- typeOf: function( obj ) {
- var type;
- if ( obj === null ) {
- type = "null";
- } else if ( typeof obj === "undefined" ) {
- type = "undefined";
- } else if ( QUnit.is( "regexp", obj) ) {
- type = "regexp";
- } else if ( QUnit.is( "date", obj) ) {
- type = "date";
- } else if ( QUnit.is( "function", obj) ) {
- type = "function";
- } else if ( typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined" ) {
- type = "window";
- } else if ( obj.nodeType === 9 ) {
- type = "document";
- } else if ( obj.nodeType ) {
- type = "node";
- } else if (
- // native arrays
- toString.call( obj ) === "[object Array]" ||
- // NodeList objects
- ( typeof obj.length === "number" && typeof obj.item !== "undefined" && ( obj.length ? obj.item(0) === obj[0] : ( obj.item( 0 ) === null && typeof obj[0] === "undefined" ) ) )
- ) {
- type = "array";
- } else if ( obj.constructor === Error.prototype.constructor ) {
- type = "error";
- } else {
- type = typeof obj;
- }
- return type;
- },
- separator: function() {
- return this.multiline ? this.HTML ? "
" : "\n" : this.HTML ? " " : " ";
- },
- // extra can be a number, shortcut for increasing-calling-decreasing
- indent: function( extra ) {
- if ( !this.multiline ) {
- return "";
- }
- var chr = this.indentChar;
- if ( this.HTML ) {
- chr = chr.replace( /\t/g, " " ).replace( / /g, " " );
- }
- return new Array( this._depth_ + (extra||0) ).join(chr);
- },
- up: function( a ) {
- this._depth_ += a || 1;
- },
- down: function( a ) {
- this._depth_ -= a || 1;
- },
- setParser: function( name, parser ) {
- this.parsers[name] = parser;
- },
- // The next 3 are exposed so you can use them
- quote: quote,
- literal: literal,
- join: join,
- //
- _depth_: 1,
- // This is the list of parsers, to modify them, use jsDump.setParser
- parsers: {
- window: "[Window]",
- document: "[Document]",
- error: function(error) {
- return "Error(\"" + error.message + "\")";
- },
- unknown: "[Unknown]",
- "null": "null",
- "undefined": "undefined",
- "function": function( fn ) {
- var ret = "function",
- // functions never have name in IE
- name = "name" in fn ? fn.name : (reName.exec(fn) || [])[1];
-
- if ( name ) {
- ret += " " + name;
- }
- ret += "( ";
-
- ret = [ ret, QUnit.jsDump.parse( fn, "functionArgs" ), "){" ].join( "" );
- return join( ret, QUnit.jsDump.parse(fn,"functionCode" ), "}" );
- },
- array: array,
- nodelist: array,
- "arguments": array,
- object: function( map, stack ) {
- var ret = [ ], keys, key, val, i;
- QUnit.jsDump.up();
- keys = [];
- for ( key in map ) {
- keys.push( key );
- }
- keys.sort();
- for ( i = 0; i < keys.length; i++ ) {
- key = keys[ i ];
- val = map[ key ];
- ret.push( QUnit.jsDump.parse( key, "key" ) + ": " + QUnit.jsDump.parse( val, undefined, stack ) );
- }
- QUnit.jsDump.down();
- return join( "{", ret, "}" );
- },
- node: function( node ) {
- var len, i, val,
- open = QUnit.jsDump.HTML ? "<" : "<",
- close = QUnit.jsDump.HTML ? ">" : ">",
- tag = node.nodeName.toLowerCase(),
- ret = open + tag,
- attrs = node.attributes;
-
- if ( attrs ) {
- for ( i = 0, len = attrs.length; i < len; i++ ) {
- val = attrs[i].nodeValue;
- // IE6 includes all attributes in .attributes, even ones not explicitly set.
- // Those have values like undefined, null, 0, false, "" or "inherit".
- if ( val && val !== "inherit" ) {
- ret += " " + attrs[i].nodeName + "=" + QUnit.jsDump.parse( val, "attribute" );
- }
- }
- }
- ret += close;
-
- // Show content of TextNode or CDATASection
- if ( node.nodeType === 3 || node.nodeType === 4 ) {
- ret += node.nodeValue;
- }
-
- return ret + open + "/" + tag + close;
- },
- // function calls it internally, it's the arguments part of the function
- functionArgs: function( fn ) {
- var args,
- l = fn.length;
-
- if ( !l ) {
- return "";
- }
-
- args = new Array(l);
- while ( l-- ) {
- // 97 is 'a'
- args[l] = String.fromCharCode(97+l);
- }
- return " " + args.join( ", " ) + " ";
- },
- // object calls it internally, the key part of an item in a map
- key: quote,
- // function calls it internally, it's the content of the function
- functionCode: "[code]",
- // node calls it internally, it's an html attribute value
- attribute: quote,
- string: quote,
- date: quote,
- regexp: literal,
- number: literal,
- "boolean": literal
- },
- // if true, entities are escaped ( <, >, \t, space and \n )
- HTML: false,
- // indentation unit
- indentChar: " ",
- // if true, items in a collection, are separated by a \n, else just a space.
- multiline: true
- };
-
- return jsDump;
-}());
-
-// from jquery.js
-function inArray( elem, array ) {
- if ( array.indexOf ) {
- return array.indexOf( elem );
- }
-
- for ( var i = 0, length = array.length; i < length; i++ ) {
- if ( array[ i ] === elem ) {
- return i;
- }
- }
-
- return -1;
-}
-
-/*
- * Javascript Diff Algorithm
- * By John Resig (http://ejohn.org/)
- * Modified by Chu Alan "sprite"
- *
- * Released under the MIT license.
- *
- * More Info:
- * http://ejohn.org/projects/javascript-diff-algorithm/
- *
- * Usage: QUnit.diff(expected, actual)
- *
- * QUnit.diff( "the quick brown fox jumped over", "the quick fox jumps over" ) == "the quick brown fox jumped jumps over"
- */
-QUnit.diff = (function() {
- /*jshint eqeqeq:false, eqnull:true */
- function diff( o, n ) {
- var i,
- ns = {},
- os = {};
-
- for ( i = 0; i < n.length; i++ ) {
- if ( !hasOwn.call( ns, n[i] ) ) {
- ns[ n[i] ] = {
- rows: [],
- o: null
- };
- }
- ns[ n[i] ].rows.push( i );
- }
-
- for ( i = 0; i < o.length; i++ ) {
- if ( !hasOwn.call( os, o[i] ) ) {
- os[ o[i] ] = {
- rows: [],
- n: null
- };
- }
- os[ o[i] ].rows.push( i );
- }
-
- for ( i in ns ) {
- if ( !hasOwn.call( ns, i ) ) {
- continue;
- }
- if ( ns[i].rows.length === 1 && hasOwn.call( os, i ) && os[i].rows.length === 1 ) {
- n[ ns[i].rows[0] ] = {
- text: n[ ns[i].rows[0] ],
- row: os[i].rows[0]
- };
- o[ os[i].rows[0] ] = {
- text: o[ os[i].rows[0] ],
- row: ns[i].rows[0]
- };
- }
- }
-
- for ( i = 0; i < n.length - 1; i++ ) {
- if ( n[i].text != null && n[ i + 1 ].text == null && n[i].row + 1 < o.length && o[ n[i].row + 1 ].text == null &&
- n[ i + 1 ] == o[ n[i].row + 1 ] ) {
-
- n[ i + 1 ] = {
- text: n[ i + 1 ],
- row: n[i].row + 1
- };
- o[ n[i].row + 1 ] = {
- text: o[ n[i].row + 1 ],
- row: i + 1
- };
- }
- }
-
- for ( i = n.length - 1; i > 0; i-- ) {
- if ( n[i].text != null && n[ i - 1 ].text == null && n[i].row > 0 && o[ n[i].row - 1 ].text == null &&
- n[ i - 1 ] == o[ n[i].row - 1 ]) {
-
- n[ i - 1 ] = {
- text: n[ i - 1 ],
- row: n[i].row - 1
- };
- o[ n[i].row - 1 ] = {
- text: o[ n[i].row - 1 ],
- row: i - 1
- };
- }
- }
-
- return {
- o: o,
- n: n
- };
- }
-
- return function( o, n ) {
- o = o.replace( /\s+$/, "" );
- n = n.replace( /\s+$/, "" );
-
- var i, pre,
- str = "",
- out = diff( o === "" ? [] : o.split(/\s+/), n === "" ? [] : n.split(/\s+/) ),
- oSpace = o.match(/\s+/g),
- nSpace = n.match(/\s+/g);
-
- if ( oSpace == null ) {
- oSpace = [ " " ];
- }
- else {
- oSpace.push( " " );
- }
-
- if ( nSpace == null ) {
- nSpace = [ " " ];
- }
- else {
- nSpace.push( " " );
- }
-
- if ( out.n.length === 0 ) {
- for ( i = 0; i < out.o.length; i++ ) {
- str += "" + out.o[i] + oSpace[i] + "";
- }
- }
- else {
- if ( out.n[0].text == null ) {
- for ( n = 0; n < out.o.length && out.o[n].text == null; n++ ) {
- str += "" + out.o[n] + oSpace[n] + "";
- }
- }
-
- for ( i = 0; i < out.n.length; i++ ) {
- if (out.n[i].text == null) {
- str += "" + out.n[i] + nSpace[i] + "";
- }
- else {
- // `pre` initialized at top of scope
- pre = "";
-
- for ( n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++ ) {
- pre += "" + out.o[n] + oSpace[n] + "";
- }
- str += " " + out.n[i].text + nSpace[i] + pre;
- }
- }
- }
-
- return str;
- };
-}());
-
-// for CommonJS enviroments, export everything
-if ( typeof exports !== "undefined" ) {
- extend( exports, QUnit );
-}
-
-// get at whatever the global object is, like window in browsers
-}( (function() {return this;}.call()) ));
diff --git a/test/lib/require.js b/test/lib/require.js
deleted file mode 100644
index 987f865..0000000
--- a/test/lib/require.js
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- RequireJS 2.1.5 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.
- Available via the MIT or new BSD license.
- see: http://github.com/jrburke/requirejs for details
-*/
-var requirejs,require,define;
-(function(aa){function I(b){return"[object Function]"===L.call(b)}function J(b){return"[object Array]"===L.call(b)}function y(b,c){if(b){var d;for(d=0;dthis.depCount&&!this.defined){if(I(n)){if(this.events.error)try{e=i.execCb(c,n,b,e)}catch(d){a=d}else e=i.execCb(c,n,b,e);this.map.isDefine&&((b=this.module)&&void 0!==b.exports&&b.exports!==this.exports?e=b.exports:void 0===e&&this.usingExports&&(e=this.exports));if(a)return a.requireMap=this.map,a.requireModules=[this.map.id],a.requireType="define",v(this.error=
-a)}else e=n;this.exports=e;if(this.map.isDefine&&!this.ignore&&(q[c]=e,l.onResourceLoad))l.onResourceLoad(i,this.map,this.depMaps);x(c);this.defined=!0}this.defining=!1;this.defined&&!this.defineEmitted&&(this.defineEmitted=!0,this.emit("defined",this.exports),this.defineEmitComplete=!0)}}else this.fetch()}},callPlugin:function(){var a=this.map,b=a.id,d=j(a.prefix);this.depMaps.push(d);t(d,"defined",u(this,function(e){var n,d;d=this.map.name;var g=this.map.parentMap?this.map.parentMap.name:null,h=
-i.makeRequire(a.parentMap,{enableBuildCallback:!0});if(this.map.unnormalized){if(e.normalize&&(d=e.normalize(d,function(a){return c(a,g,!0)})||""),e=j(a.prefix+"!"+d,this.map.parentMap),t(e,"defined",u(this,function(a){this.init([],function(){return a},null,{enabled:!0,ignore:!0})})),d=m(p,e.id)){this.depMaps.push(e);if(this.events.error)d.on("error",u(this,function(a){this.emit("error",a)}));d.enable()}}else n=u(this,function(a){this.init([],function(){return a},null,{enabled:!0})}),n.error=u(this,
-function(a){this.inited=!0;this.error=a;a.requireModules=[b];G(p,function(a){0===a.map.id.indexOf(b+"_unnormalized")&&x(a.map.id)});v(a)}),n.fromText=u(this,function(e,c){var d=a.name,g=j(d),C=O;c&&(e=c);C&&(O=!1);r(g);s(k.config,b)&&(k.config[d]=k.config[b]);try{l.exec(e)}catch(ca){return v(B("fromtexteval","fromText eval for "+b+" failed: "+ca,ca,[b]))}C&&(O=!0);this.depMaps.push(g);i.completeLoad(d);h([d],n)}),e.load(a.name,h,n,k)}));i.enable(d,this);this.pluginMaps[d.id]=d},enable:function(){V[this.map.id]=
-this;this.enabling=this.enabled=!0;y(this.depMaps,u(this,function(a,b){var c,e;if("string"===typeof a){a=j(a,this.map.isDefine?this.map:this.map.parentMap,!1,!this.skipMap);this.depMaps[b]=a;if(c=m(N,a.id)){this.depExports[b]=c(this);return}this.depCount+=1;t(a,"defined",u(this,function(a){this.defineDep(b,a);this.check()}));this.errback&&t(a,"error",this.errback)}c=a.id;e=p[c];!s(N,c)&&(e&&!e.enabled)&&i.enable(a,this)}));G(this.pluginMaps,u(this,function(a){var b=m(p,a.id);b&&!b.enabled&&i.enable(a,
-this)}));this.enabling=!1;this.check()},on:function(a,b){var c=this.events[a];c||(c=this.events[a]=[]);c.push(b)},emit:function(a,b){y(this.events[a],function(a){a(b)});"error"===a&&delete this.events[a]}};i={config:k,contextName:b,registry:p,defined:q,urlFetched:U,defQueue:H,Module:Z,makeModuleMap:j,nextTick:l.nextTick,onError:v,configure:function(a){a.baseUrl&&"/"!==a.baseUrl.charAt(a.baseUrl.length-1)&&(a.baseUrl+="/");var b=k.pkgs,c=k.shim,e={paths:!0,config:!0,map:!0};G(a,function(a,b){e[b]?
-"map"===b?(k.map||(k.map={}),R(k[b],a,!0,!0)):R(k[b],a,!0):k[b]=a});a.shim&&(G(a.shim,function(a,b){J(a)&&(a={deps:a});if((a.exports||a.init)&&!a.exportsFn)a.exportsFn=i.makeShimExports(a);c[b]=a}),k.shim=c);a.packages&&(y(a.packages,function(a){a="string"===typeof a?{name:a}:a;b[a.name]={name:a.name,location:a.location||a.name,main:(a.main||"main").replace(ja,"").replace(ea,"")}}),k.pkgs=b);G(p,function(a,b){!a.inited&&!a.map.unnormalized&&(a.map=j(b))});if(a.deps||a.callback)i.require(a.deps||[],
-a.callback)},makeShimExports:function(a){return function(){var b;a.init&&(b=a.init.apply(aa,arguments));return b||a.exports&&ba(a.exports)}},makeRequire:function(a,f){function d(e,c,h){var g,k;f.enableBuildCallback&&(c&&I(c))&&(c.__requireJsBuild=!0);if("string"===typeof e){if(I(c))return v(B("requireargs","Invalid require call"),h);if(a&&s(N,e))return N[e](p[a.id]);if(l.get)return l.get(i,e,a,d);g=j(e,a,!1,!0);g=g.id;return!s(q,g)?v(B("notloaded",'Module name "'+g+'" has not been loaded yet for context: '+
-b+(a?"":". Use require([])"))):q[g]}L();i.nextTick(function(){L();k=r(j(null,a));k.skipMap=f.skipMap;k.init(e,c,h,{enabled:!0});D()});return d}f=f||{};R(d,{isBrowser:A,toUrl:function(b){var d,f=b.lastIndexOf("."),g=b.split("/")[0];if(-1!==f&&(!("."===g||".."===g)||1h.attachEvent.toString().indexOf("[native code"))&&!Y?(O=!0,h.attachEvent("onreadystatechange",b.onScriptLoad)):(h.addEventListener("load",b.onScriptLoad,!1),h.addEventListener("error",b.onScriptError,!1)),h.src=d,K=h,D?x.insertBefore(h,D):x.appendChild(h),K=null,h;if(da)try{importScripts(d),b.completeLoad(c)}catch(j){b.onError(B("importscripts","importScripts failed for "+c+" at "+d,j,[c]))}};A&&M(document.getElementsByTagName("script"),function(b){x||(x=
-b.parentNode);if(t=b.getAttribute("data-main"))return r.baseUrl||(E=t.split("/"),Q=E.pop(),fa=E.length?E.join("/")+"/":"./",r.baseUrl=fa,t=Q),t=t.replace(ea,""),r.deps=r.deps?r.deps.concat(t):[t],!0});define=function(b,c,d){var l,h;"string"!==typeof b&&(d=c,c=b,b=null);J(c)||(d=c,c=[]);!c.length&&I(d)&&d.length&&(d.toString().replace(la,"").replace(ma,function(b,d){c.push(d)}),c=(1===d.length?["require"]:["require","exports","module"]).concat(c));if(O){if(!(l=K))P&&"interactive"===P.readyState||M(document.getElementsByTagName("script"),
-function(b){if("interactive"===b.readyState)return P=b}),l=P;l&&(b||(b=l.getAttribute("data-requiremodule")),h=F[l.getAttribute("data-requirecontext")])}(h?h.defQueue:T).push([b,c,d])};define.amd={jQuery:!0};l.exec=function(b){return eval(b)};l(r)}})(this);
diff --git a/test/lib/resemble.js b/test/lib/resemble.js
new file mode 100644
index 0000000..1cb8c29
--- /dev/null
+++ b/test/lib/resemble.js
@@ -0,0 +1,535 @@
+/*
+Author: James Cryer
+Company: Huddle
+Last updated date: 21 Feb 2013
+URL: https://github.com/Huddle/Resemble.js
+*/
+
+(function(_this){
+ 'use strict';
+
+ _this['resemble'] = function( fileData ){
+
+ var data = {};
+ var images = [];
+ var updateCallbackArray = [];
+
+ var tolerance = { // between 0 and 255
+ red: 16,
+ green: 16,
+ blue: 16,
+ minBrightness: 16,
+ maxBrightness: 240
+ };
+
+ var ignoreAntialiasing = false;
+ var ignoreColors = false;
+
+ function triggerDataUpdate(){
+ var len = updateCallbackArray.length;
+ var i;
+ for(i=0;i tolerance.maxBrightness;
+ }
+
+ function getHue(r,g,b){
+
+ r = r / 255;
+ g = g / 255;
+ b = b / 255;
+ var max = Math.max(r, g, b), min = Math.min(r, g, b);
+ var h;
+ var d;
+
+ if (max == min){
+ h = 0; // achromatic
+ } else{
+ d = max - min;
+ switch(max){
+ case r: h = (g - b) / d + (g < b ? 6 : 0); break;
+ case g: h = (b - r) / d + 2; break;
+ case b: h = (r - g) / d + 4; break;
+ }
+ h /= 6;
+ }
+
+ return h;
+ }
+
+ function isAntialiased(sourcePix, data, cacheSet, verticalPos, horizontalPos, width){
+ var offset;
+ var targetPix;
+ var distance = 1;
+ var i;
+ var j;
+ var hasHighContrastSibling = 0;
+ var hasSiblingWithDifferentHue = 0;
+ var hasEquivilantSibling = 0;
+
+ addHueInfo(sourcePix);
+
+ for (i = distance*-1; i <= distance; i++){
+ for (j = distance*-1; j <= distance; j++){
+
+ if(i===0 && j===0){
+ // ignore source pixel
+ } else {
+
+ offset = ((verticalPos+j)*width + (horizontalPos+i)) * 4;
+ targetPix = getPixelInfo(data, offset, cacheSet);
+
+ if(targetPix === null){
+ continue;
+ }
+
+ addBrightnessInfo(targetPix);
+ addHueInfo(targetPix);
+
+ if( isContrasting(sourcePix, targetPix) ){
+ hasHighContrastSibling++;
+ }
+
+ if( isRGBSame(sourcePix,targetPix) ){
+ hasEquivilantSibling++;
+ }
+
+ if( Math.abs(targetPix.h - sourcePix.h) > 0.3 ){
+ hasSiblingWithDifferentHue++;
+ }
+
+ if( hasSiblingWithDifferentHue > 1 || hasHighContrastSibling > 1){
+ return true;
+ }
+ }
+ }
+ }
+
+ if(hasEquivilantSibling < 2){
+ return true;
+ }
+
+ return false;
+ }
+
+ function errorPixel(px, offset){
+ px[offset] = 255; //r
+ px[offset + 1] = 0; //g
+ px[offset + 2] = 255; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyPixel(px, offset, data){
+ px[offset] = data.r; //r
+ px[offset + 1] = data.g; //g
+ px[offset + 2] = data.b; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyGrayScalePixel(px, offset, data){
+ px[offset] = data.brightness; //r
+ px[offset + 1] = data.brightness; //g
+ px[offset + 2] = data.brightness; //b
+ px[offset + 3] = 255; //a
+ }
+
+
+ function getPixelInfo(data, offset, cacheSet){
+ var r;
+ var g;
+ var b;
+ var d;
+
+ if(typeof data[offset] !== 'undefined'){
+ r = data[offset];
+ g = data[offset+1];
+ b = data[offset+2];
+ d = {
+ r: r,
+ g: g,
+ b: b
+ };
+
+ return d;
+ } else {
+ return null;
+ }
+ }
+
+ function addBrightnessInfo(data){
+ data.brightness = getBrightness(data.r,data.g,data.b); // 'corrected' lightness
+ }
+
+ function addHueInfo(data){
+ data.h = getHue(data.r,data.g,data.b);
+ }
+
+ function analyseImages(img1, img2, width, height){
+
+ var hiddenCanvas = document.createElement('canvas');
+
+ var data1 = img1.data;
+ var data2 = img2.data;
+
+ hiddenCanvas.width = width;
+ hiddenCanvas.height = height;
+
+ var context = hiddenCanvas.getContext('2d');
+ var imgd = context.createImageData(width,height);
+ var targetPix = imgd.data;
+
+ var mismatchCount = 0;
+
+ var time = Date.now();
+
+ var skip;
+
+ if( (width > 1200 || height > 1200) && ignoreAntialiasing){
+ skip = 6;
+ }
+
+ loop(height, width, function(verticalPos, horizontalPos){
+
+ if(skip){ // only skip if the image isn't small
+ if(verticalPos % skip === 0 || horizontalPos % skip === 0){
+ return;
+ }
+ }
+
+ var offset = (verticalPos*width + horizontalPos) * 4;
+ var pixel1 = getPixelInfo(data1, offset, 1);
+ var pixel2 = getPixelInfo(data2, offset, 2);
+
+ if(pixel1 === null || pixel2 === null){
+ return;
+ }
+
+ if (ignoreColors){
+
+ addBrightnessInfo(pixel1);
+ addBrightnessInfo(pixel2);
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ return;
+ }
+
+ if( isRGBSimilar(pixel1, pixel2) ){
+ copyPixel(targetPix, offset, pixel2);
+
+ } else if( ignoreAntialiasing && (
+ addBrightnessInfo(pixel1), // jit pixel info augmentation looks a little weird, sorry.
+ addBrightnessInfo(pixel2),
+ isAntialiased(pixel1, data1, 1, verticalPos, horizontalPos, width) ||
+ isAntialiased(pixel2, data2, 2, verticalPos, horizontalPos, width)
+ )){
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+
+ });
+
+ data.misMatchPercentage = (mismatchCount / (height*width) * 100).toFixed(2);
+ data.analysisTime = Date.now() - time;
+
+ data.getImageDataUrl = function(text){
+ var barHeight = 0;
+
+ if(text){
+ barHeight = addLabel(text,context,hiddenCanvas);
+ }
+
+ context.putImageData(imgd, 0, barHeight);
+
+ return hiddenCanvas.toDataURL("image/png");
+ };
+ }
+
+ function addLabel(text, context, hiddenCanvas){
+ var textPadding = 2;
+
+ context.font = '12px sans-serif';
+
+ var textWidth = context.measureText(text).width + textPadding*2;
+ var barHeight = 22;
+
+ if(textWidth > hiddenCanvas.width){
+ hiddenCanvas.width = textWidth;
+ }
+
+ hiddenCanvas.height += barHeight;
+
+ context.fillStyle = "#666";
+ context.fillRect(0,0,hiddenCanvas.width,barHeight -4);
+ context.fillStyle = "#fff";
+ context.fillRect(0,barHeight -4,hiddenCanvas.width, 4);
+
+ context.fillStyle = "#fff";
+ context.textBaseline = "top";
+ context.font = '12px sans-serif';
+ context.fillText(text, textPadding, 1);
+
+ return barHeight;
+ }
+
+ function normalise(img, w, h){
+ var c;
+ var context;
+
+ if(img.height < h || img.width < w){
+ c = document.createElement('canvas');
+ c.width = w;
+ c.height = h;
+ context = c.getContext('2d');
+ context.putImageData(img, 0, 0);
+ return context.getImageData(0, 0, w, h);
+ }
+
+ return img;
+ }
+
+ function compare(one, two){
+
+ function onceWeHaveBoth(){
+ var width;
+ var height;
+ if(images.length === 2){
+ width = images[0].width > images[1].width ? images[0].width : images[1].width;
+ height = images[0].height > images[1].height ? images[0].height : images[1].height;
+
+ if( (images[0].width === images[1].width) && (images[0].height === images[1].height) ){
+ data.isSameDimensions = true;
+ } else {
+ data.isSameDimensions = false;
+ }
+
+ analyseImages( normalise(images[0],width, height), normalise(images[1],width, height), width, height);
+
+ triggerDataUpdate();
+ }
+ }
+
+ images = [];
+ loadImageData(one, onceWeHaveBoth);
+ loadImageData(two, onceWeHaveBoth);
+ }
+
+ function getCompareApi(param){
+
+ var secondFileData,
+ hasMethod = typeof param === 'function';
+
+ if( !hasMethod ){
+ // assume it's file data
+ secondFileData = param;
+ }
+
+ var self = {
+ ignoreNothing: function(){
+
+ tolerance.red = 16;
+ tolerance.green = 16;
+ tolerance.blue = 16;
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreAntialiasing: function(){
+
+ tolerance.red = 32;
+ tolerance.green = 32;
+ tolerance.blue = 32;
+ tolerance.minBrightness = 64;
+ tolerance.maxBrightness = 96;
+
+ ignoreAntialiasing = true;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreColors: function(){
+
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = true;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ onComplete: function( callback ){
+
+ updateCallbackArray.push(callback);
+
+ var wrapper = function(){
+ compare(fileData, secondFileData);
+ };
+
+ wrapper();
+
+ return getCompareApi(wrapper);
+ }
+ };
+
+ return self;
+ }
+
+ return {
+ onComplete: function( callback ){
+ updateCallbackArray.push(callback);
+ loadImageData(fileData, function(imageData, width, height){
+ parseImage(imageData.data, width, height);
+ });
+ },
+ compareTo: function(secondFileData){
+ return getCompareApi(secondFileData);
+ }
+ };
+
+ };
+}(this));
\ No newline at end of file
diff --git a/test/testsuite.js b/test/testsuite.js
deleted file mode 100644
index b486acb..0000000
--- a/test/testsuite.js
+++ /dev/null
@@ -1,36 +0,0 @@
-requirejs.config({
- baseUrl: '/test/unit/'
-});
-
-define(function(require) {
- var testModules = [
- 'Pixi',
- 'Point',
- 'Rectangle',
- 'DisplayObject',
- 'DisplayObjectContainer',
- 'Sprite',
- 'MovieClip',
- 'InteractionManager',
- 'Stage',
- 'utils/Utils',
- 'utils/EventTarget',
- 'utils/Matrix',
- 'utils/Detector',
- 'renderers/WebGLShaders',
- 'renderers/WebGLRenderer',
- 'renderers/WebGLBatch',
- 'renderers/CanvasRenderer',
- 'extras/Strip',
- 'extras/Rope',
- 'textures/BaseTexture',
- 'textures/Texture',
- 'loaders/SpriteSheetLoader',
- 'loaders/AssetLoader'
- ];
-
- // Resolve all testModules and then start the Test Runner.
- require(testModules, function() {
- QUnit.start();
- });
-});
\ No newline at end of file
diff --git a/test/textures/SpriteSheet-Aliens.png b/test/textures/SpriteSheet-Aliens.png
new file mode 100644
index 0000000..210acb1
--- /dev/null
+++ b/test/textures/SpriteSheet-Aliens.png
Binary files differ
diff --git a/test/textures/SpriteSheet-Explosion.png b/test/textures/SpriteSheet-Explosion.png
new file mode 100755
index 0000000..79e1a69
--- /dev/null
+++ b/test/textures/SpriteSheet-Explosion.png
Binary files differ
diff --git a/test/textures/bunny.png b/test/textures/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/textures/bunny.png
Binary files differ
diff --git a/test/unit/DisplayObject.js b/test/unit/DisplayObject.js
deleted file mode 100644
index 5e7e72f..0000000
--- a/test/unit/DisplayObject.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObject');
-});
diff --git a/test/unit/DisplayObjectContainer.js b/test/unit/DisplayObjectContainer.js
deleted file mode 100644
index b323959..0000000
--- a/test/unit/DisplayObjectContainer.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObjectContainer');
-});
diff --git a/test/unit/InteractionManager.js b/test/unit/InteractionManager.js
deleted file mode 100644
index e751f52..0000000
--- a/test/unit/InteractionManager.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('InteractionManager');
-});
diff --git a/test/unit/MovieClip.js b/test/unit/MovieClip.js
deleted file mode 100644
index 37d9446..0000000
--- a/test/unit/MovieClip.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('MovieClip');
-});
diff --git a/test/unit/Pixi.js b/test/unit/Pixi.js
deleted file mode 100644
index 36eee73..0000000
--- a/test/unit/Pixi.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Pixi');
-});
diff --git a/test/unit/Point.js b/test/unit/Point.js
deleted file mode 100644
index 983ff6e..0000000
--- a/test/unit/Point.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Point');
-});
diff --git a/test/unit/Rectangle.js b/test/unit/Rectangle.js
deleted file mode 100644
index 3b439ba..0000000
--- a/test/unit/Rectangle.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Rectangle');
-});
diff --git a/test/unit/Sprite.js b/test/unit/Sprite.js
deleted file mode 100644
index ed4f596..0000000
--- a/test/unit/Sprite.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Sprite');
-});
diff --git a/.gitignore b/.gitignore
index 12e1b62..0b88317 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
node_modules
.DS_Store
-.project
\ No newline at end of file
+.project
+*.log
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..63e4d7c
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,8 @@
+language: node_js
+node_js:
+ - 0.10
+
+before_script:
+ - npm install -g grunt-cli
+ - export DISPLAY=:99.0
+ - sh -e /etc/init.d/xvfb start
diff --git a/Gruntfile.js b/Gruntfile.js
index b083b49..103938c 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -1,10 +1,12 @@
+'use strict';
+
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-connect');
- grunt.loadNpmTasks('grunt-contrib-qunit');
grunt.loadNpmTasks('grunt-contrib-yuidoc');
+ grunt.loadTasks('tasks');
var root = 'src/pixi/',
debug = 'bin/pixi.dev.js',
@@ -79,7 +81,7 @@
},
files: {
srcBlob: '<%= dirs.src %>/**/*.js',
- testBlob: '<%= dirs.test %>/unit/**/*.js',
+ testBlob: '<%= dirs.test %>/{functional,lib/pixi,unit}/**/*.js',
build: '<%= dirs.build %>/pixi.dev.js',
buildMin: '<%= dirs.build %>/pixi.js'
},
@@ -94,7 +96,12 @@
},
jshint: {
beforeconcat: srcFiles,
- test: ['<%= files.testBlob %>'],
+ test: {
+ src: ['<%= files.testBlob %>'],
+ options: {
+ expr: true
+ }
+ },
options: {
asi: true,
smarttabs: true
@@ -128,12 +135,6 @@
]
},
connect: {
- qunit: {
- options: {
- port: grunt.option('port-test') || 9002,
- base: './'
- }
- },
test: {
options: {
port: grunt.option('port-test') || 9002,
@@ -142,13 +143,6 @@
}
}
},
- qunit: {
- all: {
- options: {
- urls: ['http://localhost:' + (grunt.option('port-test') || 9002) + '/test/index.html']
- }
- }
- },
yuidoc: {
compile: {
name: '<%= pkg.name %>',
@@ -161,6 +155,13 @@
outdir: '<%= dirs.docs %>'
}
}
+ },
+ karma: {
+ unit: {
+ configFile: 'test/karma.conf.js',
+ // browsers: ['Chrome'],
+ singleRun: true
+ }
}
});
@@ -182,9 +183,10 @@
}
)
- grunt.registerTask('default', ['concat', 'uglify', 'distribute']);
grunt.registerTask('build', ['concat', 'uglify', 'distribute']);
- grunt.registerTask('test', ['build', 'connect:qunit', 'qunit']);
+ grunt.registerTask('test', ['concat', 'jshint:test', 'karma']);
grunt.registerTask('docs', ['yuidoc']);
-
-}
\ No newline at end of file
+ grunt.registerTask('default', ['test', 'uglify', 'distribute']);
+ // Travis CI task.
+ grunt.registerTask('travis', ['test']);
+}
diff --git a/README.md b/README.md
index c62ef86..690cfe4 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,8 @@

+[](http://travis-ci.org/drkibitz/pixi.js)
+
#### JavaScript 2D Renderer ####
The aim of this project is to provide a fast lightweight 2D library that works
diff --git a/package.json b/package.json
index b373240..1246a68 100644
--- a/package.json
+++ b/package.json
@@ -18,14 +18,21 @@
"main": "bin/pixi.js",
+ "scripts": {
+ "test": "grunt travis --verbose"
+ },
+
"dependencies": {},
"devDependencies": {
"grunt": "~0.4.x",
- "grunt-contrib-jshint": "0.3.x",
+ "grunt-contrib-jshint": "0.6.x",
"grunt-contrib-uglify": "0.2.x",
- "grunt-contrib-connect": "0.2.x",
- "grunt-contrib-qunit": "0.2.x",
+ "grunt-contrib-connect": "0.3.x",
"grunt-contrib-yuidoc": "0.4.x",
- "grunt-contrib-concat": "0.1.x"
+ "grunt-contrib-concat": "0.3.x",
+ "chai": "~1.7.0",
+ "karma": "0.11.0",
+ "karma-firefox-launcher": "0.1.0",
+ "karma-mocha": "0.1.0"
}
}
diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js
index a7c520e..ee82bbd 100644
--- a/src/pixi/InteractionManager.js
+++ b/src/pixi/InteractionManager.js
@@ -62,7 +62,6 @@
this.onTouchEnd = this.onTouchEnd.bind(this);
this.onTouchMove = this.onTouchMove.bind(this);
-
this.last = 0;
}
diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js
index 1a95d20..eef1059 100644
--- a/src/pixi/core/Ellipse.js
+++ b/src/pixi/core/Ellipse.js
@@ -78,7 +78,7 @@
return (normx + normy < 0.25);
}
-PIXI.Ellipse.getBounds = function()
+PIXI.Ellipse.prototype.getBounds = function()
{
return new PIXI.Rectangle(this.x, this.y, this.width, this.height);
}
diff --git a/tasks/karma.js b/tasks/karma.js
new file mode 100644
index 0000000..c340485
--- /dev/null
+++ b/tasks/karma.js
@@ -0,0 +1,27 @@
+'use strict';
+
+var path = require('path');
+var server = require('karma').server;
+
+module.exports = function (grunt) {
+ grunt.registerMultiTask('karma', 'run karma.', function() {
+ var done = this.async();
+ var options = this.options({
+ background: false
+ });
+ var data = this.data;
+
+ //merge options onto data, with data taking precedence
+ data = grunt.util._.merge(options, data);
+ data.configFile = path.resolve(data.configFile);
+ if (data.configFile) {
+ data.configFile = grunt.template.process(data.configFile);
+ }
+
+ server.start(
+ data,
+ function(code) {
+ done(!code);
+ });
+ });
+};
diff --git a/test/functional/example-1-basics/bunny.png b/test/functional/example-1-basics/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/functional/example-1-basics/bunny.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-30.png b/test/functional/example-1-basics/frame-30.png
new file mode 100644
index 0000000..96e3409
--- /dev/null
+++ b/test/functional/example-1-basics/frame-30.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-60.png b/test/functional/example-1-basics/frame-60.png
new file mode 100644
index 0000000..af3f4ce
--- /dev/null
+++ b/test/functional/example-1-basics/frame-60.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-90.png b/test/functional/example-1-basics/frame-90.png
new file mode 100644
index 0000000..099b823
--- /dev/null
+++ b/test/functional/example-1-basics/frame-90.png
Binary files differ
diff --git a/test/functional/example-1-basics/index.js b/test/functional/example-1-basics/index.js
new file mode 100644
index 0000000..7ae7a98
--- /dev/null
+++ b/test/functional/example-1-basics/index.js
@@ -0,0 +1,133 @@
+describe('Example 1 - Basics', function () {
+ 'use strict';
+
+ var baseUri = '/base/test/functional/example-1-basics';
+ var expect = chai.expect;
+ var currentFrame = 0;
+ var frameEvents = {};
+ var stage;
+ var renderer;
+ var bunny;
+
+ function onFrame(frame, callback) {
+ frameEvents[frame] = callback;
+ }
+
+ function animate() {
+ currentFrame += 1;
+
+ requestAnimFrame( animate );
+
+ // just for fun, lets rotate mr rabbit a little
+ bunny.rotation += 0.1;
+
+ // render the stage
+ renderer.render(stage);
+
+ if (frameEvents[currentFrame])
+ frameEvents[currentFrame](currentFrame);
+ }
+
+ function initScene() {
+ // create an new instance of a pixi stage
+ stage = new PIXI.Stage(0x66FF99);
+
+ // create a renderer instance
+ renderer = PIXI.autoDetectRenderer(400, 300);
+ console.log('Is PIXI.WebGLRenderer: ' + (renderer instanceof PIXI.WebGLRenderer));
+
+ // add the renderer view element to the DOM
+ document.body.appendChild(renderer.view);
+
+ requestAnimFrame( animate );
+
+ // create a texture from an image path
+ var texture = PIXI.Texture.fromImage(baseUri + "/bunny.png");
+ // create a new Sprite using the texture
+ bunny = new PIXI.Sprite(texture);
+
+ // center the sprites anchor point
+ bunny.anchor.x = 0.5;
+ bunny.anchor.y = 0.5;
+
+ // move the sprite t the center of the screen
+ bunny.position.x = 200;
+ bunny.position.y = 150;
+
+ stage.addChild(bunny);
+ }
+
+ it('assets loaded', function (done) {
+ var loader = new PIXI.AssetLoader([
+ baseUri + '/bunny.png',
+ baseUri + '/frame-30.png',
+ baseUri + '/frame-60.png',
+ baseUri + '/frame-90.png'
+ ]);
+ // loader.on('onProgress', function (event) {
+ // console.log(event.content);
+ // });
+ loader.on('onComplete', function (event) {
+ done();
+ initScene();
+ });
+ loader.load();
+ });
+
+ it('frame 30 should match', function (done) {
+ this.timeout(700);
+ onFrame(30, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-30.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 60 should match', function (done) {
+ this.timeout(1200);
+ onFrame(60, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-60.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 90 should match', function (done) {
+ this.timeout(1700);
+ onFrame(90, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-90.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ // it('capture something', function (done) {
+ // this.timeout(2000000);
+ // onFrame(30, function () {
+ // var img = new Image();
+ // img.src = renderer.view.toDataURL('image/png');
+ // document.body.appendChild(img);
+ // });
+ // });
+});
diff --git a/test/index.html b/test/index.html
deleted file mode 100644
index 9cbcac5..0000000
--- a/test/index.html
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
- Pixi.js Test Suite
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/test/karma.conf.js b/test/karma.conf.js
new file mode 100644
index 0000000..c66a696
--- /dev/null
+++ b/test/karma.conf.js
@@ -0,0 +1,82 @@
+module.exports = function(config) {
+ config.set({
+
+ // base path, that will be used to resolve files and exclude
+ basePath : '../',
+
+ frameworks : ['mocha'],
+
+ // list of files / patterns to load in the browser
+ files : [
+ 'node_modules/chai/chai.js',
+ 'bin/pixi.dev.js',
+ 'test/lib/**/*.js',
+ 'test/unit/**/*.js',
+ // 'test/functional/**/*.js',
+ {pattern: 'test/**/*.png', watched: false, included: false, served: true}
+ ],
+
+ // list of files to exclude
+ exclude : [],
+
+ // use dolts reporter, as travis terminal does not support escaping sequences
+ // possible values: 'dots', 'progress', 'junit', 'teamcity'
+ // CLI --reporters progress
+ reporters : ['progress'],
+
+ // web server port
+ // CLI --port 9876
+ port : 9876,
+
+ // cli runner port
+ // CLI --runner-port 9100
+ runnerPort : 9100,
+
+ // enable / disable colors in the output (reporters and logs)
+ // CLI --colors --no-colors
+ colors : true,
+
+ // level of logging
+ // possible values: karma.LOG_DISABLE || karma.LOG_ERROR || karma.LOG_WARN || karma.LOG_INFO || karma.LOG_DEBUG
+ // CLI --log-level debug
+ logLevel : config.LOG_DEBUG,
+
+ // enable / disable watching file and executing tests whenever any file changes
+ // CLI --auto-watch --no-auto-watch
+ autoWatch : false,
+
+ // Start these browsers, currently available:
+ // - Chrome
+ // - ChromeCanary
+ // - Firefox
+ // - Opera
+ // - Safari (only Mac)
+ // - PhantomJS
+ // - IE (only Windows)
+ // CLI --browsers Chrome,Firefox,Safari
+ browsers : ['Firefox'],
+
+ // If browser does not capture in given timeout [ms], kill it
+ // CLI --capture-timeout 5000
+ captureTimeout : 5000,
+
+ // Auto run tests on start (when browsers are captured) and exit
+ // CLI --single-run --no-single-run
+ singleRun : true,
+
+ // report which specs are slower than 500ms
+ // CLI --report-slower-than 500
+ reportSlowerThan : 1000,
+
+ preprocessors : {
+ // '**/client/js/*.js': 'coverage'
+ },
+
+ plugins : [
+ 'karma-mocha',
+ // 'karma-chrome-launcher',
+ 'karma-firefox-launcher',
+ // 'karma-phantomjs-launcher'
+ ]
+ });
+};
diff --git a/test/lib/pixi/core/Matrix.js b/test/lib/pixi/core/Matrix.js
new file mode 100644
index 0000000..d26386b
--- /dev/null
+++ b/test/lib/pixi/core/Matrix.js
@@ -0,0 +1,40 @@
+
+function pixi_core_Matrix_confirmNewMat3(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(1);
+ expect(matrix[5]).to.equal(0);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(1);
+}
+
+function pixi_core_Matrix_confirmNewMat4(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[0]).to.equal(1);
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(0);
+ expect(matrix[5]).to.equal(1);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(0);
+ expect(matrix[9]).to.equal(0);
+ expect(matrix[10]).to.equal(1);
+ expect(matrix[11]).to.equal(0);
+ expect(matrix[12]).to.equal(0);
+ expect(matrix[13]).to.equal(0);
+ expect(matrix[14]).to.equal(0);
+ expect(matrix[15]).to.equal(1);
+}
diff --git a/test/lib/pixi/core/Point.js b/test/lib/pixi/core/Point.js
new file mode 100644
index 0000000..e5df07b
--- /dev/null
+++ b/test/lib/pixi/core/Point.js
@@ -0,0 +1,10 @@
+
+function pixi_core_Point_confirm(obj, x, y) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Point);
+ expect(obj).to.respondTo('clone');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+}
diff --git a/test/lib/pixi/core/Rectangle.js b/test/lib/pixi/core/Rectangle.js
new file mode 100644
index 0000000..23f0d12
--- /dev/null
+++ b/test/lib/pixi/core/Rectangle.js
@@ -0,0 +1,13 @@
+
+function pixi_core_Rectangle_confirm(obj, x, y, width, height) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Rectangle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+ expect(obj).to.have.property('width', width);
+ expect(obj).to.have.property('height', height);
+}
diff --git a/test/lib/pixi/display/DisplayObject.js b/test/lib/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..1388a7f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObject.js
@@ -0,0 +1,43 @@
+
+function pixi_display_DisplayObject_confirmNew(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObject);
+ expect(obj).to.respondTo('setInteractive');
+ expect(obj).to.respondTo('addFilter');
+ expect(obj).to.respondTo('removeFilter');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.property('last', obj);
+ expect(obj).to.have.property('first', obj);
+
+ expect(obj).to.contain.property('position');
+ pixi_core_Point_confirm(obj.position, 0, 0);
+ expect(obj).to.contain.property('scale');
+ pixi_core_Point_confirm(obj.scale, 1, 1);
+ expect(obj).to.contain.property('pivot');
+ pixi_core_Point_confirm(obj.pivot, 0, 0);
+
+ expect(obj).to.have.property('rotation', 0);
+ expect(obj).to.have.property('alpha', 1);
+ expect(obj).to.have.property('visible', true);
+ expect(obj).to.have.property('buttonMode', false);
+ expect(obj).to.have.property('parent', null);
+ expect(obj).to.have.property('worldAlpha', 1);
+
+ expect(obj).to.have.property('hitArea');
+ expect(obj).to.have.property('interactive'); // TODO: Have a better default value
+ expect('mask' in obj).to.be.true; // TODO: Have a better default value
+ expect(obj.mask).to.be.undefined;
+
+ expect(obj).to.have.property('renderable');
+ expect(obj).to.have.property('stage');
+
+ expect(obj).to.have.deep.property('worldTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ expect(obj).to.have.deep.property('localTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.localTransform);
+
+ expect(obj).to.have.deep.property('color.length', 0);
+ expect(obj).to.have.property('dynamic', true);
+}
diff --git a/test/lib/pixi/display/DisplayObjectContainer.js b/test/lib/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..085c59f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,16 @@
+
+function pixi_display_DisplayObjectContainer_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObject_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObjectContainer);
+ expect(obj).to.respondTo('addChild');
+ expect(obj).to.respondTo('addChildAt');
+ expect(obj).to.respondTo('swapChildren');
+ expect(obj).to.respondTo('getChildAt');
+ expect(obj).to.respondTo('removeChild');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('children.length', 0);
+}
diff --git a/test/lib/pixi/display/Sprite.js b/test/lib/pixi/display/Sprite.js
new file mode 100644
index 0000000..cc7a2d6
--- /dev/null
+++ b/test/lib/pixi/display/Sprite.js
@@ -0,0 +1,28 @@
+
+function pixi_display_Sprite_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Sprite);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', true);
+ expect(obj).to.have.property('stage', null);
+
+ expect(obj).to.have.property('anchor');
+ pixi_core_Point_confirm(obj.anchor, 0, 0);
+
+ expect(obj).to.have.property('blendMode', PIXI.blendModes.NORMAL);
+ expect(obj).to.have.property('width', 1); // TODO: is 1 expected
+ expect(obj).to.have.property('height', 1); // TODO: is 1 expected
+
+ // FIXME: Just make this a boolean that is always there
+ expect(!!obj.updateFrame).to.equal(obj.texture.baseTexture.hasLoaded);
+
+ expect(obj).to.have.property('texture');
+ pixi_textures_Texture_confirmNew(obj.texture, done);
+}
diff --git a/test/lib/pixi/extras/Strip.js b/test/lib/pixi/extras/Strip.js
new file mode 100644
index 0000000..8927a8a
--- /dev/null
+++ b/test/lib/pixi/extras/Strip.js
@@ -0,0 +1,12 @@
+
+function pixi_extras_Strip_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Strip);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ // TODO: Test properties
+}
diff --git a/test/lib/pixi/textures/Texture.js b/test/lib/pixi/textures/Texture.js
new file mode 100644
index 0000000..d5867b6
--- /dev/null
+++ b/test/lib/pixi/textures/Texture.js
@@ -0,0 +1,31 @@
+
+function pixi_textures_Texture_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ function confirmFrameDone() {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, obj.baseTexture.width, obj.baseTexture.height);
+
+ expect(obj).to.have.property('width', obj.baseTexture.width);
+ expect(obj).to.have.property('height', obj.baseTexture.height);
+ done();
+ }
+
+ expect(obj).to.be.an.instanceof(PIXI.Texture);
+ pixi_utils_EventTarget_like(obj);
+
+ expect(obj).to.have.property('baseTexture')
+ .and.to.be.an.instanceof(PIXI.BaseTexture);
+
+ expect(obj).to.have.property('scope', obj);
+
+ expect(obj).to.have.property('trim');
+ pixi_core_Point_confirm(obj.trim, 0, 0);
+
+ expect(obj).to.have.property('frame');
+ if (obj.baseTexture.hasLoaded) {
+ confirmFrameDone();
+ } else {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, 1, 1);
+ obj.addEventListener('update', confirmFrameDone);
+ }
+}
diff --git a/test/lib/pixi/utils/EventTarget.js b/test/lib/pixi/utils/EventTarget.js
new file mode 100644
index 0000000..7b1dcfa
--- /dev/null
+++ b/test/lib/pixi/utils/EventTarget.js
@@ -0,0 +1,8 @@
+
+function pixi_utils_EventTarget_like(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.respondTo('addEventListener');
+ expect(obj).to.respondTo('dispatchEvent');
+ expect(obj).to.respondTo('removeEventListener');
+}
diff --git a/test/lib/qunit-1.11.0.css b/test/lib/qunit-1.11.0.css
deleted file mode 100644
index d7fc0c8..0000000
--- a/test/lib/qunit-1.11.0.css
+++ /dev/null
@@ -1,244 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-/** Font Family and Sizes */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
- font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
-}
-
-#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
-#qunit-tests { font-size: smaller; }
-
-
-/** Resets */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter {
- margin: 0;
- padding: 0;
-}
-
-
-/** Header */
-
-#qunit-header {
- padding: 0.5em 0 0.5em 1em;
-
- color: #8699a4;
- background-color: #0d3349;
-
- font-size: 1.5em;
- line-height: 1em;
- font-weight: normal;
-
- border-radius: 5px 5px 0 0;
- -moz-border-radius: 5px 5px 0 0;
- -webkit-border-top-right-radius: 5px;
- -webkit-border-top-left-radius: 5px;
-}
-
-#qunit-header a {
- text-decoration: none;
- color: #c2ccd1;
-}
-
-#qunit-header a:hover,
-#qunit-header a:focus {
- color: #fff;
-}
-
-#qunit-testrunner-toolbar label {
- display: inline-block;
- padding: 0 .5em 0 .1em;
-}
-
-#qunit-banner {
- height: 5px;
-}
-
-#qunit-testrunner-toolbar {
- padding: 0.5em 0 0.5em 2em;
- color: #5E740B;
- background-color: #eee;
- overflow: hidden;
-}
-
-#qunit-userAgent {
- padding: 0.5em 0 0.5em 2.5em;
- background-color: #2b81af;
- color: #fff;
- text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
-}
-
-#qunit-modulefilter-container {
- float: right;
-}
-
-/** Tests: Pass/Fail */
-
-#qunit-tests {
- list-style-position: inside;
-}
-
-#qunit-tests li {
- padding: 0.4em 0.5em 0.4em 2.5em;
- border-bottom: 1px solid #fff;
- list-style-position: inside;
-}
-
-#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running {
- display: none;
-}
-
-#qunit-tests li strong {
- cursor: pointer;
-}
-
-#qunit-tests li a {
- padding: 0.5em;
- color: #c2ccd1;
- text-decoration: none;
-}
-#qunit-tests li a:hover,
-#qunit-tests li a:focus {
- color: #000;
-}
-
-#qunit-tests li .runtime {
- float: right;
- font-size: smaller;
-}
-
-.qunit-assert-list {
- margin-top: 0.5em;
- padding: 0.5em;
-
- background-color: #fff;
-
- border-radius: 5px;
- -moz-border-radius: 5px;
- -webkit-border-radius: 5px;
-}
-
-.qunit-collapsed {
- display: none;
-}
-
-#qunit-tests table {
- border-collapse: collapse;
- margin-top: .2em;
-}
-
-#qunit-tests th {
- text-align: right;
- vertical-align: top;
- padding: 0 .5em 0 0;
-}
-
-#qunit-tests td {
- vertical-align: top;
-}
-
-#qunit-tests pre {
- margin: 0;
- white-space: pre-wrap;
- word-wrap: break-word;
-}
-
-#qunit-tests del {
- background-color: #e0f2be;
- color: #374e0c;
- text-decoration: none;
-}
-
-#qunit-tests ins {
- background-color: #ffcaca;
- color: #500;
- text-decoration: none;
-}
-
-/*** Test Counts */
-
-#qunit-tests b.counts { color: black; }
-#qunit-tests b.passed { color: #5E740B; }
-#qunit-tests b.failed { color: #710909; }
-
-#qunit-tests li li {
- padding: 5px;
- background-color: #fff;
- border-bottom: none;
- list-style-position: inside;
-}
-
-/*** Passing Styles */
-
-#qunit-tests li li.pass {
- color: #3c510c;
- background-color: #fff;
- border-left: 10px solid #C6E746;
-}
-
-#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
-#qunit-tests .pass .test-name { color: #366097; }
-
-#qunit-tests .pass .test-actual,
-#qunit-tests .pass .test-expected { color: #999999; }
-
-#qunit-banner.qunit-pass { background-color: #C6E746; }
-
-/*** Failing Styles */
-
-#qunit-tests li li.fail {
- color: #710909;
- background-color: #fff;
- border-left: 10px solid #EE5757;
- white-space: pre;
-}
-
-#qunit-tests > li:last-child {
- border-radius: 0 0 5px 5px;
- -moz-border-radius: 0 0 5px 5px;
- -webkit-border-bottom-right-radius: 5px;
- -webkit-border-bottom-left-radius: 5px;
-}
-
-#qunit-tests .fail { color: #000000; background-color: #EE5757; }
-#qunit-tests .fail .test-name,
-#qunit-tests .fail .module-name { color: #000000; }
-
-#qunit-tests .fail .test-actual { color: #EE5757; }
-#qunit-tests .fail .test-expected { color: green; }
-
-#qunit-banner.qunit-fail { background-color: #EE5757; }
-
-
-/** Result */
-
-#qunit-testresult {
- padding: 0.5em 0.5em 0.5em 2.5em;
-
- color: #2b81af;
- background-color: #D2E0E6;
-
- border-bottom: 1px solid white;
-}
-#qunit-testresult .module-name {
- font-weight: bold;
-}
-
-/** Fixture */
-
-#qunit-fixture {
- position: absolute;
- top: -10000px;
- left: -10000px;
- width: 1000px;
- height: 1000px;
-}
diff --git a/test/lib/qunit-1.11.0.js b/test/lib/qunit-1.11.0.js
deleted file mode 100644
index 302545f..0000000
--- a/test/lib/qunit-1.11.0.js
+++ /dev/null
@@ -1,2152 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-(function( window ) {
-
-var QUnit,
- assert,
- config,
- onErrorFnPrev,
- testId = 0,
- fileName = (sourceFromStacktrace( 0 ) || "" ).replace(/(:\d+)+\)?/, "").replace(/.+\//, ""),
- toString = Object.prototype.toString,
- hasOwn = Object.prototype.hasOwnProperty,
- // Keep a local reference to Date (GH-283)
- Date = window.Date,
- defined = {
- setTimeout: typeof window.setTimeout !== "undefined",
- sessionStorage: (function() {
- var x = "qunit-test-string";
- try {
- sessionStorage.setItem( x, x );
- sessionStorage.removeItem( x );
- return true;
- } catch( e ) {
- return false;
- }
- }())
- },
- /**
- * Provides a normalized error string, correcting an issue
- * with IE 7 (and prior) where Error.prototype.toString is
- * not properly implemented
- *
- * Based on http://es5.github.com/#x15.11.4.4
- *
- * @param {String|Error} error
- * @return {String} error message
- */
- errorString = function( error ) {
- var name, message,
- errorString = error.toString();
- if ( errorString.substring( 0, 7 ) === "[object" ) {
- name = error.name ? error.name.toString() : "Error";
- message = error.message ? error.message.toString() : "";
- if ( name && message ) {
- return name + ": " + message;
- } else if ( name ) {
- return name;
- } else if ( message ) {
- return message;
- } else {
- return "Error";
- }
- } else {
- return errorString;
- }
- },
- /**
- * Makes a clone of an object using only Array or Object as base,
- * and copies over the own enumerable properties.
- *
- * @param {Object} obj
- * @return {Object} New object with only the own properties (recursively).
- */
- objectValues = function( obj ) {
- // Grunt 0.3.x uses an older version of jshint that still has jshint/jshint#392.
- /*jshint newcap: false */
- var key, val,
- vals = QUnit.is( "array", obj ) ? [] : {};
- for ( key in obj ) {
- if ( hasOwn.call( obj, key ) ) {
- val = obj[key];
- vals[key] = val === Object(val) ? objectValues(val) : val;
- }
- }
- return vals;
- };
-
-function Test( settings ) {
- extend( this, settings );
- this.assertions = [];
- this.testNumber = ++Test.count;
-}
-
-Test.count = 0;
-
-Test.prototype = {
- init: function() {
- var a, b, li,
- tests = id( "qunit-tests" );
-
- if ( tests ) {
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml;
-
- // `a` initialized at top of scope
- a = document.createElement( "a" );
- a.innerHTML = "Rerun";
- a.href = QUnit.url({ testNumber: this.testNumber });
-
- li = document.createElement( "li" );
- li.appendChild( b );
- li.appendChild( a );
- li.className = "running";
- li.id = this.id = "qunit-test-output" + testId++;
-
- tests.appendChild( li );
- }
- },
- setup: function() {
- if ( this.module !== config.previousModule ) {
- if ( config.previousModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.previousModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
- config.previousModule = this.module;
- config.moduleStats = { all: 0, bad: 0 };
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- } else if ( config.autorun ) {
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- }
-
- config.current = this;
-
- this.testEnvironment = extend({
- setup: function() {},
- teardown: function() {}
- }, this.moduleTestEnvironment );
-
- this.started = +new Date();
- runLoggingCallbacks( "testStart", QUnit, {
- name: this.testName,
- module: this.module
- });
-
- // allow utility functions to access the current test environment
- // TODO why??
- QUnit.current_testEnvironment = this.testEnvironment;
-
- if ( !config.pollution ) {
- saveGlobal();
- }
- if ( config.notrycatch ) {
- this.testEnvironment.setup.call( this.testEnvironment );
- return;
- }
- try {
- this.testEnvironment.setup.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Setup failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- },
- run: function() {
- config.current = this;
-
- var running = id( "qunit-testresult" );
-
- if ( running ) {
- running.innerHTML = "Running:
" + this.nameHtml;
- }
-
- if ( this.async ) {
- QUnit.stop();
- }
-
- this.callbackStarted = +new Date();
-
- if ( config.notrycatch ) {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- return;
- }
-
- try {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- } catch( e ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
-
- QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + " " + this.stack + ": " + ( e.message || e ), extractStacktrace( e, 0 ) );
- // else next test will carry the responsibility
- saveGlobal();
-
- // Restart the tests if they're blocking
- if ( config.blocking ) {
- QUnit.start();
- }
- }
- },
- teardown: function() {
- config.current = this;
- if ( config.notrycatch ) {
- if ( typeof this.callbackRuntime === "undefined" ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
- }
- this.testEnvironment.teardown.call( this.testEnvironment );
- return;
- } else {
- try {
- this.testEnvironment.teardown.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Teardown failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- }
- checkPollution();
- },
- finish: function() {
- config.current = this;
- if ( config.requireExpects && this.expected === null ) {
- QUnit.pushFailure( "Expected number of assertions to be defined, but expect() was not called.", this.stack );
- } else if ( this.expected !== null && this.expected !== this.assertions.length ) {
- QUnit.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack );
- } else if ( this.expected === null && !this.assertions.length ) {
- QUnit.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions.", this.stack );
- }
-
- var i, assertion, a, b, time, li, ol,
- test = this,
- good = 0,
- bad = 0,
- tests = id( "qunit-tests" );
-
- this.runtime = +new Date() - this.started;
- config.stats.all += this.assertions.length;
- config.moduleStats.all += this.assertions.length;
-
- if ( tests ) {
- ol = document.createElement( "ol" );
- ol.className = "qunit-assert-list";
-
- for ( i = 0; i < this.assertions.length; i++ ) {
- assertion = this.assertions[i];
-
- li = document.createElement( "li" );
- li.className = assertion.result ? "pass" : "fail";
- li.innerHTML = assertion.message || ( assertion.result ? "okay" : "failed" );
- ol.appendChild( li );
-
- if ( assertion.result ) {
- good++;
- } else {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
-
- // store result when possible
- if ( QUnit.config.reorder && defined.sessionStorage ) {
- if ( bad ) {
- sessionStorage.setItem( "qunit-test-" + this.module + "-" + this.testName, bad );
- } else {
- sessionStorage.removeItem( "qunit-test-" + this.module + "-" + this.testName );
- }
- }
-
- if ( bad === 0 ) {
- addClass( ol, "qunit-collapsed" );
- }
-
- // `b` initialized at top of scope
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml + " (" + bad + ", " + good + ", " + this.assertions.length + ")";
-
- addEvent(b, "click", function() {
- var next = b.parentNode.lastChild,
- collapsed = hasClass( next, "qunit-collapsed" );
- ( collapsed ? removeClass : addClass )( next, "qunit-collapsed" );
- });
-
- addEvent(b, "dblclick", function( e ) {
- var target = e && e.target ? e.target : window.event.srcElement;
- if ( target.nodeName.toLowerCase() === "span" || target.nodeName.toLowerCase() === "b" ) {
- target = target.parentNode;
- }
- if ( window.location && target.nodeName.toLowerCase() === "strong" ) {
- window.location = QUnit.url({ testNumber: test.testNumber });
- }
- });
-
- // `time` initialized at top of scope
- time = document.createElement( "span" );
- time.className = "runtime";
- time.innerHTML = this.runtime + " ms";
-
- // `li` initialized at top of scope
- li = id( this.id );
- li.className = bad ? "fail" : "pass";
- li.removeChild( li.firstChild );
- a = li.firstChild;
- li.appendChild( b );
- li.appendChild( a );
- li.appendChild( time );
- li.appendChild( ol );
-
- } else {
- for ( i = 0; i < this.assertions.length; i++ ) {
- if ( !this.assertions[i].result ) {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
- }
-
- runLoggingCallbacks( "testDone", QUnit, {
- name: this.testName,
- module: this.module,
- failed: bad,
- passed: this.assertions.length - bad,
- total: this.assertions.length,
- duration: this.runtime
- });
-
- QUnit.reset();
-
- config.current = undefined;
- },
-
- queue: function() {
- var bad,
- test = this;
-
- synchronize(function() {
- test.init();
- });
- function run() {
- // each of these can by async
- synchronize(function() {
- test.setup();
- });
- synchronize(function() {
- test.run();
- });
- synchronize(function() {
- test.teardown();
- });
- synchronize(function() {
- test.finish();
- });
- }
-
- // `bad` initialized at top of scope
- // defer when previous test run passed, if storage is available
- bad = QUnit.config.reorder && defined.sessionStorage &&
- +sessionStorage.getItem( "qunit-test-" + this.module + "-" + this.testName );
-
- if ( bad ) {
- run();
- } else {
- synchronize( run, true );
- }
- }
-};
-
-// Root QUnit object.
-// `QUnit` initialized at top of scope
-QUnit = {
-
- // call on start of module test to prepend name to all tests
- module: function( name, testEnvironment ) {
- config.currentModule = name;
- config.currentModuleTestEnvironment = testEnvironment;
- config.modules[name] = true;
- },
-
- asyncTest: function( testName, expected, callback ) {
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- QUnit.test( testName, expected, callback, true );
- },
-
- test: function( testName, expected, callback, async ) {
- var test,
- nameHtml = "" + escapeText( testName ) + "";
-
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- if ( config.currentModule ) {
- nameHtml = "" + escapeText( config.currentModule ) + ": " + nameHtml;
- }
-
- test = new Test({
- nameHtml: nameHtml,
- testName: testName,
- expected: expected,
- async: async,
- callback: callback,
- module: config.currentModule,
- moduleTestEnvironment: config.currentModuleTestEnvironment,
- stack: sourceFromStacktrace( 2 )
- });
-
- if ( !validTest( test ) ) {
- return;
- }
-
- test.queue();
- },
-
- // Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through.
- expect: function( asserts ) {
- if (arguments.length === 1) {
- config.current.expected = asserts;
- } else {
- return config.current.expected;
- }
- },
-
- start: function( count ) {
- // QUnit hasn't been initialized yet.
- // Note: RequireJS (et al) may delay onLoad
- if ( config.semaphore === undefined ) {
- QUnit.begin(function() {
- // This is triggered at the top of QUnit.load, push start() to the event loop, to allow QUnit.load to finish first
- setTimeout(function() {
- QUnit.start( count );
- });
- });
- return;
- }
-
- config.semaphore -= count || 1;
- // don't start until equal number of stop-calls
- if ( config.semaphore > 0 ) {
- return;
- }
- // ignore if start is called more often then stop
- if ( config.semaphore < 0 ) {
- config.semaphore = 0;
- QUnit.pushFailure( "Called start() while already started (QUnit.config.semaphore was 0 already)", null, sourceFromStacktrace(2) );
- return;
- }
- // A slight delay, to avoid any current callbacks
- if ( defined.setTimeout ) {
- window.setTimeout(function() {
- if ( config.semaphore > 0 ) {
- return;
- }
- if ( config.timeout ) {
- clearTimeout( config.timeout );
- }
-
- config.blocking = false;
- process( true );
- }, 13);
- } else {
- config.blocking = false;
- process( true );
- }
- },
-
- stop: function( count ) {
- config.semaphore += count || 1;
- config.blocking = true;
-
- if ( config.testTimeout && defined.setTimeout ) {
- clearTimeout( config.timeout );
- config.timeout = window.setTimeout(function() {
- QUnit.ok( false, "Test timed out" );
- config.semaphore = 1;
- QUnit.start();
- }, config.testTimeout );
- }
- }
-};
-
-// `assert` initialized at top of scope
-// Asssert helpers
-// All of these must either call QUnit.push() or manually do:
-// - runLoggingCallbacks( "log", .. );
-// - config.current.assertions.push({ .. });
-// We attach it to the QUnit object *after* we expose the public API,
-// otherwise `assert` will become a global variable in browsers (#341).
-assert = {
- /**
- * Asserts rough true-ish result.
- * @name ok
- * @function
- * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" );
- */
- ok: function( result, msg ) {
- if ( !config.current ) {
- throw new Error( "ok() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
- result = !!result;
-
- var source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: msg
- };
-
- msg = escapeText( msg || (result ? "okay" : "failed" ) );
- msg = "" + msg + "";
-
- if ( !result ) {
- source = sourceFromStacktrace( 2 );
- if ( source ) {
- details.source = source;
- msg += "Source: | " + escapeText( source ) + " |
---|
";
- }
- }
- runLoggingCallbacks( "log", QUnit, details );
- config.current.assertions.push({
- result: result,
- message: msg
- });
- },
-
- /**
- * Assert that the first two arguments are equal, with an optional message.
- * Prints out both actual and expected values.
- * @name equal
- * @function
- * @example equal( format( "Received {0} bytes.", 2), "Received 2 bytes.", "format() replaces {0} with next argument" );
- */
- equal: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected == actual, actual, expected, message );
- },
-
- /**
- * @name notEqual
- * @function
- */
- notEqual: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected != actual, actual, expected, message );
- },
-
- /**
- * @name propEqual
- * @function
- */
- propEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notPropEqual
- * @function
- */
- notPropEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name deepEqual
- * @function
- */
- deepEqual: function( actual, expected, message ) {
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notDeepEqual
- * @function
- */
- notDeepEqual: function( actual, expected, message ) {
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name strictEqual
- * @function
- */
- strictEqual: function( actual, expected, message ) {
- QUnit.push( expected === actual, actual, expected, message );
- },
-
- /**
- * @name notStrictEqual
- * @function
- */
- notStrictEqual: function( actual, expected, message ) {
- QUnit.push( expected !== actual, actual, expected, message );
- },
-
- "throws": function( block, expected, message ) {
- var actual,
- expectedOutput = expected,
- ok = false;
-
- // 'expected' is optional
- if ( typeof expected === "string" ) {
- message = expected;
- expected = null;
- }
-
- config.current.ignoreGlobalErrors = true;
- try {
- block.call( config.current.testEnvironment );
- } catch (e) {
- actual = e;
- }
- config.current.ignoreGlobalErrors = false;
-
- if ( actual ) {
- // we don't want to validate thrown error
- if ( !expected ) {
- ok = true;
- expectedOutput = null;
- // expected is a regexp
- } else if ( QUnit.objectType( expected ) === "regexp" ) {
- ok = expected.test( errorString( actual ) );
- // expected is a constructor
- } else if ( actual instanceof expected ) {
- ok = true;
- // expected is a validation function which returns true is validation passed
- } else if ( expected.call( {}, actual ) === true ) {
- expectedOutput = null;
- ok = true;
- }
-
- QUnit.push( ok, actual, expectedOutput, message );
- } else {
- QUnit.pushFailure( message, null, 'No exception was thrown.' );
- }
- }
-};
-
-/**
- * @deprecate since 1.8.0
- * Kept assertion helpers in root for backwards compatibility.
- */
-extend( QUnit, assert );
-
-/**
- * @deprecated since 1.9.0
- * Kept root "raises()" for backwards compatibility.
- * (Note that we don't introduce assert.raises).
- */
-QUnit.raises = assert[ "throws" ];
-
-/**
- * @deprecated since 1.0.0, replaced with error pushes since 1.3.0
- * Kept to avoid TypeErrors for undefined methods.
- */
-QUnit.equals = function() {
- QUnit.push( false, false, false, "QUnit.equals has been deprecated since 2009 (e88049a0), use QUnit.equal instead" );
-};
-QUnit.same = function() {
- QUnit.push( false, false, false, "QUnit.same has been deprecated since 2009 (e88049a0), use QUnit.deepEqual instead" );
-};
-
-// We want access to the constructor's prototype
-(function() {
- function F() {}
- F.prototype = QUnit;
- QUnit = new F();
- // Make F QUnit's constructor so that we can add to the prototype later
- QUnit.constructor = F;
-}());
-
-/**
- * Config object: Maintain internal state
- * Later exposed as QUnit.config
- * `config` initialized at top of scope
- */
-config = {
- // The queue of tests to run
- queue: [],
-
- // block until document ready
- blocking: true,
-
- // when enabled, show only failing tests
- // gets persisted through sessionStorage and can be changed in UI via checkbox
- hidepassed: false,
-
- // by default, run previously failed tests first
- // very useful in combination with "Hide passed tests" checked
- reorder: true,
-
- // by default, modify document.title when suite is done
- altertitle: true,
-
- // when enabled, all tests must call expect()
- requireExpects: false,
-
- // add checkboxes that are persisted in the query-string
- // when enabled, the id is set to `true` as a `QUnit.config` property
- urlConfig: [
- {
- id: "noglobals",
- label: "Check for Globals",
- tooltip: "Enabling this will test if any test introduces new properties on the `window` object. Stored as query-strings."
- },
- {
- id: "notrycatch",
- label: "No try-catch",
- tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging exceptions in IE reasonable. Stored as query-strings."
- }
- ],
-
- // Set of all modules.
- modules: {},
-
- // logging callback queues
- begin: [],
- done: [],
- log: [],
- testStart: [],
- testDone: [],
- moduleStart: [],
- moduleDone: []
-};
-
-// Export global variables, unless an 'exports' object exists,
-// in that case we assume we're in CommonJS (dealt with on the bottom of the script)
-if ( typeof exports === "undefined" ) {
- extend( window, QUnit );
-
- // Expose QUnit object
- window.QUnit = QUnit;
-}
-
-// Initialize more QUnit.config and QUnit.urlParams
-(function() {
- var i,
- location = window.location || { search: "", protocol: "file:" },
- params = location.search.slice( 1 ).split( "&" ),
- length = params.length,
- urlParams = {},
- current;
-
- if ( params[ 0 ] ) {
- for ( i = 0; i < length; i++ ) {
- current = params[ i ].split( "=" );
- current[ 0 ] = decodeURIComponent( current[ 0 ] );
- // allow just a key to turn on a flag, e.g., test.html?noglobals
- current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true;
- urlParams[ current[ 0 ] ] = current[ 1 ];
- }
- }
-
- QUnit.urlParams = urlParams;
-
- // String search anywhere in moduleName+testName
- config.filter = urlParams.filter;
-
- // Exact match of the module name
- config.module = urlParams.module;
-
- config.testNumber = parseInt( urlParams.testNumber, 10 ) || null;
-
- // Figure out if we're running the tests from a server or not
- QUnit.isLocal = location.protocol === "file:";
-}());
-
-// Extend QUnit object,
-// these after set here because they should not be exposed as global functions
-extend( QUnit, {
- assert: assert,
-
- config: config,
-
- // Initialize the configuration options
- init: function() {
- extend( config, {
- stats: { all: 0, bad: 0 },
- moduleStats: { all: 0, bad: 0 },
- started: +new Date(),
- updateRate: 1000,
- blocking: false,
- autostart: true,
- autorun: false,
- filter: "",
- queue: [],
- semaphore: 1
- });
-
- var tests, banner, result,
- qunit = id( "qunit" );
-
- if ( qunit ) {
- qunit.innerHTML =
- "" +
- "" +
- "" +
- "" +
- "
";
- }
-
- tests = id( "qunit-tests" );
- banner = id( "qunit-banner" );
- result = id( "qunit-testresult" );
-
- if ( tests ) {
- tests.innerHTML = "";
- }
-
- if ( banner ) {
- banner.className = "";
- }
-
- if ( result ) {
- result.parentNode.removeChild( result );
- }
-
- if ( tests ) {
- result = document.createElement( "p" );
- result.id = "qunit-testresult";
- result.className = "result";
- tests.parentNode.insertBefore( result, tests );
- result.innerHTML = "Running...
";
- }
- },
-
- // Resets the test setup. Useful for tests that modify the DOM.
- reset: function() {
- var fixture = id( "qunit-fixture" );
- if ( fixture ) {
- fixture.innerHTML = config.fixture;
- }
- },
-
- // Trigger an event on an element.
- // @example triggerEvent( document.body, "click" );
- triggerEvent: function( elem, type, event ) {
- if ( document.createEvent ) {
- event = document.createEvent( "MouseEvents" );
- event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView,
- 0, 0, 0, 0, 0, false, false, false, false, 0, null);
-
- elem.dispatchEvent( event );
- } else if ( elem.fireEvent ) {
- elem.fireEvent( "on" + type );
- }
- },
-
- // Safe object type checking
- is: function( type, obj ) {
- return QUnit.objectType( obj ) === type;
- },
-
- objectType: function( obj ) {
- if ( typeof obj === "undefined" ) {
- return "undefined";
- // consider: typeof null === object
- }
- if ( obj === null ) {
- return "null";
- }
-
- var match = toString.call( obj ).match(/^\[object\s(.*)\]$/),
- type = match && match[1] || "";
-
- switch ( type ) {
- case "Number":
- if ( isNaN(obj) ) {
- return "nan";
- }
- return "number";
- case "String":
- case "Boolean":
- case "Array":
- case "Date":
- case "RegExp":
- case "Function":
- return type.toLowerCase();
- }
- if ( typeof obj === "object" ) {
- return "object";
- }
- return undefined;
- },
-
- push: function( result, actual, expected, message ) {
- if ( !config.current ) {
- throw new Error( "assertion outside test context, was " + sourceFromStacktrace() );
- }
-
- var output, source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: message,
- actual: actual,
- expected: expected
- };
-
- message = escapeText( message ) || ( result ? "okay" : "failed" );
- message = "" + message + "";
- output = message;
-
- if ( !result ) {
- expected = escapeText( QUnit.jsDump.parse(expected) );
- actual = escapeText( QUnit.jsDump.parse(actual) );
- output += "Expected: | " + expected + " |
";
-
- if ( actual !== expected ) {
- output += "Result: | " + actual + " |
";
- output += "Diff: | " + QUnit.diff( expected, actual ) + " |
";
- }
-
- source = sourceFromStacktrace();
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
- }
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: !!result,
- message: output
- });
- },
-
- pushFailure: function( message, source, actual ) {
- if ( !config.current ) {
- throw new Error( "pushFailure() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
-
- var output,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: false,
- message: message
- };
-
- message = escapeText( message ) || "error";
- message = "" + message + "";
- output = message;
-
- output += "";
-
- if ( actual ) {
- output += "Result: | " + escapeText( actual ) + " |
";
- }
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: false,
- message: output
- });
- },
-
- url: function( params ) {
- params = extend( extend( {}, QUnit.urlParams ), params );
- var key,
- querystring = "?";
-
- for ( key in params ) {
- if ( !hasOwn.call( params, key ) ) {
- continue;
- }
- querystring += encodeURIComponent( key ) + "=" +
- encodeURIComponent( params[ key ] ) + "&";
- }
- return window.location.protocol + "//" + window.location.host +
- window.location.pathname + querystring.slice( 0, -1 );
- },
-
- extend: extend,
- id: id,
- addEvent: addEvent
- // load, equiv, jsDump, diff: Attached later
-});
-
-/**
- * @deprecated: Created for backwards compatibility with test runner that set the hook function
- * into QUnit.{hook}, instead of invoking it and passing the hook function.
- * QUnit.constructor is set to the empty F() above so that we can add to it's prototype here.
- * Doing this allows us to tell if the following methods have been overwritten on the actual
- * QUnit object.
- */
-extend( QUnit.constructor.prototype, {
-
- // Logging callbacks; all receive a single argument with the listed properties
- // run test/logs.html for any related changes
- begin: registerLoggingCallback( "begin" ),
-
- // done: { failed, passed, total, runtime }
- done: registerLoggingCallback( "done" ),
-
- // log: { result, actual, expected, message }
- log: registerLoggingCallback( "log" ),
-
- // testStart: { name }
- testStart: registerLoggingCallback( "testStart" ),
-
- // testDone: { name, failed, passed, total, duration }
- testDone: registerLoggingCallback( "testDone" ),
-
- // moduleStart: { name }
- moduleStart: registerLoggingCallback( "moduleStart" ),
-
- // moduleDone: { name, failed, passed, total }
- moduleDone: registerLoggingCallback( "moduleDone" )
-});
-
-if ( typeof document === "undefined" || document.readyState === "complete" ) {
- config.autorun = true;
-}
-
-QUnit.load = function() {
- runLoggingCallbacks( "begin", QUnit, {} );
-
- // Initialize the config, saving the execution queue
- var banner, filter, i, label, len, main, ol, toolbar, userAgent, val,
- urlConfigCheckboxesContainer, urlConfigCheckboxes, moduleFilter,
- numModules = 0,
- moduleFilterHtml = "",
- urlConfigHtml = "",
- oldconfig = extend( {}, config );
-
- QUnit.init();
- extend(config, oldconfig);
-
- config.blocking = false;
-
- len = config.urlConfig.length;
-
- for ( i = 0; i < len; i++ ) {
- val = config.urlConfig[i];
- if ( typeof val === "string" ) {
- val = {
- id: val,
- label: val,
- tooltip: "[no tooltip available]"
- };
- }
- config[ val.id ] = QUnit.urlParams[ val.id ];
- urlConfigHtml += "";
- }
-
- moduleFilterHtml += "";
-
- // `userAgent` initialized at top of scope
- userAgent = id( "qunit-userAgent" );
- if ( userAgent ) {
- userAgent.innerHTML = navigator.userAgent;
- }
-
- // `banner` initialized at top of scope
- banner = id( "qunit-header" );
- if ( banner ) {
- banner.innerHTML = "" + banner.innerHTML + " ";
- }
-
- // `toolbar` initialized at top of scope
- toolbar = id( "qunit-testrunner-toolbar" );
- if ( toolbar ) {
- // `filter` initialized at top of scope
- filter = document.createElement( "input" );
- filter.type = "checkbox";
- filter.id = "qunit-filter-pass";
-
- addEvent( filter, "click", function() {
- var tmp,
- ol = document.getElementById( "qunit-tests" );
-
- if ( filter.checked ) {
- ol.className = ol.className + " hidepass";
- } else {
- tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " ";
- ol.className = tmp.replace( / hidepass /, " " );
- }
- if ( defined.sessionStorage ) {
- if (filter.checked) {
- sessionStorage.setItem( "qunit-filter-passed-tests", "true" );
- } else {
- sessionStorage.removeItem( "qunit-filter-passed-tests" );
- }
- }
- });
-
- if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem( "qunit-filter-passed-tests" ) ) {
- filter.checked = true;
- // `ol` initialized at top of scope
- ol = document.getElementById( "qunit-tests" );
- ol.className = ol.className + " hidepass";
- }
- toolbar.appendChild( filter );
-
- // `label` initialized at top of scope
- label = document.createElement( "label" );
- label.setAttribute( "for", "qunit-filter-pass" );
- label.setAttribute( "title", "Only show tests and assertons that fail. Stored in sessionStorage." );
- label.innerHTML = "Hide passed tests";
- toolbar.appendChild( label );
-
- urlConfigCheckboxesContainer = document.createElement("span");
- urlConfigCheckboxesContainer.innerHTML = urlConfigHtml;
- urlConfigCheckboxes = urlConfigCheckboxesContainer.getElementsByTagName("input");
- // For oldIE support:
- // * Add handlers to the individual elements instead of the container
- // * Use "click" instead of "change"
- // * Fallback from event.target to event.srcElement
- addEvents( urlConfigCheckboxes, "click", function( event ) {
- var params = {},
- target = event.target || event.srcElement;
- params[ target.name ] = target.checked ? true : undefined;
- window.location = QUnit.url( params );
- });
- toolbar.appendChild( urlConfigCheckboxesContainer );
-
- if (numModules > 1) {
- moduleFilter = document.createElement( 'span' );
- moduleFilter.setAttribute( 'id', 'qunit-modulefilter-container' );
- moduleFilter.innerHTML = moduleFilterHtml;
- addEvent( moduleFilter.lastChild, "change", function() {
- var selectBox = moduleFilter.getElementsByTagName("select")[0],
- selectedModule = decodeURIComponent(selectBox.options[selectBox.selectedIndex].value);
-
- window.location = QUnit.url( { module: ( selectedModule === "" ) ? undefined : selectedModule } );
- });
- toolbar.appendChild(moduleFilter);
- }
- }
-
- // `main` initialized at top of scope
- main = id( "qunit-fixture" );
- if ( main ) {
- config.fixture = main.innerHTML;
- }
-
- if ( config.autostart ) {
- QUnit.start();
- }
-};
-
-addEvent( window, "load", QUnit.load );
-
-// `onErrorFnPrev` initialized at top of scope
-// Preserve other handlers
-onErrorFnPrev = window.onerror;
-
-// Cover uncaught exceptions
-// Returning true will surpress the default browser handler,
-// returning false will let it run.
-window.onerror = function ( error, filePath, linerNr ) {
- var ret = false;
- if ( onErrorFnPrev ) {
- ret = onErrorFnPrev( error, filePath, linerNr );
- }
-
- // Treat return value as window.onerror itself does,
- // Only do our handling if not surpressed.
- if ( ret !== true ) {
- if ( QUnit.config.current ) {
- if ( QUnit.config.current.ignoreGlobalErrors ) {
- return true;
- }
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- } else {
- QUnit.test( "global failure", extend( function() {
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- }, { validTest: validTest } ) );
- }
- return false;
- }
-
- return ret;
-};
-
-function done() {
- config.autorun = true;
-
- // Log the last module results
- if ( config.currentModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.currentModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
-
- var i, key,
- banner = id( "qunit-banner" ),
- tests = id( "qunit-tests" ),
- runtime = +new Date() - config.started,
- passed = config.stats.all - config.stats.bad,
- html = [
- "Tests completed in ",
- runtime,
- " milliseconds.
",
- "",
- passed,
- " assertions of ",
- config.stats.all,
- " passed, ",
- config.stats.bad,
- " failed."
- ].join( "" );
-
- if ( banner ) {
- banner.className = ( config.stats.bad ? "qunit-fail" : "qunit-pass" );
- }
-
- if ( tests ) {
- id( "qunit-testresult" ).innerHTML = html;
- }
-
- if ( config.altertitle && typeof document !== "undefined" && document.title ) {
- // show ✖ for good, ✔ for bad suite result in title
- // use escape sequences in case file gets loaded with non-utf-8-charset
- document.title = [
- ( config.stats.bad ? "\u2716" : "\u2714" ),
- document.title.replace( /^[\u2714\u2716] /i, "" )
- ].join( " " );
- }
-
- // clear own sessionStorage items if all tests passed
- if ( config.reorder && defined.sessionStorage && config.stats.bad === 0 ) {
- // `key` & `i` initialized at top of scope
- for ( i = 0; i < sessionStorage.length; i++ ) {
- key = sessionStorage.key( i++ );
- if ( key.indexOf( "qunit-test-" ) === 0 ) {
- sessionStorage.removeItem( key );
- }
- }
- }
-
- // scroll back to top to show results
- if ( window.scrollTo ) {
- window.scrollTo(0, 0);
- }
-
- runLoggingCallbacks( "done", QUnit, {
- failed: config.stats.bad,
- passed: passed,
- total: config.stats.all,
- runtime: runtime
- });
-}
-
-/** @return Boolean: true if this test should be ran */
-function validTest( test ) {
- var include,
- filter = config.filter && config.filter.toLowerCase(),
- module = config.module && config.module.toLowerCase(),
- fullName = (test.module + ": " + test.testName).toLowerCase();
-
- // Internally-generated tests are always valid
- if ( test.callback && test.callback.validTest === validTest ) {
- delete test.callback.validTest;
- return true;
- }
-
- if ( config.testNumber ) {
- return test.testNumber === config.testNumber;
- }
-
- if ( module && ( !test.module || test.module.toLowerCase() !== module ) ) {
- return false;
- }
-
- if ( !filter ) {
- return true;
- }
-
- include = filter.charAt( 0 ) !== "!";
- if ( !include ) {
- filter = filter.slice( 1 );
- }
-
- // If the filter matches, we need to honour include
- if ( fullName.indexOf( filter ) !== -1 ) {
- return include;
- }
-
- // Otherwise, do the opposite
- return !include;
-}
-
-// so far supports only Firefox, Chrome and Opera (buggy), Safari (for real exceptions)
-// Later Safari and IE10 are supposed to support error.stack as well
-// See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack
-function extractStacktrace( e, offset ) {
- offset = offset === undefined ? 3 : offset;
-
- var stack, include, i;
-
- if ( e.stacktrace ) {
- // Opera
- return e.stacktrace.split( "\n" )[ offset + 3 ];
- } else if ( e.stack ) {
- // Firefox, Chrome
- stack = e.stack.split( "\n" );
- if (/^error$/i.test( stack[0] ) ) {
- stack.shift();
- }
- if ( fileName ) {
- include = [];
- for ( i = offset; i < stack.length; i++ ) {
- if ( stack[ i ].indexOf( fileName ) !== -1 ) {
- break;
- }
- include.push( stack[ i ] );
- }
- if ( include.length ) {
- return include.join( "\n" );
- }
- }
- return stack[ offset ];
- } else if ( e.sourceURL ) {
- // Safari, PhantomJS
- // hopefully one day Safari provides actual stacktraces
- // exclude useless self-reference for generated Error objects
- if ( /qunit.js$/.test( e.sourceURL ) ) {
- return;
- }
- // for actual exceptions, this is useful
- return e.sourceURL + ":" + e.line;
- }
-}
-function sourceFromStacktrace( offset ) {
- try {
- throw new Error();
- } catch ( e ) {
- return extractStacktrace( e, offset );
- }
-}
-
-/**
- * Escape text for attribute or text content.
- */
-function escapeText( s ) {
- if ( !s ) {
- return "";
- }
- s = s + "";
- // Both single quotes and double quotes (for attributes)
- return s.replace( /['"<>&]/g, function( s ) {
- switch( s ) {
- case '\'':
- return ''';
- case '"':
- return '"';
- case '<':
- return '<';
- case '>':
- return '>';
- case '&':
- return '&';
- }
- });
-}
-
-function synchronize( callback, last ) {
- config.queue.push( callback );
-
- if ( config.autorun && !config.blocking ) {
- process( last );
- }
-}
-
-function process( last ) {
- function next() {
- process( last );
- }
- var start = new Date().getTime();
- config.depth = config.depth ? config.depth + 1 : 1;
-
- while ( config.queue.length && !config.blocking ) {
- if ( !defined.setTimeout || config.updateRate <= 0 || ( ( new Date().getTime() - start ) < config.updateRate ) ) {
- config.queue.shift()();
- } else {
- window.setTimeout( next, 13 );
- break;
- }
- }
- config.depth--;
- if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) {
- done();
- }
-}
-
-function saveGlobal() {
- config.pollution = [];
-
- if ( config.noglobals ) {
- for ( var key in window ) {
- // in Opera sometimes DOM element ids show up here, ignore them
- if ( !hasOwn.call( window, key ) || /^qunit-test-output/.test( key ) ) {
- continue;
- }
- config.pollution.push( key );
- }
- }
-}
-
-function checkPollution() {
- var newGlobals,
- deletedGlobals,
- old = config.pollution;
-
- saveGlobal();
-
- newGlobals = diff( config.pollution, old );
- if ( newGlobals.length > 0 ) {
- QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join(", ") );
- }
-
- deletedGlobals = diff( old, config.pollution );
- if ( deletedGlobals.length > 0 ) {
- QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join(", ") );
- }
-}
-
-// returns a new Array with the elements that are in a but not in b
-function diff( a, b ) {
- var i, j,
- result = a.slice();
-
- for ( i = 0; i < result.length; i++ ) {
- for ( j = 0; j < b.length; j++ ) {
- if ( result[i] === b[j] ) {
- result.splice( i, 1 );
- i--;
- break;
- }
- }
- }
- return result;
-}
-
-function extend( a, b ) {
- for ( var prop in b ) {
- if ( b[ prop ] === undefined ) {
- delete a[ prop ];
-
- // Avoid "Member not found" error in IE8 caused by setting window.constructor
- } else if ( prop !== "constructor" || a !== window ) {
- a[ prop ] = b[ prop ];
- }
- }
-
- return a;
-}
-
-/**
- * @param {HTMLElement} elem
- * @param {string} type
- * @param {Function} fn
- */
-function addEvent( elem, type, fn ) {
- // Standards-based browsers
- if ( elem.addEventListener ) {
- elem.addEventListener( type, fn, false );
- // IE
- } else {
- elem.attachEvent( "on" + type, fn );
- }
-}
-
-/**
- * @param {Array|NodeList} elems
- * @param {string} type
- * @param {Function} fn
- */
-function addEvents( elems, type, fn ) {
- var i = elems.length;
- while ( i-- ) {
- addEvent( elems[i], type, fn );
- }
-}
-
-function hasClass( elem, name ) {
- return (" " + elem.className + " ").indexOf(" " + name + " ") > -1;
-}
-
-function addClass( elem, name ) {
- if ( !hasClass( elem, name ) ) {
- elem.className += (elem.className ? " " : "") + name;
- }
-}
-
-function removeClass( elem, name ) {
- var set = " " + elem.className + " ";
- // Class name may appear multiple times
- while ( set.indexOf(" " + name + " ") > -1 ) {
- set = set.replace(" " + name + " " , " ");
- }
- // If possible, trim it for prettiness, but not neccecarily
- elem.className = window.jQuery ? jQuery.trim( set ) : ( set.trim ? set.trim() : set );
-}
-
-function id( name ) {
- return !!( typeof document !== "undefined" && document && document.getElementById ) &&
- document.getElementById( name );
-}
-
-function registerLoggingCallback( key ) {
- return function( callback ) {
- config[key].push( callback );
- };
-}
-
-// Supports deprecated method of completely overwriting logging callbacks
-function runLoggingCallbacks( key, scope, args ) {
- var i, callbacks;
- if ( QUnit.hasOwnProperty( key ) ) {
- QUnit[ key ].call(scope, args );
- } else {
- callbacks = config[ key ];
- for ( i = 0; i < callbacks.length; i++ ) {
- callbacks[ i ].call( scope, args );
- }
- }
-}
-
-// Test for equality any JavaScript type.
-// Author: Philippe Rathé
-QUnit.equiv = (function() {
-
- // Call the o related callback with the given arguments.
- function bindCallbacks( o, callbacks, args ) {
- var prop = QUnit.objectType( o );
- if ( prop ) {
- if ( QUnit.objectType( callbacks[ prop ] ) === "function" ) {
- return callbacks[ prop ].apply( callbacks, args );
- } else {
- return callbacks[ prop ]; // or undefined
- }
- }
- }
-
- // the real equiv function
- var innerEquiv,
- // stack to decide between skip/abort functions
- callers = [],
- // stack to avoiding loops from circular referencing
- parents = [],
-
- getProto = Object.getPrototypeOf || function ( obj ) {
- return obj.__proto__;
- },
- callbacks = (function () {
-
- // for string, boolean, number and null
- function useStrictEquality( b, a ) {
- /*jshint eqeqeq:false */
- if ( b instanceof a.constructor || a instanceof b.constructor ) {
- // to catch short annotaion VS 'new' annotation of a
- // declaration
- // e.g. var i = 1;
- // var j = new Number(1);
- return a == b;
- } else {
- return a === b;
- }
- }
-
- return {
- "string": useStrictEquality,
- "boolean": useStrictEquality,
- "number": useStrictEquality,
- "null": useStrictEquality,
- "undefined": useStrictEquality,
-
- "nan": function( b ) {
- return isNaN( b );
- },
-
- "date": function( b, a ) {
- return QUnit.objectType( b ) === "date" && a.valueOf() === b.valueOf();
- },
-
- "regexp": function( b, a ) {
- return QUnit.objectType( b ) === "regexp" &&
- // the regex itself
- a.source === b.source &&
- // and its modifers
- a.global === b.global &&
- // (gmi) ...
- a.ignoreCase === b.ignoreCase &&
- a.multiline === b.multiline &&
- a.sticky === b.sticky;
- },
-
- // - skip when the property is a method of an instance (OOP)
- // - abort otherwise,
- // initial === would have catch identical references anyway
- "function": function() {
- var caller = callers[callers.length - 1];
- return caller !== Object && typeof caller !== "undefined";
- },
-
- "array": function( b, a ) {
- var i, j, len, loop;
-
- // b could be an object literal here
- if ( QUnit.objectType( b ) !== "array" ) {
- return false;
- }
-
- len = a.length;
- if ( len !== b.length ) {
- // safe and faster
- return false;
- }
-
- // track reference to avoid circular references
- parents.push( a );
- for ( i = 0; i < len; i++ ) {
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- loop = true;// dont rewalk array
- }
- }
- if ( !loop && !innerEquiv(a[i], b[i]) ) {
- parents.pop();
- return false;
- }
- }
- parents.pop();
- return true;
- },
-
- "object": function( b, a ) {
- var i, j, loop,
- // Default to true
- eq = true,
- aProperties = [],
- bProperties = [];
-
- // comparing constructors is more strict than using
- // instanceof
- if ( a.constructor !== b.constructor ) {
- // Allow objects with no prototype to be equivalent to
- // objects with Object as their constructor.
- if ( !(( getProto(a) === null && getProto(b) === Object.prototype ) ||
- ( getProto(b) === null && getProto(a) === Object.prototype ) ) ) {
- return false;
- }
- }
-
- // stack constructor before traversing properties
- callers.push( a.constructor );
- // track reference to avoid circular references
- parents.push( a );
-
- for ( i in a ) { // be strict: don't ensures hasOwnProperty
- // and go deep
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- // don't go down the same path twice
- loop = true;
- }
- }
- aProperties.push(i); // collect a's properties
-
- if (!loop && !innerEquiv( a[i], b[i] ) ) {
- eq = false;
- break;
- }
- }
-
- callers.pop(); // unstack, we are done
- parents.pop();
-
- for ( i in b ) {
- bProperties.push( i ); // collect b's properties
- }
-
- // Ensures identical properties name
- return eq && innerEquiv( aProperties.sort(), bProperties.sort() );
- }
- };
- }());
-
- innerEquiv = function() { // can take multiple arguments
- var args = [].slice.apply( arguments );
- if ( args.length < 2 ) {
- return true; // end transition
- }
-
- return (function( a, b ) {
- if ( a === b ) {
- return true; // catch the most you can
- } else if ( a === null || b === null || typeof a === "undefined" ||
- typeof b === "undefined" ||
- QUnit.objectType(a) !== QUnit.objectType(b) ) {
- return false; // don't lose time with error prone cases
- } else {
- return bindCallbacks(a, callbacks, [ b, a ]);
- }
-
- // apply transition with (1..n) arguments
- }( args[0], args[1] ) && arguments.callee.apply( this, args.splice(1, args.length - 1 )) );
- };
-
- return innerEquiv;
-}());
-
-/**
- * jsDump Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com |
- * http://flesler.blogspot.com Licensed under BSD
- * (http://www.opensource.org/licenses/bsd-license.php) Date: 5/15/2008
- *
- * @projectDescription Advanced and extensible data dumping for Javascript.
- * @version 1.0.0
- * @author Ariel Flesler
- * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html}
- */
-QUnit.jsDump = (function() {
- function quote( str ) {
- return '"' + str.toString().replace( /"/g, '\\"' ) + '"';
- }
- function literal( o ) {
- return o + "";
- }
- function join( pre, arr, post ) {
- var s = jsDump.separator(),
- base = jsDump.indent(),
- inner = jsDump.indent(1);
- if ( arr.join ) {
- arr = arr.join( "," + s + inner );
- }
- if ( !arr ) {
- return pre + post;
- }
- return [ pre, inner + arr, base + post ].join(s);
- }
- function array( arr, stack ) {
- var i = arr.length, ret = new Array(i);
- this.up();
- while ( i-- ) {
- ret[i] = this.parse( arr[i] , undefined , stack);
- }
- this.down();
- return join( "[", ret, "]" );
- }
-
- var reName = /^function (\w+)/,
- jsDump = {
- // type is used mostly internally, you can fix a (custom)type in advance
- parse: function( obj, type, stack ) {
- stack = stack || [ ];
- var inStack, res,
- parser = this.parsers[ type || this.typeOf(obj) ];
-
- type = typeof parser;
- inStack = inArray( obj, stack );
-
- if ( inStack !== -1 ) {
- return "recursion(" + (inStack - stack.length) + ")";
- }
- if ( type === "function" ) {
- stack.push( obj );
- res = parser.call( this, obj, stack );
- stack.pop();
- return res;
- }
- return ( type === "string" ) ? parser : this.parsers.error;
- },
- typeOf: function( obj ) {
- var type;
- if ( obj === null ) {
- type = "null";
- } else if ( typeof obj === "undefined" ) {
- type = "undefined";
- } else if ( QUnit.is( "regexp", obj) ) {
- type = "regexp";
- } else if ( QUnit.is( "date", obj) ) {
- type = "date";
- } else if ( QUnit.is( "function", obj) ) {
- type = "function";
- } else if ( typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined" ) {
- type = "window";
- } else if ( obj.nodeType === 9 ) {
- type = "document";
- } else if ( obj.nodeType ) {
- type = "node";
- } else if (
- // native arrays
- toString.call( obj ) === "[object Array]" ||
- // NodeList objects
- ( typeof obj.length === "number" && typeof obj.item !== "undefined" && ( obj.length ? obj.item(0) === obj[0] : ( obj.item( 0 ) === null && typeof obj[0] === "undefined" ) ) )
- ) {
- type = "array";
- } else if ( obj.constructor === Error.prototype.constructor ) {
- type = "error";
- } else {
- type = typeof obj;
- }
- return type;
- },
- separator: function() {
- return this.multiline ? this.HTML ? "
" : "\n" : this.HTML ? " " : " ";
- },
- // extra can be a number, shortcut for increasing-calling-decreasing
- indent: function( extra ) {
- if ( !this.multiline ) {
- return "";
- }
- var chr = this.indentChar;
- if ( this.HTML ) {
- chr = chr.replace( /\t/g, " " ).replace( / /g, " " );
- }
- return new Array( this._depth_ + (extra||0) ).join(chr);
- },
- up: function( a ) {
- this._depth_ += a || 1;
- },
- down: function( a ) {
- this._depth_ -= a || 1;
- },
- setParser: function( name, parser ) {
- this.parsers[name] = parser;
- },
- // The next 3 are exposed so you can use them
- quote: quote,
- literal: literal,
- join: join,
- //
- _depth_: 1,
- // This is the list of parsers, to modify them, use jsDump.setParser
- parsers: {
- window: "[Window]",
- document: "[Document]",
- error: function(error) {
- return "Error(\"" + error.message + "\")";
- },
- unknown: "[Unknown]",
- "null": "null",
- "undefined": "undefined",
- "function": function( fn ) {
- var ret = "function",
- // functions never have name in IE
- name = "name" in fn ? fn.name : (reName.exec(fn) || [])[1];
-
- if ( name ) {
- ret += " " + name;
- }
- ret += "( ";
-
- ret = [ ret, QUnit.jsDump.parse( fn, "functionArgs" ), "){" ].join( "" );
- return join( ret, QUnit.jsDump.parse(fn,"functionCode" ), "}" );
- },
- array: array,
- nodelist: array,
- "arguments": array,
- object: function( map, stack ) {
- var ret = [ ], keys, key, val, i;
- QUnit.jsDump.up();
- keys = [];
- for ( key in map ) {
- keys.push( key );
- }
- keys.sort();
- for ( i = 0; i < keys.length; i++ ) {
- key = keys[ i ];
- val = map[ key ];
- ret.push( QUnit.jsDump.parse( key, "key" ) + ": " + QUnit.jsDump.parse( val, undefined, stack ) );
- }
- QUnit.jsDump.down();
- return join( "{", ret, "}" );
- },
- node: function( node ) {
- var len, i, val,
- open = QUnit.jsDump.HTML ? "<" : "<",
- close = QUnit.jsDump.HTML ? ">" : ">",
- tag = node.nodeName.toLowerCase(),
- ret = open + tag,
- attrs = node.attributes;
-
- if ( attrs ) {
- for ( i = 0, len = attrs.length; i < len; i++ ) {
- val = attrs[i].nodeValue;
- // IE6 includes all attributes in .attributes, even ones not explicitly set.
- // Those have values like undefined, null, 0, false, "" or "inherit".
- if ( val && val !== "inherit" ) {
- ret += " " + attrs[i].nodeName + "=" + QUnit.jsDump.parse( val, "attribute" );
- }
- }
- }
- ret += close;
-
- // Show content of TextNode or CDATASection
- if ( node.nodeType === 3 || node.nodeType === 4 ) {
- ret += node.nodeValue;
- }
-
- return ret + open + "/" + tag + close;
- },
- // function calls it internally, it's the arguments part of the function
- functionArgs: function( fn ) {
- var args,
- l = fn.length;
-
- if ( !l ) {
- return "";
- }
-
- args = new Array(l);
- while ( l-- ) {
- // 97 is 'a'
- args[l] = String.fromCharCode(97+l);
- }
- return " " + args.join( ", " ) + " ";
- },
- // object calls it internally, the key part of an item in a map
- key: quote,
- // function calls it internally, it's the content of the function
- functionCode: "[code]",
- // node calls it internally, it's an html attribute value
- attribute: quote,
- string: quote,
- date: quote,
- regexp: literal,
- number: literal,
- "boolean": literal
- },
- // if true, entities are escaped ( <, >, \t, space and \n )
- HTML: false,
- // indentation unit
- indentChar: " ",
- // if true, items in a collection, are separated by a \n, else just a space.
- multiline: true
- };
-
- return jsDump;
-}());
-
-// from jquery.js
-function inArray( elem, array ) {
- if ( array.indexOf ) {
- return array.indexOf( elem );
- }
-
- for ( var i = 0, length = array.length; i < length; i++ ) {
- if ( array[ i ] === elem ) {
- return i;
- }
- }
-
- return -1;
-}
-
-/*
- * Javascript Diff Algorithm
- * By John Resig (http://ejohn.org/)
- * Modified by Chu Alan "sprite"
- *
- * Released under the MIT license.
- *
- * More Info:
- * http://ejohn.org/projects/javascript-diff-algorithm/
- *
- * Usage: QUnit.diff(expected, actual)
- *
- * QUnit.diff( "the quick brown fox jumped over", "the quick fox jumps over" ) == "the quick brown fox jumped jumps over"
- */
-QUnit.diff = (function() {
- /*jshint eqeqeq:false, eqnull:true */
- function diff( o, n ) {
- var i,
- ns = {},
- os = {};
-
- for ( i = 0; i < n.length; i++ ) {
- if ( !hasOwn.call( ns, n[i] ) ) {
- ns[ n[i] ] = {
- rows: [],
- o: null
- };
- }
- ns[ n[i] ].rows.push( i );
- }
-
- for ( i = 0; i < o.length; i++ ) {
- if ( !hasOwn.call( os, o[i] ) ) {
- os[ o[i] ] = {
- rows: [],
- n: null
- };
- }
- os[ o[i] ].rows.push( i );
- }
-
- for ( i in ns ) {
- if ( !hasOwn.call( ns, i ) ) {
- continue;
- }
- if ( ns[i].rows.length === 1 && hasOwn.call( os, i ) && os[i].rows.length === 1 ) {
- n[ ns[i].rows[0] ] = {
- text: n[ ns[i].rows[0] ],
- row: os[i].rows[0]
- };
- o[ os[i].rows[0] ] = {
- text: o[ os[i].rows[0] ],
- row: ns[i].rows[0]
- };
- }
- }
-
- for ( i = 0; i < n.length - 1; i++ ) {
- if ( n[i].text != null && n[ i + 1 ].text == null && n[i].row + 1 < o.length && o[ n[i].row + 1 ].text == null &&
- n[ i + 1 ] == o[ n[i].row + 1 ] ) {
-
- n[ i + 1 ] = {
- text: n[ i + 1 ],
- row: n[i].row + 1
- };
- o[ n[i].row + 1 ] = {
- text: o[ n[i].row + 1 ],
- row: i + 1
- };
- }
- }
-
- for ( i = n.length - 1; i > 0; i-- ) {
- if ( n[i].text != null && n[ i - 1 ].text == null && n[i].row > 0 && o[ n[i].row - 1 ].text == null &&
- n[ i - 1 ] == o[ n[i].row - 1 ]) {
-
- n[ i - 1 ] = {
- text: n[ i - 1 ],
- row: n[i].row - 1
- };
- o[ n[i].row - 1 ] = {
- text: o[ n[i].row - 1 ],
- row: i - 1
- };
- }
- }
-
- return {
- o: o,
- n: n
- };
- }
-
- return function( o, n ) {
- o = o.replace( /\s+$/, "" );
- n = n.replace( /\s+$/, "" );
-
- var i, pre,
- str = "",
- out = diff( o === "" ? [] : o.split(/\s+/), n === "" ? [] : n.split(/\s+/) ),
- oSpace = o.match(/\s+/g),
- nSpace = n.match(/\s+/g);
-
- if ( oSpace == null ) {
- oSpace = [ " " ];
- }
- else {
- oSpace.push( " " );
- }
-
- if ( nSpace == null ) {
- nSpace = [ " " ];
- }
- else {
- nSpace.push( " " );
- }
-
- if ( out.n.length === 0 ) {
- for ( i = 0; i < out.o.length; i++ ) {
- str += "" + out.o[i] + oSpace[i] + "";
- }
- }
- else {
- if ( out.n[0].text == null ) {
- for ( n = 0; n < out.o.length && out.o[n].text == null; n++ ) {
- str += "" + out.o[n] + oSpace[n] + "";
- }
- }
-
- for ( i = 0; i < out.n.length; i++ ) {
- if (out.n[i].text == null) {
- str += "" + out.n[i] + nSpace[i] + "";
- }
- else {
- // `pre` initialized at top of scope
- pre = "";
-
- for ( n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++ ) {
- pre += "" + out.o[n] + oSpace[n] + "";
- }
- str += " " + out.n[i].text + nSpace[i] + pre;
- }
- }
- }
-
- return str;
- };
-}());
-
-// for CommonJS enviroments, export everything
-if ( typeof exports !== "undefined" ) {
- extend( exports, QUnit );
-}
-
-// get at whatever the global object is, like window in browsers
-}( (function() {return this;}.call()) ));
diff --git a/test/lib/require.js b/test/lib/require.js
deleted file mode 100644
index 987f865..0000000
--- a/test/lib/require.js
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- RequireJS 2.1.5 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.
- Available via the MIT or new BSD license.
- see: http://github.com/jrburke/requirejs for details
-*/
-var requirejs,require,define;
-(function(aa){function I(b){return"[object Function]"===L.call(b)}function J(b){return"[object Array]"===L.call(b)}function y(b,c){if(b){var d;for(d=0;dthis.depCount&&!this.defined){if(I(n)){if(this.events.error)try{e=i.execCb(c,n,b,e)}catch(d){a=d}else e=i.execCb(c,n,b,e);this.map.isDefine&&((b=this.module)&&void 0!==b.exports&&b.exports!==this.exports?e=b.exports:void 0===e&&this.usingExports&&(e=this.exports));if(a)return a.requireMap=this.map,a.requireModules=[this.map.id],a.requireType="define",v(this.error=
-a)}else e=n;this.exports=e;if(this.map.isDefine&&!this.ignore&&(q[c]=e,l.onResourceLoad))l.onResourceLoad(i,this.map,this.depMaps);x(c);this.defined=!0}this.defining=!1;this.defined&&!this.defineEmitted&&(this.defineEmitted=!0,this.emit("defined",this.exports),this.defineEmitComplete=!0)}}else this.fetch()}},callPlugin:function(){var a=this.map,b=a.id,d=j(a.prefix);this.depMaps.push(d);t(d,"defined",u(this,function(e){var n,d;d=this.map.name;var g=this.map.parentMap?this.map.parentMap.name:null,h=
-i.makeRequire(a.parentMap,{enableBuildCallback:!0});if(this.map.unnormalized){if(e.normalize&&(d=e.normalize(d,function(a){return c(a,g,!0)})||""),e=j(a.prefix+"!"+d,this.map.parentMap),t(e,"defined",u(this,function(a){this.init([],function(){return a},null,{enabled:!0,ignore:!0})})),d=m(p,e.id)){this.depMaps.push(e);if(this.events.error)d.on("error",u(this,function(a){this.emit("error",a)}));d.enable()}}else n=u(this,function(a){this.init([],function(){return a},null,{enabled:!0})}),n.error=u(this,
-function(a){this.inited=!0;this.error=a;a.requireModules=[b];G(p,function(a){0===a.map.id.indexOf(b+"_unnormalized")&&x(a.map.id)});v(a)}),n.fromText=u(this,function(e,c){var d=a.name,g=j(d),C=O;c&&(e=c);C&&(O=!1);r(g);s(k.config,b)&&(k.config[d]=k.config[b]);try{l.exec(e)}catch(ca){return v(B("fromtexteval","fromText eval for "+b+" failed: "+ca,ca,[b]))}C&&(O=!0);this.depMaps.push(g);i.completeLoad(d);h([d],n)}),e.load(a.name,h,n,k)}));i.enable(d,this);this.pluginMaps[d.id]=d},enable:function(){V[this.map.id]=
-this;this.enabling=this.enabled=!0;y(this.depMaps,u(this,function(a,b){var c,e;if("string"===typeof a){a=j(a,this.map.isDefine?this.map:this.map.parentMap,!1,!this.skipMap);this.depMaps[b]=a;if(c=m(N,a.id)){this.depExports[b]=c(this);return}this.depCount+=1;t(a,"defined",u(this,function(a){this.defineDep(b,a);this.check()}));this.errback&&t(a,"error",this.errback)}c=a.id;e=p[c];!s(N,c)&&(e&&!e.enabled)&&i.enable(a,this)}));G(this.pluginMaps,u(this,function(a){var b=m(p,a.id);b&&!b.enabled&&i.enable(a,
-this)}));this.enabling=!1;this.check()},on:function(a,b){var c=this.events[a];c||(c=this.events[a]=[]);c.push(b)},emit:function(a,b){y(this.events[a],function(a){a(b)});"error"===a&&delete this.events[a]}};i={config:k,contextName:b,registry:p,defined:q,urlFetched:U,defQueue:H,Module:Z,makeModuleMap:j,nextTick:l.nextTick,onError:v,configure:function(a){a.baseUrl&&"/"!==a.baseUrl.charAt(a.baseUrl.length-1)&&(a.baseUrl+="/");var b=k.pkgs,c=k.shim,e={paths:!0,config:!0,map:!0};G(a,function(a,b){e[b]?
-"map"===b?(k.map||(k.map={}),R(k[b],a,!0,!0)):R(k[b],a,!0):k[b]=a});a.shim&&(G(a.shim,function(a,b){J(a)&&(a={deps:a});if((a.exports||a.init)&&!a.exportsFn)a.exportsFn=i.makeShimExports(a);c[b]=a}),k.shim=c);a.packages&&(y(a.packages,function(a){a="string"===typeof a?{name:a}:a;b[a.name]={name:a.name,location:a.location||a.name,main:(a.main||"main").replace(ja,"").replace(ea,"")}}),k.pkgs=b);G(p,function(a,b){!a.inited&&!a.map.unnormalized&&(a.map=j(b))});if(a.deps||a.callback)i.require(a.deps||[],
-a.callback)},makeShimExports:function(a){return function(){var b;a.init&&(b=a.init.apply(aa,arguments));return b||a.exports&&ba(a.exports)}},makeRequire:function(a,f){function d(e,c,h){var g,k;f.enableBuildCallback&&(c&&I(c))&&(c.__requireJsBuild=!0);if("string"===typeof e){if(I(c))return v(B("requireargs","Invalid require call"),h);if(a&&s(N,e))return N[e](p[a.id]);if(l.get)return l.get(i,e,a,d);g=j(e,a,!1,!0);g=g.id;return!s(q,g)?v(B("notloaded",'Module name "'+g+'" has not been loaded yet for context: '+
-b+(a?"":". Use require([])"))):q[g]}L();i.nextTick(function(){L();k=r(j(null,a));k.skipMap=f.skipMap;k.init(e,c,h,{enabled:!0});D()});return d}f=f||{};R(d,{isBrowser:A,toUrl:function(b){var d,f=b.lastIndexOf("."),g=b.split("/")[0];if(-1!==f&&(!("."===g||".."===g)||1h.attachEvent.toString().indexOf("[native code"))&&!Y?(O=!0,h.attachEvent("onreadystatechange",b.onScriptLoad)):(h.addEventListener("load",b.onScriptLoad,!1),h.addEventListener("error",b.onScriptError,!1)),h.src=d,K=h,D?x.insertBefore(h,D):x.appendChild(h),K=null,h;if(da)try{importScripts(d),b.completeLoad(c)}catch(j){b.onError(B("importscripts","importScripts failed for "+c+" at "+d,j,[c]))}};A&&M(document.getElementsByTagName("script"),function(b){x||(x=
-b.parentNode);if(t=b.getAttribute("data-main"))return r.baseUrl||(E=t.split("/"),Q=E.pop(),fa=E.length?E.join("/")+"/":"./",r.baseUrl=fa,t=Q),t=t.replace(ea,""),r.deps=r.deps?r.deps.concat(t):[t],!0});define=function(b,c,d){var l,h;"string"!==typeof b&&(d=c,c=b,b=null);J(c)||(d=c,c=[]);!c.length&&I(d)&&d.length&&(d.toString().replace(la,"").replace(ma,function(b,d){c.push(d)}),c=(1===d.length?["require"]:["require","exports","module"]).concat(c));if(O){if(!(l=K))P&&"interactive"===P.readyState||M(document.getElementsByTagName("script"),
-function(b){if("interactive"===b.readyState)return P=b}),l=P;l&&(b||(b=l.getAttribute("data-requiremodule")),h=F[l.getAttribute("data-requirecontext")])}(h?h.defQueue:T).push([b,c,d])};define.amd={jQuery:!0};l.exec=function(b){return eval(b)};l(r)}})(this);
diff --git a/test/lib/resemble.js b/test/lib/resemble.js
new file mode 100644
index 0000000..1cb8c29
--- /dev/null
+++ b/test/lib/resemble.js
@@ -0,0 +1,535 @@
+/*
+Author: James Cryer
+Company: Huddle
+Last updated date: 21 Feb 2013
+URL: https://github.com/Huddle/Resemble.js
+*/
+
+(function(_this){
+ 'use strict';
+
+ _this['resemble'] = function( fileData ){
+
+ var data = {};
+ var images = [];
+ var updateCallbackArray = [];
+
+ var tolerance = { // between 0 and 255
+ red: 16,
+ green: 16,
+ blue: 16,
+ minBrightness: 16,
+ maxBrightness: 240
+ };
+
+ var ignoreAntialiasing = false;
+ var ignoreColors = false;
+
+ function triggerDataUpdate(){
+ var len = updateCallbackArray.length;
+ var i;
+ for(i=0;i tolerance.maxBrightness;
+ }
+
+ function getHue(r,g,b){
+
+ r = r / 255;
+ g = g / 255;
+ b = b / 255;
+ var max = Math.max(r, g, b), min = Math.min(r, g, b);
+ var h;
+ var d;
+
+ if (max == min){
+ h = 0; // achromatic
+ } else{
+ d = max - min;
+ switch(max){
+ case r: h = (g - b) / d + (g < b ? 6 : 0); break;
+ case g: h = (b - r) / d + 2; break;
+ case b: h = (r - g) / d + 4; break;
+ }
+ h /= 6;
+ }
+
+ return h;
+ }
+
+ function isAntialiased(sourcePix, data, cacheSet, verticalPos, horizontalPos, width){
+ var offset;
+ var targetPix;
+ var distance = 1;
+ var i;
+ var j;
+ var hasHighContrastSibling = 0;
+ var hasSiblingWithDifferentHue = 0;
+ var hasEquivilantSibling = 0;
+
+ addHueInfo(sourcePix);
+
+ for (i = distance*-1; i <= distance; i++){
+ for (j = distance*-1; j <= distance; j++){
+
+ if(i===0 && j===0){
+ // ignore source pixel
+ } else {
+
+ offset = ((verticalPos+j)*width + (horizontalPos+i)) * 4;
+ targetPix = getPixelInfo(data, offset, cacheSet);
+
+ if(targetPix === null){
+ continue;
+ }
+
+ addBrightnessInfo(targetPix);
+ addHueInfo(targetPix);
+
+ if( isContrasting(sourcePix, targetPix) ){
+ hasHighContrastSibling++;
+ }
+
+ if( isRGBSame(sourcePix,targetPix) ){
+ hasEquivilantSibling++;
+ }
+
+ if( Math.abs(targetPix.h - sourcePix.h) > 0.3 ){
+ hasSiblingWithDifferentHue++;
+ }
+
+ if( hasSiblingWithDifferentHue > 1 || hasHighContrastSibling > 1){
+ return true;
+ }
+ }
+ }
+ }
+
+ if(hasEquivilantSibling < 2){
+ return true;
+ }
+
+ return false;
+ }
+
+ function errorPixel(px, offset){
+ px[offset] = 255; //r
+ px[offset + 1] = 0; //g
+ px[offset + 2] = 255; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyPixel(px, offset, data){
+ px[offset] = data.r; //r
+ px[offset + 1] = data.g; //g
+ px[offset + 2] = data.b; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyGrayScalePixel(px, offset, data){
+ px[offset] = data.brightness; //r
+ px[offset + 1] = data.brightness; //g
+ px[offset + 2] = data.brightness; //b
+ px[offset + 3] = 255; //a
+ }
+
+
+ function getPixelInfo(data, offset, cacheSet){
+ var r;
+ var g;
+ var b;
+ var d;
+
+ if(typeof data[offset] !== 'undefined'){
+ r = data[offset];
+ g = data[offset+1];
+ b = data[offset+2];
+ d = {
+ r: r,
+ g: g,
+ b: b
+ };
+
+ return d;
+ } else {
+ return null;
+ }
+ }
+
+ function addBrightnessInfo(data){
+ data.brightness = getBrightness(data.r,data.g,data.b); // 'corrected' lightness
+ }
+
+ function addHueInfo(data){
+ data.h = getHue(data.r,data.g,data.b);
+ }
+
+ function analyseImages(img1, img2, width, height){
+
+ var hiddenCanvas = document.createElement('canvas');
+
+ var data1 = img1.data;
+ var data2 = img2.data;
+
+ hiddenCanvas.width = width;
+ hiddenCanvas.height = height;
+
+ var context = hiddenCanvas.getContext('2d');
+ var imgd = context.createImageData(width,height);
+ var targetPix = imgd.data;
+
+ var mismatchCount = 0;
+
+ var time = Date.now();
+
+ var skip;
+
+ if( (width > 1200 || height > 1200) && ignoreAntialiasing){
+ skip = 6;
+ }
+
+ loop(height, width, function(verticalPos, horizontalPos){
+
+ if(skip){ // only skip if the image isn't small
+ if(verticalPos % skip === 0 || horizontalPos % skip === 0){
+ return;
+ }
+ }
+
+ var offset = (verticalPos*width + horizontalPos) * 4;
+ var pixel1 = getPixelInfo(data1, offset, 1);
+ var pixel2 = getPixelInfo(data2, offset, 2);
+
+ if(pixel1 === null || pixel2 === null){
+ return;
+ }
+
+ if (ignoreColors){
+
+ addBrightnessInfo(pixel1);
+ addBrightnessInfo(pixel2);
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ return;
+ }
+
+ if( isRGBSimilar(pixel1, pixel2) ){
+ copyPixel(targetPix, offset, pixel2);
+
+ } else if( ignoreAntialiasing && (
+ addBrightnessInfo(pixel1), // jit pixel info augmentation looks a little weird, sorry.
+ addBrightnessInfo(pixel2),
+ isAntialiased(pixel1, data1, 1, verticalPos, horizontalPos, width) ||
+ isAntialiased(pixel2, data2, 2, verticalPos, horizontalPos, width)
+ )){
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+
+ });
+
+ data.misMatchPercentage = (mismatchCount / (height*width) * 100).toFixed(2);
+ data.analysisTime = Date.now() - time;
+
+ data.getImageDataUrl = function(text){
+ var barHeight = 0;
+
+ if(text){
+ barHeight = addLabel(text,context,hiddenCanvas);
+ }
+
+ context.putImageData(imgd, 0, barHeight);
+
+ return hiddenCanvas.toDataURL("image/png");
+ };
+ }
+
+ function addLabel(text, context, hiddenCanvas){
+ var textPadding = 2;
+
+ context.font = '12px sans-serif';
+
+ var textWidth = context.measureText(text).width + textPadding*2;
+ var barHeight = 22;
+
+ if(textWidth > hiddenCanvas.width){
+ hiddenCanvas.width = textWidth;
+ }
+
+ hiddenCanvas.height += barHeight;
+
+ context.fillStyle = "#666";
+ context.fillRect(0,0,hiddenCanvas.width,barHeight -4);
+ context.fillStyle = "#fff";
+ context.fillRect(0,barHeight -4,hiddenCanvas.width, 4);
+
+ context.fillStyle = "#fff";
+ context.textBaseline = "top";
+ context.font = '12px sans-serif';
+ context.fillText(text, textPadding, 1);
+
+ return barHeight;
+ }
+
+ function normalise(img, w, h){
+ var c;
+ var context;
+
+ if(img.height < h || img.width < w){
+ c = document.createElement('canvas');
+ c.width = w;
+ c.height = h;
+ context = c.getContext('2d');
+ context.putImageData(img, 0, 0);
+ return context.getImageData(0, 0, w, h);
+ }
+
+ return img;
+ }
+
+ function compare(one, two){
+
+ function onceWeHaveBoth(){
+ var width;
+ var height;
+ if(images.length === 2){
+ width = images[0].width > images[1].width ? images[0].width : images[1].width;
+ height = images[0].height > images[1].height ? images[0].height : images[1].height;
+
+ if( (images[0].width === images[1].width) && (images[0].height === images[1].height) ){
+ data.isSameDimensions = true;
+ } else {
+ data.isSameDimensions = false;
+ }
+
+ analyseImages( normalise(images[0],width, height), normalise(images[1],width, height), width, height);
+
+ triggerDataUpdate();
+ }
+ }
+
+ images = [];
+ loadImageData(one, onceWeHaveBoth);
+ loadImageData(two, onceWeHaveBoth);
+ }
+
+ function getCompareApi(param){
+
+ var secondFileData,
+ hasMethod = typeof param === 'function';
+
+ if( !hasMethod ){
+ // assume it's file data
+ secondFileData = param;
+ }
+
+ var self = {
+ ignoreNothing: function(){
+
+ tolerance.red = 16;
+ tolerance.green = 16;
+ tolerance.blue = 16;
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreAntialiasing: function(){
+
+ tolerance.red = 32;
+ tolerance.green = 32;
+ tolerance.blue = 32;
+ tolerance.minBrightness = 64;
+ tolerance.maxBrightness = 96;
+
+ ignoreAntialiasing = true;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreColors: function(){
+
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = true;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ onComplete: function( callback ){
+
+ updateCallbackArray.push(callback);
+
+ var wrapper = function(){
+ compare(fileData, secondFileData);
+ };
+
+ wrapper();
+
+ return getCompareApi(wrapper);
+ }
+ };
+
+ return self;
+ }
+
+ return {
+ onComplete: function( callback ){
+ updateCallbackArray.push(callback);
+ loadImageData(fileData, function(imageData, width, height){
+ parseImage(imageData.data, width, height);
+ });
+ },
+ compareTo: function(secondFileData){
+ return getCompareApi(secondFileData);
+ }
+ };
+
+ };
+}(this));
\ No newline at end of file
diff --git a/test/testsuite.js b/test/testsuite.js
deleted file mode 100644
index b486acb..0000000
--- a/test/testsuite.js
+++ /dev/null
@@ -1,36 +0,0 @@
-requirejs.config({
- baseUrl: '/test/unit/'
-});
-
-define(function(require) {
- var testModules = [
- 'Pixi',
- 'Point',
- 'Rectangle',
- 'DisplayObject',
- 'DisplayObjectContainer',
- 'Sprite',
- 'MovieClip',
- 'InteractionManager',
- 'Stage',
- 'utils/Utils',
- 'utils/EventTarget',
- 'utils/Matrix',
- 'utils/Detector',
- 'renderers/WebGLShaders',
- 'renderers/WebGLRenderer',
- 'renderers/WebGLBatch',
- 'renderers/CanvasRenderer',
- 'extras/Strip',
- 'extras/Rope',
- 'textures/BaseTexture',
- 'textures/Texture',
- 'loaders/SpriteSheetLoader',
- 'loaders/AssetLoader'
- ];
-
- // Resolve all testModules and then start the Test Runner.
- require(testModules, function() {
- QUnit.start();
- });
-});
\ No newline at end of file
diff --git a/test/textures/SpriteSheet-Aliens.png b/test/textures/SpriteSheet-Aliens.png
new file mode 100644
index 0000000..210acb1
--- /dev/null
+++ b/test/textures/SpriteSheet-Aliens.png
Binary files differ
diff --git a/test/textures/SpriteSheet-Explosion.png b/test/textures/SpriteSheet-Explosion.png
new file mode 100755
index 0000000..79e1a69
--- /dev/null
+++ b/test/textures/SpriteSheet-Explosion.png
Binary files differ
diff --git a/test/textures/bunny.png b/test/textures/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/textures/bunny.png
Binary files differ
diff --git a/test/unit/DisplayObject.js b/test/unit/DisplayObject.js
deleted file mode 100644
index 5e7e72f..0000000
--- a/test/unit/DisplayObject.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObject');
-});
diff --git a/test/unit/DisplayObjectContainer.js b/test/unit/DisplayObjectContainer.js
deleted file mode 100644
index b323959..0000000
--- a/test/unit/DisplayObjectContainer.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObjectContainer');
-});
diff --git a/test/unit/InteractionManager.js b/test/unit/InteractionManager.js
deleted file mode 100644
index e751f52..0000000
--- a/test/unit/InteractionManager.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('InteractionManager');
-});
diff --git a/test/unit/MovieClip.js b/test/unit/MovieClip.js
deleted file mode 100644
index 37d9446..0000000
--- a/test/unit/MovieClip.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('MovieClip');
-});
diff --git a/test/unit/Pixi.js b/test/unit/Pixi.js
deleted file mode 100644
index 36eee73..0000000
--- a/test/unit/Pixi.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Pixi');
-});
diff --git a/test/unit/Point.js b/test/unit/Point.js
deleted file mode 100644
index 983ff6e..0000000
--- a/test/unit/Point.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Point');
-});
diff --git a/test/unit/Rectangle.js b/test/unit/Rectangle.js
deleted file mode 100644
index 3b439ba..0000000
--- a/test/unit/Rectangle.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Rectangle');
-});
diff --git a/test/unit/Sprite.js b/test/unit/Sprite.js
deleted file mode 100644
index ed4f596..0000000
--- a/test/unit/Sprite.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Sprite');
-});
diff --git a/test/unit/Stage.js b/test/unit/Stage.js
deleted file mode 100644
index 2d70291..0000000
--- a/test/unit/Stage.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Stage');
-});
diff --git a/.gitignore b/.gitignore
index 12e1b62..0b88317 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
node_modules
.DS_Store
-.project
\ No newline at end of file
+.project
+*.log
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..63e4d7c
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,8 @@
+language: node_js
+node_js:
+ - 0.10
+
+before_script:
+ - npm install -g grunt-cli
+ - export DISPLAY=:99.0
+ - sh -e /etc/init.d/xvfb start
diff --git a/Gruntfile.js b/Gruntfile.js
index b083b49..103938c 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -1,10 +1,12 @@
+'use strict';
+
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-connect');
- grunt.loadNpmTasks('grunt-contrib-qunit');
grunt.loadNpmTasks('grunt-contrib-yuidoc');
+ grunt.loadTasks('tasks');
var root = 'src/pixi/',
debug = 'bin/pixi.dev.js',
@@ -79,7 +81,7 @@
},
files: {
srcBlob: '<%= dirs.src %>/**/*.js',
- testBlob: '<%= dirs.test %>/unit/**/*.js',
+ testBlob: '<%= dirs.test %>/{functional,lib/pixi,unit}/**/*.js',
build: '<%= dirs.build %>/pixi.dev.js',
buildMin: '<%= dirs.build %>/pixi.js'
},
@@ -94,7 +96,12 @@
},
jshint: {
beforeconcat: srcFiles,
- test: ['<%= files.testBlob %>'],
+ test: {
+ src: ['<%= files.testBlob %>'],
+ options: {
+ expr: true
+ }
+ },
options: {
asi: true,
smarttabs: true
@@ -128,12 +135,6 @@
]
},
connect: {
- qunit: {
- options: {
- port: grunt.option('port-test') || 9002,
- base: './'
- }
- },
test: {
options: {
port: grunt.option('port-test') || 9002,
@@ -142,13 +143,6 @@
}
}
},
- qunit: {
- all: {
- options: {
- urls: ['http://localhost:' + (grunt.option('port-test') || 9002) + '/test/index.html']
- }
- }
- },
yuidoc: {
compile: {
name: '<%= pkg.name %>',
@@ -161,6 +155,13 @@
outdir: '<%= dirs.docs %>'
}
}
+ },
+ karma: {
+ unit: {
+ configFile: 'test/karma.conf.js',
+ // browsers: ['Chrome'],
+ singleRun: true
+ }
}
});
@@ -182,9 +183,10 @@
}
)
- grunt.registerTask('default', ['concat', 'uglify', 'distribute']);
grunt.registerTask('build', ['concat', 'uglify', 'distribute']);
- grunt.registerTask('test', ['build', 'connect:qunit', 'qunit']);
+ grunt.registerTask('test', ['concat', 'jshint:test', 'karma']);
grunt.registerTask('docs', ['yuidoc']);
-
-}
\ No newline at end of file
+ grunt.registerTask('default', ['test', 'uglify', 'distribute']);
+ // Travis CI task.
+ grunt.registerTask('travis', ['test']);
+}
diff --git a/README.md b/README.md
index c62ef86..690cfe4 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,8 @@

+[](http://travis-ci.org/drkibitz/pixi.js)
+
#### JavaScript 2D Renderer ####
The aim of this project is to provide a fast lightweight 2D library that works
diff --git a/package.json b/package.json
index b373240..1246a68 100644
--- a/package.json
+++ b/package.json
@@ -18,14 +18,21 @@
"main": "bin/pixi.js",
+ "scripts": {
+ "test": "grunt travis --verbose"
+ },
+
"dependencies": {},
"devDependencies": {
"grunt": "~0.4.x",
- "grunt-contrib-jshint": "0.3.x",
+ "grunt-contrib-jshint": "0.6.x",
"grunt-contrib-uglify": "0.2.x",
- "grunt-contrib-connect": "0.2.x",
- "grunt-contrib-qunit": "0.2.x",
+ "grunt-contrib-connect": "0.3.x",
"grunt-contrib-yuidoc": "0.4.x",
- "grunt-contrib-concat": "0.1.x"
+ "grunt-contrib-concat": "0.3.x",
+ "chai": "~1.7.0",
+ "karma": "0.11.0",
+ "karma-firefox-launcher": "0.1.0",
+ "karma-mocha": "0.1.0"
}
}
diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js
index a7c520e..ee82bbd 100644
--- a/src/pixi/InteractionManager.js
+++ b/src/pixi/InteractionManager.js
@@ -62,7 +62,6 @@
this.onTouchEnd = this.onTouchEnd.bind(this);
this.onTouchMove = this.onTouchMove.bind(this);
-
this.last = 0;
}
diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js
index 1a95d20..eef1059 100644
--- a/src/pixi/core/Ellipse.js
+++ b/src/pixi/core/Ellipse.js
@@ -78,7 +78,7 @@
return (normx + normy < 0.25);
}
-PIXI.Ellipse.getBounds = function()
+PIXI.Ellipse.prototype.getBounds = function()
{
return new PIXI.Rectangle(this.x, this.y, this.width, this.height);
}
diff --git a/tasks/karma.js b/tasks/karma.js
new file mode 100644
index 0000000..c340485
--- /dev/null
+++ b/tasks/karma.js
@@ -0,0 +1,27 @@
+'use strict';
+
+var path = require('path');
+var server = require('karma').server;
+
+module.exports = function (grunt) {
+ grunt.registerMultiTask('karma', 'run karma.', function() {
+ var done = this.async();
+ var options = this.options({
+ background: false
+ });
+ var data = this.data;
+
+ //merge options onto data, with data taking precedence
+ data = grunt.util._.merge(options, data);
+ data.configFile = path.resolve(data.configFile);
+ if (data.configFile) {
+ data.configFile = grunt.template.process(data.configFile);
+ }
+
+ server.start(
+ data,
+ function(code) {
+ done(!code);
+ });
+ });
+};
diff --git a/test/functional/example-1-basics/bunny.png b/test/functional/example-1-basics/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/functional/example-1-basics/bunny.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-30.png b/test/functional/example-1-basics/frame-30.png
new file mode 100644
index 0000000..96e3409
--- /dev/null
+++ b/test/functional/example-1-basics/frame-30.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-60.png b/test/functional/example-1-basics/frame-60.png
new file mode 100644
index 0000000..af3f4ce
--- /dev/null
+++ b/test/functional/example-1-basics/frame-60.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-90.png b/test/functional/example-1-basics/frame-90.png
new file mode 100644
index 0000000..099b823
--- /dev/null
+++ b/test/functional/example-1-basics/frame-90.png
Binary files differ
diff --git a/test/functional/example-1-basics/index.js b/test/functional/example-1-basics/index.js
new file mode 100644
index 0000000..7ae7a98
--- /dev/null
+++ b/test/functional/example-1-basics/index.js
@@ -0,0 +1,133 @@
+describe('Example 1 - Basics', function () {
+ 'use strict';
+
+ var baseUri = '/base/test/functional/example-1-basics';
+ var expect = chai.expect;
+ var currentFrame = 0;
+ var frameEvents = {};
+ var stage;
+ var renderer;
+ var bunny;
+
+ function onFrame(frame, callback) {
+ frameEvents[frame] = callback;
+ }
+
+ function animate() {
+ currentFrame += 1;
+
+ requestAnimFrame( animate );
+
+ // just for fun, lets rotate mr rabbit a little
+ bunny.rotation += 0.1;
+
+ // render the stage
+ renderer.render(stage);
+
+ if (frameEvents[currentFrame])
+ frameEvents[currentFrame](currentFrame);
+ }
+
+ function initScene() {
+ // create an new instance of a pixi stage
+ stage = new PIXI.Stage(0x66FF99);
+
+ // create a renderer instance
+ renderer = PIXI.autoDetectRenderer(400, 300);
+ console.log('Is PIXI.WebGLRenderer: ' + (renderer instanceof PIXI.WebGLRenderer));
+
+ // add the renderer view element to the DOM
+ document.body.appendChild(renderer.view);
+
+ requestAnimFrame( animate );
+
+ // create a texture from an image path
+ var texture = PIXI.Texture.fromImage(baseUri + "/bunny.png");
+ // create a new Sprite using the texture
+ bunny = new PIXI.Sprite(texture);
+
+ // center the sprites anchor point
+ bunny.anchor.x = 0.5;
+ bunny.anchor.y = 0.5;
+
+ // move the sprite t the center of the screen
+ bunny.position.x = 200;
+ bunny.position.y = 150;
+
+ stage.addChild(bunny);
+ }
+
+ it('assets loaded', function (done) {
+ var loader = new PIXI.AssetLoader([
+ baseUri + '/bunny.png',
+ baseUri + '/frame-30.png',
+ baseUri + '/frame-60.png',
+ baseUri + '/frame-90.png'
+ ]);
+ // loader.on('onProgress', function (event) {
+ // console.log(event.content);
+ // });
+ loader.on('onComplete', function (event) {
+ done();
+ initScene();
+ });
+ loader.load();
+ });
+
+ it('frame 30 should match', function (done) {
+ this.timeout(700);
+ onFrame(30, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-30.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 60 should match', function (done) {
+ this.timeout(1200);
+ onFrame(60, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-60.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 90 should match', function (done) {
+ this.timeout(1700);
+ onFrame(90, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-90.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ // it('capture something', function (done) {
+ // this.timeout(2000000);
+ // onFrame(30, function () {
+ // var img = new Image();
+ // img.src = renderer.view.toDataURL('image/png');
+ // document.body.appendChild(img);
+ // });
+ // });
+});
diff --git a/test/index.html b/test/index.html
deleted file mode 100644
index 9cbcac5..0000000
--- a/test/index.html
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
- Pixi.js Test Suite
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/test/karma.conf.js b/test/karma.conf.js
new file mode 100644
index 0000000..c66a696
--- /dev/null
+++ b/test/karma.conf.js
@@ -0,0 +1,82 @@
+module.exports = function(config) {
+ config.set({
+
+ // base path, that will be used to resolve files and exclude
+ basePath : '../',
+
+ frameworks : ['mocha'],
+
+ // list of files / patterns to load in the browser
+ files : [
+ 'node_modules/chai/chai.js',
+ 'bin/pixi.dev.js',
+ 'test/lib/**/*.js',
+ 'test/unit/**/*.js',
+ // 'test/functional/**/*.js',
+ {pattern: 'test/**/*.png', watched: false, included: false, served: true}
+ ],
+
+ // list of files to exclude
+ exclude : [],
+
+ // use dolts reporter, as travis terminal does not support escaping sequences
+ // possible values: 'dots', 'progress', 'junit', 'teamcity'
+ // CLI --reporters progress
+ reporters : ['progress'],
+
+ // web server port
+ // CLI --port 9876
+ port : 9876,
+
+ // cli runner port
+ // CLI --runner-port 9100
+ runnerPort : 9100,
+
+ // enable / disable colors in the output (reporters and logs)
+ // CLI --colors --no-colors
+ colors : true,
+
+ // level of logging
+ // possible values: karma.LOG_DISABLE || karma.LOG_ERROR || karma.LOG_WARN || karma.LOG_INFO || karma.LOG_DEBUG
+ // CLI --log-level debug
+ logLevel : config.LOG_DEBUG,
+
+ // enable / disable watching file and executing tests whenever any file changes
+ // CLI --auto-watch --no-auto-watch
+ autoWatch : false,
+
+ // Start these browsers, currently available:
+ // - Chrome
+ // - ChromeCanary
+ // - Firefox
+ // - Opera
+ // - Safari (only Mac)
+ // - PhantomJS
+ // - IE (only Windows)
+ // CLI --browsers Chrome,Firefox,Safari
+ browsers : ['Firefox'],
+
+ // If browser does not capture in given timeout [ms], kill it
+ // CLI --capture-timeout 5000
+ captureTimeout : 5000,
+
+ // Auto run tests on start (when browsers are captured) and exit
+ // CLI --single-run --no-single-run
+ singleRun : true,
+
+ // report which specs are slower than 500ms
+ // CLI --report-slower-than 500
+ reportSlowerThan : 1000,
+
+ preprocessors : {
+ // '**/client/js/*.js': 'coverage'
+ },
+
+ plugins : [
+ 'karma-mocha',
+ // 'karma-chrome-launcher',
+ 'karma-firefox-launcher',
+ // 'karma-phantomjs-launcher'
+ ]
+ });
+};
diff --git a/test/lib/pixi/core/Matrix.js b/test/lib/pixi/core/Matrix.js
new file mode 100644
index 0000000..d26386b
--- /dev/null
+++ b/test/lib/pixi/core/Matrix.js
@@ -0,0 +1,40 @@
+
+function pixi_core_Matrix_confirmNewMat3(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(1);
+ expect(matrix[5]).to.equal(0);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(1);
+}
+
+function pixi_core_Matrix_confirmNewMat4(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[0]).to.equal(1);
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(0);
+ expect(matrix[5]).to.equal(1);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(0);
+ expect(matrix[9]).to.equal(0);
+ expect(matrix[10]).to.equal(1);
+ expect(matrix[11]).to.equal(0);
+ expect(matrix[12]).to.equal(0);
+ expect(matrix[13]).to.equal(0);
+ expect(matrix[14]).to.equal(0);
+ expect(matrix[15]).to.equal(1);
+}
diff --git a/test/lib/pixi/core/Point.js b/test/lib/pixi/core/Point.js
new file mode 100644
index 0000000..e5df07b
--- /dev/null
+++ b/test/lib/pixi/core/Point.js
@@ -0,0 +1,10 @@
+
+function pixi_core_Point_confirm(obj, x, y) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Point);
+ expect(obj).to.respondTo('clone');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+}
diff --git a/test/lib/pixi/core/Rectangle.js b/test/lib/pixi/core/Rectangle.js
new file mode 100644
index 0000000..23f0d12
--- /dev/null
+++ b/test/lib/pixi/core/Rectangle.js
@@ -0,0 +1,13 @@
+
+function pixi_core_Rectangle_confirm(obj, x, y, width, height) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Rectangle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+ expect(obj).to.have.property('width', width);
+ expect(obj).to.have.property('height', height);
+}
diff --git a/test/lib/pixi/display/DisplayObject.js b/test/lib/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..1388a7f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObject.js
@@ -0,0 +1,43 @@
+
+function pixi_display_DisplayObject_confirmNew(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObject);
+ expect(obj).to.respondTo('setInteractive');
+ expect(obj).to.respondTo('addFilter');
+ expect(obj).to.respondTo('removeFilter');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.property('last', obj);
+ expect(obj).to.have.property('first', obj);
+
+ expect(obj).to.contain.property('position');
+ pixi_core_Point_confirm(obj.position, 0, 0);
+ expect(obj).to.contain.property('scale');
+ pixi_core_Point_confirm(obj.scale, 1, 1);
+ expect(obj).to.contain.property('pivot');
+ pixi_core_Point_confirm(obj.pivot, 0, 0);
+
+ expect(obj).to.have.property('rotation', 0);
+ expect(obj).to.have.property('alpha', 1);
+ expect(obj).to.have.property('visible', true);
+ expect(obj).to.have.property('buttonMode', false);
+ expect(obj).to.have.property('parent', null);
+ expect(obj).to.have.property('worldAlpha', 1);
+
+ expect(obj).to.have.property('hitArea');
+ expect(obj).to.have.property('interactive'); // TODO: Have a better default value
+ expect('mask' in obj).to.be.true; // TODO: Have a better default value
+ expect(obj.mask).to.be.undefined;
+
+ expect(obj).to.have.property('renderable');
+ expect(obj).to.have.property('stage');
+
+ expect(obj).to.have.deep.property('worldTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ expect(obj).to.have.deep.property('localTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.localTransform);
+
+ expect(obj).to.have.deep.property('color.length', 0);
+ expect(obj).to.have.property('dynamic', true);
+}
diff --git a/test/lib/pixi/display/DisplayObjectContainer.js b/test/lib/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..085c59f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,16 @@
+
+function pixi_display_DisplayObjectContainer_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObject_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObjectContainer);
+ expect(obj).to.respondTo('addChild');
+ expect(obj).to.respondTo('addChildAt');
+ expect(obj).to.respondTo('swapChildren');
+ expect(obj).to.respondTo('getChildAt');
+ expect(obj).to.respondTo('removeChild');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('children.length', 0);
+}
diff --git a/test/lib/pixi/display/Sprite.js b/test/lib/pixi/display/Sprite.js
new file mode 100644
index 0000000..cc7a2d6
--- /dev/null
+++ b/test/lib/pixi/display/Sprite.js
@@ -0,0 +1,28 @@
+
+function pixi_display_Sprite_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Sprite);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', true);
+ expect(obj).to.have.property('stage', null);
+
+ expect(obj).to.have.property('anchor');
+ pixi_core_Point_confirm(obj.anchor, 0, 0);
+
+ expect(obj).to.have.property('blendMode', PIXI.blendModes.NORMAL);
+ expect(obj).to.have.property('width', 1); // TODO: is 1 expected
+ expect(obj).to.have.property('height', 1); // TODO: is 1 expected
+
+ // FIXME: Just make this a boolean that is always there
+ expect(!!obj.updateFrame).to.equal(obj.texture.baseTexture.hasLoaded);
+
+ expect(obj).to.have.property('texture');
+ pixi_textures_Texture_confirmNew(obj.texture, done);
+}
diff --git a/test/lib/pixi/extras/Strip.js b/test/lib/pixi/extras/Strip.js
new file mode 100644
index 0000000..8927a8a
--- /dev/null
+++ b/test/lib/pixi/extras/Strip.js
@@ -0,0 +1,12 @@
+
+function pixi_extras_Strip_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Strip);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ // TODO: Test properties
+}
diff --git a/test/lib/pixi/textures/Texture.js b/test/lib/pixi/textures/Texture.js
new file mode 100644
index 0000000..d5867b6
--- /dev/null
+++ b/test/lib/pixi/textures/Texture.js
@@ -0,0 +1,31 @@
+
+function pixi_textures_Texture_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ function confirmFrameDone() {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, obj.baseTexture.width, obj.baseTexture.height);
+
+ expect(obj).to.have.property('width', obj.baseTexture.width);
+ expect(obj).to.have.property('height', obj.baseTexture.height);
+ done();
+ }
+
+ expect(obj).to.be.an.instanceof(PIXI.Texture);
+ pixi_utils_EventTarget_like(obj);
+
+ expect(obj).to.have.property('baseTexture')
+ .and.to.be.an.instanceof(PIXI.BaseTexture);
+
+ expect(obj).to.have.property('scope', obj);
+
+ expect(obj).to.have.property('trim');
+ pixi_core_Point_confirm(obj.trim, 0, 0);
+
+ expect(obj).to.have.property('frame');
+ if (obj.baseTexture.hasLoaded) {
+ confirmFrameDone();
+ } else {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, 1, 1);
+ obj.addEventListener('update', confirmFrameDone);
+ }
+}
diff --git a/test/lib/pixi/utils/EventTarget.js b/test/lib/pixi/utils/EventTarget.js
new file mode 100644
index 0000000..7b1dcfa
--- /dev/null
+++ b/test/lib/pixi/utils/EventTarget.js
@@ -0,0 +1,8 @@
+
+function pixi_utils_EventTarget_like(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.respondTo('addEventListener');
+ expect(obj).to.respondTo('dispatchEvent');
+ expect(obj).to.respondTo('removeEventListener');
+}
diff --git a/test/lib/qunit-1.11.0.css b/test/lib/qunit-1.11.0.css
deleted file mode 100644
index d7fc0c8..0000000
--- a/test/lib/qunit-1.11.0.css
+++ /dev/null
@@ -1,244 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-/** Font Family and Sizes */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
- font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
-}
-
-#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
-#qunit-tests { font-size: smaller; }
-
-
-/** Resets */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter {
- margin: 0;
- padding: 0;
-}
-
-
-/** Header */
-
-#qunit-header {
- padding: 0.5em 0 0.5em 1em;
-
- color: #8699a4;
- background-color: #0d3349;
-
- font-size: 1.5em;
- line-height: 1em;
- font-weight: normal;
-
- border-radius: 5px 5px 0 0;
- -moz-border-radius: 5px 5px 0 0;
- -webkit-border-top-right-radius: 5px;
- -webkit-border-top-left-radius: 5px;
-}
-
-#qunit-header a {
- text-decoration: none;
- color: #c2ccd1;
-}
-
-#qunit-header a:hover,
-#qunit-header a:focus {
- color: #fff;
-}
-
-#qunit-testrunner-toolbar label {
- display: inline-block;
- padding: 0 .5em 0 .1em;
-}
-
-#qunit-banner {
- height: 5px;
-}
-
-#qunit-testrunner-toolbar {
- padding: 0.5em 0 0.5em 2em;
- color: #5E740B;
- background-color: #eee;
- overflow: hidden;
-}
-
-#qunit-userAgent {
- padding: 0.5em 0 0.5em 2.5em;
- background-color: #2b81af;
- color: #fff;
- text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
-}
-
-#qunit-modulefilter-container {
- float: right;
-}
-
-/** Tests: Pass/Fail */
-
-#qunit-tests {
- list-style-position: inside;
-}
-
-#qunit-tests li {
- padding: 0.4em 0.5em 0.4em 2.5em;
- border-bottom: 1px solid #fff;
- list-style-position: inside;
-}
-
-#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running {
- display: none;
-}
-
-#qunit-tests li strong {
- cursor: pointer;
-}
-
-#qunit-tests li a {
- padding: 0.5em;
- color: #c2ccd1;
- text-decoration: none;
-}
-#qunit-tests li a:hover,
-#qunit-tests li a:focus {
- color: #000;
-}
-
-#qunit-tests li .runtime {
- float: right;
- font-size: smaller;
-}
-
-.qunit-assert-list {
- margin-top: 0.5em;
- padding: 0.5em;
-
- background-color: #fff;
-
- border-radius: 5px;
- -moz-border-radius: 5px;
- -webkit-border-radius: 5px;
-}
-
-.qunit-collapsed {
- display: none;
-}
-
-#qunit-tests table {
- border-collapse: collapse;
- margin-top: .2em;
-}
-
-#qunit-tests th {
- text-align: right;
- vertical-align: top;
- padding: 0 .5em 0 0;
-}
-
-#qunit-tests td {
- vertical-align: top;
-}
-
-#qunit-tests pre {
- margin: 0;
- white-space: pre-wrap;
- word-wrap: break-word;
-}
-
-#qunit-tests del {
- background-color: #e0f2be;
- color: #374e0c;
- text-decoration: none;
-}
-
-#qunit-tests ins {
- background-color: #ffcaca;
- color: #500;
- text-decoration: none;
-}
-
-/*** Test Counts */
-
-#qunit-tests b.counts { color: black; }
-#qunit-tests b.passed { color: #5E740B; }
-#qunit-tests b.failed { color: #710909; }
-
-#qunit-tests li li {
- padding: 5px;
- background-color: #fff;
- border-bottom: none;
- list-style-position: inside;
-}
-
-/*** Passing Styles */
-
-#qunit-tests li li.pass {
- color: #3c510c;
- background-color: #fff;
- border-left: 10px solid #C6E746;
-}
-
-#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
-#qunit-tests .pass .test-name { color: #366097; }
-
-#qunit-tests .pass .test-actual,
-#qunit-tests .pass .test-expected { color: #999999; }
-
-#qunit-banner.qunit-pass { background-color: #C6E746; }
-
-/*** Failing Styles */
-
-#qunit-tests li li.fail {
- color: #710909;
- background-color: #fff;
- border-left: 10px solid #EE5757;
- white-space: pre;
-}
-
-#qunit-tests > li:last-child {
- border-radius: 0 0 5px 5px;
- -moz-border-radius: 0 0 5px 5px;
- -webkit-border-bottom-right-radius: 5px;
- -webkit-border-bottom-left-radius: 5px;
-}
-
-#qunit-tests .fail { color: #000000; background-color: #EE5757; }
-#qunit-tests .fail .test-name,
-#qunit-tests .fail .module-name { color: #000000; }
-
-#qunit-tests .fail .test-actual { color: #EE5757; }
-#qunit-tests .fail .test-expected { color: green; }
-
-#qunit-banner.qunit-fail { background-color: #EE5757; }
-
-
-/** Result */
-
-#qunit-testresult {
- padding: 0.5em 0.5em 0.5em 2.5em;
-
- color: #2b81af;
- background-color: #D2E0E6;
-
- border-bottom: 1px solid white;
-}
-#qunit-testresult .module-name {
- font-weight: bold;
-}
-
-/** Fixture */
-
-#qunit-fixture {
- position: absolute;
- top: -10000px;
- left: -10000px;
- width: 1000px;
- height: 1000px;
-}
diff --git a/test/lib/qunit-1.11.0.js b/test/lib/qunit-1.11.0.js
deleted file mode 100644
index 302545f..0000000
--- a/test/lib/qunit-1.11.0.js
+++ /dev/null
@@ -1,2152 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-(function( window ) {
-
-var QUnit,
- assert,
- config,
- onErrorFnPrev,
- testId = 0,
- fileName = (sourceFromStacktrace( 0 ) || "" ).replace(/(:\d+)+\)?/, "").replace(/.+\//, ""),
- toString = Object.prototype.toString,
- hasOwn = Object.prototype.hasOwnProperty,
- // Keep a local reference to Date (GH-283)
- Date = window.Date,
- defined = {
- setTimeout: typeof window.setTimeout !== "undefined",
- sessionStorage: (function() {
- var x = "qunit-test-string";
- try {
- sessionStorage.setItem( x, x );
- sessionStorage.removeItem( x );
- return true;
- } catch( e ) {
- return false;
- }
- }())
- },
- /**
- * Provides a normalized error string, correcting an issue
- * with IE 7 (and prior) where Error.prototype.toString is
- * not properly implemented
- *
- * Based on http://es5.github.com/#x15.11.4.4
- *
- * @param {String|Error} error
- * @return {String} error message
- */
- errorString = function( error ) {
- var name, message,
- errorString = error.toString();
- if ( errorString.substring( 0, 7 ) === "[object" ) {
- name = error.name ? error.name.toString() : "Error";
- message = error.message ? error.message.toString() : "";
- if ( name && message ) {
- return name + ": " + message;
- } else if ( name ) {
- return name;
- } else if ( message ) {
- return message;
- } else {
- return "Error";
- }
- } else {
- return errorString;
- }
- },
- /**
- * Makes a clone of an object using only Array or Object as base,
- * and copies over the own enumerable properties.
- *
- * @param {Object} obj
- * @return {Object} New object with only the own properties (recursively).
- */
- objectValues = function( obj ) {
- // Grunt 0.3.x uses an older version of jshint that still has jshint/jshint#392.
- /*jshint newcap: false */
- var key, val,
- vals = QUnit.is( "array", obj ) ? [] : {};
- for ( key in obj ) {
- if ( hasOwn.call( obj, key ) ) {
- val = obj[key];
- vals[key] = val === Object(val) ? objectValues(val) : val;
- }
- }
- return vals;
- };
-
-function Test( settings ) {
- extend( this, settings );
- this.assertions = [];
- this.testNumber = ++Test.count;
-}
-
-Test.count = 0;
-
-Test.prototype = {
- init: function() {
- var a, b, li,
- tests = id( "qunit-tests" );
-
- if ( tests ) {
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml;
-
- // `a` initialized at top of scope
- a = document.createElement( "a" );
- a.innerHTML = "Rerun";
- a.href = QUnit.url({ testNumber: this.testNumber });
-
- li = document.createElement( "li" );
- li.appendChild( b );
- li.appendChild( a );
- li.className = "running";
- li.id = this.id = "qunit-test-output" + testId++;
-
- tests.appendChild( li );
- }
- },
- setup: function() {
- if ( this.module !== config.previousModule ) {
- if ( config.previousModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.previousModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
- config.previousModule = this.module;
- config.moduleStats = { all: 0, bad: 0 };
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- } else if ( config.autorun ) {
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- }
-
- config.current = this;
-
- this.testEnvironment = extend({
- setup: function() {},
- teardown: function() {}
- }, this.moduleTestEnvironment );
-
- this.started = +new Date();
- runLoggingCallbacks( "testStart", QUnit, {
- name: this.testName,
- module: this.module
- });
-
- // allow utility functions to access the current test environment
- // TODO why??
- QUnit.current_testEnvironment = this.testEnvironment;
-
- if ( !config.pollution ) {
- saveGlobal();
- }
- if ( config.notrycatch ) {
- this.testEnvironment.setup.call( this.testEnvironment );
- return;
- }
- try {
- this.testEnvironment.setup.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Setup failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- },
- run: function() {
- config.current = this;
-
- var running = id( "qunit-testresult" );
-
- if ( running ) {
- running.innerHTML = "Running:
" + this.nameHtml;
- }
-
- if ( this.async ) {
- QUnit.stop();
- }
-
- this.callbackStarted = +new Date();
-
- if ( config.notrycatch ) {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- return;
- }
-
- try {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- } catch( e ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
-
- QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + " " + this.stack + ": " + ( e.message || e ), extractStacktrace( e, 0 ) );
- // else next test will carry the responsibility
- saveGlobal();
-
- // Restart the tests if they're blocking
- if ( config.blocking ) {
- QUnit.start();
- }
- }
- },
- teardown: function() {
- config.current = this;
- if ( config.notrycatch ) {
- if ( typeof this.callbackRuntime === "undefined" ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
- }
- this.testEnvironment.teardown.call( this.testEnvironment );
- return;
- } else {
- try {
- this.testEnvironment.teardown.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Teardown failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- }
- checkPollution();
- },
- finish: function() {
- config.current = this;
- if ( config.requireExpects && this.expected === null ) {
- QUnit.pushFailure( "Expected number of assertions to be defined, but expect() was not called.", this.stack );
- } else if ( this.expected !== null && this.expected !== this.assertions.length ) {
- QUnit.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack );
- } else if ( this.expected === null && !this.assertions.length ) {
- QUnit.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions.", this.stack );
- }
-
- var i, assertion, a, b, time, li, ol,
- test = this,
- good = 0,
- bad = 0,
- tests = id( "qunit-tests" );
-
- this.runtime = +new Date() - this.started;
- config.stats.all += this.assertions.length;
- config.moduleStats.all += this.assertions.length;
-
- if ( tests ) {
- ol = document.createElement( "ol" );
- ol.className = "qunit-assert-list";
-
- for ( i = 0; i < this.assertions.length; i++ ) {
- assertion = this.assertions[i];
-
- li = document.createElement( "li" );
- li.className = assertion.result ? "pass" : "fail";
- li.innerHTML = assertion.message || ( assertion.result ? "okay" : "failed" );
- ol.appendChild( li );
-
- if ( assertion.result ) {
- good++;
- } else {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
-
- // store result when possible
- if ( QUnit.config.reorder && defined.sessionStorage ) {
- if ( bad ) {
- sessionStorage.setItem( "qunit-test-" + this.module + "-" + this.testName, bad );
- } else {
- sessionStorage.removeItem( "qunit-test-" + this.module + "-" + this.testName );
- }
- }
-
- if ( bad === 0 ) {
- addClass( ol, "qunit-collapsed" );
- }
-
- // `b` initialized at top of scope
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml + " (" + bad + ", " + good + ", " + this.assertions.length + ")";
-
- addEvent(b, "click", function() {
- var next = b.parentNode.lastChild,
- collapsed = hasClass( next, "qunit-collapsed" );
- ( collapsed ? removeClass : addClass )( next, "qunit-collapsed" );
- });
-
- addEvent(b, "dblclick", function( e ) {
- var target = e && e.target ? e.target : window.event.srcElement;
- if ( target.nodeName.toLowerCase() === "span" || target.nodeName.toLowerCase() === "b" ) {
- target = target.parentNode;
- }
- if ( window.location && target.nodeName.toLowerCase() === "strong" ) {
- window.location = QUnit.url({ testNumber: test.testNumber });
- }
- });
-
- // `time` initialized at top of scope
- time = document.createElement( "span" );
- time.className = "runtime";
- time.innerHTML = this.runtime + " ms";
-
- // `li` initialized at top of scope
- li = id( this.id );
- li.className = bad ? "fail" : "pass";
- li.removeChild( li.firstChild );
- a = li.firstChild;
- li.appendChild( b );
- li.appendChild( a );
- li.appendChild( time );
- li.appendChild( ol );
-
- } else {
- for ( i = 0; i < this.assertions.length; i++ ) {
- if ( !this.assertions[i].result ) {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
- }
-
- runLoggingCallbacks( "testDone", QUnit, {
- name: this.testName,
- module: this.module,
- failed: bad,
- passed: this.assertions.length - bad,
- total: this.assertions.length,
- duration: this.runtime
- });
-
- QUnit.reset();
-
- config.current = undefined;
- },
-
- queue: function() {
- var bad,
- test = this;
-
- synchronize(function() {
- test.init();
- });
- function run() {
- // each of these can by async
- synchronize(function() {
- test.setup();
- });
- synchronize(function() {
- test.run();
- });
- synchronize(function() {
- test.teardown();
- });
- synchronize(function() {
- test.finish();
- });
- }
-
- // `bad` initialized at top of scope
- // defer when previous test run passed, if storage is available
- bad = QUnit.config.reorder && defined.sessionStorage &&
- +sessionStorage.getItem( "qunit-test-" + this.module + "-" + this.testName );
-
- if ( bad ) {
- run();
- } else {
- synchronize( run, true );
- }
- }
-};
-
-// Root QUnit object.
-// `QUnit` initialized at top of scope
-QUnit = {
-
- // call on start of module test to prepend name to all tests
- module: function( name, testEnvironment ) {
- config.currentModule = name;
- config.currentModuleTestEnvironment = testEnvironment;
- config.modules[name] = true;
- },
-
- asyncTest: function( testName, expected, callback ) {
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- QUnit.test( testName, expected, callback, true );
- },
-
- test: function( testName, expected, callback, async ) {
- var test,
- nameHtml = "" + escapeText( testName ) + "";
-
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- if ( config.currentModule ) {
- nameHtml = "" + escapeText( config.currentModule ) + ": " + nameHtml;
- }
-
- test = new Test({
- nameHtml: nameHtml,
- testName: testName,
- expected: expected,
- async: async,
- callback: callback,
- module: config.currentModule,
- moduleTestEnvironment: config.currentModuleTestEnvironment,
- stack: sourceFromStacktrace( 2 )
- });
-
- if ( !validTest( test ) ) {
- return;
- }
-
- test.queue();
- },
-
- // Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through.
- expect: function( asserts ) {
- if (arguments.length === 1) {
- config.current.expected = asserts;
- } else {
- return config.current.expected;
- }
- },
-
- start: function( count ) {
- // QUnit hasn't been initialized yet.
- // Note: RequireJS (et al) may delay onLoad
- if ( config.semaphore === undefined ) {
- QUnit.begin(function() {
- // This is triggered at the top of QUnit.load, push start() to the event loop, to allow QUnit.load to finish first
- setTimeout(function() {
- QUnit.start( count );
- });
- });
- return;
- }
-
- config.semaphore -= count || 1;
- // don't start until equal number of stop-calls
- if ( config.semaphore > 0 ) {
- return;
- }
- // ignore if start is called more often then stop
- if ( config.semaphore < 0 ) {
- config.semaphore = 0;
- QUnit.pushFailure( "Called start() while already started (QUnit.config.semaphore was 0 already)", null, sourceFromStacktrace(2) );
- return;
- }
- // A slight delay, to avoid any current callbacks
- if ( defined.setTimeout ) {
- window.setTimeout(function() {
- if ( config.semaphore > 0 ) {
- return;
- }
- if ( config.timeout ) {
- clearTimeout( config.timeout );
- }
-
- config.blocking = false;
- process( true );
- }, 13);
- } else {
- config.blocking = false;
- process( true );
- }
- },
-
- stop: function( count ) {
- config.semaphore += count || 1;
- config.blocking = true;
-
- if ( config.testTimeout && defined.setTimeout ) {
- clearTimeout( config.timeout );
- config.timeout = window.setTimeout(function() {
- QUnit.ok( false, "Test timed out" );
- config.semaphore = 1;
- QUnit.start();
- }, config.testTimeout );
- }
- }
-};
-
-// `assert` initialized at top of scope
-// Asssert helpers
-// All of these must either call QUnit.push() or manually do:
-// - runLoggingCallbacks( "log", .. );
-// - config.current.assertions.push({ .. });
-// We attach it to the QUnit object *after* we expose the public API,
-// otherwise `assert` will become a global variable in browsers (#341).
-assert = {
- /**
- * Asserts rough true-ish result.
- * @name ok
- * @function
- * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" );
- */
- ok: function( result, msg ) {
- if ( !config.current ) {
- throw new Error( "ok() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
- result = !!result;
-
- var source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: msg
- };
-
- msg = escapeText( msg || (result ? "okay" : "failed" ) );
- msg = "" + msg + "";
-
- if ( !result ) {
- source = sourceFromStacktrace( 2 );
- if ( source ) {
- details.source = source;
- msg += "Source: | " + escapeText( source ) + " |
---|
";
- }
- }
- runLoggingCallbacks( "log", QUnit, details );
- config.current.assertions.push({
- result: result,
- message: msg
- });
- },
-
- /**
- * Assert that the first two arguments are equal, with an optional message.
- * Prints out both actual and expected values.
- * @name equal
- * @function
- * @example equal( format( "Received {0} bytes.", 2), "Received 2 bytes.", "format() replaces {0} with next argument" );
- */
- equal: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected == actual, actual, expected, message );
- },
-
- /**
- * @name notEqual
- * @function
- */
- notEqual: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected != actual, actual, expected, message );
- },
-
- /**
- * @name propEqual
- * @function
- */
- propEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notPropEqual
- * @function
- */
- notPropEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name deepEqual
- * @function
- */
- deepEqual: function( actual, expected, message ) {
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notDeepEqual
- * @function
- */
- notDeepEqual: function( actual, expected, message ) {
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name strictEqual
- * @function
- */
- strictEqual: function( actual, expected, message ) {
- QUnit.push( expected === actual, actual, expected, message );
- },
-
- /**
- * @name notStrictEqual
- * @function
- */
- notStrictEqual: function( actual, expected, message ) {
- QUnit.push( expected !== actual, actual, expected, message );
- },
-
- "throws": function( block, expected, message ) {
- var actual,
- expectedOutput = expected,
- ok = false;
-
- // 'expected' is optional
- if ( typeof expected === "string" ) {
- message = expected;
- expected = null;
- }
-
- config.current.ignoreGlobalErrors = true;
- try {
- block.call( config.current.testEnvironment );
- } catch (e) {
- actual = e;
- }
- config.current.ignoreGlobalErrors = false;
-
- if ( actual ) {
- // we don't want to validate thrown error
- if ( !expected ) {
- ok = true;
- expectedOutput = null;
- // expected is a regexp
- } else if ( QUnit.objectType( expected ) === "regexp" ) {
- ok = expected.test( errorString( actual ) );
- // expected is a constructor
- } else if ( actual instanceof expected ) {
- ok = true;
- // expected is a validation function which returns true is validation passed
- } else if ( expected.call( {}, actual ) === true ) {
- expectedOutput = null;
- ok = true;
- }
-
- QUnit.push( ok, actual, expectedOutput, message );
- } else {
- QUnit.pushFailure( message, null, 'No exception was thrown.' );
- }
- }
-};
-
-/**
- * @deprecate since 1.8.0
- * Kept assertion helpers in root for backwards compatibility.
- */
-extend( QUnit, assert );
-
-/**
- * @deprecated since 1.9.0
- * Kept root "raises()" for backwards compatibility.
- * (Note that we don't introduce assert.raises).
- */
-QUnit.raises = assert[ "throws" ];
-
-/**
- * @deprecated since 1.0.0, replaced with error pushes since 1.3.0
- * Kept to avoid TypeErrors for undefined methods.
- */
-QUnit.equals = function() {
- QUnit.push( false, false, false, "QUnit.equals has been deprecated since 2009 (e88049a0), use QUnit.equal instead" );
-};
-QUnit.same = function() {
- QUnit.push( false, false, false, "QUnit.same has been deprecated since 2009 (e88049a0), use QUnit.deepEqual instead" );
-};
-
-// We want access to the constructor's prototype
-(function() {
- function F() {}
- F.prototype = QUnit;
- QUnit = new F();
- // Make F QUnit's constructor so that we can add to the prototype later
- QUnit.constructor = F;
-}());
-
-/**
- * Config object: Maintain internal state
- * Later exposed as QUnit.config
- * `config` initialized at top of scope
- */
-config = {
- // The queue of tests to run
- queue: [],
-
- // block until document ready
- blocking: true,
-
- // when enabled, show only failing tests
- // gets persisted through sessionStorage and can be changed in UI via checkbox
- hidepassed: false,
-
- // by default, run previously failed tests first
- // very useful in combination with "Hide passed tests" checked
- reorder: true,
-
- // by default, modify document.title when suite is done
- altertitle: true,
-
- // when enabled, all tests must call expect()
- requireExpects: false,
-
- // add checkboxes that are persisted in the query-string
- // when enabled, the id is set to `true` as a `QUnit.config` property
- urlConfig: [
- {
- id: "noglobals",
- label: "Check for Globals",
- tooltip: "Enabling this will test if any test introduces new properties on the `window` object. Stored as query-strings."
- },
- {
- id: "notrycatch",
- label: "No try-catch",
- tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging exceptions in IE reasonable. Stored as query-strings."
- }
- ],
-
- // Set of all modules.
- modules: {},
-
- // logging callback queues
- begin: [],
- done: [],
- log: [],
- testStart: [],
- testDone: [],
- moduleStart: [],
- moduleDone: []
-};
-
-// Export global variables, unless an 'exports' object exists,
-// in that case we assume we're in CommonJS (dealt with on the bottom of the script)
-if ( typeof exports === "undefined" ) {
- extend( window, QUnit );
-
- // Expose QUnit object
- window.QUnit = QUnit;
-}
-
-// Initialize more QUnit.config and QUnit.urlParams
-(function() {
- var i,
- location = window.location || { search: "", protocol: "file:" },
- params = location.search.slice( 1 ).split( "&" ),
- length = params.length,
- urlParams = {},
- current;
-
- if ( params[ 0 ] ) {
- for ( i = 0; i < length; i++ ) {
- current = params[ i ].split( "=" );
- current[ 0 ] = decodeURIComponent( current[ 0 ] );
- // allow just a key to turn on a flag, e.g., test.html?noglobals
- current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true;
- urlParams[ current[ 0 ] ] = current[ 1 ];
- }
- }
-
- QUnit.urlParams = urlParams;
-
- // String search anywhere in moduleName+testName
- config.filter = urlParams.filter;
-
- // Exact match of the module name
- config.module = urlParams.module;
-
- config.testNumber = parseInt( urlParams.testNumber, 10 ) || null;
-
- // Figure out if we're running the tests from a server or not
- QUnit.isLocal = location.protocol === "file:";
-}());
-
-// Extend QUnit object,
-// these after set here because they should not be exposed as global functions
-extend( QUnit, {
- assert: assert,
-
- config: config,
-
- // Initialize the configuration options
- init: function() {
- extend( config, {
- stats: { all: 0, bad: 0 },
- moduleStats: { all: 0, bad: 0 },
- started: +new Date(),
- updateRate: 1000,
- blocking: false,
- autostart: true,
- autorun: false,
- filter: "",
- queue: [],
- semaphore: 1
- });
-
- var tests, banner, result,
- qunit = id( "qunit" );
-
- if ( qunit ) {
- qunit.innerHTML =
- "" +
- "" +
- "" +
- "" +
- "
";
- }
-
- tests = id( "qunit-tests" );
- banner = id( "qunit-banner" );
- result = id( "qunit-testresult" );
-
- if ( tests ) {
- tests.innerHTML = "";
- }
-
- if ( banner ) {
- banner.className = "";
- }
-
- if ( result ) {
- result.parentNode.removeChild( result );
- }
-
- if ( tests ) {
- result = document.createElement( "p" );
- result.id = "qunit-testresult";
- result.className = "result";
- tests.parentNode.insertBefore( result, tests );
- result.innerHTML = "Running...
";
- }
- },
-
- // Resets the test setup. Useful for tests that modify the DOM.
- reset: function() {
- var fixture = id( "qunit-fixture" );
- if ( fixture ) {
- fixture.innerHTML = config.fixture;
- }
- },
-
- // Trigger an event on an element.
- // @example triggerEvent( document.body, "click" );
- triggerEvent: function( elem, type, event ) {
- if ( document.createEvent ) {
- event = document.createEvent( "MouseEvents" );
- event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView,
- 0, 0, 0, 0, 0, false, false, false, false, 0, null);
-
- elem.dispatchEvent( event );
- } else if ( elem.fireEvent ) {
- elem.fireEvent( "on" + type );
- }
- },
-
- // Safe object type checking
- is: function( type, obj ) {
- return QUnit.objectType( obj ) === type;
- },
-
- objectType: function( obj ) {
- if ( typeof obj === "undefined" ) {
- return "undefined";
- // consider: typeof null === object
- }
- if ( obj === null ) {
- return "null";
- }
-
- var match = toString.call( obj ).match(/^\[object\s(.*)\]$/),
- type = match && match[1] || "";
-
- switch ( type ) {
- case "Number":
- if ( isNaN(obj) ) {
- return "nan";
- }
- return "number";
- case "String":
- case "Boolean":
- case "Array":
- case "Date":
- case "RegExp":
- case "Function":
- return type.toLowerCase();
- }
- if ( typeof obj === "object" ) {
- return "object";
- }
- return undefined;
- },
-
- push: function( result, actual, expected, message ) {
- if ( !config.current ) {
- throw new Error( "assertion outside test context, was " + sourceFromStacktrace() );
- }
-
- var output, source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: message,
- actual: actual,
- expected: expected
- };
-
- message = escapeText( message ) || ( result ? "okay" : "failed" );
- message = "" + message + "";
- output = message;
-
- if ( !result ) {
- expected = escapeText( QUnit.jsDump.parse(expected) );
- actual = escapeText( QUnit.jsDump.parse(actual) );
- output += "Expected: | " + expected + " |
";
-
- if ( actual !== expected ) {
- output += "Result: | " + actual + " |
";
- output += "Diff: | " + QUnit.diff( expected, actual ) + " |
";
- }
-
- source = sourceFromStacktrace();
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
- }
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: !!result,
- message: output
- });
- },
-
- pushFailure: function( message, source, actual ) {
- if ( !config.current ) {
- throw new Error( "pushFailure() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
-
- var output,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: false,
- message: message
- };
-
- message = escapeText( message ) || "error";
- message = "" + message + "";
- output = message;
-
- output += "";
-
- if ( actual ) {
- output += "Result: | " + escapeText( actual ) + " |
";
- }
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: false,
- message: output
- });
- },
-
- url: function( params ) {
- params = extend( extend( {}, QUnit.urlParams ), params );
- var key,
- querystring = "?";
-
- for ( key in params ) {
- if ( !hasOwn.call( params, key ) ) {
- continue;
- }
- querystring += encodeURIComponent( key ) + "=" +
- encodeURIComponent( params[ key ] ) + "&";
- }
- return window.location.protocol + "//" + window.location.host +
- window.location.pathname + querystring.slice( 0, -1 );
- },
-
- extend: extend,
- id: id,
- addEvent: addEvent
- // load, equiv, jsDump, diff: Attached later
-});
-
-/**
- * @deprecated: Created for backwards compatibility with test runner that set the hook function
- * into QUnit.{hook}, instead of invoking it and passing the hook function.
- * QUnit.constructor is set to the empty F() above so that we can add to it's prototype here.
- * Doing this allows us to tell if the following methods have been overwritten on the actual
- * QUnit object.
- */
-extend( QUnit.constructor.prototype, {
-
- // Logging callbacks; all receive a single argument with the listed properties
- // run test/logs.html for any related changes
- begin: registerLoggingCallback( "begin" ),
-
- // done: { failed, passed, total, runtime }
- done: registerLoggingCallback( "done" ),
-
- // log: { result, actual, expected, message }
- log: registerLoggingCallback( "log" ),
-
- // testStart: { name }
- testStart: registerLoggingCallback( "testStart" ),
-
- // testDone: { name, failed, passed, total, duration }
- testDone: registerLoggingCallback( "testDone" ),
-
- // moduleStart: { name }
- moduleStart: registerLoggingCallback( "moduleStart" ),
-
- // moduleDone: { name, failed, passed, total }
- moduleDone: registerLoggingCallback( "moduleDone" )
-});
-
-if ( typeof document === "undefined" || document.readyState === "complete" ) {
- config.autorun = true;
-}
-
-QUnit.load = function() {
- runLoggingCallbacks( "begin", QUnit, {} );
-
- // Initialize the config, saving the execution queue
- var banner, filter, i, label, len, main, ol, toolbar, userAgent, val,
- urlConfigCheckboxesContainer, urlConfigCheckboxes, moduleFilter,
- numModules = 0,
- moduleFilterHtml = "",
- urlConfigHtml = "",
- oldconfig = extend( {}, config );
-
- QUnit.init();
- extend(config, oldconfig);
-
- config.blocking = false;
-
- len = config.urlConfig.length;
-
- for ( i = 0; i < len; i++ ) {
- val = config.urlConfig[i];
- if ( typeof val === "string" ) {
- val = {
- id: val,
- label: val,
- tooltip: "[no tooltip available]"
- };
- }
- config[ val.id ] = QUnit.urlParams[ val.id ];
- urlConfigHtml += "";
- }
-
- moduleFilterHtml += "";
-
- // `userAgent` initialized at top of scope
- userAgent = id( "qunit-userAgent" );
- if ( userAgent ) {
- userAgent.innerHTML = navigator.userAgent;
- }
-
- // `banner` initialized at top of scope
- banner = id( "qunit-header" );
- if ( banner ) {
- banner.innerHTML = "" + banner.innerHTML + " ";
- }
-
- // `toolbar` initialized at top of scope
- toolbar = id( "qunit-testrunner-toolbar" );
- if ( toolbar ) {
- // `filter` initialized at top of scope
- filter = document.createElement( "input" );
- filter.type = "checkbox";
- filter.id = "qunit-filter-pass";
-
- addEvent( filter, "click", function() {
- var tmp,
- ol = document.getElementById( "qunit-tests" );
-
- if ( filter.checked ) {
- ol.className = ol.className + " hidepass";
- } else {
- tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " ";
- ol.className = tmp.replace( / hidepass /, " " );
- }
- if ( defined.sessionStorage ) {
- if (filter.checked) {
- sessionStorage.setItem( "qunit-filter-passed-tests", "true" );
- } else {
- sessionStorage.removeItem( "qunit-filter-passed-tests" );
- }
- }
- });
-
- if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem( "qunit-filter-passed-tests" ) ) {
- filter.checked = true;
- // `ol` initialized at top of scope
- ol = document.getElementById( "qunit-tests" );
- ol.className = ol.className + " hidepass";
- }
- toolbar.appendChild( filter );
-
- // `label` initialized at top of scope
- label = document.createElement( "label" );
- label.setAttribute( "for", "qunit-filter-pass" );
- label.setAttribute( "title", "Only show tests and assertons that fail. Stored in sessionStorage." );
- label.innerHTML = "Hide passed tests";
- toolbar.appendChild( label );
-
- urlConfigCheckboxesContainer = document.createElement("span");
- urlConfigCheckboxesContainer.innerHTML = urlConfigHtml;
- urlConfigCheckboxes = urlConfigCheckboxesContainer.getElementsByTagName("input");
- // For oldIE support:
- // * Add handlers to the individual elements instead of the container
- // * Use "click" instead of "change"
- // * Fallback from event.target to event.srcElement
- addEvents( urlConfigCheckboxes, "click", function( event ) {
- var params = {},
- target = event.target || event.srcElement;
- params[ target.name ] = target.checked ? true : undefined;
- window.location = QUnit.url( params );
- });
- toolbar.appendChild( urlConfigCheckboxesContainer );
-
- if (numModules > 1) {
- moduleFilter = document.createElement( 'span' );
- moduleFilter.setAttribute( 'id', 'qunit-modulefilter-container' );
- moduleFilter.innerHTML = moduleFilterHtml;
- addEvent( moduleFilter.lastChild, "change", function() {
- var selectBox = moduleFilter.getElementsByTagName("select")[0],
- selectedModule = decodeURIComponent(selectBox.options[selectBox.selectedIndex].value);
-
- window.location = QUnit.url( { module: ( selectedModule === "" ) ? undefined : selectedModule } );
- });
- toolbar.appendChild(moduleFilter);
- }
- }
-
- // `main` initialized at top of scope
- main = id( "qunit-fixture" );
- if ( main ) {
- config.fixture = main.innerHTML;
- }
-
- if ( config.autostart ) {
- QUnit.start();
- }
-};
-
-addEvent( window, "load", QUnit.load );
-
-// `onErrorFnPrev` initialized at top of scope
-// Preserve other handlers
-onErrorFnPrev = window.onerror;
-
-// Cover uncaught exceptions
-// Returning true will surpress the default browser handler,
-// returning false will let it run.
-window.onerror = function ( error, filePath, linerNr ) {
- var ret = false;
- if ( onErrorFnPrev ) {
- ret = onErrorFnPrev( error, filePath, linerNr );
- }
-
- // Treat return value as window.onerror itself does,
- // Only do our handling if not surpressed.
- if ( ret !== true ) {
- if ( QUnit.config.current ) {
- if ( QUnit.config.current.ignoreGlobalErrors ) {
- return true;
- }
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- } else {
- QUnit.test( "global failure", extend( function() {
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- }, { validTest: validTest } ) );
- }
- return false;
- }
-
- return ret;
-};
-
-function done() {
- config.autorun = true;
-
- // Log the last module results
- if ( config.currentModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.currentModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
-
- var i, key,
- banner = id( "qunit-banner" ),
- tests = id( "qunit-tests" ),
- runtime = +new Date() - config.started,
- passed = config.stats.all - config.stats.bad,
- html = [
- "Tests completed in ",
- runtime,
- " milliseconds.
",
- "",
- passed,
- " assertions of ",
- config.stats.all,
- " passed, ",
- config.stats.bad,
- " failed."
- ].join( "" );
-
- if ( banner ) {
- banner.className = ( config.stats.bad ? "qunit-fail" : "qunit-pass" );
- }
-
- if ( tests ) {
- id( "qunit-testresult" ).innerHTML = html;
- }
-
- if ( config.altertitle && typeof document !== "undefined" && document.title ) {
- // show ✖ for good, ✔ for bad suite result in title
- // use escape sequences in case file gets loaded with non-utf-8-charset
- document.title = [
- ( config.stats.bad ? "\u2716" : "\u2714" ),
- document.title.replace( /^[\u2714\u2716] /i, "" )
- ].join( " " );
- }
-
- // clear own sessionStorage items if all tests passed
- if ( config.reorder && defined.sessionStorage && config.stats.bad === 0 ) {
- // `key` & `i` initialized at top of scope
- for ( i = 0; i < sessionStorage.length; i++ ) {
- key = sessionStorage.key( i++ );
- if ( key.indexOf( "qunit-test-" ) === 0 ) {
- sessionStorage.removeItem( key );
- }
- }
- }
-
- // scroll back to top to show results
- if ( window.scrollTo ) {
- window.scrollTo(0, 0);
- }
-
- runLoggingCallbacks( "done", QUnit, {
- failed: config.stats.bad,
- passed: passed,
- total: config.stats.all,
- runtime: runtime
- });
-}
-
-/** @return Boolean: true if this test should be ran */
-function validTest( test ) {
- var include,
- filter = config.filter && config.filter.toLowerCase(),
- module = config.module && config.module.toLowerCase(),
- fullName = (test.module + ": " + test.testName).toLowerCase();
-
- // Internally-generated tests are always valid
- if ( test.callback && test.callback.validTest === validTest ) {
- delete test.callback.validTest;
- return true;
- }
-
- if ( config.testNumber ) {
- return test.testNumber === config.testNumber;
- }
-
- if ( module && ( !test.module || test.module.toLowerCase() !== module ) ) {
- return false;
- }
-
- if ( !filter ) {
- return true;
- }
-
- include = filter.charAt( 0 ) !== "!";
- if ( !include ) {
- filter = filter.slice( 1 );
- }
-
- // If the filter matches, we need to honour include
- if ( fullName.indexOf( filter ) !== -1 ) {
- return include;
- }
-
- // Otherwise, do the opposite
- return !include;
-}
-
-// so far supports only Firefox, Chrome and Opera (buggy), Safari (for real exceptions)
-// Later Safari and IE10 are supposed to support error.stack as well
-// See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack
-function extractStacktrace( e, offset ) {
- offset = offset === undefined ? 3 : offset;
-
- var stack, include, i;
-
- if ( e.stacktrace ) {
- // Opera
- return e.stacktrace.split( "\n" )[ offset + 3 ];
- } else if ( e.stack ) {
- // Firefox, Chrome
- stack = e.stack.split( "\n" );
- if (/^error$/i.test( stack[0] ) ) {
- stack.shift();
- }
- if ( fileName ) {
- include = [];
- for ( i = offset; i < stack.length; i++ ) {
- if ( stack[ i ].indexOf( fileName ) !== -1 ) {
- break;
- }
- include.push( stack[ i ] );
- }
- if ( include.length ) {
- return include.join( "\n" );
- }
- }
- return stack[ offset ];
- } else if ( e.sourceURL ) {
- // Safari, PhantomJS
- // hopefully one day Safari provides actual stacktraces
- // exclude useless self-reference for generated Error objects
- if ( /qunit.js$/.test( e.sourceURL ) ) {
- return;
- }
- // for actual exceptions, this is useful
- return e.sourceURL + ":" + e.line;
- }
-}
-function sourceFromStacktrace( offset ) {
- try {
- throw new Error();
- } catch ( e ) {
- return extractStacktrace( e, offset );
- }
-}
-
-/**
- * Escape text for attribute or text content.
- */
-function escapeText( s ) {
- if ( !s ) {
- return "";
- }
- s = s + "";
- // Both single quotes and double quotes (for attributes)
- return s.replace( /['"<>&]/g, function( s ) {
- switch( s ) {
- case '\'':
- return ''';
- case '"':
- return '"';
- case '<':
- return '<';
- case '>':
- return '>';
- case '&':
- return '&';
- }
- });
-}
-
-function synchronize( callback, last ) {
- config.queue.push( callback );
-
- if ( config.autorun && !config.blocking ) {
- process( last );
- }
-}
-
-function process( last ) {
- function next() {
- process( last );
- }
- var start = new Date().getTime();
- config.depth = config.depth ? config.depth + 1 : 1;
-
- while ( config.queue.length && !config.blocking ) {
- if ( !defined.setTimeout || config.updateRate <= 0 || ( ( new Date().getTime() - start ) < config.updateRate ) ) {
- config.queue.shift()();
- } else {
- window.setTimeout( next, 13 );
- break;
- }
- }
- config.depth--;
- if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) {
- done();
- }
-}
-
-function saveGlobal() {
- config.pollution = [];
-
- if ( config.noglobals ) {
- for ( var key in window ) {
- // in Opera sometimes DOM element ids show up here, ignore them
- if ( !hasOwn.call( window, key ) || /^qunit-test-output/.test( key ) ) {
- continue;
- }
- config.pollution.push( key );
- }
- }
-}
-
-function checkPollution() {
- var newGlobals,
- deletedGlobals,
- old = config.pollution;
-
- saveGlobal();
-
- newGlobals = diff( config.pollution, old );
- if ( newGlobals.length > 0 ) {
- QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join(", ") );
- }
-
- deletedGlobals = diff( old, config.pollution );
- if ( deletedGlobals.length > 0 ) {
- QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join(", ") );
- }
-}
-
-// returns a new Array with the elements that are in a but not in b
-function diff( a, b ) {
- var i, j,
- result = a.slice();
-
- for ( i = 0; i < result.length; i++ ) {
- for ( j = 0; j < b.length; j++ ) {
- if ( result[i] === b[j] ) {
- result.splice( i, 1 );
- i--;
- break;
- }
- }
- }
- return result;
-}
-
-function extend( a, b ) {
- for ( var prop in b ) {
- if ( b[ prop ] === undefined ) {
- delete a[ prop ];
-
- // Avoid "Member not found" error in IE8 caused by setting window.constructor
- } else if ( prop !== "constructor" || a !== window ) {
- a[ prop ] = b[ prop ];
- }
- }
-
- return a;
-}
-
-/**
- * @param {HTMLElement} elem
- * @param {string} type
- * @param {Function} fn
- */
-function addEvent( elem, type, fn ) {
- // Standards-based browsers
- if ( elem.addEventListener ) {
- elem.addEventListener( type, fn, false );
- // IE
- } else {
- elem.attachEvent( "on" + type, fn );
- }
-}
-
-/**
- * @param {Array|NodeList} elems
- * @param {string} type
- * @param {Function} fn
- */
-function addEvents( elems, type, fn ) {
- var i = elems.length;
- while ( i-- ) {
- addEvent( elems[i], type, fn );
- }
-}
-
-function hasClass( elem, name ) {
- return (" " + elem.className + " ").indexOf(" " + name + " ") > -1;
-}
-
-function addClass( elem, name ) {
- if ( !hasClass( elem, name ) ) {
- elem.className += (elem.className ? " " : "") + name;
- }
-}
-
-function removeClass( elem, name ) {
- var set = " " + elem.className + " ";
- // Class name may appear multiple times
- while ( set.indexOf(" " + name + " ") > -1 ) {
- set = set.replace(" " + name + " " , " ");
- }
- // If possible, trim it for prettiness, but not neccecarily
- elem.className = window.jQuery ? jQuery.trim( set ) : ( set.trim ? set.trim() : set );
-}
-
-function id( name ) {
- return !!( typeof document !== "undefined" && document && document.getElementById ) &&
- document.getElementById( name );
-}
-
-function registerLoggingCallback( key ) {
- return function( callback ) {
- config[key].push( callback );
- };
-}
-
-// Supports deprecated method of completely overwriting logging callbacks
-function runLoggingCallbacks( key, scope, args ) {
- var i, callbacks;
- if ( QUnit.hasOwnProperty( key ) ) {
- QUnit[ key ].call(scope, args );
- } else {
- callbacks = config[ key ];
- for ( i = 0; i < callbacks.length; i++ ) {
- callbacks[ i ].call( scope, args );
- }
- }
-}
-
-// Test for equality any JavaScript type.
-// Author: Philippe Rathé
-QUnit.equiv = (function() {
-
- // Call the o related callback with the given arguments.
- function bindCallbacks( o, callbacks, args ) {
- var prop = QUnit.objectType( o );
- if ( prop ) {
- if ( QUnit.objectType( callbacks[ prop ] ) === "function" ) {
- return callbacks[ prop ].apply( callbacks, args );
- } else {
- return callbacks[ prop ]; // or undefined
- }
- }
- }
-
- // the real equiv function
- var innerEquiv,
- // stack to decide between skip/abort functions
- callers = [],
- // stack to avoiding loops from circular referencing
- parents = [],
-
- getProto = Object.getPrototypeOf || function ( obj ) {
- return obj.__proto__;
- },
- callbacks = (function () {
-
- // for string, boolean, number and null
- function useStrictEquality( b, a ) {
- /*jshint eqeqeq:false */
- if ( b instanceof a.constructor || a instanceof b.constructor ) {
- // to catch short annotaion VS 'new' annotation of a
- // declaration
- // e.g. var i = 1;
- // var j = new Number(1);
- return a == b;
- } else {
- return a === b;
- }
- }
-
- return {
- "string": useStrictEquality,
- "boolean": useStrictEquality,
- "number": useStrictEquality,
- "null": useStrictEquality,
- "undefined": useStrictEquality,
-
- "nan": function( b ) {
- return isNaN( b );
- },
-
- "date": function( b, a ) {
- return QUnit.objectType( b ) === "date" && a.valueOf() === b.valueOf();
- },
-
- "regexp": function( b, a ) {
- return QUnit.objectType( b ) === "regexp" &&
- // the regex itself
- a.source === b.source &&
- // and its modifers
- a.global === b.global &&
- // (gmi) ...
- a.ignoreCase === b.ignoreCase &&
- a.multiline === b.multiline &&
- a.sticky === b.sticky;
- },
-
- // - skip when the property is a method of an instance (OOP)
- // - abort otherwise,
- // initial === would have catch identical references anyway
- "function": function() {
- var caller = callers[callers.length - 1];
- return caller !== Object && typeof caller !== "undefined";
- },
-
- "array": function( b, a ) {
- var i, j, len, loop;
-
- // b could be an object literal here
- if ( QUnit.objectType( b ) !== "array" ) {
- return false;
- }
-
- len = a.length;
- if ( len !== b.length ) {
- // safe and faster
- return false;
- }
-
- // track reference to avoid circular references
- parents.push( a );
- for ( i = 0; i < len; i++ ) {
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- loop = true;// dont rewalk array
- }
- }
- if ( !loop && !innerEquiv(a[i], b[i]) ) {
- parents.pop();
- return false;
- }
- }
- parents.pop();
- return true;
- },
-
- "object": function( b, a ) {
- var i, j, loop,
- // Default to true
- eq = true,
- aProperties = [],
- bProperties = [];
-
- // comparing constructors is more strict than using
- // instanceof
- if ( a.constructor !== b.constructor ) {
- // Allow objects with no prototype to be equivalent to
- // objects with Object as their constructor.
- if ( !(( getProto(a) === null && getProto(b) === Object.prototype ) ||
- ( getProto(b) === null && getProto(a) === Object.prototype ) ) ) {
- return false;
- }
- }
-
- // stack constructor before traversing properties
- callers.push( a.constructor );
- // track reference to avoid circular references
- parents.push( a );
-
- for ( i in a ) { // be strict: don't ensures hasOwnProperty
- // and go deep
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- // don't go down the same path twice
- loop = true;
- }
- }
- aProperties.push(i); // collect a's properties
-
- if (!loop && !innerEquiv( a[i], b[i] ) ) {
- eq = false;
- break;
- }
- }
-
- callers.pop(); // unstack, we are done
- parents.pop();
-
- for ( i in b ) {
- bProperties.push( i ); // collect b's properties
- }
-
- // Ensures identical properties name
- return eq && innerEquiv( aProperties.sort(), bProperties.sort() );
- }
- };
- }());
-
- innerEquiv = function() { // can take multiple arguments
- var args = [].slice.apply( arguments );
- if ( args.length < 2 ) {
- return true; // end transition
- }
-
- return (function( a, b ) {
- if ( a === b ) {
- return true; // catch the most you can
- } else if ( a === null || b === null || typeof a === "undefined" ||
- typeof b === "undefined" ||
- QUnit.objectType(a) !== QUnit.objectType(b) ) {
- return false; // don't lose time with error prone cases
- } else {
- return bindCallbacks(a, callbacks, [ b, a ]);
- }
-
- // apply transition with (1..n) arguments
- }( args[0], args[1] ) && arguments.callee.apply( this, args.splice(1, args.length - 1 )) );
- };
-
- return innerEquiv;
-}());
-
-/**
- * jsDump Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com |
- * http://flesler.blogspot.com Licensed under BSD
- * (http://www.opensource.org/licenses/bsd-license.php) Date: 5/15/2008
- *
- * @projectDescription Advanced and extensible data dumping for Javascript.
- * @version 1.0.0
- * @author Ariel Flesler
- * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html}
- */
-QUnit.jsDump = (function() {
- function quote( str ) {
- return '"' + str.toString().replace( /"/g, '\\"' ) + '"';
- }
- function literal( o ) {
- return o + "";
- }
- function join( pre, arr, post ) {
- var s = jsDump.separator(),
- base = jsDump.indent(),
- inner = jsDump.indent(1);
- if ( arr.join ) {
- arr = arr.join( "," + s + inner );
- }
- if ( !arr ) {
- return pre + post;
- }
- return [ pre, inner + arr, base + post ].join(s);
- }
- function array( arr, stack ) {
- var i = arr.length, ret = new Array(i);
- this.up();
- while ( i-- ) {
- ret[i] = this.parse( arr[i] , undefined , stack);
- }
- this.down();
- return join( "[", ret, "]" );
- }
-
- var reName = /^function (\w+)/,
- jsDump = {
- // type is used mostly internally, you can fix a (custom)type in advance
- parse: function( obj, type, stack ) {
- stack = stack || [ ];
- var inStack, res,
- parser = this.parsers[ type || this.typeOf(obj) ];
-
- type = typeof parser;
- inStack = inArray( obj, stack );
-
- if ( inStack !== -1 ) {
- return "recursion(" + (inStack - stack.length) + ")";
- }
- if ( type === "function" ) {
- stack.push( obj );
- res = parser.call( this, obj, stack );
- stack.pop();
- return res;
- }
- return ( type === "string" ) ? parser : this.parsers.error;
- },
- typeOf: function( obj ) {
- var type;
- if ( obj === null ) {
- type = "null";
- } else if ( typeof obj === "undefined" ) {
- type = "undefined";
- } else if ( QUnit.is( "regexp", obj) ) {
- type = "regexp";
- } else if ( QUnit.is( "date", obj) ) {
- type = "date";
- } else if ( QUnit.is( "function", obj) ) {
- type = "function";
- } else if ( typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined" ) {
- type = "window";
- } else if ( obj.nodeType === 9 ) {
- type = "document";
- } else if ( obj.nodeType ) {
- type = "node";
- } else if (
- // native arrays
- toString.call( obj ) === "[object Array]" ||
- // NodeList objects
- ( typeof obj.length === "number" && typeof obj.item !== "undefined" && ( obj.length ? obj.item(0) === obj[0] : ( obj.item( 0 ) === null && typeof obj[0] === "undefined" ) ) )
- ) {
- type = "array";
- } else if ( obj.constructor === Error.prototype.constructor ) {
- type = "error";
- } else {
- type = typeof obj;
- }
- return type;
- },
- separator: function() {
- return this.multiline ? this.HTML ? "
" : "\n" : this.HTML ? " " : " ";
- },
- // extra can be a number, shortcut for increasing-calling-decreasing
- indent: function( extra ) {
- if ( !this.multiline ) {
- return "";
- }
- var chr = this.indentChar;
- if ( this.HTML ) {
- chr = chr.replace( /\t/g, " " ).replace( / /g, " " );
- }
- return new Array( this._depth_ + (extra||0) ).join(chr);
- },
- up: function( a ) {
- this._depth_ += a || 1;
- },
- down: function( a ) {
- this._depth_ -= a || 1;
- },
- setParser: function( name, parser ) {
- this.parsers[name] = parser;
- },
- // The next 3 are exposed so you can use them
- quote: quote,
- literal: literal,
- join: join,
- //
- _depth_: 1,
- // This is the list of parsers, to modify them, use jsDump.setParser
- parsers: {
- window: "[Window]",
- document: "[Document]",
- error: function(error) {
- return "Error(\"" + error.message + "\")";
- },
- unknown: "[Unknown]",
- "null": "null",
- "undefined": "undefined",
- "function": function( fn ) {
- var ret = "function",
- // functions never have name in IE
- name = "name" in fn ? fn.name : (reName.exec(fn) || [])[1];
-
- if ( name ) {
- ret += " " + name;
- }
- ret += "( ";
-
- ret = [ ret, QUnit.jsDump.parse( fn, "functionArgs" ), "){" ].join( "" );
- return join( ret, QUnit.jsDump.parse(fn,"functionCode" ), "}" );
- },
- array: array,
- nodelist: array,
- "arguments": array,
- object: function( map, stack ) {
- var ret = [ ], keys, key, val, i;
- QUnit.jsDump.up();
- keys = [];
- for ( key in map ) {
- keys.push( key );
- }
- keys.sort();
- for ( i = 0; i < keys.length; i++ ) {
- key = keys[ i ];
- val = map[ key ];
- ret.push( QUnit.jsDump.parse( key, "key" ) + ": " + QUnit.jsDump.parse( val, undefined, stack ) );
- }
- QUnit.jsDump.down();
- return join( "{", ret, "}" );
- },
- node: function( node ) {
- var len, i, val,
- open = QUnit.jsDump.HTML ? "<" : "<",
- close = QUnit.jsDump.HTML ? ">" : ">",
- tag = node.nodeName.toLowerCase(),
- ret = open + tag,
- attrs = node.attributes;
-
- if ( attrs ) {
- for ( i = 0, len = attrs.length; i < len; i++ ) {
- val = attrs[i].nodeValue;
- // IE6 includes all attributes in .attributes, even ones not explicitly set.
- // Those have values like undefined, null, 0, false, "" or "inherit".
- if ( val && val !== "inherit" ) {
- ret += " " + attrs[i].nodeName + "=" + QUnit.jsDump.parse( val, "attribute" );
- }
- }
- }
- ret += close;
-
- // Show content of TextNode or CDATASection
- if ( node.nodeType === 3 || node.nodeType === 4 ) {
- ret += node.nodeValue;
- }
-
- return ret + open + "/" + tag + close;
- },
- // function calls it internally, it's the arguments part of the function
- functionArgs: function( fn ) {
- var args,
- l = fn.length;
-
- if ( !l ) {
- return "";
- }
-
- args = new Array(l);
- while ( l-- ) {
- // 97 is 'a'
- args[l] = String.fromCharCode(97+l);
- }
- return " " + args.join( ", " ) + " ";
- },
- // object calls it internally, the key part of an item in a map
- key: quote,
- // function calls it internally, it's the content of the function
- functionCode: "[code]",
- // node calls it internally, it's an html attribute value
- attribute: quote,
- string: quote,
- date: quote,
- regexp: literal,
- number: literal,
- "boolean": literal
- },
- // if true, entities are escaped ( <, >, \t, space and \n )
- HTML: false,
- // indentation unit
- indentChar: " ",
- // if true, items in a collection, are separated by a \n, else just a space.
- multiline: true
- };
-
- return jsDump;
-}());
-
-// from jquery.js
-function inArray( elem, array ) {
- if ( array.indexOf ) {
- return array.indexOf( elem );
- }
-
- for ( var i = 0, length = array.length; i < length; i++ ) {
- if ( array[ i ] === elem ) {
- return i;
- }
- }
-
- return -1;
-}
-
-/*
- * Javascript Diff Algorithm
- * By John Resig (http://ejohn.org/)
- * Modified by Chu Alan "sprite"
- *
- * Released under the MIT license.
- *
- * More Info:
- * http://ejohn.org/projects/javascript-diff-algorithm/
- *
- * Usage: QUnit.diff(expected, actual)
- *
- * QUnit.diff( "the quick brown fox jumped over", "the quick fox jumps over" ) == "the quick brown fox jumped jumps over"
- */
-QUnit.diff = (function() {
- /*jshint eqeqeq:false, eqnull:true */
- function diff( o, n ) {
- var i,
- ns = {},
- os = {};
-
- for ( i = 0; i < n.length; i++ ) {
- if ( !hasOwn.call( ns, n[i] ) ) {
- ns[ n[i] ] = {
- rows: [],
- o: null
- };
- }
- ns[ n[i] ].rows.push( i );
- }
-
- for ( i = 0; i < o.length; i++ ) {
- if ( !hasOwn.call( os, o[i] ) ) {
- os[ o[i] ] = {
- rows: [],
- n: null
- };
- }
- os[ o[i] ].rows.push( i );
- }
-
- for ( i in ns ) {
- if ( !hasOwn.call( ns, i ) ) {
- continue;
- }
- if ( ns[i].rows.length === 1 && hasOwn.call( os, i ) && os[i].rows.length === 1 ) {
- n[ ns[i].rows[0] ] = {
- text: n[ ns[i].rows[0] ],
- row: os[i].rows[0]
- };
- o[ os[i].rows[0] ] = {
- text: o[ os[i].rows[0] ],
- row: ns[i].rows[0]
- };
- }
- }
-
- for ( i = 0; i < n.length - 1; i++ ) {
- if ( n[i].text != null && n[ i + 1 ].text == null && n[i].row + 1 < o.length && o[ n[i].row + 1 ].text == null &&
- n[ i + 1 ] == o[ n[i].row + 1 ] ) {
-
- n[ i + 1 ] = {
- text: n[ i + 1 ],
- row: n[i].row + 1
- };
- o[ n[i].row + 1 ] = {
- text: o[ n[i].row + 1 ],
- row: i + 1
- };
- }
- }
-
- for ( i = n.length - 1; i > 0; i-- ) {
- if ( n[i].text != null && n[ i - 1 ].text == null && n[i].row > 0 && o[ n[i].row - 1 ].text == null &&
- n[ i - 1 ] == o[ n[i].row - 1 ]) {
-
- n[ i - 1 ] = {
- text: n[ i - 1 ],
- row: n[i].row - 1
- };
- o[ n[i].row - 1 ] = {
- text: o[ n[i].row - 1 ],
- row: i - 1
- };
- }
- }
-
- return {
- o: o,
- n: n
- };
- }
-
- return function( o, n ) {
- o = o.replace( /\s+$/, "" );
- n = n.replace( /\s+$/, "" );
-
- var i, pre,
- str = "",
- out = diff( o === "" ? [] : o.split(/\s+/), n === "" ? [] : n.split(/\s+/) ),
- oSpace = o.match(/\s+/g),
- nSpace = n.match(/\s+/g);
-
- if ( oSpace == null ) {
- oSpace = [ " " ];
- }
- else {
- oSpace.push( " " );
- }
-
- if ( nSpace == null ) {
- nSpace = [ " " ];
- }
- else {
- nSpace.push( " " );
- }
-
- if ( out.n.length === 0 ) {
- for ( i = 0; i < out.o.length; i++ ) {
- str += "" + out.o[i] + oSpace[i] + "";
- }
- }
- else {
- if ( out.n[0].text == null ) {
- for ( n = 0; n < out.o.length && out.o[n].text == null; n++ ) {
- str += "" + out.o[n] + oSpace[n] + "";
- }
- }
-
- for ( i = 0; i < out.n.length; i++ ) {
- if (out.n[i].text == null) {
- str += "" + out.n[i] + nSpace[i] + "";
- }
- else {
- // `pre` initialized at top of scope
- pre = "";
-
- for ( n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++ ) {
- pre += "" + out.o[n] + oSpace[n] + "";
- }
- str += " " + out.n[i].text + nSpace[i] + pre;
- }
- }
- }
-
- return str;
- };
-}());
-
-// for CommonJS enviroments, export everything
-if ( typeof exports !== "undefined" ) {
- extend( exports, QUnit );
-}
-
-// get at whatever the global object is, like window in browsers
-}( (function() {return this;}.call()) ));
diff --git a/test/lib/require.js b/test/lib/require.js
deleted file mode 100644
index 987f865..0000000
--- a/test/lib/require.js
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- RequireJS 2.1.5 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.
- Available via the MIT or new BSD license.
- see: http://github.com/jrburke/requirejs for details
-*/
-var requirejs,require,define;
-(function(aa){function I(b){return"[object Function]"===L.call(b)}function J(b){return"[object Array]"===L.call(b)}function y(b,c){if(b){var d;for(d=0;dthis.depCount&&!this.defined){if(I(n)){if(this.events.error)try{e=i.execCb(c,n,b,e)}catch(d){a=d}else e=i.execCb(c,n,b,e);this.map.isDefine&&((b=this.module)&&void 0!==b.exports&&b.exports!==this.exports?e=b.exports:void 0===e&&this.usingExports&&(e=this.exports));if(a)return a.requireMap=this.map,a.requireModules=[this.map.id],a.requireType="define",v(this.error=
-a)}else e=n;this.exports=e;if(this.map.isDefine&&!this.ignore&&(q[c]=e,l.onResourceLoad))l.onResourceLoad(i,this.map,this.depMaps);x(c);this.defined=!0}this.defining=!1;this.defined&&!this.defineEmitted&&(this.defineEmitted=!0,this.emit("defined",this.exports),this.defineEmitComplete=!0)}}else this.fetch()}},callPlugin:function(){var a=this.map,b=a.id,d=j(a.prefix);this.depMaps.push(d);t(d,"defined",u(this,function(e){var n,d;d=this.map.name;var g=this.map.parentMap?this.map.parentMap.name:null,h=
-i.makeRequire(a.parentMap,{enableBuildCallback:!0});if(this.map.unnormalized){if(e.normalize&&(d=e.normalize(d,function(a){return c(a,g,!0)})||""),e=j(a.prefix+"!"+d,this.map.parentMap),t(e,"defined",u(this,function(a){this.init([],function(){return a},null,{enabled:!0,ignore:!0})})),d=m(p,e.id)){this.depMaps.push(e);if(this.events.error)d.on("error",u(this,function(a){this.emit("error",a)}));d.enable()}}else n=u(this,function(a){this.init([],function(){return a},null,{enabled:!0})}),n.error=u(this,
-function(a){this.inited=!0;this.error=a;a.requireModules=[b];G(p,function(a){0===a.map.id.indexOf(b+"_unnormalized")&&x(a.map.id)});v(a)}),n.fromText=u(this,function(e,c){var d=a.name,g=j(d),C=O;c&&(e=c);C&&(O=!1);r(g);s(k.config,b)&&(k.config[d]=k.config[b]);try{l.exec(e)}catch(ca){return v(B("fromtexteval","fromText eval for "+b+" failed: "+ca,ca,[b]))}C&&(O=!0);this.depMaps.push(g);i.completeLoad(d);h([d],n)}),e.load(a.name,h,n,k)}));i.enable(d,this);this.pluginMaps[d.id]=d},enable:function(){V[this.map.id]=
-this;this.enabling=this.enabled=!0;y(this.depMaps,u(this,function(a,b){var c,e;if("string"===typeof a){a=j(a,this.map.isDefine?this.map:this.map.parentMap,!1,!this.skipMap);this.depMaps[b]=a;if(c=m(N,a.id)){this.depExports[b]=c(this);return}this.depCount+=1;t(a,"defined",u(this,function(a){this.defineDep(b,a);this.check()}));this.errback&&t(a,"error",this.errback)}c=a.id;e=p[c];!s(N,c)&&(e&&!e.enabled)&&i.enable(a,this)}));G(this.pluginMaps,u(this,function(a){var b=m(p,a.id);b&&!b.enabled&&i.enable(a,
-this)}));this.enabling=!1;this.check()},on:function(a,b){var c=this.events[a];c||(c=this.events[a]=[]);c.push(b)},emit:function(a,b){y(this.events[a],function(a){a(b)});"error"===a&&delete this.events[a]}};i={config:k,contextName:b,registry:p,defined:q,urlFetched:U,defQueue:H,Module:Z,makeModuleMap:j,nextTick:l.nextTick,onError:v,configure:function(a){a.baseUrl&&"/"!==a.baseUrl.charAt(a.baseUrl.length-1)&&(a.baseUrl+="/");var b=k.pkgs,c=k.shim,e={paths:!0,config:!0,map:!0};G(a,function(a,b){e[b]?
-"map"===b?(k.map||(k.map={}),R(k[b],a,!0,!0)):R(k[b],a,!0):k[b]=a});a.shim&&(G(a.shim,function(a,b){J(a)&&(a={deps:a});if((a.exports||a.init)&&!a.exportsFn)a.exportsFn=i.makeShimExports(a);c[b]=a}),k.shim=c);a.packages&&(y(a.packages,function(a){a="string"===typeof a?{name:a}:a;b[a.name]={name:a.name,location:a.location||a.name,main:(a.main||"main").replace(ja,"").replace(ea,"")}}),k.pkgs=b);G(p,function(a,b){!a.inited&&!a.map.unnormalized&&(a.map=j(b))});if(a.deps||a.callback)i.require(a.deps||[],
-a.callback)},makeShimExports:function(a){return function(){var b;a.init&&(b=a.init.apply(aa,arguments));return b||a.exports&&ba(a.exports)}},makeRequire:function(a,f){function d(e,c,h){var g,k;f.enableBuildCallback&&(c&&I(c))&&(c.__requireJsBuild=!0);if("string"===typeof e){if(I(c))return v(B("requireargs","Invalid require call"),h);if(a&&s(N,e))return N[e](p[a.id]);if(l.get)return l.get(i,e,a,d);g=j(e,a,!1,!0);g=g.id;return!s(q,g)?v(B("notloaded",'Module name "'+g+'" has not been loaded yet for context: '+
-b+(a?"":". Use require([])"))):q[g]}L();i.nextTick(function(){L();k=r(j(null,a));k.skipMap=f.skipMap;k.init(e,c,h,{enabled:!0});D()});return d}f=f||{};R(d,{isBrowser:A,toUrl:function(b){var d,f=b.lastIndexOf("."),g=b.split("/")[0];if(-1!==f&&(!("."===g||".."===g)||1h.attachEvent.toString().indexOf("[native code"))&&!Y?(O=!0,h.attachEvent("onreadystatechange",b.onScriptLoad)):(h.addEventListener("load",b.onScriptLoad,!1),h.addEventListener("error",b.onScriptError,!1)),h.src=d,K=h,D?x.insertBefore(h,D):x.appendChild(h),K=null,h;if(da)try{importScripts(d),b.completeLoad(c)}catch(j){b.onError(B("importscripts","importScripts failed for "+c+" at "+d,j,[c]))}};A&&M(document.getElementsByTagName("script"),function(b){x||(x=
-b.parentNode);if(t=b.getAttribute("data-main"))return r.baseUrl||(E=t.split("/"),Q=E.pop(),fa=E.length?E.join("/")+"/":"./",r.baseUrl=fa,t=Q),t=t.replace(ea,""),r.deps=r.deps?r.deps.concat(t):[t],!0});define=function(b,c,d){var l,h;"string"!==typeof b&&(d=c,c=b,b=null);J(c)||(d=c,c=[]);!c.length&&I(d)&&d.length&&(d.toString().replace(la,"").replace(ma,function(b,d){c.push(d)}),c=(1===d.length?["require"]:["require","exports","module"]).concat(c));if(O){if(!(l=K))P&&"interactive"===P.readyState||M(document.getElementsByTagName("script"),
-function(b){if("interactive"===b.readyState)return P=b}),l=P;l&&(b||(b=l.getAttribute("data-requiremodule")),h=F[l.getAttribute("data-requirecontext")])}(h?h.defQueue:T).push([b,c,d])};define.amd={jQuery:!0};l.exec=function(b){return eval(b)};l(r)}})(this);
diff --git a/test/lib/resemble.js b/test/lib/resemble.js
new file mode 100644
index 0000000..1cb8c29
--- /dev/null
+++ b/test/lib/resemble.js
@@ -0,0 +1,535 @@
+/*
+Author: James Cryer
+Company: Huddle
+Last updated date: 21 Feb 2013
+URL: https://github.com/Huddle/Resemble.js
+*/
+
+(function(_this){
+ 'use strict';
+
+ _this['resemble'] = function( fileData ){
+
+ var data = {};
+ var images = [];
+ var updateCallbackArray = [];
+
+ var tolerance = { // between 0 and 255
+ red: 16,
+ green: 16,
+ blue: 16,
+ minBrightness: 16,
+ maxBrightness: 240
+ };
+
+ var ignoreAntialiasing = false;
+ var ignoreColors = false;
+
+ function triggerDataUpdate(){
+ var len = updateCallbackArray.length;
+ var i;
+ for(i=0;i tolerance.maxBrightness;
+ }
+
+ function getHue(r,g,b){
+
+ r = r / 255;
+ g = g / 255;
+ b = b / 255;
+ var max = Math.max(r, g, b), min = Math.min(r, g, b);
+ var h;
+ var d;
+
+ if (max == min){
+ h = 0; // achromatic
+ } else{
+ d = max - min;
+ switch(max){
+ case r: h = (g - b) / d + (g < b ? 6 : 0); break;
+ case g: h = (b - r) / d + 2; break;
+ case b: h = (r - g) / d + 4; break;
+ }
+ h /= 6;
+ }
+
+ return h;
+ }
+
+ function isAntialiased(sourcePix, data, cacheSet, verticalPos, horizontalPos, width){
+ var offset;
+ var targetPix;
+ var distance = 1;
+ var i;
+ var j;
+ var hasHighContrastSibling = 0;
+ var hasSiblingWithDifferentHue = 0;
+ var hasEquivilantSibling = 0;
+
+ addHueInfo(sourcePix);
+
+ for (i = distance*-1; i <= distance; i++){
+ for (j = distance*-1; j <= distance; j++){
+
+ if(i===0 && j===0){
+ // ignore source pixel
+ } else {
+
+ offset = ((verticalPos+j)*width + (horizontalPos+i)) * 4;
+ targetPix = getPixelInfo(data, offset, cacheSet);
+
+ if(targetPix === null){
+ continue;
+ }
+
+ addBrightnessInfo(targetPix);
+ addHueInfo(targetPix);
+
+ if( isContrasting(sourcePix, targetPix) ){
+ hasHighContrastSibling++;
+ }
+
+ if( isRGBSame(sourcePix,targetPix) ){
+ hasEquivilantSibling++;
+ }
+
+ if( Math.abs(targetPix.h - sourcePix.h) > 0.3 ){
+ hasSiblingWithDifferentHue++;
+ }
+
+ if( hasSiblingWithDifferentHue > 1 || hasHighContrastSibling > 1){
+ return true;
+ }
+ }
+ }
+ }
+
+ if(hasEquivilantSibling < 2){
+ return true;
+ }
+
+ return false;
+ }
+
+ function errorPixel(px, offset){
+ px[offset] = 255; //r
+ px[offset + 1] = 0; //g
+ px[offset + 2] = 255; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyPixel(px, offset, data){
+ px[offset] = data.r; //r
+ px[offset + 1] = data.g; //g
+ px[offset + 2] = data.b; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyGrayScalePixel(px, offset, data){
+ px[offset] = data.brightness; //r
+ px[offset + 1] = data.brightness; //g
+ px[offset + 2] = data.brightness; //b
+ px[offset + 3] = 255; //a
+ }
+
+
+ function getPixelInfo(data, offset, cacheSet){
+ var r;
+ var g;
+ var b;
+ var d;
+
+ if(typeof data[offset] !== 'undefined'){
+ r = data[offset];
+ g = data[offset+1];
+ b = data[offset+2];
+ d = {
+ r: r,
+ g: g,
+ b: b
+ };
+
+ return d;
+ } else {
+ return null;
+ }
+ }
+
+ function addBrightnessInfo(data){
+ data.brightness = getBrightness(data.r,data.g,data.b); // 'corrected' lightness
+ }
+
+ function addHueInfo(data){
+ data.h = getHue(data.r,data.g,data.b);
+ }
+
+ function analyseImages(img1, img2, width, height){
+
+ var hiddenCanvas = document.createElement('canvas');
+
+ var data1 = img1.data;
+ var data2 = img2.data;
+
+ hiddenCanvas.width = width;
+ hiddenCanvas.height = height;
+
+ var context = hiddenCanvas.getContext('2d');
+ var imgd = context.createImageData(width,height);
+ var targetPix = imgd.data;
+
+ var mismatchCount = 0;
+
+ var time = Date.now();
+
+ var skip;
+
+ if( (width > 1200 || height > 1200) && ignoreAntialiasing){
+ skip = 6;
+ }
+
+ loop(height, width, function(verticalPos, horizontalPos){
+
+ if(skip){ // only skip if the image isn't small
+ if(verticalPos % skip === 0 || horizontalPos % skip === 0){
+ return;
+ }
+ }
+
+ var offset = (verticalPos*width + horizontalPos) * 4;
+ var pixel1 = getPixelInfo(data1, offset, 1);
+ var pixel2 = getPixelInfo(data2, offset, 2);
+
+ if(pixel1 === null || pixel2 === null){
+ return;
+ }
+
+ if (ignoreColors){
+
+ addBrightnessInfo(pixel1);
+ addBrightnessInfo(pixel2);
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ return;
+ }
+
+ if( isRGBSimilar(pixel1, pixel2) ){
+ copyPixel(targetPix, offset, pixel2);
+
+ } else if( ignoreAntialiasing && (
+ addBrightnessInfo(pixel1), // jit pixel info augmentation looks a little weird, sorry.
+ addBrightnessInfo(pixel2),
+ isAntialiased(pixel1, data1, 1, verticalPos, horizontalPos, width) ||
+ isAntialiased(pixel2, data2, 2, verticalPos, horizontalPos, width)
+ )){
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+
+ });
+
+ data.misMatchPercentage = (mismatchCount / (height*width) * 100).toFixed(2);
+ data.analysisTime = Date.now() - time;
+
+ data.getImageDataUrl = function(text){
+ var barHeight = 0;
+
+ if(text){
+ barHeight = addLabel(text,context,hiddenCanvas);
+ }
+
+ context.putImageData(imgd, 0, barHeight);
+
+ return hiddenCanvas.toDataURL("image/png");
+ };
+ }
+
+ function addLabel(text, context, hiddenCanvas){
+ var textPadding = 2;
+
+ context.font = '12px sans-serif';
+
+ var textWidth = context.measureText(text).width + textPadding*2;
+ var barHeight = 22;
+
+ if(textWidth > hiddenCanvas.width){
+ hiddenCanvas.width = textWidth;
+ }
+
+ hiddenCanvas.height += barHeight;
+
+ context.fillStyle = "#666";
+ context.fillRect(0,0,hiddenCanvas.width,barHeight -4);
+ context.fillStyle = "#fff";
+ context.fillRect(0,barHeight -4,hiddenCanvas.width, 4);
+
+ context.fillStyle = "#fff";
+ context.textBaseline = "top";
+ context.font = '12px sans-serif';
+ context.fillText(text, textPadding, 1);
+
+ return barHeight;
+ }
+
+ function normalise(img, w, h){
+ var c;
+ var context;
+
+ if(img.height < h || img.width < w){
+ c = document.createElement('canvas');
+ c.width = w;
+ c.height = h;
+ context = c.getContext('2d');
+ context.putImageData(img, 0, 0);
+ return context.getImageData(0, 0, w, h);
+ }
+
+ return img;
+ }
+
+ function compare(one, two){
+
+ function onceWeHaveBoth(){
+ var width;
+ var height;
+ if(images.length === 2){
+ width = images[0].width > images[1].width ? images[0].width : images[1].width;
+ height = images[0].height > images[1].height ? images[0].height : images[1].height;
+
+ if( (images[0].width === images[1].width) && (images[0].height === images[1].height) ){
+ data.isSameDimensions = true;
+ } else {
+ data.isSameDimensions = false;
+ }
+
+ analyseImages( normalise(images[0],width, height), normalise(images[1],width, height), width, height);
+
+ triggerDataUpdate();
+ }
+ }
+
+ images = [];
+ loadImageData(one, onceWeHaveBoth);
+ loadImageData(two, onceWeHaveBoth);
+ }
+
+ function getCompareApi(param){
+
+ var secondFileData,
+ hasMethod = typeof param === 'function';
+
+ if( !hasMethod ){
+ // assume it's file data
+ secondFileData = param;
+ }
+
+ var self = {
+ ignoreNothing: function(){
+
+ tolerance.red = 16;
+ tolerance.green = 16;
+ tolerance.blue = 16;
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreAntialiasing: function(){
+
+ tolerance.red = 32;
+ tolerance.green = 32;
+ tolerance.blue = 32;
+ tolerance.minBrightness = 64;
+ tolerance.maxBrightness = 96;
+
+ ignoreAntialiasing = true;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreColors: function(){
+
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = true;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ onComplete: function( callback ){
+
+ updateCallbackArray.push(callback);
+
+ var wrapper = function(){
+ compare(fileData, secondFileData);
+ };
+
+ wrapper();
+
+ return getCompareApi(wrapper);
+ }
+ };
+
+ return self;
+ }
+
+ return {
+ onComplete: function( callback ){
+ updateCallbackArray.push(callback);
+ loadImageData(fileData, function(imageData, width, height){
+ parseImage(imageData.data, width, height);
+ });
+ },
+ compareTo: function(secondFileData){
+ return getCompareApi(secondFileData);
+ }
+ };
+
+ };
+}(this));
\ No newline at end of file
diff --git a/test/testsuite.js b/test/testsuite.js
deleted file mode 100644
index b486acb..0000000
--- a/test/testsuite.js
+++ /dev/null
@@ -1,36 +0,0 @@
-requirejs.config({
- baseUrl: '/test/unit/'
-});
-
-define(function(require) {
- var testModules = [
- 'Pixi',
- 'Point',
- 'Rectangle',
- 'DisplayObject',
- 'DisplayObjectContainer',
- 'Sprite',
- 'MovieClip',
- 'InteractionManager',
- 'Stage',
- 'utils/Utils',
- 'utils/EventTarget',
- 'utils/Matrix',
- 'utils/Detector',
- 'renderers/WebGLShaders',
- 'renderers/WebGLRenderer',
- 'renderers/WebGLBatch',
- 'renderers/CanvasRenderer',
- 'extras/Strip',
- 'extras/Rope',
- 'textures/BaseTexture',
- 'textures/Texture',
- 'loaders/SpriteSheetLoader',
- 'loaders/AssetLoader'
- ];
-
- // Resolve all testModules and then start the Test Runner.
- require(testModules, function() {
- QUnit.start();
- });
-});
\ No newline at end of file
diff --git a/test/textures/SpriteSheet-Aliens.png b/test/textures/SpriteSheet-Aliens.png
new file mode 100644
index 0000000..210acb1
--- /dev/null
+++ b/test/textures/SpriteSheet-Aliens.png
Binary files differ
diff --git a/test/textures/SpriteSheet-Explosion.png b/test/textures/SpriteSheet-Explosion.png
new file mode 100755
index 0000000..79e1a69
--- /dev/null
+++ b/test/textures/SpriteSheet-Explosion.png
Binary files differ
diff --git a/test/textures/bunny.png b/test/textures/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/textures/bunny.png
Binary files differ
diff --git a/test/unit/DisplayObject.js b/test/unit/DisplayObject.js
deleted file mode 100644
index 5e7e72f..0000000
--- a/test/unit/DisplayObject.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObject');
-});
diff --git a/test/unit/DisplayObjectContainer.js b/test/unit/DisplayObjectContainer.js
deleted file mode 100644
index b323959..0000000
--- a/test/unit/DisplayObjectContainer.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObjectContainer');
-});
diff --git a/test/unit/InteractionManager.js b/test/unit/InteractionManager.js
deleted file mode 100644
index e751f52..0000000
--- a/test/unit/InteractionManager.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('InteractionManager');
-});
diff --git a/test/unit/MovieClip.js b/test/unit/MovieClip.js
deleted file mode 100644
index 37d9446..0000000
--- a/test/unit/MovieClip.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('MovieClip');
-});
diff --git a/test/unit/Pixi.js b/test/unit/Pixi.js
deleted file mode 100644
index 36eee73..0000000
--- a/test/unit/Pixi.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Pixi');
-});
diff --git a/test/unit/Point.js b/test/unit/Point.js
deleted file mode 100644
index 983ff6e..0000000
--- a/test/unit/Point.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Point');
-});
diff --git a/test/unit/Rectangle.js b/test/unit/Rectangle.js
deleted file mode 100644
index 3b439ba..0000000
--- a/test/unit/Rectangle.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Rectangle');
-});
diff --git a/test/unit/Sprite.js b/test/unit/Sprite.js
deleted file mode 100644
index ed4f596..0000000
--- a/test/unit/Sprite.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Sprite');
-});
diff --git a/test/unit/Stage.js b/test/unit/Stage.js
deleted file mode 100644
index 2d70291..0000000
--- a/test/unit/Stage.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Stage');
-});
diff --git a/test/unit/extras/Rope.js b/test/unit/extras/Rope.js
deleted file mode 100644
index 5606f14..0000000
--- a/test/unit/extras/Rope.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Rope');
-});
diff --git a/.gitignore b/.gitignore
index 12e1b62..0b88317 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
node_modules
.DS_Store
-.project
\ No newline at end of file
+.project
+*.log
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..63e4d7c
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,8 @@
+language: node_js
+node_js:
+ - 0.10
+
+before_script:
+ - npm install -g grunt-cli
+ - export DISPLAY=:99.0
+ - sh -e /etc/init.d/xvfb start
diff --git a/Gruntfile.js b/Gruntfile.js
index b083b49..103938c 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -1,10 +1,12 @@
+'use strict';
+
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-connect');
- grunt.loadNpmTasks('grunt-contrib-qunit');
grunt.loadNpmTasks('grunt-contrib-yuidoc');
+ grunt.loadTasks('tasks');
var root = 'src/pixi/',
debug = 'bin/pixi.dev.js',
@@ -79,7 +81,7 @@
},
files: {
srcBlob: '<%= dirs.src %>/**/*.js',
- testBlob: '<%= dirs.test %>/unit/**/*.js',
+ testBlob: '<%= dirs.test %>/{functional,lib/pixi,unit}/**/*.js',
build: '<%= dirs.build %>/pixi.dev.js',
buildMin: '<%= dirs.build %>/pixi.js'
},
@@ -94,7 +96,12 @@
},
jshint: {
beforeconcat: srcFiles,
- test: ['<%= files.testBlob %>'],
+ test: {
+ src: ['<%= files.testBlob %>'],
+ options: {
+ expr: true
+ }
+ },
options: {
asi: true,
smarttabs: true
@@ -128,12 +135,6 @@
]
},
connect: {
- qunit: {
- options: {
- port: grunt.option('port-test') || 9002,
- base: './'
- }
- },
test: {
options: {
port: grunt.option('port-test') || 9002,
@@ -142,13 +143,6 @@
}
}
},
- qunit: {
- all: {
- options: {
- urls: ['http://localhost:' + (grunt.option('port-test') || 9002) + '/test/index.html']
- }
- }
- },
yuidoc: {
compile: {
name: '<%= pkg.name %>',
@@ -161,6 +155,13 @@
outdir: '<%= dirs.docs %>'
}
}
+ },
+ karma: {
+ unit: {
+ configFile: 'test/karma.conf.js',
+ // browsers: ['Chrome'],
+ singleRun: true
+ }
}
});
@@ -182,9 +183,10 @@
}
)
- grunt.registerTask('default', ['concat', 'uglify', 'distribute']);
grunt.registerTask('build', ['concat', 'uglify', 'distribute']);
- grunt.registerTask('test', ['build', 'connect:qunit', 'qunit']);
+ grunt.registerTask('test', ['concat', 'jshint:test', 'karma']);
grunt.registerTask('docs', ['yuidoc']);
-
-}
\ No newline at end of file
+ grunt.registerTask('default', ['test', 'uglify', 'distribute']);
+ // Travis CI task.
+ grunt.registerTask('travis', ['test']);
+}
diff --git a/README.md b/README.md
index c62ef86..690cfe4 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,8 @@

+[](http://travis-ci.org/drkibitz/pixi.js)
+
#### JavaScript 2D Renderer ####
The aim of this project is to provide a fast lightweight 2D library that works
diff --git a/package.json b/package.json
index b373240..1246a68 100644
--- a/package.json
+++ b/package.json
@@ -18,14 +18,21 @@
"main": "bin/pixi.js",
+ "scripts": {
+ "test": "grunt travis --verbose"
+ },
+
"dependencies": {},
"devDependencies": {
"grunt": "~0.4.x",
- "grunt-contrib-jshint": "0.3.x",
+ "grunt-contrib-jshint": "0.6.x",
"grunt-contrib-uglify": "0.2.x",
- "grunt-contrib-connect": "0.2.x",
- "grunt-contrib-qunit": "0.2.x",
+ "grunt-contrib-connect": "0.3.x",
"grunt-contrib-yuidoc": "0.4.x",
- "grunt-contrib-concat": "0.1.x"
+ "grunt-contrib-concat": "0.3.x",
+ "chai": "~1.7.0",
+ "karma": "0.11.0",
+ "karma-firefox-launcher": "0.1.0",
+ "karma-mocha": "0.1.0"
}
}
diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js
index a7c520e..ee82bbd 100644
--- a/src/pixi/InteractionManager.js
+++ b/src/pixi/InteractionManager.js
@@ -62,7 +62,6 @@
this.onTouchEnd = this.onTouchEnd.bind(this);
this.onTouchMove = this.onTouchMove.bind(this);
-
this.last = 0;
}
diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js
index 1a95d20..eef1059 100644
--- a/src/pixi/core/Ellipse.js
+++ b/src/pixi/core/Ellipse.js
@@ -78,7 +78,7 @@
return (normx + normy < 0.25);
}
-PIXI.Ellipse.getBounds = function()
+PIXI.Ellipse.prototype.getBounds = function()
{
return new PIXI.Rectangle(this.x, this.y, this.width, this.height);
}
diff --git a/tasks/karma.js b/tasks/karma.js
new file mode 100644
index 0000000..c340485
--- /dev/null
+++ b/tasks/karma.js
@@ -0,0 +1,27 @@
+'use strict';
+
+var path = require('path');
+var server = require('karma').server;
+
+module.exports = function (grunt) {
+ grunt.registerMultiTask('karma', 'run karma.', function() {
+ var done = this.async();
+ var options = this.options({
+ background: false
+ });
+ var data = this.data;
+
+ //merge options onto data, with data taking precedence
+ data = grunt.util._.merge(options, data);
+ data.configFile = path.resolve(data.configFile);
+ if (data.configFile) {
+ data.configFile = grunt.template.process(data.configFile);
+ }
+
+ server.start(
+ data,
+ function(code) {
+ done(!code);
+ });
+ });
+};
diff --git a/test/functional/example-1-basics/bunny.png b/test/functional/example-1-basics/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/functional/example-1-basics/bunny.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-30.png b/test/functional/example-1-basics/frame-30.png
new file mode 100644
index 0000000..96e3409
--- /dev/null
+++ b/test/functional/example-1-basics/frame-30.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-60.png b/test/functional/example-1-basics/frame-60.png
new file mode 100644
index 0000000..af3f4ce
--- /dev/null
+++ b/test/functional/example-1-basics/frame-60.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-90.png b/test/functional/example-1-basics/frame-90.png
new file mode 100644
index 0000000..099b823
--- /dev/null
+++ b/test/functional/example-1-basics/frame-90.png
Binary files differ
diff --git a/test/functional/example-1-basics/index.js b/test/functional/example-1-basics/index.js
new file mode 100644
index 0000000..7ae7a98
--- /dev/null
+++ b/test/functional/example-1-basics/index.js
@@ -0,0 +1,133 @@
+describe('Example 1 - Basics', function () {
+ 'use strict';
+
+ var baseUri = '/base/test/functional/example-1-basics';
+ var expect = chai.expect;
+ var currentFrame = 0;
+ var frameEvents = {};
+ var stage;
+ var renderer;
+ var bunny;
+
+ function onFrame(frame, callback) {
+ frameEvents[frame] = callback;
+ }
+
+ function animate() {
+ currentFrame += 1;
+
+ requestAnimFrame( animate );
+
+ // just for fun, lets rotate mr rabbit a little
+ bunny.rotation += 0.1;
+
+ // render the stage
+ renderer.render(stage);
+
+ if (frameEvents[currentFrame])
+ frameEvents[currentFrame](currentFrame);
+ }
+
+ function initScene() {
+ // create an new instance of a pixi stage
+ stage = new PIXI.Stage(0x66FF99);
+
+ // create a renderer instance
+ renderer = PIXI.autoDetectRenderer(400, 300);
+ console.log('Is PIXI.WebGLRenderer: ' + (renderer instanceof PIXI.WebGLRenderer));
+
+ // add the renderer view element to the DOM
+ document.body.appendChild(renderer.view);
+
+ requestAnimFrame( animate );
+
+ // create a texture from an image path
+ var texture = PIXI.Texture.fromImage(baseUri + "/bunny.png");
+ // create a new Sprite using the texture
+ bunny = new PIXI.Sprite(texture);
+
+ // center the sprites anchor point
+ bunny.anchor.x = 0.5;
+ bunny.anchor.y = 0.5;
+
+ // move the sprite t the center of the screen
+ bunny.position.x = 200;
+ bunny.position.y = 150;
+
+ stage.addChild(bunny);
+ }
+
+ it('assets loaded', function (done) {
+ var loader = new PIXI.AssetLoader([
+ baseUri + '/bunny.png',
+ baseUri + '/frame-30.png',
+ baseUri + '/frame-60.png',
+ baseUri + '/frame-90.png'
+ ]);
+ // loader.on('onProgress', function (event) {
+ // console.log(event.content);
+ // });
+ loader.on('onComplete', function (event) {
+ done();
+ initScene();
+ });
+ loader.load();
+ });
+
+ it('frame 30 should match', function (done) {
+ this.timeout(700);
+ onFrame(30, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-30.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 60 should match', function (done) {
+ this.timeout(1200);
+ onFrame(60, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-60.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 90 should match', function (done) {
+ this.timeout(1700);
+ onFrame(90, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-90.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ // it('capture something', function (done) {
+ // this.timeout(2000000);
+ // onFrame(30, function () {
+ // var img = new Image();
+ // img.src = renderer.view.toDataURL('image/png');
+ // document.body.appendChild(img);
+ // });
+ // });
+});
diff --git a/test/index.html b/test/index.html
deleted file mode 100644
index 9cbcac5..0000000
--- a/test/index.html
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
- Pixi.js Test Suite
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/test/karma.conf.js b/test/karma.conf.js
new file mode 100644
index 0000000..c66a696
--- /dev/null
+++ b/test/karma.conf.js
@@ -0,0 +1,82 @@
+module.exports = function(config) {
+ config.set({
+
+ // base path, that will be used to resolve files and exclude
+ basePath : '../',
+
+ frameworks : ['mocha'],
+
+ // list of files / patterns to load in the browser
+ files : [
+ 'node_modules/chai/chai.js',
+ 'bin/pixi.dev.js',
+ 'test/lib/**/*.js',
+ 'test/unit/**/*.js',
+ // 'test/functional/**/*.js',
+ {pattern: 'test/**/*.png', watched: false, included: false, served: true}
+ ],
+
+ // list of files to exclude
+ exclude : [],
+
+ // use dolts reporter, as travis terminal does not support escaping sequences
+ // possible values: 'dots', 'progress', 'junit', 'teamcity'
+ // CLI --reporters progress
+ reporters : ['progress'],
+
+ // web server port
+ // CLI --port 9876
+ port : 9876,
+
+ // cli runner port
+ // CLI --runner-port 9100
+ runnerPort : 9100,
+
+ // enable / disable colors in the output (reporters and logs)
+ // CLI --colors --no-colors
+ colors : true,
+
+ // level of logging
+ // possible values: karma.LOG_DISABLE || karma.LOG_ERROR || karma.LOG_WARN || karma.LOG_INFO || karma.LOG_DEBUG
+ // CLI --log-level debug
+ logLevel : config.LOG_DEBUG,
+
+ // enable / disable watching file and executing tests whenever any file changes
+ // CLI --auto-watch --no-auto-watch
+ autoWatch : false,
+
+ // Start these browsers, currently available:
+ // - Chrome
+ // - ChromeCanary
+ // - Firefox
+ // - Opera
+ // - Safari (only Mac)
+ // - PhantomJS
+ // - IE (only Windows)
+ // CLI --browsers Chrome,Firefox,Safari
+ browsers : ['Firefox'],
+
+ // If browser does not capture in given timeout [ms], kill it
+ // CLI --capture-timeout 5000
+ captureTimeout : 5000,
+
+ // Auto run tests on start (when browsers are captured) and exit
+ // CLI --single-run --no-single-run
+ singleRun : true,
+
+ // report which specs are slower than 500ms
+ // CLI --report-slower-than 500
+ reportSlowerThan : 1000,
+
+ preprocessors : {
+ // '**/client/js/*.js': 'coverage'
+ },
+
+ plugins : [
+ 'karma-mocha',
+ // 'karma-chrome-launcher',
+ 'karma-firefox-launcher',
+ // 'karma-phantomjs-launcher'
+ ]
+ });
+};
diff --git a/test/lib/pixi/core/Matrix.js b/test/lib/pixi/core/Matrix.js
new file mode 100644
index 0000000..d26386b
--- /dev/null
+++ b/test/lib/pixi/core/Matrix.js
@@ -0,0 +1,40 @@
+
+function pixi_core_Matrix_confirmNewMat3(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(1);
+ expect(matrix[5]).to.equal(0);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(1);
+}
+
+function pixi_core_Matrix_confirmNewMat4(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[0]).to.equal(1);
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(0);
+ expect(matrix[5]).to.equal(1);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(0);
+ expect(matrix[9]).to.equal(0);
+ expect(matrix[10]).to.equal(1);
+ expect(matrix[11]).to.equal(0);
+ expect(matrix[12]).to.equal(0);
+ expect(matrix[13]).to.equal(0);
+ expect(matrix[14]).to.equal(0);
+ expect(matrix[15]).to.equal(1);
+}
diff --git a/test/lib/pixi/core/Point.js b/test/lib/pixi/core/Point.js
new file mode 100644
index 0000000..e5df07b
--- /dev/null
+++ b/test/lib/pixi/core/Point.js
@@ -0,0 +1,10 @@
+
+function pixi_core_Point_confirm(obj, x, y) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Point);
+ expect(obj).to.respondTo('clone');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+}
diff --git a/test/lib/pixi/core/Rectangle.js b/test/lib/pixi/core/Rectangle.js
new file mode 100644
index 0000000..23f0d12
--- /dev/null
+++ b/test/lib/pixi/core/Rectangle.js
@@ -0,0 +1,13 @@
+
+function pixi_core_Rectangle_confirm(obj, x, y, width, height) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Rectangle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+ expect(obj).to.have.property('width', width);
+ expect(obj).to.have.property('height', height);
+}
diff --git a/test/lib/pixi/display/DisplayObject.js b/test/lib/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..1388a7f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObject.js
@@ -0,0 +1,43 @@
+
+function pixi_display_DisplayObject_confirmNew(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObject);
+ expect(obj).to.respondTo('setInteractive');
+ expect(obj).to.respondTo('addFilter');
+ expect(obj).to.respondTo('removeFilter');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.property('last', obj);
+ expect(obj).to.have.property('first', obj);
+
+ expect(obj).to.contain.property('position');
+ pixi_core_Point_confirm(obj.position, 0, 0);
+ expect(obj).to.contain.property('scale');
+ pixi_core_Point_confirm(obj.scale, 1, 1);
+ expect(obj).to.contain.property('pivot');
+ pixi_core_Point_confirm(obj.pivot, 0, 0);
+
+ expect(obj).to.have.property('rotation', 0);
+ expect(obj).to.have.property('alpha', 1);
+ expect(obj).to.have.property('visible', true);
+ expect(obj).to.have.property('buttonMode', false);
+ expect(obj).to.have.property('parent', null);
+ expect(obj).to.have.property('worldAlpha', 1);
+
+ expect(obj).to.have.property('hitArea');
+ expect(obj).to.have.property('interactive'); // TODO: Have a better default value
+ expect('mask' in obj).to.be.true; // TODO: Have a better default value
+ expect(obj.mask).to.be.undefined;
+
+ expect(obj).to.have.property('renderable');
+ expect(obj).to.have.property('stage');
+
+ expect(obj).to.have.deep.property('worldTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ expect(obj).to.have.deep.property('localTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.localTransform);
+
+ expect(obj).to.have.deep.property('color.length', 0);
+ expect(obj).to.have.property('dynamic', true);
+}
diff --git a/test/lib/pixi/display/DisplayObjectContainer.js b/test/lib/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..085c59f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,16 @@
+
+function pixi_display_DisplayObjectContainer_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObject_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObjectContainer);
+ expect(obj).to.respondTo('addChild');
+ expect(obj).to.respondTo('addChildAt');
+ expect(obj).to.respondTo('swapChildren');
+ expect(obj).to.respondTo('getChildAt');
+ expect(obj).to.respondTo('removeChild');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('children.length', 0);
+}
diff --git a/test/lib/pixi/display/Sprite.js b/test/lib/pixi/display/Sprite.js
new file mode 100644
index 0000000..cc7a2d6
--- /dev/null
+++ b/test/lib/pixi/display/Sprite.js
@@ -0,0 +1,28 @@
+
+function pixi_display_Sprite_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Sprite);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', true);
+ expect(obj).to.have.property('stage', null);
+
+ expect(obj).to.have.property('anchor');
+ pixi_core_Point_confirm(obj.anchor, 0, 0);
+
+ expect(obj).to.have.property('blendMode', PIXI.blendModes.NORMAL);
+ expect(obj).to.have.property('width', 1); // TODO: is 1 expected
+ expect(obj).to.have.property('height', 1); // TODO: is 1 expected
+
+ // FIXME: Just make this a boolean that is always there
+ expect(!!obj.updateFrame).to.equal(obj.texture.baseTexture.hasLoaded);
+
+ expect(obj).to.have.property('texture');
+ pixi_textures_Texture_confirmNew(obj.texture, done);
+}
diff --git a/test/lib/pixi/extras/Strip.js b/test/lib/pixi/extras/Strip.js
new file mode 100644
index 0000000..8927a8a
--- /dev/null
+++ b/test/lib/pixi/extras/Strip.js
@@ -0,0 +1,12 @@
+
+function pixi_extras_Strip_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Strip);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ // TODO: Test properties
+}
diff --git a/test/lib/pixi/textures/Texture.js b/test/lib/pixi/textures/Texture.js
new file mode 100644
index 0000000..d5867b6
--- /dev/null
+++ b/test/lib/pixi/textures/Texture.js
@@ -0,0 +1,31 @@
+
+function pixi_textures_Texture_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ function confirmFrameDone() {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, obj.baseTexture.width, obj.baseTexture.height);
+
+ expect(obj).to.have.property('width', obj.baseTexture.width);
+ expect(obj).to.have.property('height', obj.baseTexture.height);
+ done();
+ }
+
+ expect(obj).to.be.an.instanceof(PIXI.Texture);
+ pixi_utils_EventTarget_like(obj);
+
+ expect(obj).to.have.property('baseTexture')
+ .and.to.be.an.instanceof(PIXI.BaseTexture);
+
+ expect(obj).to.have.property('scope', obj);
+
+ expect(obj).to.have.property('trim');
+ pixi_core_Point_confirm(obj.trim, 0, 0);
+
+ expect(obj).to.have.property('frame');
+ if (obj.baseTexture.hasLoaded) {
+ confirmFrameDone();
+ } else {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, 1, 1);
+ obj.addEventListener('update', confirmFrameDone);
+ }
+}
diff --git a/test/lib/pixi/utils/EventTarget.js b/test/lib/pixi/utils/EventTarget.js
new file mode 100644
index 0000000..7b1dcfa
--- /dev/null
+++ b/test/lib/pixi/utils/EventTarget.js
@@ -0,0 +1,8 @@
+
+function pixi_utils_EventTarget_like(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.respondTo('addEventListener');
+ expect(obj).to.respondTo('dispatchEvent');
+ expect(obj).to.respondTo('removeEventListener');
+}
diff --git a/test/lib/qunit-1.11.0.css b/test/lib/qunit-1.11.0.css
deleted file mode 100644
index d7fc0c8..0000000
--- a/test/lib/qunit-1.11.0.css
+++ /dev/null
@@ -1,244 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-/** Font Family and Sizes */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
- font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
-}
-
-#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
-#qunit-tests { font-size: smaller; }
-
-
-/** Resets */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter {
- margin: 0;
- padding: 0;
-}
-
-
-/** Header */
-
-#qunit-header {
- padding: 0.5em 0 0.5em 1em;
-
- color: #8699a4;
- background-color: #0d3349;
-
- font-size: 1.5em;
- line-height: 1em;
- font-weight: normal;
-
- border-radius: 5px 5px 0 0;
- -moz-border-radius: 5px 5px 0 0;
- -webkit-border-top-right-radius: 5px;
- -webkit-border-top-left-radius: 5px;
-}
-
-#qunit-header a {
- text-decoration: none;
- color: #c2ccd1;
-}
-
-#qunit-header a:hover,
-#qunit-header a:focus {
- color: #fff;
-}
-
-#qunit-testrunner-toolbar label {
- display: inline-block;
- padding: 0 .5em 0 .1em;
-}
-
-#qunit-banner {
- height: 5px;
-}
-
-#qunit-testrunner-toolbar {
- padding: 0.5em 0 0.5em 2em;
- color: #5E740B;
- background-color: #eee;
- overflow: hidden;
-}
-
-#qunit-userAgent {
- padding: 0.5em 0 0.5em 2.5em;
- background-color: #2b81af;
- color: #fff;
- text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
-}
-
-#qunit-modulefilter-container {
- float: right;
-}
-
-/** Tests: Pass/Fail */
-
-#qunit-tests {
- list-style-position: inside;
-}
-
-#qunit-tests li {
- padding: 0.4em 0.5em 0.4em 2.5em;
- border-bottom: 1px solid #fff;
- list-style-position: inside;
-}
-
-#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running {
- display: none;
-}
-
-#qunit-tests li strong {
- cursor: pointer;
-}
-
-#qunit-tests li a {
- padding: 0.5em;
- color: #c2ccd1;
- text-decoration: none;
-}
-#qunit-tests li a:hover,
-#qunit-tests li a:focus {
- color: #000;
-}
-
-#qunit-tests li .runtime {
- float: right;
- font-size: smaller;
-}
-
-.qunit-assert-list {
- margin-top: 0.5em;
- padding: 0.5em;
-
- background-color: #fff;
-
- border-radius: 5px;
- -moz-border-radius: 5px;
- -webkit-border-radius: 5px;
-}
-
-.qunit-collapsed {
- display: none;
-}
-
-#qunit-tests table {
- border-collapse: collapse;
- margin-top: .2em;
-}
-
-#qunit-tests th {
- text-align: right;
- vertical-align: top;
- padding: 0 .5em 0 0;
-}
-
-#qunit-tests td {
- vertical-align: top;
-}
-
-#qunit-tests pre {
- margin: 0;
- white-space: pre-wrap;
- word-wrap: break-word;
-}
-
-#qunit-tests del {
- background-color: #e0f2be;
- color: #374e0c;
- text-decoration: none;
-}
-
-#qunit-tests ins {
- background-color: #ffcaca;
- color: #500;
- text-decoration: none;
-}
-
-/*** Test Counts */
-
-#qunit-tests b.counts { color: black; }
-#qunit-tests b.passed { color: #5E740B; }
-#qunit-tests b.failed { color: #710909; }
-
-#qunit-tests li li {
- padding: 5px;
- background-color: #fff;
- border-bottom: none;
- list-style-position: inside;
-}
-
-/*** Passing Styles */
-
-#qunit-tests li li.pass {
- color: #3c510c;
- background-color: #fff;
- border-left: 10px solid #C6E746;
-}
-
-#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
-#qunit-tests .pass .test-name { color: #366097; }
-
-#qunit-tests .pass .test-actual,
-#qunit-tests .pass .test-expected { color: #999999; }
-
-#qunit-banner.qunit-pass { background-color: #C6E746; }
-
-/*** Failing Styles */
-
-#qunit-tests li li.fail {
- color: #710909;
- background-color: #fff;
- border-left: 10px solid #EE5757;
- white-space: pre;
-}
-
-#qunit-tests > li:last-child {
- border-radius: 0 0 5px 5px;
- -moz-border-radius: 0 0 5px 5px;
- -webkit-border-bottom-right-radius: 5px;
- -webkit-border-bottom-left-radius: 5px;
-}
-
-#qunit-tests .fail { color: #000000; background-color: #EE5757; }
-#qunit-tests .fail .test-name,
-#qunit-tests .fail .module-name { color: #000000; }
-
-#qunit-tests .fail .test-actual { color: #EE5757; }
-#qunit-tests .fail .test-expected { color: green; }
-
-#qunit-banner.qunit-fail { background-color: #EE5757; }
-
-
-/** Result */
-
-#qunit-testresult {
- padding: 0.5em 0.5em 0.5em 2.5em;
-
- color: #2b81af;
- background-color: #D2E0E6;
-
- border-bottom: 1px solid white;
-}
-#qunit-testresult .module-name {
- font-weight: bold;
-}
-
-/** Fixture */
-
-#qunit-fixture {
- position: absolute;
- top: -10000px;
- left: -10000px;
- width: 1000px;
- height: 1000px;
-}
diff --git a/test/lib/qunit-1.11.0.js b/test/lib/qunit-1.11.0.js
deleted file mode 100644
index 302545f..0000000
--- a/test/lib/qunit-1.11.0.js
+++ /dev/null
@@ -1,2152 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-(function( window ) {
-
-var QUnit,
- assert,
- config,
- onErrorFnPrev,
- testId = 0,
- fileName = (sourceFromStacktrace( 0 ) || "" ).replace(/(:\d+)+\)?/, "").replace(/.+\//, ""),
- toString = Object.prototype.toString,
- hasOwn = Object.prototype.hasOwnProperty,
- // Keep a local reference to Date (GH-283)
- Date = window.Date,
- defined = {
- setTimeout: typeof window.setTimeout !== "undefined",
- sessionStorage: (function() {
- var x = "qunit-test-string";
- try {
- sessionStorage.setItem( x, x );
- sessionStorage.removeItem( x );
- return true;
- } catch( e ) {
- return false;
- }
- }())
- },
- /**
- * Provides a normalized error string, correcting an issue
- * with IE 7 (and prior) where Error.prototype.toString is
- * not properly implemented
- *
- * Based on http://es5.github.com/#x15.11.4.4
- *
- * @param {String|Error} error
- * @return {String} error message
- */
- errorString = function( error ) {
- var name, message,
- errorString = error.toString();
- if ( errorString.substring( 0, 7 ) === "[object" ) {
- name = error.name ? error.name.toString() : "Error";
- message = error.message ? error.message.toString() : "";
- if ( name && message ) {
- return name + ": " + message;
- } else if ( name ) {
- return name;
- } else if ( message ) {
- return message;
- } else {
- return "Error";
- }
- } else {
- return errorString;
- }
- },
- /**
- * Makes a clone of an object using only Array or Object as base,
- * and copies over the own enumerable properties.
- *
- * @param {Object} obj
- * @return {Object} New object with only the own properties (recursively).
- */
- objectValues = function( obj ) {
- // Grunt 0.3.x uses an older version of jshint that still has jshint/jshint#392.
- /*jshint newcap: false */
- var key, val,
- vals = QUnit.is( "array", obj ) ? [] : {};
- for ( key in obj ) {
- if ( hasOwn.call( obj, key ) ) {
- val = obj[key];
- vals[key] = val === Object(val) ? objectValues(val) : val;
- }
- }
- return vals;
- };
-
-function Test( settings ) {
- extend( this, settings );
- this.assertions = [];
- this.testNumber = ++Test.count;
-}
-
-Test.count = 0;
-
-Test.prototype = {
- init: function() {
- var a, b, li,
- tests = id( "qunit-tests" );
-
- if ( tests ) {
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml;
-
- // `a` initialized at top of scope
- a = document.createElement( "a" );
- a.innerHTML = "Rerun";
- a.href = QUnit.url({ testNumber: this.testNumber });
-
- li = document.createElement( "li" );
- li.appendChild( b );
- li.appendChild( a );
- li.className = "running";
- li.id = this.id = "qunit-test-output" + testId++;
-
- tests.appendChild( li );
- }
- },
- setup: function() {
- if ( this.module !== config.previousModule ) {
- if ( config.previousModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.previousModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
- config.previousModule = this.module;
- config.moduleStats = { all: 0, bad: 0 };
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- } else if ( config.autorun ) {
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- }
-
- config.current = this;
-
- this.testEnvironment = extend({
- setup: function() {},
- teardown: function() {}
- }, this.moduleTestEnvironment );
-
- this.started = +new Date();
- runLoggingCallbacks( "testStart", QUnit, {
- name: this.testName,
- module: this.module
- });
-
- // allow utility functions to access the current test environment
- // TODO why??
- QUnit.current_testEnvironment = this.testEnvironment;
-
- if ( !config.pollution ) {
- saveGlobal();
- }
- if ( config.notrycatch ) {
- this.testEnvironment.setup.call( this.testEnvironment );
- return;
- }
- try {
- this.testEnvironment.setup.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Setup failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- },
- run: function() {
- config.current = this;
-
- var running = id( "qunit-testresult" );
-
- if ( running ) {
- running.innerHTML = "Running:
" + this.nameHtml;
- }
-
- if ( this.async ) {
- QUnit.stop();
- }
-
- this.callbackStarted = +new Date();
-
- if ( config.notrycatch ) {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- return;
- }
-
- try {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- } catch( e ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
-
- QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + " " + this.stack + ": " + ( e.message || e ), extractStacktrace( e, 0 ) );
- // else next test will carry the responsibility
- saveGlobal();
-
- // Restart the tests if they're blocking
- if ( config.blocking ) {
- QUnit.start();
- }
- }
- },
- teardown: function() {
- config.current = this;
- if ( config.notrycatch ) {
- if ( typeof this.callbackRuntime === "undefined" ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
- }
- this.testEnvironment.teardown.call( this.testEnvironment );
- return;
- } else {
- try {
- this.testEnvironment.teardown.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Teardown failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- }
- checkPollution();
- },
- finish: function() {
- config.current = this;
- if ( config.requireExpects && this.expected === null ) {
- QUnit.pushFailure( "Expected number of assertions to be defined, but expect() was not called.", this.stack );
- } else if ( this.expected !== null && this.expected !== this.assertions.length ) {
- QUnit.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack );
- } else if ( this.expected === null && !this.assertions.length ) {
- QUnit.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions.", this.stack );
- }
-
- var i, assertion, a, b, time, li, ol,
- test = this,
- good = 0,
- bad = 0,
- tests = id( "qunit-tests" );
-
- this.runtime = +new Date() - this.started;
- config.stats.all += this.assertions.length;
- config.moduleStats.all += this.assertions.length;
-
- if ( tests ) {
- ol = document.createElement( "ol" );
- ol.className = "qunit-assert-list";
-
- for ( i = 0; i < this.assertions.length; i++ ) {
- assertion = this.assertions[i];
-
- li = document.createElement( "li" );
- li.className = assertion.result ? "pass" : "fail";
- li.innerHTML = assertion.message || ( assertion.result ? "okay" : "failed" );
- ol.appendChild( li );
-
- if ( assertion.result ) {
- good++;
- } else {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
-
- // store result when possible
- if ( QUnit.config.reorder && defined.sessionStorage ) {
- if ( bad ) {
- sessionStorage.setItem( "qunit-test-" + this.module + "-" + this.testName, bad );
- } else {
- sessionStorage.removeItem( "qunit-test-" + this.module + "-" + this.testName );
- }
- }
-
- if ( bad === 0 ) {
- addClass( ol, "qunit-collapsed" );
- }
-
- // `b` initialized at top of scope
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml + " (" + bad + ", " + good + ", " + this.assertions.length + ")";
-
- addEvent(b, "click", function() {
- var next = b.parentNode.lastChild,
- collapsed = hasClass( next, "qunit-collapsed" );
- ( collapsed ? removeClass : addClass )( next, "qunit-collapsed" );
- });
-
- addEvent(b, "dblclick", function( e ) {
- var target = e && e.target ? e.target : window.event.srcElement;
- if ( target.nodeName.toLowerCase() === "span" || target.nodeName.toLowerCase() === "b" ) {
- target = target.parentNode;
- }
- if ( window.location && target.nodeName.toLowerCase() === "strong" ) {
- window.location = QUnit.url({ testNumber: test.testNumber });
- }
- });
-
- // `time` initialized at top of scope
- time = document.createElement( "span" );
- time.className = "runtime";
- time.innerHTML = this.runtime + " ms";
-
- // `li` initialized at top of scope
- li = id( this.id );
- li.className = bad ? "fail" : "pass";
- li.removeChild( li.firstChild );
- a = li.firstChild;
- li.appendChild( b );
- li.appendChild( a );
- li.appendChild( time );
- li.appendChild( ol );
-
- } else {
- for ( i = 0; i < this.assertions.length; i++ ) {
- if ( !this.assertions[i].result ) {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
- }
-
- runLoggingCallbacks( "testDone", QUnit, {
- name: this.testName,
- module: this.module,
- failed: bad,
- passed: this.assertions.length - bad,
- total: this.assertions.length,
- duration: this.runtime
- });
-
- QUnit.reset();
-
- config.current = undefined;
- },
-
- queue: function() {
- var bad,
- test = this;
-
- synchronize(function() {
- test.init();
- });
- function run() {
- // each of these can by async
- synchronize(function() {
- test.setup();
- });
- synchronize(function() {
- test.run();
- });
- synchronize(function() {
- test.teardown();
- });
- synchronize(function() {
- test.finish();
- });
- }
-
- // `bad` initialized at top of scope
- // defer when previous test run passed, if storage is available
- bad = QUnit.config.reorder && defined.sessionStorage &&
- +sessionStorage.getItem( "qunit-test-" + this.module + "-" + this.testName );
-
- if ( bad ) {
- run();
- } else {
- synchronize( run, true );
- }
- }
-};
-
-// Root QUnit object.
-// `QUnit` initialized at top of scope
-QUnit = {
-
- // call on start of module test to prepend name to all tests
- module: function( name, testEnvironment ) {
- config.currentModule = name;
- config.currentModuleTestEnvironment = testEnvironment;
- config.modules[name] = true;
- },
-
- asyncTest: function( testName, expected, callback ) {
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- QUnit.test( testName, expected, callback, true );
- },
-
- test: function( testName, expected, callback, async ) {
- var test,
- nameHtml = "" + escapeText( testName ) + "";
-
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- if ( config.currentModule ) {
- nameHtml = "" + escapeText( config.currentModule ) + ": " + nameHtml;
- }
-
- test = new Test({
- nameHtml: nameHtml,
- testName: testName,
- expected: expected,
- async: async,
- callback: callback,
- module: config.currentModule,
- moduleTestEnvironment: config.currentModuleTestEnvironment,
- stack: sourceFromStacktrace( 2 )
- });
-
- if ( !validTest( test ) ) {
- return;
- }
-
- test.queue();
- },
-
- // Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through.
- expect: function( asserts ) {
- if (arguments.length === 1) {
- config.current.expected = asserts;
- } else {
- return config.current.expected;
- }
- },
-
- start: function( count ) {
- // QUnit hasn't been initialized yet.
- // Note: RequireJS (et al) may delay onLoad
- if ( config.semaphore === undefined ) {
- QUnit.begin(function() {
- // This is triggered at the top of QUnit.load, push start() to the event loop, to allow QUnit.load to finish first
- setTimeout(function() {
- QUnit.start( count );
- });
- });
- return;
- }
-
- config.semaphore -= count || 1;
- // don't start until equal number of stop-calls
- if ( config.semaphore > 0 ) {
- return;
- }
- // ignore if start is called more often then stop
- if ( config.semaphore < 0 ) {
- config.semaphore = 0;
- QUnit.pushFailure( "Called start() while already started (QUnit.config.semaphore was 0 already)", null, sourceFromStacktrace(2) );
- return;
- }
- // A slight delay, to avoid any current callbacks
- if ( defined.setTimeout ) {
- window.setTimeout(function() {
- if ( config.semaphore > 0 ) {
- return;
- }
- if ( config.timeout ) {
- clearTimeout( config.timeout );
- }
-
- config.blocking = false;
- process( true );
- }, 13);
- } else {
- config.blocking = false;
- process( true );
- }
- },
-
- stop: function( count ) {
- config.semaphore += count || 1;
- config.blocking = true;
-
- if ( config.testTimeout && defined.setTimeout ) {
- clearTimeout( config.timeout );
- config.timeout = window.setTimeout(function() {
- QUnit.ok( false, "Test timed out" );
- config.semaphore = 1;
- QUnit.start();
- }, config.testTimeout );
- }
- }
-};
-
-// `assert` initialized at top of scope
-// Asssert helpers
-// All of these must either call QUnit.push() or manually do:
-// - runLoggingCallbacks( "log", .. );
-// - config.current.assertions.push({ .. });
-// We attach it to the QUnit object *after* we expose the public API,
-// otherwise `assert` will become a global variable in browsers (#341).
-assert = {
- /**
- * Asserts rough true-ish result.
- * @name ok
- * @function
- * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" );
- */
- ok: function( result, msg ) {
- if ( !config.current ) {
- throw new Error( "ok() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
- result = !!result;
-
- var source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: msg
- };
-
- msg = escapeText( msg || (result ? "okay" : "failed" ) );
- msg = "" + msg + "";
-
- if ( !result ) {
- source = sourceFromStacktrace( 2 );
- if ( source ) {
- details.source = source;
- msg += "Source: | " + escapeText( source ) + " |
---|
";
- }
- }
- runLoggingCallbacks( "log", QUnit, details );
- config.current.assertions.push({
- result: result,
- message: msg
- });
- },
-
- /**
- * Assert that the first two arguments are equal, with an optional message.
- * Prints out both actual and expected values.
- * @name equal
- * @function
- * @example equal( format( "Received {0} bytes.", 2), "Received 2 bytes.", "format() replaces {0} with next argument" );
- */
- equal: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected == actual, actual, expected, message );
- },
-
- /**
- * @name notEqual
- * @function
- */
- notEqual: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected != actual, actual, expected, message );
- },
-
- /**
- * @name propEqual
- * @function
- */
- propEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notPropEqual
- * @function
- */
- notPropEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name deepEqual
- * @function
- */
- deepEqual: function( actual, expected, message ) {
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notDeepEqual
- * @function
- */
- notDeepEqual: function( actual, expected, message ) {
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name strictEqual
- * @function
- */
- strictEqual: function( actual, expected, message ) {
- QUnit.push( expected === actual, actual, expected, message );
- },
-
- /**
- * @name notStrictEqual
- * @function
- */
- notStrictEqual: function( actual, expected, message ) {
- QUnit.push( expected !== actual, actual, expected, message );
- },
-
- "throws": function( block, expected, message ) {
- var actual,
- expectedOutput = expected,
- ok = false;
-
- // 'expected' is optional
- if ( typeof expected === "string" ) {
- message = expected;
- expected = null;
- }
-
- config.current.ignoreGlobalErrors = true;
- try {
- block.call( config.current.testEnvironment );
- } catch (e) {
- actual = e;
- }
- config.current.ignoreGlobalErrors = false;
-
- if ( actual ) {
- // we don't want to validate thrown error
- if ( !expected ) {
- ok = true;
- expectedOutput = null;
- // expected is a regexp
- } else if ( QUnit.objectType( expected ) === "regexp" ) {
- ok = expected.test( errorString( actual ) );
- // expected is a constructor
- } else if ( actual instanceof expected ) {
- ok = true;
- // expected is a validation function which returns true is validation passed
- } else if ( expected.call( {}, actual ) === true ) {
- expectedOutput = null;
- ok = true;
- }
-
- QUnit.push( ok, actual, expectedOutput, message );
- } else {
- QUnit.pushFailure( message, null, 'No exception was thrown.' );
- }
- }
-};
-
-/**
- * @deprecate since 1.8.0
- * Kept assertion helpers in root for backwards compatibility.
- */
-extend( QUnit, assert );
-
-/**
- * @deprecated since 1.9.0
- * Kept root "raises()" for backwards compatibility.
- * (Note that we don't introduce assert.raises).
- */
-QUnit.raises = assert[ "throws" ];
-
-/**
- * @deprecated since 1.0.0, replaced with error pushes since 1.3.0
- * Kept to avoid TypeErrors for undefined methods.
- */
-QUnit.equals = function() {
- QUnit.push( false, false, false, "QUnit.equals has been deprecated since 2009 (e88049a0), use QUnit.equal instead" );
-};
-QUnit.same = function() {
- QUnit.push( false, false, false, "QUnit.same has been deprecated since 2009 (e88049a0), use QUnit.deepEqual instead" );
-};
-
-// We want access to the constructor's prototype
-(function() {
- function F() {}
- F.prototype = QUnit;
- QUnit = new F();
- // Make F QUnit's constructor so that we can add to the prototype later
- QUnit.constructor = F;
-}());
-
-/**
- * Config object: Maintain internal state
- * Later exposed as QUnit.config
- * `config` initialized at top of scope
- */
-config = {
- // The queue of tests to run
- queue: [],
-
- // block until document ready
- blocking: true,
-
- // when enabled, show only failing tests
- // gets persisted through sessionStorage and can be changed in UI via checkbox
- hidepassed: false,
-
- // by default, run previously failed tests first
- // very useful in combination with "Hide passed tests" checked
- reorder: true,
-
- // by default, modify document.title when suite is done
- altertitle: true,
-
- // when enabled, all tests must call expect()
- requireExpects: false,
-
- // add checkboxes that are persisted in the query-string
- // when enabled, the id is set to `true` as a `QUnit.config` property
- urlConfig: [
- {
- id: "noglobals",
- label: "Check for Globals",
- tooltip: "Enabling this will test if any test introduces new properties on the `window` object. Stored as query-strings."
- },
- {
- id: "notrycatch",
- label: "No try-catch",
- tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging exceptions in IE reasonable. Stored as query-strings."
- }
- ],
-
- // Set of all modules.
- modules: {},
-
- // logging callback queues
- begin: [],
- done: [],
- log: [],
- testStart: [],
- testDone: [],
- moduleStart: [],
- moduleDone: []
-};
-
-// Export global variables, unless an 'exports' object exists,
-// in that case we assume we're in CommonJS (dealt with on the bottom of the script)
-if ( typeof exports === "undefined" ) {
- extend( window, QUnit );
-
- // Expose QUnit object
- window.QUnit = QUnit;
-}
-
-// Initialize more QUnit.config and QUnit.urlParams
-(function() {
- var i,
- location = window.location || { search: "", protocol: "file:" },
- params = location.search.slice( 1 ).split( "&" ),
- length = params.length,
- urlParams = {},
- current;
-
- if ( params[ 0 ] ) {
- for ( i = 0; i < length; i++ ) {
- current = params[ i ].split( "=" );
- current[ 0 ] = decodeURIComponent( current[ 0 ] );
- // allow just a key to turn on a flag, e.g., test.html?noglobals
- current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true;
- urlParams[ current[ 0 ] ] = current[ 1 ];
- }
- }
-
- QUnit.urlParams = urlParams;
-
- // String search anywhere in moduleName+testName
- config.filter = urlParams.filter;
-
- // Exact match of the module name
- config.module = urlParams.module;
-
- config.testNumber = parseInt( urlParams.testNumber, 10 ) || null;
-
- // Figure out if we're running the tests from a server or not
- QUnit.isLocal = location.protocol === "file:";
-}());
-
-// Extend QUnit object,
-// these after set here because they should not be exposed as global functions
-extend( QUnit, {
- assert: assert,
-
- config: config,
-
- // Initialize the configuration options
- init: function() {
- extend( config, {
- stats: { all: 0, bad: 0 },
- moduleStats: { all: 0, bad: 0 },
- started: +new Date(),
- updateRate: 1000,
- blocking: false,
- autostart: true,
- autorun: false,
- filter: "",
- queue: [],
- semaphore: 1
- });
-
- var tests, banner, result,
- qunit = id( "qunit" );
-
- if ( qunit ) {
- qunit.innerHTML =
- "" +
- "" +
- "" +
- "" +
- "
";
- }
-
- tests = id( "qunit-tests" );
- banner = id( "qunit-banner" );
- result = id( "qunit-testresult" );
-
- if ( tests ) {
- tests.innerHTML = "";
- }
-
- if ( banner ) {
- banner.className = "";
- }
-
- if ( result ) {
- result.parentNode.removeChild( result );
- }
-
- if ( tests ) {
- result = document.createElement( "p" );
- result.id = "qunit-testresult";
- result.className = "result";
- tests.parentNode.insertBefore( result, tests );
- result.innerHTML = "Running...
";
- }
- },
-
- // Resets the test setup. Useful for tests that modify the DOM.
- reset: function() {
- var fixture = id( "qunit-fixture" );
- if ( fixture ) {
- fixture.innerHTML = config.fixture;
- }
- },
-
- // Trigger an event on an element.
- // @example triggerEvent( document.body, "click" );
- triggerEvent: function( elem, type, event ) {
- if ( document.createEvent ) {
- event = document.createEvent( "MouseEvents" );
- event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView,
- 0, 0, 0, 0, 0, false, false, false, false, 0, null);
-
- elem.dispatchEvent( event );
- } else if ( elem.fireEvent ) {
- elem.fireEvent( "on" + type );
- }
- },
-
- // Safe object type checking
- is: function( type, obj ) {
- return QUnit.objectType( obj ) === type;
- },
-
- objectType: function( obj ) {
- if ( typeof obj === "undefined" ) {
- return "undefined";
- // consider: typeof null === object
- }
- if ( obj === null ) {
- return "null";
- }
-
- var match = toString.call( obj ).match(/^\[object\s(.*)\]$/),
- type = match && match[1] || "";
-
- switch ( type ) {
- case "Number":
- if ( isNaN(obj) ) {
- return "nan";
- }
- return "number";
- case "String":
- case "Boolean":
- case "Array":
- case "Date":
- case "RegExp":
- case "Function":
- return type.toLowerCase();
- }
- if ( typeof obj === "object" ) {
- return "object";
- }
- return undefined;
- },
-
- push: function( result, actual, expected, message ) {
- if ( !config.current ) {
- throw new Error( "assertion outside test context, was " + sourceFromStacktrace() );
- }
-
- var output, source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: message,
- actual: actual,
- expected: expected
- };
-
- message = escapeText( message ) || ( result ? "okay" : "failed" );
- message = "" + message + "";
- output = message;
-
- if ( !result ) {
- expected = escapeText( QUnit.jsDump.parse(expected) );
- actual = escapeText( QUnit.jsDump.parse(actual) );
- output += "Expected: | " + expected + " |
";
-
- if ( actual !== expected ) {
- output += "Result: | " + actual + " |
";
- output += "Diff: | " + QUnit.diff( expected, actual ) + " |
";
- }
-
- source = sourceFromStacktrace();
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
- }
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: !!result,
- message: output
- });
- },
-
- pushFailure: function( message, source, actual ) {
- if ( !config.current ) {
- throw new Error( "pushFailure() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
-
- var output,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: false,
- message: message
- };
-
- message = escapeText( message ) || "error";
- message = "" + message + "";
- output = message;
-
- output += "";
-
- if ( actual ) {
- output += "Result: | " + escapeText( actual ) + " |
";
- }
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: false,
- message: output
- });
- },
-
- url: function( params ) {
- params = extend( extend( {}, QUnit.urlParams ), params );
- var key,
- querystring = "?";
-
- for ( key in params ) {
- if ( !hasOwn.call( params, key ) ) {
- continue;
- }
- querystring += encodeURIComponent( key ) + "=" +
- encodeURIComponent( params[ key ] ) + "&";
- }
- return window.location.protocol + "//" + window.location.host +
- window.location.pathname + querystring.slice( 0, -1 );
- },
-
- extend: extend,
- id: id,
- addEvent: addEvent
- // load, equiv, jsDump, diff: Attached later
-});
-
-/**
- * @deprecated: Created for backwards compatibility with test runner that set the hook function
- * into QUnit.{hook}, instead of invoking it and passing the hook function.
- * QUnit.constructor is set to the empty F() above so that we can add to it's prototype here.
- * Doing this allows us to tell if the following methods have been overwritten on the actual
- * QUnit object.
- */
-extend( QUnit.constructor.prototype, {
-
- // Logging callbacks; all receive a single argument with the listed properties
- // run test/logs.html for any related changes
- begin: registerLoggingCallback( "begin" ),
-
- // done: { failed, passed, total, runtime }
- done: registerLoggingCallback( "done" ),
-
- // log: { result, actual, expected, message }
- log: registerLoggingCallback( "log" ),
-
- // testStart: { name }
- testStart: registerLoggingCallback( "testStart" ),
-
- // testDone: { name, failed, passed, total, duration }
- testDone: registerLoggingCallback( "testDone" ),
-
- // moduleStart: { name }
- moduleStart: registerLoggingCallback( "moduleStart" ),
-
- // moduleDone: { name, failed, passed, total }
- moduleDone: registerLoggingCallback( "moduleDone" )
-});
-
-if ( typeof document === "undefined" || document.readyState === "complete" ) {
- config.autorun = true;
-}
-
-QUnit.load = function() {
- runLoggingCallbacks( "begin", QUnit, {} );
-
- // Initialize the config, saving the execution queue
- var banner, filter, i, label, len, main, ol, toolbar, userAgent, val,
- urlConfigCheckboxesContainer, urlConfigCheckboxes, moduleFilter,
- numModules = 0,
- moduleFilterHtml = "",
- urlConfigHtml = "",
- oldconfig = extend( {}, config );
-
- QUnit.init();
- extend(config, oldconfig);
-
- config.blocking = false;
-
- len = config.urlConfig.length;
-
- for ( i = 0; i < len; i++ ) {
- val = config.urlConfig[i];
- if ( typeof val === "string" ) {
- val = {
- id: val,
- label: val,
- tooltip: "[no tooltip available]"
- };
- }
- config[ val.id ] = QUnit.urlParams[ val.id ];
- urlConfigHtml += "";
- }
-
- moduleFilterHtml += "";
-
- // `userAgent` initialized at top of scope
- userAgent = id( "qunit-userAgent" );
- if ( userAgent ) {
- userAgent.innerHTML = navigator.userAgent;
- }
-
- // `banner` initialized at top of scope
- banner = id( "qunit-header" );
- if ( banner ) {
- banner.innerHTML = "" + banner.innerHTML + " ";
- }
-
- // `toolbar` initialized at top of scope
- toolbar = id( "qunit-testrunner-toolbar" );
- if ( toolbar ) {
- // `filter` initialized at top of scope
- filter = document.createElement( "input" );
- filter.type = "checkbox";
- filter.id = "qunit-filter-pass";
-
- addEvent( filter, "click", function() {
- var tmp,
- ol = document.getElementById( "qunit-tests" );
-
- if ( filter.checked ) {
- ol.className = ol.className + " hidepass";
- } else {
- tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " ";
- ol.className = tmp.replace( / hidepass /, " " );
- }
- if ( defined.sessionStorage ) {
- if (filter.checked) {
- sessionStorage.setItem( "qunit-filter-passed-tests", "true" );
- } else {
- sessionStorage.removeItem( "qunit-filter-passed-tests" );
- }
- }
- });
-
- if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem( "qunit-filter-passed-tests" ) ) {
- filter.checked = true;
- // `ol` initialized at top of scope
- ol = document.getElementById( "qunit-tests" );
- ol.className = ol.className + " hidepass";
- }
- toolbar.appendChild( filter );
-
- // `label` initialized at top of scope
- label = document.createElement( "label" );
- label.setAttribute( "for", "qunit-filter-pass" );
- label.setAttribute( "title", "Only show tests and assertons that fail. Stored in sessionStorage." );
- label.innerHTML = "Hide passed tests";
- toolbar.appendChild( label );
-
- urlConfigCheckboxesContainer = document.createElement("span");
- urlConfigCheckboxesContainer.innerHTML = urlConfigHtml;
- urlConfigCheckboxes = urlConfigCheckboxesContainer.getElementsByTagName("input");
- // For oldIE support:
- // * Add handlers to the individual elements instead of the container
- // * Use "click" instead of "change"
- // * Fallback from event.target to event.srcElement
- addEvents( urlConfigCheckboxes, "click", function( event ) {
- var params = {},
- target = event.target || event.srcElement;
- params[ target.name ] = target.checked ? true : undefined;
- window.location = QUnit.url( params );
- });
- toolbar.appendChild( urlConfigCheckboxesContainer );
-
- if (numModules > 1) {
- moduleFilter = document.createElement( 'span' );
- moduleFilter.setAttribute( 'id', 'qunit-modulefilter-container' );
- moduleFilter.innerHTML = moduleFilterHtml;
- addEvent( moduleFilter.lastChild, "change", function() {
- var selectBox = moduleFilter.getElementsByTagName("select")[0],
- selectedModule = decodeURIComponent(selectBox.options[selectBox.selectedIndex].value);
-
- window.location = QUnit.url( { module: ( selectedModule === "" ) ? undefined : selectedModule } );
- });
- toolbar.appendChild(moduleFilter);
- }
- }
-
- // `main` initialized at top of scope
- main = id( "qunit-fixture" );
- if ( main ) {
- config.fixture = main.innerHTML;
- }
-
- if ( config.autostart ) {
- QUnit.start();
- }
-};
-
-addEvent( window, "load", QUnit.load );
-
-// `onErrorFnPrev` initialized at top of scope
-// Preserve other handlers
-onErrorFnPrev = window.onerror;
-
-// Cover uncaught exceptions
-// Returning true will surpress the default browser handler,
-// returning false will let it run.
-window.onerror = function ( error, filePath, linerNr ) {
- var ret = false;
- if ( onErrorFnPrev ) {
- ret = onErrorFnPrev( error, filePath, linerNr );
- }
-
- // Treat return value as window.onerror itself does,
- // Only do our handling if not surpressed.
- if ( ret !== true ) {
- if ( QUnit.config.current ) {
- if ( QUnit.config.current.ignoreGlobalErrors ) {
- return true;
- }
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- } else {
- QUnit.test( "global failure", extend( function() {
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- }, { validTest: validTest } ) );
- }
- return false;
- }
-
- return ret;
-};
-
-function done() {
- config.autorun = true;
-
- // Log the last module results
- if ( config.currentModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.currentModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
-
- var i, key,
- banner = id( "qunit-banner" ),
- tests = id( "qunit-tests" ),
- runtime = +new Date() - config.started,
- passed = config.stats.all - config.stats.bad,
- html = [
- "Tests completed in ",
- runtime,
- " milliseconds.
",
- "",
- passed,
- " assertions of ",
- config.stats.all,
- " passed, ",
- config.stats.bad,
- " failed."
- ].join( "" );
-
- if ( banner ) {
- banner.className = ( config.stats.bad ? "qunit-fail" : "qunit-pass" );
- }
-
- if ( tests ) {
- id( "qunit-testresult" ).innerHTML = html;
- }
-
- if ( config.altertitle && typeof document !== "undefined" && document.title ) {
- // show ✖ for good, ✔ for bad suite result in title
- // use escape sequences in case file gets loaded with non-utf-8-charset
- document.title = [
- ( config.stats.bad ? "\u2716" : "\u2714" ),
- document.title.replace( /^[\u2714\u2716] /i, "" )
- ].join( " " );
- }
-
- // clear own sessionStorage items if all tests passed
- if ( config.reorder && defined.sessionStorage && config.stats.bad === 0 ) {
- // `key` & `i` initialized at top of scope
- for ( i = 0; i < sessionStorage.length; i++ ) {
- key = sessionStorage.key( i++ );
- if ( key.indexOf( "qunit-test-" ) === 0 ) {
- sessionStorage.removeItem( key );
- }
- }
- }
-
- // scroll back to top to show results
- if ( window.scrollTo ) {
- window.scrollTo(0, 0);
- }
-
- runLoggingCallbacks( "done", QUnit, {
- failed: config.stats.bad,
- passed: passed,
- total: config.stats.all,
- runtime: runtime
- });
-}
-
-/** @return Boolean: true if this test should be ran */
-function validTest( test ) {
- var include,
- filter = config.filter && config.filter.toLowerCase(),
- module = config.module && config.module.toLowerCase(),
- fullName = (test.module + ": " + test.testName).toLowerCase();
-
- // Internally-generated tests are always valid
- if ( test.callback && test.callback.validTest === validTest ) {
- delete test.callback.validTest;
- return true;
- }
-
- if ( config.testNumber ) {
- return test.testNumber === config.testNumber;
- }
-
- if ( module && ( !test.module || test.module.toLowerCase() !== module ) ) {
- return false;
- }
-
- if ( !filter ) {
- return true;
- }
-
- include = filter.charAt( 0 ) !== "!";
- if ( !include ) {
- filter = filter.slice( 1 );
- }
-
- // If the filter matches, we need to honour include
- if ( fullName.indexOf( filter ) !== -1 ) {
- return include;
- }
-
- // Otherwise, do the opposite
- return !include;
-}
-
-// so far supports only Firefox, Chrome and Opera (buggy), Safari (for real exceptions)
-// Later Safari and IE10 are supposed to support error.stack as well
-// See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack
-function extractStacktrace( e, offset ) {
- offset = offset === undefined ? 3 : offset;
-
- var stack, include, i;
-
- if ( e.stacktrace ) {
- // Opera
- return e.stacktrace.split( "\n" )[ offset + 3 ];
- } else if ( e.stack ) {
- // Firefox, Chrome
- stack = e.stack.split( "\n" );
- if (/^error$/i.test( stack[0] ) ) {
- stack.shift();
- }
- if ( fileName ) {
- include = [];
- for ( i = offset; i < stack.length; i++ ) {
- if ( stack[ i ].indexOf( fileName ) !== -1 ) {
- break;
- }
- include.push( stack[ i ] );
- }
- if ( include.length ) {
- return include.join( "\n" );
- }
- }
- return stack[ offset ];
- } else if ( e.sourceURL ) {
- // Safari, PhantomJS
- // hopefully one day Safari provides actual stacktraces
- // exclude useless self-reference for generated Error objects
- if ( /qunit.js$/.test( e.sourceURL ) ) {
- return;
- }
- // for actual exceptions, this is useful
- return e.sourceURL + ":" + e.line;
- }
-}
-function sourceFromStacktrace( offset ) {
- try {
- throw new Error();
- } catch ( e ) {
- return extractStacktrace( e, offset );
- }
-}
-
-/**
- * Escape text for attribute or text content.
- */
-function escapeText( s ) {
- if ( !s ) {
- return "";
- }
- s = s + "";
- // Both single quotes and double quotes (for attributes)
- return s.replace( /['"<>&]/g, function( s ) {
- switch( s ) {
- case '\'':
- return ''';
- case '"':
- return '"';
- case '<':
- return '<';
- case '>':
- return '>';
- case '&':
- return '&';
- }
- });
-}
-
-function synchronize( callback, last ) {
- config.queue.push( callback );
-
- if ( config.autorun && !config.blocking ) {
- process( last );
- }
-}
-
-function process( last ) {
- function next() {
- process( last );
- }
- var start = new Date().getTime();
- config.depth = config.depth ? config.depth + 1 : 1;
-
- while ( config.queue.length && !config.blocking ) {
- if ( !defined.setTimeout || config.updateRate <= 0 || ( ( new Date().getTime() - start ) < config.updateRate ) ) {
- config.queue.shift()();
- } else {
- window.setTimeout( next, 13 );
- break;
- }
- }
- config.depth--;
- if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) {
- done();
- }
-}
-
-function saveGlobal() {
- config.pollution = [];
-
- if ( config.noglobals ) {
- for ( var key in window ) {
- // in Opera sometimes DOM element ids show up here, ignore them
- if ( !hasOwn.call( window, key ) || /^qunit-test-output/.test( key ) ) {
- continue;
- }
- config.pollution.push( key );
- }
- }
-}
-
-function checkPollution() {
- var newGlobals,
- deletedGlobals,
- old = config.pollution;
-
- saveGlobal();
-
- newGlobals = diff( config.pollution, old );
- if ( newGlobals.length > 0 ) {
- QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join(", ") );
- }
-
- deletedGlobals = diff( old, config.pollution );
- if ( deletedGlobals.length > 0 ) {
- QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join(", ") );
- }
-}
-
-// returns a new Array with the elements that are in a but not in b
-function diff( a, b ) {
- var i, j,
- result = a.slice();
-
- for ( i = 0; i < result.length; i++ ) {
- for ( j = 0; j < b.length; j++ ) {
- if ( result[i] === b[j] ) {
- result.splice( i, 1 );
- i--;
- break;
- }
- }
- }
- return result;
-}
-
-function extend( a, b ) {
- for ( var prop in b ) {
- if ( b[ prop ] === undefined ) {
- delete a[ prop ];
-
- // Avoid "Member not found" error in IE8 caused by setting window.constructor
- } else if ( prop !== "constructor" || a !== window ) {
- a[ prop ] = b[ prop ];
- }
- }
-
- return a;
-}
-
-/**
- * @param {HTMLElement} elem
- * @param {string} type
- * @param {Function} fn
- */
-function addEvent( elem, type, fn ) {
- // Standards-based browsers
- if ( elem.addEventListener ) {
- elem.addEventListener( type, fn, false );
- // IE
- } else {
- elem.attachEvent( "on" + type, fn );
- }
-}
-
-/**
- * @param {Array|NodeList} elems
- * @param {string} type
- * @param {Function} fn
- */
-function addEvents( elems, type, fn ) {
- var i = elems.length;
- while ( i-- ) {
- addEvent( elems[i], type, fn );
- }
-}
-
-function hasClass( elem, name ) {
- return (" " + elem.className + " ").indexOf(" " + name + " ") > -1;
-}
-
-function addClass( elem, name ) {
- if ( !hasClass( elem, name ) ) {
- elem.className += (elem.className ? " " : "") + name;
- }
-}
-
-function removeClass( elem, name ) {
- var set = " " + elem.className + " ";
- // Class name may appear multiple times
- while ( set.indexOf(" " + name + " ") > -1 ) {
- set = set.replace(" " + name + " " , " ");
- }
- // If possible, trim it for prettiness, but not neccecarily
- elem.className = window.jQuery ? jQuery.trim( set ) : ( set.trim ? set.trim() : set );
-}
-
-function id( name ) {
- return !!( typeof document !== "undefined" && document && document.getElementById ) &&
- document.getElementById( name );
-}
-
-function registerLoggingCallback( key ) {
- return function( callback ) {
- config[key].push( callback );
- };
-}
-
-// Supports deprecated method of completely overwriting logging callbacks
-function runLoggingCallbacks( key, scope, args ) {
- var i, callbacks;
- if ( QUnit.hasOwnProperty( key ) ) {
- QUnit[ key ].call(scope, args );
- } else {
- callbacks = config[ key ];
- for ( i = 0; i < callbacks.length; i++ ) {
- callbacks[ i ].call( scope, args );
- }
- }
-}
-
-// Test for equality any JavaScript type.
-// Author: Philippe Rathé
-QUnit.equiv = (function() {
-
- // Call the o related callback with the given arguments.
- function bindCallbacks( o, callbacks, args ) {
- var prop = QUnit.objectType( o );
- if ( prop ) {
- if ( QUnit.objectType( callbacks[ prop ] ) === "function" ) {
- return callbacks[ prop ].apply( callbacks, args );
- } else {
- return callbacks[ prop ]; // or undefined
- }
- }
- }
-
- // the real equiv function
- var innerEquiv,
- // stack to decide between skip/abort functions
- callers = [],
- // stack to avoiding loops from circular referencing
- parents = [],
-
- getProto = Object.getPrototypeOf || function ( obj ) {
- return obj.__proto__;
- },
- callbacks = (function () {
-
- // for string, boolean, number and null
- function useStrictEquality( b, a ) {
- /*jshint eqeqeq:false */
- if ( b instanceof a.constructor || a instanceof b.constructor ) {
- // to catch short annotaion VS 'new' annotation of a
- // declaration
- // e.g. var i = 1;
- // var j = new Number(1);
- return a == b;
- } else {
- return a === b;
- }
- }
-
- return {
- "string": useStrictEquality,
- "boolean": useStrictEquality,
- "number": useStrictEquality,
- "null": useStrictEquality,
- "undefined": useStrictEquality,
-
- "nan": function( b ) {
- return isNaN( b );
- },
-
- "date": function( b, a ) {
- return QUnit.objectType( b ) === "date" && a.valueOf() === b.valueOf();
- },
-
- "regexp": function( b, a ) {
- return QUnit.objectType( b ) === "regexp" &&
- // the regex itself
- a.source === b.source &&
- // and its modifers
- a.global === b.global &&
- // (gmi) ...
- a.ignoreCase === b.ignoreCase &&
- a.multiline === b.multiline &&
- a.sticky === b.sticky;
- },
-
- // - skip when the property is a method of an instance (OOP)
- // - abort otherwise,
- // initial === would have catch identical references anyway
- "function": function() {
- var caller = callers[callers.length - 1];
- return caller !== Object && typeof caller !== "undefined";
- },
-
- "array": function( b, a ) {
- var i, j, len, loop;
-
- // b could be an object literal here
- if ( QUnit.objectType( b ) !== "array" ) {
- return false;
- }
-
- len = a.length;
- if ( len !== b.length ) {
- // safe and faster
- return false;
- }
-
- // track reference to avoid circular references
- parents.push( a );
- for ( i = 0; i < len; i++ ) {
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- loop = true;// dont rewalk array
- }
- }
- if ( !loop && !innerEquiv(a[i], b[i]) ) {
- parents.pop();
- return false;
- }
- }
- parents.pop();
- return true;
- },
-
- "object": function( b, a ) {
- var i, j, loop,
- // Default to true
- eq = true,
- aProperties = [],
- bProperties = [];
-
- // comparing constructors is more strict than using
- // instanceof
- if ( a.constructor !== b.constructor ) {
- // Allow objects with no prototype to be equivalent to
- // objects with Object as their constructor.
- if ( !(( getProto(a) === null && getProto(b) === Object.prototype ) ||
- ( getProto(b) === null && getProto(a) === Object.prototype ) ) ) {
- return false;
- }
- }
-
- // stack constructor before traversing properties
- callers.push( a.constructor );
- // track reference to avoid circular references
- parents.push( a );
-
- for ( i in a ) { // be strict: don't ensures hasOwnProperty
- // and go deep
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- // don't go down the same path twice
- loop = true;
- }
- }
- aProperties.push(i); // collect a's properties
-
- if (!loop && !innerEquiv( a[i], b[i] ) ) {
- eq = false;
- break;
- }
- }
-
- callers.pop(); // unstack, we are done
- parents.pop();
-
- for ( i in b ) {
- bProperties.push( i ); // collect b's properties
- }
-
- // Ensures identical properties name
- return eq && innerEquiv( aProperties.sort(), bProperties.sort() );
- }
- };
- }());
-
- innerEquiv = function() { // can take multiple arguments
- var args = [].slice.apply( arguments );
- if ( args.length < 2 ) {
- return true; // end transition
- }
-
- return (function( a, b ) {
- if ( a === b ) {
- return true; // catch the most you can
- } else if ( a === null || b === null || typeof a === "undefined" ||
- typeof b === "undefined" ||
- QUnit.objectType(a) !== QUnit.objectType(b) ) {
- return false; // don't lose time with error prone cases
- } else {
- return bindCallbacks(a, callbacks, [ b, a ]);
- }
-
- // apply transition with (1..n) arguments
- }( args[0], args[1] ) && arguments.callee.apply( this, args.splice(1, args.length - 1 )) );
- };
-
- return innerEquiv;
-}());
-
-/**
- * jsDump Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com |
- * http://flesler.blogspot.com Licensed under BSD
- * (http://www.opensource.org/licenses/bsd-license.php) Date: 5/15/2008
- *
- * @projectDescription Advanced and extensible data dumping for Javascript.
- * @version 1.0.0
- * @author Ariel Flesler
- * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html}
- */
-QUnit.jsDump = (function() {
- function quote( str ) {
- return '"' + str.toString().replace( /"/g, '\\"' ) + '"';
- }
- function literal( o ) {
- return o + "";
- }
- function join( pre, arr, post ) {
- var s = jsDump.separator(),
- base = jsDump.indent(),
- inner = jsDump.indent(1);
- if ( arr.join ) {
- arr = arr.join( "," + s + inner );
- }
- if ( !arr ) {
- return pre + post;
- }
- return [ pre, inner + arr, base + post ].join(s);
- }
- function array( arr, stack ) {
- var i = arr.length, ret = new Array(i);
- this.up();
- while ( i-- ) {
- ret[i] = this.parse( arr[i] , undefined , stack);
- }
- this.down();
- return join( "[", ret, "]" );
- }
-
- var reName = /^function (\w+)/,
- jsDump = {
- // type is used mostly internally, you can fix a (custom)type in advance
- parse: function( obj, type, stack ) {
- stack = stack || [ ];
- var inStack, res,
- parser = this.parsers[ type || this.typeOf(obj) ];
-
- type = typeof parser;
- inStack = inArray( obj, stack );
-
- if ( inStack !== -1 ) {
- return "recursion(" + (inStack - stack.length) + ")";
- }
- if ( type === "function" ) {
- stack.push( obj );
- res = parser.call( this, obj, stack );
- stack.pop();
- return res;
- }
- return ( type === "string" ) ? parser : this.parsers.error;
- },
- typeOf: function( obj ) {
- var type;
- if ( obj === null ) {
- type = "null";
- } else if ( typeof obj === "undefined" ) {
- type = "undefined";
- } else if ( QUnit.is( "regexp", obj) ) {
- type = "regexp";
- } else if ( QUnit.is( "date", obj) ) {
- type = "date";
- } else if ( QUnit.is( "function", obj) ) {
- type = "function";
- } else if ( typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined" ) {
- type = "window";
- } else if ( obj.nodeType === 9 ) {
- type = "document";
- } else if ( obj.nodeType ) {
- type = "node";
- } else if (
- // native arrays
- toString.call( obj ) === "[object Array]" ||
- // NodeList objects
- ( typeof obj.length === "number" && typeof obj.item !== "undefined" && ( obj.length ? obj.item(0) === obj[0] : ( obj.item( 0 ) === null && typeof obj[0] === "undefined" ) ) )
- ) {
- type = "array";
- } else if ( obj.constructor === Error.prototype.constructor ) {
- type = "error";
- } else {
- type = typeof obj;
- }
- return type;
- },
- separator: function() {
- return this.multiline ? this.HTML ? "
" : "\n" : this.HTML ? " " : " ";
- },
- // extra can be a number, shortcut for increasing-calling-decreasing
- indent: function( extra ) {
- if ( !this.multiline ) {
- return "";
- }
- var chr = this.indentChar;
- if ( this.HTML ) {
- chr = chr.replace( /\t/g, " " ).replace( / /g, " " );
- }
- return new Array( this._depth_ + (extra||0) ).join(chr);
- },
- up: function( a ) {
- this._depth_ += a || 1;
- },
- down: function( a ) {
- this._depth_ -= a || 1;
- },
- setParser: function( name, parser ) {
- this.parsers[name] = parser;
- },
- // The next 3 are exposed so you can use them
- quote: quote,
- literal: literal,
- join: join,
- //
- _depth_: 1,
- // This is the list of parsers, to modify them, use jsDump.setParser
- parsers: {
- window: "[Window]",
- document: "[Document]",
- error: function(error) {
- return "Error(\"" + error.message + "\")";
- },
- unknown: "[Unknown]",
- "null": "null",
- "undefined": "undefined",
- "function": function( fn ) {
- var ret = "function",
- // functions never have name in IE
- name = "name" in fn ? fn.name : (reName.exec(fn) || [])[1];
-
- if ( name ) {
- ret += " " + name;
- }
- ret += "( ";
-
- ret = [ ret, QUnit.jsDump.parse( fn, "functionArgs" ), "){" ].join( "" );
- return join( ret, QUnit.jsDump.parse(fn,"functionCode" ), "}" );
- },
- array: array,
- nodelist: array,
- "arguments": array,
- object: function( map, stack ) {
- var ret = [ ], keys, key, val, i;
- QUnit.jsDump.up();
- keys = [];
- for ( key in map ) {
- keys.push( key );
- }
- keys.sort();
- for ( i = 0; i < keys.length; i++ ) {
- key = keys[ i ];
- val = map[ key ];
- ret.push( QUnit.jsDump.parse( key, "key" ) + ": " + QUnit.jsDump.parse( val, undefined, stack ) );
- }
- QUnit.jsDump.down();
- return join( "{", ret, "}" );
- },
- node: function( node ) {
- var len, i, val,
- open = QUnit.jsDump.HTML ? "<" : "<",
- close = QUnit.jsDump.HTML ? ">" : ">",
- tag = node.nodeName.toLowerCase(),
- ret = open + tag,
- attrs = node.attributes;
-
- if ( attrs ) {
- for ( i = 0, len = attrs.length; i < len; i++ ) {
- val = attrs[i].nodeValue;
- // IE6 includes all attributes in .attributes, even ones not explicitly set.
- // Those have values like undefined, null, 0, false, "" or "inherit".
- if ( val && val !== "inherit" ) {
- ret += " " + attrs[i].nodeName + "=" + QUnit.jsDump.parse( val, "attribute" );
- }
- }
- }
- ret += close;
-
- // Show content of TextNode or CDATASection
- if ( node.nodeType === 3 || node.nodeType === 4 ) {
- ret += node.nodeValue;
- }
-
- return ret + open + "/" + tag + close;
- },
- // function calls it internally, it's the arguments part of the function
- functionArgs: function( fn ) {
- var args,
- l = fn.length;
-
- if ( !l ) {
- return "";
- }
-
- args = new Array(l);
- while ( l-- ) {
- // 97 is 'a'
- args[l] = String.fromCharCode(97+l);
- }
- return " " + args.join( ", " ) + " ";
- },
- // object calls it internally, the key part of an item in a map
- key: quote,
- // function calls it internally, it's the content of the function
- functionCode: "[code]",
- // node calls it internally, it's an html attribute value
- attribute: quote,
- string: quote,
- date: quote,
- regexp: literal,
- number: literal,
- "boolean": literal
- },
- // if true, entities are escaped ( <, >, \t, space and \n )
- HTML: false,
- // indentation unit
- indentChar: " ",
- // if true, items in a collection, are separated by a \n, else just a space.
- multiline: true
- };
-
- return jsDump;
-}());
-
-// from jquery.js
-function inArray( elem, array ) {
- if ( array.indexOf ) {
- return array.indexOf( elem );
- }
-
- for ( var i = 0, length = array.length; i < length; i++ ) {
- if ( array[ i ] === elem ) {
- return i;
- }
- }
-
- return -1;
-}
-
-/*
- * Javascript Diff Algorithm
- * By John Resig (http://ejohn.org/)
- * Modified by Chu Alan "sprite"
- *
- * Released under the MIT license.
- *
- * More Info:
- * http://ejohn.org/projects/javascript-diff-algorithm/
- *
- * Usage: QUnit.diff(expected, actual)
- *
- * QUnit.diff( "the quick brown fox jumped over", "the quick fox jumps over" ) == "the quick brown fox jumped jumps over"
- */
-QUnit.diff = (function() {
- /*jshint eqeqeq:false, eqnull:true */
- function diff( o, n ) {
- var i,
- ns = {},
- os = {};
-
- for ( i = 0; i < n.length; i++ ) {
- if ( !hasOwn.call( ns, n[i] ) ) {
- ns[ n[i] ] = {
- rows: [],
- o: null
- };
- }
- ns[ n[i] ].rows.push( i );
- }
-
- for ( i = 0; i < o.length; i++ ) {
- if ( !hasOwn.call( os, o[i] ) ) {
- os[ o[i] ] = {
- rows: [],
- n: null
- };
- }
- os[ o[i] ].rows.push( i );
- }
-
- for ( i in ns ) {
- if ( !hasOwn.call( ns, i ) ) {
- continue;
- }
- if ( ns[i].rows.length === 1 && hasOwn.call( os, i ) && os[i].rows.length === 1 ) {
- n[ ns[i].rows[0] ] = {
- text: n[ ns[i].rows[0] ],
- row: os[i].rows[0]
- };
- o[ os[i].rows[0] ] = {
- text: o[ os[i].rows[0] ],
- row: ns[i].rows[0]
- };
- }
- }
-
- for ( i = 0; i < n.length - 1; i++ ) {
- if ( n[i].text != null && n[ i + 1 ].text == null && n[i].row + 1 < o.length && o[ n[i].row + 1 ].text == null &&
- n[ i + 1 ] == o[ n[i].row + 1 ] ) {
-
- n[ i + 1 ] = {
- text: n[ i + 1 ],
- row: n[i].row + 1
- };
- o[ n[i].row + 1 ] = {
- text: o[ n[i].row + 1 ],
- row: i + 1
- };
- }
- }
-
- for ( i = n.length - 1; i > 0; i-- ) {
- if ( n[i].text != null && n[ i - 1 ].text == null && n[i].row > 0 && o[ n[i].row - 1 ].text == null &&
- n[ i - 1 ] == o[ n[i].row - 1 ]) {
-
- n[ i - 1 ] = {
- text: n[ i - 1 ],
- row: n[i].row - 1
- };
- o[ n[i].row - 1 ] = {
- text: o[ n[i].row - 1 ],
- row: i - 1
- };
- }
- }
-
- return {
- o: o,
- n: n
- };
- }
-
- return function( o, n ) {
- o = o.replace( /\s+$/, "" );
- n = n.replace( /\s+$/, "" );
-
- var i, pre,
- str = "",
- out = diff( o === "" ? [] : o.split(/\s+/), n === "" ? [] : n.split(/\s+/) ),
- oSpace = o.match(/\s+/g),
- nSpace = n.match(/\s+/g);
-
- if ( oSpace == null ) {
- oSpace = [ " " ];
- }
- else {
- oSpace.push( " " );
- }
-
- if ( nSpace == null ) {
- nSpace = [ " " ];
- }
- else {
- nSpace.push( " " );
- }
-
- if ( out.n.length === 0 ) {
- for ( i = 0; i < out.o.length; i++ ) {
- str += "" + out.o[i] + oSpace[i] + "";
- }
- }
- else {
- if ( out.n[0].text == null ) {
- for ( n = 0; n < out.o.length && out.o[n].text == null; n++ ) {
- str += "" + out.o[n] + oSpace[n] + "";
- }
- }
-
- for ( i = 0; i < out.n.length; i++ ) {
- if (out.n[i].text == null) {
- str += "" + out.n[i] + nSpace[i] + "";
- }
- else {
- // `pre` initialized at top of scope
- pre = "";
-
- for ( n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++ ) {
- pre += "" + out.o[n] + oSpace[n] + "";
- }
- str += " " + out.n[i].text + nSpace[i] + pre;
- }
- }
- }
-
- return str;
- };
-}());
-
-// for CommonJS enviroments, export everything
-if ( typeof exports !== "undefined" ) {
- extend( exports, QUnit );
-}
-
-// get at whatever the global object is, like window in browsers
-}( (function() {return this;}.call()) ));
diff --git a/test/lib/require.js b/test/lib/require.js
deleted file mode 100644
index 987f865..0000000
--- a/test/lib/require.js
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- RequireJS 2.1.5 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.
- Available via the MIT or new BSD license.
- see: http://github.com/jrburke/requirejs for details
-*/
-var requirejs,require,define;
-(function(aa){function I(b){return"[object Function]"===L.call(b)}function J(b){return"[object Array]"===L.call(b)}function y(b,c){if(b){var d;for(d=0;dthis.depCount&&!this.defined){if(I(n)){if(this.events.error)try{e=i.execCb(c,n,b,e)}catch(d){a=d}else e=i.execCb(c,n,b,e);this.map.isDefine&&((b=this.module)&&void 0!==b.exports&&b.exports!==this.exports?e=b.exports:void 0===e&&this.usingExports&&(e=this.exports));if(a)return a.requireMap=this.map,a.requireModules=[this.map.id],a.requireType="define",v(this.error=
-a)}else e=n;this.exports=e;if(this.map.isDefine&&!this.ignore&&(q[c]=e,l.onResourceLoad))l.onResourceLoad(i,this.map,this.depMaps);x(c);this.defined=!0}this.defining=!1;this.defined&&!this.defineEmitted&&(this.defineEmitted=!0,this.emit("defined",this.exports),this.defineEmitComplete=!0)}}else this.fetch()}},callPlugin:function(){var a=this.map,b=a.id,d=j(a.prefix);this.depMaps.push(d);t(d,"defined",u(this,function(e){var n,d;d=this.map.name;var g=this.map.parentMap?this.map.parentMap.name:null,h=
-i.makeRequire(a.parentMap,{enableBuildCallback:!0});if(this.map.unnormalized){if(e.normalize&&(d=e.normalize(d,function(a){return c(a,g,!0)})||""),e=j(a.prefix+"!"+d,this.map.parentMap),t(e,"defined",u(this,function(a){this.init([],function(){return a},null,{enabled:!0,ignore:!0})})),d=m(p,e.id)){this.depMaps.push(e);if(this.events.error)d.on("error",u(this,function(a){this.emit("error",a)}));d.enable()}}else n=u(this,function(a){this.init([],function(){return a},null,{enabled:!0})}),n.error=u(this,
-function(a){this.inited=!0;this.error=a;a.requireModules=[b];G(p,function(a){0===a.map.id.indexOf(b+"_unnormalized")&&x(a.map.id)});v(a)}),n.fromText=u(this,function(e,c){var d=a.name,g=j(d),C=O;c&&(e=c);C&&(O=!1);r(g);s(k.config,b)&&(k.config[d]=k.config[b]);try{l.exec(e)}catch(ca){return v(B("fromtexteval","fromText eval for "+b+" failed: "+ca,ca,[b]))}C&&(O=!0);this.depMaps.push(g);i.completeLoad(d);h([d],n)}),e.load(a.name,h,n,k)}));i.enable(d,this);this.pluginMaps[d.id]=d},enable:function(){V[this.map.id]=
-this;this.enabling=this.enabled=!0;y(this.depMaps,u(this,function(a,b){var c,e;if("string"===typeof a){a=j(a,this.map.isDefine?this.map:this.map.parentMap,!1,!this.skipMap);this.depMaps[b]=a;if(c=m(N,a.id)){this.depExports[b]=c(this);return}this.depCount+=1;t(a,"defined",u(this,function(a){this.defineDep(b,a);this.check()}));this.errback&&t(a,"error",this.errback)}c=a.id;e=p[c];!s(N,c)&&(e&&!e.enabled)&&i.enable(a,this)}));G(this.pluginMaps,u(this,function(a){var b=m(p,a.id);b&&!b.enabled&&i.enable(a,
-this)}));this.enabling=!1;this.check()},on:function(a,b){var c=this.events[a];c||(c=this.events[a]=[]);c.push(b)},emit:function(a,b){y(this.events[a],function(a){a(b)});"error"===a&&delete this.events[a]}};i={config:k,contextName:b,registry:p,defined:q,urlFetched:U,defQueue:H,Module:Z,makeModuleMap:j,nextTick:l.nextTick,onError:v,configure:function(a){a.baseUrl&&"/"!==a.baseUrl.charAt(a.baseUrl.length-1)&&(a.baseUrl+="/");var b=k.pkgs,c=k.shim,e={paths:!0,config:!0,map:!0};G(a,function(a,b){e[b]?
-"map"===b?(k.map||(k.map={}),R(k[b],a,!0,!0)):R(k[b],a,!0):k[b]=a});a.shim&&(G(a.shim,function(a,b){J(a)&&(a={deps:a});if((a.exports||a.init)&&!a.exportsFn)a.exportsFn=i.makeShimExports(a);c[b]=a}),k.shim=c);a.packages&&(y(a.packages,function(a){a="string"===typeof a?{name:a}:a;b[a.name]={name:a.name,location:a.location||a.name,main:(a.main||"main").replace(ja,"").replace(ea,"")}}),k.pkgs=b);G(p,function(a,b){!a.inited&&!a.map.unnormalized&&(a.map=j(b))});if(a.deps||a.callback)i.require(a.deps||[],
-a.callback)},makeShimExports:function(a){return function(){var b;a.init&&(b=a.init.apply(aa,arguments));return b||a.exports&&ba(a.exports)}},makeRequire:function(a,f){function d(e,c,h){var g,k;f.enableBuildCallback&&(c&&I(c))&&(c.__requireJsBuild=!0);if("string"===typeof e){if(I(c))return v(B("requireargs","Invalid require call"),h);if(a&&s(N,e))return N[e](p[a.id]);if(l.get)return l.get(i,e,a,d);g=j(e,a,!1,!0);g=g.id;return!s(q,g)?v(B("notloaded",'Module name "'+g+'" has not been loaded yet for context: '+
-b+(a?"":". Use require([])"))):q[g]}L();i.nextTick(function(){L();k=r(j(null,a));k.skipMap=f.skipMap;k.init(e,c,h,{enabled:!0});D()});return d}f=f||{};R(d,{isBrowser:A,toUrl:function(b){var d,f=b.lastIndexOf("."),g=b.split("/")[0];if(-1!==f&&(!("."===g||".."===g)||1h.attachEvent.toString().indexOf("[native code"))&&!Y?(O=!0,h.attachEvent("onreadystatechange",b.onScriptLoad)):(h.addEventListener("load",b.onScriptLoad,!1),h.addEventListener("error",b.onScriptError,!1)),h.src=d,K=h,D?x.insertBefore(h,D):x.appendChild(h),K=null,h;if(da)try{importScripts(d),b.completeLoad(c)}catch(j){b.onError(B("importscripts","importScripts failed for "+c+" at "+d,j,[c]))}};A&&M(document.getElementsByTagName("script"),function(b){x||(x=
-b.parentNode);if(t=b.getAttribute("data-main"))return r.baseUrl||(E=t.split("/"),Q=E.pop(),fa=E.length?E.join("/")+"/":"./",r.baseUrl=fa,t=Q),t=t.replace(ea,""),r.deps=r.deps?r.deps.concat(t):[t],!0});define=function(b,c,d){var l,h;"string"!==typeof b&&(d=c,c=b,b=null);J(c)||(d=c,c=[]);!c.length&&I(d)&&d.length&&(d.toString().replace(la,"").replace(ma,function(b,d){c.push(d)}),c=(1===d.length?["require"]:["require","exports","module"]).concat(c));if(O){if(!(l=K))P&&"interactive"===P.readyState||M(document.getElementsByTagName("script"),
-function(b){if("interactive"===b.readyState)return P=b}),l=P;l&&(b||(b=l.getAttribute("data-requiremodule")),h=F[l.getAttribute("data-requirecontext")])}(h?h.defQueue:T).push([b,c,d])};define.amd={jQuery:!0};l.exec=function(b){return eval(b)};l(r)}})(this);
diff --git a/test/lib/resemble.js b/test/lib/resemble.js
new file mode 100644
index 0000000..1cb8c29
--- /dev/null
+++ b/test/lib/resemble.js
@@ -0,0 +1,535 @@
+/*
+Author: James Cryer
+Company: Huddle
+Last updated date: 21 Feb 2013
+URL: https://github.com/Huddle/Resemble.js
+*/
+
+(function(_this){
+ 'use strict';
+
+ _this['resemble'] = function( fileData ){
+
+ var data = {};
+ var images = [];
+ var updateCallbackArray = [];
+
+ var tolerance = { // between 0 and 255
+ red: 16,
+ green: 16,
+ blue: 16,
+ minBrightness: 16,
+ maxBrightness: 240
+ };
+
+ var ignoreAntialiasing = false;
+ var ignoreColors = false;
+
+ function triggerDataUpdate(){
+ var len = updateCallbackArray.length;
+ var i;
+ for(i=0;i tolerance.maxBrightness;
+ }
+
+ function getHue(r,g,b){
+
+ r = r / 255;
+ g = g / 255;
+ b = b / 255;
+ var max = Math.max(r, g, b), min = Math.min(r, g, b);
+ var h;
+ var d;
+
+ if (max == min){
+ h = 0; // achromatic
+ } else{
+ d = max - min;
+ switch(max){
+ case r: h = (g - b) / d + (g < b ? 6 : 0); break;
+ case g: h = (b - r) / d + 2; break;
+ case b: h = (r - g) / d + 4; break;
+ }
+ h /= 6;
+ }
+
+ return h;
+ }
+
+ function isAntialiased(sourcePix, data, cacheSet, verticalPos, horizontalPos, width){
+ var offset;
+ var targetPix;
+ var distance = 1;
+ var i;
+ var j;
+ var hasHighContrastSibling = 0;
+ var hasSiblingWithDifferentHue = 0;
+ var hasEquivilantSibling = 0;
+
+ addHueInfo(sourcePix);
+
+ for (i = distance*-1; i <= distance; i++){
+ for (j = distance*-1; j <= distance; j++){
+
+ if(i===0 && j===0){
+ // ignore source pixel
+ } else {
+
+ offset = ((verticalPos+j)*width + (horizontalPos+i)) * 4;
+ targetPix = getPixelInfo(data, offset, cacheSet);
+
+ if(targetPix === null){
+ continue;
+ }
+
+ addBrightnessInfo(targetPix);
+ addHueInfo(targetPix);
+
+ if( isContrasting(sourcePix, targetPix) ){
+ hasHighContrastSibling++;
+ }
+
+ if( isRGBSame(sourcePix,targetPix) ){
+ hasEquivilantSibling++;
+ }
+
+ if( Math.abs(targetPix.h - sourcePix.h) > 0.3 ){
+ hasSiblingWithDifferentHue++;
+ }
+
+ if( hasSiblingWithDifferentHue > 1 || hasHighContrastSibling > 1){
+ return true;
+ }
+ }
+ }
+ }
+
+ if(hasEquivilantSibling < 2){
+ return true;
+ }
+
+ return false;
+ }
+
+ function errorPixel(px, offset){
+ px[offset] = 255; //r
+ px[offset + 1] = 0; //g
+ px[offset + 2] = 255; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyPixel(px, offset, data){
+ px[offset] = data.r; //r
+ px[offset + 1] = data.g; //g
+ px[offset + 2] = data.b; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyGrayScalePixel(px, offset, data){
+ px[offset] = data.brightness; //r
+ px[offset + 1] = data.brightness; //g
+ px[offset + 2] = data.brightness; //b
+ px[offset + 3] = 255; //a
+ }
+
+
+ function getPixelInfo(data, offset, cacheSet){
+ var r;
+ var g;
+ var b;
+ var d;
+
+ if(typeof data[offset] !== 'undefined'){
+ r = data[offset];
+ g = data[offset+1];
+ b = data[offset+2];
+ d = {
+ r: r,
+ g: g,
+ b: b
+ };
+
+ return d;
+ } else {
+ return null;
+ }
+ }
+
+ function addBrightnessInfo(data){
+ data.brightness = getBrightness(data.r,data.g,data.b); // 'corrected' lightness
+ }
+
+ function addHueInfo(data){
+ data.h = getHue(data.r,data.g,data.b);
+ }
+
+ function analyseImages(img1, img2, width, height){
+
+ var hiddenCanvas = document.createElement('canvas');
+
+ var data1 = img1.data;
+ var data2 = img2.data;
+
+ hiddenCanvas.width = width;
+ hiddenCanvas.height = height;
+
+ var context = hiddenCanvas.getContext('2d');
+ var imgd = context.createImageData(width,height);
+ var targetPix = imgd.data;
+
+ var mismatchCount = 0;
+
+ var time = Date.now();
+
+ var skip;
+
+ if( (width > 1200 || height > 1200) && ignoreAntialiasing){
+ skip = 6;
+ }
+
+ loop(height, width, function(verticalPos, horizontalPos){
+
+ if(skip){ // only skip if the image isn't small
+ if(verticalPos % skip === 0 || horizontalPos % skip === 0){
+ return;
+ }
+ }
+
+ var offset = (verticalPos*width + horizontalPos) * 4;
+ var pixel1 = getPixelInfo(data1, offset, 1);
+ var pixel2 = getPixelInfo(data2, offset, 2);
+
+ if(pixel1 === null || pixel2 === null){
+ return;
+ }
+
+ if (ignoreColors){
+
+ addBrightnessInfo(pixel1);
+ addBrightnessInfo(pixel2);
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ return;
+ }
+
+ if( isRGBSimilar(pixel1, pixel2) ){
+ copyPixel(targetPix, offset, pixel2);
+
+ } else if( ignoreAntialiasing && (
+ addBrightnessInfo(pixel1), // jit pixel info augmentation looks a little weird, sorry.
+ addBrightnessInfo(pixel2),
+ isAntialiased(pixel1, data1, 1, verticalPos, horizontalPos, width) ||
+ isAntialiased(pixel2, data2, 2, verticalPos, horizontalPos, width)
+ )){
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+
+ });
+
+ data.misMatchPercentage = (mismatchCount / (height*width) * 100).toFixed(2);
+ data.analysisTime = Date.now() - time;
+
+ data.getImageDataUrl = function(text){
+ var barHeight = 0;
+
+ if(text){
+ barHeight = addLabel(text,context,hiddenCanvas);
+ }
+
+ context.putImageData(imgd, 0, barHeight);
+
+ return hiddenCanvas.toDataURL("image/png");
+ };
+ }
+
+ function addLabel(text, context, hiddenCanvas){
+ var textPadding = 2;
+
+ context.font = '12px sans-serif';
+
+ var textWidth = context.measureText(text).width + textPadding*2;
+ var barHeight = 22;
+
+ if(textWidth > hiddenCanvas.width){
+ hiddenCanvas.width = textWidth;
+ }
+
+ hiddenCanvas.height += barHeight;
+
+ context.fillStyle = "#666";
+ context.fillRect(0,0,hiddenCanvas.width,barHeight -4);
+ context.fillStyle = "#fff";
+ context.fillRect(0,barHeight -4,hiddenCanvas.width, 4);
+
+ context.fillStyle = "#fff";
+ context.textBaseline = "top";
+ context.font = '12px sans-serif';
+ context.fillText(text, textPadding, 1);
+
+ return barHeight;
+ }
+
+ function normalise(img, w, h){
+ var c;
+ var context;
+
+ if(img.height < h || img.width < w){
+ c = document.createElement('canvas');
+ c.width = w;
+ c.height = h;
+ context = c.getContext('2d');
+ context.putImageData(img, 0, 0);
+ return context.getImageData(0, 0, w, h);
+ }
+
+ return img;
+ }
+
+ function compare(one, two){
+
+ function onceWeHaveBoth(){
+ var width;
+ var height;
+ if(images.length === 2){
+ width = images[0].width > images[1].width ? images[0].width : images[1].width;
+ height = images[0].height > images[1].height ? images[0].height : images[1].height;
+
+ if( (images[0].width === images[1].width) && (images[0].height === images[1].height) ){
+ data.isSameDimensions = true;
+ } else {
+ data.isSameDimensions = false;
+ }
+
+ analyseImages( normalise(images[0],width, height), normalise(images[1],width, height), width, height);
+
+ triggerDataUpdate();
+ }
+ }
+
+ images = [];
+ loadImageData(one, onceWeHaveBoth);
+ loadImageData(two, onceWeHaveBoth);
+ }
+
+ function getCompareApi(param){
+
+ var secondFileData,
+ hasMethod = typeof param === 'function';
+
+ if( !hasMethod ){
+ // assume it's file data
+ secondFileData = param;
+ }
+
+ var self = {
+ ignoreNothing: function(){
+
+ tolerance.red = 16;
+ tolerance.green = 16;
+ tolerance.blue = 16;
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreAntialiasing: function(){
+
+ tolerance.red = 32;
+ tolerance.green = 32;
+ tolerance.blue = 32;
+ tolerance.minBrightness = 64;
+ tolerance.maxBrightness = 96;
+
+ ignoreAntialiasing = true;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreColors: function(){
+
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = true;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ onComplete: function( callback ){
+
+ updateCallbackArray.push(callback);
+
+ var wrapper = function(){
+ compare(fileData, secondFileData);
+ };
+
+ wrapper();
+
+ return getCompareApi(wrapper);
+ }
+ };
+
+ return self;
+ }
+
+ return {
+ onComplete: function( callback ){
+ updateCallbackArray.push(callback);
+ loadImageData(fileData, function(imageData, width, height){
+ parseImage(imageData.data, width, height);
+ });
+ },
+ compareTo: function(secondFileData){
+ return getCompareApi(secondFileData);
+ }
+ };
+
+ };
+}(this));
\ No newline at end of file
diff --git a/test/testsuite.js b/test/testsuite.js
deleted file mode 100644
index b486acb..0000000
--- a/test/testsuite.js
+++ /dev/null
@@ -1,36 +0,0 @@
-requirejs.config({
- baseUrl: '/test/unit/'
-});
-
-define(function(require) {
- var testModules = [
- 'Pixi',
- 'Point',
- 'Rectangle',
- 'DisplayObject',
- 'DisplayObjectContainer',
- 'Sprite',
- 'MovieClip',
- 'InteractionManager',
- 'Stage',
- 'utils/Utils',
- 'utils/EventTarget',
- 'utils/Matrix',
- 'utils/Detector',
- 'renderers/WebGLShaders',
- 'renderers/WebGLRenderer',
- 'renderers/WebGLBatch',
- 'renderers/CanvasRenderer',
- 'extras/Strip',
- 'extras/Rope',
- 'textures/BaseTexture',
- 'textures/Texture',
- 'loaders/SpriteSheetLoader',
- 'loaders/AssetLoader'
- ];
-
- // Resolve all testModules and then start the Test Runner.
- require(testModules, function() {
- QUnit.start();
- });
-});
\ No newline at end of file
diff --git a/test/textures/SpriteSheet-Aliens.png b/test/textures/SpriteSheet-Aliens.png
new file mode 100644
index 0000000..210acb1
--- /dev/null
+++ b/test/textures/SpriteSheet-Aliens.png
Binary files differ
diff --git a/test/textures/SpriteSheet-Explosion.png b/test/textures/SpriteSheet-Explosion.png
new file mode 100755
index 0000000..79e1a69
--- /dev/null
+++ b/test/textures/SpriteSheet-Explosion.png
Binary files differ
diff --git a/test/textures/bunny.png b/test/textures/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/textures/bunny.png
Binary files differ
diff --git a/test/unit/DisplayObject.js b/test/unit/DisplayObject.js
deleted file mode 100644
index 5e7e72f..0000000
--- a/test/unit/DisplayObject.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObject');
-});
diff --git a/test/unit/DisplayObjectContainer.js b/test/unit/DisplayObjectContainer.js
deleted file mode 100644
index b323959..0000000
--- a/test/unit/DisplayObjectContainer.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObjectContainer');
-});
diff --git a/test/unit/InteractionManager.js b/test/unit/InteractionManager.js
deleted file mode 100644
index e751f52..0000000
--- a/test/unit/InteractionManager.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('InteractionManager');
-});
diff --git a/test/unit/MovieClip.js b/test/unit/MovieClip.js
deleted file mode 100644
index 37d9446..0000000
--- a/test/unit/MovieClip.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('MovieClip');
-});
diff --git a/test/unit/Pixi.js b/test/unit/Pixi.js
deleted file mode 100644
index 36eee73..0000000
--- a/test/unit/Pixi.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Pixi');
-});
diff --git a/test/unit/Point.js b/test/unit/Point.js
deleted file mode 100644
index 983ff6e..0000000
--- a/test/unit/Point.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Point');
-});
diff --git a/test/unit/Rectangle.js b/test/unit/Rectangle.js
deleted file mode 100644
index 3b439ba..0000000
--- a/test/unit/Rectangle.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Rectangle');
-});
diff --git a/test/unit/Sprite.js b/test/unit/Sprite.js
deleted file mode 100644
index ed4f596..0000000
--- a/test/unit/Sprite.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Sprite');
-});
diff --git a/test/unit/Stage.js b/test/unit/Stage.js
deleted file mode 100644
index 2d70291..0000000
--- a/test/unit/Stage.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Stage');
-});
diff --git a/test/unit/extras/Rope.js b/test/unit/extras/Rope.js
deleted file mode 100644
index 5606f14..0000000
--- a/test/unit/extras/Rope.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Rope');
-});
diff --git a/test/unit/extras/Strip.js b/test/unit/extras/Strip.js
deleted file mode 100644
index 0134d3a..0000000
--- a/test/unit/extras/Strip.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Strip');
-});
diff --git a/.gitignore b/.gitignore
index 12e1b62..0b88317 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
node_modules
.DS_Store
-.project
\ No newline at end of file
+.project
+*.log
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..63e4d7c
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,8 @@
+language: node_js
+node_js:
+ - 0.10
+
+before_script:
+ - npm install -g grunt-cli
+ - export DISPLAY=:99.0
+ - sh -e /etc/init.d/xvfb start
diff --git a/Gruntfile.js b/Gruntfile.js
index b083b49..103938c 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -1,10 +1,12 @@
+'use strict';
+
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-connect');
- grunt.loadNpmTasks('grunt-contrib-qunit');
grunt.loadNpmTasks('grunt-contrib-yuidoc');
+ grunt.loadTasks('tasks');
var root = 'src/pixi/',
debug = 'bin/pixi.dev.js',
@@ -79,7 +81,7 @@
},
files: {
srcBlob: '<%= dirs.src %>/**/*.js',
- testBlob: '<%= dirs.test %>/unit/**/*.js',
+ testBlob: '<%= dirs.test %>/{functional,lib/pixi,unit}/**/*.js',
build: '<%= dirs.build %>/pixi.dev.js',
buildMin: '<%= dirs.build %>/pixi.js'
},
@@ -94,7 +96,12 @@
},
jshint: {
beforeconcat: srcFiles,
- test: ['<%= files.testBlob %>'],
+ test: {
+ src: ['<%= files.testBlob %>'],
+ options: {
+ expr: true
+ }
+ },
options: {
asi: true,
smarttabs: true
@@ -128,12 +135,6 @@
]
},
connect: {
- qunit: {
- options: {
- port: grunt.option('port-test') || 9002,
- base: './'
- }
- },
test: {
options: {
port: grunt.option('port-test') || 9002,
@@ -142,13 +143,6 @@
}
}
},
- qunit: {
- all: {
- options: {
- urls: ['http://localhost:' + (grunt.option('port-test') || 9002) + '/test/index.html']
- }
- }
- },
yuidoc: {
compile: {
name: '<%= pkg.name %>',
@@ -161,6 +155,13 @@
outdir: '<%= dirs.docs %>'
}
}
+ },
+ karma: {
+ unit: {
+ configFile: 'test/karma.conf.js',
+ // browsers: ['Chrome'],
+ singleRun: true
+ }
}
});
@@ -182,9 +183,10 @@
}
)
- grunt.registerTask('default', ['concat', 'uglify', 'distribute']);
grunt.registerTask('build', ['concat', 'uglify', 'distribute']);
- grunt.registerTask('test', ['build', 'connect:qunit', 'qunit']);
+ grunt.registerTask('test', ['concat', 'jshint:test', 'karma']);
grunt.registerTask('docs', ['yuidoc']);
-
-}
\ No newline at end of file
+ grunt.registerTask('default', ['test', 'uglify', 'distribute']);
+ // Travis CI task.
+ grunt.registerTask('travis', ['test']);
+}
diff --git a/README.md b/README.md
index c62ef86..690cfe4 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,8 @@

+[](http://travis-ci.org/drkibitz/pixi.js)
+
#### JavaScript 2D Renderer ####
The aim of this project is to provide a fast lightweight 2D library that works
diff --git a/package.json b/package.json
index b373240..1246a68 100644
--- a/package.json
+++ b/package.json
@@ -18,14 +18,21 @@
"main": "bin/pixi.js",
+ "scripts": {
+ "test": "grunt travis --verbose"
+ },
+
"dependencies": {},
"devDependencies": {
"grunt": "~0.4.x",
- "grunt-contrib-jshint": "0.3.x",
+ "grunt-contrib-jshint": "0.6.x",
"grunt-contrib-uglify": "0.2.x",
- "grunt-contrib-connect": "0.2.x",
- "grunt-contrib-qunit": "0.2.x",
+ "grunt-contrib-connect": "0.3.x",
"grunt-contrib-yuidoc": "0.4.x",
- "grunt-contrib-concat": "0.1.x"
+ "grunt-contrib-concat": "0.3.x",
+ "chai": "~1.7.0",
+ "karma": "0.11.0",
+ "karma-firefox-launcher": "0.1.0",
+ "karma-mocha": "0.1.0"
}
}
diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js
index a7c520e..ee82bbd 100644
--- a/src/pixi/InteractionManager.js
+++ b/src/pixi/InteractionManager.js
@@ -62,7 +62,6 @@
this.onTouchEnd = this.onTouchEnd.bind(this);
this.onTouchMove = this.onTouchMove.bind(this);
-
this.last = 0;
}
diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js
index 1a95d20..eef1059 100644
--- a/src/pixi/core/Ellipse.js
+++ b/src/pixi/core/Ellipse.js
@@ -78,7 +78,7 @@
return (normx + normy < 0.25);
}
-PIXI.Ellipse.getBounds = function()
+PIXI.Ellipse.prototype.getBounds = function()
{
return new PIXI.Rectangle(this.x, this.y, this.width, this.height);
}
diff --git a/tasks/karma.js b/tasks/karma.js
new file mode 100644
index 0000000..c340485
--- /dev/null
+++ b/tasks/karma.js
@@ -0,0 +1,27 @@
+'use strict';
+
+var path = require('path');
+var server = require('karma').server;
+
+module.exports = function (grunt) {
+ grunt.registerMultiTask('karma', 'run karma.', function() {
+ var done = this.async();
+ var options = this.options({
+ background: false
+ });
+ var data = this.data;
+
+ //merge options onto data, with data taking precedence
+ data = grunt.util._.merge(options, data);
+ data.configFile = path.resolve(data.configFile);
+ if (data.configFile) {
+ data.configFile = grunt.template.process(data.configFile);
+ }
+
+ server.start(
+ data,
+ function(code) {
+ done(!code);
+ });
+ });
+};
diff --git a/test/functional/example-1-basics/bunny.png b/test/functional/example-1-basics/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/functional/example-1-basics/bunny.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-30.png b/test/functional/example-1-basics/frame-30.png
new file mode 100644
index 0000000..96e3409
--- /dev/null
+++ b/test/functional/example-1-basics/frame-30.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-60.png b/test/functional/example-1-basics/frame-60.png
new file mode 100644
index 0000000..af3f4ce
--- /dev/null
+++ b/test/functional/example-1-basics/frame-60.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-90.png b/test/functional/example-1-basics/frame-90.png
new file mode 100644
index 0000000..099b823
--- /dev/null
+++ b/test/functional/example-1-basics/frame-90.png
Binary files differ
diff --git a/test/functional/example-1-basics/index.js b/test/functional/example-1-basics/index.js
new file mode 100644
index 0000000..7ae7a98
--- /dev/null
+++ b/test/functional/example-1-basics/index.js
@@ -0,0 +1,133 @@
+describe('Example 1 - Basics', function () {
+ 'use strict';
+
+ var baseUri = '/base/test/functional/example-1-basics';
+ var expect = chai.expect;
+ var currentFrame = 0;
+ var frameEvents = {};
+ var stage;
+ var renderer;
+ var bunny;
+
+ function onFrame(frame, callback) {
+ frameEvents[frame] = callback;
+ }
+
+ function animate() {
+ currentFrame += 1;
+
+ requestAnimFrame( animate );
+
+ // just for fun, lets rotate mr rabbit a little
+ bunny.rotation += 0.1;
+
+ // render the stage
+ renderer.render(stage);
+
+ if (frameEvents[currentFrame])
+ frameEvents[currentFrame](currentFrame);
+ }
+
+ function initScene() {
+ // create an new instance of a pixi stage
+ stage = new PIXI.Stage(0x66FF99);
+
+ // create a renderer instance
+ renderer = PIXI.autoDetectRenderer(400, 300);
+ console.log('Is PIXI.WebGLRenderer: ' + (renderer instanceof PIXI.WebGLRenderer));
+
+ // add the renderer view element to the DOM
+ document.body.appendChild(renderer.view);
+
+ requestAnimFrame( animate );
+
+ // create a texture from an image path
+ var texture = PIXI.Texture.fromImage(baseUri + "/bunny.png");
+ // create a new Sprite using the texture
+ bunny = new PIXI.Sprite(texture);
+
+ // center the sprites anchor point
+ bunny.anchor.x = 0.5;
+ bunny.anchor.y = 0.5;
+
+ // move the sprite t the center of the screen
+ bunny.position.x = 200;
+ bunny.position.y = 150;
+
+ stage.addChild(bunny);
+ }
+
+ it('assets loaded', function (done) {
+ var loader = new PIXI.AssetLoader([
+ baseUri + '/bunny.png',
+ baseUri + '/frame-30.png',
+ baseUri + '/frame-60.png',
+ baseUri + '/frame-90.png'
+ ]);
+ // loader.on('onProgress', function (event) {
+ // console.log(event.content);
+ // });
+ loader.on('onComplete', function (event) {
+ done();
+ initScene();
+ });
+ loader.load();
+ });
+
+ it('frame 30 should match', function (done) {
+ this.timeout(700);
+ onFrame(30, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-30.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 60 should match', function (done) {
+ this.timeout(1200);
+ onFrame(60, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-60.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 90 should match', function (done) {
+ this.timeout(1700);
+ onFrame(90, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-90.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ // it('capture something', function (done) {
+ // this.timeout(2000000);
+ // onFrame(30, function () {
+ // var img = new Image();
+ // img.src = renderer.view.toDataURL('image/png');
+ // document.body.appendChild(img);
+ // });
+ // });
+});
diff --git a/test/index.html b/test/index.html
deleted file mode 100644
index 9cbcac5..0000000
--- a/test/index.html
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
- Pixi.js Test Suite
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/test/karma.conf.js b/test/karma.conf.js
new file mode 100644
index 0000000..c66a696
--- /dev/null
+++ b/test/karma.conf.js
@@ -0,0 +1,82 @@
+module.exports = function(config) {
+ config.set({
+
+ // base path, that will be used to resolve files and exclude
+ basePath : '../',
+
+ frameworks : ['mocha'],
+
+ // list of files / patterns to load in the browser
+ files : [
+ 'node_modules/chai/chai.js',
+ 'bin/pixi.dev.js',
+ 'test/lib/**/*.js',
+ 'test/unit/**/*.js',
+ // 'test/functional/**/*.js',
+ {pattern: 'test/**/*.png', watched: false, included: false, served: true}
+ ],
+
+ // list of files to exclude
+ exclude : [],
+
+ // use dolts reporter, as travis terminal does not support escaping sequences
+ // possible values: 'dots', 'progress', 'junit', 'teamcity'
+ // CLI --reporters progress
+ reporters : ['progress'],
+
+ // web server port
+ // CLI --port 9876
+ port : 9876,
+
+ // cli runner port
+ // CLI --runner-port 9100
+ runnerPort : 9100,
+
+ // enable / disable colors in the output (reporters and logs)
+ // CLI --colors --no-colors
+ colors : true,
+
+ // level of logging
+ // possible values: karma.LOG_DISABLE || karma.LOG_ERROR || karma.LOG_WARN || karma.LOG_INFO || karma.LOG_DEBUG
+ // CLI --log-level debug
+ logLevel : config.LOG_DEBUG,
+
+ // enable / disable watching file and executing tests whenever any file changes
+ // CLI --auto-watch --no-auto-watch
+ autoWatch : false,
+
+ // Start these browsers, currently available:
+ // - Chrome
+ // - ChromeCanary
+ // - Firefox
+ // - Opera
+ // - Safari (only Mac)
+ // - PhantomJS
+ // - IE (only Windows)
+ // CLI --browsers Chrome,Firefox,Safari
+ browsers : ['Firefox'],
+
+ // If browser does not capture in given timeout [ms], kill it
+ // CLI --capture-timeout 5000
+ captureTimeout : 5000,
+
+ // Auto run tests on start (when browsers are captured) and exit
+ // CLI --single-run --no-single-run
+ singleRun : true,
+
+ // report which specs are slower than 500ms
+ // CLI --report-slower-than 500
+ reportSlowerThan : 1000,
+
+ preprocessors : {
+ // '**/client/js/*.js': 'coverage'
+ },
+
+ plugins : [
+ 'karma-mocha',
+ // 'karma-chrome-launcher',
+ 'karma-firefox-launcher',
+ // 'karma-phantomjs-launcher'
+ ]
+ });
+};
diff --git a/test/lib/pixi/core/Matrix.js b/test/lib/pixi/core/Matrix.js
new file mode 100644
index 0000000..d26386b
--- /dev/null
+++ b/test/lib/pixi/core/Matrix.js
@@ -0,0 +1,40 @@
+
+function pixi_core_Matrix_confirmNewMat3(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(1);
+ expect(matrix[5]).to.equal(0);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(1);
+}
+
+function pixi_core_Matrix_confirmNewMat4(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[0]).to.equal(1);
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(0);
+ expect(matrix[5]).to.equal(1);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(0);
+ expect(matrix[9]).to.equal(0);
+ expect(matrix[10]).to.equal(1);
+ expect(matrix[11]).to.equal(0);
+ expect(matrix[12]).to.equal(0);
+ expect(matrix[13]).to.equal(0);
+ expect(matrix[14]).to.equal(0);
+ expect(matrix[15]).to.equal(1);
+}
diff --git a/test/lib/pixi/core/Point.js b/test/lib/pixi/core/Point.js
new file mode 100644
index 0000000..e5df07b
--- /dev/null
+++ b/test/lib/pixi/core/Point.js
@@ -0,0 +1,10 @@
+
+function pixi_core_Point_confirm(obj, x, y) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Point);
+ expect(obj).to.respondTo('clone');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+}
diff --git a/test/lib/pixi/core/Rectangle.js b/test/lib/pixi/core/Rectangle.js
new file mode 100644
index 0000000..23f0d12
--- /dev/null
+++ b/test/lib/pixi/core/Rectangle.js
@@ -0,0 +1,13 @@
+
+function pixi_core_Rectangle_confirm(obj, x, y, width, height) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Rectangle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+ expect(obj).to.have.property('width', width);
+ expect(obj).to.have.property('height', height);
+}
diff --git a/test/lib/pixi/display/DisplayObject.js b/test/lib/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..1388a7f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObject.js
@@ -0,0 +1,43 @@
+
+function pixi_display_DisplayObject_confirmNew(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObject);
+ expect(obj).to.respondTo('setInteractive');
+ expect(obj).to.respondTo('addFilter');
+ expect(obj).to.respondTo('removeFilter');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.property('last', obj);
+ expect(obj).to.have.property('first', obj);
+
+ expect(obj).to.contain.property('position');
+ pixi_core_Point_confirm(obj.position, 0, 0);
+ expect(obj).to.contain.property('scale');
+ pixi_core_Point_confirm(obj.scale, 1, 1);
+ expect(obj).to.contain.property('pivot');
+ pixi_core_Point_confirm(obj.pivot, 0, 0);
+
+ expect(obj).to.have.property('rotation', 0);
+ expect(obj).to.have.property('alpha', 1);
+ expect(obj).to.have.property('visible', true);
+ expect(obj).to.have.property('buttonMode', false);
+ expect(obj).to.have.property('parent', null);
+ expect(obj).to.have.property('worldAlpha', 1);
+
+ expect(obj).to.have.property('hitArea');
+ expect(obj).to.have.property('interactive'); // TODO: Have a better default value
+ expect('mask' in obj).to.be.true; // TODO: Have a better default value
+ expect(obj.mask).to.be.undefined;
+
+ expect(obj).to.have.property('renderable');
+ expect(obj).to.have.property('stage');
+
+ expect(obj).to.have.deep.property('worldTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ expect(obj).to.have.deep.property('localTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.localTransform);
+
+ expect(obj).to.have.deep.property('color.length', 0);
+ expect(obj).to.have.property('dynamic', true);
+}
diff --git a/test/lib/pixi/display/DisplayObjectContainer.js b/test/lib/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..085c59f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,16 @@
+
+function pixi_display_DisplayObjectContainer_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObject_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObjectContainer);
+ expect(obj).to.respondTo('addChild');
+ expect(obj).to.respondTo('addChildAt');
+ expect(obj).to.respondTo('swapChildren');
+ expect(obj).to.respondTo('getChildAt');
+ expect(obj).to.respondTo('removeChild');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('children.length', 0);
+}
diff --git a/test/lib/pixi/display/Sprite.js b/test/lib/pixi/display/Sprite.js
new file mode 100644
index 0000000..cc7a2d6
--- /dev/null
+++ b/test/lib/pixi/display/Sprite.js
@@ -0,0 +1,28 @@
+
+function pixi_display_Sprite_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Sprite);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', true);
+ expect(obj).to.have.property('stage', null);
+
+ expect(obj).to.have.property('anchor');
+ pixi_core_Point_confirm(obj.anchor, 0, 0);
+
+ expect(obj).to.have.property('blendMode', PIXI.blendModes.NORMAL);
+ expect(obj).to.have.property('width', 1); // TODO: is 1 expected
+ expect(obj).to.have.property('height', 1); // TODO: is 1 expected
+
+ // FIXME: Just make this a boolean that is always there
+ expect(!!obj.updateFrame).to.equal(obj.texture.baseTexture.hasLoaded);
+
+ expect(obj).to.have.property('texture');
+ pixi_textures_Texture_confirmNew(obj.texture, done);
+}
diff --git a/test/lib/pixi/extras/Strip.js b/test/lib/pixi/extras/Strip.js
new file mode 100644
index 0000000..8927a8a
--- /dev/null
+++ b/test/lib/pixi/extras/Strip.js
@@ -0,0 +1,12 @@
+
+function pixi_extras_Strip_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Strip);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ // TODO: Test properties
+}
diff --git a/test/lib/pixi/textures/Texture.js b/test/lib/pixi/textures/Texture.js
new file mode 100644
index 0000000..d5867b6
--- /dev/null
+++ b/test/lib/pixi/textures/Texture.js
@@ -0,0 +1,31 @@
+
+function pixi_textures_Texture_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ function confirmFrameDone() {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, obj.baseTexture.width, obj.baseTexture.height);
+
+ expect(obj).to.have.property('width', obj.baseTexture.width);
+ expect(obj).to.have.property('height', obj.baseTexture.height);
+ done();
+ }
+
+ expect(obj).to.be.an.instanceof(PIXI.Texture);
+ pixi_utils_EventTarget_like(obj);
+
+ expect(obj).to.have.property('baseTexture')
+ .and.to.be.an.instanceof(PIXI.BaseTexture);
+
+ expect(obj).to.have.property('scope', obj);
+
+ expect(obj).to.have.property('trim');
+ pixi_core_Point_confirm(obj.trim, 0, 0);
+
+ expect(obj).to.have.property('frame');
+ if (obj.baseTexture.hasLoaded) {
+ confirmFrameDone();
+ } else {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, 1, 1);
+ obj.addEventListener('update', confirmFrameDone);
+ }
+}
diff --git a/test/lib/pixi/utils/EventTarget.js b/test/lib/pixi/utils/EventTarget.js
new file mode 100644
index 0000000..7b1dcfa
--- /dev/null
+++ b/test/lib/pixi/utils/EventTarget.js
@@ -0,0 +1,8 @@
+
+function pixi_utils_EventTarget_like(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.respondTo('addEventListener');
+ expect(obj).to.respondTo('dispatchEvent');
+ expect(obj).to.respondTo('removeEventListener');
+}
diff --git a/test/lib/qunit-1.11.0.css b/test/lib/qunit-1.11.0.css
deleted file mode 100644
index d7fc0c8..0000000
--- a/test/lib/qunit-1.11.0.css
+++ /dev/null
@@ -1,244 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-/** Font Family and Sizes */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
- font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
-}
-
-#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
-#qunit-tests { font-size: smaller; }
-
-
-/** Resets */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter {
- margin: 0;
- padding: 0;
-}
-
-
-/** Header */
-
-#qunit-header {
- padding: 0.5em 0 0.5em 1em;
-
- color: #8699a4;
- background-color: #0d3349;
-
- font-size: 1.5em;
- line-height: 1em;
- font-weight: normal;
-
- border-radius: 5px 5px 0 0;
- -moz-border-radius: 5px 5px 0 0;
- -webkit-border-top-right-radius: 5px;
- -webkit-border-top-left-radius: 5px;
-}
-
-#qunit-header a {
- text-decoration: none;
- color: #c2ccd1;
-}
-
-#qunit-header a:hover,
-#qunit-header a:focus {
- color: #fff;
-}
-
-#qunit-testrunner-toolbar label {
- display: inline-block;
- padding: 0 .5em 0 .1em;
-}
-
-#qunit-banner {
- height: 5px;
-}
-
-#qunit-testrunner-toolbar {
- padding: 0.5em 0 0.5em 2em;
- color: #5E740B;
- background-color: #eee;
- overflow: hidden;
-}
-
-#qunit-userAgent {
- padding: 0.5em 0 0.5em 2.5em;
- background-color: #2b81af;
- color: #fff;
- text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
-}
-
-#qunit-modulefilter-container {
- float: right;
-}
-
-/** Tests: Pass/Fail */
-
-#qunit-tests {
- list-style-position: inside;
-}
-
-#qunit-tests li {
- padding: 0.4em 0.5em 0.4em 2.5em;
- border-bottom: 1px solid #fff;
- list-style-position: inside;
-}
-
-#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running {
- display: none;
-}
-
-#qunit-tests li strong {
- cursor: pointer;
-}
-
-#qunit-tests li a {
- padding: 0.5em;
- color: #c2ccd1;
- text-decoration: none;
-}
-#qunit-tests li a:hover,
-#qunit-tests li a:focus {
- color: #000;
-}
-
-#qunit-tests li .runtime {
- float: right;
- font-size: smaller;
-}
-
-.qunit-assert-list {
- margin-top: 0.5em;
- padding: 0.5em;
-
- background-color: #fff;
-
- border-radius: 5px;
- -moz-border-radius: 5px;
- -webkit-border-radius: 5px;
-}
-
-.qunit-collapsed {
- display: none;
-}
-
-#qunit-tests table {
- border-collapse: collapse;
- margin-top: .2em;
-}
-
-#qunit-tests th {
- text-align: right;
- vertical-align: top;
- padding: 0 .5em 0 0;
-}
-
-#qunit-tests td {
- vertical-align: top;
-}
-
-#qunit-tests pre {
- margin: 0;
- white-space: pre-wrap;
- word-wrap: break-word;
-}
-
-#qunit-tests del {
- background-color: #e0f2be;
- color: #374e0c;
- text-decoration: none;
-}
-
-#qunit-tests ins {
- background-color: #ffcaca;
- color: #500;
- text-decoration: none;
-}
-
-/*** Test Counts */
-
-#qunit-tests b.counts { color: black; }
-#qunit-tests b.passed { color: #5E740B; }
-#qunit-tests b.failed { color: #710909; }
-
-#qunit-tests li li {
- padding: 5px;
- background-color: #fff;
- border-bottom: none;
- list-style-position: inside;
-}
-
-/*** Passing Styles */
-
-#qunit-tests li li.pass {
- color: #3c510c;
- background-color: #fff;
- border-left: 10px solid #C6E746;
-}
-
-#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
-#qunit-tests .pass .test-name { color: #366097; }
-
-#qunit-tests .pass .test-actual,
-#qunit-tests .pass .test-expected { color: #999999; }
-
-#qunit-banner.qunit-pass { background-color: #C6E746; }
-
-/*** Failing Styles */
-
-#qunit-tests li li.fail {
- color: #710909;
- background-color: #fff;
- border-left: 10px solid #EE5757;
- white-space: pre;
-}
-
-#qunit-tests > li:last-child {
- border-radius: 0 0 5px 5px;
- -moz-border-radius: 0 0 5px 5px;
- -webkit-border-bottom-right-radius: 5px;
- -webkit-border-bottom-left-radius: 5px;
-}
-
-#qunit-tests .fail { color: #000000; background-color: #EE5757; }
-#qunit-tests .fail .test-name,
-#qunit-tests .fail .module-name { color: #000000; }
-
-#qunit-tests .fail .test-actual { color: #EE5757; }
-#qunit-tests .fail .test-expected { color: green; }
-
-#qunit-banner.qunit-fail { background-color: #EE5757; }
-
-
-/** Result */
-
-#qunit-testresult {
- padding: 0.5em 0.5em 0.5em 2.5em;
-
- color: #2b81af;
- background-color: #D2E0E6;
-
- border-bottom: 1px solid white;
-}
-#qunit-testresult .module-name {
- font-weight: bold;
-}
-
-/** Fixture */
-
-#qunit-fixture {
- position: absolute;
- top: -10000px;
- left: -10000px;
- width: 1000px;
- height: 1000px;
-}
diff --git a/test/lib/qunit-1.11.0.js b/test/lib/qunit-1.11.0.js
deleted file mode 100644
index 302545f..0000000
--- a/test/lib/qunit-1.11.0.js
+++ /dev/null
@@ -1,2152 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-(function( window ) {
-
-var QUnit,
- assert,
- config,
- onErrorFnPrev,
- testId = 0,
- fileName = (sourceFromStacktrace( 0 ) || "" ).replace(/(:\d+)+\)?/, "").replace(/.+\//, ""),
- toString = Object.prototype.toString,
- hasOwn = Object.prototype.hasOwnProperty,
- // Keep a local reference to Date (GH-283)
- Date = window.Date,
- defined = {
- setTimeout: typeof window.setTimeout !== "undefined",
- sessionStorage: (function() {
- var x = "qunit-test-string";
- try {
- sessionStorage.setItem( x, x );
- sessionStorage.removeItem( x );
- return true;
- } catch( e ) {
- return false;
- }
- }())
- },
- /**
- * Provides a normalized error string, correcting an issue
- * with IE 7 (and prior) where Error.prototype.toString is
- * not properly implemented
- *
- * Based on http://es5.github.com/#x15.11.4.4
- *
- * @param {String|Error} error
- * @return {String} error message
- */
- errorString = function( error ) {
- var name, message,
- errorString = error.toString();
- if ( errorString.substring( 0, 7 ) === "[object" ) {
- name = error.name ? error.name.toString() : "Error";
- message = error.message ? error.message.toString() : "";
- if ( name && message ) {
- return name + ": " + message;
- } else if ( name ) {
- return name;
- } else if ( message ) {
- return message;
- } else {
- return "Error";
- }
- } else {
- return errorString;
- }
- },
- /**
- * Makes a clone of an object using only Array or Object as base,
- * and copies over the own enumerable properties.
- *
- * @param {Object} obj
- * @return {Object} New object with only the own properties (recursively).
- */
- objectValues = function( obj ) {
- // Grunt 0.3.x uses an older version of jshint that still has jshint/jshint#392.
- /*jshint newcap: false */
- var key, val,
- vals = QUnit.is( "array", obj ) ? [] : {};
- for ( key in obj ) {
- if ( hasOwn.call( obj, key ) ) {
- val = obj[key];
- vals[key] = val === Object(val) ? objectValues(val) : val;
- }
- }
- return vals;
- };
-
-function Test( settings ) {
- extend( this, settings );
- this.assertions = [];
- this.testNumber = ++Test.count;
-}
-
-Test.count = 0;
-
-Test.prototype = {
- init: function() {
- var a, b, li,
- tests = id( "qunit-tests" );
-
- if ( tests ) {
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml;
-
- // `a` initialized at top of scope
- a = document.createElement( "a" );
- a.innerHTML = "Rerun";
- a.href = QUnit.url({ testNumber: this.testNumber });
-
- li = document.createElement( "li" );
- li.appendChild( b );
- li.appendChild( a );
- li.className = "running";
- li.id = this.id = "qunit-test-output" + testId++;
-
- tests.appendChild( li );
- }
- },
- setup: function() {
- if ( this.module !== config.previousModule ) {
- if ( config.previousModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.previousModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
- config.previousModule = this.module;
- config.moduleStats = { all: 0, bad: 0 };
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- } else if ( config.autorun ) {
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- }
-
- config.current = this;
-
- this.testEnvironment = extend({
- setup: function() {},
- teardown: function() {}
- }, this.moduleTestEnvironment );
-
- this.started = +new Date();
- runLoggingCallbacks( "testStart", QUnit, {
- name: this.testName,
- module: this.module
- });
-
- // allow utility functions to access the current test environment
- // TODO why??
- QUnit.current_testEnvironment = this.testEnvironment;
-
- if ( !config.pollution ) {
- saveGlobal();
- }
- if ( config.notrycatch ) {
- this.testEnvironment.setup.call( this.testEnvironment );
- return;
- }
- try {
- this.testEnvironment.setup.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Setup failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- },
- run: function() {
- config.current = this;
-
- var running = id( "qunit-testresult" );
-
- if ( running ) {
- running.innerHTML = "Running:
" + this.nameHtml;
- }
-
- if ( this.async ) {
- QUnit.stop();
- }
-
- this.callbackStarted = +new Date();
-
- if ( config.notrycatch ) {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- return;
- }
-
- try {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- } catch( e ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
-
- QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + " " + this.stack + ": " + ( e.message || e ), extractStacktrace( e, 0 ) );
- // else next test will carry the responsibility
- saveGlobal();
-
- // Restart the tests if they're blocking
- if ( config.blocking ) {
- QUnit.start();
- }
- }
- },
- teardown: function() {
- config.current = this;
- if ( config.notrycatch ) {
- if ( typeof this.callbackRuntime === "undefined" ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
- }
- this.testEnvironment.teardown.call( this.testEnvironment );
- return;
- } else {
- try {
- this.testEnvironment.teardown.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Teardown failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- }
- checkPollution();
- },
- finish: function() {
- config.current = this;
- if ( config.requireExpects && this.expected === null ) {
- QUnit.pushFailure( "Expected number of assertions to be defined, but expect() was not called.", this.stack );
- } else if ( this.expected !== null && this.expected !== this.assertions.length ) {
- QUnit.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack );
- } else if ( this.expected === null && !this.assertions.length ) {
- QUnit.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions.", this.stack );
- }
-
- var i, assertion, a, b, time, li, ol,
- test = this,
- good = 0,
- bad = 0,
- tests = id( "qunit-tests" );
-
- this.runtime = +new Date() - this.started;
- config.stats.all += this.assertions.length;
- config.moduleStats.all += this.assertions.length;
-
- if ( tests ) {
- ol = document.createElement( "ol" );
- ol.className = "qunit-assert-list";
-
- for ( i = 0; i < this.assertions.length; i++ ) {
- assertion = this.assertions[i];
-
- li = document.createElement( "li" );
- li.className = assertion.result ? "pass" : "fail";
- li.innerHTML = assertion.message || ( assertion.result ? "okay" : "failed" );
- ol.appendChild( li );
-
- if ( assertion.result ) {
- good++;
- } else {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
-
- // store result when possible
- if ( QUnit.config.reorder && defined.sessionStorage ) {
- if ( bad ) {
- sessionStorage.setItem( "qunit-test-" + this.module + "-" + this.testName, bad );
- } else {
- sessionStorage.removeItem( "qunit-test-" + this.module + "-" + this.testName );
- }
- }
-
- if ( bad === 0 ) {
- addClass( ol, "qunit-collapsed" );
- }
-
- // `b` initialized at top of scope
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml + " (" + bad + ", " + good + ", " + this.assertions.length + ")";
-
- addEvent(b, "click", function() {
- var next = b.parentNode.lastChild,
- collapsed = hasClass( next, "qunit-collapsed" );
- ( collapsed ? removeClass : addClass )( next, "qunit-collapsed" );
- });
-
- addEvent(b, "dblclick", function( e ) {
- var target = e && e.target ? e.target : window.event.srcElement;
- if ( target.nodeName.toLowerCase() === "span" || target.nodeName.toLowerCase() === "b" ) {
- target = target.parentNode;
- }
- if ( window.location && target.nodeName.toLowerCase() === "strong" ) {
- window.location = QUnit.url({ testNumber: test.testNumber });
- }
- });
-
- // `time` initialized at top of scope
- time = document.createElement( "span" );
- time.className = "runtime";
- time.innerHTML = this.runtime + " ms";
-
- // `li` initialized at top of scope
- li = id( this.id );
- li.className = bad ? "fail" : "pass";
- li.removeChild( li.firstChild );
- a = li.firstChild;
- li.appendChild( b );
- li.appendChild( a );
- li.appendChild( time );
- li.appendChild( ol );
-
- } else {
- for ( i = 0; i < this.assertions.length; i++ ) {
- if ( !this.assertions[i].result ) {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
- }
-
- runLoggingCallbacks( "testDone", QUnit, {
- name: this.testName,
- module: this.module,
- failed: bad,
- passed: this.assertions.length - bad,
- total: this.assertions.length,
- duration: this.runtime
- });
-
- QUnit.reset();
-
- config.current = undefined;
- },
-
- queue: function() {
- var bad,
- test = this;
-
- synchronize(function() {
- test.init();
- });
- function run() {
- // each of these can by async
- synchronize(function() {
- test.setup();
- });
- synchronize(function() {
- test.run();
- });
- synchronize(function() {
- test.teardown();
- });
- synchronize(function() {
- test.finish();
- });
- }
-
- // `bad` initialized at top of scope
- // defer when previous test run passed, if storage is available
- bad = QUnit.config.reorder && defined.sessionStorage &&
- +sessionStorage.getItem( "qunit-test-" + this.module + "-" + this.testName );
-
- if ( bad ) {
- run();
- } else {
- synchronize( run, true );
- }
- }
-};
-
-// Root QUnit object.
-// `QUnit` initialized at top of scope
-QUnit = {
-
- // call on start of module test to prepend name to all tests
- module: function( name, testEnvironment ) {
- config.currentModule = name;
- config.currentModuleTestEnvironment = testEnvironment;
- config.modules[name] = true;
- },
-
- asyncTest: function( testName, expected, callback ) {
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- QUnit.test( testName, expected, callback, true );
- },
-
- test: function( testName, expected, callback, async ) {
- var test,
- nameHtml = "" + escapeText( testName ) + "";
-
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- if ( config.currentModule ) {
- nameHtml = "" + escapeText( config.currentModule ) + ": " + nameHtml;
- }
-
- test = new Test({
- nameHtml: nameHtml,
- testName: testName,
- expected: expected,
- async: async,
- callback: callback,
- module: config.currentModule,
- moduleTestEnvironment: config.currentModuleTestEnvironment,
- stack: sourceFromStacktrace( 2 )
- });
-
- if ( !validTest( test ) ) {
- return;
- }
-
- test.queue();
- },
-
- // Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through.
- expect: function( asserts ) {
- if (arguments.length === 1) {
- config.current.expected = asserts;
- } else {
- return config.current.expected;
- }
- },
-
- start: function( count ) {
- // QUnit hasn't been initialized yet.
- // Note: RequireJS (et al) may delay onLoad
- if ( config.semaphore === undefined ) {
- QUnit.begin(function() {
- // This is triggered at the top of QUnit.load, push start() to the event loop, to allow QUnit.load to finish first
- setTimeout(function() {
- QUnit.start( count );
- });
- });
- return;
- }
-
- config.semaphore -= count || 1;
- // don't start until equal number of stop-calls
- if ( config.semaphore > 0 ) {
- return;
- }
- // ignore if start is called more often then stop
- if ( config.semaphore < 0 ) {
- config.semaphore = 0;
- QUnit.pushFailure( "Called start() while already started (QUnit.config.semaphore was 0 already)", null, sourceFromStacktrace(2) );
- return;
- }
- // A slight delay, to avoid any current callbacks
- if ( defined.setTimeout ) {
- window.setTimeout(function() {
- if ( config.semaphore > 0 ) {
- return;
- }
- if ( config.timeout ) {
- clearTimeout( config.timeout );
- }
-
- config.blocking = false;
- process( true );
- }, 13);
- } else {
- config.blocking = false;
- process( true );
- }
- },
-
- stop: function( count ) {
- config.semaphore += count || 1;
- config.blocking = true;
-
- if ( config.testTimeout && defined.setTimeout ) {
- clearTimeout( config.timeout );
- config.timeout = window.setTimeout(function() {
- QUnit.ok( false, "Test timed out" );
- config.semaphore = 1;
- QUnit.start();
- }, config.testTimeout );
- }
- }
-};
-
-// `assert` initialized at top of scope
-// Asssert helpers
-// All of these must either call QUnit.push() or manually do:
-// - runLoggingCallbacks( "log", .. );
-// - config.current.assertions.push({ .. });
-// We attach it to the QUnit object *after* we expose the public API,
-// otherwise `assert` will become a global variable in browsers (#341).
-assert = {
- /**
- * Asserts rough true-ish result.
- * @name ok
- * @function
- * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" );
- */
- ok: function( result, msg ) {
- if ( !config.current ) {
- throw new Error( "ok() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
- result = !!result;
-
- var source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: msg
- };
-
- msg = escapeText( msg || (result ? "okay" : "failed" ) );
- msg = "" + msg + "";
-
- if ( !result ) {
- source = sourceFromStacktrace( 2 );
- if ( source ) {
- details.source = source;
- msg += "Source: | " + escapeText( source ) + " |
---|
";
- }
- }
- runLoggingCallbacks( "log", QUnit, details );
- config.current.assertions.push({
- result: result,
- message: msg
- });
- },
-
- /**
- * Assert that the first two arguments are equal, with an optional message.
- * Prints out both actual and expected values.
- * @name equal
- * @function
- * @example equal( format( "Received {0} bytes.", 2), "Received 2 bytes.", "format() replaces {0} with next argument" );
- */
- equal: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected == actual, actual, expected, message );
- },
-
- /**
- * @name notEqual
- * @function
- */
- notEqual: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected != actual, actual, expected, message );
- },
-
- /**
- * @name propEqual
- * @function
- */
- propEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notPropEqual
- * @function
- */
- notPropEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name deepEqual
- * @function
- */
- deepEqual: function( actual, expected, message ) {
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notDeepEqual
- * @function
- */
- notDeepEqual: function( actual, expected, message ) {
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name strictEqual
- * @function
- */
- strictEqual: function( actual, expected, message ) {
- QUnit.push( expected === actual, actual, expected, message );
- },
-
- /**
- * @name notStrictEqual
- * @function
- */
- notStrictEqual: function( actual, expected, message ) {
- QUnit.push( expected !== actual, actual, expected, message );
- },
-
- "throws": function( block, expected, message ) {
- var actual,
- expectedOutput = expected,
- ok = false;
-
- // 'expected' is optional
- if ( typeof expected === "string" ) {
- message = expected;
- expected = null;
- }
-
- config.current.ignoreGlobalErrors = true;
- try {
- block.call( config.current.testEnvironment );
- } catch (e) {
- actual = e;
- }
- config.current.ignoreGlobalErrors = false;
-
- if ( actual ) {
- // we don't want to validate thrown error
- if ( !expected ) {
- ok = true;
- expectedOutput = null;
- // expected is a regexp
- } else if ( QUnit.objectType( expected ) === "regexp" ) {
- ok = expected.test( errorString( actual ) );
- // expected is a constructor
- } else if ( actual instanceof expected ) {
- ok = true;
- // expected is a validation function which returns true is validation passed
- } else if ( expected.call( {}, actual ) === true ) {
- expectedOutput = null;
- ok = true;
- }
-
- QUnit.push( ok, actual, expectedOutput, message );
- } else {
- QUnit.pushFailure( message, null, 'No exception was thrown.' );
- }
- }
-};
-
-/**
- * @deprecate since 1.8.0
- * Kept assertion helpers in root for backwards compatibility.
- */
-extend( QUnit, assert );
-
-/**
- * @deprecated since 1.9.0
- * Kept root "raises()" for backwards compatibility.
- * (Note that we don't introduce assert.raises).
- */
-QUnit.raises = assert[ "throws" ];
-
-/**
- * @deprecated since 1.0.0, replaced with error pushes since 1.3.0
- * Kept to avoid TypeErrors for undefined methods.
- */
-QUnit.equals = function() {
- QUnit.push( false, false, false, "QUnit.equals has been deprecated since 2009 (e88049a0), use QUnit.equal instead" );
-};
-QUnit.same = function() {
- QUnit.push( false, false, false, "QUnit.same has been deprecated since 2009 (e88049a0), use QUnit.deepEqual instead" );
-};
-
-// We want access to the constructor's prototype
-(function() {
- function F() {}
- F.prototype = QUnit;
- QUnit = new F();
- // Make F QUnit's constructor so that we can add to the prototype later
- QUnit.constructor = F;
-}());
-
-/**
- * Config object: Maintain internal state
- * Later exposed as QUnit.config
- * `config` initialized at top of scope
- */
-config = {
- // The queue of tests to run
- queue: [],
-
- // block until document ready
- blocking: true,
-
- // when enabled, show only failing tests
- // gets persisted through sessionStorage and can be changed in UI via checkbox
- hidepassed: false,
-
- // by default, run previously failed tests first
- // very useful in combination with "Hide passed tests" checked
- reorder: true,
-
- // by default, modify document.title when suite is done
- altertitle: true,
-
- // when enabled, all tests must call expect()
- requireExpects: false,
-
- // add checkboxes that are persisted in the query-string
- // when enabled, the id is set to `true` as a `QUnit.config` property
- urlConfig: [
- {
- id: "noglobals",
- label: "Check for Globals",
- tooltip: "Enabling this will test if any test introduces new properties on the `window` object. Stored as query-strings."
- },
- {
- id: "notrycatch",
- label: "No try-catch",
- tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging exceptions in IE reasonable. Stored as query-strings."
- }
- ],
-
- // Set of all modules.
- modules: {},
-
- // logging callback queues
- begin: [],
- done: [],
- log: [],
- testStart: [],
- testDone: [],
- moduleStart: [],
- moduleDone: []
-};
-
-// Export global variables, unless an 'exports' object exists,
-// in that case we assume we're in CommonJS (dealt with on the bottom of the script)
-if ( typeof exports === "undefined" ) {
- extend( window, QUnit );
-
- // Expose QUnit object
- window.QUnit = QUnit;
-}
-
-// Initialize more QUnit.config and QUnit.urlParams
-(function() {
- var i,
- location = window.location || { search: "", protocol: "file:" },
- params = location.search.slice( 1 ).split( "&" ),
- length = params.length,
- urlParams = {},
- current;
-
- if ( params[ 0 ] ) {
- for ( i = 0; i < length; i++ ) {
- current = params[ i ].split( "=" );
- current[ 0 ] = decodeURIComponent( current[ 0 ] );
- // allow just a key to turn on a flag, e.g., test.html?noglobals
- current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true;
- urlParams[ current[ 0 ] ] = current[ 1 ];
- }
- }
-
- QUnit.urlParams = urlParams;
-
- // String search anywhere in moduleName+testName
- config.filter = urlParams.filter;
-
- // Exact match of the module name
- config.module = urlParams.module;
-
- config.testNumber = parseInt( urlParams.testNumber, 10 ) || null;
-
- // Figure out if we're running the tests from a server or not
- QUnit.isLocal = location.protocol === "file:";
-}());
-
-// Extend QUnit object,
-// these after set here because they should not be exposed as global functions
-extend( QUnit, {
- assert: assert,
-
- config: config,
-
- // Initialize the configuration options
- init: function() {
- extend( config, {
- stats: { all: 0, bad: 0 },
- moduleStats: { all: 0, bad: 0 },
- started: +new Date(),
- updateRate: 1000,
- blocking: false,
- autostart: true,
- autorun: false,
- filter: "",
- queue: [],
- semaphore: 1
- });
-
- var tests, banner, result,
- qunit = id( "qunit" );
-
- if ( qunit ) {
- qunit.innerHTML =
- "" +
- "" +
- "" +
- "" +
- "
";
- }
-
- tests = id( "qunit-tests" );
- banner = id( "qunit-banner" );
- result = id( "qunit-testresult" );
-
- if ( tests ) {
- tests.innerHTML = "";
- }
-
- if ( banner ) {
- banner.className = "";
- }
-
- if ( result ) {
- result.parentNode.removeChild( result );
- }
-
- if ( tests ) {
- result = document.createElement( "p" );
- result.id = "qunit-testresult";
- result.className = "result";
- tests.parentNode.insertBefore( result, tests );
- result.innerHTML = "Running...
";
- }
- },
-
- // Resets the test setup. Useful for tests that modify the DOM.
- reset: function() {
- var fixture = id( "qunit-fixture" );
- if ( fixture ) {
- fixture.innerHTML = config.fixture;
- }
- },
-
- // Trigger an event on an element.
- // @example triggerEvent( document.body, "click" );
- triggerEvent: function( elem, type, event ) {
- if ( document.createEvent ) {
- event = document.createEvent( "MouseEvents" );
- event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView,
- 0, 0, 0, 0, 0, false, false, false, false, 0, null);
-
- elem.dispatchEvent( event );
- } else if ( elem.fireEvent ) {
- elem.fireEvent( "on" + type );
- }
- },
-
- // Safe object type checking
- is: function( type, obj ) {
- return QUnit.objectType( obj ) === type;
- },
-
- objectType: function( obj ) {
- if ( typeof obj === "undefined" ) {
- return "undefined";
- // consider: typeof null === object
- }
- if ( obj === null ) {
- return "null";
- }
-
- var match = toString.call( obj ).match(/^\[object\s(.*)\]$/),
- type = match && match[1] || "";
-
- switch ( type ) {
- case "Number":
- if ( isNaN(obj) ) {
- return "nan";
- }
- return "number";
- case "String":
- case "Boolean":
- case "Array":
- case "Date":
- case "RegExp":
- case "Function":
- return type.toLowerCase();
- }
- if ( typeof obj === "object" ) {
- return "object";
- }
- return undefined;
- },
-
- push: function( result, actual, expected, message ) {
- if ( !config.current ) {
- throw new Error( "assertion outside test context, was " + sourceFromStacktrace() );
- }
-
- var output, source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: message,
- actual: actual,
- expected: expected
- };
-
- message = escapeText( message ) || ( result ? "okay" : "failed" );
- message = "" + message + "";
- output = message;
-
- if ( !result ) {
- expected = escapeText( QUnit.jsDump.parse(expected) );
- actual = escapeText( QUnit.jsDump.parse(actual) );
- output += "Expected: | " + expected + " |
";
-
- if ( actual !== expected ) {
- output += "Result: | " + actual + " |
";
- output += "Diff: | " + QUnit.diff( expected, actual ) + " |
";
- }
-
- source = sourceFromStacktrace();
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
- }
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: !!result,
- message: output
- });
- },
-
- pushFailure: function( message, source, actual ) {
- if ( !config.current ) {
- throw new Error( "pushFailure() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
-
- var output,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: false,
- message: message
- };
-
- message = escapeText( message ) || "error";
- message = "" + message + "";
- output = message;
-
- output += "";
-
- if ( actual ) {
- output += "Result: | " + escapeText( actual ) + " |
";
- }
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: false,
- message: output
- });
- },
-
- url: function( params ) {
- params = extend( extend( {}, QUnit.urlParams ), params );
- var key,
- querystring = "?";
-
- for ( key in params ) {
- if ( !hasOwn.call( params, key ) ) {
- continue;
- }
- querystring += encodeURIComponent( key ) + "=" +
- encodeURIComponent( params[ key ] ) + "&";
- }
- return window.location.protocol + "//" + window.location.host +
- window.location.pathname + querystring.slice( 0, -1 );
- },
-
- extend: extend,
- id: id,
- addEvent: addEvent
- // load, equiv, jsDump, diff: Attached later
-});
-
-/**
- * @deprecated: Created for backwards compatibility with test runner that set the hook function
- * into QUnit.{hook}, instead of invoking it and passing the hook function.
- * QUnit.constructor is set to the empty F() above so that we can add to it's prototype here.
- * Doing this allows us to tell if the following methods have been overwritten on the actual
- * QUnit object.
- */
-extend( QUnit.constructor.prototype, {
-
- // Logging callbacks; all receive a single argument with the listed properties
- // run test/logs.html for any related changes
- begin: registerLoggingCallback( "begin" ),
-
- // done: { failed, passed, total, runtime }
- done: registerLoggingCallback( "done" ),
-
- // log: { result, actual, expected, message }
- log: registerLoggingCallback( "log" ),
-
- // testStart: { name }
- testStart: registerLoggingCallback( "testStart" ),
-
- // testDone: { name, failed, passed, total, duration }
- testDone: registerLoggingCallback( "testDone" ),
-
- // moduleStart: { name }
- moduleStart: registerLoggingCallback( "moduleStart" ),
-
- // moduleDone: { name, failed, passed, total }
- moduleDone: registerLoggingCallback( "moduleDone" )
-});
-
-if ( typeof document === "undefined" || document.readyState === "complete" ) {
- config.autorun = true;
-}
-
-QUnit.load = function() {
- runLoggingCallbacks( "begin", QUnit, {} );
-
- // Initialize the config, saving the execution queue
- var banner, filter, i, label, len, main, ol, toolbar, userAgent, val,
- urlConfigCheckboxesContainer, urlConfigCheckboxes, moduleFilter,
- numModules = 0,
- moduleFilterHtml = "",
- urlConfigHtml = "",
- oldconfig = extend( {}, config );
-
- QUnit.init();
- extend(config, oldconfig);
-
- config.blocking = false;
-
- len = config.urlConfig.length;
-
- for ( i = 0; i < len; i++ ) {
- val = config.urlConfig[i];
- if ( typeof val === "string" ) {
- val = {
- id: val,
- label: val,
- tooltip: "[no tooltip available]"
- };
- }
- config[ val.id ] = QUnit.urlParams[ val.id ];
- urlConfigHtml += "";
- }
-
- moduleFilterHtml += "";
-
- // `userAgent` initialized at top of scope
- userAgent = id( "qunit-userAgent" );
- if ( userAgent ) {
- userAgent.innerHTML = navigator.userAgent;
- }
-
- // `banner` initialized at top of scope
- banner = id( "qunit-header" );
- if ( banner ) {
- banner.innerHTML = "" + banner.innerHTML + " ";
- }
-
- // `toolbar` initialized at top of scope
- toolbar = id( "qunit-testrunner-toolbar" );
- if ( toolbar ) {
- // `filter` initialized at top of scope
- filter = document.createElement( "input" );
- filter.type = "checkbox";
- filter.id = "qunit-filter-pass";
-
- addEvent( filter, "click", function() {
- var tmp,
- ol = document.getElementById( "qunit-tests" );
-
- if ( filter.checked ) {
- ol.className = ol.className + " hidepass";
- } else {
- tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " ";
- ol.className = tmp.replace( / hidepass /, " " );
- }
- if ( defined.sessionStorage ) {
- if (filter.checked) {
- sessionStorage.setItem( "qunit-filter-passed-tests", "true" );
- } else {
- sessionStorage.removeItem( "qunit-filter-passed-tests" );
- }
- }
- });
-
- if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem( "qunit-filter-passed-tests" ) ) {
- filter.checked = true;
- // `ol` initialized at top of scope
- ol = document.getElementById( "qunit-tests" );
- ol.className = ol.className + " hidepass";
- }
- toolbar.appendChild( filter );
-
- // `label` initialized at top of scope
- label = document.createElement( "label" );
- label.setAttribute( "for", "qunit-filter-pass" );
- label.setAttribute( "title", "Only show tests and assertons that fail. Stored in sessionStorage." );
- label.innerHTML = "Hide passed tests";
- toolbar.appendChild( label );
-
- urlConfigCheckboxesContainer = document.createElement("span");
- urlConfigCheckboxesContainer.innerHTML = urlConfigHtml;
- urlConfigCheckboxes = urlConfigCheckboxesContainer.getElementsByTagName("input");
- // For oldIE support:
- // * Add handlers to the individual elements instead of the container
- // * Use "click" instead of "change"
- // * Fallback from event.target to event.srcElement
- addEvents( urlConfigCheckboxes, "click", function( event ) {
- var params = {},
- target = event.target || event.srcElement;
- params[ target.name ] = target.checked ? true : undefined;
- window.location = QUnit.url( params );
- });
- toolbar.appendChild( urlConfigCheckboxesContainer );
-
- if (numModules > 1) {
- moduleFilter = document.createElement( 'span' );
- moduleFilter.setAttribute( 'id', 'qunit-modulefilter-container' );
- moduleFilter.innerHTML = moduleFilterHtml;
- addEvent( moduleFilter.lastChild, "change", function() {
- var selectBox = moduleFilter.getElementsByTagName("select")[0],
- selectedModule = decodeURIComponent(selectBox.options[selectBox.selectedIndex].value);
-
- window.location = QUnit.url( { module: ( selectedModule === "" ) ? undefined : selectedModule } );
- });
- toolbar.appendChild(moduleFilter);
- }
- }
-
- // `main` initialized at top of scope
- main = id( "qunit-fixture" );
- if ( main ) {
- config.fixture = main.innerHTML;
- }
-
- if ( config.autostart ) {
- QUnit.start();
- }
-};
-
-addEvent( window, "load", QUnit.load );
-
-// `onErrorFnPrev` initialized at top of scope
-// Preserve other handlers
-onErrorFnPrev = window.onerror;
-
-// Cover uncaught exceptions
-// Returning true will surpress the default browser handler,
-// returning false will let it run.
-window.onerror = function ( error, filePath, linerNr ) {
- var ret = false;
- if ( onErrorFnPrev ) {
- ret = onErrorFnPrev( error, filePath, linerNr );
- }
-
- // Treat return value as window.onerror itself does,
- // Only do our handling if not surpressed.
- if ( ret !== true ) {
- if ( QUnit.config.current ) {
- if ( QUnit.config.current.ignoreGlobalErrors ) {
- return true;
- }
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- } else {
- QUnit.test( "global failure", extend( function() {
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- }, { validTest: validTest } ) );
- }
- return false;
- }
-
- return ret;
-};
-
-function done() {
- config.autorun = true;
-
- // Log the last module results
- if ( config.currentModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.currentModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
-
- var i, key,
- banner = id( "qunit-banner" ),
- tests = id( "qunit-tests" ),
- runtime = +new Date() - config.started,
- passed = config.stats.all - config.stats.bad,
- html = [
- "Tests completed in ",
- runtime,
- " milliseconds.
",
- "",
- passed,
- " assertions of ",
- config.stats.all,
- " passed, ",
- config.stats.bad,
- " failed."
- ].join( "" );
-
- if ( banner ) {
- banner.className = ( config.stats.bad ? "qunit-fail" : "qunit-pass" );
- }
-
- if ( tests ) {
- id( "qunit-testresult" ).innerHTML = html;
- }
-
- if ( config.altertitle && typeof document !== "undefined" && document.title ) {
- // show ✖ for good, ✔ for bad suite result in title
- // use escape sequences in case file gets loaded with non-utf-8-charset
- document.title = [
- ( config.stats.bad ? "\u2716" : "\u2714" ),
- document.title.replace( /^[\u2714\u2716] /i, "" )
- ].join( " " );
- }
-
- // clear own sessionStorage items if all tests passed
- if ( config.reorder && defined.sessionStorage && config.stats.bad === 0 ) {
- // `key` & `i` initialized at top of scope
- for ( i = 0; i < sessionStorage.length; i++ ) {
- key = sessionStorage.key( i++ );
- if ( key.indexOf( "qunit-test-" ) === 0 ) {
- sessionStorage.removeItem( key );
- }
- }
- }
-
- // scroll back to top to show results
- if ( window.scrollTo ) {
- window.scrollTo(0, 0);
- }
-
- runLoggingCallbacks( "done", QUnit, {
- failed: config.stats.bad,
- passed: passed,
- total: config.stats.all,
- runtime: runtime
- });
-}
-
-/** @return Boolean: true if this test should be ran */
-function validTest( test ) {
- var include,
- filter = config.filter && config.filter.toLowerCase(),
- module = config.module && config.module.toLowerCase(),
- fullName = (test.module + ": " + test.testName).toLowerCase();
-
- // Internally-generated tests are always valid
- if ( test.callback && test.callback.validTest === validTest ) {
- delete test.callback.validTest;
- return true;
- }
-
- if ( config.testNumber ) {
- return test.testNumber === config.testNumber;
- }
-
- if ( module && ( !test.module || test.module.toLowerCase() !== module ) ) {
- return false;
- }
-
- if ( !filter ) {
- return true;
- }
-
- include = filter.charAt( 0 ) !== "!";
- if ( !include ) {
- filter = filter.slice( 1 );
- }
-
- // If the filter matches, we need to honour include
- if ( fullName.indexOf( filter ) !== -1 ) {
- return include;
- }
-
- // Otherwise, do the opposite
- return !include;
-}
-
-// so far supports only Firefox, Chrome and Opera (buggy), Safari (for real exceptions)
-// Later Safari and IE10 are supposed to support error.stack as well
-// See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack
-function extractStacktrace( e, offset ) {
- offset = offset === undefined ? 3 : offset;
-
- var stack, include, i;
-
- if ( e.stacktrace ) {
- // Opera
- return e.stacktrace.split( "\n" )[ offset + 3 ];
- } else if ( e.stack ) {
- // Firefox, Chrome
- stack = e.stack.split( "\n" );
- if (/^error$/i.test( stack[0] ) ) {
- stack.shift();
- }
- if ( fileName ) {
- include = [];
- for ( i = offset; i < stack.length; i++ ) {
- if ( stack[ i ].indexOf( fileName ) !== -1 ) {
- break;
- }
- include.push( stack[ i ] );
- }
- if ( include.length ) {
- return include.join( "\n" );
- }
- }
- return stack[ offset ];
- } else if ( e.sourceURL ) {
- // Safari, PhantomJS
- // hopefully one day Safari provides actual stacktraces
- // exclude useless self-reference for generated Error objects
- if ( /qunit.js$/.test( e.sourceURL ) ) {
- return;
- }
- // for actual exceptions, this is useful
- return e.sourceURL + ":" + e.line;
- }
-}
-function sourceFromStacktrace( offset ) {
- try {
- throw new Error();
- } catch ( e ) {
- return extractStacktrace( e, offset );
- }
-}
-
-/**
- * Escape text for attribute or text content.
- */
-function escapeText( s ) {
- if ( !s ) {
- return "";
- }
- s = s + "";
- // Both single quotes and double quotes (for attributes)
- return s.replace( /['"<>&]/g, function( s ) {
- switch( s ) {
- case '\'':
- return ''';
- case '"':
- return '"';
- case '<':
- return '<';
- case '>':
- return '>';
- case '&':
- return '&';
- }
- });
-}
-
-function synchronize( callback, last ) {
- config.queue.push( callback );
-
- if ( config.autorun && !config.blocking ) {
- process( last );
- }
-}
-
-function process( last ) {
- function next() {
- process( last );
- }
- var start = new Date().getTime();
- config.depth = config.depth ? config.depth + 1 : 1;
-
- while ( config.queue.length && !config.blocking ) {
- if ( !defined.setTimeout || config.updateRate <= 0 || ( ( new Date().getTime() - start ) < config.updateRate ) ) {
- config.queue.shift()();
- } else {
- window.setTimeout( next, 13 );
- break;
- }
- }
- config.depth--;
- if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) {
- done();
- }
-}
-
-function saveGlobal() {
- config.pollution = [];
-
- if ( config.noglobals ) {
- for ( var key in window ) {
- // in Opera sometimes DOM element ids show up here, ignore them
- if ( !hasOwn.call( window, key ) || /^qunit-test-output/.test( key ) ) {
- continue;
- }
- config.pollution.push( key );
- }
- }
-}
-
-function checkPollution() {
- var newGlobals,
- deletedGlobals,
- old = config.pollution;
-
- saveGlobal();
-
- newGlobals = diff( config.pollution, old );
- if ( newGlobals.length > 0 ) {
- QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join(", ") );
- }
-
- deletedGlobals = diff( old, config.pollution );
- if ( deletedGlobals.length > 0 ) {
- QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join(", ") );
- }
-}
-
-// returns a new Array with the elements that are in a but not in b
-function diff( a, b ) {
- var i, j,
- result = a.slice();
-
- for ( i = 0; i < result.length; i++ ) {
- for ( j = 0; j < b.length; j++ ) {
- if ( result[i] === b[j] ) {
- result.splice( i, 1 );
- i--;
- break;
- }
- }
- }
- return result;
-}
-
-function extend( a, b ) {
- for ( var prop in b ) {
- if ( b[ prop ] === undefined ) {
- delete a[ prop ];
-
- // Avoid "Member not found" error in IE8 caused by setting window.constructor
- } else if ( prop !== "constructor" || a !== window ) {
- a[ prop ] = b[ prop ];
- }
- }
-
- return a;
-}
-
-/**
- * @param {HTMLElement} elem
- * @param {string} type
- * @param {Function} fn
- */
-function addEvent( elem, type, fn ) {
- // Standards-based browsers
- if ( elem.addEventListener ) {
- elem.addEventListener( type, fn, false );
- // IE
- } else {
- elem.attachEvent( "on" + type, fn );
- }
-}
-
-/**
- * @param {Array|NodeList} elems
- * @param {string} type
- * @param {Function} fn
- */
-function addEvents( elems, type, fn ) {
- var i = elems.length;
- while ( i-- ) {
- addEvent( elems[i], type, fn );
- }
-}
-
-function hasClass( elem, name ) {
- return (" " + elem.className + " ").indexOf(" " + name + " ") > -1;
-}
-
-function addClass( elem, name ) {
- if ( !hasClass( elem, name ) ) {
- elem.className += (elem.className ? " " : "") + name;
- }
-}
-
-function removeClass( elem, name ) {
- var set = " " + elem.className + " ";
- // Class name may appear multiple times
- while ( set.indexOf(" " + name + " ") > -1 ) {
- set = set.replace(" " + name + " " , " ");
- }
- // If possible, trim it for prettiness, but not neccecarily
- elem.className = window.jQuery ? jQuery.trim( set ) : ( set.trim ? set.trim() : set );
-}
-
-function id( name ) {
- return !!( typeof document !== "undefined" && document && document.getElementById ) &&
- document.getElementById( name );
-}
-
-function registerLoggingCallback( key ) {
- return function( callback ) {
- config[key].push( callback );
- };
-}
-
-// Supports deprecated method of completely overwriting logging callbacks
-function runLoggingCallbacks( key, scope, args ) {
- var i, callbacks;
- if ( QUnit.hasOwnProperty( key ) ) {
- QUnit[ key ].call(scope, args );
- } else {
- callbacks = config[ key ];
- for ( i = 0; i < callbacks.length; i++ ) {
- callbacks[ i ].call( scope, args );
- }
- }
-}
-
-// Test for equality any JavaScript type.
-// Author: Philippe Rathé
-QUnit.equiv = (function() {
-
- // Call the o related callback with the given arguments.
- function bindCallbacks( o, callbacks, args ) {
- var prop = QUnit.objectType( o );
- if ( prop ) {
- if ( QUnit.objectType( callbacks[ prop ] ) === "function" ) {
- return callbacks[ prop ].apply( callbacks, args );
- } else {
- return callbacks[ prop ]; // or undefined
- }
- }
- }
-
- // the real equiv function
- var innerEquiv,
- // stack to decide between skip/abort functions
- callers = [],
- // stack to avoiding loops from circular referencing
- parents = [],
-
- getProto = Object.getPrototypeOf || function ( obj ) {
- return obj.__proto__;
- },
- callbacks = (function () {
-
- // for string, boolean, number and null
- function useStrictEquality( b, a ) {
- /*jshint eqeqeq:false */
- if ( b instanceof a.constructor || a instanceof b.constructor ) {
- // to catch short annotaion VS 'new' annotation of a
- // declaration
- // e.g. var i = 1;
- // var j = new Number(1);
- return a == b;
- } else {
- return a === b;
- }
- }
-
- return {
- "string": useStrictEquality,
- "boolean": useStrictEquality,
- "number": useStrictEquality,
- "null": useStrictEquality,
- "undefined": useStrictEquality,
-
- "nan": function( b ) {
- return isNaN( b );
- },
-
- "date": function( b, a ) {
- return QUnit.objectType( b ) === "date" && a.valueOf() === b.valueOf();
- },
-
- "regexp": function( b, a ) {
- return QUnit.objectType( b ) === "regexp" &&
- // the regex itself
- a.source === b.source &&
- // and its modifers
- a.global === b.global &&
- // (gmi) ...
- a.ignoreCase === b.ignoreCase &&
- a.multiline === b.multiline &&
- a.sticky === b.sticky;
- },
-
- // - skip when the property is a method of an instance (OOP)
- // - abort otherwise,
- // initial === would have catch identical references anyway
- "function": function() {
- var caller = callers[callers.length - 1];
- return caller !== Object && typeof caller !== "undefined";
- },
-
- "array": function( b, a ) {
- var i, j, len, loop;
-
- // b could be an object literal here
- if ( QUnit.objectType( b ) !== "array" ) {
- return false;
- }
-
- len = a.length;
- if ( len !== b.length ) {
- // safe and faster
- return false;
- }
-
- // track reference to avoid circular references
- parents.push( a );
- for ( i = 0; i < len; i++ ) {
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- loop = true;// dont rewalk array
- }
- }
- if ( !loop && !innerEquiv(a[i], b[i]) ) {
- parents.pop();
- return false;
- }
- }
- parents.pop();
- return true;
- },
-
- "object": function( b, a ) {
- var i, j, loop,
- // Default to true
- eq = true,
- aProperties = [],
- bProperties = [];
-
- // comparing constructors is more strict than using
- // instanceof
- if ( a.constructor !== b.constructor ) {
- // Allow objects with no prototype to be equivalent to
- // objects with Object as their constructor.
- if ( !(( getProto(a) === null && getProto(b) === Object.prototype ) ||
- ( getProto(b) === null && getProto(a) === Object.prototype ) ) ) {
- return false;
- }
- }
-
- // stack constructor before traversing properties
- callers.push( a.constructor );
- // track reference to avoid circular references
- parents.push( a );
-
- for ( i in a ) { // be strict: don't ensures hasOwnProperty
- // and go deep
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- // don't go down the same path twice
- loop = true;
- }
- }
- aProperties.push(i); // collect a's properties
-
- if (!loop && !innerEquiv( a[i], b[i] ) ) {
- eq = false;
- break;
- }
- }
-
- callers.pop(); // unstack, we are done
- parents.pop();
-
- for ( i in b ) {
- bProperties.push( i ); // collect b's properties
- }
-
- // Ensures identical properties name
- return eq && innerEquiv( aProperties.sort(), bProperties.sort() );
- }
- };
- }());
-
- innerEquiv = function() { // can take multiple arguments
- var args = [].slice.apply( arguments );
- if ( args.length < 2 ) {
- return true; // end transition
- }
-
- return (function( a, b ) {
- if ( a === b ) {
- return true; // catch the most you can
- } else if ( a === null || b === null || typeof a === "undefined" ||
- typeof b === "undefined" ||
- QUnit.objectType(a) !== QUnit.objectType(b) ) {
- return false; // don't lose time with error prone cases
- } else {
- return bindCallbacks(a, callbacks, [ b, a ]);
- }
-
- // apply transition with (1..n) arguments
- }( args[0], args[1] ) && arguments.callee.apply( this, args.splice(1, args.length - 1 )) );
- };
-
- return innerEquiv;
-}());
-
-/**
- * jsDump Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com |
- * http://flesler.blogspot.com Licensed under BSD
- * (http://www.opensource.org/licenses/bsd-license.php) Date: 5/15/2008
- *
- * @projectDescription Advanced and extensible data dumping for Javascript.
- * @version 1.0.0
- * @author Ariel Flesler
- * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html}
- */
-QUnit.jsDump = (function() {
- function quote( str ) {
- return '"' + str.toString().replace( /"/g, '\\"' ) + '"';
- }
- function literal( o ) {
- return o + "";
- }
- function join( pre, arr, post ) {
- var s = jsDump.separator(),
- base = jsDump.indent(),
- inner = jsDump.indent(1);
- if ( arr.join ) {
- arr = arr.join( "," + s + inner );
- }
- if ( !arr ) {
- return pre + post;
- }
- return [ pre, inner + arr, base + post ].join(s);
- }
- function array( arr, stack ) {
- var i = arr.length, ret = new Array(i);
- this.up();
- while ( i-- ) {
- ret[i] = this.parse( arr[i] , undefined , stack);
- }
- this.down();
- return join( "[", ret, "]" );
- }
-
- var reName = /^function (\w+)/,
- jsDump = {
- // type is used mostly internally, you can fix a (custom)type in advance
- parse: function( obj, type, stack ) {
- stack = stack || [ ];
- var inStack, res,
- parser = this.parsers[ type || this.typeOf(obj) ];
-
- type = typeof parser;
- inStack = inArray( obj, stack );
-
- if ( inStack !== -1 ) {
- return "recursion(" + (inStack - stack.length) + ")";
- }
- if ( type === "function" ) {
- stack.push( obj );
- res = parser.call( this, obj, stack );
- stack.pop();
- return res;
- }
- return ( type === "string" ) ? parser : this.parsers.error;
- },
- typeOf: function( obj ) {
- var type;
- if ( obj === null ) {
- type = "null";
- } else if ( typeof obj === "undefined" ) {
- type = "undefined";
- } else if ( QUnit.is( "regexp", obj) ) {
- type = "regexp";
- } else if ( QUnit.is( "date", obj) ) {
- type = "date";
- } else if ( QUnit.is( "function", obj) ) {
- type = "function";
- } else if ( typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined" ) {
- type = "window";
- } else if ( obj.nodeType === 9 ) {
- type = "document";
- } else if ( obj.nodeType ) {
- type = "node";
- } else if (
- // native arrays
- toString.call( obj ) === "[object Array]" ||
- // NodeList objects
- ( typeof obj.length === "number" && typeof obj.item !== "undefined" && ( obj.length ? obj.item(0) === obj[0] : ( obj.item( 0 ) === null && typeof obj[0] === "undefined" ) ) )
- ) {
- type = "array";
- } else if ( obj.constructor === Error.prototype.constructor ) {
- type = "error";
- } else {
- type = typeof obj;
- }
- return type;
- },
- separator: function() {
- return this.multiline ? this.HTML ? "
" : "\n" : this.HTML ? " " : " ";
- },
- // extra can be a number, shortcut for increasing-calling-decreasing
- indent: function( extra ) {
- if ( !this.multiline ) {
- return "";
- }
- var chr = this.indentChar;
- if ( this.HTML ) {
- chr = chr.replace( /\t/g, " " ).replace( / /g, " " );
- }
- return new Array( this._depth_ + (extra||0) ).join(chr);
- },
- up: function( a ) {
- this._depth_ += a || 1;
- },
- down: function( a ) {
- this._depth_ -= a || 1;
- },
- setParser: function( name, parser ) {
- this.parsers[name] = parser;
- },
- // The next 3 are exposed so you can use them
- quote: quote,
- literal: literal,
- join: join,
- //
- _depth_: 1,
- // This is the list of parsers, to modify them, use jsDump.setParser
- parsers: {
- window: "[Window]",
- document: "[Document]",
- error: function(error) {
- return "Error(\"" + error.message + "\")";
- },
- unknown: "[Unknown]",
- "null": "null",
- "undefined": "undefined",
- "function": function( fn ) {
- var ret = "function",
- // functions never have name in IE
- name = "name" in fn ? fn.name : (reName.exec(fn) || [])[1];
-
- if ( name ) {
- ret += " " + name;
- }
- ret += "( ";
-
- ret = [ ret, QUnit.jsDump.parse( fn, "functionArgs" ), "){" ].join( "" );
- return join( ret, QUnit.jsDump.parse(fn,"functionCode" ), "}" );
- },
- array: array,
- nodelist: array,
- "arguments": array,
- object: function( map, stack ) {
- var ret = [ ], keys, key, val, i;
- QUnit.jsDump.up();
- keys = [];
- for ( key in map ) {
- keys.push( key );
- }
- keys.sort();
- for ( i = 0; i < keys.length; i++ ) {
- key = keys[ i ];
- val = map[ key ];
- ret.push( QUnit.jsDump.parse( key, "key" ) + ": " + QUnit.jsDump.parse( val, undefined, stack ) );
- }
- QUnit.jsDump.down();
- return join( "{", ret, "}" );
- },
- node: function( node ) {
- var len, i, val,
- open = QUnit.jsDump.HTML ? "<" : "<",
- close = QUnit.jsDump.HTML ? ">" : ">",
- tag = node.nodeName.toLowerCase(),
- ret = open + tag,
- attrs = node.attributes;
-
- if ( attrs ) {
- for ( i = 0, len = attrs.length; i < len; i++ ) {
- val = attrs[i].nodeValue;
- // IE6 includes all attributes in .attributes, even ones not explicitly set.
- // Those have values like undefined, null, 0, false, "" or "inherit".
- if ( val && val !== "inherit" ) {
- ret += " " + attrs[i].nodeName + "=" + QUnit.jsDump.parse( val, "attribute" );
- }
- }
- }
- ret += close;
-
- // Show content of TextNode or CDATASection
- if ( node.nodeType === 3 || node.nodeType === 4 ) {
- ret += node.nodeValue;
- }
-
- return ret + open + "/" + tag + close;
- },
- // function calls it internally, it's the arguments part of the function
- functionArgs: function( fn ) {
- var args,
- l = fn.length;
-
- if ( !l ) {
- return "";
- }
-
- args = new Array(l);
- while ( l-- ) {
- // 97 is 'a'
- args[l] = String.fromCharCode(97+l);
- }
- return " " + args.join( ", " ) + " ";
- },
- // object calls it internally, the key part of an item in a map
- key: quote,
- // function calls it internally, it's the content of the function
- functionCode: "[code]",
- // node calls it internally, it's an html attribute value
- attribute: quote,
- string: quote,
- date: quote,
- regexp: literal,
- number: literal,
- "boolean": literal
- },
- // if true, entities are escaped ( <, >, \t, space and \n )
- HTML: false,
- // indentation unit
- indentChar: " ",
- // if true, items in a collection, are separated by a \n, else just a space.
- multiline: true
- };
-
- return jsDump;
-}());
-
-// from jquery.js
-function inArray( elem, array ) {
- if ( array.indexOf ) {
- return array.indexOf( elem );
- }
-
- for ( var i = 0, length = array.length; i < length; i++ ) {
- if ( array[ i ] === elem ) {
- return i;
- }
- }
-
- return -1;
-}
-
-/*
- * Javascript Diff Algorithm
- * By John Resig (http://ejohn.org/)
- * Modified by Chu Alan "sprite"
- *
- * Released under the MIT license.
- *
- * More Info:
- * http://ejohn.org/projects/javascript-diff-algorithm/
- *
- * Usage: QUnit.diff(expected, actual)
- *
- * QUnit.diff( "the quick brown fox jumped over", "the quick fox jumps over" ) == "the quick brown fox jumped jumps over"
- */
-QUnit.diff = (function() {
- /*jshint eqeqeq:false, eqnull:true */
- function diff( o, n ) {
- var i,
- ns = {},
- os = {};
-
- for ( i = 0; i < n.length; i++ ) {
- if ( !hasOwn.call( ns, n[i] ) ) {
- ns[ n[i] ] = {
- rows: [],
- o: null
- };
- }
- ns[ n[i] ].rows.push( i );
- }
-
- for ( i = 0; i < o.length; i++ ) {
- if ( !hasOwn.call( os, o[i] ) ) {
- os[ o[i] ] = {
- rows: [],
- n: null
- };
- }
- os[ o[i] ].rows.push( i );
- }
-
- for ( i in ns ) {
- if ( !hasOwn.call( ns, i ) ) {
- continue;
- }
- if ( ns[i].rows.length === 1 && hasOwn.call( os, i ) && os[i].rows.length === 1 ) {
- n[ ns[i].rows[0] ] = {
- text: n[ ns[i].rows[0] ],
- row: os[i].rows[0]
- };
- o[ os[i].rows[0] ] = {
- text: o[ os[i].rows[0] ],
- row: ns[i].rows[0]
- };
- }
- }
-
- for ( i = 0; i < n.length - 1; i++ ) {
- if ( n[i].text != null && n[ i + 1 ].text == null && n[i].row + 1 < o.length && o[ n[i].row + 1 ].text == null &&
- n[ i + 1 ] == o[ n[i].row + 1 ] ) {
-
- n[ i + 1 ] = {
- text: n[ i + 1 ],
- row: n[i].row + 1
- };
- o[ n[i].row + 1 ] = {
- text: o[ n[i].row + 1 ],
- row: i + 1
- };
- }
- }
-
- for ( i = n.length - 1; i > 0; i-- ) {
- if ( n[i].text != null && n[ i - 1 ].text == null && n[i].row > 0 && o[ n[i].row - 1 ].text == null &&
- n[ i - 1 ] == o[ n[i].row - 1 ]) {
-
- n[ i - 1 ] = {
- text: n[ i - 1 ],
- row: n[i].row - 1
- };
- o[ n[i].row - 1 ] = {
- text: o[ n[i].row - 1 ],
- row: i - 1
- };
- }
- }
-
- return {
- o: o,
- n: n
- };
- }
-
- return function( o, n ) {
- o = o.replace( /\s+$/, "" );
- n = n.replace( /\s+$/, "" );
-
- var i, pre,
- str = "",
- out = diff( o === "" ? [] : o.split(/\s+/), n === "" ? [] : n.split(/\s+/) ),
- oSpace = o.match(/\s+/g),
- nSpace = n.match(/\s+/g);
-
- if ( oSpace == null ) {
- oSpace = [ " " ];
- }
- else {
- oSpace.push( " " );
- }
-
- if ( nSpace == null ) {
- nSpace = [ " " ];
- }
- else {
- nSpace.push( " " );
- }
-
- if ( out.n.length === 0 ) {
- for ( i = 0; i < out.o.length; i++ ) {
- str += "" + out.o[i] + oSpace[i] + "";
- }
- }
- else {
- if ( out.n[0].text == null ) {
- for ( n = 0; n < out.o.length && out.o[n].text == null; n++ ) {
- str += "" + out.o[n] + oSpace[n] + "";
- }
- }
-
- for ( i = 0; i < out.n.length; i++ ) {
- if (out.n[i].text == null) {
- str += "" + out.n[i] + nSpace[i] + "";
- }
- else {
- // `pre` initialized at top of scope
- pre = "";
-
- for ( n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++ ) {
- pre += "" + out.o[n] + oSpace[n] + "";
- }
- str += " " + out.n[i].text + nSpace[i] + pre;
- }
- }
- }
-
- return str;
- };
-}());
-
-// for CommonJS enviroments, export everything
-if ( typeof exports !== "undefined" ) {
- extend( exports, QUnit );
-}
-
-// get at whatever the global object is, like window in browsers
-}( (function() {return this;}.call()) ));
diff --git a/test/lib/require.js b/test/lib/require.js
deleted file mode 100644
index 987f865..0000000
--- a/test/lib/require.js
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- RequireJS 2.1.5 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.
- Available via the MIT or new BSD license.
- see: http://github.com/jrburke/requirejs for details
-*/
-var requirejs,require,define;
-(function(aa){function I(b){return"[object Function]"===L.call(b)}function J(b){return"[object Array]"===L.call(b)}function y(b,c){if(b){var d;for(d=0;dthis.depCount&&!this.defined){if(I(n)){if(this.events.error)try{e=i.execCb(c,n,b,e)}catch(d){a=d}else e=i.execCb(c,n,b,e);this.map.isDefine&&((b=this.module)&&void 0!==b.exports&&b.exports!==this.exports?e=b.exports:void 0===e&&this.usingExports&&(e=this.exports));if(a)return a.requireMap=this.map,a.requireModules=[this.map.id],a.requireType="define",v(this.error=
-a)}else e=n;this.exports=e;if(this.map.isDefine&&!this.ignore&&(q[c]=e,l.onResourceLoad))l.onResourceLoad(i,this.map,this.depMaps);x(c);this.defined=!0}this.defining=!1;this.defined&&!this.defineEmitted&&(this.defineEmitted=!0,this.emit("defined",this.exports),this.defineEmitComplete=!0)}}else this.fetch()}},callPlugin:function(){var a=this.map,b=a.id,d=j(a.prefix);this.depMaps.push(d);t(d,"defined",u(this,function(e){var n,d;d=this.map.name;var g=this.map.parentMap?this.map.parentMap.name:null,h=
-i.makeRequire(a.parentMap,{enableBuildCallback:!0});if(this.map.unnormalized){if(e.normalize&&(d=e.normalize(d,function(a){return c(a,g,!0)})||""),e=j(a.prefix+"!"+d,this.map.parentMap),t(e,"defined",u(this,function(a){this.init([],function(){return a},null,{enabled:!0,ignore:!0})})),d=m(p,e.id)){this.depMaps.push(e);if(this.events.error)d.on("error",u(this,function(a){this.emit("error",a)}));d.enable()}}else n=u(this,function(a){this.init([],function(){return a},null,{enabled:!0})}),n.error=u(this,
-function(a){this.inited=!0;this.error=a;a.requireModules=[b];G(p,function(a){0===a.map.id.indexOf(b+"_unnormalized")&&x(a.map.id)});v(a)}),n.fromText=u(this,function(e,c){var d=a.name,g=j(d),C=O;c&&(e=c);C&&(O=!1);r(g);s(k.config,b)&&(k.config[d]=k.config[b]);try{l.exec(e)}catch(ca){return v(B("fromtexteval","fromText eval for "+b+" failed: "+ca,ca,[b]))}C&&(O=!0);this.depMaps.push(g);i.completeLoad(d);h([d],n)}),e.load(a.name,h,n,k)}));i.enable(d,this);this.pluginMaps[d.id]=d},enable:function(){V[this.map.id]=
-this;this.enabling=this.enabled=!0;y(this.depMaps,u(this,function(a,b){var c,e;if("string"===typeof a){a=j(a,this.map.isDefine?this.map:this.map.parentMap,!1,!this.skipMap);this.depMaps[b]=a;if(c=m(N,a.id)){this.depExports[b]=c(this);return}this.depCount+=1;t(a,"defined",u(this,function(a){this.defineDep(b,a);this.check()}));this.errback&&t(a,"error",this.errback)}c=a.id;e=p[c];!s(N,c)&&(e&&!e.enabled)&&i.enable(a,this)}));G(this.pluginMaps,u(this,function(a){var b=m(p,a.id);b&&!b.enabled&&i.enable(a,
-this)}));this.enabling=!1;this.check()},on:function(a,b){var c=this.events[a];c||(c=this.events[a]=[]);c.push(b)},emit:function(a,b){y(this.events[a],function(a){a(b)});"error"===a&&delete this.events[a]}};i={config:k,contextName:b,registry:p,defined:q,urlFetched:U,defQueue:H,Module:Z,makeModuleMap:j,nextTick:l.nextTick,onError:v,configure:function(a){a.baseUrl&&"/"!==a.baseUrl.charAt(a.baseUrl.length-1)&&(a.baseUrl+="/");var b=k.pkgs,c=k.shim,e={paths:!0,config:!0,map:!0};G(a,function(a,b){e[b]?
-"map"===b?(k.map||(k.map={}),R(k[b],a,!0,!0)):R(k[b],a,!0):k[b]=a});a.shim&&(G(a.shim,function(a,b){J(a)&&(a={deps:a});if((a.exports||a.init)&&!a.exportsFn)a.exportsFn=i.makeShimExports(a);c[b]=a}),k.shim=c);a.packages&&(y(a.packages,function(a){a="string"===typeof a?{name:a}:a;b[a.name]={name:a.name,location:a.location||a.name,main:(a.main||"main").replace(ja,"").replace(ea,"")}}),k.pkgs=b);G(p,function(a,b){!a.inited&&!a.map.unnormalized&&(a.map=j(b))});if(a.deps||a.callback)i.require(a.deps||[],
-a.callback)},makeShimExports:function(a){return function(){var b;a.init&&(b=a.init.apply(aa,arguments));return b||a.exports&&ba(a.exports)}},makeRequire:function(a,f){function d(e,c,h){var g,k;f.enableBuildCallback&&(c&&I(c))&&(c.__requireJsBuild=!0);if("string"===typeof e){if(I(c))return v(B("requireargs","Invalid require call"),h);if(a&&s(N,e))return N[e](p[a.id]);if(l.get)return l.get(i,e,a,d);g=j(e,a,!1,!0);g=g.id;return!s(q,g)?v(B("notloaded",'Module name "'+g+'" has not been loaded yet for context: '+
-b+(a?"":". Use require([])"))):q[g]}L();i.nextTick(function(){L();k=r(j(null,a));k.skipMap=f.skipMap;k.init(e,c,h,{enabled:!0});D()});return d}f=f||{};R(d,{isBrowser:A,toUrl:function(b){var d,f=b.lastIndexOf("."),g=b.split("/")[0];if(-1!==f&&(!("."===g||".."===g)||1h.attachEvent.toString().indexOf("[native code"))&&!Y?(O=!0,h.attachEvent("onreadystatechange",b.onScriptLoad)):(h.addEventListener("load",b.onScriptLoad,!1),h.addEventListener("error",b.onScriptError,!1)),h.src=d,K=h,D?x.insertBefore(h,D):x.appendChild(h),K=null,h;if(da)try{importScripts(d),b.completeLoad(c)}catch(j){b.onError(B("importscripts","importScripts failed for "+c+" at "+d,j,[c]))}};A&&M(document.getElementsByTagName("script"),function(b){x||(x=
-b.parentNode);if(t=b.getAttribute("data-main"))return r.baseUrl||(E=t.split("/"),Q=E.pop(),fa=E.length?E.join("/")+"/":"./",r.baseUrl=fa,t=Q),t=t.replace(ea,""),r.deps=r.deps?r.deps.concat(t):[t],!0});define=function(b,c,d){var l,h;"string"!==typeof b&&(d=c,c=b,b=null);J(c)||(d=c,c=[]);!c.length&&I(d)&&d.length&&(d.toString().replace(la,"").replace(ma,function(b,d){c.push(d)}),c=(1===d.length?["require"]:["require","exports","module"]).concat(c));if(O){if(!(l=K))P&&"interactive"===P.readyState||M(document.getElementsByTagName("script"),
-function(b){if("interactive"===b.readyState)return P=b}),l=P;l&&(b||(b=l.getAttribute("data-requiremodule")),h=F[l.getAttribute("data-requirecontext")])}(h?h.defQueue:T).push([b,c,d])};define.amd={jQuery:!0};l.exec=function(b){return eval(b)};l(r)}})(this);
diff --git a/test/lib/resemble.js b/test/lib/resemble.js
new file mode 100644
index 0000000..1cb8c29
--- /dev/null
+++ b/test/lib/resemble.js
@@ -0,0 +1,535 @@
+/*
+Author: James Cryer
+Company: Huddle
+Last updated date: 21 Feb 2013
+URL: https://github.com/Huddle/Resemble.js
+*/
+
+(function(_this){
+ 'use strict';
+
+ _this['resemble'] = function( fileData ){
+
+ var data = {};
+ var images = [];
+ var updateCallbackArray = [];
+
+ var tolerance = { // between 0 and 255
+ red: 16,
+ green: 16,
+ blue: 16,
+ minBrightness: 16,
+ maxBrightness: 240
+ };
+
+ var ignoreAntialiasing = false;
+ var ignoreColors = false;
+
+ function triggerDataUpdate(){
+ var len = updateCallbackArray.length;
+ var i;
+ for(i=0;i tolerance.maxBrightness;
+ }
+
+ function getHue(r,g,b){
+
+ r = r / 255;
+ g = g / 255;
+ b = b / 255;
+ var max = Math.max(r, g, b), min = Math.min(r, g, b);
+ var h;
+ var d;
+
+ if (max == min){
+ h = 0; // achromatic
+ } else{
+ d = max - min;
+ switch(max){
+ case r: h = (g - b) / d + (g < b ? 6 : 0); break;
+ case g: h = (b - r) / d + 2; break;
+ case b: h = (r - g) / d + 4; break;
+ }
+ h /= 6;
+ }
+
+ return h;
+ }
+
+ function isAntialiased(sourcePix, data, cacheSet, verticalPos, horizontalPos, width){
+ var offset;
+ var targetPix;
+ var distance = 1;
+ var i;
+ var j;
+ var hasHighContrastSibling = 0;
+ var hasSiblingWithDifferentHue = 0;
+ var hasEquivilantSibling = 0;
+
+ addHueInfo(sourcePix);
+
+ for (i = distance*-1; i <= distance; i++){
+ for (j = distance*-1; j <= distance; j++){
+
+ if(i===0 && j===0){
+ // ignore source pixel
+ } else {
+
+ offset = ((verticalPos+j)*width + (horizontalPos+i)) * 4;
+ targetPix = getPixelInfo(data, offset, cacheSet);
+
+ if(targetPix === null){
+ continue;
+ }
+
+ addBrightnessInfo(targetPix);
+ addHueInfo(targetPix);
+
+ if( isContrasting(sourcePix, targetPix) ){
+ hasHighContrastSibling++;
+ }
+
+ if( isRGBSame(sourcePix,targetPix) ){
+ hasEquivilantSibling++;
+ }
+
+ if( Math.abs(targetPix.h - sourcePix.h) > 0.3 ){
+ hasSiblingWithDifferentHue++;
+ }
+
+ if( hasSiblingWithDifferentHue > 1 || hasHighContrastSibling > 1){
+ return true;
+ }
+ }
+ }
+ }
+
+ if(hasEquivilantSibling < 2){
+ return true;
+ }
+
+ return false;
+ }
+
+ function errorPixel(px, offset){
+ px[offset] = 255; //r
+ px[offset + 1] = 0; //g
+ px[offset + 2] = 255; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyPixel(px, offset, data){
+ px[offset] = data.r; //r
+ px[offset + 1] = data.g; //g
+ px[offset + 2] = data.b; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyGrayScalePixel(px, offset, data){
+ px[offset] = data.brightness; //r
+ px[offset + 1] = data.brightness; //g
+ px[offset + 2] = data.brightness; //b
+ px[offset + 3] = 255; //a
+ }
+
+
+ function getPixelInfo(data, offset, cacheSet){
+ var r;
+ var g;
+ var b;
+ var d;
+
+ if(typeof data[offset] !== 'undefined'){
+ r = data[offset];
+ g = data[offset+1];
+ b = data[offset+2];
+ d = {
+ r: r,
+ g: g,
+ b: b
+ };
+
+ return d;
+ } else {
+ return null;
+ }
+ }
+
+ function addBrightnessInfo(data){
+ data.brightness = getBrightness(data.r,data.g,data.b); // 'corrected' lightness
+ }
+
+ function addHueInfo(data){
+ data.h = getHue(data.r,data.g,data.b);
+ }
+
+ function analyseImages(img1, img2, width, height){
+
+ var hiddenCanvas = document.createElement('canvas');
+
+ var data1 = img1.data;
+ var data2 = img2.data;
+
+ hiddenCanvas.width = width;
+ hiddenCanvas.height = height;
+
+ var context = hiddenCanvas.getContext('2d');
+ var imgd = context.createImageData(width,height);
+ var targetPix = imgd.data;
+
+ var mismatchCount = 0;
+
+ var time = Date.now();
+
+ var skip;
+
+ if( (width > 1200 || height > 1200) && ignoreAntialiasing){
+ skip = 6;
+ }
+
+ loop(height, width, function(verticalPos, horizontalPos){
+
+ if(skip){ // only skip if the image isn't small
+ if(verticalPos % skip === 0 || horizontalPos % skip === 0){
+ return;
+ }
+ }
+
+ var offset = (verticalPos*width + horizontalPos) * 4;
+ var pixel1 = getPixelInfo(data1, offset, 1);
+ var pixel2 = getPixelInfo(data2, offset, 2);
+
+ if(pixel1 === null || pixel2 === null){
+ return;
+ }
+
+ if (ignoreColors){
+
+ addBrightnessInfo(pixel1);
+ addBrightnessInfo(pixel2);
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ return;
+ }
+
+ if( isRGBSimilar(pixel1, pixel2) ){
+ copyPixel(targetPix, offset, pixel2);
+
+ } else if( ignoreAntialiasing && (
+ addBrightnessInfo(pixel1), // jit pixel info augmentation looks a little weird, sorry.
+ addBrightnessInfo(pixel2),
+ isAntialiased(pixel1, data1, 1, verticalPos, horizontalPos, width) ||
+ isAntialiased(pixel2, data2, 2, verticalPos, horizontalPos, width)
+ )){
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+
+ });
+
+ data.misMatchPercentage = (mismatchCount / (height*width) * 100).toFixed(2);
+ data.analysisTime = Date.now() - time;
+
+ data.getImageDataUrl = function(text){
+ var barHeight = 0;
+
+ if(text){
+ barHeight = addLabel(text,context,hiddenCanvas);
+ }
+
+ context.putImageData(imgd, 0, barHeight);
+
+ return hiddenCanvas.toDataURL("image/png");
+ };
+ }
+
+ function addLabel(text, context, hiddenCanvas){
+ var textPadding = 2;
+
+ context.font = '12px sans-serif';
+
+ var textWidth = context.measureText(text).width + textPadding*2;
+ var barHeight = 22;
+
+ if(textWidth > hiddenCanvas.width){
+ hiddenCanvas.width = textWidth;
+ }
+
+ hiddenCanvas.height += barHeight;
+
+ context.fillStyle = "#666";
+ context.fillRect(0,0,hiddenCanvas.width,barHeight -4);
+ context.fillStyle = "#fff";
+ context.fillRect(0,barHeight -4,hiddenCanvas.width, 4);
+
+ context.fillStyle = "#fff";
+ context.textBaseline = "top";
+ context.font = '12px sans-serif';
+ context.fillText(text, textPadding, 1);
+
+ return barHeight;
+ }
+
+ function normalise(img, w, h){
+ var c;
+ var context;
+
+ if(img.height < h || img.width < w){
+ c = document.createElement('canvas');
+ c.width = w;
+ c.height = h;
+ context = c.getContext('2d');
+ context.putImageData(img, 0, 0);
+ return context.getImageData(0, 0, w, h);
+ }
+
+ return img;
+ }
+
+ function compare(one, two){
+
+ function onceWeHaveBoth(){
+ var width;
+ var height;
+ if(images.length === 2){
+ width = images[0].width > images[1].width ? images[0].width : images[1].width;
+ height = images[0].height > images[1].height ? images[0].height : images[1].height;
+
+ if( (images[0].width === images[1].width) && (images[0].height === images[1].height) ){
+ data.isSameDimensions = true;
+ } else {
+ data.isSameDimensions = false;
+ }
+
+ analyseImages( normalise(images[0],width, height), normalise(images[1],width, height), width, height);
+
+ triggerDataUpdate();
+ }
+ }
+
+ images = [];
+ loadImageData(one, onceWeHaveBoth);
+ loadImageData(two, onceWeHaveBoth);
+ }
+
+ function getCompareApi(param){
+
+ var secondFileData,
+ hasMethod = typeof param === 'function';
+
+ if( !hasMethod ){
+ // assume it's file data
+ secondFileData = param;
+ }
+
+ var self = {
+ ignoreNothing: function(){
+
+ tolerance.red = 16;
+ tolerance.green = 16;
+ tolerance.blue = 16;
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreAntialiasing: function(){
+
+ tolerance.red = 32;
+ tolerance.green = 32;
+ tolerance.blue = 32;
+ tolerance.minBrightness = 64;
+ tolerance.maxBrightness = 96;
+
+ ignoreAntialiasing = true;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreColors: function(){
+
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = true;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ onComplete: function( callback ){
+
+ updateCallbackArray.push(callback);
+
+ var wrapper = function(){
+ compare(fileData, secondFileData);
+ };
+
+ wrapper();
+
+ return getCompareApi(wrapper);
+ }
+ };
+
+ return self;
+ }
+
+ return {
+ onComplete: function( callback ){
+ updateCallbackArray.push(callback);
+ loadImageData(fileData, function(imageData, width, height){
+ parseImage(imageData.data, width, height);
+ });
+ },
+ compareTo: function(secondFileData){
+ return getCompareApi(secondFileData);
+ }
+ };
+
+ };
+}(this));
\ No newline at end of file
diff --git a/test/testsuite.js b/test/testsuite.js
deleted file mode 100644
index b486acb..0000000
--- a/test/testsuite.js
+++ /dev/null
@@ -1,36 +0,0 @@
-requirejs.config({
- baseUrl: '/test/unit/'
-});
-
-define(function(require) {
- var testModules = [
- 'Pixi',
- 'Point',
- 'Rectangle',
- 'DisplayObject',
- 'DisplayObjectContainer',
- 'Sprite',
- 'MovieClip',
- 'InteractionManager',
- 'Stage',
- 'utils/Utils',
- 'utils/EventTarget',
- 'utils/Matrix',
- 'utils/Detector',
- 'renderers/WebGLShaders',
- 'renderers/WebGLRenderer',
- 'renderers/WebGLBatch',
- 'renderers/CanvasRenderer',
- 'extras/Strip',
- 'extras/Rope',
- 'textures/BaseTexture',
- 'textures/Texture',
- 'loaders/SpriteSheetLoader',
- 'loaders/AssetLoader'
- ];
-
- // Resolve all testModules and then start the Test Runner.
- require(testModules, function() {
- QUnit.start();
- });
-});
\ No newline at end of file
diff --git a/test/textures/SpriteSheet-Aliens.png b/test/textures/SpriteSheet-Aliens.png
new file mode 100644
index 0000000..210acb1
--- /dev/null
+++ b/test/textures/SpriteSheet-Aliens.png
Binary files differ
diff --git a/test/textures/SpriteSheet-Explosion.png b/test/textures/SpriteSheet-Explosion.png
new file mode 100755
index 0000000..79e1a69
--- /dev/null
+++ b/test/textures/SpriteSheet-Explosion.png
Binary files differ
diff --git a/test/textures/bunny.png b/test/textures/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/textures/bunny.png
Binary files differ
diff --git a/test/unit/DisplayObject.js b/test/unit/DisplayObject.js
deleted file mode 100644
index 5e7e72f..0000000
--- a/test/unit/DisplayObject.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObject');
-});
diff --git a/test/unit/DisplayObjectContainer.js b/test/unit/DisplayObjectContainer.js
deleted file mode 100644
index b323959..0000000
--- a/test/unit/DisplayObjectContainer.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObjectContainer');
-});
diff --git a/test/unit/InteractionManager.js b/test/unit/InteractionManager.js
deleted file mode 100644
index e751f52..0000000
--- a/test/unit/InteractionManager.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('InteractionManager');
-});
diff --git a/test/unit/MovieClip.js b/test/unit/MovieClip.js
deleted file mode 100644
index 37d9446..0000000
--- a/test/unit/MovieClip.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('MovieClip');
-});
diff --git a/test/unit/Pixi.js b/test/unit/Pixi.js
deleted file mode 100644
index 36eee73..0000000
--- a/test/unit/Pixi.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Pixi');
-});
diff --git a/test/unit/Point.js b/test/unit/Point.js
deleted file mode 100644
index 983ff6e..0000000
--- a/test/unit/Point.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Point');
-});
diff --git a/test/unit/Rectangle.js b/test/unit/Rectangle.js
deleted file mode 100644
index 3b439ba..0000000
--- a/test/unit/Rectangle.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Rectangle');
-});
diff --git a/test/unit/Sprite.js b/test/unit/Sprite.js
deleted file mode 100644
index ed4f596..0000000
--- a/test/unit/Sprite.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Sprite');
-});
diff --git a/test/unit/Stage.js b/test/unit/Stage.js
deleted file mode 100644
index 2d70291..0000000
--- a/test/unit/Stage.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Stage');
-});
diff --git a/test/unit/extras/Rope.js b/test/unit/extras/Rope.js
deleted file mode 100644
index 5606f14..0000000
--- a/test/unit/extras/Rope.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Rope');
-});
diff --git a/test/unit/extras/Strip.js b/test/unit/extras/Strip.js
deleted file mode 100644
index 0134d3a..0000000
--- a/test/unit/extras/Strip.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Strip');
-});
diff --git a/test/unit/loaders/AssetLoader.js b/test/unit/loaders/AssetLoader.js
deleted file mode 100644
index 13b8443..0000000
--- a/test/unit/loaders/AssetLoader.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('AssetLoader');
-});
diff --git a/.gitignore b/.gitignore
index 12e1b62..0b88317 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
node_modules
.DS_Store
-.project
\ No newline at end of file
+.project
+*.log
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..63e4d7c
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,8 @@
+language: node_js
+node_js:
+ - 0.10
+
+before_script:
+ - npm install -g grunt-cli
+ - export DISPLAY=:99.0
+ - sh -e /etc/init.d/xvfb start
diff --git a/Gruntfile.js b/Gruntfile.js
index b083b49..103938c 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -1,10 +1,12 @@
+'use strict';
+
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-connect');
- grunt.loadNpmTasks('grunt-contrib-qunit');
grunt.loadNpmTasks('grunt-contrib-yuidoc');
+ grunt.loadTasks('tasks');
var root = 'src/pixi/',
debug = 'bin/pixi.dev.js',
@@ -79,7 +81,7 @@
},
files: {
srcBlob: '<%= dirs.src %>/**/*.js',
- testBlob: '<%= dirs.test %>/unit/**/*.js',
+ testBlob: '<%= dirs.test %>/{functional,lib/pixi,unit}/**/*.js',
build: '<%= dirs.build %>/pixi.dev.js',
buildMin: '<%= dirs.build %>/pixi.js'
},
@@ -94,7 +96,12 @@
},
jshint: {
beforeconcat: srcFiles,
- test: ['<%= files.testBlob %>'],
+ test: {
+ src: ['<%= files.testBlob %>'],
+ options: {
+ expr: true
+ }
+ },
options: {
asi: true,
smarttabs: true
@@ -128,12 +135,6 @@
]
},
connect: {
- qunit: {
- options: {
- port: grunt.option('port-test') || 9002,
- base: './'
- }
- },
test: {
options: {
port: grunt.option('port-test') || 9002,
@@ -142,13 +143,6 @@
}
}
},
- qunit: {
- all: {
- options: {
- urls: ['http://localhost:' + (grunt.option('port-test') || 9002) + '/test/index.html']
- }
- }
- },
yuidoc: {
compile: {
name: '<%= pkg.name %>',
@@ -161,6 +155,13 @@
outdir: '<%= dirs.docs %>'
}
}
+ },
+ karma: {
+ unit: {
+ configFile: 'test/karma.conf.js',
+ // browsers: ['Chrome'],
+ singleRun: true
+ }
}
});
@@ -182,9 +183,10 @@
}
)
- grunt.registerTask('default', ['concat', 'uglify', 'distribute']);
grunt.registerTask('build', ['concat', 'uglify', 'distribute']);
- grunt.registerTask('test', ['build', 'connect:qunit', 'qunit']);
+ grunt.registerTask('test', ['concat', 'jshint:test', 'karma']);
grunt.registerTask('docs', ['yuidoc']);
-
-}
\ No newline at end of file
+ grunt.registerTask('default', ['test', 'uglify', 'distribute']);
+ // Travis CI task.
+ grunt.registerTask('travis', ['test']);
+}
diff --git a/README.md b/README.md
index c62ef86..690cfe4 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,8 @@

+[](http://travis-ci.org/drkibitz/pixi.js)
+
#### JavaScript 2D Renderer ####
The aim of this project is to provide a fast lightweight 2D library that works
diff --git a/package.json b/package.json
index b373240..1246a68 100644
--- a/package.json
+++ b/package.json
@@ -18,14 +18,21 @@
"main": "bin/pixi.js",
+ "scripts": {
+ "test": "grunt travis --verbose"
+ },
+
"dependencies": {},
"devDependencies": {
"grunt": "~0.4.x",
- "grunt-contrib-jshint": "0.3.x",
+ "grunt-contrib-jshint": "0.6.x",
"grunt-contrib-uglify": "0.2.x",
- "grunt-contrib-connect": "0.2.x",
- "grunt-contrib-qunit": "0.2.x",
+ "grunt-contrib-connect": "0.3.x",
"grunt-contrib-yuidoc": "0.4.x",
- "grunt-contrib-concat": "0.1.x"
+ "grunt-contrib-concat": "0.3.x",
+ "chai": "~1.7.0",
+ "karma": "0.11.0",
+ "karma-firefox-launcher": "0.1.0",
+ "karma-mocha": "0.1.0"
}
}
diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js
index a7c520e..ee82bbd 100644
--- a/src/pixi/InteractionManager.js
+++ b/src/pixi/InteractionManager.js
@@ -62,7 +62,6 @@
this.onTouchEnd = this.onTouchEnd.bind(this);
this.onTouchMove = this.onTouchMove.bind(this);
-
this.last = 0;
}
diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js
index 1a95d20..eef1059 100644
--- a/src/pixi/core/Ellipse.js
+++ b/src/pixi/core/Ellipse.js
@@ -78,7 +78,7 @@
return (normx + normy < 0.25);
}
-PIXI.Ellipse.getBounds = function()
+PIXI.Ellipse.prototype.getBounds = function()
{
return new PIXI.Rectangle(this.x, this.y, this.width, this.height);
}
diff --git a/tasks/karma.js b/tasks/karma.js
new file mode 100644
index 0000000..c340485
--- /dev/null
+++ b/tasks/karma.js
@@ -0,0 +1,27 @@
+'use strict';
+
+var path = require('path');
+var server = require('karma').server;
+
+module.exports = function (grunt) {
+ grunt.registerMultiTask('karma', 'run karma.', function() {
+ var done = this.async();
+ var options = this.options({
+ background: false
+ });
+ var data = this.data;
+
+ //merge options onto data, with data taking precedence
+ data = grunt.util._.merge(options, data);
+ data.configFile = path.resolve(data.configFile);
+ if (data.configFile) {
+ data.configFile = grunt.template.process(data.configFile);
+ }
+
+ server.start(
+ data,
+ function(code) {
+ done(!code);
+ });
+ });
+};
diff --git a/test/functional/example-1-basics/bunny.png b/test/functional/example-1-basics/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/functional/example-1-basics/bunny.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-30.png b/test/functional/example-1-basics/frame-30.png
new file mode 100644
index 0000000..96e3409
--- /dev/null
+++ b/test/functional/example-1-basics/frame-30.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-60.png b/test/functional/example-1-basics/frame-60.png
new file mode 100644
index 0000000..af3f4ce
--- /dev/null
+++ b/test/functional/example-1-basics/frame-60.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-90.png b/test/functional/example-1-basics/frame-90.png
new file mode 100644
index 0000000..099b823
--- /dev/null
+++ b/test/functional/example-1-basics/frame-90.png
Binary files differ
diff --git a/test/functional/example-1-basics/index.js b/test/functional/example-1-basics/index.js
new file mode 100644
index 0000000..7ae7a98
--- /dev/null
+++ b/test/functional/example-1-basics/index.js
@@ -0,0 +1,133 @@
+describe('Example 1 - Basics', function () {
+ 'use strict';
+
+ var baseUri = '/base/test/functional/example-1-basics';
+ var expect = chai.expect;
+ var currentFrame = 0;
+ var frameEvents = {};
+ var stage;
+ var renderer;
+ var bunny;
+
+ function onFrame(frame, callback) {
+ frameEvents[frame] = callback;
+ }
+
+ function animate() {
+ currentFrame += 1;
+
+ requestAnimFrame( animate );
+
+ // just for fun, lets rotate mr rabbit a little
+ bunny.rotation += 0.1;
+
+ // render the stage
+ renderer.render(stage);
+
+ if (frameEvents[currentFrame])
+ frameEvents[currentFrame](currentFrame);
+ }
+
+ function initScene() {
+ // create an new instance of a pixi stage
+ stage = new PIXI.Stage(0x66FF99);
+
+ // create a renderer instance
+ renderer = PIXI.autoDetectRenderer(400, 300);
+ console.log('Is PIXI.WebGLRenderer: ' + (renderer instanceof PIXI.WebGLRenderer));
+
+ // add the renderer view element to the DOM
+ document.body.appendChild(renderer.view);
+
+ requestAnimFrame( animate );
+
+ // create a texture from an image path
+ var texture = PIXI.Texture.fromImage(baseUri + "/bunny.png");
+ // create a new Sprite using the texture
+ bunny = new PIXI.Sprite(texture);
+
+ // center the sprites anchor point
+ bunny.anchor.x = 0.5;
+ bunny.anchor.y = 0.5;
+
+ // move the sprite t the center of the screen
+ bunny.position.x = 200;
+ bunny.position.y = 150;
+
+ stage.addChild(bunny);
+ }
+
+ it('assets loaded', function (done) {
+ var loader = new PIXI.AssetLoader([
+ baseUri + '/bunny.png',
+ baseUri + '/frame-30.png',
+ baseUri + '/frame-60.png',
+ baseUri + '/frame-90.png'
+ ]);
+ // loader.on('onProgress', function (event) {
+ // console.log(event.content);
+ // });
+ loader.on('onComplete', function (event) {
+ done();
+ initScene();
+ });
+ loader.load();
+ });
+
+ it('frame 30 should match', function (done) {
+ this.timeout(700);
+ onFrame(30, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-30.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 60 should match', function (done) {
+ this.timeout(1200);
+ onFrame(60, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-60.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 90 should match', function (done) {
+ this.timeout(1700);
+ onFrame(90, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-90.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ // it('capture something', function (done) {
+ // this.timeout(2000000);
+ // onFrame(30, function () {
+ // var img = new Image();
+ // img.src = renderer.view.toDataURL('image/png');
+ // document.body.appendChild(img);
+ // });
+ // });
+});
diff --git a/test/index.html b/test/index.html
deleted file mode 100644
index 9cbcac5..0000000
--- a/test/index.html
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
- Pixi.js Test Suite
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/test/karma.conf.js b/test/karma.conf.js
new file mode 100644
index 0000000..c66a696
--- /dev/null
+++ b/test/karma.conf.js
@@ -0,0 +1,82 @@
+module.exports = function(config) {
+ config.set({
+
+ // base path, that will be used to resolve files and exclude
+ basePath : '../',
+
+ frameworks : ['mocha'],
+
+ // list of files / patterns to load in the browser
+ files : [
+ 'node_modules/chai/chai.js',
+ 'bin/pixi.dev.js',
+ 'test/lib/**/*.js',
+ 'test/unit/**/*.js',
+ // 'test/functional/**/*.js',
+ {pattern: 'test/**/*.png', watched: false, included: false, served: true}
+ ],
+
+ // list of files to exclude
+ exclude : [],
+
+ // use dolts reporter, as travis terminal does not support escaping sequences
+ // possible values: 'dots', 'progress', 'junit', 'teamcity'
+ // CLI --reporters progress
+ reporters : ['progress'],
+
+ // web server port
+ // CLI --port 9876
+ port : 9876,
+
+ // cli runner port
+ // CLI --runner-port 9100
+ runnerPort : 9100,
+
+ // enable / disable colors in the output (reporters and logs)
+ // CLI --colors --no-colors
+ colors : true,
+
+ // level of logging
+ // possible values: karma.LOG_DISABLE || karma.LOG_ERROR || karma.LOG_WARN || karma.LOG_INFO || karma.LOG_DEBUG
+ // CLI --log-level debug
+ logLevel : config.LOG_DEBUG,
+
+ // enable / disable watching file and executing tests whenever any file changes
+ // CLI --auto-watch --no-auto-watch
+ autoWatch : false,
+
+ // Start these browsers, currently available:
+ // - Chrome
+ // - ChromeCanary
+ // - Firefox
+ // - Opera
+ // - Safari (only Mac)
+ // - PhantomJS
+ // - IE (only Windows)
+ // CLI --browsers Chrome,Firefox,Safari
+ browsers : ['Firefox'],
+
+ // If browser does not capture in given timeout [ms], kill it
+ // CLI --capture-timeout 5000
+ captureTimeout : 5000,
+
+ // Auto run tests on start (when browsers are captured) and exit
+ // CLI --single-run --no-single-run
+ singleRun : true,
+
+ // report which specs are slower than 500ms
+ // CLI --report-slower-than 500
+ reportSlowerThan : 1000,
+
+ preprocessors : {
+ // '**/client/js/*.js': 'coverage'
+ },
+
+ plugins : [
+ 'karma-mocha',
+ // 'karma-chrome-launcher',
+ 'karma-firefox-launcher',
+ // 'karma-phantomjs-launcher'
+ ]
+ });
+};
diff --git a/test/lib/pixi/core/Matrix.js b/test/lib/pixi/core/Matrix.js
new file mode 100644
index 0000000..d26386b
--- /dev/null
+++ b/test/lib/pixi/core/Matrix.js
@@ -0,0 +1,40 @@
+
+function pixi_core_Matrix_confirmNewMat3(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(1);
+ expect(matrix[5]).to.equal(0);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(1);
+}
+
+function pixi_core_Matrix_confirmNewMat4(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[0]).to.equal(1);
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(0);
+ expect(matrix[5]).to.equal(1);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(0);
+ expect(matrix[9]).to.equal(0);
+ expect(matrix[10]).to.equal(1);
+ expect(matrix[11]).to.equal(0);
+ expect(matrix[12]).to.equal(0);
+ expect(matrix[13]).to.equal(0);
+ expect(matrix[14]).to.equal(0);
+ expect(matrix[15]).to.equal(1);
+}
diff --git a/test/lib/pixi/core/Point.js b/test/lib/pixi/core/Point.js
new file mode 100644
index 0000000..e5df07b
--- /dev/null
+++ b/test/lib/pixi/core/Point.js
@@ -0,0 +1,10 @@
+
+function pixi_core_Point_confirm(obj, x, y) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Point);
+ expect(obj).to.respondTo('clone');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+}
diff --git a/test/lib/pixi/core/Rectangle.js b/test/lib/pixi/core/Rectangle.js
new file mode 100644
index 0000000..23f0d12
--- /dev/null
+++ b/test/lib/pixi/core/Rectangle.js
@@ -0,0 +1,13 @@
+
+function pixi_core_Rectangle_confirm(obj, x, y, width, height) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Rectangle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+ expect(obj).to.have.property('width', width);
+ expect(obj).to.have.property('height', height);
+}
diff --git a/test/lib/pixi/display/DisplayObject.js b/test/lib/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..1388a7f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObject.js
@@ -0,0 +1,43 @@
+
+function pixi_display_DisplayObject_confirmNew(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObject);
+ expect(obj).to.respondTo('setInteractive');
+ expect(obj).to.respondTo('addFilter');
+ expect(obj).to.respondTo('removeFilter');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.property('last', obj);
+ expect(obj).to.have.property('first', obj);
+
+ expect(obj).to.contain.property('position');
+ pixi_core_Point_confirm(obj.position, 0, 0);
+ expect(obj).to.contain.property('scale');
+ pixi_core_Point_confirm(obj.scale, 1, 1);
+ expect(obj).to.contain.property('pivot');
+ pixi_core_Point_confirm(obj.pivot, 0, 0);
+
+ expect(obj).to.have.property('rotation', 0);
+ expect(obj).to.have.property('alpha', 1);
+ expect(obj).to.have.property('visible', true);
+ expect(obj).to.have.property('buttonMode', false);
+ expect(obj).to.have.property('parent', null);
+ expect(obj).to.have.property('worldAlpha', 1);
+
+ expect(obj).to.have.property('hitArea');
+ expect(obj).to.have.property('interactive'); // TODO: Have a better default value
+ expect('mask' in obj).to.be.true; // TODO: Have a better default value
+ expect(obj.mask).to.be.undefined;
+
+ expect(obj).to.have.property('renderable');
+ expect(obj).to.have.property('stage');
+
+ expect(obj).to.have.deep.property('worldTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ expect(obj).to.have.deep.property('localTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.localTransform);
+
+ expect(obj).to.have.deep.property('color.length', 0);
+ expect(obj).to.have.property('dynamic', true);
+}
diff --git a/test/lib/pixi/display/DisplayObjectContainer.js b/test/lib/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..085c59f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,16 @@
+
+function pixi_display_DisplayObjectContainer_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObject_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObjectContainer);
+ expect(obj).to.respondTo('addChild');
+ expect(obj).to.respondTo('addChildAt');
+ expect(obj).to.respondTo('swapChildren');
+ expect(obj).to.respondTo('getChildAt');
+ expect(obj).to.respondTo('removeChild');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('children.length', 0);
+}
diff --git a/test/lib/pixi/display/Sprite.js b/test/lib/pixi/display/Sprite.js
new file mode 100644
index 0000000..cc7a2d6
--- /dev/null
+++ b/test/lib/pixi/display/Sprite.js
@@ -0,0 +1,28 @@
+
+function pixi_display_Sprite_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Sprite);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', true);
+ expect(obj).to.have.property('stage', null);
+
+ expect(obj).to.have.property('anchor');
+ pixi_core_Point_confirm(obj.anchor, 0, 0);
+
+ expect(obj).to.have.property('blendMode', PIXI.blendModes.NORMAL);
+ expect(obj).to.have.property('width', 1); // TODO: is 1 expected
+ expect(obj).to.have.property('height', 1); // TODO: is 1 expected
+
+ // FIXME: Just make this a boolean that is always there
+ expect(!!obj.updateFrame).to.equal(obj.texture.baseTexture.hasLoaded);
+
+ expect(obj).to.have.property('texture');
+ pixi_textures_Texture_confirmNew(obj.texture, done);
+}
diff --git a/test/lib/pixi/extras/Strip.js b/test/lib/pixi/extras/Strip.js
new file mode 100644
index 0000000..8927a8a
--- /dev/null
+++ b/test/lib/pixi/extras/Strip.js
@@ -0,0 +1,12 @@
+
+function pixi_extras_Strip_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Strip);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ // TODO: Test properties
+}
diff --git a/test/lib/pixi/textures/Texture.js b/test/lib/pixi/textures/Texture.js
new file mode 100644
index 0000000..d5867b6
--- /dev/null
+++ b/test/lib/pixi/textures/Texture.js
@@ -0,0 +1,31 @@
+
+function pixi_textures_Texture_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ function confirmFrameDone() {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, obj.baseTexture.width, obj.baseTexture.height);
+
+ expect(obj).to.have.property('width', obj.baseTexture.width);
+ expect(obj).to.have.property('height', obj.baseTexture.height);
+ done();
+ }
+
+ expect(obj).to.be.an.instanceof(PIXI.Texture);
+ pixi_utils_EventTarget_like(obj);
+
+ expect(obj).to.have.property('baseTexture')
+ .and.to.be.an.instanceof(PIXI.BaseTexture);
+
+ expect(obj).to.have.property('scope', obj);
+
+ expect(obj).to.have.property('trim');
+ pixi_core_Point_confirm(obj.trim, 0, 0);
+
+ expect(obj).to.have.property('frame');
+ if (obj.baseTexture.hasLoaded) {
+ confirmFrameDone();
+ } else {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, 1, 1);
+ obj.addEventListener('update', confirmFrameDone);
+ }
+}
diff --git a/test/lib/pixi/utils/EventTarget.js b/test/lib/pixi/utils/EventTarget.js
new file mode 100644
index 0000000..7b1dcfa
--- /dev/null
+++ b/test/lib/pixi/utils/EventTarget.js
@@ -0,0 +1,8 @@
+
+function pixi_utils_EventTarget_like(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.respondTo('addEventListener');
+ expect(obj).to.respondTo('dispatchEvent');
+ expect(obj).to.respondTo('removeEventListener');
+}
diff --git a/test/lib/qunit-1.11.0.css b/test/lib/qunit-1.11.0.css
deleted file mode 100644
index d7fc0c8..0000000
--- a/test/lib/qunit-1.11.0.css
+++ /dev/null
@@ -1,244 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-/** Font Family and Sizes */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
- font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
-}
-
-#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
-#qunit-tests { font-size: smaller; }
-
-
-/** Resets */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter {
- margin: 0;
- padding: 0;
-}
-
-
-/** Header */
-
-#qunit-header {
- padding: 0.5em 0 0.5em 1em;
-
- color: #8699a4;
- background-color: #0d3349;
-
- font-size: 1.5em;
- line-height: 1em;
- font-weight: normal;
-
- border-radius: 5px 5px 0 0;
- -moz-border-radius: 5px 5px 0 0;
- -webkit-border-top-right-radius: 5px;
- -webkit-border-top-left-radius: 5px;
-}
-
-#qunit-header a {
- text-decoration: none;
- color: #c2ccd1;
-}
-
-#qunit-header a:hover,
-#qunit-header a:focus {
- color: #fff;
-}
-
-#qunit-testrunner-toolbar label {
- display: inline-block;
- padding: 0 .5em 0 .1em;
-}
-
-#qunit-banner {
- height: 5px;
-}
-
-#qunit-testrunner-toolbar {
- padding: 0.5em 0 0.5em 2em;
- color: #5E740B;
- background-color: #eee;
- overflow: hidden;
-}
-
-#qunit-userAgent {
- padding: 0.5em 0 0.5em 2.5em;
- background-color: #2b81af;
- color: #fff;
- text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
-}
-
-#qunit-modulefilter-container {
- float: right;
-}
-
-/** Tests: Pass/Fail */
-
-#qunit-tests {
- list-style-position: inside;
-}
-
-#qunit-tests li {
- padding: 0.4em 0.5em 0.4em 2.5em;
- border-bottom: 1px solid #fff;
- list-style-position: inside;
-}
-
-#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running {
- display: none;
-}
-
-#qunit-tests li strong {
- cursor: pointer;
-}
-
-#qunit-tests li a {
- padding: 0.5em;
- color: #c2ccd1;
- text-decoration: none;
-}
-#qunit-tests li a:hover,
-#qunit-tests li a:focus {
- color: #000;
-}
-
-#qunit-tests li .runtime {
- float: right;
- font-size: smaller;
-}
-
-.qunit-assert-list {
- margin-top: 0.5em;
- padding: 0.5em;
-
- background-color: #fff;
-
- border-radius: 5px;
- -moz-border-radius: 5px;
- -webkit-border-radius: 5px;
-}
-
-.qunit-collapsed {
- display: none;
-}
-
-#qunit-tests table {
- border-collapse: collapse;
- margin-top: .2em;
-}
-
-#qunit-tests th {
- text-align: right;
- vertical-align: top;
- padding: 0 .5em 0 0;
-}
-
-#qunit-tests td {
- vertical-align: top;
-}
-
-#qunit-tests pre {
- margin: 0;
- white-space: pre-wrap;
- word-wrap: break-word;
-}
-
-#qunit-tests del {
- background-color: #e0f2be;
- color: #374e0c;
- text-decoration: none;
-}
-
-#qunit-tests ins {
- background-color: #ffcaca;
- color: #500;
- text-decoration: none;
-}
-
-/*** Test Counts */
-
-#qunit-tests b.counts { color: black; }
-#qunit-tests b.passed { color: #5E740B; }
-#qunit-tests b.failed { color: #710909; }
-
-#qunit-tests li li {
- padding: 5px;
- background-color: #fff;
- border-bottom: none;
- list-style-position: inside;
-}
-
-/*** Passing Styles */
-
-#qunit-tests li li.pass {
- color: #3c510c;
- background-color: #fff;
- border-left: 10px solid #C6E746;
-}
-
-#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
-#qunit-tests .pass .test-name { color: #366097; }
-
-#qunit-tests .pass .test-actual,
-#qunit-tests .pass .test-expected { color: #999999; }
-
-#qunit-banner.qunit-pass { background-color: #C6E746; }
-
-/*** Failing Styles */
-
-#qunit-tests li li.fail {
- color: #710909;
- background-color: #fff;
- border-left: 10px solid #EE5757;
- white-space: pre;
-}
-
-#qunit-tests > li:last-child {
- border-radius: 0 0 5px 5px;
- -moz-border-radius: 0 0 5px 5px;
- -webkit-border-bottom-right-radius: 5px;
- -webkit-border-bottom-left-radius: 5px;
-}
-
-#qunit-tests .fail { color: #000000; background-color: #EE5757; }
-#qunit-tests .fail .test-name,
-#qunit-tests .fail .module-name { color: #000000; }
-
-#qunit-tests .fail .test-actual { color: #EE5757; }
-#qunit-tests .fail .test-expected { color: green; }
-
-#qunit-banner.qunit-fail { background-color: #EE5757; }
-
-
-/** Result */
-
-#qunit-testresult {
- padding: 0.5em 0.5em 0.5em 2.5em;
-
- color: #2b81af;
- background-color: #D2E0E6;
-
- border-bottom: 1px solid white;
-}
-#qunit-testresult .module-name {
- font-weight: bold;
-}
-
-/** Fixture */
-
-#qunit-fixture {
- position: absolute;
- top: -10000px;
- left: -10000px;
- width: 1000px;
- height: 1000px;
-}
diff --git a/test/lib/qunit-1.11.0.js b/test/lib/qunit-1.11.0.js
deleted file mode 100644
index 302545f..0000000
--- a/test/lib/qunit-1.11.0.js
+++ /dev/null
@@ -1,2152 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-(function( window ) {
-
-var QUnit,
- assert,
- config,
- onErrorFnPrev,
- testId = 0,
- fileName = (sourceFromStacktrace( 0 ) || "" ).replace(/(:\d+)+\)?/, "").replace(/.+\//, ""),
- toString = Object.prototype.toString,
- hasOwn = Object.prototype.hasOwnProperty,
- // Keep a local reference to Date (GH-283)
- Date = window.Date,
- defined = {
- setTimeout: typeof window.setTimeout !== "undefined",
- sessionStorage: (function() {
- var x = "qunit-test-string";
- try {
- sessionStorage.setItem( x, x );
- sessionStorage.removeItem( x );
- return true;
- } catch( e ) {
- return false;
- }
- }())
- },
- /**
- * Provides a normalized error string, correcting an issue
- * with IE 7 (and prior) where Error.prototype.toString is
- * not properly implemented
- *
- * Based on http://es5.github.com/#x15.11.4.4
- *
- * @param {String|Error} error
- * @return {String} error message
- */
- errorString = function( error ) {
- var name, message,
- errorString = error.toString();
- if ( errorString.substring( 0, 7 ) === "[object" ) {
- name = error.name ? error.name.toString() : "Error";
- message = error.message ? error.message.toString() : "";
- if ( name && message ) {
- return name + ": " + message;
- } else if ( name ) {
- return name;
- } else if ( message ) {
- return message;
- } else {
- return "Error";
- }
- } else {
- return errorString;
- }
- },
- /**
- * Makes a clone of an object using only Array or Object as base,
- * and copies over the own enumerable properties.
- *
- * @param {Object} obj
- * @return {Object} New object with only the own properties (recursively).
- */
- objectValues = function( obj ) {
- // Grunt 0.3.x uses an older version of jshint that still has jshint/jshint#392.
- /*jshint newcap: false */
- var key, val,
- vals = QUnit.is( "array", obj ) ? [] : {};
- for ( key in obj ) {
- if ( hasOwn.call( obj, key ) ) {
- val = obj[key];
- vals[key] = val === Object(val) ? objectValues(val) : val;
- }
- }
- return vals;
- };
-
-function Test( settings ) {
- extend( this, settings );
- this.assertions = [];
- this.testNumber = ++Test.count;
-}
-
-Test.count = 0;
-
-Test.prototype = {
- init: function() {
- var a, b, li,
- tests = id( "qunit-tests" );
-
- if ( tests ) {
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml;
-
- // `a` initialized at top of scope
- a = document.createElement( "a" );
- a.innerHTML = "Rerun";
- a.href = QUnit.url({ testNumber: this.testNumber });
-
- li = document.createElement( "li" );
- li.appendChild( b );
- li.appendChild( a );
- li.className = "running";
- li.id = this.id = "qunit-test-output" + testId++;
-
- tests.appendChild( li );
- }
- },
- setup: function() {
- if ( this.module !== config.previousModule ) {
- if ( config.previousModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.previousModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
- config.previousModule = this.module;
- config.moduleStats = { all: 0, bad: 0 };
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- } else if ( config.autorun ) {
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- }
-
- config.current = this;
-
- this.testEnvironment = extend({
- setup: function() {},
- teardown: function() {}
- }, this.moduleTestEnvironment );
-
- this.started = +new Date();
- runLoggingCallbacks( "testStart", QUnit, {
- name: this.testName,
- module: this.module
- });
-
- // allow utility functions to access the current test environment
- // TODO why??
- QUnit.current_testEnvironment = this.testEnvironment;
-
- if ( !config.pollution ) {
- saveGlobal();
- }
- if ( config.notrycatch ) {
- this.testEnvironment.setup.call( this.testEnvironment );
- return;
- }
- try {
- this.testEnvironment.setup.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Setup failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- },
- run: function() {
- config.current = this;
-
- var running = id( "qunit-testresult" );
-
- if ( running ) {
- running.innerHTML = "Running:
" + this.nameHtml;
- }
-
- if ( this.async ) {
- QUnit.stop();
- }
-
- this.callbackStarted = +new Date();
-
- if ( config.notrycatch ) {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- return;
- }
-
- try {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- } catch( e ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
-
- QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + " " + this.stack + ": " + ( e.message || e ), extractStacktrace( e, 0 ) );
- // else next test will carry the responsibility
- saveGlobal();
-
- // Restart the tests if they're blocking
- if ( config.blocking ) {
- QUnit.start();
- }
- }
- },
- teardown: function() {
- config.current = this;
- if ( config.notrycatch ) {
- if ( typeof this.callbackRuntime === "undefined" ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
- }
- this.testEnvironment.teardown.call( this.testEnvironment );
- return;
- } else {
- try {
- this.testEnvironment.teardown.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Teardown failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- }
- checkPollution();
- },
- finish: function() {
- config.current = this;
- if ( config.requireExpects && this.expected === null ) {
- QUnit.pushFailure( "Expected number of assertions to be defined, but expect() was not called.", this.stack );
- } else if ( this.expected !== null && this.expected !== this.assertions.length ) {
- QUnit.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack );
- } else if ( this.expected === null && !this.assertions.length ) {
- QUnit.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions.", this.stack );
- }
-
- var i, assertion, a, b, time, li, ol,
- test = this,
- good = 0,
- bad = 0,
- tests = id( "qunit-tests" );
-
- this.runtime = +new Date() - this.started;
- config.stats.all += this.assertions.length;
- config.moduleStats.all += this.assertions.length;
-
- if ( tests ) {
- ol = document.createElement( "ol" );
- ol.className = "qunit-assert-list";
-
- for ( i = 0; i < this.assertions.length; i++ ) {
- assertion = this.assertions[i];
-
- li = document.createElement( "li" );
- li.className = assertion.result ? "pass" : "fail";
- li.innerHTML = assertion.message || ( assertion.result ? "okay" : "failed" );
- ol.appendChild( li );
-
- if ( assertion.result ) {
- good++;
- } else {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
-
- // store result when possible
- if ( QUnit.config.reorder && defined.sessionStorage ) {
- if ( bad ) {
- sessionStorage.setItem( "qunit-test-" + this.module + "-" + this.testName, bad );
- } else {
- sessionStorage.removeItem( "qunit-test-" + this.module + "-" + this.testName );
- }
- }
-
- if ( bad === 0 ) {
- addClass( ol, "qunit-collapsed" );
- }
-
- // `b` initialized at top of scope
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml + " (" + bad + ", " + good + ", " + this.assertions.length + ")";
-
- addEvent(b, "click", function() {
- var next = b.parentNode.lastChild,
- collapsed = hasClass( next, "qunit-collapsed" );
- ( collapsed ? removeClass : addClass )( next, "qunit-collapsed" );
- });
-
- addEvent(b, "dblclick", function( e ) {
- var target = e && e.target ? e.target : window.event.srcElement;
- if ( target.nodeName.toLowerCase() === "span" || target.nodeName.toLowerCase() === "b" ) {
- target = target.parentNode;
- }
- if ( window.location && target.nodeName.toLowerCase() === "strong" ) {
- window.location = QUnit.url({ testNumber: test.testNumber });
- }
- });
-
- // `time` initialized at top of scope
- time = document.createElement( "span" );
- time.className = "runtime";
- time.innerHTML = this.runtime + " ms";
-
- // `li` initialized at top of scope
- li = id( this.id );
- li.className = bad ? "fail" : "pass";
- li.removeChild( li.firstChild );
- a = li.firstChild;
- li.appendChild( b );
- li.appendChild( a );
- li.appendChild( time );
- li.appendChild( ol );
-
- } else {
- for ( i = 0; i < this.assertions.length; i++ ) {
- if ( !this.assertions[i].result ) {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
- }
-
- runLoggingCallbacks( "testDone", QUnit, {
- name: this.testName,
- module: this.module,
- failed: bad,
- passed: this.assertions.length - bad,
- total: this.assertions.length,
- duration: this.runtime
- });
-
- QUnit.reset();
-
- config.current = undefined;
- },
-
- queue: function() {
- var bad,
- test = this;
-
- synchronize(function() {
- test.init();
- });
- function run() {
- // each of these can by async
- synchronize(function() {
- test.setup();
- });
- synchronize(function() {
- test.run();
- });
- synchronize(function() {
- test.teardown();
- });
- synchronize(function() {
- test.finish();
- });
- }
-
- // `bad` initialized at top of scope
- // defer when previous test run passed, if storage is available
- bad = QUnit.config.reorder && defined.sessionStorage &&
- +sessionStorage.getItem( "qunit-test-" + this.module + "-" + this.testName );
-
- if ( bad ) {
- run();
- } else {
- synchronize( run, true );
- }
- }
-};
-
-// Root QUnit object.
-// `QUnit` initialized at top of scope
-QUnit = {
-
- // call on start of module test to prepend name to all tests
- module: function( name, testEnvironment ) {
- config.currentModule = name;
- config.currentModuleTestEnvironment = testEnvironment;
- config.modules[name] = true;
- },
-
- asyncTest: function( testName, expected, callback ) {
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- QUnit.test( testName, expected, callback, true );
- },
-
- test: function( testName, expected, callback, async ) {
- var test,
- nameHtml = "" + escapeText( testName ) + "";
-
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- if ( config.currentModule ) {
- nameHtml = "" + escapeText( config.currentModule ) + ": " + nameHtml;
- }
-
- test = new Test({
- nameHtml: nameHtml,
- testName: testName,
- expected: expected,
- async: async,
- callback: callback,
- module: config.currentModule,
- moduleTestEnvironment: config.currentModuleTestEnvironment,
- stack: sourceFromStacktrace( 2 )
- });
-
- if ( !validTest( test ) ) {
- return;
- }
-
- test.queue();
- },
-
- // Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through.
- expect: function( asserts ) {
- if (arguments.length === 1) {
- config.current.expected = asserts;
- } else {
- return config.current.expected;
- }
- },
-
- start: function( count ) {
- // QUnit hasn't been initialized yet.
- // Note: RequireJS (et al) may delay onLoad
- if ( config.semaphore === undefined ) {
- QUnit.begin(function() {
- // This is triggered at the top of QUnit.load, push start() to the event loop, to allow QUnit.load to finish first
- setTimeout(function() {
- QUnit.start( count );
- });
- });
- return;
- }
-
- config.semaphore -= count || 1;
- // don't start until equal number of stop-calls
- if ( config.semaphore > 0 ) {
- return;
- }
- // ignore if start is called more often then stop
- if ( config.semaphore < 0 ) {
- config.semaphore = 0;
- QUnit.pushFailure( "Called start() while already started (QUnit.config.semaphore was 0 already)", null, sourceFromStacktrace(2) );
- return;
- }
- // A slight delay, to avoid any current callbacks
- if ( defined.setTimeout ) {
- window.setTimeout(function() {
- if ( config.semaphore > 0 ) {
- return;
- }
- if ( config.timeout ) {
- clearTimeout( config.timeout );
- }
-
- config.blocking = false;
- process( true );
- }, 13);
- } else {
- config.blocking = false;
- process( true );
- }
- },
-
- stop: function( count ) {
- config.semaphore += count || 1;
- config.blocking = true;
-
- if ( config.testTimeout && defined.setTimeout ) {
- clearTimeout( config.timeout );
- config.timeout = window.setTimeout(function() {
- QUnit.ok( false, "Test timed out" );
- config.semaphore = 1;
- QUnit.start();
- }, config.testTimeout );
- }
- }
-};
-
-// `assert` initialized at top of scope
-// Asssert helpers
-// All of these must either call QUnit.push() or manually do:
-// - runLoggingCallbacks( "log", .. );
-// - config.current.assertions.push({ .. });
-// We attach it to the QUnit object *after* we expose the public API,
-// otherwise `assert` will become a global variable in browsers (#341).
-assert = {
- /**
- * Asserts rough true-ish result.
- * @name ok
- * @function
- * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" );
- */
- ok: function( result, msg ) {
- if ( !config.current ) {
- throw new Error( "ok() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
- result = !!result;
-
- var source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: msg
- };
-
- msg = escapeText( msg || (result ? "okay" : "failed" ) );
- msg = "" + msg + "";
-
- if ( !result ) {
- source = sourceFromStacktrace( 2 );
- if ( source ) {
- details.source = source;
- msg += "Source: | " + escapeText( source ) + " |
---|
";
- }
- }
- runLoggingCallbacks( "log", QUnit, details );
- config.current.assertions.push({
- result: result,
- message: msg
- });
- },
-
- /**
- * Assert that the first two arguments are equal, with an optional message.
- * Prints out both actual and expected values.
- * @name equal
- * @function
- * @example equal( format( "Received {0} bytes.", 2), "Received 2 bytes.", "format() replaces {0} with next argument" );
- */
- equal: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected == actual, actual, expected, message );
- },
-
- /**
- * @name notEqual
- * @function
- */
- notEqual: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected != actual, actual, expected, message );
- },
-
- /**
- * @name propEqual
- * @function
- */
- propEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notPropEqual
- * @function
- */
- notPropEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name deepEqual
- * @function
- */
- deepEqual: function( actual, expected, message ) {
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notDeepEqual
- * @function
- */
- notDeepEqual: function( actual, expected, message ) {
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name strictEqual
- * @function
- */
- strictEqual: function( actual, expected, message ) {
- QUnit.push( expected === actual, actual, expected, message );
- },
-
- /**
- * @name notStrictEqual
- * @function
- */
- notStrictEqual: function( actual, expected, message ) {
- QUnit.push( expected !== actual, actual, expected, message );
- },
-
- "throws": function( block, expected, message ) {
- var actual,
- expectedOutput = expected,
- ok = false;
-
- // 'expected' is optional
- if ( typeof expected === "string" ) {
- message = expected;
- expected = null;
- }
-
- config.current.ignoreGlobalErrors = true;
- try {
- block.call( config.current.testEnvironment );
- } catch (e) {
- actual = e;
- }
- config.current.ignoreGlobalErrors = false;
-
- if ( actual ) {
- // we don't want to validate thrown error
- if ( !expected ) {
- ok = true;
- expectedOutput = null;
- // expected is a regexp
- } else if ( QUnit.objectType( expected ) === "regexp" ) {
- ok = expected.test( errorString( actual ) );
- // expected is a constructor
- } else if ( actual instanceof expected ) {
- ok = true;
- // expected is a validation function which returns true is validation passed
- } else if ( expected.call( {}, actual ) === true ) {
- expectedOutput = null;
- ok = true;
- }
-
- QUnit.push( ok, actual, expectedOutput, message );
- } else {
- QUnit.pushFailure( message, null, 'No exception was thrown.' );
- }
- }
-};
-
-/**
- * @deprecate since 1.8.0
- * Kept assertion helpers in root for backwards compatibility.
- */
-extend( QUnit, assert );
-
-/**
- * @deprecated since 1.9.0
- * Kept root "raises()" for backwards compatibility.
- * (Note that we don't introduce assert.raises).
- */
-QUnit.raises = assert[ "throws" ];
-
-/**
- * @deprecated since 1.0.0, replaced with error pushes since 1.3.0
- * Kept to avoid TypeErrors for undefined methods.
- */
-QUnit.equals = function() {
- QUnit.push( false, false, false, "QUnit.equals has been deprecated since 2009 (e88049a0), use QUnit.equal instead" );
-};
-QUnit.same = function() {
- QUnit.push( false, false, false, "QUnit.same has been deprecated since 2009 (e88049a0), use QUnit.deepEqual instead" );
-};
-
-// We want access to the constructor's prototype
-(function() {
- function F() {}
- F.prototype = QUnit;
- QUnit = new F();
- // Make F QUnit's constructor so that we can add to the prototype later
- QUnit.constructor = F;
-}());
-
-/**
- * Config object: Maintain internal state
- * Later exposed as QUnit.config
- * `config` initialized at top of scope
- */
-config = {
- // The queue of tests to run
- queue: [],
-
- // block until document ready
- blocking: true,
-
- // when enabled, show only failing tests
- // gets persisted through sessionStorage and can be changed in UI via checkbox
- hidepassed: false,
-
- // by default, run previously failed tests first
- // very useful in combination with "Hide passed tests" checked
- reorder: true,
-
- // by default, modify document.title when suite is done
- altertitle: true,
-
- // when enabled, all tests must call expect()
- requireExpects: false,
-
- // add checkboxes that are persisted in the query-string
- // when enabled, the id is set to `true` as a `QUnit.config` property
- urlConfig: [
- {
- id: "noglobals",
- label: "Check for Globals",
- tooltip: "Enabling this will test if any test introduces new properties on the `window` object. Stored as query-strings."
- },
- {
- id: "notrycatch",
- label: "No try-catch",
- tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging exceptions in IE reasonable. Stored as query-strings."
- }
- ],
-
- // Set of all modules.
- modules: {},
-
- // logging callback queues
- begin: [],
- done: [],
- log: [],
- testStart: [],
- testDone: [],
- moduleStart: [],
- moduleDone: []
-};
-
-// Export global variables, unless an 'exports' object exists,
-// in that case we assume we're in CommonJS (dealt with on the bottom of the script)
-if ( typeof exports === "undefined" ) {
- extend( window, QUnit );
-
- // Expose QUnit object
- window.QUnit = QUnit;
-}
-
-// Initialize more QUnit.config and QUnit.urlParams
-(function() {
- var i,
- location = window.location || { search: "", protocol: "file:" },
- params = location.search.slice( 1 ).split( "&" ),
- length = params.length,
- urlParams = {},
- current;
-
- if ( params[ 0 ] ) {
- for ( i = 0; i < length; i++ ) {
- current = params[ i ].split( "=" );
- current[ 0 ] = decodeURIComponent( current[ 0 ] );
- // allow just a key to turn on a flag, e.g., test.html?noglobals
- current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true;
- urlParams[ current[ 0 ] ] = current[ 1 ];
- }
- }
-
- QUnit.urlParams = urlParams;
-
- // String search anywhere in moduleName+testName
- config.filter = urlParams.filter;
-
- // Exact match of the module name
- config.module = urlParams.module;
-
- config.testNumber = parseInt( urlParams.testNumber, 10 ) || null;
-
- // Figure out if we're running the tests from a server or not
- QUnit.isLocal = location.protocol === "file:";
-}());
-
-// Extend QUnit object,
-// these after set here because they should not be exposed as global functions
-extend( QUnit, {
- assert: assert,
-
- config: config,
-
- // Initialize the configuration options
- init: function() {
- extend( config, {
- stats: { all: 0, bad: 0 },
- moduleStats: { all: 0, bad: 0 },
- started: +new Date(),
- updateRate: 1000,
- blocking: false,
- autostart: true,
- autorun: false,
- filter: "",
- queue: [],
- semaphore: 1
- });
-
- var tests, banner, result,
- qunit = id( "qunit" );
-
- if ( qunit ) {
- qunit.innerHTML =
- "" +
- "" +
- "" +
- "" +
- "
";
- }
-
- tests = id( "qunit-tests" );
- banner = id( "qunit-banner" );
- result = id( "qunit-testresult" );
-
- if ( tests ) {
- tests.innerHTML = "";
- }
-
- if ( banner ) {
- banner.className = "";
- }
-
- if ( result ) {
- result.parentNode.removeChild( result );
- }
-
- if ( tests ) {
- result = document.createElement( "p" );
- result.id = "qunit-testresult";
- result.className = "result";
- tests.parentNode.insertBefore( result, tests );
- result.innerHTML = "Running...
";
- }
- },
-
- // Resets the test setup. Useful for tests that modify the DOM.
- reset: function() {
- var fixture = id( "qunit-fixture" );
- if ( fixture ) {
- fixture.innerHTML = config.fixture;
- }
- },
-
- // Trigger an event on an element.
- // @example triggerEvent( document.body, "click" );
- triggerEvent: function( elem, type, event ) {
- if ( document.createEvent ) {
- event = document.createEvent( "MouseEvents" );
- event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView,
- 0, 0, 0, 0, 0, false, false, false, false, 0, null);
-
- elem.dispatchEvent( event );
- } else if ( elem.fireEvent ) {
- elem.fireEvent( "on" + type );
- }
- },
-
- // Safe object type checking
- is: function( type, obj ) {
- return QUnit.objectType( obj ) === type;
- },
-
- objectType: function( obj ) {
- if ( typeof obj === "undefined" ) {
- return "undefined";
- // consider: typeof null === object
- }
- if ( obj === null ) {
- return "null";
- }
-
- var match = toString.call( obj ).match(/^\[object\s(.*)\]$/),
- type = match && match[1] || "";
-
- switch ( type ) {
- case "Number":
- if ( isNaN(obj) ) {
- return "nan";
- }
- return "number";
- case "String":
- case "Boolean":
- case "Array":
- case "Date":
- case "RegExp":
- case "Function":
- return type.toLowerCase();
- }
- if ( typeof obj === "object" ) {
- return "object";
- }
- return undefined;
- },
-
- push: function( result, actual, expected, message ) {
- if ( !config.current ) {
- throw new Error( "assertion outside test context, was " + sourceFromStacktrace() );
- }
-
- var output, source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: message,
- actual: actual,
- expected: expected
- };
-
- message = escapeText( message ) || ( result ? "okay" : "failed" );
- message = "" + message + "";
- output = message;
-
- if ( !result ) {
- expected = escapeText( QUnit.jsDump.parse(expected) );
- actual = escapeText( QUnit.jsDump.parse(actual) );
- output += "Expected: | " + expected + " |
";
-
- if ( actual !== expected ) {
- output += "Result: | " + actual + " |
";
- output += "Diff: | " + QUnit.diff( expected, actual ) + " |
";
- }
-
- source = sourceFromStacktrace();
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
- }
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: !!result,
- message: output
- });
- },
-
- pushFailure: function( message, source, actual ) {
- if ( !config.current ) {
- throw new Error( "pushFailure() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
-
- var output,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: false,
- message: message
- };
-
- message = escapeText( message ) || "error";
- message = "" + message + "";
- output = message;
-
- output += "";
-
- if ( actual ) {
- output += "Result: | " + escapeText( actual ) + " |
";
- }
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: false,
- message: output
- });
- },
-
- url: function( params ) {
- params = extend( extend( {}, QUnit.urlParams ), params );
- var key,
- querystring = "?";
-
- for ( key in params ) {
- if ( !hasOwn.call( params, key ) ) {
- continue;
- }
- querystring += encodeURIComponent( key ) + "=" +
- encodeURIComponent( params[ key ] ) + "&";
- }
- return window.location.protocol + "//" + window.location.host +
- window.location.pathname + querystring.slice( 0, -1 );
- },
-
- extend: extend,
- id: id,
- addEvent: addEvent
- // load, equiv, jsDump, diff: Attached later
-});
-
-/**
- * @deprecated: Created for backwards compatibility with test runner that set the hook function
- * into QUnit.{hook}, instead of invoking it and passing the hook function.
- * QUnit.constructor is set to the empty F() above so that we can add to it's prototype here.
- * Doing this allows us to tell if the following methods have been overwritten on the actual
- * QUnit object.
- */
-extend( QUnit.constructor.prototype, {
-
- // Logging callbacks; all receive a single argument with the listed properties
- // run test/logs.html for any related changes
- begin: registerLoggingCallback( "begin" ),
-
- // done: { failed, passed, total, runtime }
- done: registerLoggingCallback( "done" ),
-
- // log: { result, actual, expected, message }
- log: registerLoggingCallback( "log" ),
-
- // testStart: { name }
- testStart: registerLoggingCallback( "testStart" ),
-
- // testDone: { name, failed, passed, total, duration }
- testDone: registerLoggingCallback( "testDone" ),
-
- // moduleStart: { name }
- moduleStart: registerLoggingCallback( "moduleStart" ),
-
- // moduleDone: { name, failed, passed, total }
- moduleDone: registerLoggingCallback( "moduleDone" )
-});
-
-if ( typeof document === "undefined" || document.readyState === "complete" ) {
- config.autorun = true;
-}
-
-QUnit.load = function() {
- runLoggingCallbacks( "begin", QUnit, {} );
-
- // Initialize the config, saving the execution queue
- var banner, filter, i, label, len, main, ol, toolbar, userAgent, val,
- urlConfigCheckboxesContainer, urlConfigCheckboxes, moduleFilter,
- numModules = 0,
- moduleFilterHtml = "",
- urlConfigHtml = "",
- oldconfig = extend( {}, config );
-
- QUnit.init();
- extend(config, oldconfig);
-
- config.blocking = false;
-
- len = config.urlConfig.length;
-
- for ( i = 0; i < len; i++ ) {
- val = config.urlConfig[i];
- if ( typeof val === "string" ) {
- val = {
- id: val,
- label: val,
- tooltip: "[no tooltip available]"
- };
- }
- config[ val.id ] = QUnit.urlParams[ val.id ];
- urlConfigHtml += "";
- }
-
- moduleFilterHtml += "";
-
- // `userAgent` initialized at top of scope
- userAgent = id( "qunit-userAgent" );
- if ( userAgent ) {
- userAgent.innerHTML = navigator.userAgent;
- }
-
- // `banner` initialized at top of scope
- banner = id( "qunit-header" );
- if ( banner ) {
- banner.innerHTML = "" + banner.innerHTML + " ";
- }
-
- // `toolbar` initialized at top of scope
- toolbar = id( "qunit-testrunner-toolbar" );
- if ( toolbar ) {
- // `filter` initialized at top of scope
- filter = document.createElement( "input" );
- filter.type = "checkbox";
- filter.id = "qunit-filter-pass";
-
- addEvent( filter, "click", function() {
- var tmp,
- ol = document.getElementById( "qunit-tests" );
-
- if ( filter.checked ) {
- ol.className = ol.className + " hidepass";
- } else {
- tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " ";
- ol.className = tmp.replace( / hidepass /, " " );
- }
- if ( defined.sessionStorage ) {
- if (filter.checked) {
- sessionStorage.setItem( "qunit-filter-passed-tests", "true" );
- } else {
- sessionStorage.removeItem( "qunit-filter-passed-tests" );
- }
- }
- });
-
- if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem( "qunit-filter-passed-tests" ) ) {
- filter.checked = true;
- // `ol` initialized at top of scope
- ol = document.getElementById( "qunit-tests" );
- ol.className = ol.className + " hidepass";
- }
- toolbar.appendChild( filter );
-
- // `label` initialized at top of scope
- label = document.createElement( "label" );
- label.setAttribute( "for", "qunit-filter-pass" );
- label.setAttribute( "title", "Only show tests and assertons that fail. Stored in sessionStorage." );
- label.innerHTML = "Hide passed tests";
- toolbar.appendChild( label );
-
- urlConfigCheckboxesContainer = document.createElement("span");
- urlConfigCheckboxesContainer.innerHTML = urlConfigHtml;
- urlConfigCheckboxes = urlConfigCheckboxesContainer.getElementsByTagName("input");
- // For oldIE support:
- // * Add handlers to the individual elements instead of the container
- // * Use "click" instead of "change"
- // * Fallback from event.target to event.srcElement
- addEvents( urlConfigCheckboxes, "click", function( event ) {
- var params = {},
- target = event.target || event.srcElement;
- params[ target.name ] = target.checked ? true : undefined;
- window.location = QUnit.url( params );
- });
- toolbar.appendChild( urlConfigCheckboxesContainer );
-
- if (numModules > 1) {
- moduleFilter = document.createElement( 'span' );
- moduleFilter.setAttribute( 'id', 'qunit-modulefilter-container' );
- moduleFilter.innerHTML = moduleFilterHtml;
- addEvent( moduleFilter.lastChild, "change", function() {
- var selectBox = moduleFilter.getElementsByTagName("select")[0],
- selectedModule = decodeURIComponent(selectBox.options[selectBox.selectedIndex].value);
-
- window.location = QUnit.url( { module: ( selectedModule === "" ) ? undefined : selectedModule } );
- });
- toolbar.appendChild(moduleFilter);
- }
- }
-
- // `main` initialized at top of scope
- main = id( "qunit-fixture" );
- if ( main ) {
- config.fixture = main.innerHTML;
- }
-
- if ( config.autostart ) {
- QUnit.start();
- }
-};
-
-addEvent( window, "load", QUnit.load );
-
-// `onErrorFnPrev` initialized at top of scope
-// Preserve other handlers
-onErrorFnPrev = window.onerror;
-
-// Cover uncaught exceptions
-// Returning true will surpress the default browser handler,
-// returning false will let it run.
-window.onerror = function ( error, filePath, linerNr ) {
- var ret = false;
- if ( onErrorFnPrev ) {
- ret = onErrorFnPrev( error, filePath, linerNr );
- }
-
- // Treat return value as window.onerror itself does,
- // Only do our handling if not surpressed.
- if ( ret !== true ) {
- if ( QUnit.config.current ) {
- if ( QUnit.config.current.ignoreGlobalErrors ) {
- return true;
- }
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- } else {
- QUnit.test( "global failure", extend( function() {
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- }, { validTest: validTest } ) );
- }
- return false;
- }
-
- return ret;
-};
-
-function done() {
- config.autorun = true;
-
- // Log the last module results
- if ( config.currentModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.currentModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
-
- var i, key,
- banner = id( "qunit-banner" ),
- tests = id( "qunit-tests" ),
- runtime = +new Date() - config.started,
- passed = config.stats.all - config.stats.bad,
- html = [
- "Tests completed in ",
- runtime,
- " milliseconds.
",
- "",
- passed,
- " assertions of ",
- config.stats.all,
- " passed, ",
- config.stats.bad,
- " failed."
- ].join( "" );
-
- if ( banner ) {
- banner.className = ( config.stats.bad ? "qunit-fail" : "qunit-pass" );
- }
-
- if ( tests ) {
- id( "qunit-testresult" ).innerHTML = html;
- }
-
- if ( config.altertitle && typeof document !== "undefined" && document.title ) {
- // show ✖ for good, ✔ for bad suite result in title
- // use escape sequences in case file gets loaded with non-utf-8-charset
- document.title = [
- ( config.stats.bad ? "\u2716" : "\u2714" ),
- document.title.replace( /^[\u2714\u2716] /i, "" )
- ].join( " " );
- }
-
- // clear own sessionStorage items if all tests passed
- if ( config.reorder && defined.sessionStorage && config.stats.bad === 0 ) {
- // `key` & `i` initialized at top of scope
- for ( i = 0; i < sessionStorage.length; i++ ) {
- key = sessionStorage.key( i++ );
- if ( key.indexOf( "qunit-test-" ) === 0 ) {
- sessionStorage.removeItem( key );
- }
- }
- }
-
- // scroll back to top to show results
- if ( window.scrollTo ) {
- window.scrollTo(0, 0);
- }
-
- runLoggingCallbacks( "done", QUnit, {
- failed: config.stats.bad,
- passed: passed,
- total: config.stats.all,
- runtime: runtime
- });
-}
-
-/** @return Boolean: true if this test should be ran */
-function validTest( test ) {
- var include,
- filter = config.filter && config.filter.toLowerCase(),
- module = config.module && config.module.toLowerCase(),
- fullName = (test.module + ": " + test.testName).toLowerCase();
-
- // Internally-generated tests are always valid
- if ( test.callback && test.callback.validTest === validTest ) {
- delete test.callback.validTest;
- return true;
- }
-
- if ( config.testNumber ) {
- return test.testNumber === config.testNumber;
- }
-
- if ( module && ( !test.module || test.module.toLowerCase() !== module ) ) {
- return false;
- }
-
- if ( !filter ) {
- return true;
- }
-
- include = filter.charAt( 0 ) !== "!";
- if ( !include ) {
- filter = filter.slice( 1 );
- }
-
- // If the filter matches, we need to honour include
- if ( fullName.indexOf( filter ) !== -1 ) {
- return include;
- }
-
- // Otherwise, do the opposite
- return !include;
-}
-
-// so far supports only Firefox, Chrome and Opera (buggy), Safari (for real exceptions)
-// Later Safari and IE10 are supposed to support error.stack as well
-// See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack
-function extractStacktrace( e, offset ) {
- offset = offset === undefined ? 3 : offset;
-
- var stack, include, i;
-
- if ( e.stacktrace ) {
- // Opera
- return e.stacktrace.split( "\n" )[ offset + 3 ];
- } else if ( e.stack ) {
- // Firefox, Chrome
- stack = e.stack.split( "\n" );
- if (/^error$/i.test( stack[0] ) ) {
- stack.shift();
- }
- if ( fileName ) {
- include = [];
- for ( i = offset; i < stack.length; i++ ) {
- if ( stack[ i ].indexOf( fileName ) !== -1 ) {
- break;
- }
- include.push( stack[ i ] );
- }
- if ( include.length ) {
- return include.join( "\n" );
- }
- }
- return stack[ offset ];
- } else if ( e.sourceURL ) {
- // Safari, PhantomJS
- // hopefully one day Safari provides actual stacktraces
- // exclude useless self-reference for generated Error objects
- if ( /qunit.js$/.test( e.sourceURL ) ) {
- return;
- }
- // for actual exceptions, this is useful
- return e.sourceURL + ":" + e.line;
- }
-}
-function sourceFromStacktrace( offset ) {
- try {
- throw new Error();
- } catch ( e ) {
- return extractStacktrace( e, offset );
- }
-}
-
-/**
- * Escape text for attribute or text content.
- */
-function escapeText( s ) {
- if ( !s ) {
- return "";
- }
- s = s + "";
- // Both single quotes and double quotes (for attributes)
- return s.replace( /['"<>&]/g, function( s ) {
- switch( s ) {
- case '\'':
- return ''';
- case '"':
- return '"';
- case '<':
- return '<';
- case '>':
- return '>';
- case '&':
- return '&';
- }
- });
-}
-
-function synchronize( callback, last ) {
- config.queue.push( callback );
-
- if ( config.autorun && !config.blocking ) {
- process( last );
- }
-}
-
-function process( last ) {
- function next() {
- process( last );
- }
- var start = new Date().getTime();
- config.depth = config.depth ? config.depth + 1 : 1;
-
- while ( config.queue.length && !config.blocking ) {
- if ( !defined.setTimeout || config.updateRate <= 0 || ( ( new Date().getTime() - start ) < config.updateRate ) ) {
- config.queue.shift()();
- } else {
- window.setTimeout( next, 13 );
- break;
- }
- }
- config.depth--;
- if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) {
- done();
- }
-}
-
-function saveGlobal() {
- config.pollution = [];
-
- if ( config.noglobals ) {
- for ( var key in window ) {
- // in Opera sometimes DOM element ids show up here, ignore them
- if ( !hasOwn.call( window, key ) || /^qunit-test-output/.test( key ) ) {
- continue;
- }
- config.pollution.push( key );
- }
- }
-}
-
-function checkPollution() {
- var newGlobals,
- deletedGlobals,
- old = config.pollution;
-
- saveGlobal();
-
- newGlobals = diff( config.pollution, old );
- if ( newGlobals.length > 0 ) {
- QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join(", ") );
- }
-
- deletedGlobals = diff( old, config.pollution );
- if ( deletedGlobals.length > 0 ) {
- QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join(", ") );
- }
-}
-
-// returns a new Array with the elements that are in a but not in b
-function diff( a, b ) {
- var i, j,
- result = a.slice();
-
- for ( i = 0; i < result.length; i++ ) {
- for ( j = 0; j < b.length; j++ ) {
- if ( result[i] === b[j] ) {
- result.splice( i, 1 );
- i--;
- break;
- }
- }
- }
- return result;
-}
-
-function extend( a, b ) {
- for ( var prop in b ) {
- if ( b[ prop ] === undefined ) {
- delete a[ prop ];
-
- // Avoid "Member not found" error in IE8 caused by setting window.constructor
- } else if ( prop !== "constructor" || a !== window ) {
- a[ prop ] = b[ prop ];
- }
- }
-
- return a;
-}
-
-/**
- * @param {HTMLElement} elem
- * @param {string} type
- * @param {Function} fn
- */
-function addEvent( elem, type, fn ) {
- // Standards-based browsers
- if ( elem.addEventListener ) {
- elem.addEventListener( type, fn, false );
- // IE
- } else {
- elem.attachEvent( "on" + type, fn );
- }
-}
-
-/**
- * @param {Array|NodeList} elems
- * @param {string} type
- * @param {Function} fn
- */
-function addEvents( elems, type, fn ) {
- var i = elems.length;
- while ( i-- ) {
- addEvent( elems[i], type, fn );
- }
-}
-
-function hasClass( elem, name ) {
- return (" " + elem.className + " ").indexOf(" " + name + " ") > -1;
-}
-
-function addClass( elem, name ) {
- if ( !hasClass( elem, name ) ) {
- elem.className += (elem.className ? " " : "") + name;
- }
-}
-
-function removeClass( elem, name ) {
- var set = " " + elem.className + " ";
- // Class name may appear multiple times
- while ( set.indexOf(" " + name + " ") > -1 ) {
- set = set.replace(" " + name + " " , " ");
- }
- // If possible, trim it for prettiness, but not neccecarily
- elem.className = window.jQuery ? jQuery.trim( set ) : ( set.trim ? set.trim() : set );
-}
-
-function id( name ) {
- return !!( typeof document !== "undefined" && document && document.getElementById ) &&
- document.getElementById( name );
-}
-
-function registerLoggingCallback( key ) {
- return function( callback ) {
- config[key].push( callback );
- };
-}
-
-// Supports deprecated method of completely overwriting logging callbacks
-function runLoggingCallbacks( key, scope, args ) {
- var i, callbacks;
- if ( QUnit.hasOwnProperty( key ) ) {
- QUnit[ key ].call(scope, args );
- } else {
- callbacks = config[ key ];
- for ( i = 0; i < callbacks.length; i++ ) {
- callbacks[ i ].call( scope, args );
- }
- }
-}
-
-// Test for equality any JavaScript type.
-// Author: Philippe Rathé
-QUnit.equiv = (function() {
-
- // Call the o related callback with the given arguments.
- function bindCallbacks( o, callbacks, args ) {
- var prop = QUnit.objectType( o );
- if ( prop ) {
- if ( QUnit.objectType( callbacks[ prop ] ) === "function" ) {
- return callbacks[ prop ].apply( callbacks, args );
- } else {
- return callbacks[ prop ]; // or undefined
- }
- }
- }
-
- // the real equiv function
- var innerEquiv,
- // stack to decide between skip/abort functions
- callers = [],
- // stack to avoiding loops from circular referencing
- parents = [],
-
- getProto = Object.getPrototypeOf || function ( obj ) {
- return obj.__proto__;
- },
- callbacks = (function () {
-
- // for string, boolean, number and null
- function useStrictEquality( b, a ) {
- /*jshint eqeqeq:false */
- if ( b instanceof a.constructor || a instanceof b.constructor ) {
- // to catch short annotaion VS 'new' annotation of a
- // declaration
- // e.g. var i = 1;
- // var j = new Number(1);
- return a == b;
- } else {
- return a === b;
- }
- }
-
- return {
- "string": useStrictEquality,
- "boolean": useStrictEquality,
- "number": useStrictEquality,
- "null": useStrictEquality,
- "undefined": useStrictEquality,
-
- "nan": function( b ) {
- return isNaN( b );
- },
-
- "date": function( b, a ) {
- return QUnit.objectType( b ) === "date" && a.valueOf() === b.valueOf();
- },
-
- "regexp": function( b, a ) {
- return QUnit.objectType( b ) === "regexp" &&
- // the regex itself
- a.source === b.source &&
- // and its modifers
- a.global === b.global &&
- // (gmi) ...
- a.ignoreCase === b.ignoreCase &&
- a.multiline === b.multiline &&
- a.sticky === b.sticky;
- },
-
- // - skip when the property is a method of an instance (OOP)
- // - abort otherwise,
- // initial === would have catch identical references anyway
- "function": function() {
- var caller = callers[callers.length - 1];
- return caller !== Object && typeof caller !== "undefined";
- },
-
- "array": function( b, a ) {
- var i, j, len, loop;
-
- // b could be an object literal here
- if ( QUnit.objectType( b ) !== "array" ) {
- return false;
- }
-
- len = a.length;
- if ( len !== b.length ) {
- // safe and faster
- return false;
- }
-
- // track reference to avoid circular references
- parents.push( a );
- for ( i = 0; i < len; i++ ) {
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- loop = true;// dont rewalk array
- }
- }
- if ( !loop && !innerEquiv(a[i], b[i]) ) {
- parents.pop();
- return false;
- }
- }
- parents.pop();
- return true;
- },
-
- "object": function( b, a ) {
- var i, j, loop,
- // Default to true
- eq = true,
- aProperties = [],
- bProperties = [];
-
- // comparing constructors is more strict than using
- // instanceof
- if ( a.constructor !== b.constructor ) {
- // Allow objects with no prototype to be equivalent to
- // objects with Object as their constructor.
- if ( !(( getProto(a) === null && getProto(b) === Object.prototype ) ||
- ( getProto(b) === null && getProto(a) === Object.prototype ) ) ) {
- return false;
- }
- }
-
- // stack constructor before traversing properties
- callers.push( a.constructor );
- // track reference to avoid circular references
- parents.push( a );
-
- for ( i in a ) { // be strict: don't ensures hasOwnProperty
- // and go deep
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- // don't go down the same path twice
- loop = true;
- }
- }
- aProperties.push(i); // collect a's properties
-
- if (!loop && !innerEquiv( a[i], b[i] ) ) {
- eq = false;
- break;
- }
- }
-
- callers.pop(); // unstack, we are done
- parents.pop();
-
- for ( i in b ) {
- bProperties.push( i ); // collect b's properties
- }
-
- // Ensures identical properties name
- return eq && innerEquiv( aProperties.sort(), bProperties.sort() );
- }
- };
- }());
-
- innerEquiv = function() { // can take multiple arguments
- var args = [].slice.apply( arguments );
- if ( args.length < 2 ) {
- return true; // end transition
- }
-
- return (function( a, b ) {
- if ( a === b ) {
- return true; // catch the most you can
- } else if ( a === null || b === null || typeof a === "undefined" ||
- typeof b === "undefined" ||
- QUnit.objectType(a) !== QUnit.objectType(b) ) {
- return false; // don't lose time with error prone cases
- } else {
- return bindCallbacks(a, callbacks, [ b, a ]);
- }
-
- // apply transition with (1..n) arguments
- }( args[0], args[1] ) && arguments.callee.apply( this, args.splice(1, args.length - 1 )) );
- };
-
- return innerEquiv;
-}());
-
-/**
- * jsDump Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com |
- * http://flesler.blogspot.com Licensed under BSD
- * (http://www.opensource.org/licenses/bsd-license.php) Date: 5/15/2008
- *
- * @projectDescription Advanced and extensible data dumping for Javascript.
- * @version 1.0.0
- * @author Ariel Flesler
- * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html}
- */
-QUnit.jsDump = (function() {
- function quote( str ) {
- return '"' + str.toString().replace( /"/g, '\\"' ) + '"';
- }
- function literal( o ) {
- return o + "";
- }
- function join( pre, arr, post ) {
- var s = jsDump.separator(),
- base = jsDump.indent(),
- inner = jsDump.indent(1);
- if ( arr.join ) {
- arr = arr.join( "," + s + inner );
- }
- if ( !arr ) {
- return pre + post;
- }
- return [ pre, inner + arr, base + post ].join(s);
- }
- function array( arr, stack ) {
- var i = arr.length, ret = new Array(i);
- this.up();
- while ( i-- ) {
- ret[i] = this.parse( arr[i] , undefined , stack);
- }
- this.down();
- return join( "[", ret, "]" );
- }
-
- var reName = /^function (\w+)/,
- jsDump = {
- // type is used mostly internally, you can fix a (custom)type in advance
- parse: function( obj, type, stack ) {
- stack = stack || [ ];
- var inStack, res,
- parser = this.parsers[ type || this.typeOf(obj) ];
-
- type = typeof parser;
- inStack = inArray( obj, stack );
-
- if ( inStack !== -1 ) {
- return "recursion(" + (inStack - stack.length) + ")";
- }
- if ( type === "function" ) {
- stack.push( obj );
- res = parser.call( this, obj, stack );
- stack.pop();
- return res;
- }
- return ( type === "string" ) ? parser : this.parsers.error;
- },
- typeOf: function( obj ) {
- var type;
- if ( obj === null ) {
- type = "null";
- } else if ( typeof obj === "undefined" ) {
- type = "undefined";
- } else if ( QUnit.is( "regexp", obj) ) {
- type = "regexp";
- } else if ( QUnit.is( "date", obj) ) {
- type = "date";
- } else if ( QUnit.is( "function", obj) ) {
- type = "function";
- } else if ( typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined" ) {
- type = "window";
- } else if ( obj.nodeType === 9 ) {
- type = "document";
- } else if ( obj.nodeType ) {
- type = "node";
- } else if (
- // native arrays
- toString.call( obj ) === "[object Array]" ||
- // NodeList objects
- ( typeof obj.length === "number" && typeof obj.item !== "undefined" && ( obj.length ? obj.item(0) === obj[0] : ( obj.item( 0 ) === null && typeof obj[0] === "undefined" ) ) )
- ) {
- type = "array";
- } else if ( obj.constructor === Error.prototype.constructor ) {
- type = "error";
- } else {
- type = typeof obj;
- }
- return type;
- },
- separator: function() {
- return this.multiline ? this.HTML ? "
" : "\n" : this.HTML ? " " : " ";
- },
- // extra can be a number, shortcut for increasing-calling-decreasing
- indent: function( extra ) {
- if ( !this.multiline ) {
- return "";
- }
- var chr = this.indentChar;
- if ( this.HTML ) {
- chr = chr.replace( /\t/g, " " ).replace( / /g, " " );
- }
- return new Array( this._depth_ + (extra||0) ).join(chr);
- },
- up: function( a ) {
- this._depth_ += a || 1;
- },
- down: function( a ) {
- this._depth_ -= a || 1;
- },
- setParser: function( name, parser ) {
- this.parsers[name] = parser;
- },
- // The next 3 are exposed so you can use them
- quote: quote,
- literal: literal,
- join: join,
- //
- _depth_: 1,
- // This is the list of parsers, to modify them, use jsDump.setParser
- parsers: {
- window: "[Window]",
- document: "[Document]",
- error: function(error) {
- return "Error(\"" + error.message + "\")";
- },
- unknown: "[Unknown]",
- "null": "null",
- "undefined": "undefined",
- "function": function( fn ) {
- var ret = "function",
- // functions never have name in IE
- name = "name" in fn ? fn.name : (reName.exec(fn) || [])[1];
-
- if ( name ) {
- ret += " " + name;
- }
- ret += "( ";
-
- ret = [ ret, QUnit.jsDump.parse( fn, "functionArgs" ), "){" ].join( "" );
- return join( ret, QUnit.jsDump.parse(fn,"functionCode" ), "}" );
- },
- array: array,
- nodelist: array,
- "arguments": array,
- object: function( map, stack ) {
- var ret = [ ], keys, key, val, i;
- QUnit.jsDump.up();
- keys = [];
- for ( key in map ) {
- keys.push( key );
- }
- keys.sort();
- for ( i = 0; i < keys.length; i++ ) {
- key = keys[ i ];
- val = map[ key ];
- ret.push( QUnit.jsDump.parse( key, "key" ) + ": " + QUnit.jsDump.parse( val, undefined, stack ) );
- }
- QUnit.jsDump.down();
- return join( "{", ret, "}" );
- },
- node: function( node ) {
- var len, i, val,
- open = QUnit.jsDump.HTML ? "<" : "<",
- close = QUnit.jsDump.HTML ? ">" : ">",
- tag = node.nodeName.toLowerCase(),
- ret = open + tag,
- attrs = node.attributes;
-
- if ( attrs ) {
- for ( i = 0, len = attrs.length; i < len; i++ ) {
- val = attrs[i].nodeValue;
- // IE6 includes all attributes in .attributes, even ones not explicitly set.
- // Those have values like undefined, null, 0, false, "" or "inherit".
- if ( val && val !== "inherit" ) {
- ret += " " + attrs[i].nodeName + "=" + QUnit.jsDump.parse( val, "attribute" );
- }
- }
- }
- ret += close;
-
- // Show content of TextNode or CDATASection
- if ( node.nodeType === 3 || node.nodeType === 4 ) {
- ret += node.nodeValue;
- }
-
- return ret + open + "/" + tag + close;
- },
- // function calls it internally, it's the arguments part of the function
- functionArgs: function( fn ) {
- var args,
- l = fn.length;
-
- if ( !l ) {
- return "";
- }
-
- args = new Array(l);
- while ( l-- ) {
- // 97 is 'a'
- args[l] = String.fromCharCode(97+l);
- }
- return " " + args.join( ", " ) + " ";
- },
- // object calls it internally, the key part of an item in a map
- key: quote,
- // function calls it internally, it's the content of the function
- functionCode: "[code]",
- // node calls it internally, it's an html attribute value
- attribute: quote,
- string: quote,
- date: quote,
- regexp: literal,
- number: literal,
- "boolean": literal
- },
- // if true, entities are escaped ( <, >, \t, space and \n )
- HTML: false,
- // indentation unit
- indentChar: " ",
- // if true, items in a collection, are separated by a \n, else just a space.
- multiline: true
- };
-
- return jsDump;
-}());
-
-// from jquery.js
-function inArray( elem, array ) {
- if ( array.indexOf ) {
- return array.indexOf( elem );
- }
-
- for ( var i = 0, length = array.length; i < length; i++ ) {
- if ( array[ i ] === elem ) {
- return i;
- }
- }
-
- return -1;
-}
-
-/*
- * Javascript Diff Algorithm
- * By John Resig (http://ejohn.org/)
- * Modified by Chu Alan "sprite"
- *
- * Released under the MIT license.
- *
- * More Info:
- * http://ejohn.org/projects/javascript-diff-algorithm/
- *
- * Usage: QUnit.diff(expected, actual)
- *
- * QUnit.diff( "the quick brown fox jumped over", "the quick fox jumps over" ) == "the quick brown fox jumped jumps over"
- */
-QUnit.diff = (function() {
- /*jshint eqeqeq:false, eqnull:true */
- function diff( o, n ) {
- var i,
- ns = {},
- os = {};
-
- for ( i = 0; i < n.length; i++ ) {
- if ( !hasOwn.call( ns, n[i] ) ) {
- ns[ n[i] ] = {
- rows: [],
- o: null
- };
- }
- ns[ n[i] ].rows.push( i );
- }
-
- for ( i = 0; i < o.length; i++ ) {
- if ( !hasOwn.call( os, o[i] ) ) {
- os[ o[i] ] = {
- rows: [],
- n: null
- };
- }
- os[ o[i] ].rows.push( i );
- }
-
- for ( i in ns ) {
- if ( !hasOwn.call( ns, i ) ) {
- continue;
- }
- if ( ns[i].rows.length === 1 && hasOwn.call( os, i ) && os[i].rows.length === 1 ) {
- n[ ns[i].rows[0] ] = {
- text: n[ ns[i].rows[0] ],
- row: os[i].rows[0]
- };
- o[ os[i].rows[0] ] = {
- text: o[ os[i].rows[0] ],
- row: ns[i].rows[0]
- };
- }
- }
-
- for ( i = 0; i < n.length - 1; i++ ) {
- if ( n[i].text != null && n[ i + 1 ].text == null && n[i].row + 1 < o.length && o[ n[i].row + 1 ].text == null &&
- n[ i + 1 ] == o[ n[i].row + 1 ] ) {
-
- n[ i + 1 ] = {
- text: n[ i + 1 ],
- row: n[i].row + 1
- };
- o[ n[i].row + 1 ] = {
- text: o[ n[i].row + 1 ],
- row: i + 1
- };
- }
- }
-
- for ( i = n.length - 1; i > 0; i-- ) {
- if ( n[i].text != null && n[ i - 1 ].text == null && n[i].row > 0 && o[ n[i].row - 1 ].text == null &&
- n[ i - 1 ] == o[ n[i].row - 1 ]) {
-
- n[ i - 1 ] = {
- text: n[ i - 1 ],
- row: n[i].row - 1
- };
- o[ n[i].row - 1 ] = {
- text: o[ n[i].row - 1 ],
- row: i - 1
- };
- }
- }
-
- return {
- o: o,
- n: n
- };
- }
-
- return function( o, n ) {
- o = o.replace( /\s+$/, "" );
- n = n.replace( /\s+$/, "" );
-
- var i, pre,
- str = "",
- out = diff( o === "" ? [] : o.split(/\s+/), n === "" ? [] : n.split(/\s+/) ),
- oSpace = o.match(/\s+/g),
- nSpace = n.match(/\s+/g);
-
- if ( oSpace == null ) {
- oSpace = [ " " ];
- }
- else {
- oSpace.push( " " );
- }
-
- if ( nSpace == null ) {
- nSpace = [ " " ];
- }
- else {
- nSpace.push( " " );
- }
-
- if ( out.n.length === 0 ) {
- for ( i = 0; i < out.o.length; i++ ) {
- str += "" + out.o[i] + oSpace[i] + "";
- }
- }
- else {
- if ( out.n[0].text == null ) {
- for ( n = 0; n < out.o.length && out.o[n].text == null; n++ ) {
- str += "" + out.o[n] + oSpace[n] + "";
- }
- }
-
- for ( i = 0; i < out.n.length; i++ ) {
- if (out.n[i].text == null) {
- str += "" + out.n[i] + nSpace[i] + "";
- }
- else {
- // `pre` initialized at top of scope
- pre = "";
-
- for ( n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++ ) {
- pre += "" + out.o[n] + oSpace[n] + "";
- }
- str += " " + out.n[i].text + nSpace[i] + pre;
- }
- }
- }
-
- return str;
- };
-}());
-
-// for CommonJS enviroments, export everything
-if ( typeof exports !== "undefined" ) {
- extend( exports, QUnit );
-}
-
-// get at whatever the global object is, like window in browsers
-}( (function() {return this;}.call()) ));
diff --git a/test/lib/require.js b/test/lib/require.js
deleted file mode 100644
index 987f865..0000000
--- a/test/lib/require.js
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- RequireJS 2.1.5 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.
- Available via the MIT or new BSD license.
- see: http://github.com/jrburke/requirejs for details
-*/
-var requirejs,require,define;
-(function(aa){function I(b){return"[object Function]"===L.call(b)}function J(b){return"[object Array]"===L.call(b)}function y(b,c){if(b){var d;for(d=0;dthis.depCount&&!this.defined){if(I(n)){if(this.events.error)try{e=i.execCb(c,n,b,e)}catch(d){a=d}else e=i.execCb(c,n,b,e);this.map.isDefine&&((b=this.module)&&void 0!==b.exports&&b.exports!==this.exports?e=b.exports:void 0===e&&this.usingExports&&(e=this.exports));if(a)return a.requireMap=this.map,a.requireModules=[this.map.id],a.requireType="define",v(this.error=
-a)}else e=n;this.exports=e;if(this.map.isDefine&&!this.ignore&&(q[c]=e,l.onResourceLoad))l.onResourceLoad(i,this.map,this.depMaps);x(c);this.defined=!0}this.defining=!1;this.defined&&!this.defineEmitted&&(this.defineEmitted=!0,this.emit("defined",this.exports),this.defineEmitComplete=!0)}}else this.fetch()}},callPlugin:function(){var a=this.map,b=a.id,d=j(a.prefix);this.depMaps.push(d);t(d,"defined",u(this,function(e){var n,d;d=this.map.name;var g=this.map.parentMap?this.map.parentMap.name:null,h=
-i.makeRequire(a.parentMap,{enableBuildCallback:!0});if(this.map.unnormalized){if(e.normalize&&(d=e.normalize(d,function(a){return c(a,g,!0)})||""),e=j(a.prefix+"!"+d,this.map.parentMap),t(e,"defined",u(this,function(a){this.init([],function(){return a},null,{enabled:!0,ignore:!0})})),d=m(p,e.id)){this.depMaps.push(e);if(this.events.error)d.on("error",u(this,function(a){this.emit("error",a)}));d.enable()}}else n=u(this,function(a){this.init([],function(){return a},null,{enabled:!0})}),n.error=u(this,
-function(a){this.inited=!0;this.error=a;a.requireModules=[b];G(p,function(a){0===a.map.id.indexOf(b+"_unnormalized")&&x(a.map.id)});v(a)}),n.fromText=u(this,function(e,c){var d=a.name,g=j(d),C=O;c&&(e=c);C&&(O=!1);r(g);s(k.config,b)&&(k.config[d]=k.config[b]);try{l.exec(e)}catch(ca){return v(B("fromtexteval","fromText eval for "+b+" failed: "+ca,ca,[b]))}C&&(O=!0);this.depMaps.push(g);i.completeLoad(d);h([d],n)}),e.load(a.name,h,n,k)}));i.enable(d,this);this.pluginMaps[d.id]=d},enable:function(){V[this.map.id]=
-this;this.enabling=this.enabled=!0;y(this.depMaps,u(this,function(a,b){var c,e;if("string"===typeof a){a=j(a,this.map.isDefine?this.map:this.map.parentMap,!1,!this.skipMap);this.depMaps[b]=a;if(c=m(N,a.id)){this.depExports[b]=c(this);return}this.depCount+=1;t(a,"defined",u(this,function(a){this.defineDep(b,a);this.check()}));this.errback&&t(a,"error",this.errback)}c=a.id;e=p[c];!s(N,c)&&(e&&!e.enabled)&&i.enable(a,this)}));G(this.pluginMaps,u(this,function(a){var b=m(p,a.id);b&&!b.enabled&&i.enable(a,
-this)}));this.enabling=!1;this.check()},on:function(a,b){var c=this.events[a];c||(c=this.events[a]=[]);c.push(b)},emit:function(a,b){y(this.events[a],function(a){a(b)});"error"===a&&delete this.events[a]}};i={config:k,contextName:b,registry:p,defined:q,urlFetched:U,defQueue:H,Module:Z,makeModuleMap:j,nextTick:l.nextTick,onError:v,configure:function(a){a.baseUrl&&"/"!==a.baseUrl.charAt(a.baseUrl.length-1)&&(a.baseUrl+="/");var b=k.pkgs,c=k.shim,e={paths:!0,config:!0,map:!0};G(a,function(a,b){e[b]?
-"map"===b?(k.map||(k.map={}),R(k[b],a,!0,!0)):R(k[b],a,!0):k[b]=a});a.shim&&(G(a.shim,function(a,b){J(a)&&(a={deps:a});if((a.exports||a.init)&&!a.exportsFn)a.exportsFn=i.makeShimExports(a);c[b]=a}),k.shim=c);a.packages&&(y(a.packages,function(a){a="string"===typeof a?{name:a}:a;b[a.name]={name:a.name,location:a.location||a.name,main:(a.main||"main").replace(ja,"").replace(ea,"")}}),k.pkgs=b);G(p,function(a,b){!a.inited&&!a.map.unnormalized&&(a.map=j(b))});if(a.deps||a.callback)i.require(a.deps||[],
-a.callback)},makeShimExports:function(a){return function(){var b;a.init&&(b=a.init.apply(aa,arguments));return b||a.exports&&ba(a.exports)}},makeRequire:function(a,f){function d(e,c,h){var g,k;f.enableBuildCallback&&(c&&I(c))&&(c.__requireJsBuild=!0);if("string"===typeof e){if(I(c))return v(B("requireargs","Invalid require call"),h);if(a&&s(N,e))return N[e](p[a.id]);if(l.get)return l.get(i,e,a,d);g=j(e,a,!1,!0);g=g.id;return!s(q,g)?v(B("notloaded",'Module name "'+g+'" has not been loaded yet for context: '+
-b+(a?"":". Use require([])"))):q[g]}L();i.nextTick(function(){L();k=r(j(null,a));k.skipMap=f.skipMap;k.init(e,c,h,{enabled:!0});D()});return d}f=f||{};R(d,{isBrowser:A,toUrl:function(b){var d,f=b.lastIndexOf("."),g=b.split("/")[0];if(-1!==f&&(!("."===g||".."===g)||1h.attachEvent.toString().indexOf("[native code"))&&!Y?(O=!0,h.attachEvent("onreadystatechange",b.onScriptLoad)):(h.addEventListener("load",b.onScriptLoad,!1),h.addEventListener("error",b.onScriptError,!1)),h.src=d,K=h,D?x.insertBefore(h,D):x.appendChild(h),K=null,h;if(da)try{importScripts(d),b.completeLoad(c)}catch(j){b.onError(B("importscripts","importScripts failed for "+c+" at "+d,j,[c]))}};A&&M(document.getElementsByTagName("script"),function(b){x||(x=
-b.parentNode);if(t=b.getAttribute("data-main"))return r.baseUrl||(E=t.split("/"),Q=E.pop(),fa=E.length?E.join("/")+"/":"./",r.baseUrl=fa,t=Q),t=t.replace(ea,""),r.deps=r.deps?r.deps.concat(t):[t],!0});define=function(b,c,d){var l,h;"string"!==typeof b&&(d=c,c=b,b=null);J(c)||(d=c,c=[]);!c.length&&I(d)&&d.length&&(d.toString().replace(la,"").replace(ma,function(b,d){c.push(d)}),c=(1===d.length?["require"]:["require","exports","module"]).concat(c));if(O){if(!(l=K))P&&"interactive"===P.readyState||M(document.getElementsByTagName("script"),
-function(b){if("interactive"===b.readyState)return P=b}),l=P;l&&(b||(b=l.getAttribute("data-requiremodule")),h=F[l.getAttribute("data-requirecontext")])}(h?h.defQueue:T).push([b,c,d])};define.amd={jQuery:!0};l.exec=function(b){return eval(b)};l(r)}})(this);
diff --git a/test/lib/resemble.js b/test/lib/resemble.js
new file mode 100644
index 0000000..1cb8c29
--- /dev/null
+++ b/test/lib/resemble.js
@@ -0,0 +1,535 @@
+/*
+Author: James Cryer
+Company: Huddle
+Last updated date: 21 Feb 2013
+URL: https://github.com/Huddle/Resemble.js
+*/
+
+(function(_this){
+ 'use strict';
+
+ _this['resemble'] = function( fileData ){
+
+ var data = {};
+ var images = [];
+ var updateCallbackArray = [];
+
+ var tolerance = { // between 0 and 255
+ red: 16,
+ green: 16,
+ blue: 16,
+ minBrightness: 16,
+ maxBrightness: 240
+ };
+
+ var ignoreAntialiasing = false;
+ var ignoreColors = false;
+
+ function triggerDataUpdate(){
+ var len = updateCallbackArray.length;
+ var i;
+ for(i=0;i tolerance.maxBrightness;
+ }
+
+ function getHue(r,g,b){
+
+ r = r / 255;
+ g = g / 255;
+ b = b / 255;
+ var max = Math.max(r, g, b), min = Math.min(r, g, b);
+ var h;
+ var d;
+
+ if (max == min){
+ h = 0; // achromatic
+ } else{
+ d = max - min;
+ switch(max){
+ case r: h = (g - b) / d + (g < b ? 6 : 0); break;
+ case g: h = (b - r) / d + 2; break;
+ case b: h = (r - g) / d + 4; break;
+ }
+ h /= 6;
+ }
+
+ return h;
+ }
+
+ function isAntialiased(sourcePix, data, cacheSet, verticalPos, horizontalPos, width){
+ var offset;
+ var targetPix;
+ var distance = 1;
+ var i;
+ var j;
+ var hasHighContrastSibling = 0;
+ var hasSiblingWithDifferentHue = 0;
+ var hasEquivilantSibling = 0;
+
+ addHueInfo(sourcePix);
+
+ for (i = distance*-1; i <= distance; i++){
+ for (j = distance*-1; j <= distance; j++){
+
+ if(i===0 && j===0){
+ // ignore source pixel
+ } else {
+
+ offset = ((verticalPos+j)*width + (horizontalPos+i)) * 4;
+ targetPix = getPixelInfo(data, offset, cacheSet);
+
+ if(targetPix === null){
+ continue;
+ }
+
+ addBrightnessInfo(targetPix);
+ addHueInfo(targetPix);
+
+ if( isContrasting(sourcePix, targetPix) ){
+ hasHighContrastSibling++;
+ }
+
+ if( isRGBSame(sourcePix,targetPix) ){
+ hasEquivilantSibling++;
+ }
+
+ if( Math.abs(targetPix.h - sourcePix.h) > 0.3 ){
+ hasSiblingWithDifferentHue++;
+ }
+
+ if( hasSiblingWithDifferentHue > 1 || hasHighContrastSibling > 1){
+ return true;
+ }
+ }
+ }
+ }
+
+ if(hasEquivilantSibling < 2){
+ return true;
+ }
+
+ return false;
+ }
+
+ function errorPixel(px, offset){
+ px[offset] = 255; //r
+ px[offset + 1] = 0; //g
+ px[offset + 2] = 255; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyPixel(px, offset, data){
+ px[offset] = data.r; //r
+ px[offset + 1] = data.g; //g
+ px[offset + 2] = data.b; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyGrayScalePixel(px, offset, data){
+ px[offset] = data.brightness; //r
+ px[offset + 1] = data.brightness; //g
+ px[offset + 2] = data.brightness; //b
+ px[offset + 3] = 255; //a
+ }
+
+
+ function getPixelInfo(data, offset, cacheSet){
+ var r;
+ var g;
+ var b;
+ var d;
+
+ if(typeof data[offset] !== 'undefined'){
+ r = data[offset];
+ g = data[offset+1];
+ b = data[offset+2];
+ d = {
+ r: r,
+ g: g,
+ b: b
+ };
+
+ return d;
+ } else {
+ return null;
+ }
+ }
+
+ function addBrightnessInfo(data){
+ data.brightness = getBrightness(data.r,data.g,data.b); // 'corrected' lightness
+ }
+
+ function addHueInfo(data){
+ data.h = getHue(data.r,data.g,data.b);
+ }
+
+ function analyseImages(img1, img2, width, height){
+
+ var hiddenCanvas = document.createElement('canvas');
+
+ var data1 = img1.data;
+ var data2 = img2.data;
+
+ hiddenCanvas.width = width;
+ hiddenCanvas.height = height;
+
+ var context = hiddenCanvas.getContext('2d');
+ var imgd = context.createImageData(width,height);
+ var targetPix = imgd.data;
+
+ var mismatchCount = 0;
+
+ var time = Date.now();
+
+ var skip;
+
+ if( (width > 1200 || height > 1200) && ignoreAntialiasing){
+ skip = 6;
+ }
+
+ loop(height, width, function(verticalPos, horizontalPos){
+
+ if(skip){ // only skip if the image isn't small
+ if(verticalPos % skip === 0 || horizontalPos % skip === 0){
+ return;
+ }
+ }
+
+ var offset = (verticalPos*width + horizontalPos) * 4;
+ var pixel1 = getPixelInfo(data1, offset, 1);
+ var pixel2 = getPixelInfo(data2, offset, 2);
+
+ if(pixel1 === null || pixel2 === null){
+ return;
+ }
+
+ if (ignoreColors){
+
+ addBrightnessInfo(pixel1);
+ addBrightnessInfo(pixel2);
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ return;
+ }
+
+ if( isRGBSimilar(pixel1, pixel2) ){
+ copyPixel(targetPix, offset, pixel2);
+
+ } else if( ignoreAntialiasing && (
+ addBrightnessInfo(pixel1), // jit pixel info augmentation looks a little weird, sorry.
+ addBrightnessInfo(pixel2),
+ isAntialiased(pixel1, data1, 1, verticalPos, horizontalPos, width) ||
+ isAntialiased(pixel2, data2, 2, verticalPos, horizontalPos, width)
+ )){
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+
+ });
+
+ data.misMatchPercentage = (mismatchCount / (height*width) * 100).toFixed(2);
+ data.analysisTime = Date.now() - time;
+
+ data.getImageDataUrl = function(text){
+ var barHeight = 0;
+
+ if(text){
+ barHeight = addLabel(text,context,hiddenCanvas);
+ }
+
+ context.putImageData(imgd, 0, barHeight);
+
+ return hiddenCanvas.toDataURL("image/png");
+ };
+ }
+
+ function addLabel(text, context, hiddenCanvas){
+ var textPadding = 2;
+
+ context.font = '12px sans-serif';
+
+ var textWidth = context.measureText(text).width + textPadding*2;
+ var barHeight = 22;
+
+ if(textWidth > hiddenCanvas.width){
+ hiddenCanvas.width = textWidth;
+ }
+
+ hiddenCanvas.height += barHeight;
+
+ context.fillStyle = "#666";
+ context.fillRect(0,0,hiddenCanvas.width,barHeight -4);
+ context.fillStyle = "#fff";
+ context.fillRect(0,barHeight -4,hiddenCanvas.width, 4);
+
+ context.fillStyle = "#fff";
+ context.textBaseline = "top";
+ context.font = '12px sans-serif';
+ context.fillText(text, textPadding, 1);
+
+ return barHeight;
+ }
+
+ function normalise(img, w, h){
+ var c;
+ var context;
+
+ if(img.height < h || img.width < w){
+ c = document.createElement('canvas');
+ c.width = w;
+ c.height = h;
+ context = c.getContext('2d');
+ context.putImageData(img, 0, 0);
+ return context.getImageData(0, 0, w, h);
+ }
+
+ return img;
+ }
+
+ function compare(one, two){
+
+ function onceWeHaveBoth(){
+ var width;
+ var height;
+ if(images.length === 2){
+ width = images[0].width > images[1].width ? images[0].width : images[1].width;
+ height = images[0].height > images[1].height ? images[0].height : images[1].height;
+
+ if( (images[0].width === images[1].width) && (images[0].height === images[1].height) ){
+ data.isSameDimensions = true;
+ } else {
+ data.isSameDimensions = false;
+ }
+
+ analyseImages( normalise(images[0],width, height), normalise(images[1],width, height), width, height);
+
+ triggerDataUpdate();
+ }
+ }
+
+ images = [];
+ loadImageData(one, onceWeHaveBoth);
+ loadImageData(two, onceWeHaveBoth);
+ }
+
+ function getCompareApi(param){
+
+ var secondFileData,
+ hasMethod = typeof param === 'function';
+
+ if( !hasMethod ){
+ // assume it's file data
+ secondFileData = param;
+ }
+
+ var self = {
+ ignoreNothing: function(){
+
+ tolerance.red = 16;
+ tolerance.green = 16;
+ tolerance.blue = 16;
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreAntialiasing: function(){
+
+ tolerance.red = 32;
+ tolerance.green = 32;
+ tolerance.blue = 32;
+ tolerance.minBrightness = 64;
+ tolerance.maxBrightness = 96;
+
+ ignoreAntialiasing = true;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreColors: function(){
+
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = true;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ onComplete: function( callback ){
+
+ updateCallbackArray.push(callback);
+
+ var wrapper = function(){
+ compare(fileData, secondFileData);
+ };
+
+ wrapper();
+
+ return getCompareApi(wrapper);
+ }
+ };
+
+ return self;
+ }
+
+ return {
+ onComplete: function( callback ){
+ updateCallbackArray.push(callback);
+ loadImageData(fileData, function(imageData, width, height){
+ parseImage(imageData.data, width, height);
+ });
+ },
+ compareTo: function(secondFileData){
+ return getCompareApi(secondFileData);
+ }
+ };
+
+ };
+}(this));
\ No newline at end of file
diff --git a/test/testsuite.js b/test/testsuite.js
deleted file mode 100644
index b486acb..0000000
--- a/test/testsuite.js
+++ /dev/null
@@ -1,36 +0,0 @@
-requirejs.config({
- baseUrl: '/test/unit/'
-});
-
-define(function(require) {
- var testModules = [
- 'Pixi',
- 'Point',
- 'Rectangle',
- 'DisplayObject',
- 'DisplayObjectContainer',
- 'Sprite',
- 'MovieClip',
- 'InteractionManager',
- 'Stage',
- 'utils/Utils',
- 'utils/EventTarget',
- 'utils/Matrix',
- 'utils/Detector',
- 'renderers/WebGLShaders',
- 'renderers/WebGLRenderer',
- 'renderers/WebGLBatch',
- 'renderers/CanvasRenderer',
- 'extras/Strip',
- 'extras/Rope',
- 'textures/BaseTexture',
- 'textures/Texture',
- 'loaders/SpriteSheetLoader',
- 'loaders/AssetLoader'
- ];
-
- // Resolve all testModules and then start the Test Runner.
- require(testModules, function() {
- QUnit.start();
- });
-});
\ No newline at end of file
diff --git a/test/textures/SpriteSheet-Aliens.png b/test/textures/SpriteSheet-Aliens.png
new file mode 100644
index 0000000..210acb1
--- /dev/null
+++ b/test/textures/SpriteSheet-Aliens.png
Binary files differ
diff --git a/test/textures/SpriteSheet-Explosion.png b/test/textures/SpriteSheet-Explosion.png
new file mode 100755
index 0000000..79e1a69
--- /dev/null
+++ b/test/textures/SpriteSheet-Explosion.png
Binary files differ
diff --git a/test/textures/bunny.png b/test/textures/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/textures/bunny.png
Binary files differ
diff --git a/test/unit/DisplayObject.js b/test/unit/DisplayObject.js
deleted file mode 100644
index 5e7e72f..0000000
--- a/test/unit/DisplayObject.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObject');
-});
diff --git a/test/unit/DisplayObjectContainer.js b/test/unit/DisplayObjectContainer.js
deleted file mode 100644
index b323959..0000000
--- a/test/unit/DisplayObjectContainer.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObjectContainer');
-});
diff --git a/test/unit/InteractionManager.js b/test/unit/InteractionManager.js
deleted file mode 100644
index e751f52..0000000
--- a/test/unit/InteractionManager.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('InteractionManager');
-});
diff --git a/test/unit/MovieClip.js b/test/unit/MovieClip.js
deleted file mode 100644
index 37d9446..0000000
--- a/test/unit/MovieClip.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('MovieClip');
-});
diff --git a/test/unit/Pixi.js b/test/unit/Pixi.js
deleted file mode 100644
index 36eee73..0000000
--- a/test/unit/Pixi.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Pixi');
-});
diff --git a/test/unit/Point.js b/test/unit/Point.js
deleted file mode 100644
index 983ff6e..0000000
--- a/test/unit/Point.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Point');
-});
diff --git a/test/unit/Rectangle.js b/test/unit/Rectangle.js
deleted file mode 100644
index 3b439ba..0000000
--- a/test/unit/Rectangle.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Rectangle');
-});
diff --git a/test/unit/Sprite.js b/test/unit/Sprite.js
deleted file mode 100644
index ed4f596..0000000
--- a/test/unit/Sprite.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Sprite');
-});
diff --git a/test/unit/Stage.js b/test/unit/Stage.js
deleted file mode 100644
index 2d70291..0000000
--- a/test/unit/Stage.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Stage');
-});
diff --git a/test/unit/extras/Rope.js b/test/unit/extras/Rope.js
deleted file mode 100644
index 5606f14..0000000
--- a/test/unit/extras/Rope.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Rope');
-});
diff --git a/test/unit/extras/Strip.js b/test/unit/extras/Strip.js
deleted file mode 100644
index 0134d3a..0000000
--- a/test/unit/extras/Strip.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Strip');
-});
diff --git a/test/unit/loaders/AssetLoader.js b/test/unit/loaders/AssetLoader.js
deleted file mode 100644
index 13b8443..0000000
--- a/test/unit/loaders/AssetLoader.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('AssetLoader');
-});
diff --git a/test/unit/loaders/SpriteSheetLoader.js b/test/unit/loaders/SpriteSheetLoader.js
deleted file mode 100644
index 8bf0cb2..0000000
--- a/test/unit/loaders/SpriteSheetLoader.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('SpriteSheetLoader');
-});
diff --git a/.gitignore b/.gitignore
index 12e1b62..0b88317 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
node_modules
.DS_Store
-.project
\ No newline at end of file
+.project
+*.log
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..63e4d7c
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,8 @@
+language: node_js
+node_js:
+ - 0.10
+
+before_script:
+ - npm install -g grunt-cli
+ - export DISPLAY=:99.0
+ - sh -e /etc/init.d/xvfb start
diff --git a/Gruntfile.js b/Gruntfile.js
index b083b49..103938c 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -1,10 +1,12 @@
+'use strict';
+
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-connect');
- grunt.loadNpmTasks('grunt-contrib-qunit');
grunt.loadNpmTasks('grunt-contrib-yuidoc');
+ grunt.loadTasks('tasks');
var root = 'src/pixi/',
debug = 'bin/pixi.dev.js',
@@ -79,7 +81,7 @@
},
files: {
srcBlob: '<%= dirs.src %>/**/*.js',
- testBlob: '<%= dirs.test %>/unit/**/*.js',
+ testBlob: '<%= dirs.test %>/{functional,lib/pixi,unit}/**/*.js',
build: '<%= dirs.build %>/pixi.dev.js',
buildMin: '<%= dirs.build %>/pixi.js'
},
@@ -94,7 +96,12 @@
},
jshint: {
beforeconcat: srcFiles,
- test: ['<%= files.testBlob %>'],
+ test: {
+ src: ['<%= files.testBlob %>'],
+ options: {
+ expr: true
+ }
+ },
options: {
asi: true,
smarttabs: true
@@ -128,12 +135,6 @@
]
},
connect: {
- qunit: {
- options: {
- port: grunt.option('port-test') || 9002,
- base: './'
- }
- },
test: {
options: {
port: grunt.option('port-test') || 9002,
@@ -142,13 +143,6 @@
}
}
},
- qunit: {
- all: {
- options: {
- urls: ['http://localhost:' + (grunt.option('port-test') || 9002) + '/test/index.html']
- }
- }
- },
yuidoc: {
compile: {
name: '<%= pkg.name %>',
@@ -161,6 +155,13 @@
outdir: '<%= dirs.docs %>'
}
}
+ },
+ karma: {
+ unit: {
+ configFile: 'test/karma.conf.js',
+ // browsers: ['Chrome'],
+ singleRun: true
+ }
}
});
@@ -182,9 +183,10 @@
}
)
- grunt.registerTask('default', ['concat', 'uglify', 'distribute']);
grunt.registerTask('build', ['concat', 'uglify', 'distribute']);
- grunt.registerTask('test', ['build', 'connect:qunit', 'qunit']);
+ grunt.registerTask('test', ['concat', 'jshint:test', 'karma']);
grunt.registerTask('docs', ['yuidoc']);
-
-}
\ No newline at end of file
+ grunt.registerTask('default', ['test', 'uglify', 'distribute']);
+ // Travis CI task.
+ grunt.registerTask('travis', ['test']);
+}
diff --git a/README.md b/README.md
index c62ef86..690cfe4 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,8 @@

+[](http://travis-ci.org/drkibitz/pixi.js)
+
#### JavaScript 2D Renderer ####
The aim of this project is to provide a fast lightweight 2D library that works
diff --git a/package.json b/package.json
index b373240..1246a68 100644
--- a/package.json
+++ b/package.json
@@ -18,14 +18,21 @@
"main": "bin/pixi.js",
+ "scripts": {
+ "test": "grunt travis --verbose"
+ },
+
"dependencies": {},
"devDependencies": {
"grunt": "~0.4.x",
- "grunt-contrib-jshint": "0.3.x",
+ "grunt-contrib-jshint": "0.6.x",
"grunt-contrib-uglify": "0.2.x",
- "grunt-contrib-connect": "0.2.x",
- "grunt-contrib-qunit": "0.2.x",
+ "grunt-contrib-connect": "0.3.x",
"grunt-contrib-yuidoc": "0.4.x",
- "grunt-contrib-concat": "0.1.x"
+ "grunt-contrib-concat": "0.3.x",
+ "chai": "~1.7.0",
+ "karma": "0.11.0",
+ "karma-firefox-launcher": "0.1.0",
+ "karma-mocha": "0.1.0"
}
}
diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js
index a7c520e..ee82bbd 100644
--- a/src/pixi/InteractionManager.js
+++ b/src/pixi/InteractionManager.js
@@ -62,7 +62,6 @@
this.onTouchEnd = this.onTouchEnd.bind(this);
this.onTouchMove = this.onTouchMove.bind(this);
-
this.last = 0;
}
diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js
index 1a95d20..eef1059 100644
--- a/src/pixi/core/Ellipse.js
+++ b/src/pixi/core/Ellipse.js
@@ -78,7 +78,7 @@
return (normx + normy < 0.25);
}
-PIXI.Ellipse.getBounds = function()
+PIXI.Ellipse.prototype.getBounds = function()
{
return new PIXI.Rectangle(this.x, this.y, this.width, this.height);
}
diff --git a/tasks/karma.js b/tasks/karma.js
new file mode 100644
index 0000000..c340485
--- /dev/null
+++ b/tasks/karma.js
@@ -0,0 +1,27 @@
+'use strict';
+
+var path = require('path');
+var server = require('karma').server;
+
+module.exports = function (grunt) {
+ grunt.registerMultiTask('karma', 'run karma.', function() {
+ var done = this.async();
+ var options = this.options({
+ background: false
+ });
+ var data = this.data;
+
+ //merge options onto data, with data taking precedence
+ data = grunt.util._.merge(options, data);
+ data.configFile = path.resolve(data.configFile);
+ if (data.configFile) {
+ data.configFile = grunt.template.process(data.configFile);
+ }
+
+ server.start(
+ data,
+ function(code) {
+ done(!code);
+ });
+ });
+};
diff --git a/test/functional/example-1-basics/bunny.png b/test/functional/example-1-basics/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/functional/example-1-basics/bunny.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-30.png b/test/functional/example-1-basics/frame-30.png
new file mode 100644
index 0000000..96e3409
--- /dev/null
+++ b/test/functional/example-1-basics/frame-30.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-60.png b/test/functional/example-1-basics/frame-60.png
new file mode 100644
index 0000000..af3f4ce
--- /dev/null
+++ b/test/functional/example-1-basics/frame-60.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-90.png b/test/functional/example-1-basics/frame-90.png
new file mode 100644
index 0000000..099b823
--- /dev/null
+++ b/test/functional/example-1-basics/frame-90.png
Binary files differ
diff --git a/test/functional/example-1-basics/index.js b/test/functional/example-1-basics/index.js
new file mode 100644
index 0000000..7ae7a98
--- /dev/null
+++ b/test/functional/example-1-basics/index.js
@@ -0,0 +1,133 @@
+describe('Example 1 - Basics', function () {
+ 'use strict';
+
+ var baseUri = '/base/test/functional/example-1-basics';
+ var expect = chai.expect;
+ var currentFrame = 0;
+ var frameEvents = {};
+ var stage;
+ var renderer;
+ var bunny;
+
+ function onFrame(frame, callback) {
+ frameEvents[frame] = callback;
+ }
+
+ function animate() {
+ currentFrame += 1;
+
+ requestAnimFrame( animate );
+
+ // just for fun, lets rotate mr rabbit a little
+ bunny.rotation += 0.1;
+
+ // render the stage
+ renderer.render(stage);
+
+ if (frameEvents[currentFrame])
+ frameEvents[currentFrame](currentFrame);
+ }
+
+ function initScene() {
+ // create an new instance of a pixi stage
+ stage = new PIXI.Stage(0x66FF99);
+
+ // create a renderer instance
+ renderer = PIXI.autoDetectRenderer(400, 300);
+ console.log('Is PIXI.WebGLRenderer: ' + (renderer instanceof PIXI.WebGLRenderer));
+
+ // add the renderer view element to the DOM
+ document.body.appendChild(renderer.view);
+
+ requestAnimFrame( animate );
+
+ // create a texture from an image path
+ var texture = PIXI.Texture.fromImage(baseUri + "/bunny.png");
+ // create a new Sprite using the texture
+ bunny = new PIXI.Sprite(texture);
+
+ // center the sprites anchor point
+ bunny.anchor.x = 0.5;
+ bunny.anchor.y = 0.5;
+
+ // move the sprite t the center of the screen
+ bunny.position.x = 200;
+ bunny.position.y = 150;
+
+ stage.addChild(bunny);
+ }
+
+ it('assets loaded', function (done) {
+ var loader = new PIXI.AssetLoader([
+ baseUri + '/bunny.png',
+ baseUri + '/frame-30.png',
+ baseUri + '/frame-60.png',
+ baseUri + '/frame-90.png'
+ ]);
+ // loader.on('onProgress', function (event) {
+ // console.log(event.content);
+ // });
+ loader.on('onComplete', function (event) {
+ done();
+ initScene();
+ });
+ loader.load();
+ });
+
+ it('frame 30 should match', function (done) {
+ this.timeout(700);
+ onFrame(30, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-30.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 60 should match', function (done) {
+ this.timeout(1200);
+ onFrame(60, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-60.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 90 should match', function (done) {
+ this.timeout(1700);
+ onFrame(90, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-90.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ // it('capture something', function (done) {
+ // this.timeout(2000000);
+ // onFrame(30, function () {
+ // var img = new Image();
+ // img.src = renderer.view.toDataURL('image/png');
+ // document.body.appendChild(img);
+ // });
+ // });
+});
diff --git a/test/index.html b/test/index.html
deleted file mode 100644
index 9cbcac5..0000000
--- a/test/index.html
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
- Pixi.js Test Suite
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/test/karma.conf.js b/test/karma.conf.js
new file mode 100644
index 0000000..c66a696
--- /dev/null
+++ b/test/karma.conf.js
@@ -0,0 +1,82 @@
+module.exports = function(config) {
+ config.set({
+
+ // base path, that will be used to resolve files and exclude
+ basePath : '../',
+
+ frameworks : ['mocha'],
+
+ // list of files / patterns to load in the browser
+ files : [
+ 'node_modules/chai/chai.js',
+ 'bin/pixi.dev.js',
+ 'test/lib/**/*.js',
+ 'test/unit/**/*.js',
+ // 'test/functional/**/*.js',
+ {pattern: 'test/**/*.png', watched: false, included: false, served: true}
+ ],
+
+ // list of files to exclude
+ exclude : [],
+
+ // use dolts reporter, as travis terminal does not support escaping sequences
+ // possible values: 'dots', 'progress', 'junit', 'teamcity'
+ // CLI --reporters progress
+ reporters : ['progress'],
+
+ // web server port
+ // CLI --port 9876
+ port : 9876,
+
+ // cli runner port
+ // CLI --runner-port 9100
+ runnerPort : 9100,
+
+ // enable / disable colors in the output (reporters and logs)
+ // CLI --colors --no-colors
+ colors : true,
+
+ // level of logging
+ // possible values: karma.LOG_DISABLE || karma.LOG_ERROR || karma.LOG_WARN || karma.LOG_INFO || karma.LOG_DEBUG
+ // CLI --log-level debug
+ logLevel : config.LOG_DEBUG,
+
+ // enable / disable watching file and executing tests whenever any file changes
+ // CLI --auto-watch --no-auto-watch
+ autoWatch : false,
+
+ // Start these browsers, currently available:
+ // - Chrome
+ // - ChromeCanary
+ // - Firefox
+ // - Opera
+ // - Safari (only Mac)
+ // - PhantomJS
+ // - IE (only Windows)
+ // CLI --browsers Chrome,Firefox,Safari
+ browsers : ['Firefox'],
+
+ // If browser does not capture in given timeout [ms], kill it
+ // CLI --capture-timeout 5000
+ captureTimeout : 5000,
+
+ // Auto run tests on start (when browsers are captured) and exit
+ // CLI --single-run --no-single-run
+ singleRun : true,
+
+ // report which specs are slower than 500ms
+ // CLI --report-slower-than 500
+ reportSlowerThan : 1000,
+
+ preprocessors : {
+ // '**/client/js/*.js': 'coverage'
+ },
+
+ plugins : [
+ 'karma-mocha',
+ // 'karma-chrome-launcher',
+ 'karma-firefox-launcher',
+ // 'karma-phantomjs-launcher'
+ ]
+ });
+};
diff --git a/test/lib/pixi/core/Matrix.js b/test/lib/pixi/core/Matrix.js
new file mode 100644
index 0000000..d26386b
--- /dev/null
+++ b/test/lib/pixi/core/Matrix.js
@@ -0,0 +1,40 @@
+
+function pixi_core_Matrix_confirmNewMat3(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(1);
+ expect(matrix[5]).to.equal(0);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(1);
+}
+
+function pixi_core_Matrix_confirmNewMat4(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[0]).to.equal(1);
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(0);
+ expect(matrix[5]).to.equal(1);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(0);
+ expect(matrix[9]).to.equal(0);
+ expect(matrix[10]).to.equal(1);
+ expect(matrix[11]).to.equal(0);
+ expect(matrix[12]).to.equal(0);
+ expect(matrix[13]).to.equal(0);
+ expect(matrix[14]).to.equal(0);
+ expect(matrix[15]).to.equal(1);
+}
diff --git a/test/lib/pixi/core/Point.js b/test/lib/pixi/core/Point.js
new file mode 100644
index 0000000..e5df07b
--- /dev/null
+++ b/test/lib/pixi/core/Point.js
@@ -0,0 +1,10 @@
+
+function pixi_core_Point_confirm(obj, x, y) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Point);
+ expect(obj).to.respondTo('clone');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+}
diff --git a/test/lib/pixi/core/Rectangle.js b/test/lib/pixi/core/Rectangle.js
new file mode 100644
index 0000000..23f0d12
--- /dev/null
+++ b/test/lib/pixi/core/Rectangle.js
@@ -0,0 +1,13 @@
+
+function pixi_core_Rectangle_confirm(obj, x, y, width, height) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Rectangle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+ expect(obj).to.have.property('width', width);
+ expect(obj).to.have.property('height', height);
+}
diff --git a/test/lib/pixi/display/DisplayObject.js b/test/lib/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..1388a7f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObject.js
@@ -0,0 +1,43 @@
+
+function pixi_display_DisplayObject_confirmNew(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObject);
+ expect(obj).to.respondTo('setInteractive');
+ expect(obj).to.respondTo('addFilter');
+ expect(obj).to.respondTo('removeFilter');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.property('last', obj);
+ expect(obj).to.have.property('first', obj);
+
+ expect(obj).to.contain.property('position');
+ pixi_core_Point_confirm(obj.position, 0, 0);
+ expect(obj).to.contain.property('scale');
+ pixi_core_Point_confirm(obj.scale, 1, 1);
+ expect(obj).to.contain.property('pivot');
+ pixi_core_Point_confirm(obj.pivot, 0, 0);
+
+ expect(obj).to.have.property('rotation', 0);
+ expect(obj).to.have.property('alpha', 1);
+ expect(obj).to.have.property('visible', true);
+ expect(obj).to.have.property('buttonMode', false);
+ expect(obj).to.have.property('parent', null);
+ expect(obj).to.have.property('worldAlpha', 1);
+
+ expect(obj).to.have.property('hitArea');
+ expect(obj).to.have.property('interactive'); // TODO: Have a better default value
+ expect('mask' in obj).to.be.true; // TODO: Have a better default value
+ expect(obj.mask).to.be.undefined;
+
+ expect(obj).to.have.property('renderable');
+ expect(obj).to.have.property('stage');
+
+ expect(obj).to.have.deep.property('worldTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ expect(obj).to.have.deep.property('localTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.localTransform);
+
+ expect(obj).to.have.deep.property('color.length', 0);
+ expect(obj).to.have.property('dynamic', true);
+}
diff --git a/test/lib/pixi/display/DisplayObjectContainer.js b/test/lib/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..085c59f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,16 @@
+
+function pixi_display_DisplayObjectContainer_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObject_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObjectContainer);
+ expect(obj).to.respondTo('addChild');
+ expect(obj).to.respondTo('addChildAt');
+ expect(obj).to.respondTo('swapChildren');
+ expect(obj).to.respondTo('getChildAt');
+ expect(obj).to.respondTo('removeChild');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('children.length', 0);
+}
diff --git a/test/lib/pixi/display/Sprite.js b/test/lib/pixi/display/Sprite.js
new file mode 100644
index 0000000..cc7a2d6
--- /dev/null
+++ b/test/lib/pixi/display/Sprite.js
@@ -0,0 +1,28 @@
+
+function pixi_display_Sprite_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Sprite);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', true);
+ expect(obj).to.have.property('stage', null);
+
+ expect(obj).to.have.property('anchor');
+ pixi_core_Point_confirm(obj.anchor, 0, 0);
+
+ expect(obj).to.have.property('blendMode', PIXI.blendModes.NORMAL);
+ expect(obj).to.have.property('width', 1); // TODO: is 1 expected
+ expect(obj).to.have.property('height', 1); // TODO: is 1 expected
+
+ // FIXME: Just make this a boolean that is always there
+ expect(!!obj.updateFrame).to.equal(obj.texture.baseTexture.hasLoaded);
+
+ expect(obj).to.have.property('texture');
+ pixi_textures_Texture_confirmNew(obj.texture, done);
+}
diff --git a/test/lib/pixi/extras/Strip.js b/test/lib/pixi/extras/Strip.js
new file mode 100644
index 0000000..8927a8a
--- /dev/null
+++ b/test/lib/pixi/extras/Strip.js
@@ -0,0 +1,12 @@
+
+function pixi_extras_Strip_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Strip);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ // TODO: Test properties
+}
diff --git a/test/lib/pixi/textures/Texture.js b/test/lib/pixi/textures/Texture.js
new file mode 100644
index 0000000..d5867b6
--- /dev/null
+++ b/test/lib/pixi/textures/Texture.js
@@ -0,0 +1,31 @@
+
+function pixi_textures_Texture_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ function confirmFrameDone() {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, obj.baseTexture.width, obj.baseTexture.height);
+
+ expect(obj).to.have.property('width', obj.baseTexture.width);
+ expect(obj).to.have.property('height', obj.baseTexture.height);
+ done();
+ }
+
+ expect(obj).to.be.an.instanceof(PIXI.Texture);
+ pixi_utils_EventTarget_like(obj);
+
+ expect(obj).to.have.property('baseTexture')
+ .and.to.be.an.instanceof(PIXI.BaseTexture);
+
+ expect(obj).to.have.property('scope', obj);
+
+ expect(obj).to.have.property('trim');
+ pixi_core_Point_confirm(obj.trim, 0, 0);
+
+ expect(obj).to.have.property('frame');
+ if (obj.baseTexture.hasLoaded) {
+ confirmFrameDone();
+ } else {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, 1, 1);
+ obj.addEventListener('update', confirmFrameDone);
+ }
+}
diff --git a/test/lib/pixi/utils/EventTarget.js b/test/lib/pixi/utils/EventTarget.js
new file mode 100644
index 0000000..7b1dcfa
--- /dev/null
+++ b/test/lib/pixi/utils/EventTarget.js
@@ -0,0 +1,8 @@
+
+function pixi_utils_EventTarget_like(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.respondTo('addEventListener');
+ expect(obj).to.respondTo('dispatchEvent');
+ expect(obj).to.respondTo('removeEventListener');
+}
diff --git a/test/lib/qunit-1.11.0.css b/test/lib/qunit-1.11.0.css
deleted file mode 100644
index d7fc0c8..0000000
--- a/test/lib/qunit-1.11.0.css
+++ /dev/null
@@ -1,244 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-/** Font Family and Sizes */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
- font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
-}
-
-#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
-#qunit-tests { font-size: smaller; }
-
-
-/** Resets */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter {
- margin: 0;
- padding: 0;
-}
-
-
-/** Header */
-
-#qunit-header {
- padding: 0.5em 0 0.5em 1em;
-
- color: #8699a4;
- background-color: #0d3349;
-
- font-size: 1.5em;
- line-height: 1em;
- font-weight: normal;
-
- border-radius: 5px 5px 0 0;
- -moz-border-radius: 5px 5px 0 0;
- -webkit-border-top-right-radius: 5px;
- -webkit-border-top-left-radius: 5px;
-}
-
-#qunit-header a {
- text-decoration: none;
- color: #c2ccd1;
-}
-
-#qunit-header a:hover,
-#qunit-header a:focus {
- color: #fff;
-}
-
-#qunit-testrunner-toolbar label {
- display: inline-block;
- padding: 0 .5em 0 .1em;
-}
-
-#qunit-banner {
- height: 5px;
-}
-
-#qunit-testrunner-toolbar {
- padding: 0.5em 0 0.5em 2em;
- color: #5E740B;
- background-color: #eee;
- overflow: hidden;
-}
-
-#qunit-userAgent {
- padding: 0.5em 0 0.5em 2.5em;
- background-color: #2b81af;
- color: #fff;
- text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
-}
-
-#qunit-modulefilter-container {
- float: right;
-}
-
-/** Tests: Pass/Fail */
-
-#qunit-tests {
- list-style-position: inside;
-}
-
-#qunit-tests li {
- padding: 0.4em 0.5em 0.4em 2.5em;
- border-bottom: 1px solid #fff;
- list-style-position: inside;
-}
-
-#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running {
- display: none;
-}
-
-#qunit-tests li strong {
- cursor: pointer;
-}
-
-#qunit-tests li a {
- padding: 0.5em;
- color: #c2ccd1;
- text-decoration: none;
-}
-#qunit-tests li a:hover,
-#qunit-tests li a:focus {
- color: #000;
-}
-
-#qunit-tests li .runtime {
- float: right;
- font-size: smaller;
-}
-
-.qunit-assert-list {
- margin-top: 0.5em;
- padding: 0.5em;
-
- background-color: #fff;
-
- border-radius: 5px;
- -moz-border-radius: 5px;
- -webkit-border-radius: 5px;
-}
-
-.qunit-collapsed {
- display: none;
-}
-
-#qunit-tests table {
- border-collapse: collapse;
- margin-top: .2em;
-}
-
-#qunit-tests th {
- text-align: right;
- vertical-align: top;
- padding: 0 .5em 0 0;
-}
-
-#qunit-tests td {
- vertical-align: top;
-}
-
-#qunit-tests pre {
- margin: 0;
- white-space: pre-wrap;
- word-wrap: break-word;
-}
-
-#qunit-tests del {
- background-color: #e0f2be;
- color: #374e0c;
- text-decoration: none;
-}
-
-#qunit-tests ins {
- background-color: #ffcaca;
- color: #500;
- text-decoration: none;
-}
-
-/*** Test Counts */
-
-#qunit-tests b.counts { color: black; }
-#qunit-tests b.passed { color: #5E740B; }
-#qunit-tests b.failed { color: #710909; }
-
-#qunit-tests li li {
- padding: 5px;
- background-color: #fff;
- border-bottom: none;
- list-style-position: inside;
-}
-
-/*** Passing Styles */
-
-#qunit-tests li li.pass {
- color: #3c510c;
- background-color: #fff;
- border-left: 10px solid #C6E746;
-}
-
-#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
-#qunit-tests .pass .test-name { color: #366097; }
-
-#qunit-tests .pass .test-actual,
-#qunit-tests .pass .test-expected { color: #999999; }
-
-#qunit-banner.qunit-pass { background-color: #C6E746; }
-
-/*** Failing Styles */
-
-#qunit-tests li li.fail {
- color: #710909;
- background-color: #fff;
- border-left: 10px solid #EE5757;
- white-space: pre;
-}
-
-#qunit-tests > li:last-child {
- border-radius: 0 0 5px 5px;
- -moz-border-radius: 0 0 5px 5px;
- -webkit-border-bottom-right-radius: 5px;
- -webkit-border-bottom-left-radius: 5px;
-}
-
-#qunit-tests .fail { color: #000000; background-color: #EE5757; }
-#qunit-tests .fail .test-name,
-#qunit-tests .fail .module-name { color: #000000; }
-
-#qunit-tests .fail .test-actual { color: #EE5757; }
-#qunit-tests .fail .test-expected { color: green; }
-
-#qunit-banner.qunit-fail { background-color: #EE5757; }
-
-
-/** Result */
-
-#qunit-testresult {
- padding: 0.5em 0.5em 0.5em 2.5em;
-
- color: #2b81af;
- background-color: #D2E0E6;
-
- border-bottom: 1px solid white;
-}
-#qunit-testresult .module-name {
- font-weight: bold;
-}
-
-/** Fixture */
-
-#qunit-fixture {
- position: absolute;
- top: -10000px;
- left: -10000px;
- width: 1000px;
- height: 1000px;
-}
diff --git a/test/lib/qunit-1.11.0.js b/test/lib/qunit-1.11.0.js
deleted file mode 100644
index 302545f..0000000
--- a/test/lib/qunit-1.11.0.js
+++ /dev/null
@@ -1,2152 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-(function( window ) {
-
-var QUnit,
- assert,
- config,
- onErrorFnPrev,
- testId = 0,
- fileName = (sourceFromStacktrace( 0 ) || "" ).replace(/(:\d+)+\)?/, "").replace(/.+\//, ""),
- toString = Object.prototype.toString,
- hasOwn = Object.prototype.hasOwnProperty,
- // Keep a local reference to Date (GH-283)
- Date = window.Date,
- defined = {
- setTimeout: typeof window.setTimeout !== "undefined",
- sessionStorage: (function() {
- var x = "qunit-test-string";
- try {
- sessionStorage.setItem( x, x );
- sessionStorage.removeItem( x );
- return true;
- } catch( e ) {
- return false;
- }
- }())
- },
- /**
- * Provides a normalized error string, correcting an issue
- * with IE 7 (and prior) where Error.prototype.toString is
- * not properly implemented
- *
- * Based on http://es5.github.com/#x15.11.4.4
- *
- * @param {String|Error} error
- * @return {String} error message
- */
- errorString = function( error ) {
- var name, message,
- errorString = error.toString();
- if ( errorString.substring( 0, 7 ) === "[object" ) {
- name = error.name ? error.name.toString() : "Error";
- message = error.message ? error.message.toString() : "";
- if ( name && message ) {
- return name + ": " + message;
- } else if ( name ) {
- return name;
- } else if ( message ) {
- return message;
- } else {
- return "Error";
- }
- } else {
- return errorString;
- }
- },
- /**
- * Makes a clone of an object using only Array or Object as base,
- * and copies over the own enumerable properties.
- *
- * @param {Object} obj
- * @return {Object} New object with only the own properties (recursively).
- */
- objectValues = function( obj ) {
- // Grunt 0.3.x uses an older version of jshint that still has jshint/jshint#392.
- /*jshint newcap: false */
- var key, val,
- vals = QUnit.is( "array", obj ) ? [] : {};
- for ( key in obj ) {
- if ( hasOwn.call( obj, key ) ) {
- val = obj[key];
- vals[key] = val === Object(val) ? objectValues(val) : val;
- }
- }
- return vals;
- };
-
-function Test( settings ) {
- extend( this, settings );
- this.assertions = [];
- this.testNumber = ++Test.count;
-}
-
-Test.count = 0;
-
-Test.prototype = {
- init: function() {
- var a, b, li,
- tests = id( "qunit-tests" );
-
- if ( tests ) {
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml;
-
- // `a` initialized at top of scope
- a = document.createElement( "a" );
- a.innerHTML = "Rerun";
- a.href = QUnit.url({ testNumber: this.testNumber });
-
- li = document.createElement( "li" );
- li.appendChild( b );
- li.appendChild( a );
- li.className = "running";
- li.id = this.id = "qunit-test-output" + testId++;
-
- tests.appendChild( li );
- }
- },
- setup: function() {
- if ( this.module !== config.previousModule ) {
- if ( config.previousModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.previousModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
- config.previousModule = this.module;
- config.moduleStats = { all: 0, bad: 0 };
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- } else if ( config.autorun ) {
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- }
-
- config.current = this;
-
- this.testEnvironment = extend({
- setup: function() {},
- teardown: function() {}
- }, this.moduleTestEnvironment );
-
- this.started = +new Date();
- runLoggingCallbacks( "testStart", QUnit, {
- name: this.testName,
- module: this.module
- });
-
- // allow utility functions to access the current test environment
- // TODO why??
- QUnit.current_testEnvironment = this.testEnvironment;
-
- if ( !config.pollution ) {
- saveGlobal();
- }
- if ( config.notrycatch ) {
- this.testEnvironment.setup.call( this.testEnvironment );
- return;
- }
- try {
- this.testEnvironment.setup.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Setup failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- },
- run: function() {
- config.current = this;
-
- var running = id( "qunit-testresult" );
-
- if ( running ) {
- running.innerHTML = "Running:
" + this.nameHtml;
- }
-
- if ( this.async ) {
- QUnit.stop();
- }
-
- this.callbackStarted = +new Date();
-
- if ( config.notrycatch ) {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- return;
- }
-
- try {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- } catch( e ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
-
- QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + " " + this.stack + ": " + ( e.message || e ), extractStacktrace( e, 0 ) );
- // else next test will carry the responsibility
- saveGlobal();
-
- // Restart the tests if they're blocking
- if ( config.blocking ) {
- QUnit.start();
- }
- }
- },
- teardown: function() {
- config.current = this;
- if ( config.notrycatch ) {
- if ( typeof this.callbackRuntime === "undefined" ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
- }
- this.testEnvironment.teardown.call( this.testEnvironment );
- return;
- } else {
- try {
- this.testEnvironment.teardown.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Teardown failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- }
- checkPollution();
- },
- finish: function() {
- config.current = this;
- if ( config.requireExpects && this.expected === null ) {
- QUnit.pushFailure( "Expected number of assertions to be defined, but expect() was not called.", this.stack );
- } else if ( this.expected !== null && this.expected !== this.assertions.length ) {
- QUnit.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack );
- } else if ( this.expected === null && !this.assertions.length ) {
- QUnit.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions.", this.stack );
- }
-
- var i, assertion, a, b, time, li, ol,
- test = this,
- good = 0,
- bad = 0,
- tests = id( "qunit-tests" );
-
- this.runtime = +new Date() - this.started;
- config.stats.all += this.assertions.length;
- config.moduleStats.all += this.assertions.length;
-
- if ( tests ) {
- ol = document.createElement( "ol" );
- ol.className = "qunit-assert-list";
-
- for ( i = 0; i < this.assertions.length; i++ ) {
- assertion = this.assertions[i];
-
- li = document.createElement( "li" );
- li.className = assertion.result ? "pass" : "fail";
- li.innerHTML = assertion.message || ( assertion.result ? "okay" : "failed" );
- ol.appendChild( li );
-
- if ( assertion.result ) {
- good++;
- } else {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
-
- // store result when possible
- if ( QUnit.config.reorder && defined.sessionStorage ) {
- if ( bad ) {
- sessionStorage.setItem( "qunit-test-" + this.module + "-" + this.testName, bad );
- } else {
- sessionStorage.removeItem( "qunit-test-" + this.module + "-" + this.testName );
- }
- }
-
- if ( bad === 0 ) {
- addClass( ol, "qunit-collapsed" );
- }
-
- // `b` initialized at top of scope
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml + " (" + bad + ", " + good + ", " + this.assertions.length + ")";
-
- addEvent(b, "click", function() {
- var next = b.parentNode.lastChild,
- collapsed = hasClass( next, "qunit-collapsed" );
- ( collapsed ? removeClass : addClass )( next, "qunit-collapsed" );
- });
-
- addEvent(b, "dblclick", function( e ) {
- var target = e && e.target ? e.target : window.event.srcElement;
- if ( target.nodeName.toLowerCase() === "span" || target.nodeName.toLowerCase() === "b" ) {
- target = target.parentNode;
- }
- if ( window.location && target.nodeName.toLowerCase() === "strong" ) {
- window.location = QUnit.url({ testNumber: test.testNumber });
- }
- });
-
- // `time` initialized at top of scope
- time = document.createElement( "span" );
- time.className = "runtime";
- time.innerHTML = this.runtime + " ms";
-
- // `li` initialized at top of scope
- li = id( this.id );
- li.className = bad ? "fail" : "pass";
- li.removeChild( li.firstChild );
- a = li.firstChild;
- li.appendChild( b );
- li.appendChild( a );
- li.appendChild( time );
- li.appendChild( ol );
-
- } else {
- for ( i = 0; i < this.assertions.length; i++ ) {
- if ( !this.assertions[i].result ) {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
- }
-
- runLoggingCallbacks( "testDone", QUnit, {
- name: this.testName,
- module: this.module,
- failed: bad,
- passed: this.assertions.length - bad,
- total: this.assertions.length,
- duration: this.runtime
- });
-
- QUnit.reset();
-
- config.current = undefined;
- },
-
- queue: function() {
- var bad,
- test = this;
-
- synchronize(function() {
- test.init();
- });
- function run() {
- // each of these can by async
- synchronize(function() {
- test.setup();
- });
- synchronize(function() {
- test.run();
- });
- synchronize(function() {
- test.teardown();
- });
- synchronize(function() {
- test.finish();
- });
- }
-
- // `bad` initialized at top of scope
- // defer when previous test run passed, if storage is available
- bad = QUnit.config.reorder && defined.sessionStorage &&
- +sessionStorage.getItem( "qunit-test-" + this.module + "-" + this.testName );
-
- if ( bad ) {
- run();
- } else {
- synchronize( run, true );
- }
- }
-};
-
-// Root QUnit object.
-// `QUnit` initialized at top of scope
-QUnit = {
-
- // call on start of module test to prepend name to all tests
- module: function( name, testEnvironment ) {
- config.currentModule = name;
- config.currentModuleTestEnvironment = testEnvironment;
- config.modules[name] = true;
- },
-
- asyncTest: function( testName, expected, callback ) {
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- QUnit.test( testName, expected, callback, true );
- },
-
- test: function( testName, expected, callback, async ) {
- var test,
- nameHtml = "" + escapeText( testName ) + "";
-
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- if ( config.currentModule ) {
- nameHtml = "" + escapeText( config.currentModule ) + ": " + nameHtml;
- }
-
- test = new Test({
- nameHtml: nameHtml,
- testName: testName,
- expected: expected,
- async: async,
- callback: callback,
- module: config.currentModule,
- moduleTestEnvironment: config.currentModuleTestEnvironment,
- stack: sourceFromStacktrace( 2 )
- });
-
- if ( !validTest( test ) ) {
- return;
- }
-
- test.queue();
- },
-
- // Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through.
- expect: function( asserts ) {
- if (arguments.length === 1) {
- config.current.expected = asserts;
- } else {
- return config.current.expected;
- }
- },
-
- start: function( count ) {
- // QUnit hasn't been initialized yet.
- // Note: RequireJS (et al) may delay onLoad
- if ( config.semaphore === undefined ) {
- QUnit.begin(function() {
- // This is triggered at the top of QUnit.load, push start() to the event loop, to allow QUnit.load to finish first
- setTimeout(function() {
- QUnit.start( count );
- });
- });
- return;
- }
-
- config.semaphore -= count || 1;
- // don't start until equal number of stop-calls
- if ( config.semaphore > 0 ) {
- return;
- }
- // ignore if start is called more often then stop
- if ( config.semaphore < 0 ) {
- config.semaphore = 0;
- QUnit.pushFailure( "Called start() while already started (QUnit.config.semaphore was 0 already)", null, sourceFromStacktrace(2) );
- return;
- }
- // A slight delay, to avoid any current callbacks
- if ( defined.setTimeout ) {
- window.setTimeout(function() {
- if ( config.semaphore > 0 ) {
- return;
- }
- if ( config.timeout ) {
- clearTimeout( config.timeout );
- }
-
- config.blocking = false;
- process( true );
- }, 13);
- } else {
- config.blocking = false;
- process( true );
- }
- },
-
- stop: function( count ) {
- config.semaphore += count || 1;
- config.blocking = true;
-
- if ( config.testTimeout && defined.setTimeout ) {
- clearTimeout( config.timeout );
- config.timeout = window.setTimeout(function() {
- QUnit.ok( false, "Test timed out" );
- config.semaphore = 1;
- QUnit.start();
- }, config.testTimeout );
- }
- }
-};
-
-// `assert` initialized at top of scope
-// Asssert helpers
-// All of these must either call QUnit.push() or manually do:
-// - runLoggingCallbacks( "log", .. );
-// - config.current.assertions.push({ .. });
-// We attach it to the QUnit object *after* we expose the public API,
-// otherwise `assert` will become a global variable in browsers (#341).
-assert = {
- /**
- * Asserts rough true-ish result.
- * @name ok
- * @function
- * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" );
- */
- ok: function( result, msg ) {
- if ( !config.current ) {
- throw new Error( "ok() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
- result = !!result;
-
- var source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: msg
- };
-
- msg = escapeText( msg || (result ? "okay" : "failed" ) );
- msg = "" + msg + "";
-
- if ( !result ) {
- source = sourceFromStacktrace( 2 );
- if ( source ) {
- details.source = source;
- msg += "Source: | " + escapeText( source ) + " |
---|
";
- }
- }
- runLoggingCallbacks( "log", QUnit, details );
- config.current.assertions.push({
- result: result,
- message: msg
- });
- },
-
- /**
- * Assert that the first two arguments are equal, with an optional message.
- * Prints out both actual and expected values.
- * @name equal
- * @function
- * @example equal( format( "Received {0} bytes.", 2), "Received 2 bytes.", "format() replaces {0} with next argument" );
- */
- equal: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected == actual, actual, expected, message );
- },
-
- /**
- * @name notEqual
- * @function
- */
- notEqual: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected != actual, actual, expected, message );
- },
-
- /**
- * @name propEqual
- * @function
- */
- propEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notPropEqual
- * @function
- */
- notPropEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name deepEqual
- * @function
- */
- deepEqual: function( actual, expected, message ) {
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notDeepEqual
- * @function
- */
- notDeepEqual: function( actual, expected, message ) {
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name strictEqual
- * @function
- */
- strictEqual: function( actual, expected, message ) {
- QUnit.push( expected === actual, actual, expected, message );
- },
-
- /**
- * @name notStrictEqual
- * @function
- */
- notStrictEqual: function( actual, expected, message ) {
- QUnit.push( expected !== actual, actual, expected, message );
- },
-
- "throws": function( block, expected, message ) {
- var actual,
- expectedOutput = expected,
- ok = false;
-
- // 'expected' is optional
- if ( typeof expected === "string" ) {
- message = expected;
- expected = null;
- }
-
- config.current.ignoreGlobalErrors = true;
- try {
- block.call( config.current.testEnvironment );
- } catch (e) {
- actual = e;
- }
- config.current.ignoreGlobalErrors = false;
-
- if ( actual ) {
- // we don't want to validate thrown error
- if ( !expected ) {
- ok = true;
- expectedOutput = null;
- // expected is a regexp
- } else if ( QUnit.objectType( expected ) === "regexp" ) {
- ok = expected.test( errorString( actual ) );
- // expected is a constructor
- } else if ( actual instanceof expected ) {
- ok = true;
- // expected is a validation function which returns true is validation passed
- } else if ( expected.call( {}, actual ) === true ) {
- expectedOutput = null;
- ok = true;
- }
-
- QUnit.push( ok, actual, expectedOutput, message );
- } else {
- QUnit.pushFailure( message, null, 'No exception was thrown.' );
- }
- }
-};
-
-/**
- * @deprecate since 1.8.0
- * Kept assertion helpers in root for backwards compatibility.
- */
-extend( QUnit, assert );
-
-/**
- * @deprecated since 1.9.0
- * Kept root "raises()" for backwards compatibility.
- * (Note that we don't introduce assert.raises).
- */
-QUnit.raises = assert[ "throws" ];
-
-/**
- * @deprecated since 1.0.0, replaced with error pushes since 1.3.0
- * Kept to avoid TypeErrors for undefined methods.
- */
-QUnit.equals = function() {
- QUnit.push( false, false, false, "QUnit.equals has been deprecated since 2009 (e88049a0), use QUnit.equal instead" );
-};
-QUnit.same = function() {
- QUnit.push( false, false, false, "QUnit.same has been deprecated since 2009 (e88049a0), use QUnit.deepEqual instead" );
-};
-
-// We want access to the constructor's prototype
-(function() {
- function F() {}
- F.prototype = QUnit;
- QUnit = new F();
- // Make F QUnit's constructor so that we can add to the prototype later
- QUnit.constructor = F;
-}());
-
-/**
- * Config object: Maintain internal state
- * Later exposed as QUnit.config
- * `config` initialized at top of scope
- */
-config = {
- // The queue of tests to run
- queue: [],
-
- // block until document ready
- blocking: true,
-
- // when enabled, show only failing tests
- // gets persisted through sessionStorage and can be changed in UI via checkbox
- hidepassed: false,
-
- // by default, run previously failed tests first
- // very useful in combination with "Hide passed tests" checked
- reorder: true,
-
- // by default, modify document.title when suite is done
- altertitle: true,
-
- // when enabled, all tests must call expect()
- requireExpects: false,
-
- // add checkboxes that are persisted in the query-string
- // when enabled, the id is set to `true` as a `QUnit.config` property
- urlConfig: [
- {
- id: "noglobals",
- label: "Check for Globals",
- tooltip: "Enabling this will test if any test introduces new properties on the `window` object. Stored as query-strings."
- },
- {
- id: "notrycatch",
- label: "No try-catch",
- tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging exceptions in IE reasonable. Stored as query-strings."
- }
- ],
-
- // Set of all modules.
- modules: {},
-
- // logging callback queues
- begin: [],
- done: [],
- log: [],
- testStart: [],
- testDone: [],
- moduleStart: [],
- moduleDone: []
-};
-
-// Export global variables, unless an 'exports' object exists,
-// in that case we assume we're in CommonJS (dealt with on the bottom of the script)
-if ( typeof exports === "undefined" ) {
- extend( window, QUnit );
-
- // Expose QUnit object
- window.QUnit = QUnit;
-}
-
-// Initialize more QUnit.config and QUnit.urlParams
-(function() {
- var i,
- location = window.location || { search: "", protocol: "file:" },
- params = location.search.slice( 1 ).split( "&" ),
- length = params.length,
- urlParams = {},
- current;
-
- if ( params[ 0 ] ) {
- for ( i = 0; i < length; i++ ) {
- current = params[ i ].split( "=" );
- current[ 0 ] = decodeURIComponent( current[ 0 ] );
- // allow just a key to turn on a flag, e.g., test.html?noglobals
- current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true;
- urlParams[ current[ 0 ] ] = current[ 1 ];
- }
- }
-
- QUnit.urlParams = urlParams;
-
- // String search anywhere in moduleName+testName
- config.filter = urlParams.filter;
-
- // Exact match of the module name
- config.module = urlParams.module;
-
- config.testNumber = parseInt( urlParams.testNumber, 10 ) || null;
-
- // Figure out if we're running the tests from a server or not
- QUnit.isLocal = location.protocol === "file:";
-}());
-
-// Extend QUnit object,
-// these after set here because they should not be exposed as global functions
-extend( QUnit, {
- assert: assert,
-
- config: config,
-
- // Initialize the configuration options
- init: function() {
- extend( config, {
- stats: { all: 0, bad: 0 },
- moduleStats: { all: 0, bad: 0 },
- started: +new Date(),
- updateRate: 1000,
- blocking: false,
- autostart: true,
- autorun: false,
- filter: "",
- queue: [],
- semaphore: 1
- });
-
- var tests, banner, result,
- qunit = id( "qunit" );
-
- if ( qunit ) {
- qunit.innerHTML =
- "" +
- "" +
- "" +
- "" +
- "
";
- }
-
- tests = id( "qunit-tests" );
- banner = id( "qunit-banner" );
- result = id( "qunit-testresult" );
-
- if ( tests ) {
- tests.innerHTML = "";
- }
-
- if ( banner ) {
- banner.className = "";
- }
-
- if ( result ) {
- result.parentNode.removeChild( result );
- }
-
- if ( tests ) {
- result = document.createElement( "p" );
- result.id = "qunit-testresult";
- result.className = "result";
- tests.parentNode.insertBefore( result, tests );
- result.innerHTML = "Running...
";
- }
- },
-
- // Resets the test setup. Useful for tests that modify the DOM.
- reset: function() {
- var fixture = id( "qunit-fixture" );
- if ( fixture ) {
- fixture.innerHTML = config.fixture;
- }
- },
-
- // Trigger an event on an element.
- // @example triggerEvent( document.body, "click" );
- triggerEvent: function( elem, type, event ) {
- if ( document.createEvent ) {
- event = document.createEvent( "MouseEvents" );
- event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView,
- 0, 0, 0, 0, 0, false, false, false, false, 0, null);
-
- elem.dispatchEvent( event );
- } else if ( elem.fireEvent ) {
- elem.fireEvent( "on" + type );
- }
- },
-
- // Safe object type checking
- is: function( type, obj ) {
- return QUnit.objectType( obj ) === type;
- },
-
- objectType: function( obj ) {
- if ( typeof obj === "undefined" ) {
- return "undefined";
- // consider: typeof null === object
- }
- if ( obj === null ) {
- return "null";
- }
-
- var match = toString.call( obj ).match(/^\[object\s(.*)\]$/),
- type = match && match[1] || "";
-
- switch ( type ) {
- case "Number":
- if ( isNaN(obj) ) {
- return "nan";
- }
- return "number";
- case "String":
- case "Boolean":
- case "Array":
- case "Date":
- case "RegExp":
- case "Function":
- return type.toLowerCase();
- }
- if ( typeof obj === "object" ) {
- return "object";
- }
- return undefined;
- },
-
- push: function( result, actual, expected, message ) {
- if ( !config.current ) {
- throw new Error( "assertion outside test context, was " + sourceFromStacktrace() );
- }
-
- var output, source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: message,
- actual: actual,
- expected: expected
- };
-
- message = escapeText( message ) || ( result ? "okay" : "failed" );
- message = "" + message + "";
- output = message;
-
- if ( !result ) {
- expected = escapeText( QUnit.jsDump.parse(expected) );
- actual = escapeText( QUnit.jsDump.parse(actual) );
- output += "Expected: | " + expected + " |
";
-
- if ( actual !== expected ) {
- output += "Result: | " + actual + " |
";
- output += "Diff: | " + QUnit.diff( expected, actual ) + " |
";
- }
-
- source = sourceFromStacktrace();
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
- }
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: !!result,
- message: output
- });
- },
-
- pushFailure: function( message, source, actual ) {
- if ( !config.current ) {
- throw new Error( "pushFailure() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
-
- var output,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: false,
- message: message
- };
-
- message = escapeText( message ) || "error";
- message = "" + message + "";
- output = message;
-
- output += "";
-
- if ( actual ) {
- output += "Result: | " + escapeText( actual ) + " |
";
- }
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: false,
- message: output
- });
- },
-
- url: function( params ) {
- params = extend( extend( {}, QUnit.urlParams ), params );
- var key,
- querystring = "?";
-
- for ( key in params ) {
- if ( !hasOwn.call( params, key ) ) {
- continue;
- }
- querystring += encodeURIComponent( key ) + "=" +
- encodeURIComponent( params[ key ] ) + "&";
- }
- return window.location.protocol + "//" + window.location.host +
- window.location.pathname + querystring.slice( 0, -1 );
- },
-
- extend: extend,
- id: id,
- addEvent: addEvent
- // load, equiv, jsDump, diff: Attached later
-});
-
-/**
- * @deprecated: Created for backwards compatibility with test runner that set the hook function
- * into QUnit.{hook}, instead of invoking it and passing the hook function.
- * QUnit.constructor is set to the empty F() above so that we can add to it's prototype here.
- * Doing this allows us to tell if the following methods have been overwritten on the actual
- * QUnit object.
- */
-extend( QUnit.constructor.prototype, {
-
- // Logging callbacks; all receive a single argument with the listed properties
- // run test/logs.html for any related changes
- begin: registerLoggingCallback( "begin" ),
-
- // done: { failed, passed, total, runtime }
- done: registerLoggingCallback( "done" ),
-
- // log: { result, actual, expected, message }
- log: registerLoggingCallback( "log" ),
-
- // testStart: { name }
- testStart: registerLoggingCallback( "testStart" ),
-
- // testDone: { name, failed, passed, total, duration }
- testDone: registerLoggingCallback( "testDone" ),
-
- // moduleStart: { name }
- moduleStart: registerLoggingCallback( "moduleStart" ),
-
- // moduleDone: { name, failed, passed, total }
- moduleDone: registerLoggingCallback( "moduleDone" )
-});
-
-if ( typeof document === "undefined" || document.readyState === "complete" ) {
- config.autorun = true;
-}
-
-QUnit.load = function() {
- runLoggingCallbacks( "begin", QUnit, {} );
-
- // Initialize the config, saving the execution queue
- var banner, filter, i, label, len, main, ol, toolbar, userAgent, val,
- urlConfigCheckboxesContainer, urlConfigCheckboxes, moduleFilter,
- numModules = 0,
- moduleFilterHtml = "",
- urlConfigHtml = "",
- oldconfig = extend( {}, config );
-
- QUnit.init();
- extend(config, oldconfig);
-
- config.blocking = false;
-
- len = config.urlConfig.length;
-
- for ( i = 0; i < len; i++ ) {
- val = config.urlConfig[i];
- if ( typeof val === "string" ) {
- val = {
- id: val,
- label: val,
- tooltip: "[no tooltip available]"
- };
- }
- config[ val.id ] = QUnit.urlParams[ val.id ];
- urlConfigHtml += "";
- }
-
- moduleFilterHtml += "";
-
- // `userAgent` initialized at top of scope
- userAgent = id( "qunit-userAgent" );
- if ( userAgent ) {
- userAgent.innerHTML = navigator.userAgent;
- }
-
- // `banner` initialized at top of scope
- banner = id( "qunit-header" );
- if ( banner ) {
- banner.innerHTML = "" + banner.innerHTML + " ";
- }
-
- // `toolbar` initialized at top of scope
- toolbar = id( "qunit-testrunner-toolbar" );
- if ( toolbar ) {
- // `filter` initialized at top of scope
- filter = document.createElement( "input" );
- filter.type = "checkbox";
- filter.id = "qunit-filter-pass";
-
- addEvent( filter, "click", function() {
- var tmp,
- ol = document.getElementById( "qunit-tests" );
-
- if ( filter.checked ) {
- ol.className = ol.className + " hidepass";
- } else {
- tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " ";
- ol.className = tmp.replace( / hidepass /, " " );
- }
- if ( defined.sessionStorage ) {
- if (filter.checked) {
- sessionStorage.setItem( "qunit-filter-passed-tests", "true" );
- } else {
- sessionStorage.removeItem( "qunit-filter-passed-tests" );
- }
- }
- });
-
- if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem( "qunit-filter-passed-tests" ) ) {
- filter.checked = true;
- // `ol` initialized at top of scope
- ol = document.getElementById( "qunit-tests" );
- ol.className = ol.className + " hidepass";
- }
- toolbar.appendChild( filter );
-
- // `label` initialized at top of scope
- label = document.createElement( "label" );
- label.setAttribute( "for", "qunit-filter-pass" );
- label.setAttribute( "title", "Only show tests and assertons that fail. Stored in sessionStorage." );
- label.innerHTML = "Hide passed tests";
- toolbar.appendChild( label );
-
- urlConfigCheckboxesContainer = document.createElement("span");
- urlConfigCheckboxesContainer.innerHTML = urlConfigHtml;
- urlConfigCheckboxes = urlConfigCheckboxesContainer.getElementsByTagName("input");
- // For oldIE support:
- // * Add handlers to the individual elements instead of the container
- // * Use "click" instead of "change"
- // * Fallback from event.target to event.srcElement
- addEvents( urlConfigCheckboxes, "click", function( event ) {
- var params = {},
- target = event.target || event.srcElement;
- params[ target.name ] = target.checked ? true : undefined;
- window.location = QUnit.url( params );
- });
- toolbar.appendChild( urlConfigCheckboxesContainer );
-
- if (numModules > 1) {
- moduleFilter = document.createElement( 'span' );
- moduleFilter.setAttribute( 'id', 'qunit-modulefilter-container' );
- moduleFilter.innerHTML = moduleFilterHtml;
- addEvent( moduleFilter.lastChild, "change", function() {
- var selectBox = moduleFilter.getElementsByTagName("select")[0],
- selectedModule = decodeURIComponent(selectBox.options[selectBox.selectedIndex].value);
-
- window.location = QUnit.url( { module: ( selectedModule === "" ) ? undefined : selectedModule } );
- });
- toolbar.appendChild(moduleFilter);
- }
- }
-
- // `main` initialized at top of scope
- main = id( "qunit-fixture" );
- if ( main ) {
- config.fixture = main.innerHTML;
- }
-
- if ( config.autostart ) {
- QUnit.start();
- }
-};
-
-addEvent( window, "load", QUnit.load );
-
-// `onErrorFnPrev` initialized at top of scope
-// Preserve other handlers
-onErrorFnPrev = window.onerror;
-
-// Cover uncaught exceptions
-// Returning true will surpress the default browser handler,
-// returning false will let it run.
-window.onerror = function ( error, filePath, linerNr ) {
- var ret = false;
- if ( onErrorFnPrev ) {
- ret = onErrorFnPrev( error, filePath, linerNr );
- }
-
- // Treat return value as window.onerror itself does,
- // Only do our handling if not surpressed.
- if ( ret !== true ) {
- if ( QUnit.config.current ) {
- if ( QUnit.config.current.ignoreGlobalErrors ) {
- return true;
- }
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- } else {
- QUnit.test( "global failure", extend( function() {
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- }, { validTest: validTest } ) );
- }
- return false;
- }
-
- return ret;
-};
-
-function done() {
- config.autorun = true;
-
- // Log the last module results
- if ( config.currentModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.currentModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
-
- var i, key,
- banner = id( "qunit-banner" ),
- tests = id( "qunit-tests" ),
- runtime = +new Date() - config.started,
- passed = config.stats.all - config.stats.bad,
- html = [
- "Tests completed in ",
- runtime,
- " milliseconds.
",
- "",
- passed,
- " assertions of ",
- config.stats.all,
- " passed, ",
- config.stats.bad,
- " failed."
- ].join( "" );
-
- if ( banner ) {
- banner.className = ( config.stats.bad ? "qunit-fail" : "qunit-pass" );
- }
-
- if ( tests ) {
- id( "qunit-testresult" ).innerHTML = html;
- }
-
- if ( config.altertitle && typeof document !== "undefined" && document.title ) {
- // show ✖ for good, ✔ for bad suite result in title
- // use escape sequences in case file gets loaded with non-utf-8-charset
- document.title = [
- ( config.stats.bad ? "\u2716" : "\u2714" ),
- document.title.replace( /^[\u2714\u2716] /i, "" )
- ].join( " " );
- }
-
- // clear own sessionStorage items if all tests passed
- if ( config.reorder && defined.sessionStorage && config.stats.bad === 0 ) {
- // `key` & `i` initialized at top of scope
- for ( i = 0; i < sessionStorage.length; i++ ) {
- key = sessionStorage.key( i++ );
- if ( key.indexOf( "qunit-test-" ) === 0 ) {
- sessionStorage.removeItem( key );
- }
- }
- }
-
- // scroll back to top to show results
- if ( window.scrollTo ) {
- window.scrollTo(0, 0);
- }
-
- runLoggingCallbacks( "done", QUnit, {
- failed: config.stats.bad,
- passed: passed,
- total: config.stats.all,
- runtime: runtime
- });
-}
-
-/** @return Boolean: true if this test should be ran */
-function validTest( test ) {
- var include,
- filter = config.filter && config.filter.toLowerCase(),
- module = config.module && config.module.toLowerCase(),
- fullName = (test.module + ": " + test.testName).toLowerCase();
-
- // Internally-generated tests are always valid
- if ( test.callback && test.callback.validTest === validTest ) {
- delete test.callback.validTest;
- return true;
- }
-
- if ( config.testNumber ) {
- return test.testNumber === config.testNumber;
- }
-
- if ( module && ( !test.module || test.module.toLowerCase() !== module ) ) {
- return false;
- }
-
- if ( !filter ) {
- return true;
- }
-
- include = filter.charAt( 0 ) !== "!";
- if ( !include ) {
- filter = filter.slice( 1 );
- }
-
- // If the filter matches, we need to honour include
- if ( fullName.indexOf( filter ) !== -1 ) {
- return include;
- }
-
- // Otherwise, do the opposite
- return !include;
-}
-
-// so far supports only Firefox, Chrome and Opera (buggy), Safari (for real exceptions)
-// Later Safari and IE10 are supposed to support error.stack as well
-// See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack
-function extractStacktrace( e, offset ) {
- offset = offset === undefined ? 3 : offset;
-
- var stack, include, i;
-
- if ( e.stacktrace ) {
- // Opera
- return e.stacktrace.split( "\n" )[ offset + 3 ];
- } else if ( e.stack ) {
- // Firefox, Chrome
- stack = e.stack.split( "\n" );
- if (/^error$/i.test( stack[0] ) ) {
- stack.shift();
- }
- if ( fileName ) {
- include = [];
- for ( i = offset; i < stack.length; i++ ) {
- if ( stack[ i ].indexOf( fileName ) !== -1 ) {
- break;
- }
- include.push( stack[ i ] );
- }
- if ( include.length ) {
- return include.join( "\n" );
- }
- }
- return stack[ offset ];
- } else if ( e.sourceURL ) {
- // Safari, PhantomJS
- // hopefully one day Safari provides actual stacktraces
- // exclude useless self-reference for generated Error objects
- if ( /qunit.js$/.test( e.sourceURL ) ) {
- return;
- }
- // for actual exceptions, this is useful
- return e.sourceURL + ":" + e.line;
- }
-}
-function sourceFromStacktrace( offset ) {
- try {
- throw new Error();
- } catch ( e ) {
- return extractStacktrace( e, offset );
- }
-}
-
-/**
- * Escape text for attribute or text content.
- */
-function escapeText( s ) {
- if ( !s ) {
- return "";
- }
- s = s + "";
- // Both single quotes and double quotes (for attributes)
- return s.replace( /['"<>&]/g, function( s ) {
- switch( s ) {
- case '\'':
- return ''';
- case '"':
- return '"';
- case '<':
- return '<';
- case '>':
- return '>';
- case '&':
- return '&';
- }
- });
-}
-
-function synchronize( callback, last ) {
- config.queue.push( callback );
-
- if ( config.autorun && !config.blocking ) {
- process( last );
- }
-}
-
-function process( last ) {
- function next() {
- process( last );
- }
- var start = new Date().getTime();
- config.depth = config.depth ? config.depth + 1 : 1;
-
- while ( config.queue.length && !config.blocking ) {
- if ( !defined.setTimeout || config.updateRate <= 0 || ( ( new Date().getTime() - start ) < config.updateRate ) ) {
- config.queue.shift()();
- } else {
- window.setTimeout( next, 13 );
- break;
- }
- }
- config.depth--;
- if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) {
- done();
- }
-}
-
-function saveGlobal() {
- config.pollution = [];
-
- if ( config.noglobals ) {
- for ( var key in window ) {
- // in Opera sometimes DOM element ids show up here, ignore them
- if ( !hasOwn.call( window, key ) || /^qunit-test-output/.test( key ) ) {
- continue;
- }
- config.pollution.push( key );
- }
- }
-}
-
-function checkPollution() {
- var newGlobals,
- deletedGlobals,
- old = config.pollution;
-
- saveGlobal();
-
- newGlobals = diff( config.pollution, old );
- if ( newGlobals.length > 0 ) {
- QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join(", ") );
- }
-
- deletedGlobals = diff( old, config.pollution );
- if ( deletedGlobals.length > 0 ) {
- QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join(", ") );
- }
-}
-
-// returns a new Array with the elements that are in a but not in b
-function diff( a, b ) {
- var i, j,
- result = a.slice();
-
- for ( i = 0; i < result.length; i++ ) {
- for ( j = 0; j < b.length; j++ ) {
- if ( result[i] === b[j] ) {
- result.splice( i, 1 );
- i--;
- break;
- }
- }
- }
- return result;
-}
-
-function extend( a, b ) {
- for ( var prop in b ) {
- if ( b[ prop ] === undefined ) {
- delete a[ prop ];
-
- // Avoid "Member not found" error in IE8 caused by setting window.constructor
- } else if ( prop !== "constructor" || a !== window ) {
- a[ prop ] = b[ prop ];
- }
- }
-
- return a;
-}
-
-/**
- * @param {HTMLElement} elem
- * @param {string} type
- * @param {Function} fn
- */
-function addEvent( elem, type, fn ) {
- // Standards-based browsers
- if ( elem.addEventListener ) {
- elem.addEventListener( type, fn, false );
- // IE
- } else {
- elem.attachEvent( "on" + type, fn );
- }
-}
-
-/**
- * @param {Array|NodeList} elems
- * @param {string} type
- * @param {Function} fn
- */
-function addEvents( elems, type, fn ) {
- var i = elems.length;
- while ( i-- ) {
- addEvent( elems[i], type, fn );
- }
-}
-
-function hasClass( elem, name ) {
- return (" " + elem.className + " ").indexOf(" " + name + " ") > -1;
-}
-
-function addClass( elem, name ) {
- if ( !hasClass( elem, name ) ) {
- elem.className += (elem.className ? " " : "") + name;
- }
-}
-
-function removeClass( elem, name ) {
- var set = " " + elem.className + " ";
- // Class name may appear multiple times
- while ( set.indexOf(" " + name + " ") > -1 ) {
- set = set.replace(" " + name + " " , " ");
- }
- // If possible, trim it for prettiness, but not neccecarily
- elem.className = window.jQuery ? jQuery.trim( set ) : ( set.trim ? set.trim() : set );
-}
-
-function id( name ) {
- return !!( typeof document !== "undefined" && document && document.getElementById ) &&
- document.getElementById( name );
-}
-
-function registerLoggingCallback( key ) {
- return function( callback ) {
- config[key].push( callback );
- };
-}
-
-// Supports deprecated method of completely overwriting logging callbacks
-function runLoggingCallbacks( key, scope, args ) {
- var i, callbacks;
- if ( QUnit.hasOwnProperty( key ) ) {
- QUnit[ key ].call(scope, args );
- } else {
- callbacks = config[ key ];
- for ( i = 0; i < callbacks.length; i++ ) {
- callbacks[ i ].call( scope, args );
- }
- }
-}
-
-// Test for equality any JavaScript type.
-// Author: Philippe Rathé
-QUnit.equiv = (function() {
-
- // Call the o related callback with the given arguments.
- function bindCallbacks( o, callbacks, args ) {
- var prop = QUnit.objectType( o );
- if ( prop ) {
- if ( QUnit.objectType( callbacks[ prop ] ) === "function" ) {
- return callbacks[ prop ].apply( callbacks, args );
- } else {
- return callbacks[ prop ]; // or undefined
- }
- }
- }
-
- // the real equiv function
- var innerEquiv,
- // stack to decide between skip/abort functions
- callers = [],
- // stack to avoiding loops from circular referencing
- parents = [],
-
- getProto = Object.getPrototypeOf || function ( obj ) {
- return obj.__proto__;
- },
- callbacks = (function () {
-
- // for string, boolean, number and null
- function useStrictEquality( b, a ) {
- /*jshint eqeqeq:false */
- if ( b instanceof a.constructor || a instanceof b.constructor ) {
- // to catch short annotaion VS 'new' annotation of a
- // declaration
- // e.g. var i = 1;
- // var j = new Number(1);
- return a == b;
- } else {
- return a === b;
- }
- }
-
- return {
- "string": useStrictEquality,
- "boolean": useStrictEquality,
- "number": useStrictEquality,
- "null": useStrictEquality,
- "undefined": useStrictEquality,
-
- "nan": function( b ) {
- return isNaN( b );
- },
-
- "date": function( b, a ) {
- return QUnit.objectType( b ) === "date" && a.valueOf() === b.valueOf();
- },
-
- "regexp": function( b, a ) {
- return QUnit.objectType( b ) === "regexp" &&
- // the regex itself
- a.source === b.source &&
- // and its modifers
- a.global === b.global &&
- // (gmi) ...
- a.ignoreCase === b.ignoreCase &&
- a.multiline === b.multiline &&
- a.sticky === b.sticky;
- },
-
- // - skip when the property is a method of an instance (OOP)
- // - abort otherwise,
- // initial === would have catch identical references anyway
- "function": function() {
- var caller = callers[callers.length - 1];
- return caller !== Object && typeof caller !== "undefined";
- },
-
- "array": function( b, a ) {
- var i, j, len, loop;
-
- // b could be an object literal here
- if ( QUnit.objectType( b ) !== "array" ) {
- return false;
- }
-
- len = a.length;
- if ( len !== b.length ) {
- // safe and faster
- return false;
- }
-
- // track reference to avoid circular references
- parents.push( a );
- for ( i = 0; i < len; i++ ) {
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- loop = true;// dont rewalk array
- }
- }
- if ( !loop && !innerEquiv(a[i], b[i]) ) {
- parents.pop();
- return false;
- }
- }
- parents.pop();
- return true;
- },
-
- "object": function( b, a ) {
- var i, j, loop,
- // Default to true
- eq = true,
- aProperties = [],
- bProperties = [];
-
- // comparing constructors is more strict than using
- // instanceof
- if ( a.constructor !== b.constructor ) {
- // Allow objects with no prototype to be equivalent to
- // objects with Object as their constructor.
- if ( !(( getProto(a) === null && getProto(b) === Object.prototype ) ||
- ( getProto(b) === null && getProto(a) === Object.prototype ) ) ) {
- return false;
- }
- }
-
- // stack constructor before traversing properties
- callers.push( a.constructor );
- // track reference to avoid circular references
- parents.push( a );
-
- for ( i in a ) { // be strict: don't ensures hasOwnProperty
- // and go deep
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- // don't go down the same path twice
- loop = true;
- }
- }
- aProperties.push(i); // collect a's properties
-
- if (!loop && !innerEquiv( a[i], b[i] ) ) {
- eq = false;
- break;
- }
- }
-
- callers.pop(); // unstack, we are done
- parents.pop();
-
- for ( i in b ) {
- bProperties.push( i ); // collect b's properties
- }
-
- // Ensures identical properties name
- return eq && innerEquiv( aProperties.sort(), bProperties.sort() );
- }
- };
- }());
-
- innerEquiv = function() { // can take multiple arguments
- var args = [].slice.apply( arguments );
- if ( args.length < 2 ) {
- return true; // end transition
- }
-
- return (function( a, b ) {
- if ( a === b ) {
- return true; // catch the most you can
- } else if ( a === null || b === null || typeof a === "undefined" ||
- typeof b === "undefined" ||
- QUnit.objectType(a) !== QUnit.objectType(b) ) {
- return false; // don't lose time with error prone cases
- } else {
- return bindCallbacks(a, callbacks, [ b, a ]);
- }
-
- // apply transition with (1..n) arguments
- }( args[0], args[1] ) && arguments.callee.apply( this, args.splice(1, args.length - 1 )) );
- };
-
- return innerEquiv;
-}());
-
-/**
- * jsDump Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com |
- * http://flesler.blogspot.com Licensed under BSD
- * (http://www.opensource.org/licenses/bsd-license.php) Date: 5/15/2008
- *
- * @projectDescription Advanced and extensible data dumping for Javascript.
- * @version 1.0.0
- * @author Ariel Flesler
- * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html}
- */
-QUnit.jsDump = (function() {
- function quote( str ) {
- return '"' + str.toString().replace( /"/g, '\\"' ) + '"';
- }
- function literal( o ) {
- return o + "";
- }
- function join( pre, arr, post ) {
- var s = jsDump.separator(),
- base = jsDump.indent(),
- inner = jsDump.indent(1);
- if ( arr.join ) {
- arr = arr.join( "," + s + inner );
- }
- if ( !arr ) {
- return pre + post;
- }
- return [ pre, inner + arr, base + post ].join(s);
- }
- function array( arr, stack ) {
- var i = arr.length, ret = new Array(i);
- this.up();
- while ( i-- ) {
- ret[i] = this.parse( arr[i] , undefined , stack);
- }
- this.down();
- return join( "[", ret, "]" );
- }
-
- var reName = /^function (\w+)/,
- jsDump = {
- // type is used mostly internally, you can fix a (custom)type in advance
- parse: function( obj, type, stack ) {
- stack = stack || [ ];
- var inStack, res,
- parser = this.parsers[ type || this.typeOf(obj) ];
-
- type = typeof parser;
- inStack = inArray( obj, stack );
-
- if ( inStack !== -1 ) {
- return "recursion(" + (inStack - stack.length) + ")";
- }
- if ( type === "function" ) {
- stack.push( obj );
- res = parser.call( this, obj, stack );
- stack.pop();
- return res;
- }
- return ( type === "string" ) ? parser : this.parsers.error;
- },
- typeOf: function( obj ) {
- var type;
- if ( obj === null ) {
- type = "null";
- } else if ( typeof obj === "undefined" ) {
- type = "undefined";
- } else if ( QUnit.is( "regexp", obj) ) {
- type = "regexp";
- } else if ( QUnit.is( "date", obj) ) {
- type = "date";
- } else if ( QUnit.is( "function", obj) ) {
- type = "function";
- } else if ( typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined" ) {
- type = "window";
- } else if ( obj.nodeType === 9 ) {
- type = "document";
- } else if ( obj.nodeType ) {
- type = "node";
- } else if (
- // native arrays
- toString.call( obj ) === "[object Array]" ||
- // NodeList objects
- ( typeof obj.length === "number" && typeof obj.item !== "undefined" && ( obj.length ? obj.item(0) === obj[0] : ( obj.item( 0 ) === null && typeof obj[0] === "undefined" ) ) )
- ) {
- type = "array";
- } else if ( obj.constructor === Error.prototype.constructor ) {
- type = "error";
- } else {
- type = typeof obj;
- }
- return type;
- },
- separator: function() {
- return this.multiline ? this.HTML ? "
" : "\n" : this.HTML ? " " : " ";
- },
- // extra can be a number, shortcut for increasing-calling-decreasing
- indent: function( extra ) {
- if ( !this.multiline ) {
- return "";
- }
- var chr = this.indentChar;
- if ( this.HTML ) {
- chr = chr.replace( /\t/g, " " ).replace( / /g, " " );
- }
- return new Array( this._depth_ + (extra||0) ).join(chr);
- },
- up: function( a ) {
- this._depth_ += a || 1;
- },
- down: function( a ) {
- this._depth_ -= a || 1;
- },
- setParser: function( name, parser ) {
- this.parsers[name] = parser;
- },
- // The next 3 are exposed so you can use them
- quote: quote,
- literal: literal,
- join: join,
- //
- _depth_: 1,
- // This is the list of parsers, to modify them, use jsDump.setParser
- parsers: {
- window: "[Window]",
- document: "[Document]",
- error: function(error) {
- return "Error(\"" + error.message + "\")";
- },
- unknown: "[Unknown]",
- "null": "null",
- "undefined": "undefined",
- "function": function( fn ) {
- var ret = "function",
- // functions never have name in IE
- name = "name" in fn ? fn.name : (reName.exec(fn) || [])[1];
-
- if ( name ) {
- ret += " " + name;
- }
- ret += "( ";
-
- ret = [ ret, QUnit.jsDump.parse( fn, "functionArgs" ), "){" ].join( "" );
- return join( ret, QUnit.jsDump.parse(fn,"functionCode" ), "}" );
- },
- array: array,
- nodelist: array,
- "arguments": array,
- object: function( map, stack ) {
- var ret = [ ], keys, key, val, i;
- QUnit.jsDump.up();
- keys = [];
- for ( key in map ) {
- keys.push( key );
- }
- keys.sort();
- for ( i = 0; i < keys.length; i++ ) {
- key = keys[ i ];
- val = map[ key ];
- ret.push( QUnit.jsDump.parse( key, "key" ) + ": " + QUnit.jsDump.parse( val, undefined, stack ) );
- }
- QUnit.jsDump.down();
- return join( "{", ret, "}" );
- },
- node: function( node ) {
- var len, i, val,
- open = QUnit.jsDump.HTML ? "<" : "<",
- close = QUnit.jsDump.HTML ? ">" : ">",
- tag = node.nodeName.toLowerCase(),
- ret = open + tag,
- attrs = node.attributes;
-
- if ( attrs ) {
- for ( i = 0, len = attrs.length; i < len; i++ ) {
- val = attrs[i].nodeValue;
- // IE6 includes all attributes in .attributes, even ones not explicitly set.
- // Those have values like undefined, null, 0, false, "" or "inherit".
- if ( val && val !== "inherit" ) {
- ret += " " + attrs[i].nodeName + "=" + QUnit.jsDump.parse( val, "attribute" );
- }
- }
- }
- ret += close;
-
- // Show content of TextNode or CDATASection
- if ( node.nodeType === 3 || node.nodeType === 4 ) {
- ret += node.nodeValue;
- }
-
- return ret + open + "/" + tag + close;
- },
- // function calls it internally, it's the arguments part of the function
- functionArgs: function( fn ) {
- var args,
- l = fn.length;
-
- if ( !l ) {
- return "";
- }
-
- args = new Array(l);
- while ( l-- ) {
- // 97 is 'a'
- args[l] = String.fromCharCode(97+l);
- }
- return " " + args.join( ", " ) + " ";
- },
- // object calls it internally, the key part of an item in a map
- key: quote,
- // function calls it internally, it's the content of the function
- functionCode: "[code]",
- // node calls it internally, it's an html attribute value
- attribute: quote,
- string: quote,
- date: quote,
- regexp: literal,
- number: literal,
- "boolean": literal
- },
- // if true, entities are escaped ( <, >, \t, space and \n )
- HTML: false,
- // indentation unit
- indentChar: " ",
- // if true, items in a collection, are separated by a \n, else just a space.
- multiline: true
- };
-
- return jsDump;
-}());
-
-// from jquery.js
-function inArray( elem, array ) {
- if ( array.indexOf ) {
- return array.indexOf( elem );
- }
-
- for ( var i = 0, length = array.length; i < length; i++ ) {
- if ( array[ i ] === elem ) {
- return i;
- }
- }
-
- return -1;
-}
-
-/*
- * Javascript Diff Algorithm
- * By John Resig (http://ejohn.org/)
- * Modified by Chu Alan "sprite"
- *
- * Released under the MIT license.
- *
- * More Info:
- * http://ejohn.org/projects/javascript-diff-algorithm/
- *
- * Usage: QUnit.diff(expected, actual)
- *
- * QUnit.diff( "the quick brown fox jumped over", "the quick fox jumps over" ) == "the quick brown fox jumped jumps over"
- */
-QUnit.diff = (function() {
- /*jshint eqeqeq:false, eqnull:true */
- function diff( o, n ) {
- var i,
- ns = {},
- os = {};
-
- for ( i = 0; i < n.length; i++ ) {
- if ( !hasOwn.call( ns, n[i] ) ) {
- ns[ n[i] ] = {
- rows: [],
- o: null
- };
- }
- ns[ n[i] ].rows.push( i );
- }
-
- for ( i = 0; i < o.length; i++ ) {
- if ( !hasOwn.call( os, o[i] ) ) {
- os[ o[i] ] = {
- rows: [],
- n: null
- };
- }
- os[ o[i] ].rows.push( i );
- }
-
- for ( i in ns ) {
- if ( !hasOwn.call( ns, i ) ) {
- continue;
- }
- if ( ns[i].rows.length === 1 && hasOwn.call( os, i ) && os[i].rows.length === 1 ) {
- n[ ns[i].rows[0] ] = {
- text: n[ ns[i].rows[0] ],
- row: os[i].rows[0]
- };
- o[ os[i].rows[0] ] = {
- text: o[ os[i].rows[0] ],
- row: ns[i].rows[0]
- };
- }
- }
-
- for ( i = 0; i < n.length - 1; i++ ) {
- if ( n[i].text != null && n[ i + 1 ].text == null && n[i].row + 1 < o.length && o[ n[i].row + 1 ].text == null &&
- n[ i + 1 ] == o[ n[i].row + 1 ] ) {
-
- n[ i + 1 ] = {
- text: n[ i + 1 ],
- row: n[i].row + 1
- };
- o[ n[i].row + 1 ] = {
- text: o[ n[i].row + 1 ],
- row: i + 1
- };
- }
- }
-
- for ( i = n.length - 1; i > 0; i-- ) {
- if ( n[i].text != null && n[ i - 1 ].text == null && n[i].row > 0 && o[ n[i].row - 1 ].text == null &&
- n[ i - 1 ] == o[ n[i].row - 1 ]) {
-
- n[ i - 1 ] = {
- text: n[ i - 1 ],
- row: n[i].row - 1
- };
- o[ n[i].row - 1 ] = {
- text: o[ n[i].row - 1 ],
- row: i - 1
- };
- }
- }
-
- return {
- o: o,
- n: n
- };
- }
-
- return function( o, n ) {
- o = o.replace( /\s+$/, "" );
- n = n.replace( /\s+$/, "" );
-
- var i, pre,
- str = "",
- out = diff( o === "" ? [] : o.split(/\s+/), n === "" ? [] : n.split(/\s+/) ),
- oSpace = o.match(/\s+/g),
- nSpace = n.match(/\s+/g);
-
- if ( oSpace == null ) {
- oSpace = [ " " ];
- }
- else {
- oSpace.push( " " );
- }
-
- if ( nSpace == null ) {
- nSpace = [ " " ];
- }
- else {
- nSpace.push( " " );
- }
-
- if ( out.n.length === 0 ) {
- for ( i = 0; i < out.o.length; i++ ) {
- str += "" + out.o[i] + oSpace[i] + "";
- }
- }
- else {
- if ( out.n[0].text == null ) {
- for ( n = 0; n < out.o.length && out.o[n].text == null; n++ ) {
- str += "" + out.o[n] + oSpace[n] + "";
- }
- }
-
- for ( i = 0; i < out.n.length; i++ ) {
- if (out.n[i].text == null) {
- str += "" + out.n[i] + nSpace[i] + "";
- }
- else {
- // `pre` initialized at top of scope
- pre = "";
-
- for ( n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++ ) {
- pre += "" + out.o[n] + oSpace[n] + "";
- }
- str += " " + out.n[i].text + nSpace[i] + pre;
- }
- }
- }
-
- return str;
- };
-}());
-
-// for CommonJS enviroments, export everything
-if ( typeof exports !== "undefined" ) {
- extend( exports, QUnit );
-}
-
-// get at whatever the global object is, like window in browsers
-}( (function() {return this;}.call()) ));
diff --git a/test/lib/require.js b/test/lib/require.js
deleted file mode 100644
index 987f865..0000000
--- a/test/lib/require.js
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- RequireJS 2.1.5 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.
- Available via the MIT or new BSD license.
- see: http://github.com/jrburke/requirejs for details
-*/
-var requirejs,require,define;
-(function(aa){function I(b){return"[object Function]"===L.call(b)}function J(b){return"[object Array]"===L.call(b)}function y(b,c){if(b){var d;for(d=0;dthis.depCount&&!this.defined){if(I(n)){if(this.events.error)try{e=i.execCb(c,n,b,e)}catch(d){a=d}else e=i.execCb(c,n,b,e);this.map.isDefine&&((b=this.module)&&void 0!==b.exports&&b.exports!==this.exports?e=b.exports:void 0===e&&this.usingExports&&(e=this.exports));if(a)return a.requireMap=this.map,a.requireModules=[this.map.id],a.requireType="define",v(this.error=
-a)}else e=n;this.exports=e;if(this.map.isDefine&&!this.ignore&&(q[c]=e,l.onResourceLoad))l.onResourceLoad(i,this.map,this.depMaps);x(c);this.defined=!0}this.defining=!1;this.defined&&!this.defineEmitted&&(this.defineEmitted=!0,this.emit("defined",this.exports),this.defineEmitComplete=!0)}}else this.fetch()}},callPlugin:function(){var a=this.map,b=a.id,d=j(a.prefix);this.depMaps.push(d);t(d,"defined",u(this,function(e){var n,d;d=this.map.name;var g=this.map.parentMap?this.map.parentMap.name:null,h=
-i.makeRequire(a.parentMap,{enableBuildCallback:!0});if(this.map.unnormalized){if(e.normalize&&(d=e.normalize(d,function(a){return c(a,g,!0)})||""),e=j(a.prefix+"!"+d,this.map.parentMap),t(e,"defined",u(this,function(a){this.init([],function(){return a},null,{enabled:!0,ignore:!0})})),d=m(p,e.id)){this.depMaps.push(e);if(this.events.error)d.on("error",u(this,function(a){this.emit("error",a)}));d.enable()}}else n=u(this,function(a){this.init([],function(){return a},null,{enabled:!0})}),n.error=u(this,
-function(a){this.inited=!0;this.error=a;a.requireModules=[b];G(p,function(a){0===a.map.id.indexOf(b+"_unnormalized")&&x(a.map.id)});v(a)}),n.fromText=u(this,function(e,c){var d=a.name,g=j(d),C=O;c&&(e=c);C&&(O=!1);r(g);s(k.config,b)&&(k.config[d]=k.config[b]);try{l.exec(e)}catch(ca){return v(B("fromtexteval","fromText eval for "+b+" failed: "+ca,ca,[b]))}C&&(O=!0);this.depMaps.push(g);i.completeLoad(d);h([d],n)}),e.load(a.name,h,n,k)}));i.enable(d,this);this.pluginMaps[d.id]=d},enable:function(){V[this.map.id]=
-this;this.enabling=this.enabled=!0;y(this.depMaps,u(this,function(a,b){var c,e;if("string"===typeof a){a=j(a,this.map.isDefine?this.map:this.map.parentMap,!1,!this.skipMap);this.depMaps[b]=a;if(c=m(N,a.id)){this.depExports[b]=c(this);return}this.depCount+=1;t(a,"defined",u(this,function(a){this.defineDep(b,a);this.check()}));this.errback&&t(a,"error",this.errback)}c=a.id;e=p[c];!s(N,c)&&(e&&!e.enabled)&&i.enable(a,this)}));G(this.pluginMaps,u(this,function(a){var b=m(p,a.id);b&&!b.enabled&&i.enable(a,
-this)}));this.enabling=!1;this.check()},on:function(a,b){var c=this.events[a];c||(c=this.events[a]=[]);c.push(b)},emit:function(a,b){y(this.events[a],function(a){a(b)});"error"===a&&delete this.events[a]}};i={config:k,contextName:b,registry:p,defined:q,urlFetched:U,defQueue:H,Module:Z,makeModuleMap:j,nextTick:l.nextTick,onError:v,configure:function(a){a.baseUrl&&"/"!==a.baseUrl.charAt(a.baseUrl.length-1)&&(a.baseUrl+="/");var b=k.pkgs,c=k.shim,e={paths:!0,config:!0,map:!0};G(a,function(a,b){e[b]?
-"map"===b?(k.map||(k.map={}),R(k[b],a,!0,!0)):R(k[b],a,!0):k[b]=a});a.shim&&(G(a.shim,function(a,b){J(a)&&(a={deps:a});if((a.exports||a.init)&&!a.exportsFn)a.exportsFn=i.makeShimExports(a);c[b]=a}),k.shim=c);a.packages&&(y(a.packages,function(a){a="string"===typeof a?{name:a}:a;b[a.name]={name:a.name,location:a.location||a.name,main:(a.main||"main").replace(ja,"").replace(ea,"")}}),k.pkgs=b);G(p,function(a,b){!a.inited&&!a.map.unnormalized&&(a.map=j(b))});if(a.deps||a.callback)i.require(a.deps||[],
-a.callback)},makeShimExports:function(a){return function(){var b;a.init&&(b=a.init.apply(aa,arguments));return b||a.exports&&ba(a.exports)}},makeRequire:function(a,f){function d(e,c,h){var g,k;f.enableBuildCallback&&(c&&I(c))&&(c.__requireJsBuild=!0);if("string"===typeof e){if(I(c))return v(B("requireargs","Invalid require call"),h);if(a&&s(N,e))return N[e](p[a.id]);if(l.get)return l.get(i,e,a,d);g=j(e,a,!1,!0);g=g.id;return!s(q,g)?v(B("notloaded",'Module name "'+g+'" has not been loaded yet for context: '+
-b+(a?"":". Use require([])"))):q[g]}L();i.nextTick(function(){L();k=r(j(null,a));k.skipMap=f.skipMap;k.init(e,c,h,{enabled:!0});D()});return d}f=f||{};R(d,{isBrowser:A,toUrl:function(b){var d,f=b.lastIndexOf("."),g=b.split("/")[0];if(-1!==f&&(!("."===g||".."===g)||1h.attachEvent.toString().indexOf("[native code"))&&!Y?(O=!0,h.attachEvent("onreadystatechange",b.onScriptLoad)):(h.addEventListener("load",b.onScriptLoad,!1),h.addEventListener("error",b.onScriptError,!1)),h.src=d,K=h,D?x.insertBefore(h,D):x.appendChild(h),K=null,h;if(da)try{importScripts(d),b.completeLoad(c)}catch(j){b.onError(B("importscripts","importScripts failed for "+c+" at "+d,j,[c]))}};A&&M(document.getElementsByTagName("script"),function(b){x||(x=
-b.parentNode);if(t=b.getAttribute("data-main"))return r.baseUrl||(E=t.split("/"),Q=E.pop(),fa=E.length?E.join("/")+"/":"./",r.baseUrl=fa,t=Q),t=t.replace(ea,""),r.deps=r.deps?r.deps.concat(t):[t],!0});define=function(b,c,d){var l,h;"string"!==typeof b&&(d=c,c=b,b=null);J(c)||(d=c,c=[]);!c.length&&I(d)&&d.length&&(d.toString().replace(la,"").replace(ma,function(b,d){c.push(d)}),c=(1===d.length?["require"]:["require","exports","module"]).concat(c));if(O){if(!(l=K))P&&"interactive"===P.readyState||M(document.getElementsByTagName("script"),
-function(b){if("interactive"===b.readyState)return P=b}),l=P;l&&(b||(b=l.getAttribute("data-requiremodule")),h=F[l.getAttribute("data-requirecontext")])}(h?h.defQueue:T).push([b,c,d])};define.amd={jQuery:!0};l.exec=function(b){return eval(b)};l(r)}})(this);
diff --git a/test/lib/resemble.js b/test/lib/resemble.js
new file mode 100644
index 0000000..1cb8c29
--- /dev/null
+++ b/test/lib/resemble.js
@@ -0,0 +1,535 @@
+/*
+Author: James Cryer
+Company: Huddle
+Last updated date: 21 Feb 2013
+URL: https://github.com/Huddle/Resemble.js
+*/
+
+(function(_this){
+ 'use strict';
+
+ _this['resemble'] = function( fileData ){
+
+ var data = {};
+ var images = [];
+ var updateCallbackArray = [];
+
+ var tolerance = { // between 0 and 255
+ red: 16,
+ green: 16,
+ blue: 16,
+ minBrightness: 16,
+ maxBrightness: 240
+ };
+
+ var ignoreAntialiasing = false;
+ var ignoreColors = false;
+
+ function triggerDataUpdate(){
+ var len = updateCallbackArray.length;
+ var i;
+ for(i=0;i tolerance.maxBrightness;
+ }
+
+ function getHue(r,g,b){
+
+ r = r / 255;
+ g = g / 255;
+ b = b / 255;
+ var max = Math.max(r, g, b), min = Math.min(r, g, b);
+ var h;
+ var d;
+
+ if (max == min){
+ h = 0; // achromatic
+ } else{
+ d = max - min;
+ switch(max){
+ case r: h = (g - b) / d + (g < b ? 6 : 0); break;
+ case g: h = (b - r) / d + 2; break;
+ case b: h = (r - g) / d + 4; break;
+ }
+ h /= 6;
+ }
+
+ return h;
+ }
+
+ function isAntialiased(sourcePix, data, cacheSet, verticalPos, horizontalPos, width){
+ var offset;
+ var targetPix;
+ var distance = 1;
+ var i;
+ var j;
+ var hasHighContrastSibling = 0;
+ var hasSiblingWithDifferentHue = 0;
+ var hasEquivilantSibling = 0;
+
+ addHueInfo(sourcePix);
+
+ for (i = distance*-1; i <= distance; i++){
+ for (j = distance*-1; j <= distance; j++){
+
+ if(i===0 && j===0){
+ // ignore source pixel
+ } else {
+
+ offset = ((verticalPos+j)*width + (horizontalPos+i)) * 4;
+ targetPix = getPixelInfo(data, offset, cacheSet);
+
+ if(targetPix === null){
+ continue;
+ }
+
+ addBrightnessInfo(targetPix);
+ addHueInfo(targetPix);
+
+ if( isContrasting(sourcePix, targetPix) ){
+ hasHighContrastSibling++;
+ }
+
+ if( isRGBSame(sourcePix,targetPix) ){
+ hasEquivilantSibling++;
+ }
+
+ if( Math.abs(targetPix.h - sourcePix.h) > 0.3 ){
+ hasSiblingWithDifferentHue++;
+ }
+
+ if( hasSiblingWithDifferentHue > 1 || hasHighContrastSibling > 1){
+ return true;
+ }
+ }
+ }
+ }
+
+ if(hasEquivilantSibling < 2){
+ return true;
+ }
+
+ return false;
+ }
+
+ function errorPixel(px, offset){
+ px[offset] = 255; //r
+ px[offset + 1] = 0; //g
+ px[offset + 2] = 255; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyPixel(px, offset, data){
+ px[offset] = data.r; //r
+ px[offset + 1] = data.g; //g
+ px[offset + 2] = data.b; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyGrayScalePixel(px, offset, data){
+ px[offset] = data.brightness; //r
+ px[offset + 1] = data.brightness; //g
+ px[offset + 2] = data.brightness; //b
+ px[offset + 3] = 255; //a
+ }
+
+
+ function getPixelInfo(data, offset, cacheSet){
+ var r;
+ var g;
+ var b;
+ var d;
+
+ if(typeof data[offset] !== 'undefined'){
+ r = data[offset];
+ g = data[offset+1];
+ b = data[offset+2];
+ d = {
+ r: r,
+ g: g,
+ b: b
+ };
+
+ return d;
+ } else {
+ return null;
+ }
+ }
+
+ function addBrightnessInfo(data){
+ data.brightness = getBrightness(data.r,data.g,data.b); // 'corrected' lightness
+ }
+
+ function addHueInfo(data){
+ data.h = getHue(data.r,data.g,data.b);
+ }
+
+ function analyseImages(img1, img2, width, height){
+
+ var hiddenCanvas = document.createElement('canvas');
+
+ var data1 = img1.data;
+ var data2 = img2.data;
+
+ hiddenCanvas.width = width;
+ hiddenCanvas.height = height;
+
+ var context = hiddenCanvas.getContext('2d');
+ var imgd = context.createImageData(width,height);
+ var targetPix = imgd.data;
+
+ var mismatchCount = 0;
+
+ var time = Date.now();
+
+ var skip;
+
+ if( (width > 1200 || height > 1200) && ignoreAntialiasing){
+ skip = 6;
+ }
+
+ loop(height, width, function(verticalPos, horizontalPos){
+
+ if(skip){ // only skip if the image isn't small
+ if(verticalPos % skip === 0 || horizontalPos % skip === 0){
+ return;
+ }
+ }
+
+ var offset = (verticalPos*width + horizontalPos) * 4;
+ var pixel1 = getPixelInfo(data1, offset, 1);
+ var pixel2 = getPixelInfo(data2, offset, 2);
+
+ if(pixel1 === null || pixel2 === null){
+ return;
+ }
+
+ if (ignoreColors){
+
+ addBrightnessInfo(pixel1);
+ addBrightnessInfo(pixel2);
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ return;
+ }
+
+ if( isRGBSimilar(pixel1, pixel2) ){
+ copyPixel(targetPix, offset, pixel2);
+
+ } else if( ignoreAntialiasing && (
+ addBrightnessInfo(pixel1), // jit pixel info augmentation looks a little weird, sorry.
+ addBrightnessInfo(pixel2),
+ isAntialiased(pixel1, data1, 1, verticalPos, horizontalPos, width) ||
+ isAntialiased(pixel2, data2, 2, verticalPos, horizontalPos, width)
+ )){
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+
+ });
+
+ data.misMatchPercentage = (mismatchCount / (height*width) * 100).toFixed(2);
+ data.analysisTime = Date.now() - time;
+
+ data.getImageDataUrl = function(text){
+ var barHeight = 0;
+
+ if(text){
+ barHeight = addLabel(text,context,hiddenCanvas);
+ }
+
+ context.putImageData(imgd, 0, barHeight);
+
+ return hiddenCanvas.toDataURL("image/png");
+ };
+ }
+
+ function addLabel(text, context, hiddenCanvas){
+ var textPadding = 2;
+
+ context.font = '12px sans-serif';
+
+ var textWidth = context.measureText(text).width + textPadding*2;
+ var barHeight = 22;
+
+ if(textWidth > hiddenCanvas.width){
+ hiddenCanvas.width = textWidth;
+ }
+
+ hiddenCanvas.height += barHeight;
+
+ context.fillStyle = "#666";
+ context.fillRect(0,0,hiddenCanvas.width,barHeight -4);
+ context.fillStyle = "#fff";
+ context.fillRect(0,barHeight -4,hiddenCanvas.width, 4);
+
+ context.fillStyle = "#fff";
+ context.textBaseline = "top";
+ context.font = '12px sans-serif';
+ context.fillText(text, textPadding, 1);
+
+ return barHeight;
+ }
+
+ function normalise(img, w, h){
+ var c;
+ var context;
+
+ if(img.height < h || img.width < w){
+ c = document.createElement('canvas');
+ c.width = w;
+ c.height = h;
+ context = c.getContext('2d');
+ context.putImageData(img, 0, 0);
+ return context.getImageData(0, 0, w, h);
+ }
+
+ return img;
+ }
+
+ function compare(one, two){
+
+ function onceWeHaveBoth(){
+ var width;
+ var height;
+ if(images.length === 2){
+ width = images[0].width > images[1].width ? images[0].width : images[1].width;
+ height = images[0].height > images[1].height ? images[0].height : images[1].height;
+
+ if( (images[0].width === images[1].width) && (images[0].height === images[1].height) ){
+ data.isSameDimensions = true;
+ } else {
+ data.isSameDimensions = false;
+ }
+
+ analyseImages( normalise(images[0],width, height), normalise(images[1],width, height), width, height);
+
+ triggerDataUpdate();
+ }
+ }
+
+ images = [];
+ loadImageData(one, onceWeHaveBoth);
+ loadImageData(two, onceWeHaveBoth);
+ }
+
+ function getCompareApi(param){
+
+ var secondFileData,
+ hasMethod = typeof param === 'function';
+
+ if( !hasMethod ){
+ // assume it's file data
+ secondFileData = param;
+ }
+
+ var self = {
+ ignoreNothing: function(){
+
+ tolerance.red = 16;
+ tolerance.green = 16;
+ tolerance.blue = 16;
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreAntialiasing: function(){
+
+ tolerance.red = 32;
+ tolerance.green = 32;
+ tolerance.blue = 32;
+ tolerance.minBrightness = 64;
+ tolerance.maxBrightness = 96;
+
+ ignoreAntialiasing = true;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreColors: function(){
+
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = true;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ onComplete: function( callback ){
+
+ updateCallbackArray.push(callback);
+
+ var wrapper = function(){
+ compare(fileData, secondFileData);
+ };
+
+ wrapper();
+
+ return getCompareApi(wrapper);
+ }
+ };
+
+ return self;
+ }
+
+ return {
+ onComplete: function( callback ){
+ updateCallbackArray.push(callback);
+ loadImageData(fileData, function(imageData, width, height){
+ parseImage(imageData.data, width, height);
+ });
+ },
+ compareTo: function(secondFileData){
+ return getCompareApi(secondFileData);
+ }
+ };
+
+ };
+}(this));
\ No newline at end of file
diff --git a/test/testsuite.js b/test/testsuite.js
deleted file mode 100644
index b486acb..0000000
--- a/test/testsuite.js
+++ /dev/null
@@ -1,36 +0,0 @@
-requirejs.config({
- baseUrl: '/test/unit/'
-});
-
-define(function(require) {
- var testModules = [
- 'Pixi',
- 'Point',
- 'Rectangle',
- 'DisplayObject',
- 'DisplayObjectContainer',
- 'Sprite',
- 'MovieClip',
- 'InteractionManager',
- 'Stage',
- 'utils/Utils',
- 'utils/EventTarget',
- 'utils/Matrix',
- 'utils/Detector',
- 'renderers/WebGLShaders',
- 'renderers/WebGLRenderer',
- 'renderers/WebGLBatch',
- 'renderers/CanvasRenderer',
- 'extras/Strip',
- 'extras/Rope',
- 'textures/BaseTexture',
- 'textures/Texture',
- 'loaders/SpriteSheetLoader',
- 'loaders/AssetLoader'
- ];
-
- // Resolve all testModules and then start the Test Runner.
- require(testModules, function() {
- QUnit.start();
- });
-});
\ No newline at end of file
diff --git a/test/textures/SpriteSheet-Aliens.png b/test/textures/SpriteSheet-Aliens.png
new file mode 100644
index 0000000..210acb1
--- /dev/null
+++ b/test/textures/SpriteSheet-Aliens.png
Binary files differ
diff --git a/test/textures/SpriteSheet-Explosion.png b/test/textures/SpriteSheet-Explosion.png
new file mode 100755
index 0000000..79e1a69
--- /dev/null
+++ b/test/textures/SpriteSheet-Explosion.png
Binary files differ
diff --git a/test/textures/bunny.png b/test/textures/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/textures/bunny.png
Binary files differ
diff --git a/test/unit/DisplayObject.js b/test/unit/DisplayObject.js
deleted file mode 100644
index 5e7e72f..0000000
--- a/test/unit/DisplayObject.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObject');
-});
diff --git a/test/unit/DisplayObjectContainer.js b/test/unit/DisplayObjectContainer.js
deleted file mode 100644
index b323959..0000000
--- a/test/unit/DisplayObjectContainer.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObjectContainer');
-});
diff --git a/test/unit/InteractionManager.js b/test/unit/InteractionManager.js
deleted file mode 100644
index e751f52..0000000
--- a/test/unit/InteractionManager.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('InteractionManager');
-});
diff --git a/test/unit/MovieClip.js b/test/unit/MovieClip.js
deleted file mode 100644
index 37d9446..0000000
--- a/test/unit/MovieClip.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('MovieClip');
-});
diff --git a/test/unit/Pixi.js b/test/unit/Pixi.js
deleted file mode 100644
index 36eee73..0000000
--- a/test/unit/Pixi.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Pixi');
-});
diff --git a/test/unit/Point.js b/test/unit/Point.js
deleted file mode 100644
index 983ff6e..0000000
--- a/test/unit/Point.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Point');
-});
diff --git a/test/unit/Rectangle.js b/test/unit/Rectangle.js
deleted file mode 100644
index 3b439ba..0000000
--- a/test/unit/Rectangle.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Rectangle');
-});
diff --git a/test/unit/Sprite.js b/test/unit/Sprite.js
deleted file mode 100644
index ed4f596..0000000
--- a/test/unit/Sprite.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Sprite');
-});
diff --git a/test/unit/Stage.js b/test/unit/Stage.js
deleted file mode 100644
index 2d70291..0000000
--- a/test/unit/Stage.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Stage');
-});
diff --git a/test/unit/extras/Rope.js b/test/unit/extras/Rope.js
deleted file mode 100644
index 5606f14..0000000
--- a/test/unit/extras/Rope.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Rope');
-});
diff --git a/test/unit/extras/Strip.js b/test/unit/extras/Strip.js
deleted file mode 100644
index 0134d3a..0000000
--- a/test/unit/extras/Strip.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Strip');
-});
diff --git a/test/unit/loaders/AssetLoader.js b/test/unit/loaders/AssetLoader.js
deleted file mode 100644
index 13b8443..0000000
--- a/test/unit/loaders/AssetLoader.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('AssetLoader');
-});
diff --git a/test/unit/loaders/SpriteSheetLoader.js b/test/unit/loaders/SpriteSheetLoader.js
deleted file mode 100644
index 8bf0cb2..0000000
--- a/test/unit/loaders/SpriteSheetLoader.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('SpriteSheetLoader');
-});
diff --git a/test/unit/pixi/InteractionManager.js b/test/unit/pixi/InteractionManager.js
new file mode 100644
index 0000000..ed3001f
--- /dev/null
+++ b/test/unit/pixi/InteractionManager.js
@@ -0,0 +1,10 @@
+describe('pixi/InteractionManager', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var InteractionManager = PIXI.InteractionManager;
+
+ it('Module exists', function () {
+ expect(InteractionManager).to.be.a('function');
+ });
+});
diff --git a/.gitignore b/.gitignore
index 12e1b62..0b88317 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
node_modules
.DS_Store
-.project
\ No newline at end of file
+.project
+*.log
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..63e4d7c
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,8 @@
+language: node_js
+node_js:
+ - 0.10
+
+before_script:
+ - npm install -g grunt-cli
+ - export DISPLAY=:99.0
+ - sh -e /etc/init.d/xvfb start
diff --git a/Gruntfile.js b/Gruntfile.js
index b083b49..103938c 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -1,10 +1,12 @@
+'use strict';
+
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-connect');
- grunt.loadNpmTasks('grunt-contrib-qunit');
grunt.loadNpmTasks('grunt-contrib-yuidoc');
+ grunt.loadTasks('tasks');
var root = 'src/pixi/',
debug = 'bin/pixi.dev.js',
@@ -79,7 +81,7 @@
},
files: {
srcBlob: '<%= dirs.src %>/**/*.js',
- testBlob: '<%= dirs.test %>/unit/**/*.js',
+ testBlob: '<%= dirs.test %>/{functional,lib/pixi,unit}/**/*.js',
build: '<%= dirs.build %>/pixi.dev.js',
buildMin: '<%= dirs.build %>/pixi.js'
},
@@ -94,7 +96,12 @@
},
jshint: {
beforeconcat: srcFiles,
- test: ['<%= files.testBlob %>'],
+ test: {
+ src: ['<%= files.testBlob %>'],
+ options: {
+ expr: true
+ }
+ },
options: {
asi: true,
smarttabs: true
@@ -128,12 +135,6 @@
]
},
connect: {
- qunit: {
- options: {
- port: grunt.option('port-test') || 9002,
- base: './'
- }
- },
test: {
options: {
port: grunt.option('port-test') || 9002,
@@ -142,13 +143,6 @@
}
}
},
- qunit: {
- all: {
- options: {
- urls: ['http://localhost:' + (grunt.option('port-test') || 9002) + '/test/index.html']
- }
- }
- },
yuidoc: {
compile: {
name: '<%= pkg.name %>',
@@ -161,6 +155,13 @@
outdir: '<%= dirs.docs %>'
}
}
+ },
+ karma: {
+ unit: {
+ configFile: 'test/karma.conf.js',
+ // browsers: ['Chrome'],
+ singleRun: true
+ }
}
});
@@ -182,9 +183,10 @@
}
)
- grunt.registerTask('default', ['concat', 'uglify', 'distribute']);
grunt.registerTask('build', ['concat', 'uglify', 'distribute']);
- grunt.registerTask('test', ['build', 'connect:qunit', 'qunit']);
+ grunt.registerTask('test', ['concat', 'jshint:test', 'karma']);
grunt.registerTask('docs', ['yuidoc']);
-
-}
\ No newline at end of file
+ grunt.registerTask('default', ['test', 'uglify', 'distribute']);
+ // Travis CI task.
+ grunt.registerTask('travis', ['test']);
+}
diff --git a/README.md b/README.md
index c62ef86..690cfe4 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,8 @@

+[](http://travis-ci.org/drkibitz/pixi.js)
+
#### JavaScript 2D Renderer ####
The aim of this project is to provide a fast lightweight 2D library that works
diff --git a/package.json b/package.json
index b373240..1246a68 100644
--- a/package.json
+++ b/package.json
@@ -18,14 +18,21 @@
"main": "bin/pixi.js",
+ "scripts": {
+ "test": "grunt travis --verbose"
+ },
+
"dependencies": {},
"devDependencies": {
"grunt": "~0.4.x",
- "grunt-contrib-jshint": "0.3.x",
+ "grunt-contrib-jshint": "0.6.x",
"grunt-contrib-uglify": "0.2.x",
- "grunt-contrib-connect": "0.2.x",
- "grunt-contrib-qunit": "0.2.x",
+ "grunt-contrib-connect": "0.3.x",
"grunt-contrib-yuidoc": "0.4.x",
- "grunt-contrib-concat": "0.1.x"
+ "grunt-contrib-concat": "0.3.x",
+ "chai": "~1.7.0",
+ "karma": "0.11.0",
+ "karma-firefox-launcher": "0.1.0",
+ "karma-mocha": "0.1.0"
}
}
diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js
index a7c520e..ee82bbd 100644
--- a/src/pixi/InteractionManager.js
+++ b/src/pixi/InteractionManager.js
@@ -62,7 +62,6 @@
this.onTouchEnd = this.onTouchEnd.bind(this);
this.onTouchMove = this.onTouchMove.bind(this);
-
this.last = 0;
}
diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js
index 1a95d20..eef1059 100644
--- a/src/pixi/core/Ellipse.js
+++ b/src/pixi/core/Ellipse.js
@@ -78,7 +78,7 @@
return (normx + normy < 0.25);
}
-PIXI.Ellipse.getBounds = function()
+PIXI.Ellipse.prototype.getBounds = function()
{
return new PIXI.Rectangle(this.x, this.y, this.width, this.height);
}
diff --git a/tasks/karma.js b/tasks/karma.js
new file mode 100644
index 0000000..c340485
--- /dev/null
+++ b/tasks/karma.js
@@ -0,0 +1,27 @@
+'use strict';
+
+var path = require('path');
+var server = require('karma').server;
+
+module.exports = function (grunt) {
+ grunt.registerMultiTask('karma', 'run karma.', function() {
+ var done = this.async();
+ var options = this.options({
+ background: false
+ });
+ var data = this.data;
+
+ //merge options onto data, with data taking precedence
+ data = grunt.util._.merge(options, data);
+ data.configFile = path.resolve(data.configFile);
+ if (data.configFile) {
+ data.configFile = grunt.template.process(data.configFile);
+ }
+
+ server.start(
+ data,
+ function(code) {
+ done(!code);
+ });
+ });
+};
diff --git a/test/functional/example-1-basics/bunny.png b/test/functional/example-1-basics/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/functional/example-1-basics/bunny.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-30.png b/test/functional/example-1-basics/frame-30.png
new file mode 100644
index 0000000..96e3409
--- /dev/null
+++ b/test/functional/example-1-basics/frame-30.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-60.png b/test/functional/example-1-basics/frame-60.png
new file mode 100644
index 0000000..af3f4ce
--- /dev/null
+++ b/test/functional/example-1-basics/frame-60.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-90.png b/test/functional/example-1-basics/frame-90.png
new file mode 100644
index 0000000..099b823
--- /dev/null
+++ b/test/functional/example-1-basics/frame-90.png
Binary files differ
diff --git a/test/functional/example-1-basics/index.js b/test/functional/example-1-basics/index.js
new file mode 100644
index 0000000..7ae7a98
--- /dev/null
+++ b/test/functional/example-1-basics/index.js
@@ -0,0 +1,133 @@
+describe('Example 1 - Basics', function () {
+ 'use strict';
+
+ var baseUri = '/base/test/functional/example-1-basics';
+ var expect = chai.expect;
+ var currentFrame = 0;
+ var frameEvents = {};
+ var stage;
+ var renderer;
+ var bunny;
+
+ function onFrame(frame, callback) {
+ frameEvents[frame] = callback;
+ }
+
+ function animate() {
+ currentFrame += 1;
+
+ requestAnimFrame( animate );
+
+ // just for fun, lets rotate mr rabbit a little
+ bunny.rotation += 0.1;
+
+ // render the stage
+ renderer.render(stage);
+
+ if (frameEvents[currentFrame])
+ frameEvents[currentFrame](currentFrame);
+ }
+
+ function initScene() {
+ // create an new instance of a pixi stage
+ stage = new PIXI.Stage(0x66FF99);
+
+ // create a renderer instance
+ renderer = PIXI.autoDetectRenderer(400, 300);
+ console.log('Is PIXI.WebGLRenderer: ' + (renderer instanceof PIXI.WebGLRenderer));
+
+ // add the renderer view element to the DOM
+ document.body.appendChild(renderer.view);
+
+ requestAnimFrame( animate );
+
+ // create a texture from an image path
+ var texture = PIXI.Texture.fromImage(baseUri + "/bunny.png");
+ // create a new Sprite using the texture
+ bunny = new PIXI.Sprite(texture);
+
+ // center the sprites anchor point
+ bunny.anchor.x = 0.5;
+ bunny.anchor.y = 0.5;
+
+ // move the sprite t the center of the screen
+ bunny.position.x = 200;
+ bunny.position.y = 150;
+
+ stage.addChild(bunny);
+ }
+
+ it('assets loaded', function (done) {
+ var loader = new PIXI.AssetLoader([
+ baseUri + '/bunny.png',
+ baseUri + '/frame-30.png',
+ baseUri + '/frame-60.png',
+ baseUri + '/frame-90.png'
+ ]);
+ // loader.on('onProgress', function (event) {
+ // console.log(event.content);
+ // });
+ loader.on('onComplete', function (event) {
+ done();
+ initScene();
+ });
+ loader.load();
+ });
+
+ it('frame 30 should match', function (done) {
+ this.timeout(700);
+ onFrame(30, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-30.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 60 should match', function (done) {
+ this.timeout(1200);
+ onFrame(60, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-60.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 90 should match', function (done) {
+ this.timeout(1700);
+ onFrame(90, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-90.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ // it('capture something', function (done) {
+ // this.timeout(2000000);
+ // onFrame(30, function () {
+ // var img = new Image();
+ // img.src = renderer.view.toDataURL('image/png');
+ // document.body.appendChild(img);
+ // });
+ // });
+});
diff --git a/test/index.html b/test/index.html
deleted file mode 100644
index 9cbcac5..0000000
--- a/test/index.html
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
- Pixi.js Test Suite
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/test/karma.conf.js b/test/karma.conf.js
new file mode 100644
index 0000000..c66a696
--- /dev/null
+++ b/test/karma.conf.js
@@ -0,0 +1,82 @@
+module.exports = function(config) {
+ config.set({
+
+ // base path, that will be used to resolve files and exclude
+ basePath : '../',
+
+ frameworks : ['mocha'],
+
+ // list of files / patterns to load in the browser
+ files : [
+ 'node_modules/chai/chai.js',
+ 'bin/pixi.dev.js',
+ 'test/lib/**/*.js',
+ 'test/unit/**/*.js',
+ // 'test/functional/**/*.js',
+ {pattern: 'test/**/*.png', watched: false, included: false, served: true}
+ ],
+
+ // list of files to exclude
+ exclude : [],
+
+ // use dolts reporter, as travis terminal does not support escaping sequences
+ // possible values: 'dots', 'progress', 'junit', 'teamcity'
+ // CLI --reporters progress
+ reporters : ['progress'],
+
+ // web server port
+ // CLI --port 9876
+ port : 9876,
+
+ // cli runner port
+ // CLI --runner-port 9100
+ runnerPort : 9100,
+
+ // enable / disable colors in the output (reporters and logs)
+ // CLI --colors --no-colors
+ colors : true,
+
+ // level of logging
+ // possible values: karma.LOG_DISABLE || karma.LOG_ERROR || karma.LOG_WARN || karma.LOG_INFO || karma.LOG_DEBUG
+ // CLI --log-level debug
+ logLevel : config.LOG_DEBUG,
+
+ // enable / disable watching file and executing tests whenever any file changes
+ // CLI --auto-watch --no-auto-watch
+ autoWatch : false,
+
+ // Start these browsers, currently available:
+ // - Chrome
+ // - ChromeCanary
+ // - Firefox
+ // - Opera
+ // - Safari (only Mac)
+ // - PhantomJS
+ // - IE (only Windows)
+ // CLI --browsers Chrome,Firefox,Safari
+ browsers : ['Firefox'],
+
+ // If browser does not capture in given timeout [ms], kill it
+ // CLI --capture-timeout 5000
+ captureTimeout : 5000,
+
+ // Auto run tests on start (when browsers are captured) and exit
+ // CLI --single-run --no-single-run
+ singleRun : true,
+
+ // report which specs are slower than 500ms
+ // CLI --report-slower-than 500
+ reportSlowerThan : 1000,
+
+ preprocessors : {
+ // '**/client/js/*.js': 'coverage'
+ },
+
+ plugins : [
+ 'karma-mocha',
+ // 'karma-chrome-launcher',
+ 'karma-firefox-launcher',
+ // 'karma-phantomjs-launcher'
+ ]
+ });
+};
diff --git a/test/lib/pixi/core/Matrix.js b/test/lib/pixi/core/Matrix.js
new file mode 100644
index 0000000..d26386b
--- /dev/null
+++ b/test/lib/pixi/core/Matrix.js
@@ -0,0 +1,40 @@
+
+function pixi_core_Matrix_confirmNewMat3(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(1);
+ expect(matrix[5]).to.equal(0);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(1);
+}
+
+function pixi_core_Matrix_confirmNewMat4(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[0]).to.equal(1);
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(0);
+ expect(matrix[5]).to.equal(1);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(0);
+ expect(matrix[9]).to.equal(0);
+ expect(matrix[10]).to.equal(1);
+ expect(matrix[11]).to.equal(0);
+ expect(matrix[12]).to.equal(0);
+ expect(matrix[13]).to.equal(0);
+ expect(matrix[14]).to.equal(0);
+ expect(matrix[15]).to.equal(1);
+}
diff --git a/test/lib/pixi/core/Point.js b/test/lib/pixi/core/Point.js
new file mode 100644
index 0000000..e5df07b
--- /dev/null
+++ b/test/lib/pixi/core/Point.js
@@ -0,0 +1,10 @@
+
+function pixi_core_Point_confirm(obj, x, y) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Point);
+ expect(obj).to.respondTo('clone');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+}
diff --git a/test/lib/pixi/core/Rectangle.js b/test/lib/pixi/core/Rectangle.js
new file mode 100644
index 0000000..23f0d12
--- /dev/null
+++ b/test/lib/pixi/core/Rectangle.js
@@ -0,0 +1,13 @@
+
+function pixi_core_Rectangle_confirm(obj, x, y, width, height) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Rectangle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+ expect(obj).to.have.property('width', width);
+ expect(obj).to.have.property('height', height);
+}
diff --git a/test/lib/pixi/display/DisplayObject.js b/test/lib/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..1388a7f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObject.js
@@ -0,0 +1,43 @@
+
+function pixi_display_DisplayObject_confirmNew(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObject);
+ expect(obj).to.respondTo('setInteractive');
+ expect(obj).to.respondTo('addFilter');
+ expect(obj).to.respondTo('removeFilter');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.property('last', obj);
+ expect(obj).to.have.property('first', obj);
+
+ expect(obj).to.contain.property('position');
+ pixi_core_Point_confirm(obj.position, 0, 0);
+ expect(obj).to.contain.property('scale');
+ pixi_core_Point_confirm(obj.scale, 1, 1);
+ expect(obj).to.contain.property('pivot');
+ pixi_core_Point_confirm(obj.pivot, 0, 0);
+
+ expect(obj).to.have.property('rotation', 0);
+ expect(obj).to.have.property('alpha', 1);
+ expect(obj).to.have.property('visible', true);
+ expect(obj).to.have.property('buttonMode', false);
+ expect(obj).to.have.property('parent', null);
+ expect(obj).to.have.property('worldAlpha', 1);
+
+ expect(obj).to.have.property('hitArea');
+ expect(obj).to.have.property('interactive'); // TODO: Have a better default value
+ expect('mask' in obj).to.be.true; // TODO: Have a better default value
+ expect(obj.mask).to.be.undefined;
+
+ expect(obj).to.have.property('renderable');
+ expect(obj).to.have.property('stage');
+
+ expect(obj).to.have.deep.property('worldTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ expect(obj).to.have.deep.property('localTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.localTransform);
+
+ expect(obj).to.have.deep.property('color.length', 0);
+ expect(obj).to.have.property('dynamic', true);
+}
diff --git a/test/lib/pixi/display/DisplayObjectContainer.js b/test/lib/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..085c59f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,16 @@
+
+function pixi_display_DisplayObjectContainer_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObject_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObjectContainer);
+ expect(obj).to.respondTo('addChild');
+ expect(obj).to.respondTo('addChildAt');
+ expect(obj).to.respondTo('swapChildren');
+ expect(obj).to.respondTo('getChildAt');
+ expect(obj).to.respondTo('removeChild');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('children.length', 0);
+}
diff --git a/test/lib/pixi/display/Sprite.js b/test/lib/pixi/display/Sprite.js
new file mode 100644
index 0000000..cc7a2d6
--- /dev/null
+++ b/test/lib/pixi/display/Sprite.js
@@ -0,0 +1,28 @@
+
+function pixi_display_Sprite_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Sprite);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', true);
+ expect(obj).to.have.property('stage', null);
+
+ expect(obj).to.have.property('anchor');
+ pixi_core_Point_confirm(obj.anchor, 0, 0);
+
+ expect(obj).to.have.property('blendMode', PIXI.blendModes.NORMAL);
+ expect(obj).to.have.property('width', 1); // TODO: is 1 expected
+ expect(obj).to.have.property('height', 1); // TODO: is 1 expected
+
+ // FIXME: Just make this a boolean that is always there
+ expect(!!obj.updateFrame).to.equal(obj.texture.baseTexture.hasLoaded);
+
+ expect(obj).to.have.property('texture');
+ pixi_textures_Texture_confirmNew(obj.texture, done);
+}
diff --git a/test/lib/pixi/extras/Strip.js b/test/lib/pixi/extras/Strip.js
new file mode 100644
index 0000000..8927a8a
--- /dev/null
+++ b/test/lib/pixi/extras/Strip.js
@@ -0,0 +1,12 @@
+
+function pixi_extras_Strip_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Strip);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ // TODO: Test properties
+}
diff --git a/test/lib/pixi/textures/Texture.js b/test/lib/pixi/textures/Texture.js
new file mode 100644
index 0000000..d5867b6
--- /dev/null
+++ b/test/lib/pixi/textures/Texture.js
@@ -0,0 +1,31 @@
+
+function pixi_textures_Texture_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ function confirmFrameDone() {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, obj.baseTexture.width, obj.baseTexture.height);
+
+ expect(obj).to.have.property('width', obj.baseTexture.width);
+ expect(obj).to.have.property('height', obj.baseTexture.height);
+ done();
+ }
+
+ expect(obj).to.be.an.instanceof(PIXI.Texture);
+ pixi_utils_EventTarget_like(obj);
+
+ expect(obj).to.have.property('baseTexture')
+ .and.to.be.an.instanceof(PIXI.BaseTexture);
+
+ expect(obj).to.have.property('scope', obj);
+
+ expect(obj).to.have.property('trim');
+ pixi_core_Point_confirm(obj.trim, 0, 0);
+
+ expect(obj).to.have.property('frame');
+ if (obj.baseTexture.hasLoaded) {
+ confirmFrameDone();
+ } else {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, 1, 1);
+ obj.addEventListener('update', confirmFrameDone);
+ }
+}
diff --git a/test/lib/pixi/utils/EventTarget.js b/test/lib/pixi/utils/EventTarget.js
new file mode 100644
index 0000000..7b1dcfa
--- /dev/null
+++ b/test/lib/pixi/utils/EventTarget.js
@@ -0,0 +1,8 @@
+
+function pixi_utils_EventTarget_like(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.respondTo('addEventListener');
+ expect(obj).to.respondTo('dispatchEvent');
+ expect(obj).to.respondTo('removeEventListener');
+}
diff --git a/test/lib/qunit-1.11.0.css b/test/lib/qunit-1.11.0.css
deleted file mode 100644
index d7fc0c8..0000000
--- a/test/lib/qunit-1.11.0.css
+++ /dev/null
@@ -1,244 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-/** Font Family and Sizes */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
- font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
-}
-
-#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
-#qunit-tests { font-size: smaller; }
-
-
-/** Resets */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter {
- margin: 0;
- padding: 0;
-}
-
-
-/** Header */
-
-#qunit-header {
- padding: 0.5em 0 0.5em 1em;
-
- color: #8699a4;
- background-color: #0d3349;
-
- font-size: 1.5em;
- line-height: 1em;
- font-weight: normal;
-
- border-radius: 5px 5px 0 0;
- -moz-border-radius: 5px 5px 0 0;
- -webkit-border-top-right-radius: 5px;
- -webkit-border-top-left-radius: 5px;
-}
-
-#qunit-header a {
- text-decoration: none;
- color: #c2ccd1;
-}
-
-#qunit-header a:hover,
-#qunit-header a:focus {
- color: #fff;
-}
-
-#qunit-testrunner-toolbar label {
- display: inline-block;
- padding: 0 .5em 0 .1em;
-}
-
-#qunit-banner {
- height: 5px;
-}
-
-#qunit-testrunner-toolbar {
- padding: 0.5em 0 0.5em 2em;
- color: #5E740B;
- background-color: #eee;
- overflow: hidden;
-}
-
-#qunit-userAgent {
- padding: 0.5em 0 0.5em 2.5em;
- background-color: #2b81af;
- color: #fff;
- text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
-}
-
-#qunit-modulefilter-container {
- float: right;
-}
-
-/** Tests: Pass/Fail */
-
-#qunit-tests {
- list-style-position: inside;
-}
-
-#qunit-tests li {
- padding: 0.4em 0.5em 0.4em 2.5em;
- border-bottom: 1px solid #fff;
- list-style-position: inside;
-}
-
-#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running {
- display: none;
-}
-
-#qunit-tests li strong {
- cursor: pointer;
-}
-
-#qunit-tests li a {
- padding: 0.5em;
- color: #c2ccd1;
- text-decoration: none;
-}
-#qunit-tests li a:hover,
-#qunit-tests li a:focus {
- color: #000;
-}
-
-#qunit-tests li .runtime {
- float: right;
- font-size: smaller;
-}
-
-.qunit-assert-list {
- margin-top: 0.5em;
- padding: 0.5em;
-
- background-color: #fff;
-
- border-radius: 5px;
- -moz-border-radius: 5px;
- -webkit-border-radius: 5px;
-}
-
-.qunit-collapsed {
- display: none;
-}
-
-#qunit-tests table {
- border-collapse: collapse;
- margin-top: .2em;
-}
-
-#qunit-tests th {
- text-align: right;
- vertical-align: top;
- padding: 0 .5em 0 0;
-}
-
-#qunit-tests td {
- vertical-align: top;
-}
-
-#qunit-tests pre {
- margin: 0;
- white-space: pre-wrap;
- word-wrap: break-word;
-}
-
-#qunit-tests del {
- background-color: #e0f2be;
- color: #374e0c;
- text-decoration: none;
-}
-
-#qunit-tests ins {
- background-color: #ffcaca;
- color: #500;
- text-decoration: none;
-}
-
-/*** Test Counts */
-
-#qunit-tests b.counts { color: black; }
-#qunit-tests b.passed { color: #5E740B; }
-#qunit-tests b.failed { color: #710909; }
-
-#qunit-tests li li {
- padding: 5px;
- background-color: #fff;
- border-bottom: none;
- list-style-position: inside;
-}
-
-/*** Passing Styles */
-
-#qunit-tests li li.pass {
- color: #3c510c;
- background-color: #fff;
- border-left: 10px solid #C6E746;
-}
-
-#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
-#qunit-tests .pass .test-name { color: #366097; }
-
-#qunit-tests .pass .test-actual,
-#qunit-tests .pass .test-expected { color: #999999; }
-
-#qunit-banner.qunit-pass { background-color: #C6E746; }
-
-/*** Failing Styles */
-
-#qunit-tests li li.fail {
- color: #710909;
- background-color: #fff;
- border-left: 10px solid #EE5757;
- white-space: pre;
-}
-
-#qunit-tests > li:last-child {
- border-radius: 0 0 5px 5px;
- -moz-border-radius: 0 0 5px 5px;
- -webkit-border-bottom-right-radius: 5px;
- -webkit-border-bottom-left-radius: 5px;
-}
-
-#qunit-tests .fail { color: #000000; background-color: #EE5757; }
-#qunit-tests .fail .test-name,
-#qunit-tests .fail .module-name { color: #000000; }
-
-#qunit-tests .fail .test-actual { color: #EE5757; }
-#qunit-tests .fail .test-expected { color: green; }
-
-#qunit-banner.qunit-fail { background-color: #EE5757; }
-
-
-/** Result */
-
-#qunit-testresult {
- padding: 0.5em 0.5em 0.5em 2.5em;
-
- color: #2b81af;
- background-color: #D2E0E6;
-
- border-bottom: 1px solid white;
-}
-#qunit-testresult .module-name {
- font-weight: bold;
-}
-
-/** Fixture */
-
-#qunit-fixture {
- position: absolute;
- top: -10000px;
- left: -10000px;
- width: 1000px;
- height: 1000px;
-}
diff --git a/test/lib/qunit-1.11.0.js b/test/lib/qunit-1.11.0.js
deleted file mode 100644
index 302545f..0000000
--- a/test/lib/qunit-1.11.0.js
+++ /dev/null
@@ -1,2152 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-(function( window ) {
-
-var QUnit,
- assert,
- config,
- onErrorFnPrev,
- testId = 0,
- fileName = (sourceFromStacktrace( 0 ) || "" ).replace(/(:\d+)+\)?/, "").replace(/.+\//, ""),
- toString = Object.prototype.toString,
- hasOwn = Object.prototype.hasOwnProperty,
- // Keep a local reference to Date (GH-283)
- Date = window.Date,
- defined = {
- setTimeout: typeof window.setTimeout !== "undefined",
- sessionStorage: (function() {
- var x = "qunit-test-string";
- try {
- sessionStorage.setItem( x, x );
- sessionStorage.removeItem( x );
- return true;
- } catch( e ) {
- return false;
- }
- }())
- },
- /**
- * Provides a normalized error string, correcting an issue
- * with IE 7 (and prior) where Error.prototype.toString is
- * not properly implemented
- *
- * Based on http://es5.github.com/#x15.11.4.4
- *
- * @param {String|Error} error
- * @return {String} error message
- */
- errorString = function( error ) {
- var name, message,
- errorString = error.toString();
- if ( errorString.substring( 0, 7 ) === "[object" ) {
- name = error.name ? error.name.toString() : "Error";
- message = error.message ? error.message.toString() : "";
- if ( name && message ) {
- return name + ": " + message;
- } else if ( name ) {
- return name;
- } else if ( message ) {
- return message;
- } else {
- return "Error";
- }
- } else {
- return errorString;
- }
- },
- /**
- * Makes a clone of an object using only Array or Object as base,
- * and copies over the own enumerable properties.
- *
- * @param {Object} obj
- * @return {Object} New object with only the own properties (recursively).
- */
- objectValues = function( obj ) {
- // Grunt 0.3.x uses an older version of jshint that still has jshint/jshint#392.
- /*jshint newcap: false */
- var key, val,
- vals = QUnit.is( "array", obj ) ? [] : {};
- for ( key in obj ) {
- if ( hasOwn.call( obj, key ) ) {
- val = obj[key];
- vals[key] = val === Object(val) ? objectValues(val) : val;
- }
- }
- return vals;
- };
-
-function Test( settings ) {
- extend( this, settings );
- this.assertions = [];
- this.testNumber = ++Test.count;
-}
-
-Test.count = 0;
-
-Test.prototype = {
- init: function() {
- var a, b, li,
- tests = id( "qunit-tests" );
-
- if ( tests ) {
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml;
-
- // `a` initialized at top of scope
- a = document.createElement( "a" );
- a.innerHTML = "Rerun";
- a.href = QUnit.url({ testNumber: this.testNumber });
-
- li = document.createElement( "li" );
- li.appendChild( b );
- li.appendChild( a );
- li.className = "running";
- li.id = this.id = "qunit-test-output" + testId++;
-
- tests.appendChild( li );
- }
- },
- setup: function() {
- if ( this.module !== config.previousModule ) {
- if ( config.previousModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.previousModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
- config.previousModule = this.module;
- config.moduleStats = { all: 0, bad: 0 };
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- } else if ( config.autorun ) {
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- }
-
- config.current = this;
-
- this.testEnvironment = extend({
- setup: function() {},
- teardown: function() {}
- }, this.moduleTestEnvironment );
-
- this.started = +new Date();
- runLoggingCallbacks( "testStart", QUnit, {
- name: this.testName,
- module: this.module
- });
-
- // allow utility functions to access the current test environment
- // TODO why??
- QUnit.current_testEnvironment = this.testEnvironment;
-
- if ( !config.pollution ) {
- saveGlobal();
- }
- if ( config.notrycatch ) {
- this.testEnvironment.setup.call( this.testEnvironment );
- return;
- }
- try {
- this.testEnvironment.setup.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Setup failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- },
- run: function() {
- config.current = this;
-
- var running = id( "qunit-testresult" );
-
- if ( running ) {
- running.innerHTML = "Running:
" + this.nameHtml;
- }
-
- if ( this.async ) {
- QUnit.stop();
- }
-
- this.callbackStarted = +new Date();
-
- if ( config.notrycatch ) {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- return;
- }
-
- try {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- } catch( e ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
-
- QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + " " + this.stack + ": " + ( e.message || e ), extractStacktrace( e, 0 ) );
- // else next test will carry the responsibility
- saveGlobal();
-
- // Restart the tests if they're blocking
- if ( config.blocking ) {
- QUnit.start();
- }
- }
- },
- teardown: function() {
- config.current = this;
- if ( config.notrycatch ) {
- if ( typeof this.callbackRuntime === "undefined" ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
- }
- this.testEnvironment.teardown.call( this.testEnvironment );
- return;
- } else {
- try {
- this.testEnvironment.teardown.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Teardown failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- }
- checkPollution();
- },
- finish: function() {
- config.current = this;
- if ( config.requireExpects && this.expected === null ) {
- QUnit.pushFailure( "Expected number of assertions to be defined, but expect() was not called.", this.stack );
- } else if ( this.expected !== null && this.expected !== this.assertions.length ) {
- QUnit.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack );
- } else if ( this.expected === null && !this.assertions.length ) {
- QUnit.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions.", this.stack );
- }
-
- var i, assertion, a, b, time, li, ol,
- test = this,
- good = 0,
- bad = 0,
- tests = id( "qunit-tests" );
-
- this.runtime = +new Date() - this.started;
- config.stats.all += this.assertions.length;
- config.moduleStats.all += this.assertions.length;
-
- if ( tests ) {
- ol = document.createElement( "ol" );
- ol.className = "qunit-assert-list";
-
- for ( i = 0; i < this.assertions.length; i++ ) {
- assertion = this.assertions[i];
-
- li = document.createElement( "li" );
- li.className = assertion.result ? "pass" : "fail";
- li.innerHTML = assertion.message || ( assertion.result ? "okay" : "failed" );
- ol.appendChild( li );
-
- if ( assertion.result ) {
- good++;
- } else {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
-
- // store result when possible
- if ( QUnit.config.reorder && defined.sessionStorage ) {
- if ( bad ) {
- sessionStorage.setItem( "qunit-test-" + this.module + "-" + this.testName, bad );
- } else {
- sessionStorage.removeItem( "qunit-test-" + this.module + "-" + this.testName );
- }
- }
-
- if ( bad === 0 ) {
- addClass( ol, "qunit-collapsed" );
- }
-
- // `b` initialized at top of scope
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml + " (" + bad + ", " + good + ", " + this.assertions.length + ")";
-
- addEvent(b, "click", function() {
- var next = b.parentNode.lastChild,
- collapsed = hasClass( next, "qunit-collapsed" );
- ( collapsed ? removeClass : addClass )( next, "qunit-collapsed" );
- });
-
- addEvent(b, "dblclick", function( e ) {
- var target = e && e.target ? e.target : window.event.srcElement;
- if ( target.nodeName.toLowerCase() === "span" || target.nodeName.toLowerCase() === "b" ) {
- target = target.parentNode;
- }
- if ( window.location && target.nodeName.toLowerCase() === "strong" ) {
- window.location = QUnit.url({ testNumber: test.testNumber });
- }
- });
-
- // `time` initialized at top of scope
- time = document.createElement( "span" );
- time.className = "runtime";
- time.innerHTML = this.runtime + " ms";
-
- // `li` initialized at top of scope
- li = id( this.id );
- li.className = bad ? "fail" : "pass";
- li.removeChild( li.firstChild );
- a = li.firstChild;
- li.appendChild( b );
- li.appendChild( a );
- li.appendChild( time );
- li.appendChild( ol );
-
- } else {
- for ( i = 0; i < this.assertions.length; i++ ) {
- if ( !this.assertions[i].result ) {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
- }
-
- runLoggingCallbacks( "testDone", QUnit, {
- name: this.testName,
- module: this.module,
- failed: bad,
- passed: this.assertions.length - bad,
- total: this.assertions.length,
- duration: this.runtime
- });
-
- QUnit.reset();
-
- config.current = undefined;
- },
-
- queue: function() {
- var bad,
- test = this;
-
- synchronize(function() {
- test.init();
- });
- function run() {
- // each of these can by async
- synchronize(function() {
- test.setup();
- });
- synchronize(function() {
- test.run();
- });
- synchronize(function() {
- test.teardown();
- });
- synchronize(function() {
- test.finish();
- });
- }
-
- // `bad` initialized at top of scope
- // defer when previous test run passed, if storage is available
- bad = QUnit.config.reorder && defined.sessionStorage &&
- +sessionStorage.getItem( "qunit-test-" + this.module + "-" + this.testName );
-
- if ( bad ) {
- run();
- } else {
- synchronize( run, true );
- }
- }
-};
-
-// Root QUnit object.
-// `QUnit` initialized at top of scope
-QUnit = {
-
- // call on start of module test to prepend name to all tests
- module: function( name, testEnvironment ) {
- config.currentModule = name;
- config.currentModuleTestEnvironment = testEnvironment;
- config.modules[name] = true;
- },
-
- asyncTest: function( testName, expected, callback ) {
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- QUnit.test( testName, expected, callback, true );
- },
-
- test: function( testName, expected, callback, async ) {
- var test,
- nameHtml = "" + escapeText( testName ) + "";
-
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- if ( config.currentModule ) {
- nameHtml = "" + escapeText( config.currentModule ) + ": " + nameHtml;
- }
-
- test = new Test({
- nameHtml: nameHtml,
- testName: testName,
- expected: expected,
- async: async,
- callback: callback,
- module: config.currentModule,
- moduleTestEnvironment: config.currentModuleTestEnvironment,
- stack: sourceFromStacktrace( 2 )
- });
-
- if ( !validTest( test ) ) {
- return;
- }
-
- test.queue();
- },
-
- // Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through.
- expect: function( asserts ) {
- if (arguments.length === 1) {
- config.current.expected = asserts;
- } else {
- return config.current.expected;
- }
- },
-
- start: function( count ) {
- // QUnit hasn't been initialized yet.
- // Note: RequireJS (et al) may delay onLoad
- if ( config.semaphore === undefined ) {
- QUnit.begin(function() {
- // This is triggered at the top of QUnit.load, push start() to the event loop, to allow QUnit.load to finish first
- setTimeout(function() {
- QUnit.start( count );
- });
- });
- return;
- }
-
- config.semaphore -= count || 1;
- // don't start until equal number of stop-calls
- if ( config.semaphore > 0 ) {
- return;
- }
- // ignore if start is called more often then stop
- if ( config.semaphore < 0 ) {
- config.semaphore = 0;
- QUnit.pushFailure( "Called start() while already started (QUnit.config.semaphore was 0 already)", null, sourceFromStacktrace(2) );
- return;
- }
- // A slight delay, to avoid any current callbacks
- if ( defined.setTimeout ) {
- window.setTimeout(function() {
- if ( config.semaphore > 0 ) {
- return;
- }
- if ( config.timeout ) {
- clearTimeout( config.timeout );
- }
-
- config.blocking = false;
- process( true );
- }, 13);
- } else {
- config.blocking = false;
- process( true );
- }
- },
-
- stop: function( count ) {
- config.semaphore += count || 1;
- config.blocking = true;
-
- if ( config.testTimeout && defined.setTimeout ) {
- clearTimeout( config.timeout );
- config.timeout = window.setTimeout(function() {
- QUnit.ok( false, "Test timed out" );
- config.semaphore = 1;
- QUnit.start();
- }, config.testTimeout );
- }
- }
-};
-
-// `assert` initialized at top of scope
-// Asssert helpers
-// All of these must either call QUnit.push() or manually do:
-// - runLoggingCallbacks( "log", .. );
-// - config.current.assertions.push({ .. });
-// We attach it to the QUnit object *after* we expose the public API,
-// otherwise `assert` will become a global variable in browsers (#341).
-assert = {
- /**
- * Asserts rough true-ish result.
- * @name ok
- * @function
- * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" );
- */
- ok: function( result, msg ) {
- if ( !config.current ) {
- throw new Error( "ok() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
- result = !!result;
-
- var source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: msg
- };
-
- msg = escapeText( msg || (result ? "okay" : "failed" ) );
- msg = "" + msg + "";
-
- if ( !result ) {
- source = sourceFromStacktrace( 2 );
- if ( source ) {
- details.source = source;
- msg += "Source: | " + escapeText( source ) + " |
---|
";
- }
- }
- runLoggingCallbacks( "log", QUnit, details );
- config.current.assertions.push({
- result: result,
- message: msg
- });
- },
-
- /**
- * Assert that the first two arguments are equal, with an optional message.
- * Prints out both actual and expected values.
- * @name equal
- * @function
- * @example equal( format( "Received {0} bytes.", 2), "Received 2 bytes.", "format() replaces {0} with next argument" );
- */
- equal: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected == actual, actual, expected, message );
- },
-
- /**
- * @name notEqual
- * @function
- */
- notEqual: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected != actual, actual, expected, message );
- },
-
- /**
- * @name propEqual
- * @function
- */
- propEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notPropEqual
- * @function
- */
- notPropEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name deepEqual
- * @function
- */
- deepEqual: function( actual, expected, message ) {
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notDeepEqual
- * @function
- */
- notDeepEqual: function( actual, expected, message ) {
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name strictEqual
- * @function
- */
- strictEqual: function( actual, expected, message ) {
- QUnit.push( expected === actual, actual, expected, message );
- },
-
- /**
- * @name notStrictEqual
- * @function
- */
- notStrictEqual: function( actual, expected, message ) {
- QUnit.push( expected !== actual, actual, expected, message );
- },
-
- "throws": function( block, expected, message ) {
- var actual,
- expectedOutput = expected,
- ok = false;
-
- // 'expected' is optional
- if ( typeof expected === "string" ) {
- message = expected;
- expected = null;
- }
-
- config.current.ignoreGlobalErrors = true;
- try {
- block.call( config.current.testEnvironment );
- } catch (e) {
- actual = e;
- }
- config.current.ignoreGlobalErrors = false;
-
- if ( actual ) {
- // we don't want to validate thrown error
- if ( !expected ) {
- ok = true;
- expectedOutput = null;
- // expected is a regexp
- } else if ( QUnit.objectType( expected ) === "regexp" ) {
- ok = expected.test( errorString( actual ) );
- // expected is a constructor
- } else if ( actual instanceof expected ) {
- ok = true;
- // expected is a validation function which returns true is validation passed
- } else if ( expected.call( {}, actual ) === true ) {
- expectedOutput = null;
- ok = true;
- }
-
- QUnit.push( ok, actual, expectedOutput, message );
- } else {
- QUnit.pushFailure( message, null, 'No exception was thrown.' );
- }
- }
-};
-
-/**
- * @deprecate since 1.8.0
- * Kept assertion helpers in root for backwards compatibility.
- */
-extend( QUnit, assert );
-
-/**
- * @deprecated since 1.9.0
- * Kept root "raises()" for backwards compatibility.
- * (Note that we don't introduce assert.raises).
- */
-QUnit.raises = assert[ "throws" ];
-
-/**
- * @deprecated since 1.0.0, replaced with error pushes since 1.3.0
- * Kept to avoid TypeErrors for undefined methods.
- */
-QUnit.equals = function() {
- QUnit.push( false, false, false, "QUnit.equals has been deprecated since 2009 (e88049a0), use QUnit.equal instead" );
-};
-QUnit.same = function() {
- QUnit.push( false, false, false, "QUnit.same has been deprecated since 2009 (e88049a0), use QUnit.deepEqual instead" );
-};
-
-// We want access to the constructor's prototype
-(function() {
- function F() {}
- F.prototype = QUnit;
- QUnit = new F();
- // Make F QUnit's constructor so that we can add to the prototype later
- QUnit.constructor = F;
-}());
-
-/**
- * Config object: Maintain internal state
- * Later exposed as QUnit.config
- * `config` initialized at top of scope
- */
-config = {
- // The queue of tests to run
- queue: [],
-
- // block until document ready
- blocking: true,
-
- // when enabled, show only failing tests
- // gets persisted through sessionStorage and can be changed in UI via checkbox
- hidepassed: false,
-
- // by default, run previously failed tests first
- // very useful in combination with "Hide passed tests" checked
- reorder: true,
-
- // by default, modify document.title when suite is done
- altertitle: true,
-
- // when enabled, all tests must call expect()
- requireExpects: false,
-
- // add checkboxes that are persisted in the query-string
- // when enabled, the id is set to `true` as a `QUnit.config` property
- urlConfig: [
- {
- id: "noglobals",
- label: "Check for Globals",
- tooltip: "Enabling this will test if any test introduces new properties on the `window` object. Stored as query-strings."
- },
- {
- id: "notrycatch",
- label: "No try-catch",
- tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging exceptions in IE reasonable. Stored as query-strings."
- }
- ],
-
- // Set of all modules.
- modules: {},
-
- // logging callback queues
- begin: [],
- done: [],
- log: [],
- testStart: [],
- testDone: [],
- moduleStart: [],
- moduleDone: []
-};
-
-// Export global variables, unless an 'exports' object exists,
-// in that case we assume we're in CommonJS (dealt with on the bottom of the script)
-if ( typeof exports === "undefined" ) {
- extend( window, QUnit );
-
- // Expose QUnit object
- window.QUnit = QUnit;
-}
-
-// Initialize more QUnit.config and QUnit.urlParams
-(function() {
- var i,
- location = window.location || { search: "", protocol: "file:" },
- params = location.search.slice( 1 ).split( "&" ),
- length = params.length,
- urlParams = {},
- current;
-
- if ( params[ 0 ] ) {
- for ( i = 0; i < length; i++ ) {
- current = params[ i ].split( "=" );
- current[ 0 ] = decodeURIComponent( current[ 0 ] );
- // allow just a key to turn on a flag, e.g., test.html?noglobals
- current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true;
- urlParams[ current[ 0 ] ] = current[ 1 ];
- }
- }
-
- QUnit.urlParams = urlParams;
-
- // String search anywhere in moduleName+testName
- config.filter = urlParams.filter;
-
- // Exact match of the module name
- config.module = urlParams.module;
-
- config.testNumber = parseInt( urlParams.testNumber, 10 ) || null;
-
- // Figure out if we're running the tests from a server or not
- QUnit.isLocal = location.protocol === "file:";
-}());
-
-// Extend QUnit object,
-// these after set here because they should not be exposed as global functions
-extend( QUnit, {
- assert: assert,
-
- config: config,
-
- // Initialize the configuration options
- init: function() {
- extend( config, {
- stats: { all: 0, bad: 0 },
- moduleStats: { all: 0, bad: 0 },
- started: +new Date(),
- updateRate: 1000,
- blocking: false,
- autostart: true,
- autorun: false,
- filter: "",
- queue: [],
- semaphore: 1
- });
-
- var tests, banner, result,
- qunit = id( "qunit" );
-
- if ( qunit ) {
- qunit.innerHTML =
- "" +
- "" +
- "" +
- "" +
- "
";
- }
-
- tests = id( "qunit-tests" );
- banner = id( "qunit-banner" );
- result = id( "qunit-testresult" );
-
- if ( tests ) {
- tests.innerHTML = "";
- }
-
- if ( banner ) {
- banner.className = "";
- }
-
- if ( result ) {
- result.parentNode.removeChild( result );
- }
-
- if ( tests ) {
- result = document.createElement( "p" );
- result.id = "qunit-testresult";
- result.className = "result";
- tests.parentNode.insertBefore( result, tests );
- result.innerHTML = "Running...
";
- }
- },
-
- // Resets the test setup. Useful for tests that modify the DOM.
- reset: function() {
- var fixture = id( "qunit-fixture" );
- if ( fixture ) {
- fixture.innerHTML = config.fixture;
- }
- },
-
- // Trigger an event on an element.
- // @example triggerEvent( document.body, "click" );
- triggerEvent: function( elem, type, event ) {
- if ( document.createEvent ) {
- event = document.createEvent( "MouseEvents" );
- event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView,
- 0, 0, 0, 0, 0, false, false, false, false, 0, null);
-
- elem.dispatchEvent( event );
- } else if ( elem.fireEvent ) {
- elem.fireEvent( "on" + type );
- }
- },
-
- // Safe object type checking
- is: function( type, obj ) {
- return QUnit.objectType( obj ) === type;
- },
-
- objectType: function( obj ) {
- if ( typeof obj === "undefined" ) {
- return "undefined";
- // consider: typeof null === object
- }
- if ( obj === null ) {
- return "null";
- }
-
- var match = toString.call( obj ).match(/^\[object\s(.*)\]$/),
- type = match && match[1] || "";
-
- switch ( type ) {
- case "Number":
- if ( isNaN(obj) ) {
- return "nan";
- }
- return "number";
- case "String":
- case "Boolean":
- case "Array":
- case "Date":
- case "RegExp":
- case "Function":
- return type.toLowerCase();
- }
- if ( typeof obj === "object" ) {
- return "object";
- }
- return undefined;
- },
-
- push: function( result, actual, expected, message ) {
- if ( !config.current ) {
- throw new Error( "assertion outside test context, was " + sourceFromStacktrace() );
- }
-
- var output, source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: message,
- actual: actual,
- expected: expected
- };
-
- message = escapeText( message ) || ( result ? "okay" : "failed" );
- message = "" + message + "";
- output = message;
-
- if ( !result ) {
- expected = escapeText( QUnit.jsDump.parse(expected) );
- actual = escapeText( QUnit.jsDump.parse(actual) );
- output += "Expected: | " + expected + " |
";
-
- if ( actual !== expected ) {
- output += "Result: | " + actual + " |
";
- output += "Diff: | " + QUnit.diff( expected, actual ) + " |
";
- }
-
- source = sourceFromStacktrace();
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
- }
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: !!result,
- message: output
- });
- },
-
- pushFailure: function( message, source, actual ) {
- if ( !config.current ) {
- throw new Error( "pushFailure() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
-
- var output,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: false,
- message: message
- };
-
- message = escapeText( message ) || "error";
- message = "" + message + "";
- output = message;
-
- output += "";
-
- if ( actual ) {
- output += "Result: | " + escapeText( actual ) + " |
";
- }
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: false,
- message: output
- });
- },
-
- url: function( params ) {
- params = extend( extend( {}, QUnit.urlParams ), params );
- var key,
- querystring = "?";
-
- for ( key in params ) {
- if ( !hasOwn.call( params, key ) ) {
- continue;
- }
- querystring += encodeURIComponent( key ) + "=" +
- encodeURIComponent( params[ key ] ) + "&";
- }
- return window.location.protocol + "//" + window.location.host +
- window.location.pathname + querystring.slice( 0, -1 );
- },
-
- extend: extend,
- id: id,
- addEvent: addEvent
- // load, equiv, jsDump, diff: Attached later
-});
-
-/**
- * @deprecated: Created for backwards compatibility with test runner that set the hook function
- * into QUnit.{hook}, instead of invoking it and passing the hook function.
- * QUnit.constructor is set to the empty F() above so that we can add to it's prototype here.
- * Doing this allows us to tell if the following methods have been overwritten on the actual
- * QUnit object.
- */
-extend( QUnit.constructor.prototype, {
-
- // Logging callbacks; all receive a single argument with the listed properties
- // run test/logs.html for any related changes
- begin: registerLoggingCallback( "begin" ),
-
- // done: { failed, passed, total, runtime }
- done: registerLoggingCallback( "done" ),
-
- // log: { result, actual, expected, message }
- log: registerLoggingCallback( "log" ),
-
- // testStart: { name }
- testStart: registerLoggingCallback( "testStart" ),
-
- // testDone: { name, failed, passed, total, duration }
- testDone: registerLoggingCallback( "testDone" ),
-
- // moduleStart: { name }
- moduleStart: registerLoggingCallback( "moduleStart" ),
-
- // moduleDone: { name, failed, passed, total }
- moduleDone: registerLoggingCallback( "moduleDone" )
-});
-
-if ( typeof document === "undefined" || document.readyState === "complete" ) {
- config.autorun = true;
-}
-
-QUnit.load = function() {
- runLoggingCallbacks( "begin", QUnit, {} );
-
- // Initialize the config, saving the execution queue
- var banner, filter, i, label, len, main, ol, toolbar, userAgent, val,
- urlConfigCheckboxesContainer, urlConfigCheckboxes, moduleFilter,
- numModules = 0,
- moduleFilterHtml = "",
- urlConfigHtml = "",
- oldconfig = extend( {}, config );
-
- QUnit.init();
- extend(config, oldconfig);
-
- config.blocking = false;
-
- len = config.urlConfig.length;
-
- for ( i = 0; i < len; i++ ) {
- val = config.urlConfig[i];
- if ( typeof val === "string" ) {
- val = {
- id: val,
- label: val,
- tooltip: "[no tooltip available]"
- };
- }
- config[ val.id ] = QUnit.urlParams[ val.id ];
- urlConfigHtml += "";
- }
-
- moduleFilterHtml += "";
-
- // `userAgent` initialized at top of scope
- userAgent = id( "qunit-userAgent" );
- if ( userAgent ) {
- userAgent.innerHTML = navigator.userAgent;
- }
-
- // `banner` initialized at top of scope
- banner = id( "qunit-header" );
- if ( banner ) {
- banner.innerHTML = "" + banner.innerHTML + " ";
- }
-
- // `toolbar` initialized at top of scope
- toolbar = id( "qunit-testrunner-toolbar" );
- if ( toolbar ) {
- // `filter` initialized at top of scope
- filter = document.createElement( "input" );
- filter.type = "checkbox";
- filter.id = "qunit-filter-pass";
-
- addEvent( filter, "click", function() {
- var tmp,
- ol = document.getElementById( "qunit-tests" );
-
- if ( filter.checked ) {
- ol.className = ol.className + " hidepass";
- } else {
- tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " ";
- ol.className = tmp.replace( / hidepass /, " " );
- }
- if ( defined.sessionStorage ) {
- if (filter.checked) {
- sessionStorage.setItem( "qunit-filter-passed-tests", "true" );
- } else {
- sessionStorage.removeItem( "qunit-filter-passed-tests" );
- }
- }
- });
-
- if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem( "qunit-filter-passed-tests" ) ) {
- filter.checked = true;
- // `ol` initialized at top of scope
- ol = document.getElementById( "qunit-tests" );
- ol.className = ol.className + " hidepass";
- }
- toolbar.appendChild( filter );
-
- // `label` initialized at top of scope
- label = document.createElement( "label" );
- label.setAttribute( "for", "qunit-filter-pass" );
- label.setAttribute( "title", "Only show tests and assertons that fail. Stored in sessionStorage." );
- label.innerHTML = "Hide passed tests";
- toolbar.appendChild( label );
-
- urlConfigCheckboxesContainer = document.createElement("span");
- urlConfigCheckboxesContainer.innerHTML = urlConfigHtml;
- urlConfigCheckboxes = urlConfigCheckboxesContainer.getElementsByTagName("input");
- // For oldIE support:
- // * Add handlers to the individual elements instead of the container
- // * Use "click" instead of "change"
- // * Fallback from event.target to event.srcElement
- addEvents( urlConfigCheckboxes, "click", function( event ) {
- var params = {},
- target = event.target || event.srcElement;
- params[ target.name ] = target.checked ? true : undefined;
- window.location = QUnit.url( params );
- });
- toolbar.appendChild( urlConfigCheckboxesContainer );
-
- if (numModules > 1) {
- moduleFilter = document.createElement( 'span' );
- moduleFilter.setAttribute( 'id', 'qunit-modulefilter-container' );
- moduleFilter.innerHTML = moduleFilterHtml;
- addEvent( moduleFilter.lastChild, "change", function() {
- var selectBox = moduleFilter.getElementsByTagName("select")[0],
- selectedModule = decodeURIComponent(selectBox.options[selectBox.selectedIndex].value);
-
- window.location = QUnit.url( { module: ( selectedModule === "" ) ? undefined : selectedModule } );
- });
- toolbar.appendChild(moduleFilter);
- }
- }
-
- // `main` initialized at top of scope
- main = id( "qunit-fixture" );
- if ( main ) {
- config.fixture = main.innerHTML;
- }
-
- if ( config.autostart ) {
- QUnit.start();
- }
-};
-
-addEvent( window, "load", QUnit.load );
-
-// `onErrorFnPrev` initialized at top of scope
-// Preserve other handlers
-onErrorFnPrev = window.onerror;
-
-// Cover uncaught exceptions
-// Returning true will surpress the default browser handler,
-// returning false will let it run.
-window.onerror = function ( error, filePath, linerNr ) {
- var ret = false;
- if ( onErrorFnPrev ) {
- ret = onErrorFnPrev( error, filePath, linerNr );
- }
-
- // Treat return value as window.onerror itself does,
- // Only do our handling if not surpressed.
- if ( ret !== true ) {
- if ( QUnit.config.current ) {
- if ( QUnit.config.current.ignoreGlobalErrors ) {
- return true;
- }
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- } else {
- QUnit.test( "global failure", extend( function() {
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- }, { validTest: validTest } ) );
- }
- return false;
- }
-
- return ret;
-};
-
-function done() {
- config.autorun = true;
-
- // Log the last module results
- if ( config.currentModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.currentModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
-
- var i, key,
- banner = id( "qunit-banner" ),
- tests = id( "qunit-tests" ),
- runtime = +new Date() - config.started,
- passed = config.stats.all - config.stats.bad,
- html = [
- "Tests completed in ",
- runtime,
- " milliseconds.
",
- "",
- passed,
- " assertions of ",
- config.stats.all,
- " passed, ",
- config.stats.bad,
- " failed."
- ].join( "" );
-
- if ( banner ) {
- banner.className = ( config.stats.bad ? "qunit-fail" : "qunit-pass" );
- }
-
- if ( tests ) {
- id( "qunit-testresult" ).innerHTML = html;
- }
-
- if ( config.altertitle && typeof document !== "undefined" && document.title ) {
- // show ✖ for good, ✔ for bad suite result in title
- // use escape sequences in case file gets loaded with non-utf-8-charset
- document.title = [
- ( config.stats.bad ? "\u2716" : "\u2714" ),
- document.title.replace( /^[\u2714\u2716] /i, "" )
- ].join( " " );
- }
-
- // clear own sessionStorage items if all tests passed
- if ( config.reorder && defined.sessionStorage && config.stats.bad === 0 ) {
- // `key` & `i` initialized at top of scope
- for ( i = 0; i < sessionStorage.length; i++ ) {
- key = sessionStorage.key( i++ );
- if ( key.indexOf( "qunit-test-" ) === 0 ) {
- sessionStorage.removeItem( key );
- }
- }
- }
-
- // scroll back to top to show results
- if ( window.scrollTo ) {
- window.scrollTo(0, 0);
- }
-
- runLoggingCallbacks( "done", QUnit, {
- failed: config.stats.bad,
- passed: passed,
- total: config.stats.all,
- runtime: runtime
- });
-}
-
-/** @return Boolean: true if this test should be ran */
-function validTest( test ) {
- var include,
- filter = config.filter && config.filter.toLowerCase(),
- module = config.module && config.module.toLowerCase(),
- fullName = (test.module + ": " + test.testName).toLowerCase();
-
- // Internally-generated tests are always valid
- if ( test.callback && test.callback.validTest === validTest ) {
- delete test.callback.validTest;
- return true;
- }
-
- if ( config.testNumber ) {
- return test.testNumber === config.testNumber;
- }
-
- if ( module && ( !test.module || test.module.toLowerCase() !== module ) ) {
- return false;
- }
-
- if ( !filter ) {
- return true;
- }
-
- include = filter.charAt( 0 ) !== "!";
- if ( !include ) {
- filter = filter.slice( 1 );
- }
-
- // If the filter matches, we need to honour include
- if ( fullName.indexOf( filter ) !== -1 ) {
- return include;
- }
-
- // Otherwise, do the opposite
- return !include;
-}
-
-// so far supports only Firefox, Chrome and Opera (buggy), Safari (for real exceptions)
-// Later Safari and IE10 are supposed to support error.stack as well
-// See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack
-function extractStacktrace( e, offset ) {
- offset = offset === undefined ? 3 : offset;
-
- var stack, include, i;
-
- if ( e.stacktrace ) {
- // Opera
- return e.stacktrace.split( "\n" )[ offset + 3 ];
- } else if ( e.stack ) {
- // Firefox, Chrome
- stack = e.stack.split( "\n" );
- if (/^error$/i.test( stack[0] ) ) {
- stack.shift();
- }
- if ( fileName ) {
- include = [];
- for ( i = offset; i < stack.length; i++ ) {
- if ( stack[ i ].indexOf( fileName ) !== -1 ) {
- break;
- }
- include.push( stack[ i ] );
- }
- if ( include.length ) {
- return include.join( "\n" );
- }
- }
- return stack[ offset ];
- } else if ( e.sourceURL ) {
- // Safari, PhantomJS
- // hopefully one day Safari provides actual stacktraces
- // exclude useless self-reference for generated Error objects
- if ( /qunit.js$/.test( e.sourceURL ) ) {
- return;
- }
- // for actual exceptions, this is useful
- return e.sourceURL + ":" + e.line;
- }
-}
-function sourceFromStacktrace( offset ) {
- try {
- throw new Error();
- } catch ( e ) {
- return extractStacktrace( e, offset );
- }
-}
-
-/**
- * Escape text for attribute or text content.
- */
-function escapeText( s ) {
- if ( !s ) {
- return "";
- }
- s = s + "";
- // Both single quotes and double quotes (for attributes)
- return s.replace( /['"<>&]/g, function( s ) {
- switch( s ) {
- case '\'':
- return ''';
- case '"':
- return '"';
- case '<':
- return '<';
- case '>':
- return '>';
- case '&':
- return '&';
- }
- });
-}
-
-function synchronize( callback, last ) {
- config.queue.push( callback );
-
- if ( config.autorun && !config.blocking ) {
- process( last );
- }
-}
-
-function process( last ) {
- function next() {
- process( last );
- }
- var start = new Date().getTime();
- config.depth = config.depth ? config.depth + 1 : 1;
-
- while ( config.queue.length && !config.blocking ) {
- if ( !defined.setTimeout || config.updateRate <= 0 || ( ( new Date().getTime() - start ) < config.updateRate ) ) {
- config.queue.shift()();
- } else {
- window.setTimeout( next, 13 );
- break;
- }
- }
- config.depth--;
- if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) {
- done();
- }
-}
-
-function saveGlobal() {
- config.pollution = [];
-
- if ( config.noglobals ) {
- for ( var key in window ) {
- // in Opera sometimes DOM element ids show up here, ignore them
- if ( !hasOwn.call( window, key ) || /^qunit-test-output/.test( key ) ) {
- continue;
- }
- config.pollution.push( key );
- }
- }
-}
-
-function checkPollution() {
- var newGlobals,
- deletedGlobals,
- old = config.pollution;
-
- saveGlobal();
-
- newGlobals = diff( config.pollution, old );
- if ( newGlobals.length > 0 ) {
- QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join(", ") );
- }
-
- deletedGlobals = diff( old, config.pollution );
- if ( deletedGlobals.length > 0 ) {
- QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join(", ") );
- }
-}
-
-// returns a new Array with the elements that are in a but not in b
-function diff( a, b ) {
- var i, j,
- result = a.slice();
-
- for ( i = 0; i < result.length; i++ ) {
- for ( j = 0; j < b.length; j++ ) {
- if ( result[i] === b[j] ) {
- result.splice( i, 1 );
- i--;
- break;
- }
- }
- }
- return result;
-}
-
-function extend( a, b ) {
- for ( var prop in b ) {
- if ( b[ prop ] === undefined ) {
- delete a[ prop ];
-
- // Avoid "Member not found" error in IE8 caused by setting window.constructor
- } else if ( prop !== "constructor" || a !== window ) {
- a[ prop ] = b[ prop ];
- }
- }
-
- return a;
-}
-
-/**
- * @param {HTMLElement} elem
- * @param {string} type
- * @param {Function} fn
- */
-function addEvent( elem, type, fn ) {
- // Standards-based browsers
- if ( elem.addEventListener ) {
- elem.addEventListener( type, fn, false );
- // IE
- } else {
- elem.attachEvent( "on" + type, fn );
- }
-}
-
-/**
- * @param {Array|NodeList} elems
- * @param {string} type
- * @param {Function} fn
- */
-function addEvents( elems, type, fn ) {
- var i = elems.length;
- while ( i-- ) {
- addEvent( elems[i], type, fn );
- }
-}
-
-function hasClass( elem, name ) {
- return (" " + elem.className + " ").indexOf(" " + name + " ") > -1;
-}
-
-function addClass( elem, name ) {
- if ( !hasClass( elem, name ) ) {
- elem.className += (elem.className ? " " : "") + name;
- }
-}
-
-function removeClass( elem, name ) {
- var set = " " + elem.className + " ";
- // Class name may appear multiple times
- while ( set.indexOf(" " + name + " ") > -1 ) {
- set = set.replace(" " + name + " " , " ");
- }
- // If possible, trim it for prettiness, but not neccecarily
- elem.className = window.jQuery ? jQuery.trim( set ) : ( set.trim ? set.trim() : set );
-}
-
-function id( name ) {
- return !!( typeof document !== "undefined" && document && document.getElementById ) &&
- document.getElementById( name );
-}
-
-function registerLoggingCallback( key ) {
- return function( callback ) {
- config[key].push( callback );
- };
-}
-
-// Supports deprecated method of completely overwriting logging callbacks
-function runLoggingCallbacks( key, scope, args ) {
- var i, callbacks;
- if ( QUnit.hasOwnProperty( key ) ) {
- QUnit[ key ].call(scope, args );
- } else {
- callbacks = config[ key ];
- for ( i = 0; i < callbacks.length; i++ ) {
- callbacks[ i ].call( scope, args );
- }
- }
-}
-
-// Test for equality any JavaScript type.
-// Author: Philippe Rathé
-QUnit.equiv = (function() {
-
- // Call the o related callback with the given arguments.
- function bindCallbacks( o, callbacks, args ) {
- var prop = QUnit.objectType( o );
- if ( prop ) {
- if ( QUnit.objectType( callbacks[ prop ] ) === "function" ) {
- return callbacks[ prop ].apply( callbacks, args );
- } else {
- return callbacks[ prop ]; // or undefined
- }
- }
- }
-
- // the real equiv function
- var innerEquiv,
- // stack to decide between skip/abort functions
- callers = [],
- // stack to avoiding loops from circular referencing
- parents = [],
-
- getProto = Object.getPrototypeOf || function ( obj ) {
- return obj.__proto__;
- },
- callbacks = (function () {
-
- // for string, boolean, number and null
- function useStrictEquality( b, a ) {
- /*jshint eqeqeq:false */
- if ( b instanceof a.constructor || a instanceof b.constructor ) {
- // to catch short annotaion VS 'new' annotation of a
- // declaration
- // e.g. var i = 1;
- // var j = new Number(1);
- return a == b;
- } else {
- return a === b;
- }
- }
-
- return {
- "string": useStrictEquality,
- "boolean": useStrictEquality,
- "number": useStrictEquality,
- "null": useStrictEquality,
- "undefined": useStrictEquality,
-
- "nan": function( b ) {
- return isNaN( b );
- },
-
- "date": function( b, a ) {
- return QUnit.objectType( b ) === "date" && a.valueOf() === b.valueOf();
- },
-
- "regexp": function( b, a ) {
- return QUnit.objectType( b ) === "regexp" &&
- // the regex itself
- a.source === b.source &&
- // and its modifers
- a.global === b.global &&
- // (gmi) ...
- a.ignoreCase === b.ignoreCase &&
- a.multiline === b.multiline &&
- a.sticky === b.sticky;
- },
-
- // - skip when the property is a method of an instance (OOP)
- // - abort otherwise,
- // initial === would have catch identical references anyway
- "function": function() {
- var caller = callers[callers.length - 1];
- return caller !== Object && typeof caller !== "undefined";
- },
-
- "array": function( b, a ) {
- var i, j, len, loop;
-
- // b could be an object literal here
- if ( QUnit.objectType( b ) !== "array" ) {
- return false;
- }
-
- len = a.length;
- if ( len !== b.length ) {
- // safe and faster
- return false;
- }
-
- // track reference to avoid circular references
- parents.push( a );
- for ( i = 0; i < len; i++ ) {
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- loop = true;// dont rewalk array
- }
- }
- if ( !loop && !innerEquiv(a[i], b[i]) ) {
- parents.pop();
- return false;
- }
- }
- parents.pop();
- return true;
- },
-
- "object": function( b, a ) {
- var i, j, loop,
- // Default to true
- eq = true,
- aProperties = [],
- bProperties = [];
-
- // comparing constructors is more strict than using
- // instanceof
- if ( a.constructor !== b.constructor ) {
- // Allow objects with no prototype to be equivalent to
- // objects with Object as their constructor.
- if ( !(( getProto(a) === null && getProto(b) === Object.prototype ) ||
- ( getProto(b) === null && getProto(a) === Object.prototype ) ) ) {
- return false;
- }
- }
-
- // stack constructor before traversing properties
- callers.push( a.constructor );
- // track reference to avoid circular references
- parents.push( a );
-
- for ( i in a ) { // be strict: don't ensures hasOwnProperty
- // and go deep
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- // don't go down the same path twice
- loop = true;
- }
- }
- aProperties.push(i); // collect a's properties
-
- if (!loop && !innerEquiv( a[i], b[i] ) ) {
- eq = false;
- break;
- }
- }
-
- callers.pop(); // unstack, we are done
- parents.pop();
-
- for ( i in b ) {
- bProperties.push( i ); // collect b's properties
- }
-
- // Ensures identical properties name
- return eq && innerEquiv( aProperties.sort(), bProperties.sort() );
- }
- };
- }());
-
- innerEquiv = function() { // can take multiple arguments
- var args = [].slice.apply( arguments );
- if ( args.length < 2 ) {
- return true; // end transition
- }
-
- return (function( a, b ) {
- if ( a === b ) {
- return true; // catch the most you can
- } else if ( a === null || b === null || typeof a === "undefined" ||
- typeof b === "undefined" ||
- QUnit.objectType(a) !== QUnit.objectType(b) ) {
- return false; // don't lose time with error prone cases
- } else {
- return bindCallbacks(a, callbacks, [ b, a ]);
- }
-
- // apply transition with (1..n) arguments
- }( args[0], args[1] ) && arguments.callee.apply( this, args.splice(1, args.length - 1 )) );
- };
-
- return innerEquiv;
-}());
-
-/**
- * jsDump Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com |
- * http://flesler.blogspot.com Licensed under BSD
- * (http://www.opensource.org/licenses/bsd-license.php) Date: 5/15/2008
- *
- * @projectDescription Advanced and extensible data dumping for Javascript.
- * @version 1.0.0
- * @author Ariel Flesler
- * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html}
- */
-QUnit.jsDump = (function() {
- function quote( str ) {
- return '"' + str.toString().replace( /"/g, '\\"' ) + '"';
- }
- function literal( o ) {
- return o + "";
- }
- function join( pre, arr, post ) {
- var s = jsDump.separator(),
- base = jsDump.indent(),
- inner = jsDump.indent(1);
- if ( arr.join ) {
- arr = arr.join( "," + s + inner );
- }
- if ( !arr ) {
- return pre + post;
- }
- return [ pre, inner + arr, base + post ].join(s);
- }
- function array( arr, stack ) {
- var i = arr.length, ret = new Array(i);
- this.up();
- while ( i-- ) {
- ret[i] = this.parse( arr[i] , undefined , stack);
- }
- this.down();
- return join( "[", ret, "]" );
- }
-
- var reName = /^function (\w+)/,
- jsDump = {
- // type is used mostly internally, you can fix a (custom)type in advance
- parse: function( obj, type, stack ) {
- stack = stack || [ ];
- var inStack, res,
- parser = this.parsers[ type || this.typeOf(obj) ];
-
- type = typeof parser;
- inStack = inArray( obj, stack );
-
- if ( inStack !== -1 ) {
- return "recursion(" + (inStack - stack.length) + ")";
- }
- if ( type === "function" ) {
- stack.push( obj );
- res = parser.call( this, obj, stack );
- stack.pop();
- return res;
- }
- return ( type === "string" ) ? parser : this.parsers.error;
- },
- typeOf: function( obj ) {
- var type;
- if ( obj === null ) {
- type = "null";
- } else if ( typeof obj === "undefined" ) {
- type = "undefined";
- } else if ( QUnit.is( "regexp", obj) ) {
- type = "regexp";
- } else if ( QUnit.is( "date", obj) ) {
- type = "date";
- } else if ( QUnit.is( "function", obj) ) {
- type = "function";
- } else if ( typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined" ) {
- type = "window";
- } else if ( obj.nodeType === 9 ) {
- type = "document";
- } else if ( obj.nodeType ) {
- type = "node";
- } else if (
- // native arrays
- toString.call( obj ) === "[object Array]" ||
- // NodeList objects
- ( typeof obj.length === "number" && typeof obj.item !== "undefined" && ( obj.length ? obj.item(0) === obj[0] : ( obj.item( 0 ) === null && typeof obj[0] === "undefined" ) ) )
- ) {
- type = "array";
- } else if ( obj.constructor === Error.prototype.constructor ) {
- type = "error";
- } else {
- type = typeof obj;
- }
- return type;
- },
- separator: function() {
- return this.multiline ? this.HTML ? "
" : "\n" : this.HTML ? " " : " ";
- },
- // extra can be a number, shortcut for increasing-calling-decreasing
- indent: function( extra ) {
- if ( !this.multiline ) {
- return "";
- }
- var chr = this.indentChar;
- if ( this.HTML ) {
- chr = chr.replace( /\t/g, " " ).replace( / /g, " " );
- }
- return new Array( this._depth_ + (extra||0) ).join(chr);
- },
- up: function( a ) {
- this._depth_ += a || 1;
- },
- down: function( a ) {
- this._depth_ -= a || 1;
- },
- setParser: function( name, parser ) {
- this.parsers[name] = parser;
- },
- // The next 3 are exposed so you can use them
- quote: quote,
- literal: literal,
- join: join,
- //
- _depth_: 1,
- // This is the list of parsers, to modify them, use jsDump.setParser
- parsers: {
- window: "[Window]",
- document: "[Document]",
- error: function(error) {
- return "Error(\"" + error.message + "\")";
- },
- unknown: "[Unknown]",
- "null": "null",
- "undefined": "undefined",
- "function": function( fn ) {
- var ret = "function",
- // functions never have name in IE
- name = "name" in fn ? fn.name : (reName.exec(fn) || [])[1];
-
- if ( name ) {
- ret += " " + name;
- }
- ret += "( ";
-
- ret = [ ret, QUnit.jsDump.parse( fn, "functionArgs" ), "){" ].join( "" );
- return join( ret, QUnit.jsDump.parse(fn,"functionCode" ), "}" );
- },
- array: array,
- nodelist: array,
- "arguments": array,
- object: function( map, stack ) {
- var ret = [ ], keys, key, val, i;
- QUnit.jsDump.up();
- keys = [];
- for ( key in map ) {
- keys.push( key );
- }
- keys.sort();
- for ( i = 0; i < keys.length; i++ ) {
- key = keys[ i ];
- val = map[ key ];
- ret.push( QUnit.jsDump.parse( key, "key" ) + ": " + QUnit.jsDump.parse( val, undefined, stack ) );
- }
- QUnit.jsDump.down();
- return join( "{", ret, "}" );
- },
- node: function( node ) {
- var len, i, val,
- open = QUnit.jsDump.HTML ? "<" : "<",
- close = QUnit.jsDump.HTML ? ">" : ">",
- tag = node.nodeName.toLowerCase(),
- ret = open + tag,
- attrs = node.attributes;
-
- if ( attrs ) {
- for ( i = 0, len = attrs.length; i < len; i++ ) {
- val = attrs[i].nodeValue;
- // IE6 includes all attributes in .attributes, even ones not explicitly set.
- // Those have values like undefined, null, 0, false, "" or "inherit".
- if ( val && val !== "inherit" ) {
- ret += " " + attrs[i].nodeName + "=" + QUnit.jsDump.parse( val, "attribute" );
- }
- }
- }
- ret += close;
-
- // Show content of TextNode or CDATASection
- if ( node.nodeType === 3 || node.nodeType === 4 ) {
- ret += node.nodeValue;
- }
-
- return ret + open + "/" + tag + close;
- },
- // function calls it internally, it's the arguments part of the function
- functionArgs: function( fn ) {
- var args,
- l = fn.length;
-
- if ( !l ) {
- return "";
- }
-
- args = new Array(l);
- while ( l-- ) {
- // 97 is 'a'
- args[l] = String.fromCharCode(97+l);
- }
- return " " + args.join( ", " ) + " ";
- },
- // object calls it internally, the key part of an item in a map
- key: quote,
- // function calls it internally, it's the content of the function
- functionCode: "[code]",
- // node calls it internally, it's an html attribute value
- attribute: quote,
- string: quote,
- date: quote,
- regexp: literal,
- number: literal,
- "boolean": literal
- },
- // if true, entities are escaped ( <, >, \t, space and \n )
- HTML: false,
- // indentation unit
- indentChar: " ",
- // if true, items in a collection, are separated by a \n, else just a space.
- multiline: true
- };
-
- return jsDump;
-}());
-
-// from jquery.js
-function inArray( elem, array ) {
- if ( array.indexOf ) {
- return array.indexOf( elem );
- }
-
- for ( var i = 0, length = array.length; i < length; i++ ) {
- if ( array[ i ] === elem ) {
- return i;
- }
- }
-
- return -1;
-}
-
-/*
- * Javascript Diff Algorithm
- * By John Resig (http://ejohn.org/)
- * Modified by Chu Alan "sprite"
- *
- * Released under the MIT license.
- *
- * More Info:
- * http://ejohn.org/projects/javascript-diff-algorithm/
- *
- * Usage: QUnit.diff(expected, actual)
- *
- * QUnit.diff( "the quick brown fox jumped over", "the quick fox jumps over" ) == "the quick brown fox jumped jumps over"
- */
-QUnit.diff = (function() {
- /*jshint eqeqeq:false, eqnull:true */
- function diff( o, n ) {
- var i,
- ns = {},
- os = {};
-
- for ( i = 0; i < n.length; i++ ) {
- if ( !hasOwn.call( ns, n[i] ) ) {
- ns[ n[i] ] = {
- rows: [],
- o: null
- };
- }
- ns[ n[i] ].rows.push( i );
- }
-
- for ( i = 0; i < o.length; i++ ) {
- if ( !hasOwn.call( os, o[i] ) ) {
- os[ o[i] ] = {
- rows: [],
- n: null
- };
- }
- os[ o[i] ].rows.push( i );
- }
-
- for ( i in ns ) {
- if ( !hasOwn.call( ns, i ) ) {
- continue;
- }
- if ( ns[i].rows.length === 1 && hasOwn.call( os, i ) && os[i].rows.length === 1 ) {
- n[ ns[i].rows[0] ] = {
- text: n[ ns[i].rows[0] ],
- row: os[i].rows[0]
- };
- o[ os[i].rows[0] ] = {
- text: o[ os[i].rows[0] ],
- row: ns[i].rows[0]
- };
- }
- }
-
- for ( i = 0; i < n.length - 1; i++ ) {
- if ( n[i].text != null && n[ i + 1 ].text == null && n[i].row + 1 < o.length && o[ n[i].row + 1 ].text == null &&
- n[ i + 1 ] == o[ n[i].row + 1 ] ) {
-
- n[ i + 1 ] = {
- text: n[ i + 1 ],
- row: n[i].row + 1
- };
- o[ n[i].row + 1 ] = {
- text: o[ n[i].row + 1 ],
- row: i + 1
- };
- }
- }
-
- for ( i = n.length - 1; i > 0; i-- ) {
- if ( n[i].text != null && n[ i - 1 ].text == null && n[i].row > 0 && o[ n[i].row - 1 ].text == null &&
- n[ i - 1 ] == o[ n[i].row - 1 ]) {
-
- n[ i - 1 ] = {
- text: n[ i - 1 ],
- row: n[i].row - 1
- };
- o[ n[i].row - 1 ] = {
- text: o[ n[i].row - 1 ],
- row: i - 1
- };
- }
- }
-
- return {
- o: o,
- n: n
- };
- }
-
- return function( o, n ) {
- o = o.replace( /\s+$/, "" );
- n = n.replace( /\s+$/, "" );
-
- var i, pre,
- str = "",
- out = diff( o === "" ? [] : o.split(/\s+/), n === "" ? [] : n.split(/\s+/) ),
- oSpace = o.match(/\s+/g),
- nSpace = n.match(/\s+/g);
-
- if ( oSpace == null ) {
- oSpace = [ " " ];
- }
- else {
- oSpace.push( " " );
- }
-
- if ( nSpace == null ) {
- nSpace = [ " " ];
- }
- else {
- nSpace.push( " " );
- }
-
- if ( out.n.length === 0 ) {
- for ( i = 0; i < out.o.length; i++ ) {
- str += "" + out.o[i] + oSpace[i] + "";
- }
- }
- else {
- if ( out.n[0].text == null ) {
- for ( n = 0; n < out.o.length && out.o[n].text == null; n++ ) {
- str += "" + out.o[n] + oSpace[n] + "";
- }
- }
-
- for ( i = 0; i < out.n.length; i++ ) {
- if (out.n[i].text == null) {
- str += "" + out.n[i] + nSpace[i] + "";
- }
- else {
- // `pre` initialized at top of scope
- pre = "";
-
- for ( n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++ ) {
- pre += "" + out.o[n] + oSpace[n] + "";
- }
- str += " " + out.n[i].text + nSpace[i] + pre;
- }
- }
- }
-
- return str;
- };
-}());
-
-// for CommonJS enviroments, export everything
-if ( typeof exports !== "undefined" ) {
- extend( exports, QUnit );
-}
-
-// get at whatever the global object is, like window in browsers
-}( (function() {return this;}.call()) ));
diff --git a/test/lib/require.js b/test/lib/require.js
deleted file mode 100644
index 987f865..0000000
--- a/test/lib/require.js
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- RequireJS 2.1.5 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.
- Available via the MIT or new BSD license.
- see: http://github.com/jrburke/requirejs for details
-*/
-var requirejs,require,define;
-(function(aa){function I(b){return"[object Function]"===L.call(b)}function J(b){return"[object Array]"===L.call(b)}function y(b,c){if(b){var d;for(d=0;dthis.depCount&&!this.defined){if(I(n)){if(this.events.error)try{e=i.execCb(c,n,b,e)}catch(d){a=d}else e=i.execCb(c,n,b,e);this.map.isDefine&&((b=this.module)&&void 0!==b.exports&&b.exports!==this.exports?e=b.exports:void 0===e&&this.usingExports&&(e=this.exports));if(a)return a.requireMap=this.map,a.requireModules=[this.map.id],a.requireType="define",v(this.error=
-a)}else e=n;this.exports=e;if(this.map.isDefine&&!this.ignore&&(q[c]=e,l.onResourceLoad))l.onResourceLoad(i,this.map,this.depMaps);x(c);this.defined=!0}this.defining=!1;this.defined&&!this.defineEmitted&&(this.defineEmitted=!0,this.emit("defined",this.exports),this.defineEmitComplete=!0)}}else this.fetch()}},callPlugin:function(){var a=this.map,b=a.id,d=j(a.prefix);this.depMaps.push(d);t(d,"defined",u(this,function(e){var n,d;d=this.map.name;var g=this.map.parentMap?this.map.parentMap.name:null,h=
-i.makeRequire(a.parentMap,{enableBuildCallback:!0});if(this.map.unnormalized){if(e.normalize&&(d=e.normalize(d,function(a){return c(a,g,!0)})||""),e=j(a.prefix+"!"+d,this.map.parentMap),t(e,"defined",u(this,function(a){this.init([],function(){return a},null,{enabled:!0,ignore:!0})})),d=m(p,e.id)){this.depMaps.push(e);if(this.events.error)d.on("error",u(this,function(a){this.emit("error",a)}));d.enable()}}else n=u(this,function(a){this.init([],function(){return a},null,{enabled:!0})}),n.error=u(this,
-function(a){this.inited=!0;this.error=a;a.requireModules=[b];G(p,function(a){0===a.map.id.indexOf(b+"_unnormalized")&&x(a.map.id)});v(a)}),n.fromText=u(this,function(e,c){var d=a.name,g=j(d),C=O;c&&(e=c);C&&(O=!1);r(g);s(k.config,b)&&(k.config[d]=k.config[b]);try{l.exec(e)}catch(ca){return v(B("fromtexteval","fromText eval for "+b+" failed: "+ca,ca,[b]))}C&&(O=!0);this.depMaps.push(g);i.completeLoad(d);h([d],n)}),e.load(a.name,h,n,k)}));i.enable(d,this);this.pluginMaps[d.id]=d},enable:function(){V[this.map.id]=
-this;this.enabling=this.enabled=!0;y(this.depMaps,u(this,function(a,b){var c,e;if("string"===typeof a){a=j(a,this.map.isDefine?this.map:this.map.parentMap,!1,!this.skipMap);this.depMaps[b]=a;if(c=m(N,a.id)){this.depExports[b]=c(this);return}this.depCount+=1;t(a,"defined",u(this,function(a){this.defineDep(b,a);this.check()}));this.errback&&t(a,"error",this.errback)}c=a.id;e=p[c];!s(N,c)&&(e&&!e.enabled)&&i.enable(a,this)}));G(this.pluginMaps,u(this,function(a){var b=m(p,a.id);b&&!b.enabled&&i.enable(a,
-this)}));this.enabling=!1;this.check()},on:function(a,b){var c=this.events[a];c||(c=this.events[a]=[]);c.push(b)},emit:function(a,b){y(this.events[a],function(a){a(b)});"error"===a&&delete this.events[a]}};i={config:k,contextName:b,registry:p,defined:q,urlFetched:U,defQueue:H,Module:Z,makeModuleMap:j,nextTick:l.nextTick,onError:v,configure:function(a){a.baseUrl&&"/"!==a.baseUrl.charAt(a.baseUrl.length-1)&&(a.baseUrl+="/");var b=k.pkgs,c=k.shim,e={paths:!0,config:!0,map:!0};G(a,function(a,b){e[b]?
-"map"===b?(k.map||(k.map={}),R(k[b],a,!0,!0)):R(k[b],a,!0):k[b]=a});a.shim&&(G(a.shim,function(a,b){J(a)&&(a={deps:a});if((a.exports||a.init)&&!a.exportsFn)a.exportsFn=i.makeShimExports(a);c[b]=a}),k.shim=c);a.packages&&(y(a.packages,function(a){a="string"===typeof a?{name:a}:a;b[a.name]={name:a.name,location:a.location||a.name,main:(a.main||"main").replace(ja,"").replace(ea,"")}}),k.pkgs=b);G(p,function(a,b){!a.inited&&!a.map.unnormalized&&(a.map=j(b))});if(a.deps||a.callback)i.require(a.deps||[],
-a.callback)},makeShimExports:function(a){return function(){var b;a.init&&(b=a.init.apply(aa,arguments));return b||a.exports&&ba(a.exports)}},makeRequire:function(a,f){function d(e,c,h){var g,k;f.enableBuildCallback&&(c&&I(c))&&(c.__requireJsBuild=!0);if("string"===typeof e){if(I(c))return v(B("requireargs","Invalid require call"),h);if(a&&s(N,e))return N[e](p[a.id]);if(l.get)return l.get(i,e,a,d);g=j(e,a,!1,!0);g=g.id;return!s(q,g)?v(B("notloaded",'Module name "'+g+'" has not been loaded yet for context: '+
-b+(a?"":". Use require([])"))):q[g]}L();i.nextTick(function(){L();k=r(j(null,a));k.skipMap=f.skipMap;k.init(e,c,h,{enabled:!0});D()});return d}f=f||{};R(d,{isBrowser:A,toUrl:function(b){var d,f=b.lastIndexOf("."),g=b.split("/")[0];if(-1!==f&&(!("."===g||".."===g)||1h.attachEvent.toString().indexOf("[native code"))&&!Y?(O=!0,h.attachEvent("onreadystatechange",b.onScriptLoad)):(h.addEventListener("load",b.onScriptLoad,!1),h.addEventListener("error",b.onScriptError,!1)),h.src=d,K=h,D?x.insertBefore(h,D):x.appendChild(h),K=null,h;if(da)try{importScripts(d),b.completeLoad(c)}catch(j){b.onError(B("importscripts","importScripts failed for "+c+" at "+d,j,[c]))}};A&&M(document.getElementsByTagName("script"),function(b){x||(x=
-b.parentNode);if(t=b.getAttribute("data-main"))return r.baseUrl||(E=t.split("/"),Q=E.pop(),fa=E.length?E.join("/")+"/":"./",r.baseUrl=fa,t=Q),t=t.replace(ea,""),r.deps=r.deps?r.deps.concat(t):[t],!0});define=function(b,c,d){var l,h;"string"!==typeof b&&(d=c,c=b,b=null);J(c)||(d=c,c=[]);!c.length&&I(d)&&d.length&&(d.toString().replace(la,"").replace(ma,function(b,d){c.push(d)}),c=(1===d.length?["require"]:["require","exports","module"]).concat(c));if(O){if(!(l=K))P&&"interactive"===P.readyState||M(document.getElementsByTagName("script"),
-function(b){if("interactive"===b.readyState)return P=b}),l=P;l&&(b||(b=l.getAttribute("data-requiremodule")),h=F[l.getAttribute("data-requirecontext")])}(h?h.defQueue:T).push([b,c,d])};define.amd={jQuery:!0};l.exec=function(b){return eval(b)};l(r)}})(this);
diff --git a/test/lib/resemble.js b/test/lib/resemble.js
new file mode 100644
index 0000000..1cb8c29
--- /dev/null
+++ b/test/lib/resemble.js
@@ -0,0 +1,535 @@
+/*
+Author: James Cryer
+Company: Huddle
+Last updated date: 21 Feb 2013
+URL: https://github.com/Huddle/Resemble.js
+*/
+
+(function(_this){
+ 'use strict';
+
+ _this['resemble'] = function( fileData ){
+
+ var data = {};
+ var images = [];
+ var updateCallbackArray = [];
+
+ var tolerance = { // between 0 and 255
+ red: 16,
+ green: 16,
+ blue: 16,
+ minBrightness: 16,
+ maxBrightness: 240
+ };
+
+ var ignoreAntialiasing = false;
+ var ignoreColors = false;
+
+ function triggerDataUpdate(){
+ var len = updateCallbackArray.length;
+ var i;
+ for(i=0;i tolerance.maxBrightness;
+ }
+
+ function getHue(r,g,b){
+
+ r = r / 255;
+ g = g / 255;
+ b = b / 255;
+ var max = Math.max(r, g, b), min = Math.min(r, g, b);
+ var h;
+ var d;
+
+ if (max == min){
+ h = 0; // achromatic
+ } else{
+ d = max - min;
+ switch(max){
+ case r: h = (g - b) / d + (g < b ? 6 : 0); break;
+ case g: h = (b - r) / d + 2; break;
+ case b: h = (r - g) / d + 4; break;
+ }
+ h /= 6;
+ }
+
+ return h;
+ }
+
+ function isAntialiased(sourcePix, data, cacheSet, verticalPos, horizontalPos, width){
+ var offset;
+ var targetPix;
+ var distance = 1;
+ var i;
+ var j;
+ var hasHighContrastSibling = 0;
+ var hasSiblingWithDifferentHue = 0;
+ var hasEquivilantSibling = 0;
+
+ addHueInfo(sourcePix);
+
+ for (i = distance*-1; i <= distance; i++){
+ for (j = distance*-1; j <= distance; j++){
+
+ if(i===0 && j===0){
+ // ignore source pixel
+ } else {
+
+ offset = ((verticalPos+j)*width + (horizontalPos+i)) * 4;
+ targetPix = getPixelInfo(data, offset, cacheSet);
+
+ if(targetPix === null){
+ continue;
+ }
+
+ addBrightnessInfo(targetPix);
+ addHueInfo(targetPix);
+
+ if( isContrasting(sourcePix, targetPix) ){
+ hasHighContrastSibling++;
+ }
+
+ if( isRGBSame(sourcePix,targetPix) ){
+ hasEquivilantSibling++;
+ }
+
+ if( Math.abs(targetPix.h - sourcePix.h) > 0.3 ){
+ hasSiblingWithDifferentHue++;
+ }
+
+ if( hasSiblingWithDifferentHue > 1 || hasHighContrastSibling > 1){
+ return true;
+ }
+ }
+ }
+ }
+
+ if(hasEquivilantSibling < 2){
+ return true;
+ }
+
+ return false;
+ }
+
+ function errorPixel(px, offset){
+ px[offset] = 255; //r
+ px[offset + 1] = 0; //g
+ px[offset + 2] = 255; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyPixel(px, offset, data){
+ px[offset] = data.r; //r
+ px[offset + 1] = data.g; //g
+ px[offset + 2] = data.b; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyGrayScalePixel(px, offset, data){
+ px[offset] = data.brightness; //r
+ px[offset + 1] = data.brightness; //g
+ px[offset + 2] = data.brightness; //b
+ px[offset + 3] = 255; //a
+ }
+
+
+ function getPixelInfo(data, offset, cacheSet){
+ var r;
+ var g;
+ var b;
+ var d;
+
+ if(typeof data[offset] !== 'undefined'){
+ r = data[offset];
+ g = data[offset+1];
+ b = data[offset+2];
+ d = {
+ r: r,
+ g: g,
+ b: b
+ };
+
+ return d;
+ } else {
+ return null;
+ }
+ }
+
+ function addBrightnessInfo(data){
+ data.brightness = getBrightness(data.r,data.g,data.b); // 'corrected' lightness
+ }
+
+ function addHueInfo(data){
+ data.h = getHue(data.r,data.g,data.b);
+ }
+
+ function analyseImages(img1, img2, width, height){
+
+ var hiddenCanvas = document.createElement('canvas');
+
+ var data1 = img1.data;
+ var data2 = img2.data;
+
+ hiddenCanvas.width = width;
+ hiddenCanvas.height = height;
+
+ var context = hiddenCanvas.getContext('2d');
+ var imgd = context.createImageData(width,height);
+ var targetPix = imgd.data;
+
+ var mismatchCount = 0;
+
+ var time = Date.now();
+
+ var skip;
+
+ if( (width > 1200 || height > 1200) && ignoreAntialiasing){
+ skip = 6;
+ }
+
+ loop(height, width, function(verticalPos, horizontalPos){
+
+ if(skip){ // only skip if the image isn't small
+ if(verticalPos % skip === 0 || horizontalPos % skip === 0){
+ return;
+ }
+ }
+
+ var offset = (verticalPos*width + horizontalPos) * 4;
+ var pixel1 = getPixelInfo(data1, offset, 1);
+ var pixel2 = getPixelInfo(data2, offset, 2);
+
+ if(pixel1 === null || pixel2 === null){
+ return;
+ }
+
+ if (ignoreColors){
+
+ addBrightnessInfo(pixel1);
+ addBrightnessInfo(pixel2);
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ return;
+ }
+
+ if( isRGBSimilar(pixel1, pixel2) ){
+ copyPixel(targetPix, offset, pixel2);
+
+ } else if( ignoreAntialiasing && (
+ addBrightnessInfo(pixel1), // jit pixel info augmentation looks a little weird, sorry.
+ addBrightnessInfo(pixel2),
+ isAntialiased(pixel1, data1, 1, verticalPos, horizontalPos, width) ||
+ isAntialiased(pixel2, data2, 2, verticalPos, horizontalPos, width)
+ )){
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+
+ });
+
+ data.misMatchPercentage = (mismatchCount / (height*width) * 100).toFixed(2);
+ data.analysisTime = Date.now() - time;
+
+ data.getImageDataUrl = function(text){
+ var barHeight = 0;
+
+ if(text){
+ barHeight = addLabel(text,context,hiddenCanvas);
+ }
+
+ context.putImageData(imgd, 0, barHeight);
+
+ return hiddenCanvas.toDataURL("image/png");
+ };
+ }
+
+ function addLabel(text, context, hiddenCanvas){
+ var textPadding = 2;
+
+ context.font = '12px sans-serif';
+
+ var textWidth = context.measureText(text).width + textPadding*2;
+ var barHeight = 22;
+
+ if(textWidth > hiddenCanvas.width){
+ hiddenCanvas.width = textWidth;
+ }
+
+ hiddenCanvas.height += barHeight;
+
+ context.fillStyle = "#666";
+ context.fillRect(0,0,hiddenCanvas.width,barHeight -4);
+ context.fillStyle = "#fff";
+ context.fillRect(0,barHeight -4,hiddenCanvas.width, 4);
+
+ context.fillStyle = "#fff";
+ context.textBaseline = "top";
+ context.font = '12px sans-serif';
+ context.fillText(text, textPadding, 1);
+
+ return barHeight;
+ }
+
+ function normalise(img, w, h){
+ var c;
+ var context;
+
+ if(img.height < h || img.width < w){
+ c = document.createElement('canvas');
+ c.width = w;
+ c.height = h;
+ context = c.getContext('2d');
+ context.putImageData(img, 0, 0);
+ return context.getImageData(0, 0, w, h);
+ }
+
+ return img;
+ }
+
+ function compare(one, two){
+
+ function onceWeHaveBoth(){
+ var width;
+ var height;
+ if(images.length === 2){
+ width = images[0].width > images[1].width ? images[0].width : images[1].width;
+ height = images[0].height > images[1].height ? images[0].height : images[1].height;
+
+ if( (images[0].width === images[1].width) && (images[0].height === images[1].height) ){
+ data.isSameDimensions = true;
+ } else {
+ data.isSameDimensions = false;
+ }
+
+ analyseImages( normalise(images[0],width, height), normalise(images[1],width, height), width, height);
+
+ triggerDataUpdate();
+ }
+ }
+
+ images = [];
+ loadImageData(one, onceWeHaveBoth);
+ loadImageData(two, onceWeHaveBoth);
+ }
+
+ function getCompareApi(param){
+
+ var secondFileData,
+ hasMethod = typeof param === 'function';
+
+ if( !hasMethod ){
+ // assume it's file data
+ secondFileData = param;
+ }
+
+ var self = {
+ ignoreNothing: function(){
+
+ tolerance.red = 16;
+ tolerance.green = 16;
+ tolerance.blue = 16;
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreAntialiasing: function(){
+
+ tolerance.red = 32;
+ tolerance.green = 32;
+ tolerance.blue = 32;
+ tolerance.minBrightness = 64;
+ tolerance.maxBrightness = 96;
+
+ ignoreAntialiasing = true;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreColors: function(){
+
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = true;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ onComplete: function( callback ){
+
+ updateCallbackArray.push(callback);
+
+ var wrapper = function(){
+ compare(fileData, secondFileData);
+ };
+
+ wrapper();
+
+ return getCompareApi(wrapper);
+ }
+ };
+
+ return self;
+ }
+
+ return {
+ onComplete: function( callback ){
+ updateCallbackArray.push(callback);
+ loadImageData(fileData, function(imageData, width, height){
+ parseImage(imageData.data, width, height);
+ });
+ },
+ compareTo: function(secondFileData){
+ return getCompareApi(secondFileData);
+ }
+ };
+
+ };
+}(this));
\ No newline at end of file
diff --git a/test/testsuite.js b/test/testsuite.js
deleted file mode 100644
index b486acb..0000000
--- a/test/testsuite.js
+++ /dev/null
@@ -1,36 +0,0 @@
-requirejs.config({
- baseUrl: '/test/unit/'
-});
-
-define(function(require) {
- var testModules = [
- 'Pixi',
- 'Point',
- 'Rectangle',
- 'DisplayObject',
- 'DisplayObjectContainer',
- 'Sprite',
- 'MovieClip',
- 'InteractionManager',
- 'Stage',
- 'utils/Utils',
- 'utils/EventTarget',
- 'utils/Matrix',
- 'utils/Detector',
- 'renderers/WebGLShaders',
- 'renderers/WebGLRenderer',
- 'renderers/WebGLBatch',
- 'renderers/CanvasRenderer',
- 'extras/Strip',
- 'extras/Rope',
- 'textures/BaseTexture',
- 'textures/Texture',
- 'loaders/SpriteSheetLoader',
- 'loaders/AssetLoader'
- ];
-
- // Resolve all testModules and then start the Test Runner.
- require(testModules, function() {
- QUnit.start();
- });
-});
\ No newline at end of file
diff --git a/test/textures/SpriteSheet-Aliens.png b/test/textures/SpriteSheet-Aliens.png
new file mode 100644
index 0000000..210acb1
--- /dev/null
+++ b/test/textures/SpriteSheet-Aliens.png
Binary files differ
diff --git a/test/textures/SpriteSheet-Explosion.png b/test/textures/SpriteSheet-Explosion.png
new file mode 100755
index 0000000..79e1a69
--- /dev/null
+++ b/test/textures/SpriteSheet-Explosion.png
Binary files differ
diff --git a/test/textures/bunny.png b/test/textures/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/textures/bunny.png
Binary files differ
diff --git a/test/unit/DisplayObject.js b/test/unit/DisplayObject.js
deleted file mode 100644
index 5e7e72f..0000000
--- a/test/unit/DisplayObject.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObject');
-});
diff --git a/test/unit/DisplayObjectContainer.js b/test/unit/DisplayObjectContainer.js
deleted file mode 100644
index b323959..0000000
--- a/test/unit/DisplayObjectContainer.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObjectContainer');
-});
diff --git a/test/unit/InteractionManager.js b/test/unit/InteractionManager.js
deleted file mode 100644
index e751f52..0000000
--- a/test/unit/InteractionManager.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('InteractionManager');
-});
diff --git a/test/unit/MovieClip.js b/test/unit/MovieClip.js
deleted file mode 100644
index 37d9446..0000000
--- a/test/unit/MovieClip.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('MovieClip');
-});
diff --git a/test/unit/Pixi.js b/test/unit/Pixi.js
deleted file mode 100644
index 36eee73..0000000
--- a/test/unit/Pixi.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Pixi');
-});
diff --git a/test/unit/Point.js b/test/unit/Point.js
deleted file mode 100644
index 983ff6e..0000000
--- a/test/unit/Point.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Point');
-});
diff --git a/test/unit/Rectangle.js b/test/unit/Rectangle.js
deleted file mode 100644
index 3b439ba..0000000
--- a/test/unit/Rectangle.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Rectangle');
-});
diff --git a/test/unit/Sprite.js b/test/unit/Sprite.js
deleted file mode 100644
index ed4f596..0000000
--- a/test/unit/Sprite.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Sprite');
-});
diff --git a/test/unit/Stage.js b/test/unit/Stage.js
deleted file mode 100644
index 2d70291..0000000
--- a/test/unit/Stage.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Stage');
-});
diff --git a/test/unit/extras/Rope.js b/test/unit/extras/Rope.js
deleted file mode 100644
index 5606f14..0000000
--- a/test/unit/extras/Rope.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Rope');
-});
diff --git a/test/unit/extras/Strip.js b/test/unit/extras/Strip.js
deleted file mode 100644
index 0134d3a..0000000
--- a/test/unit/extras/Strip.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Strip');
-});
diff --git a/test/unit/loaders/AssetLoader.js b/test/unit/loaders/AssetLoader.js
deleted file mode 100644
index 13b8443..0000000
--- a/test/unit/loaders/AssetLoader.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('AssetLoader');
-});
diff --git a/test/unit/loaders/SpriteSheetLoader.js b/test/unit/loaders/SpriteSheetLoader.js
deleted file mode 100644
index 8bf0cb2..0000000
--- a/test/unit/loaders/SpriteSheetLoader.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('SpriteSheetLoader');
-});
diff --git a/test/unit/pixi/InteractionManager.js b/test/unit/pixi/InteractionManager.js
new file mode 100644
index 0000000..ed3001f
--- /dev/null
+++ b/test/unit/pixi/InteractionManager.js
@@ -0,0 +1,10 @@
+describe('pixi/InteractionManager', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var InteractionManager = PIXI.InteractionManager;
+
+ it('Module exists', function () {
+ expect(InteractionManager).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/Pixi.js b/test/unit/pixi/Pixi.js
new file mode 100644
index 0000000..27debc1
--- /dev/null
+++ b/test/unit/pixi/Pixi.js
@@ -0,0 +1,9 @@
+describe('pixi/Pixi', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+
+ it('Module exists', function () {
+ expect(global).to.have.property('PIXI').and.to.be.an('object');
+ });
+});
diff --git a/.gitignore b/.gitignore
index 12e1b62..0b88317 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
node_modules
.DS_Store
-.project
\ No newline at end of file
+.project
+*.log
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..63e4d7c
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,8 @@
+language: node_js
+node_js:
+ - 0.10
+
+before_script:
+ - npm install -g grunt-cli
+ - export DISPLAY=:99.0
+ - sh -e /etc/init.d/xvfb start
diff --git a/Gruntfile.js b/Gruntfile.js
index b083b49..103938c 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -1,10 +1,12 @@
+'use strict';
+
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-connect');
- grunt.loadNpmTasks('grunt-contrib-qunit');
grunt.loadNpmTasks('grunt-contrib-yuidoc');
+ grunt.loadTasks('tasks');
var root = 'src/pixi/',
debug = 'bin/pixi.dev.js',
@@ -79,7 +81,7 @@
},
files: {
srcBlob: '<%= dirs.src %>/**/*.js',
- testBlob: '<%= dirs.test %>/unit/**/*.js',
+ testBlob: '<%= dirs.test %>/{functional,lib/pixi,unit}/**/*.js',
build: '<%= dirs.build %>/pixi.dev.js',
buildMin: '<%= dirs.build %>/pixi.js'
},
@@ -94,7 +96,12 @@
},
jshint: {
beforeconcat: srcFiles,
- test: ['<%= files.testBlob %>'],
+ test: {
+ src: ['<%= files.testBlob %>'],
+ options: {
+ expr: true
+ }
+ },
options: {
asi: true,
smarttabs: true
@@ -128,12 +135,6 @@
]
},
connect: {
- qunit: {
- options: {
- port: grunt.option('port-test') || 9002,
- base: './'
- }
- },
test: {
options: {
port: grunt.option('port-test') || 9002,
@@ -142,13 +143,6 @@
}
}
},
- qunit: {
- all: {
- options: {
- urls: ['http://localhost:' + (grunt.option('port-test') || 9002) + '/test/index.html']
- }
- }
- },
yuidoc: {
compile: {
name: '<%= pkg.name %>',
@@ -161,6 +155,13 @@
outdir: '<%= dirs.docs %>'
}
}
+ },
+ karma: {
+ unit: {
+ configFile: 'test/karma.conf.js',
+ // browsers: ['Chrome'],
+ singleRun: true
+ }
}
});
@@ -182,9 +183,10 @@
}
)
- grunt.registerTask('default', ['concat', 'uglify', 'distribute']);
grunt.registerTask('build', ['concat', 'uglify', 'distribute']);
- grunt.registerTask('test', ['build', 'connect:qunit', 'qunit']);
+ grunt.registerTask('test', ['concat', 'jshint:test', 'karma']);
grunt.registerTask('docs', ['yuidoc']);
-
-}
\ No newline at end of file
+ grunt.registerTask('default', ['test', 'uglify', 'distribute']);
+ // Travis CI task.
+ grunt.registerTask('travis', ['test']);
+}
diff --git a/README.md b/README.md
index c62ef86..690cfe4 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,8 @@

+[](http://travis-ci.org/drkibitz/pixi.js)
+
#### JavaScript 2D Renderer ####
The aim of this project is to provide a fast lightweight 2D library that works
diff --git a/package.json b/package.json
index b373240..1246a68 100644
--- a/package.json
+++ b/package.json
@@ -18,14 +18,21 @@
"main": "bin/pixi.js",
+ "scripts": {
+ "test": "grunt travis --verbose"
+ },
+
"dependencies": {},
"devDependencies": {
"grunt": "~0.4.x",
- "grunt-contrib-jshint": "0.3.x",
+ "grunt-contrib-jshint": "0.6.x",
"grunt-contrib-uglify": "0.2.x",
- "grunt-contrib-connect": "0.2.x",
- "grunt-contrib-qunit": "0.2.x",
+ "grunt-contrib-connect": "0.3.x",
"grunt-contrib-yuidoc": "0.4.x",
- "grunt-contrib-concat": "0.1.x"
+ "grunt-contrib-concat": "0.3.x",
+ "chai": "~1.7.0",
+ "karma": "0.11.0",
+ "karma-firefox-launcher": "0.1.0",
+ "karma-mocha": "0.1.0"
}
}
diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js
index a7c520e..ee82bbd 100644
--- a/src/pixi/InteractionManager.js
+++ b/src/pixi/InteractionManager.js
@@ -62,7 +62,6 @@
this.onTouchEnd = this.onTouchEnd.bind(this);
this.onTouchMove = this.onTouchMove.bind(this);
-
this.last = 0;
}
diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js
index 1a95d20..eef1059 100644
--- a/src/pixi/core/Ellipse.js
+++ b/src/pixi/core/Ellipse.js
@@ -78,7 +78,7 @@
return (normx + normy < 0.25);
}
-PIXI.Ellipse.getBounds = function()
+PIXI.Ellipse.prototype.getBounds = function()
{
return new PIXI.Rectangle(this.x, this.y, this.width, this.height);
}
diff --git a/tasks/karma.js b/tasks/karma.js
new file mode 100644
index 0000000..c340485
--- /dev/null
+++ b/tasks/karma.js
@@ -0,0 +1,27 @@
+'use strict';
+
+var path = require('path');
+var server = require('karma').server;
+
+module.exports = function (grunt) {
+ grunt.registerMultiTask('karma', 'run karma.', function() {
+ var done = this.async();
+ var options = this.options({
+ background: false
+ });
+ var data = this.data;
+
+ //merge options onto data, with data taking precedence
+ data = grunt.util._.merge(options, data);
+ data.configFile = path.resolve(data.configFile);
+ if (data.configFile) {
+ data.configFile = grunt.template.process(data.configFile);
+ }
+
+ server.start(
+ data,
+ function(code) {
+ done(!code);
+ });
+ });
+};
diff --git a/test/functional/example-1-basics/bunny.png b/test/functional/example-1-basics/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/functional/example-1-basics/bunny.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-30.png b/test/functional/example-1-basics/frame-30.png
new file mode 100644
index 0000000..96e3409
--- /dev/null
+++ b/test/functional/example-1-basics/frame-30.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-60.png b/test/functional/example-1-basics/frame-60.png
new file mode 100644
index 0000000..af3f4ce
--- /dev/null
+++ b/test/functional/example-1-basics/frame-60.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-90.png b/test/functional/example-1-basics/frame-90.png
new file mode 100644
index 0000000..099b823
--- /dev/null
+++ b/test/functional/example-1-basics/frame-90.png
Binary files differ
diff --git a/test/functional/example-1-basics/index.js b/test/functional/example-1-basics/index.js
new file mode 100644
index 0000000..7ae7a98
--- /dev/null
+++ b/test/functional/example-1-basics/index.js
@@ -0,0 +1,133 @@
+describe('Example 1 - Basics', function () {
+ 'use strict';
+
+ var baseUri = '/base/test/functional/example-1-basics';
+ var expect = chai.expect;
+ var currentFrame = 0;
+ var frameEvents = {};
+ var stage;
+ var renderer;
+ var bunny;
+
+ function onFrame(frame, callback) {
+ frameEvents[frame] = callback;
+ }
+
+ function animate() {
+ currentFrame += 1;
+
+ requestAnimFrame( animate );
+
+ // just for fun, lets rotate mr rabbit a little
+ bunny.rotation += 0.1;
+
+ // render the stage
+ renderer.render(stage);
+
+ if (frameEvents[currentFrame])
+ frameEvents[currentFrame](currentFrame);
+ }
+
+ function initScene() {
+ // create an new instance of a pixi stage
+ stage = new PIXI.Stage(0x66FF99);
+
+ // create a renderer instance
+ renderer = PIXI.autoDetectRenderer(400, 300);
+ console.log('Is PIXI.WebGLRenderer: ' + (renderer instanceof PIXI.WebGLRenderer));
+
+ // add the renderer view element to the DOM
+ document.body.appendChild(renderer.view);
+
+ requestAnimFrame( animate );
+
+ // create a texture from an image path
+ var texture = PIXI.Texture.fromImage(baseUri + "/bunny.png");
+ // create a new Sprite using the texture
+ bunny = new PIXI.Sprite(texture);
+
+ // center the sprites anchor point
+ bunny.anchor.x = 0.5;
+ bunny.anchor.y = 0.5;
+
+ // move the sprite t the center of the screen
+ bunny.position.x = 200;
+ bunny.position.y = 150;
+
+ stage.addChild(bunny);
+ }
+
+ it('assets loaded', function (done) {
+ var loader = new PIXI.AssetLoader([
+ baseUri + '/bunny.png',
+ baseUri + '/frame-30.png',
+ baseUri + '/frame-60.png',
+ baseUri + '/frame-90.png'
+ ]);
+ // loader.on('onProgress', function (event) {
+ // console.log(event.content);
+ // });
+ loader.on('onComplete', function (event) {
+ done();
+ initScene();
+ });
+ loader.load();
+ });
+
+ it('frame 30 should match', function (done) {
+ this.timeout(700);
+ onFrame(30, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-30.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 60 should match', function (done) {
+ this.timeout(1200);
+ onFrame(60, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-60.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 90 should match', function (done) {
+ this.timeout(1700);
+ onFrame(90, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-90.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ // it('capture something', function (done) {
+ // this.timeout(2000000);
+ // onFrame(30, function () {
+ // var img = new Image();
+ // img.src = renderer.view.toDataURL('image/png');
+ // document.body.appendChild(img);
+ // });
+ // });
+});
diff --git a/test/index.html b/test/index.html
deleted file mode 100644
index 9cbcac5..0000000
--- a/test/index.html
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
- Pixi.js Test Suite
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/test/karma.conf.js b/test/karma.conf.js
new file mode 100644
index 0000000..c66a696
--- /dev/null
+++ b/test/karma.conf.js
@@ -0,0 +1,82 @@
+module.exports = function(config) {
+ config.set({
+
+ // base path, that will be used to resolve files and exclude
+ basePath : '../',
+
+ frameworks : ['mocha'],
+
+ // list of files / patterns to load in the browser
+ files : [
+ 'node_modules/chai/chai.js',
+ 'bin/pixi.dev.js',
+ 'test/lib/**/*.js',
+ 'test/unit/**/*.js',
+ // 'test/functional/**/*.js',
+ {pattern: 'test/**/*.png', watched: false, included: false, served: true}
+ ],
+
+ // list of files to exclude
+ exclude : [],
+
+ // use dolts reporter, as travis terminal does not support escaping sequences
+ // possible values: 'dots', 'progress', 'junit', 'teamcity'
+ // CLI --reporters progress
+ reporters : ['progress'],
+
+ // web server port
+ // CLI --port 9876
+ port : 9876,
+
+ // cli runner port
+ // CLI --runner-port 9100
+ runnerPort : 9100,
+
+ // enable / disable colors in the output (reporters and logs)
+ // CLI --colors --no-colors
+ colors : true,
+
+ // level of logging
+ // possible values: karma.LOG_DISABLE || karma.LOG_ERROR || karma.LOG_WARN || karma.LOG_INFO || karma.LOG_DEBUG
+ // CLI --log-level debug
+ logLevel : config.LOG_DEBUG,
+
+ // enable / disable watching file and executing tests whenever any file changes
+ // CLI --auto-watch --no-auto-watch
+ autoWatch : false,
+
+ // Start these browsers, currently available:
+ // - Chrome
+ // - ChromeCanary
+ // - Firefox
+ // - Opera
+ // - Safari (only Mac)
+ // - PhantomJS
+ // - IE (only Windows)
+ // CLI --browsers Chrome,Firefox,Safari
+ browsers : ['Firefox'],
+
+ // If browser does not capture in given timeout [ms], kill it
+ // CLI --capture-timeout 5000
+ captureTimeout : 5000,
+
+ // Auto run tests on start (when browsers are captured) and exit
+ // CLI --single-run --no-single-run
+ singleRun : true,
+
+ // report which specs are slower than 500ms
+ // CLI --report-slower-than 500
+ reportSlowerThan : 1000,
+
+ preprocessors : {
+ // '**/client/js/*.js': 'coverage'
+ },
+
+ plugins : [
+ 'karma-mocha',
+ // 'karma-chrome-launcher',
+ 'karma-firefox-launcher',
+ // 'karma-phantomjs-launcher'
+ ]
+ });
+};
diff --git a/test/lib/pixi/core/Matrix.js b/test/lib/pixi/core/Matrix.js
new file mode 100644
index 0000000..d26386b
--- /dev/null
+++ b/test/lib/pixi/core/Matrix.js
@@ -0,0 +1,40 @@
+
+function pixi_core_Matrix_confirmNewMat3(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(1);
+ expect(matrix[5]).to.equal(0);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(1);
+}
+
+function pixi_core_Matrix_confirmNewMat4(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[0]).to.equal(1);
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(0);
+ expect(matrix[5]).to.equal(1);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(0);
+ expect(matrix[9]).to.equal(0);
+ expect(matrix[10]).to.equal(1);
+ expect(matrix[11]).to.equal(0);
+ expect(matrix[12]).to.equal(0);
+ expect(matrix[13]).to.equal(0);
+ expect(matrix[14]).to.equal(0);
+ expect(matrix[15]).to.equal(1);
+}
diff --git a/test/lib/pixi/core/Point.js b/test/lib/pixi/core/Point.js
new file mode 100644
index 0000000..e5df07b
--- /dev/null
+++ b/test/lib/pixi/core/Point.js
@@ -0,0 +1,10 @@
+
+function pixi_core_Point_confirm(obj, x, y) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Point);
+ expect(obj).to.respondTo('clone');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+}
diff --git a/test/lib/pixi/core/Rectangle.js b/test/lib/pixi/core/Rectangle.js
new file mode 100644
index 0000000..23f0d12
--- /dev/null
+++ b/test/lib/pixi/core/Rectangle.js
@@ -0,0 +1,13 @@
+
+function pixi_core_Rectangle_confirm(obj, x, y, width, height) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Rectangle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+ expect(obj).to.have.property('width', width);
+ expect(obj).to.have.property('height', height);
+}
diff --git a/test/lib/pixi/display/DisplayObject.js b/test/lib/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..1388a7f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObject.js
@@ -0,0 +1,43 @@
+
+function pixi_display_DisplayObject_confirmNew(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObject);
+ expect(obj).to.respondTo('setInteractive');
+ expect(obj).to.respondTo('addFilter');
+ expect(obj).to.respondTo('removeFilter');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.property('last', obj);
+ expect(obj).to.have.property('first', obj);
+
+ expect(obj).to.contain.property('position');
+ pixi_core_Point_confirm(obj.position, 0, 0);
+ expect(obj).to.contain.property('scale');
+ pixi_core_Point_confirm(obj.scale, 1, 1);
+ expect(obj).to.contain.property('pivot');
+ pixi_core_Point_confirm(obj.pivot, 0, 0);
+
+ expect(obj).to.have.property('rotation', 0);
+ expect(obj).to.have.property('alpha', 1);
+ expect(obj).to.have.property('visible', true);
+ expect(obj).to.have.property('buttonMode', false);
+ expect(obj).to.have.property('parent', null);
+ expect(obj).to.have.property('worldAlpha', 1);
+
+ expect(obj).to.have.property('hitArea');
+ expect(obj).to.have.property('interactive'); // TODO: Have a better default value
+ expect('mask' in obj).to.be.true; // TODO: Have a better default value
+ expect(obj.mask).to.be.undefined;
+
+ expect(obj).to.have.property('renderable');
+ expect(obj).to.have.property('stage');
+
+ expect(obj).to.have.deep.property('worldTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ expect(obj).to.have.deep.property('localTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.localTransform);
+
+ expect(obj).to.have.deep.property('color.length', 0);
+ expect(obj).to.have.property('dynamic', true);
+}
diff --git a/test/lib/pixi/display/DisplayObjectContainer.js b/test/lib/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..085c59f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,16 @@
+
+function pixi_display_DisplayObjectContainer_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObject_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObjectContainer);
+ expect(obj).to.respondTo('addChild');
+ expect(obj).to.respondTo('addChildAt');
+ expect(obj).to.respondTo('swapChildren');
+ expect(obj).to.respondTo('getChildAt');
+ expect(obj).to.respondTo('removeChild');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('children.length', 0);
+}
diff --git a/test/lib/pixi/display/Sprite.js b/test/lib/pixi/display/Sprite.js
new file mode 100644
index 0000000..cc7a2d6
--- /dev/null
+++ b/test/lib/pixi/display/Sprite.js
@@ -0,0 +1,28 @@
+
+function pixi_display_Sprite_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Sprite);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', true);
+ expect(obj).to.have.property('stage', null);
+
+ expect(obj).to.have.property('anchor');
+ pixi_core_Point_confirm(obj.anchor, 0, 0);
+
+ expect(obj).to.have.property('blendMode', PIXI.blendModes.NORMAL);
+ expect(obj).to.have.property('width', 1); // TODO: is 1 expected
+ expect(obj).to.have.property('height', 1); // TODO: is 1 expected
+
+ // FIXME: Just make this a boolean that is always there
+ expect(!!obj.updateFrame).to.equal(obj.texture.baseTexture.hasLoaded);
+
+ expect(obj).to.have.property('texture');
+ pixi_textures_Texture_confirmNew(obj.texture, done);
+}
diff --git a/test/lib/pixi/extras/Strip.js b/test/lib/pixi/extras/Strip.js
new file mode 100644
index 0000000..8927a8a
--- /dev/null
+++ b/test/lib/pixi/extras/Strip.js
@@ -0,0 +1,12 @@
+
+function pixi_extras_Strip_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Strip);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ // TODO: Test properties
+}
diff --git a/test/lib/pixi/textures/Texture.js b/test/lib/pixi/textures/Texture.js
new file mode 100644
index 0000000..d5867b6
--- /dev/null
+++ b/test/lib/pixi/textures/Texture.js
@@ -0,0 +1,31 @@
+
+function pixi_textures_Texture_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ function confirmFrameDone() {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, obj.baseTexture.width, obj.baseTexture.height);
+
+ expect(obj).to.have.property('width', obj.baseTexture.width);
+ expect(obj).to.have.property('height', obj.baseTexture.height);
+ done();
+ }
+
+ expect(obj).to.be.an.instanceof(PIXI.Texture);
+ pixi_utils_EventTarget_like(obj);
+
+ expect(obj).to.have.property('baseTexture')
+ .and.to.be.an.instanceof(PIXI.BaseTexture);
+
+ expect(obj).to.have.property('scope', obj);
+
+ expect(obj).to.have.property('trim');
+ pixi_core_Point_confirm(obj.trim, 0, 0);
+
+ expect(obj).to.have.property('frame');
+ if (obj.baseTexture.hasLoaded) {
+ confirmFrameDone();
+ } else {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, 1, 1);
+ obj.addEventListener('update', confirmFrameDone);
+ }
+}
diff --git a/test/lib/pixi/utils/EventTarget.js b/test/lib/pixi/utils/EventTarget.js
new file mode 100644
index 0000000..7b1dcfa
--- /dev/null
+++ b/test/lib/pixi/utils/EventTarget.js
@@ -0,0 +1,8 @@
+
+function pixi_utils_EventTarget_like(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.respondTo('addEventListener');
+ expect(obj).to.respondTo('dispatchEvent');
+ expect(obj).to.respondTo('removeEventListener');
+}
diff --git a/test/lib/qunit-1.11.0.css b/test/lib/qunit-1.11.0.css
deleted file mode 100644
index d7fc0c8..0000000
--- a/test/lib/qunit-1.11.0.css
+++ /dev/null
@@ -1,244 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-/** Font Family and Sizes */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
- font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
-}
-
-#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
-#qunit-tests { font-size: smaller; }
-
-
-/** Resets */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter {
- margin: 0;
- padding: 0;
-}
-
-
-/** Header */
-
-#qunit-header {
- padding: 0.5em 0 0.5em 1em;
-
- color: #8699a4;
- background-color: #0d3349;
-
- font-size: 1.5em;
- line-height: 1em;
- font-weight: normal;
-
- border-radius: 5px 5px 0 0;
- -moz-border-radius: 5px 5px 0 0;
- -webkit-border-top-right-radius: 5px;
- -webkit-border-top-left-radius: 5px;
-}
-
-#qunit-header a {
- text-decoration: none;
- color: #c2ccd1;
-}
-
-#qunit-header a:hover,
-#qunit-header a:focus {
- color: #fff;
-}
-
-#qunit-testrunner-toolbar label {
- display: inline-block;
- padding: 0 .5em 0 .1em;
-}
-
-#qunit-banner {
- height: 5px;
-}
-
-#qunit-testrunner-toolbar {
- padding: 0.5em 0 0.5em 2em;
- color: #5E740B;
- background-color: #eee;
- overflow: hidden;
-}
-
-#qunit-userAgent {
- padding: 0.5em 0 0.5em 2.5em;
- background-color: #2b81af;
- color: #fff;
- text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
-}
-
-#qunit-modulefilter-container {
- float: right;
-}
-
-/** Tests: Pass/Fail */
-
-#qunit-tests {
- list-style-position: inside;
-}
-
-#qunit-tests li {
- padding: 0.4em 0.5em 0.4em 2.5em;
- border-bottom: 1px solid #fff;
- list-style-position: inside;
-}
-
-#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running {
- display: none;
-}
-
-#qunit-tests li strong {
- cursor: pointer;
-}
-
-#qunit-tests li a {
- padding: 0.5em;
- color: #c2ccd1;
- text-decoration: none;
-}
-#qunit-tests li a:hover,
-#qunit-tests li a:focus {
- color: #000;
-}
-
-#qunit-tests li .runtime {
- float: right;
- font-size: smaller;
-}
-
-.qunit-assert-list {
- margin-top: 0.5em;
- padding: 0.5em;
-
- background-color: #fff;
-
- border-radius: 5px;
- -moz-border-radius: 5px;
- -webkit-border-radius: 5px;
-}
-
-.qunit-collapsed {
- display: none;
-}
-
-#qunit-tests table {
- border-collapse: collapse;
- margin-top: .2em;
-}
-
-#qunit-tests th {
- text-align: right;
- vertical-align: top;
- padding: 0 .5em 0 0;
-}
-
-#qunit-tests td {
- vertical-align: top;
-}
-
-#qunit-tests pre {
- margin: 0;
- white-space: pre-wrap;
- word-wrap: break-word;
-}
-
-#qunit-tests del {
- background-color: #e0f2be;
- color: #374e0c;
- text-decoration: none;
-}
-
-#qunit-tests ins {
- background-color: #ffcaca;
- color: #500;
- text-decoration: none;
-}
-
-/*** Test Counts */
-
-#qunit-tests b.counts { color: black; }
-#qunit-tests b.passed { color: #5E740B; }
-#qunit-tests b.failed { color: #710909; }
-
-#qunit-tests li li {
- padding: 5px;
- background-color: #fff;
- border-bottom: none;
- list-style-position: inside;
-}
-
-/*** Passing Styles */
-
-#qunit-tests li li.pass {
- color: #3c510c;
- background-color: #fff;
- border-left: 10px solid #C6E746;
-}
-
-#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
-#qunit-tests .pass .test-name { color: #366097; }
-
-#qunit-tests .pass .test-actual,
-#qunit-tests .pass .test-expected { color: #999999; }
-
-#qunit-banner.qunit-pass { background-color: #C6E746; }
-
-/*** Failing Styles */
-
-#qunit-tests li li.fail {
- color: #710909;
- background-color: #fff;
- border-left: 10px solid #EE5757;
- white-space: pre;
-}
-
-#qunit-tests > li:last-child {
- border-radius: 0 0 5px 5px;
- -moz-border-radius: 0 0 5px 5px;
- -webkit-border-bottom-right-radius: 5px;
- -webkit-border-bottom-left-radius: 5px;
-}
-
-#qunit-tests .fail { color: #000000; background-color: #EE5757; }
-#qunit-tests .fail .test-name,
-#qunit-tests .fail .module-name { color: #000000; }
-
-#qunit-tests .fail .test-actual { color: #EE5757; }
-#qunit-tests .fail .test-expected { color: green; }
-
-#qunit-banner.qunit-fail { background-color: #EE5757; }
-
-
-/** Result */
-
-#qunit-testresult {
- padding: 0.5em 0.5em 0.5em 2.5em;
-
- color: #2b81af;
- background-color: #D2E0E6;
-
- border-bottom: 1px solid white;
-}
-#qunit-testresult .module-name {
- font-weight: bold;
-}
-
-/** Fixture */
-
-#qunit-fixture {
- position: absolute;
- top: -10000px;
- left: -10000px;
- width: 1000px;
- height: 1000px;
-}
diff --git a/test/lib/qunit-1.11.0.js b/test/lib/qunit-1.11.0.js
deleted file mode 100644
index 302545f..0000000
--- a/test/lib/qunit-1.11.0.js
+++ /dev/null
@@ -1,2152 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-(function( window ) {
-
-var QUnit,
- assert,
- config,
- onErrorFnPrev,
- testId = 0,
- fileName = (sourceFromStacktrace( 0 ) || "" ).replace(/(:\d+)+\)?/, "").replace(/.+\//, ""),
- toString = Object.prototype.toString,
- hasOwn = Object.prototype.hasOwnProperty,
- // Keep a local reference to Date (GH-283)
- Date = window.Date,
- defined = {
- setTimeout: typeof window.setTimeout !== "undefined",
- sessionStorage: (function() {
- var x = "qunit-test-string";
- try {
- sessionStorage.setItem( x, x );
- sessionStorage.removeItem( x );
- return true;
- } catch( e ) {
- return false;
- }
- }())
- },
- /**
- * Provides a normalized error string, correcting an issue
- * with IE 7 (and prior) where Error.prototype.toString is
- * not properly implemented
- *
- * Based on http://es5.github.com/#x15.11.4.4
- *
- * @param {String|Error} error
- * @return {String} error message
- */
- errorString = function( error ) {
- var name, message,
- errorString = error.toString();
- if ( errorString.substring( 0, 7 ) === "[object" ) {
- name = error.name ? error.name.toString() : "Error";
- message = error.message ? error.message.toString() : "";
- if ( name && message ) {
- return name + ": " + message;
- } else if ( name ) {
- return name;
- } else if ( message ) {
- return message;
- } else {
- return "Error";
- }
- } else {
- return errorString;
- }
- },
- /**
- * Makes a clone of an object using only Array or Object as base,
- * and copies over the own enumerable properties.
- *
- * @param {Object} obj
- * @return {Object} New object with only the own properties (recursively).
- */
- objectValues = function( obj ) {
- // Grunt 0.3.x uses an older version of jshint that still has jshint/jshint#392.
- /*jshint newcap: false */
- var key, val,
- vals = QUnit.is( "array", obj ) ? [] : {};
- for ( key in obj ) {
- if ( hasOwn.call( obj, key ) ) {
- val = obj[key];
- vals[key] = val === Object(val) ? objectValues(val) : val;
- }
- }
- return vals;
- };
-
-function Test( settings ) {
- extend( this, settings );
- this.assertions = [];
- this.testNumber = ++Test.count;
-}
-
-Test.count = 0;
-
-Test.prototype = {
- init: function() {
- var a, b, li,
- tests = id( "qunit-tests" );
-
- if ( tests ) {
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml;
-
- // `a` initialized at top of scope
- a = document.createElement( "a" );
- a.innerHTML = "Rerun";
- a.href = QUnit.url({ testNumber: this.testNumber });
-
- li = document.createElement( "li" );
- li.appendChild( b );
- li.appendChild( a );
- li.className = "running";
- li.id = this.id = "qunit-test-output" + testId++;
-
- tests.appendChild( li );
- }
- },
- setup: function() {
- if ( this.module !== config.previousModule ) {
- if ( config.previousModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.previousModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
- config.previousModule = this.module;
- config.moduleStats = { all: 0, bad: 0 };
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- } else if ( config.autorun ) {
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- }
-
- config.current = this;
-
- this.testEnvironment = extend({
- setup: function() {},
- teardown: function() {}
- }, this.moduleTestEnvironment );
-
- this.started = +new Date();
- runLoggingCallbacks( "testStart", QUnit, {
- name: this.testName,
- module: this.module
- });
-
- // allow utility functions to access the current test environment
- // TODO why??
- QUnit.current_testEnvironment = this.testEnvironment;
-
- if ( !config.pollution ) {
- saveGlobal();
- }
- if ( config.notrycatch ) {
- this.testEnvironment.setup.call( this.testEnvironment );
- return;
- }
- try {
- this.testEnvironment.setup.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Setup failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- },
- run: function() {
- config.current = this;
-
- var running = id( "qunit-testresult" );
-
- if ( running ) {
- running.innerHTML = "Running:
" + this.nameHtml;
- }
-
- if ( this.async ) {
- QUnit.stop();
- }
-
- this.callbackStarted = +new Date();
-
- if ( config.notrycatch ) {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- return;
- }
-
- try {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- } catch( e ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
-
- QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + " " + this.stack + ": " + ( e.message || e ), extractStacktrace( e, 0 ) );
- // else next test will carry the responsibility
- saveGlobal();
-
- // Restart the tests if they're blocking
- if ( config.blocking ) {
- QUnit.start();
- }
- }
- },
- teardown: function() {
- config.current = this;
- if ( config.notrycatch ) {
- if ( typeof this.callbackRuntime === "undefined" ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
- }
- this.testEnvironment.teardown.call( this.testEnvironment );
- return;
- } else {
- try {
- this.testEnvironment.teardown.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Teardown failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- }
- checkPollution();
- },
- finish: function() {
- config.current = this;
- if ( config.requireExpects && this.expected === null ) {
- QUnit.pushFailure( "Expected number of assertions to be defined, but expect() was not called.", this.stack );
- } else if ( this.expected !== null && this.expected !== this.assertions.length ) {
- QUnit.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack );
- } else if ( this.expected === null && !this.assertions.length ) {
- QUnit.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions.", this.stack );
- }
-
- var i, assertion, a, b, time, li, ol,
- test = this,
- good = 0,
- bad = 0,
- tests = id( "qunit-tests" );
-
- this.runtime = +new Date() - this.started;
- config.stats.all += this.assertions.length;
- config.moduleStats.all += this.assertions.length;
-
- if ( tests ) {
- ol = document.createElement( "ol" );
- ol.className = "qunit-assert-list";
-
- for ( i = 0; i < this.assertions.length; i++ ) {
- assertion = this.assertions[i];
-
- li = document.createElement( "li" );
- li.className = assertion.result ? "pass" : "fail";
- li.innerHTML = assertion.message || ( assertion.result ? "okay" : "failed" );
- ol.appendChild( li );
-
- if ( assertion.result ) {
- good++;
- } else {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
-
- // store result when possible
- if ( QUnit.config.reorder && defined.sessionStorage ) {
- if ( bad ) {
- sessionStorage.setItem( "qunit-test-" + this.module + "-" + this.testName, bad );
- } else {
- sessionStorage.removeItem( "qunit-test-" + this.module + "-" + this.testName );
- }
- }
-
- if ( bad === 0 ) {
- addClass( ol, "qunit-collapsed" );
- }
-
- // `b` initialized at top of scope
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml + " (" + bad + ", " + good + ", " + this.assertions.length + ")";
-
- addEvent(b, "click", function() {
- var next = b.parentNode.lastChild,
- collapsed = hasClass( next, "qunit-collapsed" );
- ( collapsed ? removeClass : addClass )( next, "qunit-collapsed" );
- });
-
- addEvent(b, "dblclick", function( e ) {
- var target = e && e.target ? e.target : window.event.srcElement;
- if ( target.nodeName.toLowerCase() === "span" || target.nodeName.toLowerCase() === "b" ) {
- target = target.parentNode;
- }
- if ( window.location && target.nodeName.toLowerCase() === "strong" ) {
- window.location = QUnit.url({ testNumber: test.testNumber });
- }
- });
-
- // `time` initialized at top of scope
- time = document.createElement( "span" );
- time.className = "runtime";
- time.innerHTML = this.runtime + " ms";
-
- // `li` initialized at top of scope
- li = id( this.id );
- li.className = bad ? "fail" : "pass";
- li.removeChild( li.firstChild );
- a = li.firstChild;
- li.appendChild( b );
- li.appendChild( a );
- li.appendChild( time );
- li.appendChild( ol );
-
- } else {
- for ( i = 0; i < this.assertions.length; i++ ) {
- if ( !this.assertions[i].result ) {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
- }
-
- runLoggingCallbacks( "testDone", QUnit, {
- name: this.testName,
- module: this.module,
- failed: bad,
- passed: this.assertions.length - bad,
- total: this.assertions.length,
- duration: this.runtime
- });
-
- QUnit.reset();
-
- config.current = undefined;
- },
-
- queue: function() {
- var bad,
- test = this;
-
- synchronize(function() {
- test.init();
- });
- function run() {
- // each of these can by async
- synchronize(function() {
- test.setup();
- });
- synchronize(function() {
- test.run();
- });
- synchronize(function() {
- test.teardown();
- });
- synchronize(function() {
- test.finish();
- });
- }
-
- // `bad` initialized at top of scope
- // defer when previous test run passed, if storage is available
- bad = QUnit.config.reorder && defined.sessionStorage &&
- +sessionStorage.getItem( "qunit-test-" + this.module + "-" + this.testName );
-
- if ( bad ) {
- run();
- } else {
- synchronize( run, true );
- }
- }
-};
-
-// Root QUnit object.
-// `QUnit` initialized at top of scope
-QUnit = {
-
- // call on start of module test to prepend name to all tests
- module: function( name, testEnvironment ) {
- config.currentModule = name;
- config.currentModuleTestEnvironment = testEnvironment;
- config.modules[name] = true;
- },
-
- asyncTest: function( testName, expected, callback ) {
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- QUnit.test( testName, expected, callback, true );
- },
-
- test: function( testName, expected, callback, async ) {
- var test,
- nameHtml = "" + escapeText( testName ) + "";
-
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- if ( config.currentModule ) {
- nameHtml = "" + escapeText( config.currentModule ) + ": " + nameHtml;
- }
-
- test = new Test({
- nameHtml: nameHtml,
- testName: testName,
- expected: expected,
- async: async,
- callback: callback,
- module: config.currentModule,
- moduleTestEnvironment: config.currentModuleTestEnvironment,
- stack: sourceFromStacktrace( 2 )
- });
-
- if ( !validTest( test ) ) {
- return;
- }
-
- test.queue();
- },
-
- // Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through.
- expect: function( asserts ) {
- if (arguments.length === 1) {
- config.current.expected = asserts;
- } else {
- return config.current.expected;
- }
- },
-
- start: function( count ) {
- // QUnit hasn't been initialized yet.
- // Note: RequireJS (et al) may delay onLoad
- if ( config.semaphore === undefined ) {
- QUnit.begin(function() {
- // This is triggered at the top of QUnit.load, push start() to the event loop, to allow QUnit.load to finish first
- setTimeout(function() {
- QUnit.start( count );
- });
- });
- return;
- }
-
- config.semaphore -= count || 1;
- // don't start until equal number of stop-calls
- if ( config.semaphore > 0 ) {
- return;
- }
- // ignore if start is called more often then stop
- if ( config.semaphore < 0 ) {
- config.semaphore = 0;
- QUnit.pushFailure( "Called start() while already started (QUnit.config.semaphore was 0 already)", null, sourceFromStacktrace(2) );
- return;
- }
- // A slight delay, to avoid any current callbacks
- if ( defined.setTimeout ) {
- window.setTimeout(function() {
- if ( config.semaphore > 0 ) {
- return;
- }
- if ( config.timeout ) {
- clearTimeout( config.timeout );
- }
-
- config.blocking = false;
- process( true );
- }, 13);
- } else {
- config.blocking = false;
- process( true );
- }
- },
-
- stop: function( count ) {
- config.semaphore += count || 1;
- config.blocking = true;
-
- if ( config.testTimeout && defined.setTimeout ) {
- clearTimeout( config.timeout );
- config.timeout = window.setTimeout(function() {
- QUnit.ok( false, "Test timed out" );
- config.semaphore = 1;
- QUnit.start();
- }, config.testTimeout );
- }
- }
-};
-
-// `assert` initialized at top of scope
-// Asssert helpers
-// All of these must either call QUnit.push() or manually do:
-// - runLoggingCallbacks( "log", .. );
-// - config.current.assertions.push({ .. });
-// We attach it to the QUnit object *after* we expose the public API,
-// otherwise `assert` will become a global variable in browsers (#341).
-assert = {
- /**
- * Asserts rough true-ish result.
- * @name ok
- * @function
- * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" );
- */
- ok: function( result, msg ) {
- if ( !config.current ) {
- throw new Error( "ok() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
- result = !!result;
-
- var source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: msg
- };
-
- msg = escapeText( msg || (result ? "okay" : "failed" ) );
- msg = "" + msg + "";
-
- if ( !result ) {
- source = sourceFromStacktrace( 2 );
- if ( source ) {
- details.source = source;
- msg += "Source: | " + escapeText( source ) + " |
---|
";
- }
- }
- runLoggingCallbacks( "log", QUnit, details );
- config.current.assertions.push({
- result: result,
- message: msg
- });
- },
-
- /**
- * Assert that the first two arguments are equal, with an optional message.
- * Prints out both actual and expected values.
- * @name equal
- * @function
- * @example equal( format( "Received {0} bytes.", 2), "Received 2 bytes.", "format() replaces {0} with next argument" );
- */
- equal: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected == actual, actual, expected, message );
- },
-
- /**
- * @name notEqual
- * @function
- */
- notEqual: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected != actual, actual, expected, message );
- },
-
- /**
- * @name propEqual
- * @function
- */
- propEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notPropEqual
- * @function
- */
- notPropEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name deepEqual
- * @function
- */
- deepEqual: function( actual, expected, message ) {
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notDeepEqual
- * @function
- */
- notDeepEqual: function( actual, expected, message ) {
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name strictEqual
- * @function
- */
- strictEqual: function( actual, expected, message ) {
- QUnit.push( expected === actual, actual, expected, message );
- },
-
- /**
- * @name notStrictEqual
- * @function
- */
- notStrictEqual: function( actual, expected, message ) {
- QUnit.push( expected !== actual, actual, expected, message );
- },
-
- "throws": function( block, expected, message ) {
- var actual,
- expectedOutput = expected,
- ok = false;
-
- // 'expected' is optional
- if ( typeof expected === "string" ) {
- message = expected;
- expected = null;
- }
-
- config.current.ignoreGlobalErrors = true;
- try {
- block.call( config.current.testEnvironment );
- } catch (e) {
- actual = e;
- }
- config.current.ignoreGlobalErrors = false;
-
- if ( actual ) {
- // we don't want to validate thrown error
- if ( !expected ) {
- ok = true;
- expectedOutput = null;
- // expected is a regexp
- } else if ( QUnit.objectType( expected ) === "regexp" ) {
- ok = expected.test( errorString( actual ) );
- // expected is a constructor
- } else if ( actual instanceof expected ) {
- ok = true;
- // expected is a validation function which returns true is validation passed
- } else if ( expected.call( {}, actual ) === true ) {
- expectedOutput = null;
- ok = true;
- }
-
- QUnit.push( ok, actual, expectedOutput, message );
- } else {
- QUnit.pushFailure( message, null, 'No exception was thrown.' );
- }
- }
-};
-
-/**
- * @deprecate since 1.8.0
- * Kept assertion helpers in root for backwards compatibility.
- */
-extend( QUnit, assert );
-
-/**
- * @deprecated since 1.9.0
- * Kept root "raises()" for backwards compatibility.
- * (Note that we don't introduce assert.raises).
- */
-QUnit.raises = assert[ "throws" ];
-
-/**
- * @deprecated since 1.0.0, replaced with error pushes since 1.3.0
- * Kept to avoid TypeErrors for undefined methods.
- */
-QUnit.equals = function() {
- QUnit.push( false, false, false, "QUnit.equals has been deprecated since 2009 (e88049a0), use QUnit.equal instead" );
-};
-QUnit.same = function() {
- QUnit.push( false, false, false, "QUnit.same has been deprecated since 2009 (e88049a0), use QUnit.deepEqual instead" );
-};
-
-// We want access to the constructor's prototype
-(function() {
- function F() {}
- F.prototype = QUnit;
- QUnit = new F();
- // Make F QUnit's constructor so that we can add to the prototype later
- QUnit.constructor = F;
-}());
-
-/**
- * Config object: Maintain internal state
- * Later exposed as QUnit.config
- * `config` initialized at top of scope
- */
-config = {
- // The queue of tests to run
- queue: [],
-
- // block until document ready
- blocking: true,
-
- // when enabled, show only failing tests
- // gets persisted through sessionStorage and can be changed in UI via checkbox
- hidepassed: false,
-
- // by default, run previously failed tests first
- // very useful in combination with "Hide passed tests" checked
- reorder: true,
-
- // by default, modify document.title when suite is done
- altertitle: true,
-
- // when enabled, all tests must call expect()
- requireExpects: false,
-
- // add checkboxes that are persisted in the query-string
- // when enabled, the id is set to `true` as a `QUnit.config` property
- urlConfig: [
- {
- id: "noglobals",
- label: "Check for Globals",
- tooltip: "Enabling this will test if any test introduces new properties on the `window` object. Stored as query-strings."
- },
- {
- id: "notrycatch",
- label: "No try-catch",
- tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging exceptions in IE reasonable. Stored as query-strings."
- }
- ],
-
- // Set of all modules.
- modules: {},
-
- // logging callback queues
- begin: [],
- done: [],
- log: [],
- testStart: [],
- testDone: [],
- moduleStart: [],
- moduleDone: []
-};
-
-// Export global variables, unless an 'exports' object exists,
-// in that case we assume we're in CommonJS (dealt with on the bottom of the script)
-if ( typeof exports === "undefined" ) {
- extend( window, QUnit );
-
- // Expose QUnit object
- window.QUnit = QUnit;
-}
-
-// Initialize more QUnit.config and QUnit.urlParams
-(function() {
- var i,
- location = window.location || { search: "", protocol: "file:" },
- params = location.search.slice( 1 ).split( "&" ),
- length = params.length,
- urlParams = {},
- current;
-
- if ( params[ 0 ] ) {
- for ( i = 0; i < length; i++ ) {
- current = params[ i ].split( "=" );
- current[ 0 ] = decodeURIComponent( current[ 0 ] );
- // allow just a key to turn on a flag, e.g., test.html?noglobals
- current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true;
- urlParams[ current[ 0 ] ] = current[ 1 ];
- }
- }
-
- QUnit.urlParams = urlParams;
-
- // String search anywhere in moduleName+testName
- config.filter = urlParams.filter;
-
- // Exact match of the module name
- config.module = urlParams.module;
-
- config.testNumber = parseInt( urlParams.testNumber, 10 ) || null;
-
- // Figure out if we're running the tests from a server or not
- QUnit.isLocal = location.protocol === "file:";
-}());
-
-// Extend QUnit object,
-// these after set here because they should not be exposed as global functions
-extend( QUnit, {
- assert: assert,
-
- config: config,
-
- // Initialize the configuration options
- init: function() {
- extend( config, {
- stats: { all: 0, bad: 0 },
- moduleStats: { all: 0, bad: 0 },
- started: +new Date(),
- updateRate: 1000,
- blocking: false,
- autostart: true,
- autorun: false,
- filter: "",
- queue: [],
- semaphore: 1
- });
-
- var tests, banner, result,
- qunit = id( "qunit" );
-
- if ( qunit ) {
- qunit.innerHTML =
- "" +
- "" +
- "" +
- "" +
- "
";
- }
-
- tests = id( "qunit-tests" );
- banner = id( "qunit-banner" );
- result = id( "qunit-testresult" );
-
- if ( tests ) {
- tests.innerHTML = "";
- }
-
- if ( banner ) {
- banner.className = "";
- }
-
- if ( result ) {
- result.parentNode.removeChild( result );
- }
-
- if ( tests ) {
- result = document.createElement( "p" );
- result.id = "qunit-testresult";
- result.className = "result";
- tests.parentNode.insertBefore( result, tests );
- result.innerHTML = "Running...
";
- }
- },
-
- // Resets the test setup. Useful for tests that modify the DOM.
- reset: function() {
- var fixture = id( "qunit-fixture" );
- if ( fixture ) {
- fixture.innerHTML = config.fixture;
- }
- },
-
- // Trigger an event on an element.
- // @example triggerEvent( document.body, "click" );
- triggerEvent: function( elem, type, event ) {
- if ( document.createEvent ) {
- event = document.createEvent( "MouseEvents" );
- event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView,
- 0, 0, 0, 0, 0, false, false, false, false, 0, null);
-
- elem.dispatchEvent( event );
- } else if ( elem.fireEvent ) {
- elem.fireEvent( "on" + type );
- }
- },
-
- // Safe object type checking
- is: function( type, obj ) {
- return QUnit.objectType( obj ) === type;
- },
-
- objectType: function( obj ) {
- if ( typeof obj === "undefined" ) {
- return "undefined";
- // consider: typeof null === object
- }
- if ( obj === null ) {
- return "null";
- }
-
- var match = toString.call( obj ).match(/^\[object\s(.*)\]$/),
- type = match && match[1] || "";
-
- switch ( type ) {
- case "Number":
- if ( isNaN(obj) ) {
- return "nan";
- }
- return "number";
- case "String":
- case "Boolean":
- case "Array":
- case "Date":
- case "RegExp":
- case "Function":
- return type.toLowerCase();
- }
- if ( typeof obj === "object" ) {
- return "object";
- }
- return undefined;
- },
-
- push: function( result, actual, expected, message ) {
- if ( !config.current ) {
- throw new Error( "assertion outside test context, was " + sourceFromStacktrace() );
- }
-
- var output, source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: message,
- actual: actual,
- expected: expected
- };
-
- message = escapeText( message ) || ( result ? "okay" : "failed" );
- message = "" + message + "";
- output = message;
-
- if ( !result ) {
- expected = escapeText( QUnit.jsDump.parse(expected) );
- actual = escapeText( QUnit.jsDump.parse(actual) );
- output += "Expected: | " + expected + " |
";
-
- if ( actual !== expected ) {
- output += "Result: | " + actual + " |
";
- output += "Diff: | " + QUnit.diff( expected, actual ) + " |
";
- }
-
- source = sourceFromStacktrace();
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
- }
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: !!result,
- message: output
- });
- },
-
- pushFailure: function( message, source, actual ) {
- if ( !config.current ) {
- throw new Error( "pushFailure() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
-
- var output,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: false,
- message: message
- };
-
- message = escapeText( message ) || "error";
- message = "" + message + "";
- output = message;
-
- output += "";
-
- if ( actual ) {
- output += "Result: | " + escapeText( actual ) + " |
";
- }
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: false,
- message: output
- });
- },
-
- url: function( params ) {
- params = extend( extend( {}, QUnit.urlParams ), params );
- var key,
- querystring = "?";
-
- for ( key in params ) {
- if ( !hasOwn.call( params, key ) ) {
- continue;
- }
- querystring += encodeURIComponent( key ) + "=" +
- encodeURIComponent( params[ key ] ) + "&";
- }
- return window.location.protocol + "//" + window.location.host +
- window.location.pathname + querystring.slice( 0, -1 );
- },
-
- extend: extend,
- id: id,
- addEvent: addEvent
- // load, equiv, jsDump, diff: Attached later
-});
-
-/**
- * @deprecated: Created for backwards compatibility with test runner that set the hook function
- * into QUnit.{hook}, instead of invoking it and passing the hook function.
- * QUnit.constructor is set to the empty F() above so that we can add to it's prototype here.
- * Doing this allows us to tell if the following methods have been overwritten on the actual
- * QUnit object.
- */
-extend( QUnit.constructor.prototype, {
-
- // Logging callbacks; all receive a single argument with the listed properties
- // run test/logs.html for any related changes
- begin: registerLoggingCallback( "begin" ),
-
- // done: { failed, passed, total, runtime }
- done: registerLoggingCallback( "done" ),
-
- // log: { result, actual, expected, message }
- log: registerLoggingCallback( "log" ),
-
- // testStart: { name }
- testStart: registerLoggingCallback( "testStart" ),
-
- // testDone: { name, failed, passed, total, duration }
- testDone: registerLoggingCallback( "testDone" ),
-
- // moduleStart: { name }
- moduleStart: registerLoggingCallback( "moduleStart" ),
-
- // moduleDone: { name, failed, passed, total }
- moduleDone: registerLoggingCallback( "moduleDone" )
-});
-
-if ( typeof document === "undefined" || document.readyState === "complete" ) {
- config.autorun = true;
-}
-
-QUnit.load = function() {
- runLoggingCallbacks( "begin", QUnit, {} );
-
- // Initialize the config, saving the execution queue
- var banner, filter, i, label, len, main, ol, toolbar, userAgent, val,
- urlConfigCheckboxesContainer, urlConfigCheckboxes, moduleFilter,
- numModules = 0,
- moduleFilterHtml = "",
- urlConfigHtml = "",
- oldconfig = extend( {}, config );
-
- QUnit.init();
- extend(config, oldconfig);
-
- config.blocking = false;
-
- len = config.urlConfig.length;
-
- for ( i = 0; i < len; i++ ) {
- val = config.urlConfig[i];
- if ( typeof val === "string" ) {
- val = {
- id: val,
- label: val,
- tooltip: "[no tooltip available]"
- };
- }
- config[ val.id ] = QUnit.urlParams[ val.id ];
- urlConfigHtml += "";
- }
-
- moduleFilterHtml += "";
-
- // `userAgent` initialized at top of scope
- userAgent = id( "qunit-userAgent" );
- if ( userAgent ) {
- userAgent.innerHTML = navigator.userAgent;
- }
-
- // `banner` initialized at top of scope
- banner = id( "qunit-header" );
- if ( banner ) {
- banner.innerHTML = "" + banner.innerHTML + " ";
- }
-
- // `toolbar` initialized at top of scope
- toolbar = id( "qunit-testrunner-toolbar" );
- if ( toolbar ) {
- // `filter` initialized at top of scope
- filter = document.createElement( "input" );
- filter.type = "checkbox";
- filter.id = "qunit-filter-pass";
-
- addEvent( filter, "click", function() {
- var tmp,
- ol = document.getElementById( "qunit-tests" );
-
- if ( filter.checked ) {
- ol.className = ol.className + " hidepass";
- } else {
- tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " ";
- ol.className = tmp.replace( / hidepass /, " " );
- }
- if ( defined.sessionStorage ) {
- if (filter.checked) {
- sessionStorage.setItem( "qunit-filter-passed-tests", "true" );
- } else {
- sessionStorage.removeItem( "qunit-filter-passed-tests" );
- }
- }
- });
-
- if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem( "qunit-filter-passed-tests" ) ) {
- filter.checked = true;
- // `ol` initialized at top of scope
- ol = document.getElementById( "qunit-tests" );
- ol.className = ol.className + " hidepass";
- }
- toolbar.appendChild( filter );
-
- // `label` initialized at top of scope
- label = document.createElement( "label" );
- label.setAttribute( "for", "qunit-filter-pass" );
- label.setAttribute( "title", "Only show tests and assertons that fail. Stored in sessionStorage." );
- label.innerHTML = "Hide passed tests";
- toolbar.appendChild( label );
-
- urlConfigCheckboxesContainer = document.createElement("span");
- urlConfigCheckboxesContainer.innerHTML = urlConfigHtml;
- urlConfigCheckboxes = urlConfigCheckboxesContainer.getElementsByTagName("input");
- // For oldIE support:
- // * Add handlers to the individual elements instead of the container
- // * Use "click" instead of "change"
- // * Fallback from event.target to event.srcElement
- addEvents( urlConfigCheckboxes, "click", function( event ) {
- var params = {},
- target = event.target || event.srcElement;
- params[ target.name ] = target.checked ? true : undefined;
- window.location = QUnit.url( params );
- });
- toolbar.appendChild( urlConfigCheckboxesContainer );
-
- if (numModules > 1) {
- moduleFilter = document.createElement( 'span' );
- moduleFilter.setAttribute( 'id', 'qunit-modulefilter-container' );
- moduleFilter.innerHTML = moduleFilterHtml;
- addEvent( moduleFilter.lastChild, "change", function() {
- var selectBox = moduleFilter.getElementsByTagName("select")[0],
- selectedModule = decodeURIComponent(selectBox.options[selectBox.selectedIndex].value);
-
- window.location = QUnit.url( { module: ( selectedModule === "" ) ? undefined : selectedModule } );
- });
- toolbar.appendChild(moduleFilter);
- }
- }
-
- // `main` initialized at top of scope
- main = id( "qunit-fixture" );
- if ( main ) {
- config.fixture = main.innerHTML;
- }
-
- if ( config.autostart ) {
- QUnit.start();
- }
-};
-
-addEvent( window, "load", QUnit.load );
-
-// `onErrorFnPrev` initialized at top of scope
-// Preserve other handlers
-onErrorFnPrev = window.onerror;
-
-// Cover uncaught exceptions
-// Returning true will surpress the default browser handler,
-// returning false will let it run.
-window.onerror = function ( error, filePath, linerNr ) {
- var ret = false;
- if ( onErrorFnPrev ) {
- ret = onErrorFnPrev( error, filePath, linerNr );
- }
-
- // Treat return value as window.onerror itself does,
- // Only do our handling if not surpressed.
- if ( ret !== true ) {
- if ( QUnit.config.current ) {
- if ( QUnit.config.current.ignoreGlobalErrors ) {
- return true;
- }
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- } else {
- QUnit.test( "global failure", extend( function() {
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- }, { validTest: validTest } ) );
- }
- return false;
- }
-
- return ret;
-};
-
-function done() {
- config.autorun = true;
-
- // Log the last module results
- if ( config.currentModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.currentModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
-
- var i, key,
- banner = id( "qunit-banner" ),
- tests = id( "qunit-tests" ),
- runtime = +new Date() - config.started,
- passed = config.stats.all - config.stats.bad,
- html = [
- "Tests completed in ",
- runtime,
- " milliseconds.
",
- "",
- passed,
- " assertions of ",
- config.stats.all,
- " passed, ",
- config.stats.bad,
- " failed."
- ].join( "" );
-
- if ( banner ) {
- banner.className = ( config.stats.bad ? "qunit-fail" : "qunit-pass" );
- }
-
- if ( tests ) {
- id( "qunit-testresult" ).innerHTML = html;
- }
-
- if ( config.altertitle && typeof document !== "undefined" && document.title ) {
- // show ✖ for good, ✔ for bad suite result in title
- // use escape sequences in case file gets loaded with non-utf-8-charset
- document.title = [
- ( config.stats.bad ? "\u2716" : "\u2714" ),
- document.title.replace( /^[\u2714\u2716] /i, "" )
- ].join( " " );
- }
-
- // clear own sessionStorage items if all tests passed
- if ( config.reorder && defined.sessionStorage && config.stats.bad === 0 ) {
- // `key` & `i` initialized at top of scope
- for ( i = 0; i < sessionStorage.length; i++ ) {
- key = sessionStorage.key( i++ );
- if ( key.indexOf( "qunit-test-" ) === 0 ) {
- sessionStorage.removeItem( key );
- }
- }
- }
-
- // scroll back to top to show results
- if ( window.scrollTo ) {
- window.scrollTo(0, 0);
- }
-
- runLoggingCallbacks( "done", QUnit, {
- failed: config.stats.bad,
- passed: passed,
- total: config.stats.all,
- runtime: runtime
- });
-}
-
-/** @return Boolean: true if this test should be ran */
-function validTest( test ) {
- var include,
- filter = config.filter && config.filter.toLowerCase(),
- module = config.module && config.module.toLowerCase(),
- fullName = (test.module + ": " + test.testName).toLowerCase();
-
- // Internally-generated tests are always valid
- if ( test.callback && test.callback.validTest === validTest ) {
- delete test.callback.validTest;
- return true;
- }
-
- if ( config.testNumber ) {
- return test.testNumber === config.testNumber;
- }
-
- if ( module && ( !test.module || test.module.toLowerCase() !== module ) ) {
- return false;
- }
-
- if ( !filter ) {
- return true;
- }
-
- include = filter.charAt( 0 ) !== "!";
- if ( !include ) {
- filter = filter.slice( 1 );
- }
-
- // If the filter matches, we need to honour include
- if ( fullName.indexOf( filter ) !== -1 ) {
- return include;
- }
-
- // Otherwise, do the opposite
- return !include;
-}
-
-// so far supports only Firefox, Chrome and Opera (buggy), Safari (for real exceptions)
-// Later Safari and IE10 are supposed to support error.stack as well
-// See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack
-function extractStacktrace( e, offset ) {
- offset = offset === undefined ? 3 : offset;
-
- var stack, include, i;
-
- if ( e.stacktrace ) {
- // Opera
- return e.stacktrace.split( "\n" )[ offset + 3 ];
- } else if ( e.stack ) {
- // Firefox, Chrome
- stack = e.stack.split( "\n" );
- if (/^error$/i.test( stack[0] ) ) {
- stack.shift();
- }
- if ( fileName ) {
- include = [];
- for ( i = offset; i < stack.length; i++ ) {
- if ( stack[ i ].indexOf( fileName ) !== -1 ) {
- break;
- }
- include.push( stack[ i ] );
- }
- if ( include.length ) {
- return include.join( "\n" );
- }
- }
- return stack[ offset ];
- } else if ( e.sourceURL ) {
- // Safari, PhantomJS
- // hopefully one day Safari provides actual stacktraces
- // exclude useless self-reference for generated Error objects
- if ( /qunit.js$/.test( e.sourceURL ) ) {
- return;
- }
- // for actual exceptions, this is useful
- return e.sourceURL + ":" + e.line;
- }
-}
-function sourceFromStacktrace( offset ) {
- try {
- throw new Error();
- } catch ( e ) {
- return extractStacktrace( e, offset );
- }
-}
-
-/**
- * Escape text for attribute or text content.
- */
-function escapeText( s ) {
- if ( !s ) {
- return "";
- }
- s = s + "";
- // Both single quotes and double quotes (for attributes)
- return s.replace( /['"<>&]/g, function( s ) {
- switch( s ) {
- case '\'':
- return ''';
- case '"':
- return '"';
- case '<':
- return '<';
- case '>':
- return '>';
- case '&':
- return '&';
- }
- });
-}
-
-function synchronize( callback, last ) {
- config.queue.push( callback );
-
- if ( config.autorun && !config.blocking ) {
- process( last );
- }
-}
-
-function process( last ) {
- function next() {
- process( last );
- }
- var start = new Date().getTime();
- config.depth = config.depth ? config.depth + 1 : 1;
-
- while ( config.queue.length && !config.blocking ) {
- if ( !defined.setTimeout || config.updateRate <= 0 || ( ( new Date().getTime() - start ) < config.updateRate ) ) {
- config.queue.shift()();
- } else {
- window.setTimeout( next, 13 );
- break;
- }
- }
- config.depth--;
- if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) {
- done();
- }
-}
-
-function saveGlobal() {
- config.pollution = [];
-
- if ( config.noglobals ) {
- for ( var key in window ) {
- // in Opera sometimes DOM element ids show up here, ignore them
- if ( !hasOwn.call( window, key ) || /^qunit-test-output/.test( key ) ) {
- continue;
- }
- config.pollution.push( key );
- }
- }
-}
-
-function checkPollution() {
- var newGlobals,
- deletedGlobals,
- old = config.pollution;
-
- saveGlobal();
-
- newGlobals = diff( config.pollution, old );
- if ( newGlobals.length > 0 ) {
- QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join(", ") );
- }
-
- deletedGlobals = diff( old, config.pollution );
- if ( deletedGlobals.length > 0 ) {
- QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join(", ") );
- }
-}
-
-// returns a new Array with the elements that are in a but not in b
-function diff( a, b ) {
- var i, j,
- result = a.slice();
-
- for ( i = 0; i < result.length; i++ ) {
- for ( j = 0; j < b.length; j++ ) {
- if ( result[i] === b[j] ) {
- result.splice( i, 1 );
- i--;
- break;
- }
- }
- }
- return result;
-}
-
-function extend( a, b ) {
- for ( var prop in b ) {
- if ( b[ prop ] === undefined ) {
- delete a[ prop ];
-
- // Avoid "Member not found" error in IE8 caused by setting window.constructor
- } else if ( prop !== "constructor" || a !== window ) {
- a[ prop ] = b[ prop ];
- }
- }
-
- return a;
-}
-
-/**
- * @param {HTMLElement} elem
- * @param {string} type
- * @param {Function} fn
- */
-function addEvent( elem, type, fn ) {
- // Standards-based browsers
- if ( elem.addEventListener ) {
- elem.addEventListener( type, fn, false );
- // IE
- } else {
- elem.attachEvent( "on" + type, fn );
- }
-}
-
-/**
- * @param {Array|NodeList} elems
- * @param {string} type
- * @param {Function} fn
- */
-function addEvents( elems, type, fn ) {
- var i = elems.length;
- while ( i-- ) {
- addEvent( elems[i], type, fn );
- }
-}
-
-function hasClass( elem, name ) {
- return (" " + elem.className + " ").indexOf(" " + name + " ") > -1;
-}
-
-function addClass( elem, name ) {
- if ( !hasClass( elem, name ) ) {
- elem.className += (elem.className ? " " : "") + name;
- }
-}
-
-function removeClass( elem, name ) {
- var set = " " + elem.className + " ";
- // Class name may appear multiple times
- while ( set.indexOf(" " + name + " ") > -1 ) {
- set = set.replace(" " + name + " " , " ");
- }
- // If possible, trim it for prettiness, but not neccecarily
- elem.className = window.jQuery ? jQuery.trim( set ) : ( set.trim ? set.trim() : set );
-}
-
-function id( name ) {
- return !!( typeof document !== "undefined" && document && document.getElementById ) &&
- document.getElementById( name );
-}
-
-function registerLoggingCallback( key ) {
- return function( callback ) {
- config[key].push( callback );
- };
-}
-
-// Supports deprecated method of completely overwriting logging callbacks
-function runLoggingCallbacks( key, scope, args ) {
- var i, callbacks;
- if ( QUnit.hasOwnProperty( key ) ) {
- QUnit[ key ].call(scope, args );
- } else {
- callbacks = config[ key ];
- for ( i = 0; i < callbacks.length; i++ ) {
- callbacks[ i ].call( scope, args );
- }
- }
-}
-
-// Test for equality any JavaScript type.
-// Author: Philippe Rathé
-QUnit.equiv = (function() {
-
- // Call the o related callback with the given arguments.
- function bindCallbacks( o, callbacks, args ) {
- var prop = QUnit.objectType( o );
- if ( prop ) {
- if ( QUnit.objectType( callbacks[ prop ] ) === "function" ) {
- return callbacks[ prop ].apply( callbacks, args );
- } else {
- return callbacks[ prop ]; // or undefined
- }
- }
- }
-
- // the real equiv function
- var innerEquiv,
- // stack to decide between skip/abort functions
- callers = [],
- // stack to avoiding loops from circular referencing
- parents = [],
-
- getProto = Object.getPrototypeOf || function ( obj ) {
- return obj.__proto__;
- },
- callbacks = (function () {
-
- // for string, boolean, number and null
- function useStrictEquality( b, a ) {
- /*jshint eqeqeq:false */
- if ( b instanceof a.constructor || a instanceof b.constructor ) {
- // to catch short annotaion VS 'new' annotation of a
- // declaration
- // e.g. var i = 1;
- // var j = new Number(1);
- return a == b;
- } else {
- return a === b;
- }
- }
-
- return {
- "string": useStrictEquality,
- "boolean": useStrictEquality,
- "number": useStrictEquality,
- "null": useStrictEquality,
- "undefined": useStrictEquality,
-
- "nan": function( b ) {
- return isNaN( b );
- },
-
- "date": function( b, a ) {
- return QUnit.objectType( b ) === "date" && a.valueOf() === b.valueOf();
- },
-
- "regexp": function( b, a ) {
- return QUnit.objectType( b ) === "regexp" &&
- // the regex itself
- a.source === b.source &&
- // and its modifers
- a.global === b.global &&
- // (gmi) ...
- a.ignoreCase === b.ignoreCase &&
- a.multiline === b.multiline &&
- a.sticky === b.sticky;
- },
-
- // - skip when the property is a method of an instance (OOP)
- // - abort otherwise,
- // initial === would have catch identical references anyway
- "function": function() {
- var caller = callers[callers.length - 1];
- return caller !== Object && typeof caller !== "undefined";
- },
-
- "array": function( b, a ) {
- var i, j, len, loop;
-
- // b could be an object literal here
- if ( QUnit.objectType( b ) !== "array" ) {
- return false;
- }
-
- len = a.length;
- if ( len !== b.length ) {
- // safe and faster
- return false;
- }
-
- // track reference to avoid circular references
- parents.push( a );
- for ( i = 0; i < len; i++ ) {
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- loop = true;// dont rewalk array
- }
- }
- if ( !loop && !innerEquiv(a[i], b[i]) ) {
- parents.pop();
- return false;
- }
- }
- parents.pop();
- return true;
- },
-
- "object": function( b, a ) {
- var i, j, loop,
- // Default to true
- eq = true,
- aProperties = [],
- bProperties = [];
-
- // comparing constructors is more strict than using
- // instanceof
- if ( a.constructor !== b.constructor ) {
- // Allow objects with no prototype to be equivalent to
- // objects with Object as their constructor.
- if ( !(( getProto(a) === null && getProto(b) === Object.prototype ) ||
- ( getProto(b) === null && getProto(a) === Object.prototype ) ) ) {
- return false;
- }
- }
-
- // stack constructor before traversing properties
- callers.push( a.constructor );
- // track reference to avoid circular references
- parents.push( a );
-
- for ( i in a ) { // be strict: don't ensures hasOwnProperty
- // and go deep
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- // don't go down the same path twice
- loop = true;
- }
- }
- aProperties.push(i); // collect a's properties
-
- if (!loop && !innerEquiv( a[i], b[i] ) ) {
- eq = false;
- break;
- }
- }
-
- callers.pop(); // unstack, we are done
- parents.pop();
-
- for ( i in b ) {
- bProperties.push( i ); // collect b's properties
- }
-
- // Ensures identical properties name
- return eq && innerEquiv( aProperties.sort(), bProperties.sort() );
- }
- };
- }());
-
- innerEquiv = function() { // can take multiple arguments
- var args = [].slice.apply( arguments );
- if ( args.length < 2 ) {
- return true; // end transition
- }
-
- return (function( a, b ) {
- if ( a === b ) {
- return true; // catch the most you can
- } else if ( a === null || b === null || typeof a === "undefined" ||
- typeof b === "undefined" ||
- QUnit.objectType(a) !== QUnit.objectType(b) ) {
- return false; // don't lose time with error prone cases
- } else {
- return bindCallbacks(a, callbacks, [ b, a ]);
- }
-
- // apply transition with (1..n) arguments
- }( args[0], args[1] ) && arguments.callee.apply( this, args.splice(1, args.length - 1 )) );
- };
-
- return innerEquiv;
-}());
-
-/**
- * jsDump Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com |
- * http://flesler.blogspot.com Licensed under BSD
- * (http://www.opensource.org/licenses/bsd-license.php) Date: 5/15/2008
- *
- * @projectDescription Advanced and extensible data dumping for Javascript.
- * @version 1.0.0
- * @author Ariel Flesler
- * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html}
- */
-QUnit.jsDump = (function() {
- function quote( str ) {
- return '"' + str.toString().replace( /"/g, '\\"' ) + '"';
- }
- function literal( o ) {
- return o + "";
- }
- function join( pre, arr, post ) {
- var s = jsDump.separator(),
- base = jsDump.indent(),
- inner = jsDump.indent(1);
- if ( arr.join ) {
- arr = arr.join( "," + s + inner );
- }
- if ( !arr ) {
- return pre + post;
- }
- return [ pre, inner + arr, base + post ].join(s);
- }
- function array( arr, stack ) {
- var i = arr.length, ret = new Array(i);
- this.up();
- while ( i-- ) {
- ret[i] = this.parse( arr[i] , undefined , stack);
- }
- this.down();
- return join( "[", ret, "]" );
- }
-
- var reName = /^function (\w+)/,
- jsDump = {
- // type is used mostly internally, you can fix a (custom)type in advance
- parse: function( obj, type, stack ) {
- stack = stack || [ ];
- var inStack, res,
- parser = this.parsers[ type || this.typeOf(obj) ];
-
- type = typeof parser;
- inStack = inArray( obj, stack );
-
- if ( inStack !== -1 ) {
- return "recursion(" + (inStack - stack.length) + ")";
- }
- if ( type === "function" ) {
- stack.push( obj );
- res = parser.call( this, obj, stack );
- stack.pop();
- return res;
- }
- return ( type === "string" ) ? parser : this.parsers.error;
- },
- typeOf: function( obj ) {
- var type;
- if ( obj === null ) {
- type = "null";
- } else if ( typeof obj === "undefined" ) {
- type = "undefined";
- } else if ( QUnit.is( "regexp", obj) ) {
- type = "regexp";
- } else if ( QUnit.is( "date", obj) ) {
- type = "date";
- } else if ( QUnit.is( "function", obj) ) {
- type = "function";
- } else if ( typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined" ) {
- type = "window";
- } else if ( obj.nodeType === 9 ) {
- type = "document";
- } else if ( obj.nodeType ) {
- type = "node";
- } else if (
- // native arrays
- toString.call( obj ) === "[object Array]" ||
- // NodeList objects
- ( typeof obj.length === "number" && typeof obj.item !== "undefined" && ( obj.length ? obj.item(0) === obj[0] : ( obj.item( 0 ) === null && typeof obj[0] === "undefined" ) ) )
- ) {
- type = "array";
- } else if ( obj.constructor === Error.prototype.constructor ) {
- type = "error";
- } else {
- type = typeof obj;
- }
- return type;
- },
- separator: function() {
- return this.multiline ? this.HTML ? "
" : "\n" : this.HTML ? " " : " ";
- },
- // extra can be a number, shortcut for increasing-calling-decreasing
- indent: function( extra ) {
- if ( !this.multiline ) {
- return "";
- }
- var chr = this.indentChar;
- if ( this.HTML ) {
- chr = chr.replace( /\t/g, " " ).replace( / /g, " " );
- }
- return new Array( this._depth_ + (extra||0) ).join(chr);
- },
- up: function( a ) {
- this._depth_ += a || 1;
- },
- down: function( a ) {
- this._depth_ -= a || 1;
- },
- setParser: function( name, parser ) {
- this.parsers[name] = parser;
- },
- // The next 3 are exposed so you can use them
- quote: quote,
- literal: literal,
- join: join,
- //
- _depth_: 1,
- // This is the list of parsers, to modify them, use jsDump.setParser
- parsers: {
- window: "[Window]",
- document: "[Document]",
- error: function(error) {
- return "Error(\"" + error.message + "\")";
- },
- unknown: "[Unknown]",
- "null": "null",
- "undefined": "undefined",
- "function": function( fn ) {
- var ret = "function",
- // functions never have name in IE
- name = "name" in fn ? fn.name : (reName.exec(fn) || [])[1];
-
- if ( name ) {
- ret += " " + name;
- }
- ret += "( ";
-
- ret = [ ret, QUnit.jsDump.parse( fn, "functionArgs" ), "){" ].join( "" );
- return join( ret, QUnit.jsDump.parse(fn,"functionCode" ), "}" );
- },
- array: array,
- nodelist: array,
- "arguments": array,
- object: function( map, stack ) {
- var ret = [ ], keys, key, val, i;
- QUnit.jsDump.up();
- keys = [];
- for ( key in map ) {
- keys.push( key );
- }
- keys.sort();
- for ( i = 0; i < keys.length; i++ ) {
- key = keys[ i ];
- val = map[ key ];
- ret.push( QUnit.jsDump.parse( key, "key" ) + ": " + QUnit.jsDump.parse( val, undefined, stack ) );
- }
- QUnit.jsDump.down();
- return join( "{", ret, "}" );
- },
- node: function( node ) {
- var len, i, val,
- open = QUnit.jsDump.HTML ? "<" : "<",
- close = QUnit.jsDump.HTML ? ">" : ">",
- tag = node.nodeName.toLowerCase(),
- ret = open + tag,
- attrs = node.attributes;
-
- if ( attrs ) {
- for ( i = 0, len = attrs.length; i < len; i++ ) {
- val = attrs[i].nodeValue;
- // IE6 includes all attributes in .attributes, even ones not explicitly set.
- // Those have values like undefined, null, 0, false, "" or "inherit".
- if ( val && val !== "inherit" ) {
- ret += " " + attrs[i].nodeName + "=" + QUnit.jsDump.parse( val, "attribute" );
- }
- }
- }
- ret += close;
-
- // Show content of TextNode or CDATASection
- if ( node.nodeType === 3 || node.nodeType === 4 ) {
- ret += node.nodeValue;
- }
-
- return ret + open + "/" + tag + close;
- },
- // function calls it internally, it's the arguments part of the function
- functionArgs: function( fn ) {
- var args,
- l = fn.length;
-
- if ( !l ) {
- return "";
- }
-
- args = new Array(l);
- while ( l-- ) {
- // 97 is 'a'
- args[l] = String.fromCharCode(97+l);
- }
- return " " + args.join( ", " ) + " ";
- },
- // object calls it internally, the key part of an item in a map
- key: quote,
- // function calls it internally, it's the content of the function
- functionCode: "[code]",
- // node calls it internally, it's an html attribute value
- attribute: quote,
- string: quote,
- date: quote,
- regexp: literal,
- number: literal,
- "boolean": literal
- },
- // if true, entities are escaped ( <, >, \t, space and \n )
- HTML: false,
- // indentation unit
- indentChar: " ",
- // if true, items in a collection, are separated by a \n, else just a space.
- multiline: true
- };
-
- return jsDump;
-}());
-
-// from jquery.js
-function inArray( elem, array ) {
- if ( array.indexOf ) {
- return array.indexOf( elem );
- }
-
- for ( var i = 0, length = array.length; i < length; i++ ) {
- if ( array[ i ] === elem ) {
- return i;
- }
- }
-
- return -1;
-}
-
-/*
- * Javascript Diff Algorithm
- * By John Resig (http://ejohn.org/)
- * Modified by Chu Alan "sprite"
- *
- * Released under the MIT license.
- *
- * More Info:
- * http://ejohn.org/projects/javascript-diff-algorithm/
- *
- * Usage: QUnit.diff(expected, actual)
- *
- * QUnit.diff( "the quick brown fox jumped over", "the quick fox jumps over" ) == "the quick brown fox jumped jumps over"
- */
-QUnit.diff = (function() {
- /*jshint eqeqeq:false, eqnull:true */
- function diff( o, n ) {
- var i,
- ns = {},
- os = {};
-
- for ( i = 0; i < n.length; i++ ) {
- if ( !hasOwn.call( ns, n[i] ) ) {
- ns[ n[i] ] = {
- rows: [],
- o: null
- };
- }
- ns[ n[i] ].rows.push( i );
- }
-
- for ( i = 0; i < o.length; i++ ) {
- if ( !hasOwn.call( os, o[i] ) ) {
- os[ o[i] ] = {
- rows: [],
- n: null
- };
- }
- os[ o[i] ].rows.push( i );
- }
-
- for ( i in ns ) {
- if ( !hasOwn.call( ns, i ) ) {
- continue;
- }
- if ( ns[i].rows.length === 1 && hasOwn.call( os, i ) && os[i].rows.length === 1 ) {
- n[ ns[i].rows[0] ] = {
- text: n[ ns[i].rows[0] ],
- row: os[i].rows[0]
- };
- o[ os[i].rows[0] ] = {
- text: o[ os[i].rows[0] ],
- row: ns[i].rows[0]
- };
- }
- }
-
- for ( i = 0; i < n.length - 1; i++ ) {
- if ( n[i].text != null && n[ i + 1 ].text == null && n[i].row + 1 < o.length && o[ n[i].row + 1 ].text == null &&
- n[ i + 1 ] == o[ n[i].row + 1 ] ) {
-
- n[ i + 1 ] = {
- text: n[ i + 1 ],
- row: n[i].row + 1
- };
- o[ n[i].row + 1 ] = {
- text: o[ n[i].row + 1 ],
- row: i + 1
- };
- }
- }
-
- for ( i = n.length - 1; i > 0; i-- ) {
- if ( n[i].text != null && n[ i - 1 ].text == null && n[i].row > 0 && o[ n[i].row - 1 ].text == null &&
- n[ i - 1 ] == o[ n[i].row - 1 ]) {
-
- n[ i - 1 ] = {
- text: n[ i - 1 ],
- row: n[i].row - 1
- };
- o[ n[i].row - 1 ] = {
- text: o[ n[i].row - 1 ],
- row: i - 1
- };
- }
- }
-
- return {
- o: o,
- n: n
- };
- }
-
- return function( o, n ) {
- o = o.replace( /\s+$/, "" );
- n = n.replace( /\s+$/, "" );
-
- var i, pre,
- str = "",
- out = diff( o === "" ? [] : o.split(/\s+/), n === "" ? [] : n.split(/\s+/) ),
- oSpace = o.match(/\s+/g),
- nSpace = n.match(/\s+/g);
-
- if ( oSpace == null ) {
- oSpace = [ " " ];
- }
- else {
- oSpace.push( " " );
- }
-
- if ( nSpace == null ) {
- nSpace = [ " " ];
- }
- else {
- nSpace.push( " " );
- }
-
- if ( out.n.length === 0 ) {
- for ( i = 0; i < out.o.length; i++ ) {
- str += "" + out.o[i] + oSpace[i] + "";
- }
- }
- else {
- if ( out.n[0].text == null ) {
- for ( n = 0; n < out.o.length && out.o[n].text == null; n++ ) {
- str += "" + out.o[n] + oSpace[n] + "";
- }
- }
-
- for ( i = 0; i < out.n.length; i++ ) {
- if (out.n[i].text == null) {
- str += "" + out.n[i] + nSpace[i] + "";
- }
- else {
- // `pre` initialized at top of scope
- pre = "";
-
- for ( n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++ ) {
- pre += "" + out.o[n] + oSpace[n] + "";
- }
- str += " " + out.n[i].text + nSpace[i] + pre;
- }
- }
- }
-
- return str;
- };
-}());
-
-// for CommonJS enviroments, export everything
-if ( typeof exports !== "undefined" ) {
- extend( exports, QUnit );
-}
-
-// get at whatever the global object is, like window in browsers
-}( (function() {return this;}.call()) ));
diff --git a/test/lib/require.js b/test/lib/require.js
deleted file mode 100644
index 987f865..0000000
--- a/test/lib/require.js
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- RequireJS 2.1.5 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.
- Available via the MIT or new BSD license.
- see: http://github.com/jrburke/requirejs for details
-*/
-var requirejs,require,define;
-(function(aa){function I(b){return"[object Function]"===L.call(b)}function J(b){return"[object Array]"===L.call(b)}function y(b,c){if(b){var d;for(d=0;dthis.depCount&&!this.defined){if(I(n)){if(this.events.error)try{e=i.execCb(c,n,b,e)}catch(d){a=d}else e=i.execCb(c,n,b,e);this.map.isDefine&&((b=this.module)&&void 0!==b.exports&&b.exports!==this.exports?e=b.exports:void 0===e&&this.usingExports&&(e=this.exports));if(a)return a.requireMap=this.map,a.requireModules=[this.map.id],a.requireType="define",v(this.error=
-a)}else e=n;this.exports=e;if(this.map.isDefine&&!this.ignore&&(q[c]=e,l.onResourceLoad))l.onResourceLoad(i,this.map,this.depMaps);x(c);this.defined=!0}this.defining=!1;this.defined&&!this.defineEmitted&&(this.defineEmitted=!0,this.emit("defined",this.exports),this.defineEmitComplete=!0)}}else this.fetch()}},callPlugin:function(){var a=this.map,b=a.id,d=j(a.prefix);this.depMaps.push(d);t(d,"defined",u(this,function(e){var n,d;d=this.map.name;var g=this.map.parentMap?this.map.parentMap.name:null,h=
-i.makeRequire(a.parentMap,{enableBuildCallback:!0});if(this.map.unnormalized){if(e.normalize&&(d=e.normalize(d,function(a){return c(a,g,!0)})||""),e=j(a.prefix+"!"+d,this.map.parentMap),t(e,"defined",u(this,function(a){this.init([],function(){return a},null,{enabled:!0,ignore:!0})})),d=m(p,e.id)){this.depMaps.push(e);if(this.events.error)d.on("error",u(this,function(a){this.emit("error",a)}));d.enable()}}else n=u(this,function(a){this.init([],function(){return a},null,{enabled:!0})}),n.error=u(this,
-function(a){this.inited=!0;this.error=a;a.requireModules=[b];G(p,function(a){0===a.map.id.indexOf(b+"_unnormalized")&&x(a.map.id)});v(a)}),n.fromText=u(this,function(e,c){var d=a.name,g=j(d),C=O;c&&(e=c);C&&(O=!1);r(g);s(k.config,b)&&(k.config[d]=k.config[b]);try{l.exec(e)}catch(ca){return v(B("fromtexteval","fromText eval for "+b+" failed: "+ca,ca,[b]))}C&&(O=!0);this.depMaps.push(g);i.completeLoad(d);h([d],n)}),e.load(a.name,h,n,k)}));i.enable(d,this);this.pluginMaps[d.id]=d},enable:function(){V[this.map.id]=
-this;this.enabling=this.enabled=!0;y(this.depMaps,u(this,function(a,b){var c,e;if("string"===typeof a){a=j(a,this.map.isDefine?this.map:this.map.parentMap,!1,!this.skipMap);this.depMaps[b]=a;if(c=m(N,a.id)){this.depExports[b]=c(this);return}this.depCount+=1;t(a,"defined",u(this,function(a){this.defineDep(b,a);this.check()}));this.errback&&t(a,"error",this.errback)}c=a.id;e=p[c];!s(N,c)&&(e&&!e.enabled)&&i.enable(a,this)}));G(this.pluginMaps,u(this,function(a){var b=m(p,a.id);b&&!b.enabled&&i.enable(a,
-this)}));this.enabling=!1;this.check()},on:function(a,b){var c=this.events[a];c||(c=this.events[a]=[]);c.push(b)},emit:function(a,b){y(this.events[a],function(a){a(b)});"error"===a&&delete this.events[a]}};i={config:k,contextName:b,registry:p,defined:q,urlFetched:U,defQueue:H,Module:Z,makeModuleMap:j,nextTick:l.nextTick,onError:v,configure:function(a){a.baseUrl&&"/"!==a.baseUrl.charAt(a.baseUrl.length-1)&&(a.baseUrl+="/");var b=k.pkgs,c=k.shim,e={paths:!0,config:!0,map:!0};G(a,function(a,b){e[b]?
-"map"===b?(k.map||(k.map={}),R(k[b],a,!0,!0)):R(k[b],a,!0):k[b]=a});a.shim&&(G(a.shim,function(a,b){J(a)&&(a={deps:a});if((a.exports||a.init)&&!a.exportsFn)a.exportsFn=i.makeShimExports(a);c[b]=a}),k.shim=c);a.packages&&(y(a.packages,function(a){a="string"===typeof a?{name:a}:a;b[a.name]={name:a.name,location:a.location||a.name,main:(a.main||"main").replace(ja,"").replace(ea,"")}}),k.pkgs=b);G(p,function(a,b){!a.inited&&!a.map.unnormalized&&(a.map=j(b))});if(a.deps||a.callback)i.require(a.deps||[],
-a.callback)},makeShimExports:function(a){return function(){var b;a.init&&(b=a.init.apply(aa,arguments));return b||a.exports&&ba(a.exports)}},makeRequire:function(a,f){function d(e,c,h){var g,k;f.enableBuildCallback&&(c&&I(c))&&(c.__requireJsBuild=!0);if("string"===typeof e){if(I(c))return v(B("requireargs","Invalid require call"),h);if(a&&s(N,e))return N[e](p[a.id]);if(l.get)return l.get(i,e,a,d);g=j(e,a,!1,!0);g=g.id;return!s(q,g)?v(B("notloaded",'Module name "'+g+'" has not been loaded yet for context: '+
-b+(a?"":". Use require([])"))):q[g]}L();i.nextTick(function(){L();k=r(j(null,a));k.skipMap=f.skipMap;k.init(e,c,h,{enabled:!0});D()});return d}f=f||{};R(d,{isBrowser:A,toUrl:function(b){var d,f=b.lastIndexOf("."),g=b.split("/")[0];if(-1!==f&&(!("."===g||".."===g)||1h.attachEvent.toString().indexOf("[native code"))&&!Y?(O=!0,h.attachEvent("onreadystatechange",b.onScriptLoad)):(h.addEventListener("load",b.onScriptLoad,!1),h.addEventListener("error",b.onScriptError,!1)),h.src=d,K=h,D?x.insertBefore(h,D):x.appendChild(h),K=null,h;if(da)try{importScripts(d),b.completeLoad(c)}catch(j){b.onError(B("importscripts","importScripts failed for "+c+" at "+d,j,[c]))}};A&&M(document.getElementsByTagName("script"),function(b){x||(x=
-b.parentNode);if(t=b.getAttribute("data-main"))return r.baseUrl||(E=t.split("/"),Q=E.pop(),fa=E.length?E.join("/")+"/":"./",r.baseUrl=fa,t=Q),t=t.replace(ea,""),r.deps=r.deps?r.deps.concat(t):[t],!0});define=function(b,c,d){var l,h;"string"!==typeof b&&(d=c,c=b,b=null);J(c)||(d=c,c=[]);!c.length&&I(d)&&d.length&&(d.toString().replace(la,"").replace(ma,function(b,d){c.push(d)}),c=(1===d.length?["require"]:["require","exports","module"]).concat(c));if(O){if(!(l=K))P&&"interactive"===P.readyState||M(document.getElementsByTagName("script"),
-function(b){if("interactive"===b.readyState)return P=b}),l=P;l&&(b||(b=l.getAttribute("data-requiremodule")),h=F[l.getAttribute("data-requirecontext")])}(h?h.defQueue:T).push([b,c,d])};define.amd={jQuery:!0};l.exec=function(b){return eval(b)};l(r)}})(this);
diff --git a/test/lib/resemble.js b/test/lib/resemble.js
new file mode 100644
index 0000000..1cb8c29
--- /dev/null
+++ b/test/lib/resemble.js
@@ -0,0 +1,535 @@
+/*
+Author: James Cryer
+Company: Huddle
+Last updated date: 21 Feb 2013
+URL: https://github.com/Huddle/Resemble.js
+*/
+
+(function(_this){
+ 'use strict';
+
+ _this['resemble'] = function( fileData ){
+
+ var data = {};
+ var images = [];
+ var updateCallbackArray = [];
+
+ var tolerance = { // between 0 and 255
+ red: 16,
+ green: 16,
+ blue: 16,
+ minBrightness: 16,
+ maxBrightness: 240
+ };
+
+ var ignoreAntialiasing = false;
+ var ignoreColors = false;
+
+ function triggerDataUpdate(){
+ var len = updateCallbackArray.length;
+ var i;
+ for(i=0;i tolerance.maxBrightness;
+ }
+
+ function getHue(r,g,b){
+
+ r = r / 255;
+ g = g / 255;
+ b = b / 255;
+ var max = Math.max(r, g, b), min = Math.min(r, g, b);
+ var h;
+ var d;
+
+ if (max == min){
+ h = 0; // achromatic
+ } else{
+ d = max - min;
+ switch(max){
+ case r: h = (g - b) / d + (g < b ? 6 : 0); break;
+ case g: h = (b - r) / d + 2; break;
+ case b: h = (r - g) / d + 4; break;
+ }
+ h /= 6;
+ }
+
+ return h;
+ }
+
+ function isAntialiased(sourcePix, data, cacheSet, verticalPos, horizontalPos, width){
+ var offset;
+ var targetPix;
+ var distance = 1;
+ var i;
+ var j;
+ var hasHighContrastSibling = 0;
+ var hasSiblingWithDifferentHue = 0;
+ var hasEquivilantSibling = 0;
+
+ addHueInfo(sourcePix);
+
+ for (i = distance*-1; i <= distance; i++){
+ for (j = distance*-1; j <= distance; j++){
+
+ if(i===0 && j===0){
+ // ignore source pixel
+ } else {
+
+ offset = ((verticalPos+j)*width + (horizontalPos+i)) * 4;
+ targetPix = getPixelInfo(data, offset, cacheSet);
+
+ if(targetPix === null){
+ continue;
+ }
+
+ addBrightnessInfo(targetPix);
+ addHueInfo(targetPix);
+
+ if( isContrasting(sourcePix, targetPix) ){
+ hasHighContrastSibling++;
+ }
+
+ if( isRGBSame(sourcePix,targetPix) ){
+ hasEquivilantSibling++;
+ }
+
+ if( Math.abs(targetPix.h - sourcePix.h) > 0.3 ){
+ hasSiblingWithDifferentHue++;
+ }
+
+ if( hasSiblingWithDifferentHue > 1 || hasHighContrastSibling > 1){
+ return true;
+ }
+ }
+ }
+ }
+
+ if(hasEquivilantSibling < 2){
+ return true;
+ }
+
+ return false;
+ }
+
+ function errorPixel(px, offset){
+ px[offset] = 255; //r
+ px[offset + 1] = 0; //g
+ px[offset + 2] = 255; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyPixel(px, offset, data){
+ px[offset] = data.r; //r
+ px[offset + 1] = data.g; //g
+ px[offset + 2] = data.b; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyGrayScalePixel(px, offset, data){
+ px[offset] = data.brightness; //r
+ px[offset + 1] = data.brightness; //g
+ px[offset + 2] = data.brightness; //b
+ px[offset + 3] = 255; //a
+ }
+
+
+ function getPixelInfo(data, offset, cacheSet){
+ var r;
+ var g;
+ var b;
+ var d;
+
+ if(typeof data[offset] !== 'undefined'){
+ r = data[offset];
+ g = data[offset+1];
+ b = data[offset+2];
+ d = {
+ r: r,
+ g: g,
+ b: b
+ };
+
+ return d;
+ } else {
+ return null;
+ }
+ }
+
+ function addBrightnessInfo(data){
+ data.brightness = getBrightness(data.r,data.g,data.b); // 'corrected' lightness
+ }
+
+ function addHueInfo(data){
+ data.h = getHue(data.r,data.g,data.b);
+ }
+
+ function analyseImages(img1, img2, width, height){
+
+ var hiddenCanvas = document.createElement('canvas');
+
+ var data1 = img1.data;
+ var data2 = img2.data;
+
+ hiddenCanvas.width = width;
+ hiddenCanvas.height = height;
+
+ var context = hiddenCanvas.getContext('2d');
+ var imgd = context.createImageData(width,height);
+ var targetPix = imgd.data;
+
+ var mismatchCount = 0;
+
+ var time = Date.now();
+
+ var skip;
+
+ if( (width > 1200 || height > 1200) && ignoreAntialiasing){
+ skip = 6;
+ }
+
+ loop(height, width, function(verticalPos, horizontalPos){
+
+ if(skip){ // only skip if the image isn't small
+ if(verticalPos % skip === 0 || horizontalPos % skip === 0){
+ return;
+ }
+ }
+
+ var offset = (verticalPos*width + horizontalPos) * 4;
+ var pixel1 = getPixelInfo(data1, offset, 1);
+ var pixel2 = getPixelInfo(data2, offset, 2);
+
+ if(pixel1 === null || pixel2 === null){
+ return;
+ }
+
+ if (ignoreColors){
+
+ addBrightnessInfo(pixel1);
+ addBrightnessInfo(pixel2);
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ return;
+ }
+
+ if( isRGBSimilar(pixel1, pixel2) ){
+ copyPixel(targetPix, offset, pixel2);
+
+ } else if( ignoreAntialiasing && (
+ addBrightnessInfo(pixel1), // jit pixel info augmentation looks a little weird, sorry.
+ addBrightnessInfo(pixel2),
+ isAntialiased(pixel1, data1, 1, verticalPos, horizontalPos, width) ||
+ isAntialiased(pixel2, data2, 2, verticalPos, horizontalPos, width)
+ )){
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+
+ });
+
+ data.misMatchPercentage = (mismatchCount / (height*width) * 100).toFixed(2);
+ data.analysisTime = Date.now() - time;
+
+ data.getImageDataUrl = function(text){
+ var barHeight = 0;
+
+ if(text){
+ barHeight = addLabel(text,context,hiddenCanvas);
+ }
+
+ context.putImageData(imgd, 0, barHeight);
+
+ return hiddenCanvas.toDataURL("image/png");
+ };
+ }
+
+ function addLabel(text, context, hiddenCanvas){
+ var textPadding = 2;
+
+ context.font = '12px sans-serif';
+
+ var textWidth = context.measureText(text).width + textPadding*2;
+ var barHeight = 22;
+
+ if(textWidth > hiddenCanvas.width){
+ hiddenCanvas.width = textWidth;
+ }
+
+ hiddenCanvas.height += barHeight;
+
+ context.fillStyle = "#666";
+ context.fillRect(0,0,hiddenCanvas.width,barHeight -4);
+ context.fillStyle = "#fff";
+ context.fillRect(0,barHeight -4,hiddenCanvas.width, 4);
+
+ context.fillStyle = "#fff";
+ context.textBaseline = "top";
+ context.font = '12px sans-serif';
+ context.fillText(text, textPadding, 1);
+
+ return barHeight;
+ }
+
+ function normalise(img, w, h){
+ var c;
+ var context;
+
+ if(img.height < h || img.width < w){
+ c = document.createElement('canvas');
+ c.width = w;
+ c.height = h;
+ context = c.getContext('2d');
+ context.putImageData(img, 0, 0);
+ return context.getImageData(0, 0, w, h);
+ }
+
+ return img;
+ }
+
+ function compare(one, two){
+
+ function onceWeHaveBoth(){
+ var width;
+ var height;
+ if(images.length === 2){
+ width = images[0].width > images[1].width ? images[0].width : images[1].width;
+ height = images[0].height > images[1].height ? images[0].height : images[1].height;
+
+ if( (images[0].width === images[1].width) && (images[0].height === images[1].height) ){
+ data.isSameDimensions = true;
+ } else {
+ data.isSameDimensions = false;
+ }
+
+ analyseImages( normalise(images[0],width, height), normalise(images[1],width, height), width, height);
+
+ triggerDataUpdate();
+ }
+ }
+
+ images = [];
+ loadImageData(one, onceWeHaveBoth);
+ loadImageData(two, onceWeHaveBoth);
+ }
+
+ function getCompareApi(param){
+
+ var secondFileData,
+ hasMethod = typeof param === 'function';
+
+ if( !hasMethod ){
+ // assume it's file data
+ secondFileData = param;
+ }
+
+ var self = {
+ ignoreNothing: function(){
+
+ tolerance.red = 16;
+ tolerance.green = 16;
+ tolerance.blue = 16;
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreAntialiasing: function(){
+
+ tolerance.red = 32;
+ tolerance.green = 32;
+ tolerance.blue = 32;
+ tolerance.minBrightness = 64;
+ tolerance.maxBrightness = 96;
+
+ ignoreAntialiasing = true;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreColors: function(){
+
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = true;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ onComplete: function( callback ){
+
+ updateCallbackArray.push(callback);
+
+ var wrapper = function(){
+ compare(fileData, secondFileData);
+ };
+
+ wrapper();
+
+ return getCompareApi(wrapper);
+ }
+ };
+
+ return self;
+ }
+
+ return {
+ onComplete: function( callback ){
+ updateCallbackArray.push(callback);
+ loadImageData(fileData, function(imageData, width, height){
+ parseImage(imageData.data, width, height);
+ });
+ },
+ compareTo: function(secondFileData){
+ return getCompareApi(secondFileData);
+ }
+ };
+
+ };
+}(this));
\ No newline at end of file
diff --git a/test/testsuite.js b/test/testsuite.js
deleted file mode 100644
index b486acb..0000000
--- a/test/testsuite.js
+++ /dev/null
@@ -1,36 +0,0 @@
-requirejs.config({
- baseUrl: '/test/unit/'
-});
-
-define(function(require) {
- var testModules = [
- 'Pixi',
- 'Point',
- 'Rectangle',
- 'DisplayObject',
- 'DisplayObjectContainer',
- 'Sprite',
- 'MovieClip',
- 'InteractionManager',
- 'Stage',
- 'utils/Utils',
- 'utils/EventTarget',
- 'utils/Matrix',
- 'utils/Detector',
- 'renderers/WebGLShaders',
- 'renderers/WebGLRenderer',
- 'renderers/WebGLBatch',
- 'renderers/CanvasRenderer',
- 'extras/Strip',
- 'extras/Rope',
- 'textures/BaseTexture',
- 'textures/Texture',
- 'loaders/SpriteSheetLoader',
- 'loaders/AssetLoader'
- ];
-
- // Resolve all testModules and then start the Test Runner.
- require(testModules, function() {
- QUnit.start();
- });
-});
\ No newline at end of file
diff --git a/test/textures/SpriteSheet-Aliens.png b/test/textures/SpriteSheet-Aliens.png
new file mode 100644
index 0000000..210acb1
--- /dev/null
+++ b/test/textures/SpriteSheet-Aliens.png
Binary files differ
diff --git a/test/textures/SpriteSheet-Explosion.png b/test/textures/SpriteSheet-Explosion.png
new file mode 100755
index 0000000..79e1a69
--- /dev/null
+++ b/test/textures/SpriteSheet-Explosion.png
Binary files differ
diff --git a/test/textures/bunny.png b/test/textures/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/textures/bunny.png
Binary files differ
diff --git a/test/unit/DisplayObject.js b/test/unit/DisplayObject.js
deleted file mode 100644
index 5e7e72f..0000000
--- a/test/unit/DisplayObject.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObject');
-});
diff --git a/test/unit/DisplayObjectContainer.js b/test/unit/DisplayObjectContainer.js
deleted file mode 100644
index b323959..0000000
--- a/test/unit/DisplayObjectContainer.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObjectContainer');
-});
diff --git a/test/unit/InteractionManager.js b/test/unit/InteractionManager.js
deleted file mode 100644
index e751f52..0000000
--- a/test/unit/InteractionManager.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('InteractionManager');
-});
diff --git a/test/unit/MovieClip.js b/test/unit/MovieClip.js
deleted file mode 100644
index 37d9446..0000000
--- a/test/unit/MovieClip.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('MovieClip');
-});
diff --git a/test/unit/Pixi.js b/test/unit/Pixi.js
deleted file mode 100644
index 36eee73..0000000
--- a/test/unit/Pixi.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Pixi');
-});
diff --git a/test/unit/Point.js b/test/unit/Point.js
deleted file mode 100644
index 983ff6e..0000000
--- a/test/unit/Point.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Point');
-});
diff --git a/test/unit/Rectangle.js b/test/unit/Rectangle.js
deleted file mode 100644
index 3b439ba..0000000
--- a/test/unit/Rectangle.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Rectangle');
-});
diff --git a/test/unit/Sprite.js b/test/unit/Sprite.js
deleted file mode 100644
index ed4f596..0000000
--- a/test/unit/Sprite.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Sprite');
-});
diff --git a/test/unit/Stage.js b/test/unit/Stage.js
deleted file mode 100644
index 2d70291..0000000
--- a/test/unit/Stage.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Stage');
-});
diff --git a/test/unit/extras/Rope.js b/test/unit/extras/Rope.js
deleted file mode 100644
index 5606f14..0000000
--- a/test/unit/extras/Rope.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Rope');
-});
diff --git a/test/unit/extras/Strip.js b/test/unit/extras/Strip.js
deleted file mode 100644
index 0134d3a..0000000
--- a/test/unit/extras/Strip.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Strip');
-});
diff --git a/test/unit/loaders/AssetLoader.js b/test/unit/loaders/AssetLoader.js
deleted file mode 100644
index 13b8443..0000000
--- a/test/unit/loaders/AssetLoader.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('AssetLoader');
-});
diff --git a/test/unit/loaders/SpriteSheetLoader.js b/test/unit/loaders/SpriteSheetLoader.js
deleted file mode 100644
index 8bf0cb2..0000000
--- a/test/unit/loaders/SpriteSheetLoader.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('SpriteSheetLoader');
-});
diff --git a/test/unit/pixi/InteractionManager.js b/test/unit/pixi/InteractionManager.js
new file mode 100644
index 0000000..ed3001f
--- /dev/null
+++ b/test/unit/pixi/InteractionManager.js
@@ -0,0 +1,10 @@
+describe('pixi/InteractionManager', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var InteractionManager = PIXI.InteractionManager;
+
+ it('Module exists', function () {
+ expect(InteractionManager).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/Pixi.js b/test/unit/pixi/Pixi.js
new file mode 100644
index 0000000..27debc1
--- /dev/null
+++ b/test/unit/pixi/Pixi.js
@@ -0,0 +1,9 @@
+describe('pixi/Pixi', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+
+ it('Module exists', function () {
+ expect(global).to.have.property('PIXI').and.to.be.an('object');
+ });
+});
diff --git a/test/unit/pixi/core/Circle.js b/test/unit/pixi/core/Circle.js
new file mode 100644
index 0000000..93a4456
--- /dev/null
+++ b/test/unit/pixi/core/Circle.js
@@ -0,0 +1,22 @@
+describe('pixi/core/Circle', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Circle = PIXI.Circle;
+
+ it('Module exists', function () {
+ expect(Circle).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Circle();
+
+ expect(obj).to.be.an.instanceof(Circle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', 0);
+ expect(obj).to.have.property('y', 0);
+ expect(obj).to.have.property('radius', 0);
+ });
+});
diff --git a/.gitignore b/.gitignore
index 12e1b62..0b88317 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
node_modules
.DS_Store
-.project
\ No newline at end of file
+.project
+*.log
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..63e4d7c
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,8 @@
+language: node_js
+node_js:
+ - 0.10
+
+before_script:
+ - npm install -g grunt-cli
+ - export DISPLAY=:99.0
+ - sh -e /etc/init.d/xvfb start
diff --git a/Gruntfile.js b/Gruntfile.js
index b083b49..103938c 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -1,10 +1,12 @@
+'use strict';
+
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-connect');
- grunt.loadNpmTasks('grunt-contrib-qunit');
grunt.loadNpmTasks('grunt-contrib-yuidoc');
+ grunt.loadTasks('tasks');
var root = 'src/pixi/',
debug = 'bin/pixi.dev.js',
@@ -79,7 +81,7 @@
},
files: {
srcBlob: '<%= dirs.src %>/**/*.js',
- testBlob: '<%= dirs.test %>/unit/**/*.js',
+ testBlob: '<%= dirs.test %>/{functional,lib/pixi,unit}/**/*.js',
build: '<%= dirs.build %>/pixi.dev.js',
buildMin: '<%= dirs.build %>/pixi.js'
},
@@ -94,7 +96,12 @@
},
jshint: {
beforeconcat: srcFiles,
- test: ['<%= files.testBlob %>'],
+ test: {
+ src: ['<%= files.testBlob %>'],
+ options: {
+ expr: true
+ }
+ },
options: {
asi: true,
smarttabs: true
@@ -128,12 +135,6 @@
]
},
connect: {
- qunit: {
- options: {
- port: grunt.option('port-test') || 9002,
- base: './'
- }
- },
test: {
options: {
port: grunt.option('port-test') || 9002,
@@ -142,13 +143,6 @@
}
}
},
- qunit: {
- all: {
- options: {
- urls: ['http://localhost:' + (grunt.option('port-test') || 9002) + '/test/index.html']
- }
- }
- },
yuidoc: {
compile: {
name: '<%= pkg.name %>',
@@ -161,6 +155,13 @@
outdir: '<%= dirs.docs %>'
}
}
+ },
+ karma: {
+ unit: {
+ configFile: 'test/karma.conf.js',
+ // browsers: ['Chrome'],
+ singleRun: true
+ }
}
});
@@ -182,9 +183,10 @@
}
)
- grunt.registerTask('default', ['concat', 'uglify', 'distribute']);
grunt.registerTask('build', ['concat', 'uglify', 'distribute']);
- grunt.registerTask('test', ['build', 'connect:qunit', 'qunit']);
+ grunt.registerTask('test', ['concat', 'jshint:test', 'karma']);
grunt.registerTask('docs', ['yuidoc']);
-
-}
\ No newline at end of file
+ grunt.registerTask('default', ['test', 'uglify', 'distribute']);
+ // Travis CI task.
+ grunt.registerTask('travis', ['test']);
+}
diff --git a/README.md b/README.md
index c62ef86..690cfe4 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,8 @@

+[](http://travis-ci.org/drkibitz/pixi.js)
+
#### JavaScript 2D Renderer ####
The aim of this project is to provide a fast lightweight 2D library that works
diff --git a/package.json b/package.json
index b373240..1246a68 100644
--- a/package.json
+++ b/package.json
@@ -18,14 +18,21 @@
"main": "bin/pixi.js",
+ "scripts": {
+ "test": "grunt travis --verbose"
+ },
+
"dependencies": {},
"devDependencies": {
"grunt": "~0.4.x",
- "grunt-contrib-jshint": "0.3.x",
+ "grunt-contrib-jshint": "0.6.x",
"grunt-contrib-uglify": "0.2.x",
- "grunt-contrib-connect": "0.2.x",
- "grunt-contrib-qunit": "0.2.x",
+ "grunt-contrib-connect": "0.3.x",
"grunt-contrib-yuidoc": "0.4.x",
- "grunt-contrib-concat": "0.1.x"
+ "grunt-contrib-concat": "0.3.x",
+ "chai": "~1.7.0",
+ "karma": "0.11.0",
+ "karma-firefox-launcher": "0.1.0",
+ "karma-mocha": "0.1.0"
}
}
diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js
index a7c520e..ee82bbd 100644
--- a/src/pixi/InteractionManager.js
+++ b/src/pixi/InteractionManager.js
@@ -62,7 +62,6 @@
this.onTouchEnd = this.onTouchEnd.bind(this);
this.onTouchMove = this.onTouchMove.bind(this);
-
this.last = 0;
}
diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js
index 1a95d20..eef1059 100644
--- a/src/pixi/core/Ellipse.js
+++ b/src/pixi/core/Ellipse.js
@@ -78,7 +78,7 @@
return (normx + normy < 0.25);
}
-PIXI.Ellipse.getBounds = function()
+PIXI.Ellipse.prototype.getBounds = function()
{
return new PIXI.Rectangle(this.x, this.y, this.width, this.height);
}
diff --git a/tasks/karma.js b/tasks/karma.js
new file mode 100644
index 0000000..c340485
--- /dev/null
+++ b/tasks/karma.js
@@ -0,0 +1,27 @@
+'use strict';
+
+var path = require('path');
+var server = require('karma').server;
+
+module.exports = function (grunt) {
+ grunt.registerMultiTask('karma', 'run karma.', function() {
+ var done = this.async();
+ var options = this.options({
+ background: false
+ });
+ var data = this.data;
+
+ //merge options onto data, with data taking precedence
+ data = grunt.util._.merge(options, data);
+ data.configFile = path.resolve(data.configFile);
+ if (data.configFile) {
+ data.configFile = grunt.template.process(data.configFile);
+ }
+
+ server.start(
+ data,
+ function(code) {
+ done(!code);
+ });
+ });
+};
diff --git a/test/functional/example-1-basics/bunny.png b/test/functional/example-1-basics/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/functional/example-1-basics/bunny.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-30.png b/test/functional/example-1-basics/frame-30.png
new file mode 100644
index 0000000..96e3409
--- /dev/null
+++ b/test/functional/example-1-basics/frame-30.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-60.png b/test/functional/example-1-basics/frame-60.png
new file mode 100644
index 0000000..af3f4ce
--- /dev/null
+++ b/test/functional/example-1-basics/frame-60.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-90.png b/test/functional/example-1-basics/frame-90.png
new file mode 100644
index 0000000..099b823
--- /dev/null
+++ b/test/functional/example-1-basics/frame-90.png
Binary files differ
diff --git a/test/functional/example-1-basics/index.js b/test/functional/example-1-basics/index.js
new file mode 100644
index 0000000..7ae7a98
--- /dev/null
+++ b/test/functional/example-1-basics/index.js
@@ -0,0 +1,133 @@
+describe('Example 1 - Basics', function () {
+ 'use strict';
+
+ var baseUri = '/base/test/functional/example-1-basics';
+ var expect = chai.expect;
+ var currentFrame = 0;
+ var frameEvents = {};
+ var stage;
+ var renderer;
+ var bunny;
+
+ function onFrame(frame, callback) {
+ frameEvents[frame] = callback;
+ }
+
+ function animate() {
+ currentFrame += 1;
+
+ requestAnimFrame( animate );
+
+ // just for fun, lets rotate mr rabbit a little
+ bunny.rotation += 0.1;
+
+ // render the stage
+ renderer.render(stage);
+
+ if (frameEvents[currentFrame])
+ frameEvents[currentFrame](currentFrame);
+ }
+
+ function initScene() {
+ // create an new instance of a pixi stage
+ stage = new PIXI.Stage(0x66FF99);
+
+ // create a renderer instance
+ renderer = PIXI.autoDetectRenderer(400, 300);
+ console.log('Is PIXI.WebGLRenderer: ' + (renderer instanceof PIXI.WebGLRenderer));
+
+ // add the renderer view element to the DOM
+ document.body.appendChild(renderer.view);
+
+ requestAnimFrame( animate );
+
+ // create a texture from an image path
+ var texture = PIXI.Texture.fromImage(baseUri + "/bunny.png");
+ // create a new Sprite using the texture
+ bunny = new PIXI.Sprite(texture);
+
+ // center the sprites anchor point
+ bunny.anchor.x = 0.5;
+ bunny.anchor.y = 0.5;
+
+ // move the sprite t the center of the screen
+ bunny.position.x = 200;
+ bunny.position.y = 150;
+
+ stage.addChild(bunny);
+ }
+
+ it('assets loaded', function (done) {
+ var loader = new PIXI.AssetLoader([
+ baseUri + '/bunny.png',
+ baseUri + '/frame-30.png',
+ baseUri + '/frame-60.png',
+ baseUri + '/frame-90.png'
+ ]);
+ // loader.on('onProgress', function (event) {
+ // console.log(event.content);
+ // });
+ loader.on('onComplete', function (event) {
+ done();
+ initScene();
+ });
+ loader.load();
+ });
+
+ it('frame 30 should match', function (done) {
+ this.timeout(700);
+ onFrame(30, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-30.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 60 should match', function (done) {
+ this.timeout(1200);
+ onFrame(60, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-60.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 90 should match', function (done) {
+ this.timeout(1700);
+ onFrame(90, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-90.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ // it('capture something', function (done) {
+ // this.timeout(2000000);
+ // onFrame(30, function () {
+ // var img = new Image();
+ // img.src = renderer.view.toDataURL('image/png');
+ // document.body.appendChild(img);
+ // });
+ // });
+});
diff --git a/test/index.html b/test/index.html
deleted file mode 100644
index 9cbcac5..0000000
--- a/test/index.html
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
- Pixi.js Test Suite
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/test/karma.conf.js b/test/karma.conf.js
new file mode 100644
index 0000000..c66a696
--- /dev/null
+++ b/test/karma.conf.js
@@ -0,0 +1,82 @@
+module.exports = function(config) {
+ config.set({
+
+ // base path, that will be used to resolve files and exclude
+ basePath : '../',
+
+ frameworks : ['mocha'],
+
+ // list of files / patterns to load in the browser
+ files : [
+ 'node_modules/chai/chai.js',
+ 'bin/pixi.dev.js',
+ 'test/lib/**/*.js',
+ 'test/unit/**/*.js',
+ // 'test/functional/**/*.js',
+ {pattern: 'test/**/*.png', watched: false, included: false, served: true}
+ ],
+
+ // list of files to exclude
+ exclude : [],
+
+ // use dolts reporter, as travis terminal does not support escaping sequences
+ // possible values: 'dots', 'progress', 'junit', 'teamcity'
+ // CLI --reporters progress
+ reporters : ['progress'],
+
+ // web server port
+ // CLI --port 9876
+ port : 9876,
+
+ // cli runner port
+ // CLI --runner-port 9100
+ runnerPort : 9100,
+
+ // enable / disable colors in the output (reporters and logs)
+ // CLI --colors --no-colors
+ colors : true,
+
+ // level of logging
+ // possible values: karma.LOG_DISABLE || karma.LOG_ERROR || karma.LOG_WARN || karma.LOG_INFO || karma.LOG_DEBUG
+ // CLI --log-level debug
+ logLevel : config.LOG_DEBUG,
+
+ // enable / disable watching file and executing tests whenever any file changes
+ // CLI --auto-watch --no-auto-watch
+ autoWatch : false,
+
+ // Start these browsers, currently available:
+ // - Chrome
+ // - ChromeCanary
+ // - Firefox
+ // - Opera
+ // - Safari (only Mac)
+ // - PhantomJS
+ // - IE (only Windows)
+ // CLI --browsers Chrome,Firefox,Safari
+ browsers : ['Firefox'],
+
+ // If browser does not capture in given timeout [ms], kill it
+ // CLI --capture-timeout 5000
+ captureTimeout : 5000,
+
+ // Auto run tests on start (when browsers are captured) and exit
+ // CLI --single-run --no-single-run
+ singleRun : true,
+
+ // report which specs are slower than 500ms
+ // CLI --report-slower-than 500
+ reportSlowerThan : 1000,
+
+ preprocessors : {
+ // '**/client/js/*.js': 'coverage'
+ },
+
+ plugins : [
+ 'karma-mocha',
+ // 'karma-chrome-launcher',
+ 'karma-firefox-launcher',
+ // 'karma-phantomjs-launcher'
+ ]
+ });
+};
diff --git a/test/lib/pixi/core/Matrix.js b/test/lib/pixi/core/Matrix.js
new file mode 100644
index 0000000..d26386b
--- /dev/null
+++ b/test/lib/pixi/core/Matrix.js
@@ -0,0 +1,40 @@
+
+function pixi_core_Matrix_confirmNewMat3(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(1);
+ expect(matrix[5]).to.equal(0);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(1);
+}
+
+function pixi_core_Matrix_confirmNewMat4(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[0]).to.equal(1);
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(0);
+ expect(matrix[5]).to.equal(1);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(0);
+ expect(matrix[9]).to.equal(0);
+ expect(matrix[10]).to.equal(1);
+ expect(matrix[11]).to.equal(0);
+ expect(matrix[12]).to.equal(0);
+ expect(matrix[13]).to.equal(0);
+ expect(matrix[14]).to.equal(0);
+ expect(matrix[15]).to.equal(1);
+}
diff --git a/test/lib/pixi/core/Point.js b/test/lib/pixi/core/Point.js
new file mode 100644
index 0000000..e5df07b
--- /dev/null
+++ b/test/lib/pixi/core/Point.js
@@ -0,0 +1,10 @@
+
+function pixi_core_Point_confirm(obj, x, y) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Point);
+ expect(obj).to.respondTo('clone');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+}
diff --git a/test/lib/pixi/core/Rectangle.js b/test/lib/pixi/core/Rectangle.js
new file mode 100644
index 0000000..23f0d12
--- /dev/null
+++ b/test/lib/pixi/core/Rectangle.js
@@ -0,0 +1,13 @@
+
+function pixi_core_Rectangle_confirm(obj, x, y, width, height) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Rectangle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+ expect(obj).to.have.property('width', width);
+ expect(obj).to.have.property('height', height);
+}
diff --git a/test/lib/pixi/display/DisplayObject.js b/test/lib/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..1388a7f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObject.js
@@ -0,0 +1,43 @@
+
+function pixi_display_DisplayObject_confirmNew(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObject);
+ expect(obj).to.respondTo('setInteractive');
+ expect(obj).to.respondTo('addFilter');
+ expect(obj).to.respondTo('removeFilter');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.property('last', obj);
+ expect(obj).to.have.property('first', obj);
+
+ expect(obj).to.contain.property('position');
+ pixi_core_Point_confirm(obj.position, 0, 0);
+ expect(obj).to.contain.property('scale');
+ pixi_core_Point_confirm(obj.scale, 1, 1);
+ expect(obj).to.contain.property('pivot');
+ pixi_core_Point_confirm(obj.pivot, 0, 0);
+
+ expect(obj).to.have.property('rotation', 0);
+ expect(obj).to.have.property('alpha', 1);
+ expect(obj).to.have.property('visible', true);
+ expect(obj).to.have.property('buttonMode', false);
+ expect(obj).to.have.property('parent', null);
+ expect(obj).to.have.property('worldAlpha', 1);
+
+ expect(obj).to.have.property('hitArea');
+ expect(obj).to.have.property('interactive'); // TODO: Have a better default value
+ expect('mask' in obj).to.be.true; // TODO: Have a better default value
+ expect(obj.mask).to.be.undefined;
+
+ expect(obj).to.have.property('renderable');
+ expect(obj).to.have.property('stage');
+
+ expect(obj).to.have.deep.property('worldTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ expect(obj).to.have.deep.property('localTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.localTransform);
+
+ expect(obj).to.have.deep.property('color.length', 0);
+ expect(obj).to.have.property('dynamic', true);
+}
diff --git a/test/lib/pixi/display/DisplayObjectContainer.js b/test/lib/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..085c59f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,16 @@
+
+function pixi_display_DisplayObjectContainer_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObject_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObjectContainer);
+ expect(obj).to.respondTo('addChild');
+ expect(obj).to.respondTo('addChildAt');
+ expect(obj).to.respondTo('swapChildren');
+ expect(obj).to.respondTo('getChildAt');
+ expect(obj).to.respondTo('removeChild');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('children.length', 0);
+}
diff --git a/test/lib/pixi/display/Sprite.js b/test/lib/pixi/display/Sprite.js
new file mode 100644
index 0000000..cc7a2d6
--- /dev/null
+++ b/test/lib/pixi/display/Sprite.js
@@ -0,0 +1,28 @@
+
+function pixi_display_Sprite_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Sprite);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', true);
+ expect(obj).to.have.property('stage', null);
+
+ expect(obj).to.have.property('anchor');
+ pixi_core_Point_confirm(obj.anchor, 0, 0);
+
+ expect(obj).to.have.property('blendMode', PIXI.blendModes.NORMAL);
+ expect(obj).to.have.property('width', 1); // TODO: is 1 expected
+ expect(obj).to.have.property('height', 1); // TODO: is 1 expected
+
+ // FIXME: Just make this a boolean that is always there
+ expect(!!obj.updateFrame).to.equal(obj.texture.baseTexture.hasLoaded);
+
+ expect(obj).to.have.property('texture');
+ pixi_textures_Texture_confirmNew(obj.texture, done);
+}
diff --git a/test/lib/pixi/extras/Strip.js b/test/lib/pixi/extras/Strip.js
new file mode 100644
index 0000000..8927a8a
--- /dev/null
+++ b/test/lib/pixi/extras/Strip.js
@@ -0,0 +1,12 @@
+
+function pixi_extras_Strip_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Strip);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ // TODO: Test properties
+}
diff --git a/test/lib/pixi/textures/Texture.js b/test/lib/pixi/textures/Texture.js
new file mode 100644
index 0000000..d5867b6
--- /dev/null
+++ b/test/lib/pixi/textures/Texture.js
@@ -0,0 +1,31 @@
+
+function pixi_textures_Texture_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ function confirmFrameDone() {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, obj.baseTexture.width, obj.baseTexture.height);
+
+ expect(obj).to.have.property('width', obj.baseTexture.width);
+ expect(obj).to.have.property('height', obj.baseTexture.height);
+ done();
+ }
+
+ expect(obj).to.be.an.instanceof(PIXI.Texture);
+ pixi_utils_EventTarget_like(obj);
+
+ expect(obj).to.have.property('baseTexture')
+ .and.to.be.an.instanceof(PIXI.BaseTexture);
+
+ expect(obj).to.have.property('scope', obj);
+
+ expect(obj).to.have.property('trim');
+ pixi_core_Point_confirm(obj.trim, 0, 0);
+
+ expect(obj).to.have.property('frame');
+ if (obj.baseTexture.hasLoaded) {
+ confirmFrameDone();
+ } else {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, 1, 1);
+ obj.addEventListener('update', confirmFrameDone);
+ }
+}
diff --git a/test/lib/pixi/utils/EventTarget.js b/test/lib/pixi/utils/EventTarget.js
new file mode 100644
index 0000000..7b1dcfa
--- /dev/null
+++ b/test/lib/pixi/utils/EventTarget.js
@@ -0,0 +1,8 @@
+
+function pixi_utils_EventTarget_like(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.respondTo('addEventListener');
+ expect(obj).to.respondTo('dispatchEvent');
+ expect(obj).to.respondTo('removeEventListener');
+}
diff --git a/test/lib/qunit-1.11.0.css b/test/lib/qunit-1.11.0.css
deleted file mode 100644
index d7fc0c8..0000000
--- a/test/lib/qunit-1.11.0.css
+++ /dev/null
@@ -1,244 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-/** Font Family and Sizes */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
- font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
-}
-
-#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
-#qunit-tests { font-size: smaller; }
-
-
-/** Resets */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter {
- margin: 0;
- padding: 0;
-}
-
-
-/** Header */
-
-#qunit-header {
- padding: 0.5em 0 0.5em 1em;
-
- color: #8699a4;
- background-color: #0d3349;
-
- font-size: 1.5em;
- line-height: 1em;
- font-weight: normal;
-
- border-radius: 5px 5px 0 0;
- -moz-border-radius: 5px 5px 0 0;
- -webkit-border-top-right-radius: 5px;
- -webkit-border-top-left-radius: 5px;
-}
-
-#qunit-header a {
- text-decoration: none;
- color: #c2ccd1;
-}
-
-#qunit-header a:hover,
-#qunit-header a:focus {
- color: #fff;
-}
-
-#qunit-testrunner-toolbar label {
- display: inline-block;
- padding: 0 .5em 0 .1em;
-}
-
-#qunit-banner {
- height: 5px;
-}
-
-#qunit-testrunner-toolbar {
- padding: 0.5em 0 0.5em 2em;
- color: #5E740B;
- background-color: #eee;
- overflow: hidden;
-}
-
-#qunit-userAgent {
- padding: 0.5em 0 0.5em 2.5em;
- background-color: #2b81af;
- color: #fff;
- text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
-}
-
-#qunit-modulefilter-container {
- float: right;
-}
-
-/** Tests: Pass/Fail */
-
-#qunit-tests {
- list-style-position: inside;
-}
-
-#qunit-tests li {
- padding: 0.4em 0.5em 0.4em 2.5em;
- border-bottom: 1px solid #fff;
- list-style-position: inside;
-}
-
-#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running {
- display: none;
-}
-
-#qunit-tests li strong {
- cursor: pointer;
-}
-
-#qunit-tests li a {
- padding: 0.5em;
- color: #c2ccd1;
- text-decoration: none;
-}
-#qunit-tests li a:hover,
-#qunit-tests li a:focus {
- color: #000;
-}
-
-#qunit-tests li .runtime {
- float: right;
- font-size: smaller;
-}
-
-.qunit-assert-list {
- margin-top: 0.5em;
- padding: 0.5em;
-
- background-color: #fff;
-
- border-radius: 5px;
- -moz-border-radius: 5px;
- -webkit-border-radius: 5px;
-}
-
-.qunit-collapsed {
- display: none;
-}
-
-#qunit-tests table {
- border-collapse: collapse;
- margin-top: .2em;
-}
-
-#qunit-tests th {
- text-align: right;
- vertical-align: top;
- padding: 0 .5em 0 0;
-}
-
-#qunit-tests td {
- vertical-align: top;
-}
-
-#qunit-tests pre {
- margin: 0;
- white-space: pre-wrap;
- word-wrap: break-word;
-}
-
-#qunit-tests del {
- background-color: #e0f2be;
- color: #374e0c;
- text-decoration: none;
-}
-
-#qunit-tests ins {
- background-color: #ffcaca;
- color: #500;
- text-decoration: none;
-}
-
-/*** Test Counts */
-
-#qunit-tests b.counts { color: black; }
-#qunit-tests b.passed { color: #5E740B; }
-#qunit-tests b.failed { color: #710909; }
-
-#qunit-tests li li {
- padding: 5px;
- background-color: #fff;
- border-bottom: none;
- list-style-position: inside;
-}
-
-/*** Passing Styles */
-
-#qunit-tests li li.pass {
- color: #3c510c;
- background-color: #fff;
- border-left: 10px solid #C6E746;
-}
-
-#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
-#qunit-tests .pass .test-name { color: #366097; }
-
-#qunit-tests .pass .test-actual,
-#qunit-tests .pass .test-expected { color: #999999; }
-
-#qunit-banner.qunit-pass { background-color: #C6E746; }
-
-/*** Failing Styles */
-
-#qunit-tests li li.fail {
- color: #710909;
- background-color: #fff;
- border-left: 10px solid #EE5757;
- white-space: pre;
-}
-
-#qunit-tests > li:last-child {
- border-radius: 0 0 5px 5px;
- -moz-border-radius: 0 0 5px 5px;
- -webkit-border-bottom-right-radius: 5px;
- -webkit-border-bottom-left-radius: 5px;
-}
-
-#qunit-tests .fail { color: #000000; background-color: #EE5757; }
-#qunit-tests .fail .test-name,
-#qunit-tests .fail .module-name { color: #000000; }
-
-#qunit-tests .fail .test-actual { color: #EE5757; }
-#qunit-tests .fail .test-expected { color: green; }
-
-#qunit-banner.qunit-fail { background-color: #EE5757; }
-
-
-/** Result */
-
-#qunit-testresult {
- padding: 0.5em 0.5em 0.5em 2.5em;
-
- color: #2b81af;
- background-color: #D2E0E6;
-
- border-bottom: 1px solid white;
-}
-#qunit-testresult .module-name {
- font-weight: bold;
-}
-
-/** Fixture */
-
-#qunit-fixture {
- position: absolute;
- top: -10000px;
- left: -10000px;
- width: 1000px;
- height: 1000px;
-}
diff --git a/test/lib/qunit-1.11.0.js b/test/lib/qunit-1.11.0.js
deleted file mode 100644
index 302545f..0000000
--- a/test/lib/qunit-1.11.0.js
+++ /dev/null
@@ -1,2152 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-(function( window ) {
-
-var QUnit,
- assert,
- config,
- onErrorFnPrev,
- testId = 0,
- fileName = (sourceFromStacktrace( 0 ) || "" ).replace(/(:\d+)+\)?/, "").replace(/.+\//, ""),
- toString = Object.prototype.toString,
- hasOwn = Object.prototype.hasOwnProperty,
- // Keep a local reference to Date (GH-283)
- Date = window.Date,
- defined = {
- setTimeout: typeof window.setTimeout !== "undefined",
- sessionStorage: (function() {
- var x = "qunit-test-string";
- try {
- sessionStorage.setItem( x, x );
- sessionStorage.removeItem( x );
- return true;
- } catch( e ) {
- return false;
- }
- }())
- },
- /**
- * Provides a normalized error string, correcting an issue
- * with IE 7 (and prior) where Error.prototype.toString is
- * not properly implemented
- *
- * Based on http://es5.github.com/#x15.11.4.4
- *
- * @param {String|Error} error
- * @return {String} error message
- */
- errorString = function( error ) {
- var name, message,
- errorString = error.toString();
- if ( errorString.substring( 0, 7 ) === "[object" ) {
- name = error.name ? error.name.toString() : "Error";
- message = error.message ? error.message.toString() : "";
- if ( name && message ) {
- return name + ": " + message;
- } else if ( name ) {
- return name;
- } else if ( message ) {
- return message;
- } else {
- return "Error";
- }
- } else {
- return errorString;
- }
- },
- /**
- * Makes a clone of an object using only Array or Object as base,
- * and copies over the own enumerable properties.
- *
- * @param {Object} obj
- * @return {Object} New object with only the own properties (recursively).
- */
- objectValues = function( obj ) {
- // Grunt 0.3.x uses an older version of jshint that still has jshint/jshint#392.
- /*jshint newcap: false */
- var key, val,
- vals = QUnit.is( "array", obj ) ? [] : {};
- for ( key in obj ) {
- if ( hasOwn.call( obj, key ) ) {
- val = obj[key];
- vals[key] = val === Object(val) ? objectValues(val) : val;
- }
- }
- return vals;
- };
-
-function Test( settings ) {
- extend( this, settings );
- this.assertions = [];
- this.testNumber = ++Test.count;
-}
-
-Test.count = 0;
-
-Test.prototype = {
- init: function() {
- var a, b, li,
- tests = id( "qunit-tests" );
-
- if ( tests ) {
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml;
-
- // `a` initialized at top of scope
- a = document.createElement( "a" );
- a.innerHTML = "Rerun";
- a.href = QUnit.url({ testNumber: this.testNumber });
-
- li = document.createElement( "li" );
- li.appendChild( b );
- li.appendChild( a );
- li.className = "running";
- li.id = this.id = "qunit-test-output" + testId++;
-
- tests.appendChild( li );
- }
- },
- setup: function() {
- if ( this.module !== config.previousModule ) {
- if ( config.previousModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.previousModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
- config.previousModule = this.module;
- config.moduleStats = { all: 0, bad: 0 };
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- } else if ( config.autorun ) {
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- }
-
- config.current = this;
-
- this.testEnvironment = extend({
- setup: function() {},
- teardown: function() {}
- }, this.moduleTestEnvironment );
-
- this.started = +new Date();
- runLoggingCallbacks( "testStart", QUnit, {
- name: this.testName,
- module: this.module
- });
-
- // allow utility functions to access the current test environment
- // TODO why??
- QUnit.current_testEnvironment = this.testEnvironment;
-
- if ( !config.pollution ) {
- saveGlobal();
- }
- if ( config.notrycatch ) {
- this.testEnvironment.setup.call( this.testEnvironment );
- return;
- }
- try {
- this.testEnvironment.setup.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Setup failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- },
- run: function() {
- config.current = this;
-
- var running = id( "qunit-testresult" );
-
- if ( running ) {
- running.innerHTML = "Running:
" + this.nameHtml;
- }
-
- if ( this.async ) {
- QUnit.stop();
- }
-
- this.callbackStarted = +new Date();
-
- if ( config.notrycatch ) {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- return;
- }
-
- try {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- } catch( e ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
-
- QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + " " + this.stack + ": " + ( e.message || e ), extractStacktrace( e, 0 ) );
- // else next test will carry the responsibility
- saveGlobal();
-
- // Restart the tests if they're blocking
- if ( config.blocking ) {
- QUnit.start();
- }
- }
- },
- teardown: function() {
- config.current = this;
- if ( config.notrycatch ) {
- if ( typeof this.callbackRuntime === "undefined" ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
- }
- this.testEnvironment.teardown.call( this.testEnvironment );
- return;
- } else {
- try {
- this.testEnvironment.teardown.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Teardown failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- }
- checkPollution();
- },
- finish: function() {
- config.current = this;
- if ( config.requireExpects && this.expected === null ) {
- QUnit.pushFailure( "Expected number of assertions to be defined, but expect() was not called.", this.stack );
- } else if ( this.expected !== null && this.expected !== this.assertions.length ) {
- QUnit.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack );
- } else if ( this.expected === null && !this.assertions.length ) {
- QUnit.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions.", this.stack );
- }
-
- var i, assertion, a, b, time, li, ol,
- test = this,
- good = 0,
- bad = 0,
- tests = id( "qunit-tests" );
-
- this.runtime = +new Date() - this.started;
- config.stats.all += this.assertions.length;
- config.moduleStats.all += this.assertions.length;
-
- if ( tests ) {
- ol = document.createElement( "ol" );
- ol.className = "qunit-assert-list";
-
- for ( i = 0; i < this.assertions.length; i++ ) {
- assertion = this.assertions[i];
-
- li = document.createElement( "li" );
- li.className = assertion.result ? "pass" : "fail";
- li.innerHTML = assertion.message || ( assertion.result ? "okay" : "failed" );
- ol.appendChild( li );
-
- if ( assertion.result ) {
- good++;
- } else {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
-
- // store result when possible
- if ( QUnit.config.reorder && defined.sessionStorage ) {
- if ( bad ) {
- sessionStorage.setItem( "qunit-test-" + this.module + "-" + this.testName, bad );
- } else {
- sessionStorage.removeItem( "qunit-test-" + this.module + "-" + this.testName );
- }
- }
-
- if ( bad === 0 ) {
- addClass( ol, "qunit-collapsed" );
- }
-
- // `b` initialized at top of scope
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml + " (" + bad + ", " + good + ", " + this.assertions.length + ")";
-
- addEvent(b, "click", function() {
- var next = b.parentNode.lastChild,
- collapsed = hasClass( next, "qunit-collapsed" );
- ( collapsed ? removeClass : addClass )( next, "qunit-collapsed" );
- });
-
- addEvent(b, "dblclick", function( e ) {
- var target = e && e.target ? e.target : window.event.srcElement;
- if ( target.nodeName.toLowerCase() === "span" || target.nodeName.toLowerCase() === "b" ) {
- target = target.parentNode;
- }
- if ( window.location && target.nodeName.toLowerCase() === "strong" ) {
- window.location = QUnit.url({ testNumber: test.testNumber });
- }
- });
-
- // `time` initialized at top of scope
- time = document.createElement( "span" );
- time.className = "runtime";
- time.innerHTML = this.runtime + " ms";
-
- // `li` initialized at top of scope
- li = id( this.id );
- li.className = bad ? "fail" : "pass";
- li.removeChild( li.firstChild );
- a = li.firstChild;
- li.appendChild( b );
- li.appendChild( a );
- li.appendChild( time );
- li.appendChild( ol );
-
- } else {
- for ( i = 0; i < this.assertions.length; i++ ) {
- if ( !this.assertions[i].result ) {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
- }
-
- runLoggingCallbacks( "testDone", QUnit, {
- name: this.testName,
- module: this.module,
- failed: bad,
- passed: this.assertions.length - bad,
- total: this.assertions.length,
- duration: this.runtime
- });
-
- QUnit.reset();
-
- config.current = undefined;
- },
-
- queue: function() {
- var bad,
- test = this;
-
- synchronize(function() {
- test.init();
- });
- function run() {
- // each of these can by async
- synchronize(function() {
- test.setup();
- });
- synchronize(function() {
- test.run();
- });
- synchronize(function() {
- test.teardown();
- });
- synchronize(function() {
- test.finish();
- });
- }
-
- // `bad` initialized at top of scope
- // defer when previous test run passed, if storage is available
- bad = QUnit.config.reorder && defined.sessionStorage &&
- +sessionStorage.getItem( "qunit-test-" + this.module + "-" + this.testName );
-
- if ( bad ) {
- run();
- } else {
- synchronize( run, true );
- }
- }
-};
-
-// Root QUnit object.
-// `QUnit` initialized at top of scope
-QUnit = {
-
- // call on start of module test to prepend name to all tests
- module: function( name, testEnvironment ) {
- config.currentModule = name;
- config.currentModuleTestEnvironment = testEnvironment;
- config.modules[name] = true;
- },
-
- asyncTest: function( testName, expected, callback ) {
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- QUnit.test( testName, expected, callback, true );
- },
-
- test: function( testName, expected, callback, async ) {
- var test,
- nameHtml = "" + escapeText( testName ) + "";
-
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- if ( config.currentModule ) {
- nameHtml = "" + escapeText( config.currentModule ) + ": " + nameHtml;
- }
-
- test = new Test({
- nameHtml: nameHtml,
- testName: testName,
- expected: expected,
- async: async,
- callback: callback,
- module: config.currentModule,
- moduleTestEnvironment: config.currentModuleTestEnvironment,
- stack: sourceFromStacktrace( 2 )
- });
-
- if ( !validTest( test ) ) {
- return;
- }
-
- test.queue();
- },
-
- // Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through.
- expect: function( asserts ) {
- if (arguments.length === 1) {
- config.current.expected = asserts;
- } else {
- return config.current.expected;
- }
- },
-
- start: function( count ) {
- // QUnit hasn't been initialized yet.
- // Note: RequireJS (et al) may delay onLoad
- if ( config.semaphore === undefined ) {
- QUnit.begin(function() {
- // This is triggered at the top of QUnit.load, push start() to the event loop, to allow QUnit.load to finish first
- setTimeout(function() {
- QUnit.start( count );
- });
- });
- return;
- }
-
- config.semaphore -= count || 1;
- // don't start until equal number of stop-calls
- if ( config.semaphore > 0 ) {
- return;
- }
- // ignore if start is called more often then stop
- if ( config.semaphore < 0 ) {
- config.semaphore = 0;
- QUnit.pushFailure( "Called start() while already started (QUnit.config.semaphore was 0 already)", null, sourceFromStacktrace(2) );
- return;
- }
- // A slight delay, to avoid any current callbacks
- if ( defined.setTimeout ) {
- window.setTimeout(function() {
- if ( config.semaphore > 0 ) {
- return;
- }
- if ( config.timeout ) {
- clearTimeout( config.timeout );
- }
-
- config.blocking = false;
- process( true );
- }, 13);
- } else {
- config.blocking = false;
- process( true );
- }
- },
-
- stop: function( count ) {
- config.semaphore += count || 1;
- config.blocking = true;
-
- if ( config.testTimeout && defined.setTimeout ) {
- clearTimeout( config.timeout );
- config.timeout = window.setTimeout(function() {
- QUnit.ok( false, "Test timed out" );
- config.semaphore = 1;
- QUnit.start();
- }, config.testTimeout );
- }
- }
-};
-
-// `assert` initialized at top of scope
-// Asssert helpers
-// All of these must either call QUnit.push() or manually do:
-// - runLoggingCallbacks( "log", .. );
-// - config.current.assertions.push({ .. });
-// We attach it to the QUnit object *after* we expose the public API,
-// otherwise `assert` will become a global variable in browsers (#341).
-assert = {
- /**
- * Asserts rough true-ish result.
- * @name ok
- * @function
- * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" );
- */
- ok: function( result, msg ) {
- if ( !config.current ) {
- throw new Error( "ok() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
- result = !!result;
-
- var source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: msg
- };
-
- msg = escapeText( msg || (result ? "okay" : "failed" ) );
- msg = "" + msg + "";
-
- if ( !result ) {
- source = sourceFromStacktrace( 2 );
- if ( source ) {
- details.source = source;
- msg += "Source: | " + escapeText( source ) + " |
---|
";
- }
- }
- runLoggingCallbacks( "log", QUnit, details );
- config.current.assertions.push({
- result: result,
- message: msg
- });
- },
-
- /**
- * Assert that the first two arguments are equal, with an optional message.
- * Prints out both actual and expected values.
- * @name equal
- * @function
- * @example equal( format( "Received {0} bytes.", 2), "Received 2 bytes.", "format() replaces {0} with next argument" );
- */
- equal: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected == actual, actual, expected, message );
- },
-
- /**
- * @name notEqual
- * @function
- */
- notEqual: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected != actual, actual, expected, message );
- },
-
- /**
- * @name propEqual
- * @function
- */
- propEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notPropEqual
- * @function
- */
- notPropEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name deepEqual
- * @function
- */
- deepEqual: function( actual, expected, message ) {
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notDeepEqual
- * @function
- */
- notDeepEqual: function( actual, expected, message ) {
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name strictEqual
- * @function
- */
- strictEqual: function( actual, expected, message ) {
- QUnit.push( expected === actual, actual, expected, message );
- },
-
- /**
- * @name notStrictEqual
- * @function
- */
- notStrictEqual: function( actual, expected, message ) {
- QUnit.push( expected !== actual, actual, expected, message );
- },
-
- "throws": function( block, expected, message ) {
- var actual,
- expectedOutput = expected,
- ok = false;
-
- // 'expected' is optional
- if ( typeof expected === "string" ) {
- message = expected;
- expected = null;
- }
-
- config.current.ignoreGlobalErrors = true;
- try {
- block.call( config.current.testEnvironment );
- } catch (e) {
- actual = e;
- }
- config.current.ignoreGlobalErrors = false;
-
- if ( actual ) {
- // we don't want to validate thrown error
- if ( !expected ) {
- ok = true;
- expectedOutput = null;
- // expected is a regexp
- } else if ( QUnit.objectType( expected ) === "regexp" ) {
- ok = expected.test( errorString( actual ) );
- // expected is a constructor
- } else if ( actual instanceof expected ) {
- ok = true;
- // expected is a validation function which returns true is validation passed
- } else if ( expected.call( {}, actual ) === true ) {
- expectedOutput = null;
- ok = true;
- }
-
- QUnit.push( ok, actual, expectedOutput, message );
- } else {
- QUnit.pushFailure( message, null, 'No exception was thrown.' );
- }
- }
-};
-
-/**
- * @deprecate since 1.8.0
- * Kept assertion helpers in root for backwards compatibility.
- */
-extend( QUnit, assert );
-
-/**
- * @deprecated since 1.9.0
- * Kept root "raises()" for backwards compatibility.
- * (Note that we don't introduce assert.raises).
- */
-QUnit.raises = assert[ "throws" ];
-
-/**
- * @deprecated since 1.0.0, replaced with error pushes since 1.3.0
- * Kept to avoid TypeErrors for undefined methods.
- */
-QUnit.equals = function() {
- QUnit.push( false, false, false, "QUnit.equals has been deprecated since 2009 (e88049a0), use QUnit.equal instead" );
-};
-QUnit.same = function() {
- QUnit.push( false, false, false, "QUnit.same has been deprecated since 2009 (e88049a0), use QUnit.deepEqual instead" );
-};
-
-// We want access to the constructor's prototype
-(function() {
- function F() {}
- F.prototype = QUnit;
- QUnit = new F();
- // Make F QUnit's constructor so that we can add to the prototype later
- QUnit.constructor = F;
-}());
-
-/**
- * Config object: Maintain internal state
- * Later exposed as QUnit.config
- * `config` initialized at top of scope
- */
-config = {
- // The queue of tests to run
- queue: [],
-
- // block until document ready
- blocking: true,
-
- // when enabled, show only failing tests
- // gets persisted through sessionStorage and can be changed in UI via checkbox
- hidepassed: false,
-
- // by default, run previously failed tests first
- // very useful in combination with "Hide passed tests" checked
- reorder: true,
-
- // by default, modify document.title when suite is done
- altertitle: true,
-
- // when enabled, all tests must call expect()
- requireExpects: false,
-
- // add checkboxes that are persisted in the query-string
- // when enabled, the id is set to `true` as a `QUnit.config` property
- urlConfig: [
- {
- id: "noglobals",
- label: "Check for Globals",
- tooltip: "Enabling this will test if any test introduces new properties on the `window` object. Stored as query-strings."
- },
- {
- id: "notrycatch",
- label: "No try-catch",
- tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging exceptions in IE reasonable. Stored as query-strings."
- }
- ],
-
- // Set of all modules.
- modules: {},
-
- // logging callback queues
- begin: [],
- done: [],
- log: [],
- testStart: [],
- testDone: [],
- moduleStart: [],
- moduleDone: []
-};
-
-// Export global variables, unless an 'exports' object exists,
-// in that case we assume we're in CommonJS (dealt with on the bottom of the script)
-if ( typeof exports === "undefined" ) {
- extend( window, QUnit );
-
- // Expose QUnit object
- window.QUnit = QUnit;
-}
-
-// Initialize more QUnit.config and QUnit.urlParams
-(function() {
- var i,
- location = window.location || { search: "", protocol: "file:" },
- params = location.search.slice( 1 ).split( "&" ),
- length = params.length,
- urlParams = {},
- current;
-
- if ( params[ 0 ] ) {
- for ( i = 0; i < length; i++ ) {
- current = params[ i ].split( "=" );
- current[ 0 ] = decodeURIComponent( current[ 0 ] );
- // allow just a key to turn on a flag, e.g., test.html?noglobals
- current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true;
- urlParams[ current[ 0 ] ] = current[ 1 ];
- }
- }
-
- QUnit.urlParams = urlParams;
-
- // String search anywhere in moduleName+testName
- config.filter = urlParams.filter;
-
- // Exact match of the module name
- config.module = urlParams.module;
-
- config.testNumber = parseInt( urlParams.testNumber, 10 ) || null;
-
- // Figure out if we're running the tests from a server or not
- QUnit.isLocal = location.protocol === "file:";
-}());
-
-// Extend QUnit object,
-// these after set here because they should not be exposed as global functions
-extend( QUnit, {
- assert: assert,
-
- config: config,
-
- // Initialize the configuration options
- init: function() {
- extend( config, {
- stats: { all: 0, bad: 0 },
- moduleStats: { all: 0, bad: 0 },
- started: +new Date(),
- updateRate: 1000,
- blocking: false,
- autostart: true,
- autorun: false,
- filter: "",
- queue: [],
- semaphore: 1
- });
-
- var tests, banner, result,
- qunit = id( "qunit" );
-
- if ( qunit ) {
- qunit.innerHTML =
- "" +
- "" +
- "" +
- "" +
- "
";
- }
-
- tests = id( "qunit-tests" );
- banner = id( "qunit-banner" );
- result = id( "qunit-testresult" );
-
- if ( tests ) {
- tests.innerHTML = "";
- }
-
- if ( banner ) {
- banner.className = "";
- }
-
- if ( result ) {
- result.parentNode.removeChild( result );
- }
-
- if ( tests ) {
- result = document.createElement( "p" );
- result.id = "qunit-testresult";
- result.className = "result";
- tests.parentNode.insertBefore( result, tests );
- result.innerHTML = "Running...
";
- }
- },
-
- // Resets the test setup. Useful for tests that modify the DOM.
- reset: function() {
- var fixture = id( "qunit-fixture" );
- if ( fixture ) {
- fixture.innerHTML = config.fixture;
- }
- },
-
- // Trigger an event on an element.
- // @example triggerEvent( document.body, "click" );
- triggerEvent: function( elem, type, event ) {
- if ( document.createEvent ) {
- event = document.createEvent( "MouseEvents" );
- event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView,
- 0, 0, 0, 0, 0, false, false, false, false, 0, null);
-
- elem.dispatchEvent( event );
- } else if ( elem.fireEvent ) {
- elem.fireEvent( "on" + type );
- }
- },
-
- // Safe object type checking
- is: function( type, obj ) {
- return QUnit.objectType( obj ) === type;
- },
-
- objectType: function( obj ) {
- if ( typeof obj === "undefined" ) {
- return "undefined";
- // consider: typeof null === object
- }
- if ( obj === null ) {
- return "null";
- }
-
- var match = toString.call( obj ).match(/^\[object\s(.*)\]$/),
- type = match && match[1] || "";
-
- switch ( type ) {
- case "Number":
- if ( isNaN(obj) ) {
- return "nan";
- }
- return "number";
- case "String":
- case "Boolean":
- case "Array":
- case "Date":
- case "RegExp":
- case "Function":
- return type.toLowerCase();
- }
- if ( typeof obj === "object" ) {
- return "object";
- }
- return undefined;
- },
-
- push: function( result, actual, expected, message ) {
- if ( !config.current ) {
- throw new Error( "assertion outside test context, was " + sourceFromStacktrace() );
- }
-
- var output, source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: message,
- actual: actual,
- expected: expected
- };
-
- message = escapeText( message ) || ( result ? "okay" : "failed" );
- message = "" + message + "";
- output = message;
-
- if ( !result ) {
- expected = escapeText( QUnit.jsDump.parse(expected) );
- actual = escapeText( QUnit.jsDump.parse(actual) );
- output += "Expected: | " + expected + " |
";
-
- if ( actual !== expected ) {
- output += "Result: | " + actual + " |
";
- output += "Diff: | " + QUnit.diff( expected, actual ) + " |
";
- }
-
- source = sourceFromStacktrace();
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
- }
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: !!result,
- message: output
- });
- },
-
- pushFailure: function( message, source, actual ) {
- if ( !config.current ) {
- throw new Error( "pushFailure() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
-
- var output,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: false,
- message: message
- };
-
- message = escapeText( message ) || "error";
- message = "" + message + "";
- output = message;
-
- output += "";
-
- if ( actual ) {
- output += "Result: | " + escapeText( actual ) + " |
";
- }
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: false,
- message: output
- });
- },
-
- url: function( params ) {
- params = extend( extend( {}, QUnit.urlParams ), params );
- var key,
- querystring = "?";
-
- for ( key in params ) {
- if ( !hasOwn.call( params, key ) ) {
- continue;
- }
- querystring += encodeURIComponent( key ) + "=" +
- encodeURIComponent( params[ key ] ) + "&";
- }
- return window.location.protocol + "//" + window.location.host +
- window.location.pathname + querystring.slice( 0, -1 );
- },
-
- extend: extend,
- id: id,
- addEvent: addEvent
- // load, equiv, jsDump, diff: Attached later
-});
-
-/**
- * @deprecated: Created for backwards compatibility with test runner that set the hook function
- * into QUnit.{hook}, instead of invoking it and passing the hook function.
- * QUnit.constructor is set to the empty F() above so that we can add to it's prototype here.
- * Doing this allows us to tell if the following methods have been overwritten on the actual
- * QUnit object.
- */
-extend( QUnit.constructor.prototype, {
-
- // Logging callbacks; all receive a single argument with the listed properties
- // run test/logs.html for any related changes
- begin: registerLoggingCallback( "begin" ),
-
- // done: { failed, passed, total, runtime }
- done: registerLoggingCallback( "done" ),
-
- // log: { result, actual, expected, message }
- log: registerLoggingCallback( "log" ),
-
- // testStart: { name }
- testStart: registerLoggingCallback( "testStart" ),
-
- // testDone: { name, failed, passed, total, duration }
- testDone: registerLoggingCallback( "testDone" ),
-
- // moduleStart: { name }
- moduleStart: registerLoggingCallback( "moduleStart" ),
-
- // moduleDone: { name, failed, passed, total }
- moduleDone: registerLoggingCallback( "moduleDone" )
-});
-
-if ( typeof document === "undefined" || document.readyState === "complete" ) {
- config.autorun = true;
-}
-
-QUnit.load = function() {
- runLoggingCallbacks( "begin", QUnit, {} );
-
- // Initialize the config, saving the execution queue
- var banner, filter, i, label, len, main, ol, toolbar, userAgent, val,
- urlConfigCheckboxesContainer, urlConfigCheckboxes, moduleFilter,
- numModules = 0,
- moduleFilterHtml = "",
- urlConfigHtml = "",
- oldconfig = extend( {}, config );
-
- QUnit.init();
- extend(config, oldconfig);
-
- config.blocking = false;
-
- len = config.urlConfig.length;
-
- for ( i = 0; i < len; i++ ) {
- val = config.urlConfig[i];
- if ( typeof val === "string" ) {
- val = {
- id: val,
- label: val,
- tooltip: "[no tooltip available]"
- };
- }
- config[ val.id ] = QUnit.urlParams[ val.id ];
- urlConfigHtml += "";
- }
-
- moduleFilterHtml += "";
-
- // `userAgent` initialized at top of scope
- userAgent = id( "qunit-userAgent" );
- if ( userAgent ) {
- userAgent.innerHTML = navigator.userAgent;
- }
-
- // `banner` initialized at top of scope
- banner = id( "qunit-header" );
- if ( banner ) {
- banner.innerHTML = "" + banner.innerHTML + " ";
- }
-
- // `toolbar` initialized at top of scope
- toolbar = id( "qunit-testrunner-toolbar" );
- if ( toolbar ) {
- // `filter` initialized at top of scope
- filter = document.createElement( "input" );
- filter.type = "checkbox";
- filter.id = "qunit-filter-pass";
-
- addEvent( filter, "click", function() {
- var tmp,
- ol = document.getElementById( "qunit-tests" );
-
- if ( filter.checked ) {
- ol.className = ol.className + " hidepass";
- } else {
- tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " ";
- ol.className = tmp.replace( / hidepass /, " " );
- }
- if ( defined.sessionStorage ) {
- if (filter.checked) {
- sessionStorage.setItem( "qunit-filter-passed-tests", "true" );
- } else {
- sessionStorage.removeItem( "qunit-filter-passed-tests" );
- }
- }
- });
-
- if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem( "qunit-filter-passed-tests" ) ) {
- filter.checked = true;
- // `ol` initialized at top of scope
- ol = document.getElementById( "qunit-tests" );
- ol.className = ol.className + " hidepass";
- }
- toolbar.appendChild( filter );
-
- // `label` initialized at top of scope
- label = document.createElement( "label" );
- label.setAttribute( "for", "qunit-filter-pass" );
- label.setAttribute( "title", "Only show tests and assertons that fail. Stored in sessionStorage." );
- label.innerHTML = "Hide passed tests";
- toolbar.appendChild( label );
-
- urlConfigCheckboxesContainer = document.createElement("span");
- urlConfigCheckboxesContainer.innerHTML = urlConfigHtml;
- urlConfigCheckboxes = urlConfigCheckboxesContainer.getElementsByTagName("input");
- // For oldIE support:
- // * Add handlers to the individual elements instead of the container
- // * Use "click" instead of "change"
- // * Fallback from event.target to event.srcElement
- addEvents( urlConfigCheckboxes, "click", function( event ) {
- var params = {},
- target = event.target || event.srcElement;
- params[ target.name ] = target.checked ? true : undefined;
- window.location = QUnit.url( params );
- });
- toolbar.appendChild( urlConfigCheckboxesContainer );
-
- if (numModules > 1) {
- moduleFilter = document.createElement( 'span' );
- moduleFilter.setAttribute( 'id', 'qunit-modulefilter-container' );
- moduleFilter.innerHTML = moduleFilterHtml;
- addEvent( moduleFilter.lastChild, "change", function() {
- var selectBox = moduleFilter.getElementsByTagName("select")[0],
- selectedModule = decodeURIComponent(selectBox.options[selectBox.selectedIndex].value);
-
- window.location = QUnit.url( { module: ( selectedModule === "" ) ? undefined : selectedModule } );
- });
- toolbar.appendChild(moduleFilter);
- }
- }
-
- // `main` initialized at top of scope
- main = id( "qunit-fixture" );
- if ( main ) {
- config.fixture = main.innerHTML;
- }
-
- if ( config.autostart ) {
- QUnit.start();
- }
-};
-
-addEvent( window, "load", QUnit.load );
-
-// `onErrorFnPrev` initialized at top of scope
-// Preserve other handlers
-onErrorFnPrev = window.onerror;
-
-// Cover uncaught exceptions
-// Returning true will surpress the default browser handler,
-// returning false will let it run.
-window.onerror = function ( error, filePath, linerNr ) {
- var ret = false;
- if ( onErrorFnPrev ) {
- ret = onErrorFnPrev( error, filePath, linerNr );
- }
-
- // Treat return value as window.onerror itself does,
- // Only do our handling if not surpressed.
- if ( ret !== true ) {
- if ( QUnit.config.current ) {
- if ( QUnit.config.current.ignoreGlobalErrors ) {
- return true;
- }
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- } else {
- QUnit.test( "global failure", extend( function() {
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- }, { validTest: validTest } ) );
- }
- return false;
- }
-
- return ret;
-};
-
-function done() {
- config.autorun = true;
-
- // Log the last module results
- if ( config.currentModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.currentModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
-
- var i, key,
- banner = id( "qunit-banner" ),
- tests = id( "qunit-tests" ),
- runtime = +new Date() - config.started,
- passed = config.stats.all - config.stats.bad,
- html = [
- "Tests completed in ",
- runtime,
- " milliseconds.
",
- "",
- passed,
- " assertions of ",
- config.stats.all,
- " passed, ",
- config.stats.bad,
- " failed."
- ].join( "" );
-
- if ( banner ) {
- banner.className = ( config.stats.bad ? "qunit-fail" : "qunit-pass" );
- }
-
- if ( tests ) {
- id( "qunit-testresult" ).innerHTML = html;
- }
-
- if ( config.altertitle && typeof document !== "undefined" && document.title ) {
- // show ✖ for good, ✔ for bad suite result in title
- // use escape sequences in case file gets loaded with non-utf-8-charset
- document.title = [
- ( config.stats.bad ? "\u2716" : "\u2714" ),
- document.title.replace( /^[\u2714\u2716] /i, "" )
- ].join( " " );
- }
-
- // clear own sessionStorage items if all tests passed
- if ( config.reorder && defined.sessionStorage && config.stats.bad === 0 ) {
- // `key` & `i` initialized at top of scope
- for ( i = 0; i < sessionStorage.length; i++ ) {
- key = sessionStorage.key( i++ );
- if ( key.indexOf( "qunit-test-" ) === 0 ) {
- sessionStorage.removeItem( key );
- }
- }
- }
-
- // scroll back to top to show results
- if ( window.scrollTo ) {
- window.scrollTo(0, 0);
- }
-
- runLoggingCallbacks( "done", QUnit, {
- failed: config.stats.bad,
- passed: passed,
- total: config.stats.all,
- runtime: runtime
- });
-}
-
-/** @return Boolean: true if this test should be ran */
-function validTest( test ) {
- var include,
- filter = config.filter && config.filter.toLowerCase(),
- module = config.module && config.module.toLowerCase(),
- fullName = (test.module + ": " + test.testName).toLowerCase();
-
- // Internally-generated tests are always valid
- if ( test.callback && test.callback.validTest === validTest ) {
- delete test.callback.validTest;
- return true;
- }
-
- if ( config.testNumber ) {
- return test.testNumber === config.testNumber;
- }
-
- if ( module && ( !test.module || test.module.toLowerCase() !== module ) ) {
- return false;
- }
-
- if ( !filter ) {
- return true;
- }
-
- include = filter.charAt( 0 ) !== "!";
- if ( !include ) {
- filter = filter.slice( 1 );
- }
-
- // If the filter matches, we need to honour include
- if ( fullName.indexOf( filter ) !== -1 ) {
- return include;
- }
-
- // Otherwise, do the opposite
- return !include;
-}
-
-// so far supports only Firefox, Chrome and Opera (buggy), Safari (for real exceptions)
-// Later Safari and IE10 are supposed to support error.stack as well
-// See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack
-function extractStacktrace( e, offset ) {
- offset = offset === undefined ? 3 : offset;
-
- var stack, include, i;
-
- if ( e.stacktrace ) {
- // Opera
- return e.stacktrace.split( "\n" )[ offset + 3 ];
- } else if ( e.stack ) {
- // Firefox, Chrome
- stack = e.stack.split( "\n" );
- if (/^error$/i.test( stack[0] ) ) {
- stack.shift();
- }
- if ( fileName ) {
- include = [];
- for ( i = offset; i < stack.length; i++ ) {
- if ( stack[ i ].indexOf( fileName ) !== -1 ) {
- break;
- }
- include.push( stack[ i ] );
- }
- if ( include.length ) {
- return include.join( "\n" );
- }
- }
- return stack[ offset ];
- } else if ( e.sourceURL ) {
- // Safari, PhantomJS
- // hopefully one day Safari provides actual stacktraces
- // exclude useless self-reference for generated Error objects
- if ( /qunit.js$/.test( e.sourceURL ) ) {
- return;
- }
- // for actual exceptions, this is useful
- return e.sourceURL + ":" + e.line;
- }
-}
-function sourceFromStacktrace( offset ) {
- try {
- throw new Error();
- } catch ( e ) {
- return extractStacktrace( e, offset );
- }
-}
-
-/**
- * Escape text for attribute or text content.
- */
-function escapeText( s ) {
- if ( !s ) {
- return "";
- }
- s = s + "";
- // Both single quotes and double quotes (for attributes)
- return s.replace( /['"<>&]/g, function( s ) {
- switch( s ) {
- case '\'':
- return ''';
- case '"':
- return '"';
- case '<':
- return '<';
- case '>':
- return '>';
- case '&':
- return '&';
- }
- });
-}
-
-function synchronize( callback, last ) {
- config.queue.push( callback );
-
- if ( config.autorun && !config.blocking ) {
- process( last );
- }
-}
-
-function process( last ) {
- function next() {
- process( last );
- }
- var start = new Date().getTime();
- config.depth = config.depth ? config.depth + 1 : 1;
-
- while ( config.queue.length && !config.blocking ) {
- if ( !defined.setTimeout || config.updateRate <= 0 || ( ( new Date().getTime() - start ) < config.updateRate ) ) {
- config.queue.shift()();
- } else {
- window.setTimeout( next, 13 );
- break;
- }
- }
- config.depth--;
- if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) {
- done();
- }
-}
-
-function saveGlobal() {
- config.pollution = [];
-
- if ( config.noglobals ) {
- for ( var key in window ) {
- // in Opera sometimes DOM element ids show up here, ignore them
- if ( !hasOwn.call( window, key ) || /^qunit-test-output/.test( key ) ) {
- continue;
- }
- config.pollution.push( key );
- }
- }
-}
-
-function checkPollution() {
- var newGlobals,
- deletedGlobals,
- old = config.pollution;
-
- saveGlobal();
-
- newGlobals = diff( config.pollution, old );
- if ( newGlobals.length > 0 ) {
- QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join(", ") );
- }
-
- deletedGlobals = diff( old, config.pollution );
- if ( deletedGlobals.length > 0 ) {
- QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join(", ") );
- }
-}
-
-// returns a new Array with the elements that are in a but not in b
-function diff( a, b ) {
- var i, j,
- result = a.slice();
-
- for ( i = 0; i < result.length; i++ ) {
- for ( j = 0; j < b.length; j++ ) {
- if ( result[i] === b[j] ) {
- result.splice( i, 1 );
- i--;
- break;
- }
- }
- }
- return result;
-}
-
-function extend( a, b ) {
- for ( var prop in b ) {
- if ( b[ prop ] === undefined ) {
- delete a[ prop ];
-
- // Avoid "Member not found" error in IE8 caused by setting window.constructor
- } else if ( prop !== "constructor" || a !== window ) {
- a[ prop ] = b[ prop ];
- }
- }
-
- return a;
-}
-
-/**
- * @param {HTMLElement} elem
- * @param {string} type
- * @param {Function} fn
- */
-function addEvent( elem, type, fn ) {
- // Standards-based browsers
- if ( elem.addEventListener ) {
- elem.addEventListener( type, fn, false );
- // IE
- } else {
- elem.attachEvent( "on" + type, fn );
- }
-}
-
-/**
- * @param {Array|NodeList} elems
- * @param {string} type
- * @param {Function} fn
- */
-function addEvents( elems, type, fn ) {
- var i = elems.length;
- while ( i-- ) {
- addEvent( elems[i], type, fn );
- }
-}
-
-function hasClass( elem, name ) {
- return (" " + elem.className + " ").indexOf(" " + name + " ") > -1;
-}
-
-function addClass( elem, name ) {
- if ( !hasClass( elem, name ) ) {
- elem.className += (elem.className ? " " : "") + name;
- }
-}
-
-function removeClass( elem, name ) {
- var set = " " + elem.className + " ";
- // Class name may appear multiple times
- while ( set.indexOf(" " + name + " ") > -1 ) {
- set = set.replace(" " + name + " " , " ");
- }
- // If possible, trim it for prettiness, but not neccecarily
- elem.className = window.jQuery ? jQuery.trim( set ) : ( set.trim ? set.trim() : set );
-}
-
-function id( name ) {
- return !!( typeof document !== "undefined" && document && document.getElementById ) &&
- document.getElementById( name );
-}
-
-function registerLoggingCallback( key ) {
- return function( callback ) {
- config[key].push( callback );
- };
-}
-
-// Supports deprecated method of completely overwriting logging callbacks
-function runLoggingCallbacks( key, scope, args ) {
- var i, callbacks;
- if ( QUnit.hasOwnProperty( key ) ) {
- QUnit[ key ].call(scope, args );
- } else {
- callbacks = config[ key ];
- for ( i = 0; i < callbacks.length; i++ ) {
- callbacks[ i ].call( scope, args );
- }
- }
-}
-
-// Test for equality any JavaScript type.
-// Author: Philippe Rathé
-QUnit.equiv = (function() {
-
- // Call the o related callback with the given arguments.
- function bindCallbacks( o, callbacks, args ) {
- var prop = QUnit.objectType( o );
- if ( prop ) {
- if ( QUnit.objectType( callbacks[ prop ] ) === "function" ) {
- return callbacks[ prop ].apply( callbacks, args );
- } else {
- return callbacks[ prop ]; // or undefined
- }
- }
- }
-
- // the real equiv function
- var innerEquiv,
- // stack to decide between skip/abort functions
- callers = [],
- // stack to avoiding loops from circular referencing
- parents = [],
-
- getProto = Object.getPrototypeOf || function ( obj ) {
- return obj.__proto__;
- },
- callbacks = (function () {
-
- // for string, boolean, number and null
- function useStrictEquality( b, a ) {
- /*jshint eqeqeq:false */
- if ( b instanceof a.constructor || a instanceof b.constructor ) {
- // to catch short annotaion VS 'new' annotation of a
- // declaration
- // e.g. var i = 1;
- // var j = new Number(1);
- return a == b;
- } else {
- return a === b;
- }
- }
-
- return {
- "string": useStrictEquality,
- "boolean": useStrictEquality,
- "number": useStrictEquality,
- "null": useStrictEquality,
- "undefined": useStrictEquality,
-
- "nan": function( b ) {
- return isNaN( b );
- },
-
- "date": function( b, a ) {
- return QUnit.objectType( b ) === "date" && a.valueOf() === b.valueOf();
- },
-
- "regexp": function( b, a ) {
- return QUnit.objectType( b ) === "regexp" &&
- // the regex itself
- a.source === b.source &&
- // and its modifers
- a.global === b.global &&
- // (gmi) ...
- a.ignoreCase === b.ignoreCase &&
- a.multiline === b.multiline &&
- a.sticky === b.sticky;
- },
-
- // - skip when the property is a method of an instance (OOP)
- // - abort otherwise,
- // initial === would have catch identical references anyway
- "function": function() {
- var caller = callers[callers.length - 1];
- return caller !== Object && typeof caller !== "undefined";
- },
-
- "array": function( b, a ) {
- var i, j, len, loop;
-
- // b could be an object literal here
- if ( QUnit.objectType( b ) !== "array" ) {
- return false;
- }
-
- len = a.length;
- if ( len !== b.length ) {
- // safe and faster
- return false;
- }
-
- // track reference to avoid circular references
- parents.push( a );
- for ( i = 0; i < len; i++ ) {
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- loop = true;// dont rewalk array
- }
- }
- if ( !loop && !innerEquiv(a[i], b[i]) ) {
- parents.pop();
- return false;
- }
- }
- parents.pop();
- return true;
- },
-
- "object": function( b, a ) {
- var i, j, loop,
- // Default to true
- eq = true,
- aProperties = [],
- bProperties = [];
-
- // comparing constructors is more strict than using
- // instanceof
- if ( a.constructor !== b.constructor ) {
- // Allow objects with no prototype to be equivalent to
- // objects with Object as their constructor.
- if ( !(( getProto(a) === null && getProto(b) === Object.prototype ) ||
- ( getProto(b) === null && getProto(a) === Object.prototype ) ) ) {
- return false;
- }
- }
-
- // stack constructor before traversing properties
- callers.push( a.constructor );
- // track reference to avoid circular references
- parents.push( a );
-
- for ( i in a ) { // be strict: don't ensures hasOwnProperty
- // and go deep
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- // don't go down the same path twice
- loop = true;
- }
- }
- aProperties.push(i); // collect a's properties
-
- if (!loop && !innerEquiv( a[i], b[i] ) ) {
- eq = false;
- break;
- }
- }
-
- callers.pop(); // unstack, we are done
- parents.pop();
-
- for ( i in b ) {
- bProperties.push( i ); // collect b's properties
- }
-
- // Ensures identical properties name
- return eq && innerEquiv( aProperties.sort(), bProperties.sort() );
- }
- };
- }());
-
- innerEquiv = function() { // can take multiple arguments
- var args = [].slice.apply( arguments );
- if ( args.length < 2 ) {
- return true; // end transition
- }
-
- return (function( a, b ) {
- if ( a === b ) {
- return true; // catch the most you can
- } else if ( a === null || b === null || typeof a === "undefined" ||
- typeof b === "undefined" ||
- QUnit.objectType(a) !== QUnit.objectType(b) ) {
- return false; // don't lose time with error prone cases
- } else {
- return bindCallbacks(a, callbacks, [ b, a ]);
- }
-
- // apply transition with (1..n) arguments
- }( args[0], args[1] ) && arguments.callee.apply( this, args.splice(1, args.length - 1 )) );
- };
-
- return innerEquiv;
-}());
-
-/**
- * jsDump Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com |
- * http://flesler.blogspot.com Licensed under BSD
- * (http://www.opensource.org/licenses/bsd-license.php) Date: 5/15/2008
- *
- * @projectDescription Advanced and extensible data dumping for Javascript.
- * @version 1.0.0
- * @author Ariel Flesler
- * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html}
- */
-QUnit.jsDump = (function() {
- function quote( str ) {
- return '"' + str.toString().replace( /"/g, '\\"' ) + '"';
- }
- function literal( o ) {
- return o + "";
- }
- function join( pre, arr, post ) {
- var s = jsDump.separator(),
- base = jsDump.indent(),
- inner = jsDump.indent(1);
- if ( arr.join ) {
- arr = arr.join( "," + s + inner );
- }
- if ( !arr ) {
- return pre + post;
- }
- return [ pre, inner + arr, base + post ].join(s);
- }
- function array( arr, stack ) {
- var i = arr.length, ret = new Array(i);
- this.up();
- while ( i-- ) {
- ret[i] = this.parse( arr[i] , undefined , stack);
- }
- this.down();
- return join( "[", ret, "]" );
- }
-
- var reName = /^function (\w+)/,
- jsDump = {
- // type is used mostly internally, you can fix a (custom)type in advance
- parse: function( obj, type, stack ) {
- stack = stack || [ ];
- var inStack, res,
- parser = this.parsers[ type || this.typeOf(obj) ];
-
- type = typeof parser;
- inStack = inArray( obj, stack );
-
- if ( inStack !== -1 ) {
- return "recursion(" + (inStack - stack.length) + ")";
- }
- if ( type === "function" ) {
- stack.push( obj );
- res = parser.call( this, obj, stack );
- stack.pop();
- return res;
- }
- return ( type === "string" ) ? parser : this.parsers.error;
- },
- typeOf: function( obj ) {
- var type;
- if ( obj === null ) {
- type = "null";
- } else if ( typeof obj === "undefined" ) {
- type = "undefined";
- } else if ( QUnit.is( "regexp", obj) ) {
- type = "regexp";
- } else if ( QUnit.is( "date", obj) ) {
- type = "date";
- } else if ( QUnit.is( "function", obj) ) {
- type = "function";
- } else if ( typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined" ) {
- type = "window";
- } else if ( obj.nodeType === 9 ) {
- type = "document";
- } else if ( obj.nodeType ) {
- type = "node";
- } else if (
- // native arrays
- toString.call( obj ) === "[object Array]" ||
- // NodeList objects
- ( typeof obj.length === "number" && typeof obj.item !== "undefined" && ( obj.length ? obj.item(0) === obj[0] : ( obj.item( 0 ) === null && typeof obj[0] === "undefined" ) ) )
- ) {
- type = "array";
- } else if ( obj.constructor === Error.prototype.constructor ) {
- type = "error";
- } else {
- type = typeof obj;
- }
- return type;
- },
- separator: function() {
- return this.multiline ? this.HTML ? "
" : "\n" : this.HTML ? " " : " ";
- },
- // extra can be a number, shortcut for increasing-calling-decreasing
- indent: function( extra ) {
- if ( !this.multiline ) {
- return "";
- }
- var chr = this.indentChar;
- if ( this.HTML ) {
- chr = chr.replace( /\t/g, " " ).replace( / /g, " " );
- }
- return new Array( this._depth_ + (extra||0) ).join(chr);
- },
- up: function( a ) {
- this._depth_ += a || 1;
- },
- down: function( a ) {
- this._depth_ -= a || 1;
- },
- setParser: function( name, parser ) {
- this.parsers[name] = parser;
- },
- // The next 3 are exposed so you can use them
- quote: quote,
- literal: literal,
- join: join,
- //
- _depth_: 1,
- // This is the list of parsers, to modify them, use jsDump.setParser
- parsers: {
- window: "[Window]",
- document: "[Document]",
- error: function(error) {
- return "Error(\"" + error.message + "\")";
- },
- unknown: "[Unknown]",
- "null": "null",
- "undefined": "undefined",
- "function": function( fn ) {
- var ret = "function",
- // functions never have name in IE
- name = "name" in fn ? fn.name : (reName.exec(fn) || [])[1];
-
- if ( name ) {
- ret += " " + name;
- }
- ret += "( ";
-
- ret = [ ret, QUnit.jsDump.parse( fn, "functionArgs" ), "){" ].join( "" );
- return join( ret, QUnit.jsDump.parse(fn,"functionCode" ), "}" );
- },
- array: array,
- nodelist: array,
- "arguments": array,
- object: function( map, stack ) {
- var ret = [ ], keys, key, val, i;
- QUnit.jsDump.up();
- keys = [];
- for ( key in map ) {
- keys.push( key );
- }
- keys.sort();
- for ( i = 0; i < keys.length; i++ ) {
- key = keys[ i ];
- val = map[ key ];
- ret.push( QUnit.jsDump.parse( key, "key" ) + ": " + QUnit.jsDump.parse( val, undefined, stack ) );
- }
- QUnit.jsDump.down();
- return join( "{", ret, "}" );
- },
- node: function( node ) {
- var len, i, val,
- open = QUnit.jsDump.HTML ? "<" : "<",
- close = QUnit.jsDump.HTML ? ">" : ">",
- tag = node.nodeName.toLowerCase(),
- ret = open + tag,
- attrs = node.attributes;
-
- if ( attrs ) {
- for ( i = 0, len = attrs.length; i < len; i++ ) {
- val = attrs[i].nodeValue;
- // IE6 includes all attributes in .attributes, even ones not explicitly set.
- // Those have values like undefined, null, 0, false, "" or "inherit".
- if ( val && val !== "inherit" ) {
- ret += " " + attrs[i].nodeName + "=" + QUnit.jsDump.parse( val, "attribute" );
- }
- }
- }
- ret += close;
-
- // Show content of TextNode or CDATASection
- if ( node.nodeType === 3 || node.nodeType === 4 ) {
- ret += node.nodeValue;
- }
-
- return ret + open + "/" + tag + close;
- },
- // function calls it internally, it's the arguments part of the function
- functionArgs: function( fn ) {
- var args,
- l = fn.length;
-
- if ( !l ) {
- return "";
- }
-
- args = new Array(l);
- while ( l-- ) {
- // 97 is 'a'
- args[l] = String.fromCharCode(97+l);
- }
- return " " + args.join( ", " ) + " ";
- },
- // object calls it internally, the key part of an item in a map
- key: quote,
- // function calls it internally, it's the content of the function
- functionCode: "[code]",
- // node calls it internally, it's an html attribute value
- attribute: quote,
- string: quote,
- date: quote,
- regexp: literal,
- number: literal,
- "boolean": literal
- },
- // if true, entities are escaped ( <, >, \t, space and \n )
- HTML: false,
- // indentation unit
- indentChar: " ",
- // if true, items in a collection, are separated by a \n, else just a space.
- multiline: true
- };
-
- return jsDump;
-}());
-
-// from jquery.js
-function inArray( elem, array ) {
- if ( array.indexOf ) {
- return array.indexOf( elem );
- }
-
- for ( var i = 0, length = array.length; i < length; i++ ) {
- if ( array[ i ] === elem ) {
- return i;
- }
- }
-
- return -1;
-}
-
-/*
- * Javascript Diff Algorithm
- * By John Resig (http://ejohn.org/)
- * Modified by Chu Alan "sprite"
- *
- * Released under the MIT license.
- *
- * More Info:
- * http://ejohn.org/projects/javascript-diff-algorithm/
- *
- * Usage: QUnit.diff(expected, actual)
- *
- * QUnit.diff( "the quick brown fox jumped over", "the quick fox jumps over" ) == "the quick brown fox jumped jumps over"
- */
-QUnit.diff = (function() {
- /*jshint eqeqeq:false, eqnull:true */
- function diff( o, n ) {
- var i,
- ns = {},
- os = {};
-
- for ( i = 0; i < n.length; i++ ) {
- if ( !hasOwn.call( ns, n[i] ) ) {
- ns[ n[i] ] = {
- rows: [],
- o: null
- };
- }
- ns[ n[i] ].rows.push( i );
- }
-
- for ( i = 0; i < o.length; i++ ) {
- if ( !hasOwn.call( os, o[i] ) ) {
- os[ o[i] ] = {
- rows: [],
- n: null
- };
- }
- os[ o[i] ].rows.push( i );
- }
-
- for ( i in ns ) {
- if ( !hasOwn.call( ns, i ) ) {
- continue;
- }
- if ( ns[i].rows.length === 1 && hasOwn.call( os, i ) && os[i].rows.length === 1 ) {
- n[ ns[i].rows[0] ] = {
- text: n[ ns[i].rows[0] ],
- row: os[i].rows[0]
- };
- o[ os[i].rows[0] ] = {
- text: o[ os[i].rows[0] ],
- row: ns[i].rows[0]
- };
- }
- }
-
- for ( i = 0; i < n.length - 1; i++ ) {
- if ( n[i].text != null && n[ i + 1 ].text == null && n[i].row + 1 < o.length && o[ n[i].row + 1 ].text == null &&
- n[ i + 1 ] == o[ n[i].row + 1 ] ) {
-
- n[ i + 1 ] = {
- text: n[ i + 1 ],
- row: n[i].row + 1
- };
- o[ n[i].row + 1 ] = {
- text: o[ n[i].row + 1 ],
- row: i + 1
- };
- }
- }
-
- for ( i = n.length - 1; i > 0; i-- ) {
- if ( n[i].text != null && n[ i - 1 ].text == null && n[i].row > 0 && o[ n[i].row - 1 ].text == null &&
- n[ i - 1 ] == o[ n[i].row - 1 ]) {
-
- n[ i - 1 ] = {
- text: n[ i - 1 ],
- row: n[i].row - 1
- };
- o[ n[i].row - 1 ] = {
- text: o[ n[i].row - 1 ],
- row: i - 1
- };
- }
- }
-
- return {
- o: o,
- n: n
- };
- }
-
- return function( o, n ) {
- o = o.replace( /\s+$/, "" );
- n = n.replace( /\s+$/, "" );
-
- var i, pre,
- str = "",
- out = diff( o === "" ? [] : o.split(/\s+/), n === "" ? [] : n.split(/\s+/) ),
- oSpace = o.match(/\s+/g),
- nSpace = n.match(/\s+/g);
-
- if ( oSpace == null ) {
- oSpace = [ " " ];
- }
- else {
- oSpace.push( " " );
- }
-
- if ( nSpace == null ) {
- nSpace = [ " " ];
- }
- else {
- nSpace.push( " " );
- }
-
- if ( out.n.length === 0 ) {
- for ( i = 0; i < out.o.length; i++ ) {
- str += "" + out.o[i] + oSpace[i] + "";
- }
- }
- else {
- if ( out.n[0].text == null ) {
- for ( n = 0; n < out.o.length && out.o[n].text == null; n++ ) {
- str += "" + out.o[n] + oSpace[n] + "";
- }
- }
-
- for ( i = 0; i < out.n.length; i++ ) {
- if (out.n[i].text == null) {
- str += "" + out.n[i] + nSpace[i] + "";
- }
- else {
- // `pre` initialized at top of scope
- pre = "";
-
- for ( n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++ ) {
- pre += "" + out.o[n] + oSpace[n] + "";
- }
- str += " " + out.n[i].text + nSpace[i] + pre;
- }
- }
- }
-
- return str;
- };
-}());
-
-// for CommonJS enviroments, export everything
-if ( typeof exports !== "undefined" ) {
- extend( exports, QUnit );
-}
-
-// get at whatever the global object is, like window in browsers
-}( (function() {return this;}.call()) ));
diff --git a/test/lib/require.js b/test/lib/require.js
deleted file mode 100644
index 987f865..0000000
--- a/test/lib/require.js
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- RequireJS 2.1.5 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.
- Available via the MIT or new BSD license.
- see: http://github.com/jrburke/requirejs for details
-*/
-var requirejs,require,define;
-(function(aa){function I(b){return"[object Function]"===L.call(b)}function J(b){return"[object Array]"===L.call(b)}function y(b,c){if(b){var d;for(d=0;dthis.depCount&&!this.defined){if(I(n)){if(this.events.error)try{e=i.execCb(c,n,b,e)}catch(d){a=d}else e=i.execCb(c,n,b,e);this.map.isDefine&&((b=this.module)&&void 0!==b.exports&&b.exports!==this.exports?e=b.exports:void 0===e&&this.usingExports&&(e=this.exports));if(a)return a.requireMap=this.map,a.requireModules=[this.map.id],a.requireType="define",v(this.error=
-a)}else e=n;this.exports=e;if(this.map.isDefine&&!this.ignore&&(q[c]=e,l.onResourceLoad))l.onResourceLoad(i,this.map,this.depMaps);x(c);this.defined=!0}this.defining=!1;this.defined&&!this.defineEmitted&&(this.defineEmitted=!0,this.emit("defined",this.exports),this.defineEmitComplete=!0)}}else this.fetch()}},callPlugin:function(){var a=this.map,b=a.id,d=j(a.prefix);this.depMaps.push(d);t(d,"defined",u(this,function(e){var n,d;d=this.map.name;var g=this.map.parentMap?this.map.parentMap.name:null,h=
-i.makeRequire(a.parentMap,{enableBuildCallback:!0});if(this.map.unnormalized){if(e.normalize&&(d=e.normalize(d,function(a){return c(a,g,!0)})||""),e=j(a.prefix+"!"+d,this.map.parentMap),t(e,"defined",u(this,function(a){this.init([],function(){return a},null,{enabled:!0,ignore:!0})})),d=m(p,e.id)){this.depMaps.push(e);if(this.events.error)d.on("error",u(this,function(a){this.emit("error",a)}));d.enable()}}else n=u(this,function(a){this.init([],function(){return a},null,{enabled:!0})}),n.error=u(this,
-function(a){this.inited=!0;this.error=a;a.requireModules=[b];G(p,function(a){0===a.map.id.indexOf(b+"_unnormalized")&&x(a.map.id)});v(a)}),n.fromText=u(this,function(e,c){var d=a.name,g=j(d),C=O;c&&(e=c);C&&(O=!1);r(g);s(k.config,b)&&(k.config[d]=k.config[b]);try{l.exec(e)}catch(ca){return v(B("fromtexteval","fromText eval for "+b+" failed: "+ca,ca,[b]))}C&&(O=!0);this.depMaps.push(g);i.completeLoad(d);h([d],n)}),e.load(a.name,h,n,k)}));i.enable(d,this);this.pluginMaps[d.id]=d},enable:function(){V[this.map.id]=
-this;this.enabling=this.enabled=!0;y(this.depMaps,u(this,function(a,b){var c,e;if("string"===typeof a){a=j(a,this.map.isDefine?this.map:this.map.parentMap,!1,!this.skipMap);this.depMaps[b]=a;if(c=m(N,a.id)){this.depExports[b]=c(this);return}this.depCount+=1;t(a,"defined",u(this,function(a){this.defineDep(b,a);this.check()}));this.errback&&t(a,"error",this.errback)}c=a.id;e=p[c];!s(N,c)&&(e&&!e.enabled)&&i.enable(a,this)}));G(this.pluginMaps,u(this,function(a){var b=m(p,a.id);b&&!b.enabled&&i.enable(a,
-this)}));this.enabling=!1;this.check()},on:function(a,b){var c=this.events[a];c||(c=this.events[a]=[]);c.push(b)},emit:function(a,b){y(this.events[a],function(a){a(b)});"error"===a&&delete this.events[a]}};i={config:k,contextName:b,registry:p,defined:q,urlFetched:U,defQueue:H,Module:Z,makeModuleMap:j,nextTick:l.nextTick,onError:v,configure:function(a){a.baseUrl&&"/"!==a.baseUrl.charAt(a.baseUrl.length-1)&&(a.baseUrl+="/");var b=k.pkgs,c=k.shim,e={paths:!0,config:!0,map:!0};G(a,function(a,b){e[b]?
-"map"===b?(k.map||(k.map={}),R(k[b],a,!0,!0)):R(k[b],a,!0):k[b]=a});a.shim&&(G(a.shim,function(a,b){J(a)&&(a={deps:a});if((a.exports||a.init)&&!a.exportsFn)a.exportsFn=i.makeShimExports(a);c[b]=a}),k.shim=c);a.packages&&(y(a.packages,function(a){a="string"===typeof a?{name:a}:a;b[a.name]={name:a.name,location:a.location||a.name,main:(a.main||"main").replace(ja,"").replace(ea,"")}}),k.pkgs=b);G(p,function(a,b){!a.inited&&!a.map.unnormalized&&(a.map=j(b))});if(a.deps||a.callback)i.require(a.deps||[],
-a.callback)},makeShimExports:function(a){return function(){var b;a.init&&(b=a.init.apply(aa,arguments));return b||a.exports&&ba(a.exports)}},makeRequire:function(a,f){function d(e,c,h){var g,k;f.enableBuildCallback&&(c&&I(c))&&(c.__requireJsBuild=!0);if("string"===typeof e){if(I(c))return v(B("requireargs","Invalid require call"),h);if(a&&s(N,e))return N[e](p[a.id]);if(l.get)return l.get(i,e,a,d);g=j(e,a,!1,!0);g=g.id;return!s(q,g)?v(B("notloaded",'Module name "'+g+'" has not been loaded yet for context: '+
-b+(a?"":". Use require([])"))):q[g]}L();i.nextTick(function(){L();k=r(j(null,a));k.skipMap=f.skipMap;k.init(e,c,h,{enabled:!0});D()});return d}f=f||{};R(d,{isBrowser:A,toUrl:function(b){var d,f=b.lastIndexOf("."),g=b.split("/")[0];if(-1!==f&&(!("."===g||".."===g)||1h.attachEvent.toString().indexOf("[native code"))&&!Y?(O=!0,h.attachEvent("onreadystatechange",b.onScriptLoad)):(h.addEventListener("load",b.onScriptLoad,!1),h.addEventListener("error",b.onScriptError,!1)),h.src=d,K=h,D?x.insertBefore(h,D):x.appendChild(h),K=null,h;if(da)try{importScripts(d),b.completeLoad(c)}catch(j){b.onError(B("importscripts","importScripts failed for "+c+" at "+d,j,[c]))}};A&&M(document.getElementsByTagName("script"),function(b){x||(x=
-b.parentNode);if(t=b.getAttribute("data-main"))return r.baseUrl||(E=t.split("/"),Q=E.pop(),fa=E.length?E.join("/")+"/":"./",r.baseUrl=fa,t=Q),t=t.replace(ea,""),r.deps=r.deps?r.deps.concat(t):[t],!0});define=function(b,c,d){var l,h;"string"!==typeof b&&(d=c,c=b,b=null);J(c)||(d=c,c=[]);!c.length&&I(d)&&d.length&&(d.toString().replace(la,"").replace(ma,function(b,d){c.push(d)}),c=(1===d.length?["require"]:["require","exports","module"]).concat(c));if(O){if(!(l=K))P&&"interactive"===P.readyState||M(document.getElementsByTagName("script"),
-function(b){if("interactive"===b.readyState)return P=b}),l=P;l&&(b||(b=l.getAttribute("data-requiremodule")),h=F[l.getAttribute("data-requirecontext")])}(h?h.defQueue:T).push([b,c,d])};define.amd={jQuery:!0};l.exec=function(b){return eval(b)};l(r)}})(this);
diff --git a/test/lib/resemble.js b/test/lib/resemble.js
new file mode 100644
index 0000000..1cb8c29
--- /dev/null
+++ b/test/lib/resemble.js
@@ -0,0 +1,535 @@
+/*
+Author: James Cryer
+Company: Huddle
+Last updated date: 21 Feb 2013
+URL: https://github.com/Huddle/Resemble.js
+*/
+
+(function(_this){
+ 'use strict';
+
+ _this['resemble'] = function( fileData ){
+
+ var data = {};
+ var images = [];
+ var updateCallbackArray = [];
+
+ var tolerance = { // between 0 and 255
+ red: 16,
+ green: 16,
+ blue: 16,
+ minBrightness: 16,
+ maxBrightness: 240
+ };
+
+ var ignoreAntialiasing = false;
+ var ignoreColors = false;
+
+ function triggerDataUpdate(){
+ var len = updateCallbackArray.length;
+ var i;
+ for(i=0;i tolerance.maxBrightness;
+ }
+
+ function getHue(r,g,b){
+
+ r = r / 255;
+ g = g / 255;
+ b = b / 255;
+ var max = Math.max(r, g, b), min = Math.min(r, g, b);
+ var h;
+ var d;
+
+ if (max == min){
+ h = 0; // achromatic
+ } else{
+ d = max - min;
+ switch(max){
+ case r: h = (g - b) / d + (g < b ? 6 : 0); break;
+ case g: h = (b - r) / d + 2; break;
+ case b: h = (r - g) / d + 4; break;
+ }
+ h /= 6;
+ }
+
+ return h;
+ }
+
+ function isAntialiased(sourcePix, data, cacheSet, verticalPos, horizontalPos, width){
+ var offset;
+ var targetPix;
+ var distance = 1;
+ var i;
+ var j;
+ var hasHighContrastSibling = 0;
+ var hasSiblingWithDifferentHue = 0;
+ var hasEquivilantSibling = 0;
+
+ addHueInfo(sourcePix);
+
+ for (i = distance*-1; i <= distance; i++){
+ for (j = distance*-1; j <= distance; j++){
+
+ if(i===0 && j===0){
+ // ignore source pixel
+ } else {
+
+ offset = ((verticalPos+j)*width + (horizontalPos+i)) * 4;
+ targetPix = getPixelInfo(data, offset, cacheSet);
+
+ if(targetPix === null){
+ continue;
+ }
+
+ addBrightnessInfo(targetPix);
+ addHueInfo(targetPix);
+
+ if( isContrasting(sourcePix, targetPix) ){
+ hasHighContrastSibling++;
+ }
+
+ if( isRGBSame(sourcePix,targetPix) ){
+ hasEquivilantSibling++;
+ }
+
+ if( Math.abs(targetPix.h - sourcePix.h) > 0.3 ){
+ hasSiblingWithDifferentHue++;
+ }
+
+ if( hasSiblingWithDifferentHue > 1 || hasHighContrastSibling > 1){
+ return true;
+ }
+ }
+ }
+ }
+
+ if(hasEquivilantSibling < 2){
+ return true;
+ }
+
+ return false;
+ }
+
+ function errorPixel(px, offset){
+ px[offset] = 255; //r
+ px[offset + 1] = 0; //g
+ px[offset + 2] = 255; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyPixel(px, offset, data){
+ px[offset] = data.r; //r
+ px[offset + 1] = data.g; //g
+ px[offset + 2] = data.b; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyGrayScalePixel(px, offset, data){
+ px[offset] = data.brightness; //r
+ px[offset + 1] = data.brightness; //g
+ px[offset + 2] = data.brightness; //b
+ px[offset + 3] = 255; //a
+ }
+
+
+ function getPixelInfo(data, offset, cacheSet){
+ var r;
+ var g;
+ var b;
+ var d;
+
+ if(typeof data[offset] !== 'undefined'){
+ r = data[offset];
+ g = data[offset+1];
+ b = data[offset+2];
+ d = {
+ r: r,
+ g: g,
+ b: b
+ };
+
+ return d;
+ } else {
+ return null;
+ }
+ }
+
+ function addBrightnessInfo(data){
+ data.brightness = getBrightness(data.r,data.g,data.b); // 'corrected' lightness
+ }
+
+ function addHueInfo(data){
+ data.h = getHue(data.r,data.g,data.b);
+ }
+
+ function analyseImages(img1, img2, width, height){
+
+ var hiddenCanvas = document.createElement('canvas');
+
+ var data1 = img1.data;
+ var data2 = img2.data;
+
+ hiddenCanvas.width = width;
+ hiddenCanvas.height = height;
+
+ var context = hiddenCanvas.getContext('2d');
+ var imgd = context.createImageData(width,height);
+ var targetPix = imgd.data;
+
+ var mismatchCount = 0;
+
+ var time = Date.now();
+
+ var skip;
+
+ if( (width > 1200 || height > 1200) && ignoreAntialiasing){
+ skip = 6;
+ }
+
+ loop(height, width, function(verticalPos, horizontalPos){
+
+ if(skip){ // only skip if the image isn't small
+ if(verticalPos % skip === 0 || horizontalPos % skip === 0){
+ return;
+ }
+ }
+
+ var offset = (verticalPos*width + horizontalPos) * 4;
+ var pixel1 = getPixelInfo(data1, offset, 1);
+ var pixel2 = getPixelInfo(data2, offset, 2);
+
+ if(pixel1 === null || pixel2 === null){
+ return;
+ }
+
+ if (ignoreColors){
+
+ addBrightnessInfo(pixel1);
+ addBrightnessInfo(pixel2);
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ return;
+ }
+
+ if( isRGBSimilar(pixel1, pixel2) ){
+ copyPixel(targetPix, offset, pixel2);
+
+ } else if( ignoreAntialiasing && (
+ addBrightnessInfo(pixel1), // jit pixel info augmentation looks a little weird, sorry.
+ addBrightnessInfo(pixel2),
+ isAntialiased(pixel1, data1, 1, verticalPos, horizontalPos, width) ||
+ isAntialiased(pixel2, data2, 2, verticalPos, horizontalPos, width)
+ )){
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+
+ });
+
+ data.misMatchPercentage = (mismatchCount / (height*width) * 100).toFixed(2);
+ data.analysisTime = Date.now() - time;
+
+ data.getImageDataUrl = function(text){
+ var barHeight = 0;
+
+ if(text){
+ barHeight = addLabel(text,context,hiddenCanvas);
+ }
+
+ context.putImageData(imgd, 0, barHeight);
+
+ return hiddenCanvas.toDataURL("image/png");
+ };
+ }
+
+ function addLabel(text, context, hiddenCanvas){
+ var textPadding = 2;
+
+ context.font = '12px sans-serif';
+
+ var textWidth = context.measureText(text).width + textPadding*2;
+ var barHeight = 22;
+
+ if(textWidth > hiddenCanvas.width){
+ hiddenCanvas.width = textWidth;
+ }
+
+ hiddenCanvas.height += barHeight;
+
+ context.fillStyle = "#666";
+ context.fillRect(0,0,hiddenCanvas.width,barHeight -4);
+ context.fillStyle = "#fff";
+ context.fillRect(0,barHeight -4,hiddenCanvas.width, 4);
+
+ context.fillStyle = "#fff";
+ context.textBaseline = "top";
+ context.font = '12px sans-serif';
+ context.fillText(text, textPadding, 1);
+
+ return barHeight;
+ }
+
+ function normalise(img, w, h){
+ var c;
+ var context;
+
+ if(img.height < h || img.width < w){
+ c = document.createElement('canvas');
+ c.width = w;
+ c.height = h;
+ context = c.getContext('2d');
+ context.putImageData(img, 0, 0);
+ return context.getImageData(0, 0, w, h);
+ }
+
+ return img;
+ }
+
+ function compare(one, two){
+
+ function onceWeHaveBoth(){
+ var width;
+ var height;
+ if(images.length === 2){
+ width = images[0].width > images[1].width ? images[0].width : images[1].width;
+ height = images[0].height > images[1].height ? images[0].height : images[1].height;
+
+ if( (images[0].width === images[1].width) && (images[0].height === images[1].height) ){
+ data.isSameDimensions = true;
+ } else {
+ data.isSameDimensions = false;
+ }
+
+ analyseImages( normalise(images[0],width, height), normalise(images[1],width, height), width, height);
+
+ triggerDataUpdate();
+ }
+ }
+
+ images = [];
+ loadImageData(one, onceWeHaveBoth);
+ loadImageData(two, onceWeHaveBoth);
+ }
+
+ function getCompareApi(param){
+
+ var secondFileData,
+ hasMethod = typeof param === 'function';
+
+ if( !hasMethod ){
+ // assume it's file data
+ secondFileData = param;
+ }
+
+ var self = {
+ ignoreNothing: function(){
+
+ tolerance.red = 16;
+ tolerance.green = 16;
+ tolerance.blue = 16;
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreAntialiasing: function(){
+
+ tolerance.red = 32;
+ tolerance.green = 32;
+ tolerance.blue = 32;
+ tolerance.minBrightness = 64;
+ tolerance.maxBrightness = 96;
+
+ ignoreAntialiasing = true;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreColors: function(){
+
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = true;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ onComplete: function( callback ){
+
+ updateCallbackArray.push(callback);
+
+ var wrapper = function(){
+ compare(fileData, secondFileData);
+ };
+
+ wrapper();
+
+ return getCompareApi(wrapper);
+ }
+ };
+
+ return self;
+ }
+
+ return {
+ onComplete: function( callback ){
+ updateCallbackArray.push(callback);
+ loadImageData(fileData, function(imageData, width, height){
+ parseImage(imageData.data, width, height);
+ });
+ },
+ compareTo: function(secondFileData){
+ return getCompareApi(secondFileData);
+ }
+ };
+
+ };
+}(this));
\ No newline at end of file
diff --git a/test/testsuite.js b/test/testsuite.js
deleted file mode 100644
index b486acb..0000000
--- a/test/testsuite.js
+++ /dev/null
@@ -1,36 +0,0 @@
-requirejs.config({
- baseUrl: '/test/unit/'
-});
-
-define(function(require) {
- var testModules = [
- 'Pixi',
- 'Point',
- 'Rectangle',
- 'DisplayObject',
- 'DisplayObjectContainer',
- 'Sprite',
- 'MovieClip',
- 'InteractionManager',
- 'Stage',
- 'utils/Utils',
- 'utils/EventTarget',
- 'utils/Matrix',
- 'utils/Detector',
- 'renderers/WebGLShaders',
- 'renderers/WebGLRenderer',
- 'renderers/WebGLBatch',
- 'renderers/CanvasRenderer',
- 'extras/Strip',
- 'extras/Rope',
- 'textures/BaseTexture',
- 'textures/Texture',
- 'loaders/SpriteSheetLoader',
- 'loaders/AssetLoader'
- ];
-
- // Resolve all testModules and then start the Test Runner.
- require(testModules, function() {
- QUnit.start();
- });
-});
\ No newline at end of file
diff --git a/test/textures/SpriteSheet-Aliens.png b/test/textures/SpriteSheet-Aliens.png
new file mode 100644
index 0000000..210acb1
--- /dev/null
+++ b/test/textures/SpriteSheet-Aliens.png
Binary files differ
diff --git a/test/textures/SpriteSheet-Explosion.png b/test/textures/SpriteSheet-Explosion.png
new file mode 100755
index 0000000..79e1a69
--- /dev/null
+++ b/test/textures/SpriteSheet-Explosion.png
Binary files differ
diff --git a/test/textures/bunny.png b/test/textures/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/textures/bunny.png
Binary files differ
diff --git a/test/unit/DisplayObject.js b/test/unit/DisplayObject.js
deleted file mode 100644
index 5e7e72f..0000000
--- a/test/unit/DisplayObject.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObject');
-});
diff --git a/test/unit/DisplayObjectContainer.js b/test/unit/DisplayObjectContainer.js
deleted file mode 100644
index b323959..0000000
--- a/test/unit/DisplayObjectContainer.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObjectContainer');
-});
diff --git a/test/unit/InteractionManager.js b/test/unit/InteractionManager.js
deleted file mode 100644
index e751f52..0000000
--- a/test/unit/InteractionManager.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('InteractionManager');
-});
diff --git a/test/unit/MovieClip.js b/test/unit/MovieClip.js
deleted file mode 100644
index 37d9446..0000000
--- a/test/unit/MovieClip.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('MovieClip');
-});
diff --git a/test/unit/Pixi.js b/test/unit/Pixi.js
deleted file mode 100644
index 36eee73..0000000
--- a/test/unit/Pixi.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Pixi');
-});
diff --git a/test/unit/Point.js b/test/unit/Point.js
deleted file mode 100644
index 983ff6e..0000000
--- a/test/unit/Point.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Point');
-});
diff --git a/test/unit/Rectangle.js b/test/unit/Rectangle.js
deleted file mode 100644
index 3b439ba..0000000
--- a/test/unit/Rectangle.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Rectangle');
-});
diff --git a/test/unit/Sprite.js b/test/unit/Sprite.js
deleted file mode 100644
index ed4f596..0000000
--- a/test/unit/Sprite.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Sprite');
-});
diff --git a/test/unit/Stage.js b/test/unit/Stage.js
deleted file mode 100644
index 2d70291..0000000
--- a/test/unit/Stage.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Stage');
-});
diff --git a/test/unit/extras/Rope.js b/test/unit/extras/Rope.js
deleted file mode 100644
index 5606f14..0000000
--- a/test/unit/extras/Rope.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Rope');
-});
diff --git a/test/unit/extras/Strip.js b/test/unit/extras/Strip.js
deleted file mode 100644
index 0134d3a..0000000
--- a/test/unit/extras/Strip.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Strip');
-});
diff --git a/test/unit/loaders/AssetLoader.js b/test/unit/loaders/AssetLoader.js
deleted file mode 100644
index 13b8443..0000000
--- a/test/unit/loaders/AssetLoader.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('AssetLoader');
-});
diff --git a/test/unit/loaders/SpriteSheetLoader.js b/test/unit/loaders/SpriteSheetLoader.js
deleted file mode 100644
index 8bf0cb2..0000000
--- a/test/unit/loaders/SpriteSheetLoader.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('SpriteSheetLoader');
-});
diff --git a/test/unit/pixi/InteractionManager.js b/test/unit/pixi/InteractionManager.js
new file mode 100644
index 0000000..ed3001f
--- /dev/null
+++ b/test/unit/pixi/InteractionManager.js
@@ -0,0 +1,10 @@
+describe('pixi/InteractionManager', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var InteractionManager = PIXI.InteractionManager;
+
+ it('Module exists', function () {
+ expect(InteractionManager).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/Pixi.js b/test/unit/pixi/Pixi.js
new file mode 100644
index 0000000..27debc1
--- /dev/null
+++ b/test/unit/pixi/Pixi.js
@@ -0,0 +1,9 @@
+describe('pixi/Pixi', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+
+ it('Module exists', function () {
+ expect(global).to.have.property('PIXI').and.to.be.an('object');
+ });
+});
diff --git a/test/unit/pixi/core/Circle.js b/test/unit/pixi/core/Circle.js
new file mode 100644
index 0000000..93a4456
--- /dev/null
+++ b/test/unit/pixi/core/Circle.js
@@ -0,0 +1,22 @@
+describe('pixi/core/Circle', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Circle = PIXI.Circle;
+
+ it('Module exists', function () {
+ expect(Circle).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Circle();
+
+ expect(obj).to.be.an.instanceof(Circle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', 0);
+ expect(obj).to.have.property('y', 0);
+ expect(obj).to.have.property('radius', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Ellipse.js b/test/unit/pixi/core/Ellipse.js
new file mode 100644
index 0000000..026b56f
--- /dev/null
+++ b/test/unit/pixi/core/Ellipse.js
@@ -0,0 +1,24 @@
+describe('pixi/core/Ellipse', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Ellipse = PIXI.Ellipse;
+
+ it('Module exists', function () {
+ expect(Ellipse).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Ellipse();
+
+ expect(obj).to.be.an.instanceof(Ellipse);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+ expect(obj).to.respondTo('getBounds');
+
+ expect(obj).to.have.property('x', 0);
+ expect(obj).to.have.property('y', 0);
+ expect(obj).to.have.property('width', 0);
+ expect(obj).to.have.property('height', 0);
+ });
+});
diff --git a/.gitignore b/.gitignore
index 12e1b62..0b88317 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
node_modules
.DS_Store
-.project
\ No newline at end of file
+.project
+*.log
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..63e4d7c
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,8 @@
+language: node_js
+node_js:
+ - 0.10
+
+before_script:
+ - npm install -g grunt-cli
+ - export DISPLAY=:99.0
+ - sh -e /etc/init.d/xvfb start
diff --git a/Gruntfile.js b/Gruntfile.js
index b083b49..103938c 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -1,10 +1,12 @@
+'use strict';
+
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-connect');
- grunt.loadNpmTasks('grunt-contrib-qunit');
grunt.loadNpmTasks('grunt-contrib-yuidoc');
+ grunt.loadTasks('tasks');
var root = 'src/pixi/',
debug = 'bin/pixi.dev.js',
@@ -79,7 +81,7 @@
},
files: {
srcBlob: '<%= dirs.src %>/**/*.js',
- testBlob: '<%= dirs.test %>/unit/**/*.js',
+ testBlob: '<%= dirs.test %>/{functional,lib/pixi,unit}/**/*.js',
build: '<%= dirs.build %>/pixi.dev.js',
buildMin: '<%= dirs.build %>/pixi.js'
},
@@ -94,7 +96,12 @@
},
jshint: {
beforeconcat: srcFiles,
- test: ['<%= files.testBlob %>'],
+ test: {
+ src: ['<%= files.testBlob %>'],
+ options: {
+ expr: true
+ }
+ },
options: {
asi: true,
smarttabs: true
@@ -128,12 +135,6 @@
]
},
connect: {
- qunit: {
- options: {
- port: grunt.option('port-test') || 9002,
- base: './'
- }
- },
test: {
options: {
port: grunt.option('port-test') || 9002,
@@ -142,13 +143,6 @@
}
}
},
- qunit: {
- all: {
- options: {
- urls: ['http://localhost:' + (grunt.option('port-test') || 9002) + '/test/index.html']
- }
- }
- },
yuidoc: {
compile: {
name: '<%= pkg.name %>',
@@ -161,6 +155,13 @@
outdir: '<%= dirs.docs %>'
}
}
+ },
+ karma: {
+ unit: {
+ configFile: 'test/karma.conf.js',
+ // browsers: ['Chrome'],
+ singleRun: true
+ }
}
});
@@ -182,9 +183,10 @@
}
)
- grunt.registerTask('default', ['concat', 'uglify', 'distribute']);
grunt.registerTask('build', ['concat', 'uglify', 'distribute']);
- grunt.registerTask('test', ['build', 'connect:qunit', 'qunit']);
+ grunt.registerTask('test', ['concat', 'jshint:test', 'karma']);
grunt.registerTask('docs', ['yuidoc']);
-
-}
\ No newline at end of file
+ grunt.registerTask('default', ['test', 'uglify', 'distribute']);
+ // Travis CI task.
+ grunt.registerTask('travis', ['test']);
+}
diff --git a/README.md b/README.md
index c62ef86..690cfe4 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,8 @@

+[](http://travis-ci.org/drkibitz/pixi.js)
+
#### JavaScript 2D Renderer ####
The aim of this project is to provide a fast lightweight 2D library that works
diff --git a/package.json b/package.json
index b373240..1246a68 100644
--- a/package.json
+++ b/package.json
@@ -18,14 +18,21 @@
"main": "bin/pixi.js",
+ "scripts": {
+ "test": "grunt travis --verbose"
+ },
+
"dependencies": {},
"devDependencies": {
"grunt": "~0.4.x",
- "grunt-contrib-jshint": "0.3.x",
+ "grunt-contrib-jshint": "0.6.x",
"grunt-contrib-uglify": "0.2.x",
- "grunt-contrib-connect": "0.2.x",
- "grunt-contrib-qunit": "0.2.x",
+ "grunt-contrib-connect": "0.3.x",
"grunt-contrib-yuidoc": "0.4.x",
- "grunt-contrib-concat": "0.1.x"
+ "grunt-contrib-concat": "0.3.x",
+ "chai": "~1.7.0",
+ "karma": "0.11.0",
+ "karma-firefox-launcher": "0.1.0",
+ "karma-mocha": "0.1.0"
}
}
diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js
index a7c520e..ee82bbd 100644
--- a/src/pixi/InteractionManager.js
+++ b/src/pixi/InteractionManager.js
@@ -62,7 +62,6 @@
this.onTouchEnd = this.onTouchEnd.bind(this);
this.onTouchMove = this.onTouchMove.bind(this);
-
this.last = 0;
}
diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js
index 1a95d20..eef1059 100644
--- a/src/pixi/core/Ellipse.js
+++ b/src/pixi/core/Ellipse.js
@@ -78,7 +78,7 @@
return (normx + normy < 0.25);
}
-PIXI.Ellipse.getBounds = function()
+PIXI.Ellipse.prototype.getBounds = function()
{
return new PIXI.Rectangle(this.x, this.y, this.width, this.height);
}
diff --git a/tasks/karma.js b/tasks/karma.js
new file mode 100644
index 0000000..c340485
--- /dev/null
+++ b/tasks/karma.js
@@ -0,0 +1,27 @@
+'use strict';
+
+var path = require('path');
+var server = require('karma').server;
+
+module.exports = function (grunt) {
+ grunt.registerMultiTask('karma', 'run karma.', function() {
+ var done = this.async();
+ var options = this.options({
+ background: false
+ });
+ var data = this.data;
+
+ //merge options onto data, with data taking precedence
+ data = grunt.util._.merge(options, data);
+ data.configFile = path.resolve(data.configFile);
+ if (data.configFile) {
+ data.configFile = grunt.template.process(data.configFile);
+ }
+
+ server.start(
+ data,
+ function(code) {
+ done(!code);
+ });
+ });
+};
diff --git a/test/functional/example-1-basics/bunny.png b/test/functional/example-1-basics/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/functional/example-1-basics/bunny.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-30.png b/test/functional/example-1-basics/frame-30.png
new file mode 100644
index 0000000..96e3409
--- /dev/null
+++ b/test/functional/example-1-basics/frame-30.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-60.png b/test/functional/example-1-basics/frame-60.png
new file mode 100644
index 0000000..af3f4ce
--- /dev/null
+++ b/test/functional/example-1-basics/frame-60.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-90.png b/test/functional/example-1-basics/frame-90.png
new file mode 100644
index 0000000..099b823
--- /dev/null
+++ b/test/functional/example-1-basics/frame-90.png
Binary files differ
diff --git a/test/functional/example-1-basics/index.js b/test/functional/example-1-basics/index.js
new file mode 100644
index 0000000..7ae7a98
--- /dev/null
+++ b/test/functional/example-1-basics/index.js
@@ -0,0 +1,133 @@
+describe('Example 1 - Basics', function () {
+ 'use strict';
+
+ var baseUri = '/base/test/functional/example-1-basics';
+ var expect = chai.expect;
+ var currentFrame = 0;
+ var frameEvents = {};
+ var stage;
+ var renderer;
+ var bunny;
+
+ function onFrame(frame, callback) {
+ frameEvents[frame] = callback;
+ }
+
+ function animate() {
+ currentFrame += 1;
+
+ requestAnimFrame( animate );
+
+ // just for fun, lets rotate mr rabbit a little
+ bunny.rotation += 0.1;
+
+ // render the stage
+ renderer.render(stage);
+
+ if (frameEvents[currentFrame])
+ frameEvents[currentFrame](currentFrame);
+ }
+
+ function initScene() {
+ // create an new instance of a pixi stage
+ stage = new PIXI.Stage(0x66FF99);
+
+ // create a renderer instance
+ renderer = PIXI.autoDetectRenderer(400, 300);
+ console.log('Is PIXI.WebGLRenderer: ' + (renderer instanceof PIXI.WebGLRenderer));
+
+ // add the renderer view element to the DOM
+ document.body.appendChild(renderer.view);
+
+ requestAnimFrame( animate );
+
+ // create a texture from an image path
+ var texture = PIXI.Texture.fromImage(baseUri + "/bunny.png");
+ // create a new Sprite using the texture
+ bunny = new PIXI.Sprite(texture);
+
+ // center the sprites anchor point
+ bunny.anchor.x = 0.5;
+ bunny.anchor.y = 0.5;
+
+ // move the sprite t the center of the screen
+ bunny.position.x = 200;
+ bunny.position.y = 150;
+
+ stage.addChild(bunny);
+ }
+
+ it('assets loaded', function (done) {
+ var loader = new PIXI.AssetLoader([
+ baseUri + '/bunny.png',
+ baseUri + '/frame-30.png',
+ baseUri + '/frame-60.png',
+ baseUri + '/frame-90.png'
+ ]);
+ // loader.on('onProgress', function (event) {
+ // console.log(event.content);
+ // });
+ loader.on('onComplete', function (event) {
+ done();
+ initScene();
+ });
+ loader.load();
+ });
+
+ it('frame 30 should match', function (done) {
+ this.timeout(700);
+ onFrame(30, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-30.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 60 should match', function (done) {
+ this.timeout(1200);
+ onFrame(60, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-60.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 90 should match', function (done) {
+ this.timeout(1700);
+ onFrame(90, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-90.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ // it('capture something', function (done) {
+ // this.timeout(2000000);
+ // onFrame(30, function () {
+ // var img = new Image();
+ // img.src = renderer.view.toDataURL('image/png');
+ // document.body.appendChild(img);
+ // });
+ // });
+});
diff --git a/test/index.html b/test/index.html
deleted file mode 100644
index 9cbcac5..0000000
--- a/test/index.html
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
- Pixi.js Test Suite
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/test/karma.conf.js b/test/karma.conf.js
new file mode 100644
index 0000000..c66a696
--- /dev/null
+++ b/test/karma.conf.js
@@ -0,0 +1,82 @@
+module.exports = function(config) {
+ config.set({
+
+ // base path, that will be used to resolve files and exclude
+ basePath : '../',
+
+ frameworks : ['mocha'],
+
+ // list of files / patterns to load in the browser
+ files : [
+ 'node_modules/chai/chai.js',
+ 'bin/pixi.dev.js',
+ 'test/lib/**/*.js',
+ 'test/unit/**/*.js',
+ // 'test/functional/**/*.js',
+ {pattern: 'test/**/*.png', watched: false, included: false, served: true}
+ ],
+
+ // list of files to exclude
+ exclude : [],
+
+ // use dolts reporter, as travis terminal does not support escaping sequences
+ // possible values: 'dots', 'progress', 'junit', 'teamcity'
+ // CLI --reporters progress
+ reporters : ['progress'],
+
+ // web server port
+ // CLI --port 9876
+ port : 9876,
+
+ // cli runner port
+ // CLI --runner-port 9100
+ runnerPort : 9100,
+
+ // enable / disable colors in the output (reporters and logs)
+ // CLI --colors --no-colors
+ colors : true,
+
+ // level of logging
+ // possible values: karma.LOG_DISABLE || karma.LOG_ERROR || karma.LOG_WARN || karma.LOG_INFO || karma.LOG_DEBUG
+ // CLI --log-level debug
+ logLevel : config.LOG_DEBUG,
+
+ // enable / disable watching file and executing tests whenever any file changes
+ // CLI --auto-watch --no-auto-watch
+ autoWatch : false,
+
+ // Start these browsers, currently available:
+ // - Chrome
+ // - ChromeCanary
+ // - Firefox
+ // - Opera
+ // - Safari (only Mac)
+ // - PhantomJS
+ // - IE (only Windows)
+ // CLI --browsers Chrome,Firefox,Safari
+ browsers : ['Firefox'],
+
+ // If browser does not capture in given timeout [ms], kill it
+ // CLI --capture-timeout 5000
+ captureTimeout : 5000,
+
+ // Auto run tests on start (when browsers are captured) and exit
+ // CLI --single-run --no-single-run
+ singleRun : true,
+
+ // report which specs are slower than 500ms
+ // CLI --report-slower-than 500
+ reportSlowerThan : 1000,
+
+ preprocessors : {
+ // '**/client/js/*.js': 'coverage'
+ },
+
+ plugins : [
+ 'karma-mocha',
+ // 'karma-chrome-launcher',
+ 'karma-firefox-launcher',
+ // 'karma-phantomjs-launcher'
+ ]
+ });
+};
diff --git a/test/lib/pixi/core/Matrix.js b/test/lib/pixi/core/Matrix.js
new file mode 100644
index 0000000..d26386b
--- /dev/null
+++ b/test/lib/pixi/core/Matrix.js
@@ -0,0 +1,40 @@
+
+function pixi_core_Matrix_confirmNewMat3(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(1);
+ expect(matrix[5]).to.equal(0);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(1);
+}
+
+function pixi_core_Matrix_confirmNewMat4(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[0]).to.equal(1);
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(0);
+ expect(matrix[5]).to.equal(1);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(0);
+ expect(matrix[9]).to.equal(0);
+ expect(matrix[10]).to.equal(1);
+ expect(matrix[11]).to.equal(0);
+ expect(matrix[12]).to.equal(0);
+ expect(matrix[13]).to.equal(0);
+ expect(matrix[14]).to.equal(0);
+ expect(matrix[15]).to.equal(1);
+}
diff --git a/test/lib/pixi/core/Point.js b/test/lib/pixi/core/Point.js
new file mode 100644
index 0000000..e5df07b
--- /dev/null
+++ b/test/lib/pixi/core/Point.js
@@ -0,0 +1,10 @@
+
+function pixi_core_Point_confirm(obj, x, y) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Point);
+ expect(obj).to.respondTo('clone');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+}
diff --git a/test/lib/pixi/core/Rectangle.js b/test/lib/pixi/core/Rectangle.js
new file mode 100644
index 0000000..23f0d12
--- /dev/null
+++ b/test/lib/pixi/core/Rectangle.js
@@ -0,0 +1,13 @@
+
+function pixi_core_Rectangle_confirm(obj, x, y, width, height) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Rectangle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+ expect(obj).to.have.property('width', width);
+ expect(obj).to.have.property('height', height);
+}
diff --git a/test/lib/pixi/display/DisplayObject.js b/test/lib/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..1388a7f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObject.js
@@ -0,0 +1,43 @@
+
+function pixi_display_DisplayObject_confirmNew(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObject);
+ expect(obj).to.respondTo('setInteractive');
+ expect(obj).to.respondTo('addFilter');
+ expect(obj).to.respondTo('removeFilter');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.property('last', obj);
+ expect(obj).to.have.property('first', obj);
+
+ expect(obj).to.contain.property('position');
+ pixi_core_Point_confirm(obj.position, 0, 0);
+ expect(obj).to.contain.property('scale');
+ pixi_core_Point_confirm(obj.scale, 1, 1);
+ expect(obj).to.contain.property('pivot');
+ pixi_core_Point_confirm(obj.pivot, 0, 0);
+
+ expect(obj).to.have.property('rotation', 0);
+ expect(obj).to.have.property('alpha', 1);
+ expect(obj).to.have.property('visible', true);
+ expect(obj).to.have.property('buttonMode', false);
+ expect(obj).to.have.property('parent', null);
+ expect(obj).to.have.property('worldAlpha', 1);
+
+ expect(obj).to.have.property('hitArea');
+ expect(obj).to.have.property('interactive'); // TODO: Have a better default value
+ expect('mask' in obj).to.be.true; // TODO: Have a better default value
+ expect(obj.mask).to.be.undefined;
+
+ expect(obj).to.have.property('renderable');
+ expect(obj).to.have.property('stage');
+
+ expect(obj).to.have.deep.property('worldTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ expect(obj).to.have.deep.property('localTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.localTransform);
+
+ expect(obj).to.have.deep.property('color.length', 0);
+ expect(obj).to.have.property('dynamic', true);
+}
diff --git a/test/lib/pixi/display/DisplayObjectContainer.js b/test/lib/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..085c59f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,16 @@
+
+function pixi_display_DisplayObjectContainer_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObject_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObjectContainer);
+ expect(obj).to.respondTo('addChild');
+ expect(obj).to.respondTo('addChildAt');
+ expect(obj).to.respondTo('swapChildren');
+ expect(obj).to.respondTo('getChildAt');
+ expect(obj).to.respondTo('removeChild');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('children.length', 0);
+}
diff --git a/test/lib/pixi/display/Sprite.js b/test/lib/pixi/display/Sprite.js
new file mode 100644
index 0000000..cc7a2d6
--- /dev/null
+++ b/test/lib/pixi/display/Sprite.js
@@ -0,0 +1,28 @@
+
+function pixi_display_Sprite_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Sprite);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', true);
+ expect(obj).to.have.property('stage', null);
+
+ expect(obj).to.have.property('anchor');
+ pixi_core_Point_confirm(obj.anchor, 0, 0);
+
+ expect(obj).to.have.property('blendMode', PIXI.blendModes.NORMAL);
+ expect(obj).to.have.property('width', 1); // TODO: is 1 expected
+ expect(obj).to.have.property('height', 1); // TODO: is 1 expected
+
+ // FIXME: Just make this a boolean that is always there
+ expect(!!obj.updateFrame).to.equal(obj.texture.baseTexture.hasLoaded);
+
+ expect(obj).to.have.property('texture');
+ pixi_textures_Texture_confirmNew(obj.texture, done);
+}
diff --git a/test/lib/pixi/extras/Strip.js b/test/lib/pixi/extras/Strip.js
new file mode 100644
index 0000000..8927a8a
--- /dev/null
+++ b/test/lib/pixi/extras/Strip.js
@@ -0,0 +1,12 @@
+
+function pixi_extras_Strip_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Strip);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ // TODO: Test properties
+}
diff --git a/test/lib/pixi/textures/Texture.js b/test/lib/pixi/textures/Texture.js
new file mode 100644
index 0000000..d5867b6
--- /dev/null
+++ b/test/lib/pixi/textures/Texture.js
@@ -0,0 +1,31 @@
+
+function pixi_textures_Texture_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ function confirmFrameDone() {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, obj.baseTexture.width, obj.baseTexture.height);
+
+ expect(obj).to.have.property('width', obj.baseTexture.width);
+ expect(obj).to.have.property('height', obj.baseTexture.height);
+ done();
+ }
+
+ expect(obj).to.be.an.instanceof(PIXI.Texture);
+ pixi_utils_EventTarget_like(obj);
+
+ expect(obj).to.have.property('baseTexture')
+ .and.to.be.an.instanceof(PIXI.BaseTexture);
+
+ expect(obj).to.have.property('scope', obj);
+
+ expect(obj).to.have.property('trim');
+ pixi_core_Point_confirm(obj.trim, 0, 0);
+
+ expect(obj).to.have.property('frame');
+ if (obj.baseTexture.hasLoaded) {
+ confirmFrameDone();
+ } else {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, 1, 1);
+ obj.addEventListener('update', confirmFrameDone);
+ }
+}
diff --git a/test/lib/pixi/utils/EventTarget.js b/test/lib/pixi/utils/EventTarget.js
new file mode 100644
index 0000000..7b1dcfa
--- /dev/null
+++ b/test/lib/pixi/utils/EventTarget.js
@@ -0,0 +1,8 @@
+
+function pixi_utils_EventTarget_like(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.respondTo('addEventListener');
+ expect(obj).to.respondTo('dispatchEvent');
+ expect(obj).to.respondTo('removeEventListener');
+}
diff --git a/test/lib/qunit-1.11.0.css b/test/lib/qunit-1.11.0.css
deleted file mode 100644
index d7fc0c8..0000000
--- a/test/lib/qunit-1.11.0.css
+++ /dev/null
@@ -1,244 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-/** Font Family and Sizes */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
- font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
-}
-
-#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
-#qunit-tests { font-size: smaller; }
-
-
-/** Resets */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter {
- margin: 0;
- padding: 0;
-}
-
-
-/** Header */
-
-#qunit-header {
- padding: 0.5em 0 0.5em 1em;
-
- color: #8699a4;
- background-color: #0d3349;
-
- font-size: 1.5em;
- line-height: 1em;
- font-weight: normal;
-
- border-radius: 5px 5px 0 0;
- -moz-border-radius: 5px 5px 0 0;
- -webkit-border-top-right-radius: 5px;
- -webkit-border-top-left-radius: 5px;
-}
-
-#qunit-header a {
- text-decoration: none;
- color: #c2ccd1;
-}
-
-#qunit-header a:hover,
-#qunit-header a:focus {
- color: #fff;
-}
-
-#qunit-testrunner-toolbar label {
- display: inline-block;
- padding: 0 .5em 0 .1em;
-}
-
-#qunit-banner {
- height: 5px;
-}
-
-#qunit-testrunner-toolbar {
- padding: 0.5em 0 0.5em 2em;
- color: #5E740B;
- background-color: #eee;
- overflow: hidden;
-}
-
-#qunit-userAgent {
- padding: 0.5em 0 0.5em 2.5em;
- background-color: #2b81af;
- color: #fff;
- text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
-}
-
-#qunit-modulefilter-container {
- float: right;
-}
-
-/** Tests: Pass/Fail */
-
-#qunit-tests {
- list-style-position: inside;
-}
-
-#qunit-tests li {
- padding: 0.4em 0.5em 0.4em 2.5em;
- border-bottom: 1px solid #fff;
- list-style-position: inside;
-}
-
-#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running {
- display: none;
-}
-
-#qunit-tests li strong {
- cursor: pointer;
-}
-
-#qunit-tests li a {
- padding: 0.5em;
- color: #c2ccd1;
- text-decoration: none;
-}
-#qunit-tests li a:hover,
-#qunit-tests li a:focus {
- color: #000;
-}
-
-#qunit-tests li .runtime {
- float: right;
- font-size: smaller;
-}
-
-.qunit-assert-list {
- margin-top: 0.5em;
- padding: 0.5em;
-
- background-color: #fff;
-
- border-radius: 5px;
- -moz-border-radius: 5px;
- -webkit-border-radius: 5px;
-}
-
-.qunit-collapsed {
- display: none;
-}
-
-#qunit-tests table {
- border-collapse: collapse;
- margin-top: .2em;
-}
-
-#qunit-tests th {
- text-align: right;
- vertical-align: top;
- padding: 0 .5em 0 0;
-}
-
-#qunit-tests td {
- vertical-align: top;
-}
-
-#qunit-tests pre {
- margin: 0;
- white-space: pre-wrap;
- word-wrap: break-word;
-}
-
-#qunit-tests del {
- background-color: #e0f2be;
- color: #374e0c;
- text-decoration: none;
-}
-
-#qunit-tests ins {
- background-color: #ffcaca;
- color: #500;
- text-decoration: none;
-}
-
-/*** Test Counts */
-
-#qunit-tests b.counts { color: black; }
-#qunit-tests b.passed { color: #5E740B; }
-#qunit-tests b.failed { color: #710909; }
-
-#qunit-tests li li {
- padding: 5px;
- background-color: #fff;
- border-bottom: none;
- list-style-position: inside;
-}
-
-/*** Passing Styles */
-
-#qunit-tests li li.pass {
- color: #3c510c;
- background-color: #fff;
- border-left: 10px solid #C6E746;
-}
-
-#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
-#qunit-tests .pass .test-name { color: #366097; }
-
-#qunit-tests .pass .test-actual,
-#qunit-tests .pass .test-expected { color: #999999; }
-
-#qunit-banner.qunit-pass { background-color: #C6E746; }
-
-/*** Failing Styles */
-
-#qunit-tests li li.fail {
- color: #710909;
- background-color: #fff;
- border-left: 10px solid #EE5757;
- white-space: pre;
-}
-
-#qunit-tests > li:last-child {
- border-radius: 0 0 5px 5px;
- -moz-border-radius: 0 0 5px 5px;
- -webkit-border-bottom-right-radius: 5px;
- -webkit-border-bottom-left-radius: 5px;
-}
-
-#qunit-tests .fail { color: #000000; background-color: #EE5757; }
-#qunit-tests .fail .test-name,
-#qunit-tests .fail .module-name { color: #000000; }
-
-#qunit-tests .fail .test-actual { color: #EE5757; }
-#qunit-tests .fail .test-expected { color: green; }
-
-#qunit-banner.qunit-fail { background-color: #EE5757; }
-
-
-/** Result */
-
-#qunit-testresult {
- padding: 0.5em 0.5em 0.5em 2.5em;
-
- color: #2b81af;
- background-color: #D2E0E6;
-
- border-bottom: 1px solid white;
-}
-#qunit-testresult .module-name {
- font-weight: bold;
-}
-
-/** Fixture */
-
-#qunit-fixture {
- position: absolute;
- top: -10000px;
- left: -10000px;
- width: 1000px;
- height: 1000px;
-}
diff --git a/test/lib/qunit-1.11.0.js b/test/lib/qunit-1.11.0.js
deleted file mode 100644
index 302545f..0000000
--- a/test/lib/qunit-1.11.0.js
+++ /dev/null
@@ -1,2152 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-(function( window ) {
-
-var QUnit,
- assert,
- config,
- onErrorFnPrev,
- testId = 0,
- fileName = (sourceFromStacktrace( 0 ) || "" ).replace(/(:\d+)+\)?/, "").replace(/.+\//, ""),
- toString = Object.prototype.toString,
- hasOwn = Object.prototype.hasOwnProperty,
- // Keep a local reference to Date (GH-283)
- Date = window.Date,
- defined = {
- setTimeout: typeof window.setTimeout !== "undefined",
- sessionStorage: (function() {
- var x = "qunit-test-string";
- try {
- sessionStorage.setItem( x, x );
- sessionStorage.removeItem( x );
- return true;
- } catch( e ) {
- return false;
- }
- }())
- },
- /**
- * Provides a normalized error string, correcting an issue
- * with IE 7 (and prior) where Error.prototype.toString is
- * not properly implemented
- *
- * Based on http://es5.github.com/#x15.11.4.4
- *
- * @param {String|Error} error
- * @return {String} error message
- */
- errorString = function( error ) {
- var name, message,
- errorString = error.toString();
- if ( errorString.substring( 0, 7 ) === "[object" ) {
- name = error.name ? error.name.toString() : "Error";
- message = error.message ? error.message.toString() : "";
- if ( name && message ) {
- return name + ": " + message;
- } else if ( name ) {
- return name;
- } else if ( message ) {
- return message;
- } else {
- return "Error";
- }
- } else {
- return errorString;
- }
- },
- /**
- * Makes a clone of an object using only Array or Object as base,
- * and copies over the own enumerable properties.
- *
- * @param {Object} obj
- * @return {Object} New object with only the own properties (recursively).
- */
- objectValues = function( obj ) {
- // Grunt 0.3.x uses an older version of jshint that still has jshint/jshint#392.
- /*jshint newcap: false */
- var key, val,
- vals = QUnit.is( "array", obj ) ? [] : {};
- for ( key in obj ) {
- if ( hasOwn.call( obj, key ) ) {
- val = obj[key];
- vals[key] = val === Object(val) ? objectValues(val) : val;
- }
- }
- return vals;
- };
-
-function Test( settings ) {
- extend( this, settings );
- this.assertions = [];
- this.testNumber = ++Test.count;
-}
-
-Test.count = 0;
-
-Test.prototype = {
- init: function() {
- var a, b, li,
- tests = id( "qunit-tests" );
-
- if ( tests ) {
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml;
-
- // `a` initialized at top of scope
- a = document.createElement( "a" );
- a.innerHTML = "Rerun";
- a.href = QUnit.url({ testNumber: this.testNumber });
-
- li = document.createElement( "li" );
- li.appendChild( b );
- li.appendChild( a );
- li.className = "running";
- li.id = this.id = "qunit-test-output" + testId++;
-
- tests.appendChild( li );
- }
- },
- setup: function() {
- if ( this.module !== config.previousModule ) {
- if ( config.previousModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.previousModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
- config.previousModule = this.module;
- config.moduleStats = { all: 0, bad: 0 };
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- } else if ( config.autorun ) {
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- }
-
- config.current = this;
-
- this.testEnvironment = extend({
- setup: function() {},
- teardown: function() {}
- }, this.moduleTestEnvironment );
-
- this.started = +new Date();
- runLoggingCallbacks( "testStart", QUnit, {
- name: this.testName,
- module: this.module
- });
-
- // allow utility functions to access the current test environment
- // TODO why??
- QUnit.current_testEnvironment = this.testEnvironment;
-
- if ( !config.pollution ) {
- saveGlobal();
- }
- if ( config.notrycatch ) {
- this.testEnvironment.setup.call( this.testEnvironment );
- return;
- }
- try {
- this.testEnvironment.setup.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Setup failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- },
- run: function() {
- config.current = this;
-
- var running = id( "qunit-testresult" );
-
- if ( running ) {
- running.innerHTML = "Running:
" + this.nameHtml;
- }
-
- if ( this.async ) {
- QUnit.stop();
- }
-
- this.callbackStarted = +new Date();
-
- if ( config.notrycatch ) {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- return;
- }
-
- try {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- } catch( e ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
-
- QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + " " + this.stack + ": " + ( e.message || e ), extractStacktrace( e, 0 ) );
- // else next test will carry the responsibility
- saveGlobal();
-
- // Restart the tests if they're blocking
- if ( config.blocking ) {
- QUnit.start();
- }
- }
- },
- teardown: function() {
- config.current = this;
- if ( config.notrycatch ) {
- if ( typeof this.callbackRuntime === "undefined" ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
- }
- this.testEnvironment.teardown.call( this.testEnvironment );
- return;
- } else {
- try {
- this.testEnvironment.teardown.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Teardown failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- }
- checkPollution();
- },
- finish: function() {
- config.current = this;
- if ( config.requireExpects && this.expected === null ) {
- QUnit.pushFailure( "Expected number of assertions to be defined, but expect() was not called.", this.stack );
- } else if ( this.expected !== null && this.expected !== this.assertions.length ) {
- QUnit.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack );
- } else if ( this.expected === null && !this.assertions.length ) {
- QUnit.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions.", this.stack );
- }
-
- var i, assertion, a, b, time, li, ol,
- test = this,
- good = 0,
- bad = 0,
- tests = id( "qunit-tests" );
-
- this.runtime = +new Date() - this.started;
- config.stats.all += this.assertions.length;
- config.moduleStats.all += this.assertions.length;
-
- if ( tests ) {
- ol = document.createElement( "ol" );
- ol.className = "qunit-assert-list";
-
- for ( i = 0; i < this.assertions.length; i++ ) {
- assertion = this.assertions[i];
-
- li = document.createElement( "li" );
- li.className = assertion.result ? "pass" : "fail";
- li.innerHTML = assertion.message || ( assertion.result ? "okay" : "failed" );
- ol.appendChild( li );
-
- if ( assertion.result ) {
- good++;
- } else {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
-
- // store result when possible
- if ( QUnit.config.reorder && defined.sessionStorage ) {
- if ( bad ) {
- sessionStorage.setItem( "qunit-test-" + this.module + "-" + this.testName, bad );
- } else {
- sessionStorage.removeItem( "qunit-test-" + this.module + "-" + this.testName );
- }
- }
-
- if ( bad === 0 ) {
- addClass( ol, "qunit-collapsed" );
- }
-
- // `b` initialized at top of scope
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml + " (" + bad + ", " + good + ", " + this.assertions.length + ")";
-
- addEvent(b, "click", function() {
- var next = b.parentNode.lastChild,
- collapsed = hasClass( next, "qunit-collapsed" );
- ( collapsed ? removeClass : addClass )( next, "qunit-collapsed" );
- });
-
- addEvent(b, "dblclick", function( e ) {
- var target = e && e.target ? e.target : window.event.srcElement;
- if ( target.nodeName.toLowerCase() === "span" || target.nodeName.toLowerCase() === "b" ) {
- target = target.parentNode;
- }
- if ( window.location && target.nodeName.toLowerCase() === "strong" ) {
- window.location = QUnit.url({ testNumber: test.testNumber });
- }
- });
-
- // `time` initialized at top of scope
- time = document.createElement( "span" );
- time.className = "runtime";
- time.innerHTML = this.runtime + " ms";
-
- // `li` initialized at top of scope
- li = id( this.id );
- li.className = bad ? "fail" : "pass";
- li.removeChild( li.firstChild );
- a = li.firstChild;
- li.appendChild( b );
- li.appendChild( a );
- li.appendChild( time );
- li.appendChild( ol );
-
- } else {
- for ( i = 0; i < this.assertions.length; i++ ) {
- if ( !this.assertions[i].result ) {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
- }
-
- runLoggingCallbacks( "testDone", QUnit, {
- name: this.testName,
- module: this.module,
- failed: bad,
- passed: this.assertions.length - bad,
- total: this.assertions.length,
- duration: this.runtime
- });
-
- QUnit.reset();
-
- config.current = undefined;
- },
-
- queue: function() {
- var bad,
- test = this;
-
- synchronize(function() {
- test.init();
- });
- function run() {
- // each of these can by async
- synchronize(function() {
- test.setup();
- });
- synchronize(function() {
- test.run();
- });
- synchronize(function() {
- test.teardown();
- });
- synchronize(function() {
- test.finish();
- });
- }
-
- // `bad` initialized at top of scope
- // defer when previous test run passed, if storage is available
- bad = QUnit.config.reorder && defined.sessionStorage &&
- +sessionStorage.getItem( "qunit-test-" + this.module + "-" + this.testName );
-
- if ( bad ) {
- run();
- } else {
- synchronize( run, true );
- }
- }
-};
-
-// Root QUnit object.
-// `QUnit` initialized at top of scope
-QUnit = {
-
- // call on start of module test to prepend name to all tests
- module: function( name, testEnvironment ) {
- config.currentModule = name;
- config.currentModuleTestEnvironment = testEnvironment;
- config.modules[name] = true;
- },
-
- asyncTest: function( testName, expected, callback ) {
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- QUnit.test( testName, expected, callback, true );
- },
-
- test: function( testName, expected, callback, async ) {
- var test,
- nameHtml = "" + escapeText( testName ) + "";
-
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- if ( config.currentModule ) {
- nameHtml = "" + escapeText( config.currentModule ) + ": " + nameHtml;
- }
-
- test = new Test({
- nameHtml: nameHtml,
- testName: testName,
- expected: expected,
- async: async,
- callback: callback,
- module: config.currentModule,
- moduleTestEnvironment: config.currentModuleTestEnvironment,
- stack: sourceFromStacktrace( 2 )
- });
-
- if ( !validTest( test ) ) {
- return;
- }
-
- test.queue();
- },
-
- // Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through.
- expect: function( asserts ) {
- if (arguments.length === 1) {
- config.current.expected = asserts;
- } else {
- return config.current.expected;
- }
- },
-
- start: function( count ) {
- // QUnit hasn't been initialized yet.
- // Note: RequireJS (et al) may delay onLoad
- if ( config.semaphore === undefined ) {
- QUnit.begin(function() {
- // This is triggered at the top of QUnit.load, push start() to the event loop, to allow QUnit.load to finish first
- setTimeout(function() {
- QUnit.start( count );
- });
- });
- return;
- }
-
- config.semaphore -= count || 1;
- // don't start until equal number of stop-calls
- if ( config.semaphore > 0 ) {
- return;
- }
- // ignore if start is called more often then stop
- if ( config.semaphore < 0 ) {
- config.semaphore = 0;
- QUnit.pushFailure( "Called start() while already started (QUnit.config.semaphore was 0 already)", null, sourceFromStacktrace(2) );
- return;
- }
- // A slight delay, to avoid any current callbacks
- if ( defined.setTimeout ) {
- window.setTimeout(function() {
- if ( config.semaphore > 0 ) {
- return;
- }
- if ( config.timeout ) {
- clearTimeout( config.timeout );
- }
-
- config.blocking = false;
- process( true );
- }, 13);
- } else {
- config.blocking = false;
- process( true );
- }
- },
-
- stop: function( count ) {
- config.semaphore += count || 1;
- config.blocking = true;
-
- if ( config.testTimeout && defined.setTimeout ) {
- clearTimeout( config.timeout );
- config.timeout = window.setTimeout(function() {
- QUnit.ok( false, "Test timed out" );
- config.semaphore = 1;
- QUnit.start();
- }, config.testTimeout );
- }
- }
-};
-
-// `assert` initialized at top of scope
-// Asssert helpers
-// All of these must either call QUnit.push() or manually do:
-// - runLoggingCallbacks( "log", .. );
-// - config.current.assertions.push({ .. });
-// We attach it to the QUnit object *after* we expose the public API,
-// otherwise `assert` will become a global variable in browsers (#341).
-assert = {
- /**
- * Asserts rough true-ish result.
- * @name ok
- * @function
- * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" );
- */
- ok: function( result, msg ) {
- if ( !config.current ) {
- throw new Error( "ok() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
- result = !!result;
-
- var source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: msg
- };
-
- msg = escapeText( msg || (result ? "okay" : "failed" ) );
- msg = "" + msg + "";
-
- if ( !result ) {
- source = sourceFromStacktrace( 2 );
- if ( source ) {
- details.source = source;
- msg += "Source: | " + escapeText( source ) + " |
---|
";
- }
- }
- runLoggingCallbacks( "log", QUnit, details );
- config.current.assertions.push({
- result: result,
- message: msg
- });
- },
-
- /**
- * Assert that the first two arguments are equal, with an optional message.
- * Prints out both actual and expected values.
- * @name equal
- * @function
- * @example equal( format( "Received {0} bytes.", 2), "Received 2 bytes.", "format() replaces {0} with next argument" );
- */
- equal: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected == actual, actual, expected, message );
- },
-
- /**
- * @name notEqual
- * @function
- */
- notEqual: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected != actual, actual, expected, message );
- },
-
- /**
- * @name propEqual
- * @function
- */
- propEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notPropEqual
- * @function
- */
- notPropEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name deepEqual
- * @function
- */
- deepEqual: function( actual, expected, message ) {
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notDeepEqual
- * @function
- */
- notDeepEqual: function( actual, expected, message ) {
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name strictEqual
- * @function
- */
- strictEqual: function( actual, expected, message ) {
- QUnit.push( expected === actual, actual, expected, message );
- },
-
- /**
- * @name notStrictEqual
- * @function
- */
- notStrictEqual: function( actual, expected, message ) {
- QUnit.push( expected !== actual, actual, expected, message );
- },
-
- "throws": function( block, expected, message ) {
- var actual,
- expectedOutput = expected,
- ok = false;
-
- // 'expected' is optional
- if ( typeof expected === "string" ) {
- message = expected;
- expected = null;
- }
-
- config.current.ignoreGlobalErrors = true;
- try {
- block.call( config.current.testEnvironment );
- } catch (e) {
- actual = e;
- }
- config.current.ignoreGlobalErrors = false;
-
- if ( actual ) {
- // we don't want to validate thrown error
- if ( !expected ) {
- ok = true;
- expectedOutput = null;
- // expected is a regexp
- } else if ( QUnit.objectType( expected ) === "regexp" ) {
- ok = expected.test( errorString( actual ) );
- // expected is a constructor
- } else if ( actual instanceof expected ) {
- ok = true;
- // expected is a validation function which returns true is validation passed
- } else if ( expected.call( {}, actual ) === true ) {
- expectedOutput = null;
- ok = true;
- }
-
- QUnit.push( ok, actual, expectedOutput, message );
- } else {
- QUnit.pushFailure( message, null, 'No exception was thrown.' );
- }
- }
-};
-
-/**
- * @deprecate since 1.8.0
- * Kept assertion helpers in root for backwards compatibility.
- */
-extend( QUnit, assert );
-
-/**
- * @deprecated since 1.9.0
- * Kept root "raises()" for backwards compatibility.
- * (Note that we don't introduce assert.raises).
- */
-QUnit.raises = assert[ "throws" ];
-
-/**
- * @deprecated since 1.0.0, replaced with error pushes since 1.3.0
- * Kept to avoid TypeErrors for undefined methods.
- */
-QUnit.equals = function() {
- QUnit.push( false, false, false, "QUnit.equals has been deprecated since 2009 (e88049a0), use QUnit.equal instead" );
-};
-QUnit.same = function() {
- QUnit.push( false, false, false, "QUnit.same has been deprecated since 2009 (e88049a0), use QUnit.deepEqual instead" );
-};
-
-// We want access to the constructor's prototype
-(function() {
- function F() {}
- F.prototype = QUnit;
- QUnit = new F();
- // Make F QUnit's constructor so that we can add to the prototype later
- QUnit.constructor = F;
-}());
-
-/**
- * Config object: Maintain internal state
- * Later exposed as QUnit.config
- * `config` initialized at top of scope
- */
-config = {
- // The queue of tests to run
- queue: [],
-
- // block until document ready
- blocking: true,
-
- // when enabled, show only failing tests
- // gets persisted through sessionStorage and can be changed in UI via checkbox
- hidepassed: false,
-
- // by default, run previously failed tests first
- // very useful in combination with "Hide passed tests" checked
- reorder: true,
-
- // by default, modify document.title when suite is done
- altertitle: true,
-
- // when enabled, all tests must call expect()
- requireExpects: false,
-
- // add checkboxes that are persisted in the query-string
- // when enabled, the id is set to `true` as a `QUnit.config` property
- urlConfig: [
- {
- id: "noglobals",
- label: "Check for Globals",
- tooltip: "Enabling this will test if any test introduces new properties on the `window` object. Stored as query-strings."
- },
- {
- id: "notrycatch",
- label: "No try-catch",
- tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging exceptions in IE reasonable. Stored as query-strings."
- }
- ],
-
- // Set of all modules.
- modules: {},
-
- // logging callback queues
- begin: [],
- done: [],
- log: [],
- testStart: [],
- testDone: [],
- moduleStart: [],
- moduleDone: []
-};
-
-// Export global variables, unless an 'exports' object exists,
-// in that case we assume we're in CommonJS (dealt with on the bottom of the script)
-if ( typeof exports === "undefined" ) {
- extend( window, QUnit );
-
- // Expose QUnit object
- window.QUnit = QUnit;
-}
-
-// Initialize more QUnit.config and QUnit.urlParams
-(function() {
- var i,
- location = window.location || { search: "", protocol: "file:" },
- params = location.search.slice( 1 ).split( "&" ),
- length = params.length,
- urlParams = {},
- current;
-
- if ( params[ 0 ] ) {
- for ( i = 0; i < length; i++ ) {
- current = params[ i ].split( "=" );
- current[ 0 ] = decodeURIComponent( current[ 0 ] );
- // allow just a key to turn on a flag, e.g., test.html?noglobals
- current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true;
- urlParams[ current[ 0 ] ] = current[ 1 ];
- }
- }
-
- QUnit.urlParams = urlParams;
-
- // String search anywhere in moduleName+testName
- config.filter = urlParams.filter;
-
- // Exact match of the module name
- config.module = urlParams.module;
-
- config.testNumber = parseInt( urlParams.testNumber, 10 ) || null;
-
- // Figure out if we're running the tests from a server or not
- QUnit.isLocal = location.protocol === "file:";
-}());
-
-// Extend QUnit object,
-// these after set here because they should not be exposed as global functions
-extend( QUnit, {
- assert: assert,
-
- config: config,
-
- // Initialize the configuration options
- init: function() {
- extend( config, {
- stats: { all: 0, bad: 0 },
- moduleStats: { all: 0, bad: 0 },
- started: +new Date(),
- updateRate: 1000,
- blocking: false,
- autostart: true,
- autorun: false,
- filter: "",
- queue: [],
- semaphore: 1
- });
-
- var tests, banner, result,
- qunit = id( "qunit" );
-
- if ( qunit ) {
- qunit.innerHTML =
- "" +
- "" +
- "" +
- "" +
- "
";
- }
-
- tests = id( "qunit-tests" );
- banner = id( "qunit-banner" );
- result = id( "qunit-testresult" );
-
- if ( tests ) {
- tests.innerHTML = "";
- }
-
- if ( banner ) {
- banner.className = "";
- }
-
- if ( result ) {
- result.parentNode.removeChild( result );
- }
-
- if ( tests ) {
- result = document.createElement( "p" );
- result.id = "qunit-testresult";
- result.className = "result";
- tests.parentNode.insertBefore( result, tests );
- result.innerHTML = "Running...
";
- }
- },
-
- // Resets the test setup. Useful for tests that modify the DOM.
- reset: function() {
- var fixture = id( "qunit-fixture" );
- if ( fixture ) {
- fixture.innerHTML = config.fixture;
- }
- },
-
- // Trigger an event on an element.
- // @example triggerEvent( document.body, "click" );
- triggerEvent: function( elem, type, event ) {
- if ( document.createEvent ) {
- event = document.createEvent( "MouseEvents" );
- event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView,
- 0, 0, 0, 0, 0, false, false, false, false, 0, null);
-
- elem.dispatchEvent( event );
- } else if ( elem.fireEvent ) {
- elem.fireEvent( "on" + type );
- }
- },
-
- // Safe object type checking
- is: function( type, obj ) {
- return QUnit.objectType( obj ) === type;
- },
-
- objectType: function( obj ) {
- if ( typeof obj === "undefined" ) {
- return "undefined";
- // consider: typeof null === object
- }
- if ( obj === null ) {
- return "null";
- }
-
- var match = toString.call( obj ).match(/^\[object\s(.*)\]$/),
- type = match && match[1] || "";
-
- switch ( type ) {
- case "Number":
- if ( isNaN(obj) ) {
- return "nan";
- }
- return "number";
- case "String":
- case "Boolean":
- case "Array":
- case "Date":
- case "RegExp":
- case "Function":
- return type.toLowerCase();
- }
- if ( typeof obj === "object" ) {
- return "object";
- }
- return undefined;
- },
-
- push: function( result, actual, expected, message ) {
- if ( !config.current ) {
- throw new Error( "assertion outside test context, was " + sourceFromStacktrace() );
- }
-
- var output, source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: message,
- actual: actual,
- expected: expected
- };
-
- message = escapeText( message ) || ( result ? "okay" : "failed" );
- message = "" + message + "";
- output = message;
-
- if ( !result ) {
- expected = escapeText( QUnit.jsDump.parse(expected) );
- actual = escapeText( QUnit.jsDump.parse(actual) );
- output += "Expected: | " + expected + " |
";
-
- if ( actual !== expected ) {
- output += "Result: | " + actual + " |
";
- output += "Diff: | " + QUnit.diff( expected, actual ) + " |
";
- }
-
- source = sourceFromStacktrace();
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
- }
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: !!result,
- message: output
- });
- },
-
- pushFailure: function( message, source, actual ) {
- if ( !config.current ) {
- throw new Error( "pushFailure() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
-
- var output,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: false,
- message: message
- };
-
- message = escapeText( message ) || "error";
- message = "" + message + "";
- output = message;
-
- output += "";
-
- if ( actual ) {
- output += "Result: | " + escapeText( actual ) + " |
";
- }
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: false,
- message: output
- });
- },
-
- url: function( params ) {
- params = extend( extend( {}, QUnit.urlParams ), params );
- var key,
- querystring = "?";
-
- for ( key in params ) {
- if ( !hasOwn.call( params, key ) ) {
- continue;
- }
- querystring += encodeURIComponent( key ) + "=" +
- encodeURIComponent( params[ key ] ) + "&";
- }
- return window.location.protocol + "//" + window.location.host +
- window.location.pathname + querystring.slice( 0, -1 );
- },
-
- extend: extend,
- id: id,
- addEvent: addEvent
- // load, equiv, jsDump, diff: Attached later
-});
-
-/**
- * @deprecated: Created for backwards compatibility with test runner that set the hook function
- * into QUnit.{hook}, instead of invoking it and passing the hook function.
- * QUnit.constructor is set to the empty F() above so that we can add to it's prototype here.
- * Doing this allows us to tell if the following methods have been overwritten on the actual
- * QUnit object.
- */
-extend( QUnit.constructor.prototype, {
-
- // Logging callbacks; all receive a single argument with the listed properties
- // run test/logs.html for any related changes
- begin: registerLoggingCallback( "begin" ),
-
- // done: { failed, passed, total, runtime }
- done: registerLoggingCallback( "done" ),
-
- // log: { result, actual, expected, message }
- log: registerLoggingCallback( "log" ),
-
- // testStart: { name }
- testStart: registerLoggingCallback( "testStart" ),
-
- // testDone: { name, failed, passed, total, duration }
- testDone: registerLoggingCallback( "testDone" ),
-
- // moduleStart: { name }
- moduleStart: registerLoggingCallback( "moduleStart" ),
-
- // moduleDone: { name, failed, passed, total }
- moduleDone: registerLoggingCallback( "moduleDone" )
-});
-
-if ( typeof document === "undefined" || document.readyState === "complete" ) {
- config.autorun = true;
-}
-
-QUnit.load = function() {
- runLoggingCallbacks( "begin", QUnit, {} );
-
- // Initialize the config, saving the execution queue
- var banner, filter, i, label, len, main, ol, toolbar, userAgent, val,
- urlConfigCheckboxesContainer, urlConfigCheckboxes, moduleFilter,
- numModules = 0,
- moduleFilterHtml = "",
- urlConfigHtml = "",
- oldconfig = extend( {}, config );
-
- QUnit.init();
- extend(config, oldconfig);
-
- config.blocking = false;
-
- len = config.urlConfig.length;
-
- for ( i = 0; i < len; i++ ) {
- val = config.urlConfig[i];
- if ( typeof val === "string" ) {
- val = {
- id: val,
- label: val,
- tooltip: "[no tooltip available]"
- };
- }
- config[ val.id ] = QUnit.urlParams[ val.id ];
- urlConfigHtml += "";
- }
-
- moduleFilterHtml += "";
-
- // `userAgent` initialized at top of scope
- userAgent = id( "qunit-userAgent" );
- if ( userAgent ) {
- userAgent.innerHTML = navigator.userAgent;
- }
-
- // `banner` initialized at top of scope
- banner = id( "qunit-header" );
- if ( banner ) {
- banner.innerHTML = "" + banner.innerHTML + " ";
- }
-
- // `toolbar` initialized at top of scope
- toolbar = id( "qunit-testrunner-toolbar" );
- if ( toolbar ) {
- // `filter` initialized at top of scope
- filter = document.createElement( "input" );
- filter.type = "checkbox";
- filter.id = "qunit-filter-pass";
-
- addEvent( filter, "click", function() {
- var tmp,
- ol = document.getElementById( "qunit-tests" );
-
- if ( filter.checked ) {
- ol.className = ol.className + " hidepass";
- } else {
- tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " ";
- ol.className = tmp.replace( / hidepass /, " " );
- }
- if ( defined.sessionStorage ) {
- if (filter.checked) {
- sessionStorage.setItem( "qunit-filter-passed-tests", "true" );
- } else {
- sessionStorage.removeItem( "qunit-filter-passed-tests" );
- }
- }
- });
-
- if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem( "qunit-filter-passed-tests" ) ) {
- filter.checked = true;
- // `ol` initialized at top of scope
- ol = document.getElementById( "qunit-tests" );
- ol.className = ol.className + " hidepass";
- }
- toolbar.appendChild( filter );
-
- // `label` initialized at top of scope
- label = document.createElement( "label" );
- label.setAttribute( "for", "qunit-filter-pass" );
- label.setAttribute( "title", "Only show tests and assertons that fail. Stored in sessionStorage." );
- label.innerHTML = "Hide passed tests";
- toolbar.appendChild( label );
-
- urlConfigCheckboxesContainer = document.createElement("span");
- urlConfigCheckboxesContainer.innerHTML = urlConfigHtml;
- urlConfigCheckboxes = urlConfigCheckboxesContainer.getElementsByTagName("input");
- // For oldIE support:
- // * Add handlers to the individual elements instead of the container
- // * Use "click" instead of "change"
- // * Fallback from event.target to event.srcElement
- addEvents( urlConfigCheckboxes, "click", function( event ) {
- var params = {},
- target = event.target || event.srcElement;
- params[ target.name ] = target.checked ? true : undefined;
- window.location = QUnit.url( params );
- });
- toolbar.appendChild( urlConfigCheckboxesContainer );
-
- if (numModules > 1) {
- moduleFilter = document.createElement( 'span' );
- moduleFilter.setAttribute( 'id', 'qunit-modulefilter-container' );
- moduleFilter.innerHTML = moduleFilterHtml;
- addEvent( moduleFilter.lastChild, "change", function() {
- var selectBox = moduleFilter.getElementsByTagName("select")[0],
- selectedModule = decodeURIComponent(selectBox.options[selectBox.selectedIndex].value);
-
- window.location = QUnit.url( { module: ( selectedModule === "" ) ? undefined : selectedModule } );
- });
- toolbar.appendChild(moduleFilter);
- }
- }
-
- // `main` initialized at top of scope
- main = id( "qunit-fixture" );
- if ( main ) {
- config.fixture = main.innerHTML;
- }
-
- if ( config.autostart ) {
- QUnit.start();
- }
-};
-
-addEvent( window, "load", QUnit.load );
-
-// `onErrorFnPrev` initialized at top of scope
-// Preserve other handlers
-onErrorFnPrev = window.onerror;
-
-// Cover uncaught exceptions
-// Returning true will surpress the default browser handler,
-// returning false will let it run.
-window.onerror = function ( error, filePath, linerNr ) {
- var ret = false;
- if ( onErrorFnPrev ) {
- ret = onErrorFnPrev( error, filePath, linerNr );
- }
-
- // Treat return value as window.onerror itself does,
- // Only do our handling if not surpressed.
- if ( ret !== true ) {
- if ( QUnit.config.current ) {
- if ( QUnit.config.current.ignoreGlobalErrors ) {
- return true;
- }
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- } else {
- QUnit.test( "global failure", extend( function() {
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- }, { validTest: validTest } ) );
- }
- return false;
- }
-
- return ret;
-};
-
-function done() {
- config.autorun = true;
-
- // Log the last module results
- if ( config.currentModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.currentModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
-
- var i, key,
- banner = id( "qunit-banner" ),
- tests = id( "qunit-tests" ),
- runtime = +new Date() - config.started,
- passed = config.stats.all - config.stats.bad,
- html = [
- "Tests completed in ",
- runtime,
- " milliseconds.
",
- "",
- passed,
- " assertions of ",
- config.stats.all,
- " passed, ",
- config.stats.bad,
- " failed."
- ].join( "" );
-
- if ( banner ) {
- banner.className = ( config.stats.bad ? "qunit-fail" : "qunit-pass" );
- }
-
- if ( tests ) {
- id( "qunit-testresult" ).innerHTML = html;
- }
-
- if ( config.altertitle && typeof document !== "undefined" && document.title ) {
- // show ✖ for good, ✔ for bad suite result in title
- // use escape sequences in case file gets loaded with non-utf-8-charset
- document.title = [
- ( config.stats.bad ? "\u2716" : "\u2714" ),
- document.title.replace( /^[\u2714\u2716] /i, "" )
- ].join( " " );
- }
-
- // clear own sessionStorage items if all tests passed
- if ( config.reorder && defined.sessionStorage && config.stats.bad === 0 ) {
- // `key` & `i` initialized at top of scope
- for ( i = 0; i < sessionStorage.length; i++ ) {
- key = sessionStorage.key( i++ );
- if ( key.indexOf( "qunit-test-" ) === 0 ) {
- sessionStorage.removeItem( key );
- }
- }
- }
-
- // scroll back to top to show results
- if ( window.scrollTo ) {
- window.scrollTo(0, 0);
- }
-
- runLoggingCallbacks( "done", QUnit, {
- failed: config.stats.bad,
- passed: passed,
- total: config.stats.all,
- runtime: runtime
- });
-}
-
-/** @return Boolean: true if this test should be ran */
-function validTest( test ) {
- var include,
- filter = config.filter && config.filter.toLowerCase(),
- module = config.module && config.module.toLowerCase(),
- fullName = (test.module + ": " + test.testName).toLowerCase();
-
- // Internally-generated tests are always valid
- if ( test.callback && test.callback.validTest === validTest ) {
- delete test.callback.validTest;
- return true;
- }
-
- if ( config.testNumber ) {
- return test.testNumber === config.testNumber;
- }
-
- if ( module && ( !test.module || test.module.toLowerCase() !== module ) ) {
- return false;
- }
-
- if ( !filter ) {
- return true;
- }
-
- include = filter.charAt( 0 ) !== "!";
- if ( !include ) {
- filter = filter.slice( 1 );
- }
-
- // If the filter matches, we need to honour include
- if ( fullName.indexOf( filter ) !== -1 ) {
- return include;
- }
-
- // Otherwise, do the opposite
- return !include;
-}
-
-// so far supports only Firefox, Chrome and Opera (buggy), Safari (for real exceptions)
-// Later Safari and IE10 are supposed to support error.stack as well
-// See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack
-function extractStacktrace( e, offset ) {
- offset = offset === undefined ? 3 : offset;
-
- var stack, include, i;
-
- if ( e.stacktrace ) {
- // Opera
- return e.stacktrace.split( "\n" )[ offset + 3 ];
- } else if ( e.stack ) {
- // Firefox, Chrome
- stack = e.stack.split( "\n" );
- if (/^error$/i.test( stack[0] ) ) {
- stack.shift();
- }
- if ( fileName ) {
- include = [];
- for ( i = offset; i < stack.length; i++ ) {
- if ( stack[ i ].indexOf( fileName ) !== -1 ) {
- break;
- }
- include.push( stack[ i ] );
- }
- if ( include.length ) {
- return include.join( "\n" );
- }
- }
- return stack[ offset ];
- } else if ( e.sourceURL ) {
- // Safari, PhantomJS
- // hopefully one day Safari provides actual stacktraces
- // exclude useless self-reference for generated Error objects
- if ( /qunit.js$/.test( e.sourceURL ) ) {
- return;
- }
- // for actual exceptions, this is useful
- return e.sourceURL + ":" + e.line;
- }
-}
-function sourceFromStacktrace( offset ) {
- try {
- throw new Error();
- } catch ( e ) {
- return extractStacktrace( e, offset );
- }
-}
-
-/**
- * Escape text for attribute or text content.
- */
-function escapeText( s ) {
- if ( !s ) {
- return "";
- }
- s = s + "";
- // Both single quotes and double quotes (for attributes)
- return s.replace( /['"<>&]/g, function( s ) {
- switch( s ) {
- case '\'':
- return ''';
- case '"':
- return '"';
- case '<':
- return '<';
- case '>':
- return '>';
- case '&':
- return '&';
- }
- });
-}
-
-function synchronize( callback, last ) {
- config.queue.push( callback );
-
- if ( config.autorun && !config.blocking ) {
- process( last );
- }
-}
-
-function process( last ) {
- function next() {
- process( last );
- }
- var start = new Date().getTime();
- config.depth = config.depth ? config.depth + 1 : 1;
-
- while ( config.queue.length && !config.blocking ) {
- if ( !defined.setTimeout || config.updateRate <= 0 || ( ( new Date().getTime() - start ) < config.updateRate ) ) {
- config.queue.shift()();
- } else {
- window.setTimeout( next, 13 );
- break;
- }
- }
- config.depth--;
- if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) {
- done();
- }
-}
-
-function saveGlobal() {
- config.pollution = [];
-
- if ( config.noglobals ) {
- for ( var key in window ) {
- // in Opera sometimes DOM element ids show up here, ignore them
- if ( !hasOwn.call( window, key ) || /^qunit-test-output/.test( key ) ) {
- continue;
- }
- config.pollution.push( key );
- }
- }
-}
-
-function checkPollution() {
- var newGlobals,
- deletedGlobals,
- old = config.pollution;
-
- saveGlobal();
-
- newGlobals = diff( config.pollution, old );
- if ( newGlobals.length > 0 ) {
- QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join(", ") );
- }
-
- deletedGlobals = diff( old, config.pollution );
- if ( deletedGlobals.length > 0 ) {
- QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join(", ") );
- }
-}
-
-// returns a new Array with the elements that are in a but not in b
-function diff( a, b ) {
- var i, j,
- result = a.slice();
-
- for ( i = 0; i < result.length; i++ ) {
- for ( j = 0; j < b.length; j++ ) {
- if ( result[i] === b[j] ) {
- result.splice( i, 1 );
- i--;
- break;
- }
- }
- }
- return result;
-}
-
-function extend( a, b ) {
- for ( var prop in b ) {
- if ( b[ prop ] === undefined ) {
- delete a[ prop ];
-
- // Avoid "Member not found" error in IE8 caused by setting window.constructor
- } else if ( prop !== "constructor" || a !== window ) {
- a[ prop ] = b[ prop ];
- }
- }
-
- return a;
-}
-
-/**
- * @param {HTMLElement} elem
- * @param {string} type
- * @param {Function} fn
- */
-function addEvent( elem, type, fn ) {
- // Standards-based browsers
- if ( elem.addEventListener ) {
- elem.addEventListener( type, fn, false );
- // IE
- } else {
- elem.attachEvent( "on" + type, fn );
- }
-}
-
-/**
- * @param {Array|NodeList} elems
- * @param {string} type
- * @param {Function} fn
- */
-function addEvents( elems, type, fn ) {
- var i = elems.length;
- while ( i-- ) {
- addEvent( elems[i], type, fn );
- }
-}
-
-function hasClass( elem, name ) {
- return (" " + elem.className + " ").indexOf(" " + name + " ") > -1;
-}
-
-function addClass( elem, name ) {
- if ( !hasClass( elem, name ) ) {
- elem.className += (elem.className ? " " : "") + name;
- }
-}
-
-function removeClass( elem, name ) {
- var set = " " + elem.className + " ";
- // Class name may appear multiple times
- while ( set.indexOf(" " + name + " ") > -1 ) {
- set = set.replace(" " + name + " " , " ");
- }
- // If possible, trim it for prettiness, but not neccecarily
- elem.className = window.jQuery ? jQuery.trim( set ) : ( set.trim ? set.trim() : set );
-}
-
-function id( name ) {
- return !!( typeof document !== "undefined" && document && document.getElementById ) &&
- document.getElementById( name );
-}
-
-function registerLoggingCallback( key ) {
- return function( callback ) {
- config[key].push( callback );
- };
-}
-
-// Supports deprecated method of completely overwriting logging callbacks
-function runLoggingCallbacks( key, scope, args ) {
- var i, callbacks;
- if ( QUnit.hasOwnProperty( key ) ) {
- QUnit[ key ].call(scope, args );
- } else {
- callbacks = config[ key ];
- for ( i = 0; i < callbacks.length; i++ ) {
- callbacks[ i ].call( scope, args );
- }
- }
-}
-
-// Test for equality any JavaScript type.
-// Author: Philippe Rathé
-QUnit.equiv = (function() {
-
- // Call the o related callback with the given arguments.
- function bindCallbacks( o, callbacks, args ) {
- var prop = QUnit.objectType( o );
- if ( prop ) {
- if ( QUnit.objectType( callbacks[ prop ] ) === "function" ) {
- return callbacks[ prop ].apply( callbacks, args );
- } else {
- return callbacks[ prop ]; // or undefined
- }
- }
- }
-
- // the real equiv function
- var innerEquiv,
- // stack to decide between skip/abort functions
- callers = [],
- // stack to avoiding loops from circular referencing
- parents = [],
-
- getProto = Object.getPrototypeOf || function ( obj ) {
- return obj.__proto__;
- },
- callbacks = (function () {
-
- // for string, boolean, number and null
- function useStrictEquality( b, a ) {
- /*jshint eqeqeq:false */
- if ( b instanceof a.constructor || a instanceof b.constructor ) {
- // to catch short annotaion VS 'new' annotation of a
- // declaration
- // e.g. var i = 1;
- // var j = new Number(1);
- return a == b;
- } else {
- return a === b;
- }
- }
-
- return {
- "string": useStrictEquality,
- "boolean": useStrictEquality,
- "number": useStrictEquality,
- "null": useStrictEquality,
- "undefined": useStrictEquality,
-
- "nan": function( b ) {
- return isNaN( b );
- },
-
- "date": function( b, a ) {
- return QUnit.objectType( b ) === "date" && a.valueOf() === b.valueOf();
- },
-
- "regexp": function( b, a ) {
- return QUnit.objectType( b ) === "regexp" &&
- // the regex itself
- a.source === b.source &&
- // and its modifers
- a.global === b.global &&
- // (gmi) ...
- a.ignoreCase === b.ignoreCase &&
- a.multiline === b.multiline &&
- a.sticky === b.sticky;
- },
-
- // - skip when the property is a method of an instance (OOP)
- // - abort otherwise,
- // initial === would have catch identical references anyway
- "function": function() {
- var caller = callers[callers.length - 1];
- return caller !== Object && typeof caller !== "undefined";
- },
-
- "array": function( b, a ) {
- var i, j, len, loop;
-
- // b could be an object literal here
- if ( QUnit.objectType( b ) !== "array" ) {
- return false;
- }
-
- len = a.length;
- if ( len !== b.length ) {
- // safe and faster
- return false;
- }
-
- // track reference to avoid circular references
- parents.push( a );
- for ( i = 0; i < len; i++ ) {
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- loop = true;// dont rewalk array
- }
- }
- if ( !loop && !innerEquiv(a[i], b[i]) ) {
- parents.pop();
- return false;
- }
- }
- parents.pop();
- return true;
- },
-
- "object": function( b, a ) {
- var i, j, loop,
- // Default to true
- eq = true,
- aProperties = [],
- bProperties = [];
-
- // comparing constructors is more strict than using
- // instanceof
- if ( a.constructor !== b.constructor ) {
- // Allow objects with no prototype to be equivalent to
- // objects with Object as their constructor.
- if ( !(( getProto(a) === null && getProto(b) === Object.prototype ) ||
- ( getProto(b) === null && getProto(a) === Object.prototype ) ) ) {
- return false;
- }
- }
-
- // stack constructor before traversing properties
- callers.push( a.constructor );
- // track reference to avoid circular references
- parents.push( a );
-
- for ( i in a ) { // be strict: don't ensures hasOwnProperty
- // and go deep
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- // don't go down the same path twice
- loop = true;
- }
- }
- aProperties.push(i); // collect a's properties
-
- if (!loop && !innerEquiv( a[i], b[i] ) ) {
- eq = false;
- break;
- }
- }
-
- callers.pop(); // unstack, we are done
- parents.pop();
-
- for ( i in b ) {
- bProperties.push( i ); // collect b's properties
- }
-
- // Ensures identical properties name
- return eq && innerEquiv( aProperties.sort(), bProperties.sort() );
- }
- };
- }());
-
- innerEquiv = function() { // can take multiple arguments
- var args = [].slice.apply( arguments );
- if ( args.length < 2 ) {
- return true; // end transition
- }
-
- return (function( a, b ) {
- if ( a === b ) {
- return true; // catch the most you can
- } else if ( a === null || b === null || typeof a === "undefined" ||
- typeof b === "undefined" ||
- QUnit.objectType(a) !== QUnit.objectType(b) ) {
- return false; // don't lose time with error prone cases
- } else {
- return bindCallbacks(a, callbacks, [ b, a ]);
- }
-
- // apply transition with (1..n) arguments
- }( args[0], args[1] ) && arguments.callee.apply( this, args.splice(1, args.length - 1 )) );
- };
-
- return innerEquiv;
-}());
-
-/**
- * jsDump Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com |
- * http://flesler.blogspot.com Licensed under BSD
- * (http://www.opensource.org/licenses/bsd-license.php) Date: 5/15/2008
- *
- * @projectDescription Advanced and extensible data dumping for Javascript.
- * @version 1.0.0
- * @author Ariel Flesler
- * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html}
- */
-QUnit.jsDump = (function() {
- function quote( str ) {
- return '"' + str.toString().replace( /"/g, '\\"' ) + '"';
- }
- function literal( o ) {
- return o + "";
- }
- function join( pre, arr, post ) {
- var s = jsDump.separator(),
- base = jsDump.indent(),
- inner = jsDump.indent(1);
- if ( arr.join ) {
- arr = arr.join( "," + s + inner );
- }
- if ( !arr ) {
- return pre + post;
- }
- return [ pre, inner + arr, base + post ].join(s);
- }
- function array( arr, stack ) {
- var i = arr.length, ret = new Array(i);
- this.up();
- while ( i-- ) {
- ret[i] = this.parse( arr[i] , undefined , stack);
- }
- this.down();
- return join( "[", ret, "]" );
- }
-
- var reName = /^function (\w+)/,
- jsDump = {
- // type is used mostly internally, you can fix a (custom)type in advance
- parse: function( obj, type, stack ) {
- stack = stack || [ ];
- var inStack, res,
- parser = this.parsers[ type || this.typeOf(obj) ];
-
- type = typeof parser;
- inStack = inArray( obj, stack );
-
- if ( inStack !== -1 ) {
- return "recursion(" + (inStack - stack.length) + ")";
- }
- if ( type === "function" ) {
- stack.push( obj );
- res = parser.call( this, obj, stack );
- stack.pop();
- return res;
- }
- return ( type === "string" ) ? parser : this.parsers.error;
- },
- typeOf: function( obj ) {
- var type;
- if ( obj === null ) {
- type = "null";
- } else if ( typeof obj === "undefined" ) {
- type = "undefined";
- } else if ( QUnit.is( "regexp", obj) ) {
- type = "regexp";
- } else if ( QUnit.is( "date", obj) ) {
- type = "date";
- } else if ( QUnit.is( "function", obj) ) {
- type = "function";
- } else if ( typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined" ) {
- type = "window";
- } else if ( obj.nodeType === 9 ) {
- type = "document";
- } else if ( obj.nodeType ) {
- type = "node";
- } else if (
- // native arrays
- toString.call( obj ) === "[object Array]" ||
- // NodeList objects
- ( typeof obj.length === "number" && typeof obj.item !== "undefined" && ( obj.length ? obj.item(0) === obj[0] : ( obj.item( 0 ) === null && typeof obj[0] === "undefined" ) ) )
- ) {
- type = "array";
- } else if ( obj.constructor === Error.prototype.constructor ) {
- type = "error";
- } else {
- type = typeof obj;
- }
- return type;
- },
- separator: function() {
- return this.multiline ? this.HTML ? "
" : "\n" : this.HTML ? " " : " ";
- },
- // extra can be a number, shortcut for increasing-calling-decreasing
- indent: function( extra ) {
- if ( !this.multiline ) {
- return "";
- }
- var chr = this.indentChar;
- if ( this.HTML ) {
- chr = chr.replace( /\t/g, " " ).replace( / /g, " " );
- }
- return new Array( this._depth_ + (extra||0) ).join(chr);
- },
- up: function( a ) {
- this._depth_ += a || 1;
- },
- down: function( a ) {
- this._depth_ -= a || 1;
- },
- setParser: function( name, parser ) {
- this.parsers[name] = parser;
- },
- // The next 3 are exposed so you can use them
- quote: quote,
- literal: literal,
- join: join,
- //
- _depth_: 1,
- // This is the list of parsers, to modify them, use jsDump.setParser
- parsers: {
- window: "[Window]",
- document: "[Document]",
- error: function(error) {
- return "Error(\"" + error.message + "\")";
- },
- unknown: "[Unknown]",
- "null": "null",
- "undefined": "undefined",
- "function": function( fn ) {
- var ret = "function",
- // functions never have name in IE
- name = "name" in fn ? fn.name : (reName.exec(fn) || [])[1];
-
- if ( name ) {
- ret += " " + name;
- }
- ret += "( ";
-
- ret = [ ret, QUnit.jsDump.parse( fn, "functionArgs" ), "){" ].join( "" );
- return join( ret, QUnit.jsDump.parse(fn,"functionCode" ), "}" );
- },
- array: array,
- nodelist: array,
- "arguments": array,
- object: function( map, stack ) {
- var ret = [ ], keys, key, val, i;
- QUnit.jsDump.up();
- keys = [];
- for ( key in map ) {
- keys.push( key );
- }
- keys.sort();
- for ( i = 0; i < keys.length; i++ ) {
- key = keys[ i ];
- val = map[ key ];
- ret.push( QUnit.jsDump.parse( key, "key" ) + ": " + QUnit.jsDump.parse( val, undefined, stack ) );
- }
- QUnit.jsDump.down();
- return join( "{", ret, "}" );
- },
- node: function( node ) {
- var len, i, val,
- open = QUnit.jsDump.HTML ? "<" : "<",
- close = QUnit.jsDump.HTML ? ">" : ">",
- tag = node.nodeName.toLowerCase(),
- ret = open + tag,
- attrs = node.attributes;
-
- if ( attrs ) {
- for ( i = 0, len = attrs.length; i < len; i++ ) {
- val = attrs[i].nodeValue;
- // IE6 includes all attributes in .attributes, even ones not explicitly set.
- // Those have values like undefined, null, 0, false, "" or "inherit".
- if ( val && val !== "inherit" ) {
- ret += " " + attrs[i].nodeName + "=" + QUnit.jsDump.parse( val, "attribute" );
- }
- }
- }
- ret += close;
-
- // Show content of TextNode or CDATASection
- if ( node.nodeType === 3 || node.nodeType === 4 ) {
- ret += node.nodeValue;
- }
-
- return ret + open + "/" + tag + close;
- },
- // function calls it internally, it's the arguments part of the function
- functionArgs: function( fn ) {
- var args,
- l = fn.length;
-
- if ( !l ) {
- return "";
- }
-
- args = new Array(l);
- while ( l-- ) {
- // 97 is 'a'
- args[l] = String.fromCharCode(97+l);
- }
- return " " + args.join( ", " ) + " ";
- },
- // object calls it internally, the key part of an item in a map
- key: quote,
- // function calls it internally, it's the content of the function
- functionCode: "[code]",
- // node calls it internally, it's an html attribute value
- attribute: quote,
- string: quote,
- date: quote,
- regexp: literal,
- number: literal,
- "boolean": literal
- },
- // if true, entities are escaped ( <, >, \t, space and \n )
- HTML: false,
- // indentation unit
- indentChar: " ",
- // if true, items in a collection, are separated by a \n, else just a space.
- multiline: true
- };
-
- return jsDump;
-}());
-
-// from jquery.js
-function inArray( elem, array ) {
- if ( array.indexOf ) {
- return array.indexOf( elem );
- }
-
- for ( var i = 0, length = array.length; i < length; i++ ) {
- if ( array[ i ] === elem ) {
- return i;
- }
- }
-
- return -1;
-}
-
-/*
- * Javascript Diff Algorithm
- * By John Resig (http://ejohn.org/)
- * Modified by Chu Alan "sprite"
- *
- * Released under the MIT license.
- *
- * More Info:
- * http://ejohn.org/projects/javascript-diff-algorithm/
- *
- * Usage: QUnit.diff(expected, actual)
- *
- * QUnit.diff( "the quick brown fox jumped over", "the quick fox jumps over" ) == "the quick brown fox jumped jumps over"
- */
-QUnit.diff = (function() {
- /*jshint eqeqeq:false, eqnull:true */
- function diff( o, n ) {
- var i,
- ns = {},
- os = {};
-
- for ( i = 0; i < n.length; i++ ) {
- if ( !hasOwn.call( ns, n[i] ) ) {
- ns[ n[i] ] = {
- rows: [],
- o: null
- };
- }
- ns[ n[i] ].rows.push( i );
- }
-
- for ( i = 0; i < o.length; i++ ) {
- if ( !hasOwn.call( os, o[i] ) ) {
- os[ o[i] ] = {
- rows: [],
- n: null
- };
- }
- os[ o[i] ].rows.push( i );
- }
-
- for ( i in ns ) {
- if ( !hasOwn.call( ns, i ) ) {
- continue;
- }
- if ( ns[i].rows.length === 1 && hasOwn.call( os, i ) && os[i].rows.length === 1 ) {
- n[ ns[i].rows[0] ] = {
- text: n[ ns[i].rows[0] ],
- row: os[i].rows[0]
- };
- o[ os[i].rows[0] ] = {
- text: o[ os[i].rows[0] ],
- row: ns[i].rows[0]
- };
- }
- }
-
- for ( i = 0; i < n.length - 1; i++ ) {
- if ( n[i].text != null && n[ i + 1 ].text == null && n[i].row + 1 < o.length && o[ n[i].row + 1 ].text == null &&
- n[ i + 1 ] == o[ n[i].row + 1 ] ) {
-
- n[ i + 1 ] = {
- text: n[ i + 1 ],
- row: n[i].row + 1
- };
- o[ n[i].row + 1 ] = {
- text: o[ n[i].row + 1 ],
- row: i + 1
- };
- }
- }
-
- for ( i = n.length - 1; i > 0; i-- ) {
- if ( n[i].text != null && n[ i - 1 ].text == null && n[i].row > 0 && o[ n[i].row - 1 ].text == null &&
- n[ i - 1 ] == o[ n[i].row - 1 ]) {
-
- n[ i - 1 ] = {
- text: n[ i - 1 ],
- row: n[i].row - 1
- };
- o[ n[i].row - 1 ] = {
- text: o[ n[i].row - 1 ],
- row: i - 1
- };
- }
- }
-
- return {
- o: o,
- n: n
- };
- }
-
- return function( o, n ) {
- o = o.replace( /\s+$/, "" );
- n = n.replace( /\s+$/, "" );
-
- var i, pre,
- str = "",
- out = diff( o === "" ? [] : o.split(/\s+/), n === "" ? [] : n.split(/\s+/) ),
- oSpace = o.match(/\s+/g),
- nSpace = n.match(/\s+/g);
-
- if ( oSpace == null ) {
- oSpace = [ " " ];
- }
- else {
- oSpace.push( " " );
- }
-
- if ( nSpace == null ) {
- nSpace = [ " " ];
- }
- else {
- nSpace.push( " " );
- }
-
- if ( out.n.length === 0 ) {
- for ( i = 0; i < out.o.length; i++ ) {
- str += "" + out.o[i] + oSpace[i] + "";
- }
- }
- else {
- if ( out.n[0].text == null ) {
- for ( n = 0; n < out.o.length && out.o[n].text == null; n++ ) {
- str += "" + out.o[n] + oSpace[n] + "";
- }
- }
-
- for ( i = 0; i < out.n.length; i++ ) {
- if (out.n[i].text == null) {
- str += "" + out.n[i] + nSpace[i] + "";
- }
- else {
- // `pre` initialized at top of scope
- pre = "";
-
- for ( n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++ ) {
- pre += "" + out.o[n] + oSpace[n] + "";
- }
- str += " " + out.n[i].text + nSpace[i] + pre;
- }
- }
- }
-
- return str;
- };
-}());
-
-// for CommonJS enviroments, export everything
-if ( typeof exports !== "undefined" ) {
- extend( exports, QUnit );
-}
-
-// get at whatever the global object is, like window in browsers
-}( (function() {return this;}.call()) ));
diff --git a/test/lib/require.js b/test/lib/require.js
deleted file mode 100644
index 987f865..0000000
--- a/test/lib/require.js
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- RequireJS 2.1.5 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.
- Available via the MIT or new BSD license.
- see: http://github.com/jrburke/requirejs for details
-*/
-var requirejs,require,define;
-(function(aa){function I(b){return"[object Function]"===L.call(b)}function J(b){return"[object Array]"===L.call(b)}function y(b,c){if(b){var d;for(d=0;dthis.depCount&&!this.defined){if(I(n)){if(this.events.error)try{e=i.execCb(c,n,b,e)}catch(d){a=d}else e=i.execCb(c,n,b,e);this.map.isDefine&&((b=this.module)&&void 0!==b.exports&&b.exports!==this.exports?e=b.exports:void 0===e&&this.usingExports&&(e=this.exports));if(a)return a.requireMap=this.map,a.requireModules=[this.map.id],a.requireType="define",v(this.error=
-a)}else e=n;this.exports=e;if(this.map.isDefine&&!this.ignore&&(q[c]=e,l.onResourceLoad))l.onResourceLoad(i,this.map,this.depMaps);x(c);this.defined=!0}this.defining=!1;this.defined&&!this.defineEmitted&&(this.defineEmitted=!0,this.emit("defined",this.exports),this.defineEmitComplete=!0)}}else this.fetch()}},callPlugin:function(){var a=this.map,b=a.id,d=j(a.prefix);this.depMaps.push(d);t(d,"defined",u(this,function(e){var n,d;d=this.map.name;var g=this.map.parentMap?this.map.parentMap.name:null,h=
-i.makeRequire(a.parentMap,{enableBuildCallback:!0});if(this.map.unnormalized){if(e.normalize&&(d=e.normalize(d,function(a){return c(a,g,!0)})||""),e=j(a.prefix+"!"+d,this.map.parentMap),t(e,"defined",u(this,function(a){this.init([],function(){return a},null,{enabled:!0,ignore:!0})})),d=m(p,e.id)){this.depMaps.push(e);if(this.events.error)d.on("error",u(this,function(a){this.emit("error",a)}));d.enable()}}else n=u(this,function(a){this.init([],function(){return a},null,{enabled:!0})}),n.error=u(this,
-function(a){this.inited=!0;this.error=a;a.requireModules=[b];G(p,function(a){0===a.map.id.indexOf(b+"_unnormalized")&&x(a.map.id)});v(a)}),n.fromText=u(this,function(e,c){var d=a.name,g=j(d),C=O;c&&(e=c);C&&(O=!1);r(g);s(k.config,b)&&(k.config[d]=k.config[b]);try{l.exec(e)}catch(ca){return v(B("fromtexteval","fromText eval for "+b+" failed: "+ca,ca,[b]))}C&&(O=!0);this.depMaps.push(g);i.completeLoad(d);h([d],n)}),e.load(a.name,h,n,k)}));i.enable(d,this);this.pluginMaps[d.id]=d},enable:function(){V[this.map.id]=
-this;this.enabling=this.enabled=!0;y(this.depMaps,u(this,function(a,b){var c,e;if("string"===typeof a){a=j(a,this.map.isDefine?this.map:this.map.parentMap,!1,!this.skipMap);this.depMaps[b]=a;if(c=m(N,a.id)){this.depExports[b]=c(this);return}this.depCount+=1;t(a,"defined",u(this,function(a){this.defineDep(b,a);this.check()}));this.errback&&t(a,"error",this.errback)}c=a.id;e=p[c];!s(N,c)&&(e&&!e.enabled)&&i.enable(a,this)}));G(this.pluginMaps,u(this,function(a){var b=m(p,a.id);b&&!b.enabled&&i.enable(a,
-this)}));this.enabling=!1;this.check()},on:function(a,b){var c=this.events[a];c||(c=this.events[a]=[]);c.push(b)},emit:function(a,b){y(this.events[a],function(a){a(b)});"error"===a&&delete this.events[a]}};i={config:k,contextName:b,registry:p,defined:q,urlFetched:U,defQueue:H,Module:Z,makeModuleMap:j,nextTick:l.nextTick,onError:v,configure:function(a){a.baseUrl&&"/"!==a.baseUrl.charAt(a.baseUrl.length-1)&&(a.baseUrl+="/");var b=k.pkgs,c=k.shim,e={paths:!0,config:!0,map:!0};G(a,function(a,b){e[b]?
-"map"===b?(k.map||(k.map={}),R(k[b],a,!0,!0)):R(k[b],a,!0):k[b]=a});a.shim&&(G(a.shim,function(a,b){J(a)&&(a={deps:a});if((a.exports||a.init)&&!a.exportsFn)a.exportsFn=i.makeShimExports(a);c[b]=a}),k.shim=c);a.packages&&(y(a.packages,function(a){a="string"===typeof a?{name:a}:a;b[a.name]={name:a.name,location:a.location||a.name,main:(a.main||"main").replace(ja,"").replace(ea,"")}}),k.pkgs=b);G(p,function(a,b){!a.inited&&!a.map.unnormalized&&(a.map=j(b))});if(a.deps||a.callback)i.require(a.deps||[],
-a.callback)},makeShimExports:function(a){return function(){var b;a.init&&(b=a.init.apply(aa,arguments));return b||a.exports&&ba(a.exports)}},makeRequire:function(a,f){function d(e,c,h){var g,k;f.enableBuildCallback&&(c&&I(c))&&(c.__requireJsBuild=!0);if("string"===typeof e){if(I(c))return v(B("requireargs","Invalid require call"),h);if(a&&s(N,e))return N[e](p[a.id]);if(l.get)return l.get(i,e,a,d);g=j(e,a,!1,!0);g=g.id;return!s(q,g)?v(B("notloaded",'Module name "'+g+'" has not been loaded yet for context: '+
-b+(a?"":". Use require([])"))):q[g]}L();i.nextTick(function(){L();k=r(j(null,a));k.skipMap=f.skipMap;k.init(e,c,h,{enabled:!0});D()});return d}f=f||{};R(d,{isBrowser:A,toUrl:function(b){var d,f=b.lastIndexOf("."),g=b.split("/")[0];if(-1!==f&&(!("."===g||".."===g)||1h.attachEvent.toString().indexOf("[native code"))&&!Y?(O=!0,h.attachEvent("onreadystatechange",b.onScriptLoad)):(h.addEventListener("load",b.onScriptLoad,!1),h.addEventListener("error",b.onScriptError,!1)),h.src=d,K=h,D?x.insertBefore(h,D):x.appendChild(h),K=null,h;if(da)try{importScripts(d),b.completeLoad(c)}catch(j){b.onError(B("importscripts","importScripts failed for "+c+" at "+d,j,[c]))}};A&&M(document.getElementsByTagName("script"),function(b){x||(x=
-b.parentNode);if(t=b.getAttribute("data-main"))return r.baseUrl||(E=t.split("/"),Q=E.pop(),fa=E.length?E.join("/")+"/":"./",r.baseUrl=fa,t=Q),t=t.replace(ea,""),r.deps=r.deps?r.deps.concat(t):[t],!0});define=function(b,c,d){var l,h;"string"!==typeof b&&(d=c,c=b,b=null);J(c)||(d=c,c=[]);!c.length&&I(d)&&d.length&&(d.toString().replace(la,"").replace(ma,function(b,d){c.push(d)}),c=(1===d.length?["require"]:["require","exports","module"]).concat(c));if(O){if(!(l=K))P&&"interactive"===P.readyState||M(document.getElementsByTagName("script"),
-function(b){if("interactive"===b.readyState)return P=b}),l=P;l&&(b||(b=l.getAttribute("data-requiremodule")),h=F[l.getAttribute("data-requirecontext")])}(h?h.defQueue:T).push([b,c,d])};define.amd={jQuery:!0};l.exec=function(b){return eval(b)};l(r)}})(this);
diff --git a/test/lib/resemble.js b/test/lib/resemble.js
new file mode 100644
index 0000000..1cb8c29
--- /dev/null
+++ b/test/lib/resemble.js
@@ -0,0 +1,535 @@
+/*
+Author: James Cryer
+Company: Huddle
+Last updated date: 21 Feb 2013
+URL: https://github.com/Huddle/Resemble.js
+*/
+
+(function(_this){
+ 'use strict';
+
+ _this['resemble'] = function( fileData ){
+
+ var data = {};
+ var images = [];
+ var updateCallbackArray = [];
+
+ var tolerance = { // between 0 and 255
+ red: 16,
+ green: 16,
+ blue: 16,
+ minBrightness: 16,
+ maxBrightness: 240
+ };
+
+ var ignoreAntialiasing = false;
+ var ignoreColors = false;
+
+ function triggerDataUpdate(){
+ var len = updateCallbackArray.length;
+ var i;
+ for(i=0;i tolerance.maxBrightness;
+ }
+
+ function getHue(r,g,b){
+
+ r = r / 255;
+ g = g / 255;
+ b = b / 255;
+ var max = Math.max(r, g, b), min = Math.min(r, g, b);
+ var h;
+ var d;
+
+ if (max == min){
+ h = 0; // achromatic
+ } else{
+ d = max - min;
+ switch(max){
+ case r: h = (g - b) / d + (g < b ? 6 : 0); break;
+ case g: h = (b - r) / d + 2; break;
+ case b: h = (r - g) / d + 4; break;
+ }
+ h /= 6;
+ }
+
+ return h;
+ }
+
+ function isAntialiased(sourcePix, data, cacheSet, verticalPos, horizontalPos, width){
+ var offset;
+ var targetPix;
+ var distance = 1;
+ var i;
+ var j;
+ var hasHighContrastSibling = 0;
+ var hasSiblingWithDifferentHue = 0;
+ var hasEquivilantSibling = 0;
+
+ addHueInfo(sourcePix);
+
+ for (i = distance*-1; i <= distance; i++){
+ for (j = distance*-1; j <= distance; j++){
+
+ if(i===0 && j===0){
+ // ignore source pixel
+ } else {
+
+ offset = ((verticalPos+j)*width + (horizontalPos+i)) * 4;
+ targetPix = getPixelInfo(data, offset, cacheSet);
+
+ if(targetPix === null){
+ continue;
+ }
+
+ addBrightnessInfo(targetPix);
+ addHueInfo(targetPix);
+
+ if( isContrasting(sourcePix, targetPix) ){
+ hasHighContrastSibling++;
+ }
+
+ if( isRGBSame(sourcePix,targetPix) ){
+ hasEquivilantSibling++;
+ }
+
+ if( Math.abs(targetPix.h - sourcePix.h) > 0.3 ){
+ hasSiblingWithDifferentHue++;
+ }
+
+ if( hasSiblingWithDifferentHue > 1 || hasHighContrastSibling > 1){
+ return true;
+ }
+ }
+ }
+ }
+
+ if(hasEquivilantSibling < 2){
+ return true;
+ }
+
+ return false;
+ }
+
+ function errorPixel(px, offset){
+ px[offset] = 255; //r
+ px[offset + 1] = 0; //g
+ px[offset + 2] = 255; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyPixel(px, offset, data){
+ px[offset] = data.r; //r
+ px[offset + 1] = data.g; //g
+ px[offset + 2] = data.b; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyGrayScalePixel(px, offset, data){
+ px[offset] = data.brightness; //r
+ px[offset + 1] = data.brightness; //g
+ px[offset + 2] = data.brightness; //b
+ px[offset + 3] = 255; //a
+ }
+
+
+ function getPixelInfo(data, offset, cacheSet){
+ var r;
+ var g;
+ var b;
+ var d;
+
+ if(typeof data[offset] !== 'undefined'){
+ r = data[offset];
+ g = data[offset+1];
+ b = data[offset+2];
+ d = {
+ r: r,
+ g: g,
+ b: b
+ };
+
+ return d;
+ } else {
+ return null;
+ }
+ }
+
+ function addBrightnessInfo(data){
+ data.brightness = getBrightness(data.r,data.g,data.b); // 'corrected' lightness
+ }
+
+ function addHueInfo(data){
+ data.h = getHue(data.r,data.g,data.b);
+ }
+
+ function analyseImages(img1, img2, width, height){
+
+ var hiddenCanvas = document.createElement('canvas');
+
+ var data1 = img1.data;
+ var data2 = img2.data;
+
+ hiddenCanvas.width = width;
+ hiddenCanvas.height = height;
+
+ var context = hiddenCanvas.getContext('2d');
+ var imgd = context.createImageData(width,height);
+ var targetPix = imgd.data;
+
+ var mismatchCount = 0;
+
+ var time = Date.now();
+
+ var skip;
+
+ if( (width > 1200 || height > 1200) && ignoreAntialiasing){
+ skip = 6;
+ }
+
+ loop(height, width, function(verticalPos, horizontalPos){
+
+ if(skip){ // only skip if the image isn't small
+ if(verticalPos % skip === 0 || horizontalPos % skip === 0){
+ return;
+ }
+ }
+
+ var offset = (verticalPos*width + horizontalPos) * 4;
+ var pixel1 = getPixelInfo(data1, offset, 1);
+ var pixel2 = getPixelInfo(data2, offset, 2);
+
+ if(pixel1 === null || pixel2 === null){
+ return;
+ }
+
+ if (ignoreColors){
+
+ addBrightnessInfo(pixel1);
+ addBrightnessInfo(pixel2);
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ return;
+ }
+
+ if( isRGBSimilar(pixel1, pixel2) ){
+ copyPixel(targetPix, offset, pixel2);
+
+ } else if( ignoreAntialiasing && (
+ addBrightnessInfo(pixel1), // jit pixel info augmentation looks a little weird, sorry.
+ addBrightnessInfo(pixel2),
+ isAntialiased(pixel1, data1, 1, verticalPos, horizontalPos, width) ||
+ isAntialiased(pixel2, data2, 2, verticalPos, horizontalPos, width)
+ )){
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+
+ });
+
+ data.misMatchPercentage = (mismatchCount / (height*width) * 100).toFixed(2);
+ data.analysisTime = Date.now() - time;
+
+ data.getImageDataUrl = function(text){
+ var barHeight = 0;
+
+ if(text){
+ barHeight = addLabel(text,context,hiddenCanvas);
+ }
+
+ context.putImageData(imgd, 0, barHeight);
+
+ return hiddenCanvas.toDataURL("image/png");
+ };
+ }
+
+ function addLabel(text, context, hiddenCanvas){
+ var textPadding = 2;
+
+ context.font = '12px sans-serif';
+
+ var textWidth = context.measureText(text).width + textPadding*2;
+ var barHeight = 22;
+
+ if(textWidth > hiddenCanvas.width){
+ hiddenCanvas.width = textWidth;
+ }
+
+ hiddenCanvas.height += barHeight;
+
+ context.fillStyle = "#666";
+ context.fillRect(0,0,hiddenCanvas.width,barHeight -4);
+ context.fillStyle = "#fff";
+ context.fillRect(0,barHeight -4,hiddenCanvas.width, 4);
+
+ context.fillStyle = "#fff";
+ context.textBaseline = "top";
+ context.font = '12px sans-serif';
+ context.fillText(text, textPadding, 1);
+
+ return barHeight;
+ }
+
+ function normalise(img, w, h){
+ var c;
+ var context;
+
+ if(img.height < h || img.width < w){
+ c = document.createElement('canvas');
+ c.width = w;
+ c.height = h;
+ context = c.getContext('2d');
+ context.putImageData(img, 0, 0);
+ return context.getImageData(0, 0, w, h);
+ }
+
+ return img;
+ }
+
+ function compare(one, two){
+
+ function onceWeHaveBoth(){
+ var width;
+ var height;
+ if(images.length === 2){
+ width = images[0].width > images[1].width ? images[0].width : images[1].width;
+ height = images[0].height > images[1].height ? images[0].height : images[1].height;
+
+ if( (images[0].width === images[1].width) && (images[0].height === images[1].height) ){
+ data.isSameDimensions = true;
+ } else {
+ data.isSameDimensions = false;
+ }
+
+ analyseImages( normalise(images[0],width, height), normalise(images[1],width, height), width, height);
+
+ triggerDataUpdate();
+ }
+ }
+
+ images = [];
+ loadImageData(one, onceWeHaveBoth);
+ loadImageData(two, onceWeHaveBoth);
+ }
+
+ function getCompareApi(param){
+
+ var secondFileData,
+ hasMethod = typeof param === 'function';
+
+ if( !hasMethod ){
+ // assume it's file data
+ secondFileData = param;
+ }
+
+ var self = {
+ ignoreNothing: function(){
+
+ tolerance.red = 16;
+ tolerance.green = 16;
+ tolerance.blue = 16;
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreAntialiasing: function(){
+
+ tolerance.red = 32;
+ tolerance.green = 32;
+ tolerance.blue = 32;
+ tolerance.minBrightness = 64;
+ tolerance.maxBrightness = 96;
+
+ ignoreAntialiasing = true;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreColors: function(){
+
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = true;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ onComplete: function( callback ){
+
+ updateCallbackArray.push(callback);
+
+ var wrapper = function(){
+ compare(fileData, secondFileData);
+ };
+
+ wrapper();
+
+ return getCompareApi(wrapper);
+ }
+ };
+
+ return self;
+ }
+
+ return {
+ onComplete: function( callback ){
+ updateCallbackArray.push(callback);
+ loadImageData(fileData, function(imageData, width, height){
+ parseImage(imageData.data, width, height);
+ });
+ },
+ compareTo: function(secondFileData){
+ return getCompareApi(secondFileData);
+ }
+ };
+
+ };
+}(this));
\ No newline at end of file
diff --git a/test/testsuite.js b/test/testsuite.js
deleted file mode 100644
index b486acb..0000000
--- a/test/testsuite.js
+++ /dev/null
@@ -1,36 +0,0 @@
-requirejs.config({
- baseUrl: '/test/unit/'
-});
-
-define(function(require) {
- var testModules = [
- 'Pixi',
- 'Point',
- 'Rectangle',
- 'DisplayObject',
- 'DisplayObjectContainer',
- 'Sprite',
- 'MovieClip',
- 'InteractionManager',
- 'Stage',
- 'utils/Utils',
- 'utils/EventTarget',
- 'utils/Matrix',
- 'utils/Detector',
- 'renderers/WebGLShaders',
- 'renderers/WebGLRenderer',
- 'renderers/WebGLBatch',
- 'renderers/CanvasRenderer',
- 'extras/Strip',
- 'extras/Rope',
- 'textures/BaseTexture',
- 'textures/Texture',
- 'loaders/SpriteSheetLoader',
- 'loaders/AssetLoader'
- ];
-
- // Resolve all testModules and then start the Test Runner.
- require(testModules, function() {
- QUnit.start();
- });
-});
\ No newline at end of file
diff --git a/test/textures/SpriteSheet-Aliens.png b/test/textures/SpriteSheet-Aliens.png
new file mode 100644
index 0000000..210acb1
--- /dev/null
+++ b/test/textures/SpriteSheet-Aliens.png
Binary files differ
diff --git a/test/textures/SpriteSheet-Explosion.png b/test/textures/SpriteSheet-Explosion.png
new file mode 100755
index 0000000..79e1a69
--- /dev/null
+++ b/test/textures/SpriteSheet-Explosion.png
Binary files differ
diff --git a/test/textures/bunny.png b/test/textures/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/textures/bunny.png
Binary files differ
diff --git a/test/unit/DisplayObject.js b/test/unit/DisplayObject.js
deleted file mode 100644
index 5e7e72f..0000000
--- a/test/unit/DisplayObject.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObject');
-});
diff --git a/test/unit/DisplayObjectContainer.js b/test/unit/DisplayObjectContainer.js
deleted file mode 100644
index b323959..0000000
--- a/test/unit/DisplayObjectContainer.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObjectContainer');
-});
diff --git a/test/unit/InteractionManager.js b/test/unit/InteractionManager.js
deleted file mode 100644
index e751f52..0000000
--- a/test/unit/InteractionManager.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('InteractionManager');
-});
diff --git a/test/unit/MovieClip.js b/test/unit/MovieClip.js
deleted file mode 100644
index 37d9446..0000000
--- a/test/unit/MovieClip.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('MovieClip');
-});
diff --git a/test/unit/Pixi.js b/test/unit/Pixi.js
deleted file mode 100644
index 36eee73..0000000
--- a/test/unit/Pixi.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Pixi');
-});
diff --git a/test/unit/Point.js b/test/unit/Point.js
deleted file mode 100644
index 983ff6e..0000000
--- a/test/unit/Point.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Point');
-});
diff --git a/test/unit/Rectangle.js b/test/unit/Rectangle.js
deleted file mode 100644
index 3b439ba..0000000
--- a/test/unit/Rectangle.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Rectangle');
-});
diff --git a/test/unit/Sprite.js b/test/unit/Sprite.js
deleted file mode 100644
index ed4f596..0000000
--- a/test/unit/Sprite.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Sprite');
-});
diff --git a/test/unit/Stage.js b/test/unit/Stage.js
deleted file mode 100644
index 2d70291..0000000
--- a/test/unit/Stage.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Stage');
-});
diff --git a/test/unit/extras/Rope.js b/test/unit/extras/Rope.js
deleted file mode 100644
index 5606f14..0000000
--- a/test/unit/extras/Rope.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Rope');
-});
diff --git a/test/unit/extras/Strip.js b/test/unit/extras/Strip.js
deleted file mode 100644
index 0134d3a..0000000
--- a/test/unit/extras/Strip.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Strip');
-});
diff --git a/test/unit/loaders/AssetLoader.js b/test/unit/loaders/AssetLoader.js
deleted file mode 100644
index 13b8443..0000000
--- a/test/unit/loaders/AssetLoader.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('AssetLoader');
-});
diff --git a/test/unit/loaders/SpriteSheetLoader.js b/test/unit/loaders/SpriteSheetLoader.js
deleted file mode 100644
index 8bf0cb2..0000000
--- a/test/unit/loaders/SpriteSheetLoader.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('SpriteSheetLoader');
-});
diff --git a/test/unit/pixi/InteractionManager.js b/test/unit/pixi/InteractionManager.js
new file mode 100644
index 0000000..ed3001f
--- /dev/null
+++ b/test/unit/pixi/InteractionManager.js
@@ -0,0 +1,10 @@
+describe('pixi/InteractionManager', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var InteractionManager = PIXI.InteractionManager;
+
+ it('Module exists', function () {
+ expect(InteractionManager).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/Pixi.js b/test/unit/pixi/Pixi.js
new file mode 100644
index 0000000..27debc1
--- /dev/null
+++ b/test/unit/pixi/Pixi.js
@@ -0,0 +1,9 @@
+describe('pixi/Pixi', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+
+ it('Module exists', function () {
+ expect(global).to.have.property('PIXI').and.to.be.an('object');
+ });
+});
diff --git a/test/unit/pixi/core/Circle.js b/test/unit/pixi/core/Circle.js
new file mode 100644
index 0000000..93a4456
--- /dev/null
+++ b/test/unit/pixi/core/Circle.js
@@ -0,0 +1,22 @@
+describe('pixi/core/Circle', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Circle = PIXI.Circle;
+
+ it('Module exists', function () {
+ expect(Circle).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Circle();
+
+ expect(obj).to.be.an.instanceof(Circle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', 0);
+ expect(obj).to.have.property('y', 0);
+ expect(obj).to.have.property('radius', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Ellipse.js b/test/unit/pixi/core/Ellipse.js
new file mode 100644
index 0000000..026b56f
--- /dev/null
+++ b/test/unit/pixi/core/Ellipse.js
@@ -0,0 +1,24 @@
+describe('pixi/core/Ellipse', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Ellipse = PIXI.Ellipse;
+
+ it('Module exists', function () {
+ expect(Ellipse).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Ellipse();
+
+ expect(obj).to.be.an.instanceof(Ellipse);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+ expect(obj).to.respondTo('getBounds');
+
+ expect(obj).to.have.property('x', 0);
+ expect(obj).to.have.property('y', 0);
+ expect(obj).to.have.property('width', 0);
+ expect(obj).to.have.property('height', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Matrix.js b/test/unit/pixi/core/Matrix.js
new file mode 100644
index 0000000..b48989e
--- /dev/null
+++ b/test/unit/pixi/core/Matrix.js
@@ -0,0 +1,30 @@
+describe('pixi/core/Matrix', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var mat3 = PIXI.mat3;
+ var mat4 = PIXI.mat4;
+ var Matrix = PIXI.Matrix;
+
+ it('Ensure determineMatrixArrayType works', function () {
+ expect(Matrix).to.be.a('function');
+ });
+
+ it('mat3 exists', function () {
+ expect(mat3).to.be.an('object');
+ });
+
+ it('Confirm new mat3 matrix', function () {
+ var matrix = new mat3.create();
+ pixi_core_Matrix_confirmNewMat3(matrix);
+ });
+
+ it('mat3 exists', function () {
+ expect(mat4).to.be.an('object');
+ });
+
+ it('Confirm new mat4 matrix', function () {
+ var matrix = new mat4.create();
+ pixi_core_Matrix_confirmNewMat4(matrix);
+ });
+});
diff --git a/.gitignore b/.gitignore
index 12e1b62..0b88317 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
node_modules
.DS_Store
-.project
\ No newline at end of file
+.project
+*.log
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..63e4d7c
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,8 @@
+language: node_js
+node_js:
+ - 0.10
+
+before_script:
+ - npm install -g grunt-cli
+ - export DISPLAY=:99.0
+ - sh -e /etc/init.d/xvfb start
diff --git a/Gruntfile.js b/Gruntfile.js
index b083b49..103938c 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -1,10 +1,12 @@
+'use strict';
+
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-connect');
- grunt.loadNpmTasks('grunt-contrib-qunit');
grunt.loadNpmTasks('grunt-contrib-yuidoc');
+ grunt.loadTasks('tasks');
var root = 'src/pixi/',
debug = 'bin/pixi.dev.js',
@@ -79,7 +81,7 @@
},
files: {
srcBlob: '<%= dirs.src %>/**/*.js',
- testBlob: '<%= dirs.test %>/unit/**/*.js',
+ testBlob: '<%= dirs.test %>/{functional,lib/pixi,unit}/**/*.js',
build: '<%= dirs.build %>/pixi.dev.js',
buildMin: '<%= dirs.build %>/pixi.js'
},
@@ -94,7 +96,12 @@
},
jshint: {
beforeconcat: srcFiles,
- test: ['<%= files.testBlob %>'],
+ test: {
+ src: ['<%= files.testBlob %>'],
+ options: {
+ expr: true
+ }
+ },
options: {
asi: true,
smarttabs: true
@@ -128,12 +135,6 @@
]
},
connect: {
- qunit: {
- options: {
- port: grunt.option('port-test') || 9002,
- base: './'
- }
- },
test: {
options: {
port: grunt.option('port-test') || 9002,
@@ -142,13 +143,6 @@
}
}
},
- qunit: {
- all: {
- options: {
- urls: ['http://localhost:' + (grunt.option('port-test') || 9002) + '/test/index.html']
- }
- }
- },
yuidoc: {
compile: {
name: '<%= pkg.name %>',
@@ -161,6 +155,13 @@
outdir: '<%= dirs.docs %>'
}
}
+ },
+ karma: {
+ unit: {
+ configFile: 'test/karma.conf.js',
+ // browsers: ['Chrome'],
+ singleRun: true
+ }
}
});
@@ -182,9 +183,10 @@
}
)
- grunt.registerTask('default', ['concat', 'uglify', 'distribute']);
grunt.registerTask('build', ['concat', 'uglify', 'distribute']);
- grunt.registerTask('test', ['build', 'connect:qunit', 'qunit']);
+ grunt.registerTask('test', ['concat', 'jshint:test', 'karma']);
grunt.registerTask('docs', ['yuidoc']);
-
-}
\ No newline at end of file
+ grunt.registerTask('default', ['test', 'uglify', 'distribute']);
+ // Travis CI task.
+ grunt.registerTask('travis', ['test']);
+}
diff --git a/README.md b/README.md
index c62ef86..690cfe4 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,8 @@

+[](http://travis-ci.org/drkibitz/pixi.js)
+
#### JavaScript 2D Renderer ####
The aim of this project is to provide a fast lightweight 2D library that works
diff --git a/package.json b/package.json
index b373240..1246a68 100644
--- a/package.json
+++ b/package.json
@@ -18,14 +18,21 @@
"main": "bin/pixi.js",
+ "scripts": {
+ "test": "grunt travis --verbose"
+ },
+
"dependencies": {},
"devDependencies": {
"grunt": "~0.4.x",
- "grunt-contrib-jshint": "0.3.x",
+ "grunt-contrib-jshint": "0.6.x",
"grunt-contrib-uglify": "0.2.x",
- "grunt-contrib-connect": "0.2.x",
- "grunt-contrib-qunit": "0.2.x",
+ "grunt-contrib-connect": "0.3.x",
"grunt-contrib-yuidoc": "0.4.x",
- "grunt-contrib-concat": "0.1.x"
+ "grunt-contrib-concat": "0.3.x",
+ "chai": "~1.7.0",
+ "karma": "0.11.0",
+ "karma-firefox-launcher": "0.1.0",
+ "karma-mocha": "0.1.0"
}
}
diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js
index a7c520e..ee82bbd 100644
--- a/src/pixi/InteractionManager.js
+++ b/src/pixi/InteractionManager.js
@@ -62,7 +62,6 @@
this.onTouchEnd = this.onTouchEnd.bind(this);
this.onTouchMove = this.onTouchMove.bind(this);
-
this.last = 0;
}
diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js
index 1a95d20..eef1059 100644
--- a/src/pixi/core/Ellipse.js
+++ b/src/pixi/core/Ellipse.js
@@ -78,7 +78,7 @@
return (normx + normy < 0.25);
}
-PIXI.Ellipse.getBounds = function()
+PIXI.Ellipse.prototype.getBounds = function()
{
return new PIXI.Rectangle(this.x, this.y, this.width, this.height);
}
diff --git a/tasks/karma.js b/tasks/karma.js
new file mode 100644
index 0000000..c340485
--- /dev/null
+++ b/tasks/karma.js
@@ -0,0 +1,27 @@
+'use strict';
+
+var path = require('path');
+var server = require('karma').server;
+
+module.exports = function (grunt) {
+ grunt.registerMultiTask('karma', 'run karma.', function() {
+ var done = this.async();
+ var options = this.options({
+ background: false
+ });
+ var data = this.data;
+
+ //merge options onto data, with data taking precedence
+ data = grunt.util._.merge(options, data);
+ data.configFile = path.resolve(data.configFile);
+ if (data.configFile) {
+ data.configFile = grunt.template.process(data.configFile);
+ }
+
+ server.start(
+ data,
+ function(code) {
+ done(!code);
+ });
+ });
+};
diff --git a/test/functional/example-1-basics/bunny.png b/test/functional/example-1-basics/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/functional/example-1-basics/bunny.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-30.png b/test/functional/example-1-basics/frame-30.png
new file mode 100644
index 0000000..96e3409
--- /dev/null
+++ b/test/functional/example-1-basics/frame-30.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-60.png b/test/functional/example-1-basics/frame-60.png
new file mode 100644
index 0000000..af3f4ce
--- /dev/null
+++ b/test/functional/example-1-basics/frame-60.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-90.png b/test/functional/example-1-basics/frame-90.png
new file mode 100644
index 0000000..099b823
--- /dev/null
+++ b/test/functional/example-1-basics/frame-90.png
Binary files differ
diff --git a/test/functional/example-1-basics/index.js b/test/functional/example-1-basics/index.js
new file mode 100644
index 0000000..7ae7a98
--- /dev/null
+++ b/test/functional/example-1-basics/index.js
@@ -0,0 +1,133 @@
+describe('Example 1 - Basics', function () {
+ 'use strict';
+
+ var baseUri = '/base/test/functional/example-1-basics';
+ var expect = chai.expect;
+ var currentFrame = 0;
+ var frameEvents = {};
+ var stage;
+ var renderer;
+ var bunny;
+
+ function onFrame(frame, callback) {
+ frameEvents[frame] = callback;
+ }
+
+ function animate() {
+ currentFrame += 1;
+
+ requestAnimFrame( animate );
+
+ // just for fun, lets rotate mr rabbit a little
+ bunny.rotation += 0.1;
+
+ // render the stage
+ renderer.render(stage);
+
+ if (frameEvents[currentFrame])
+ frameEvents[currentFrame](currentFrame);
+ }
+
+ function initScene() {
+ // create an new instance of a pixi stage
+ stage = new PIXI.Stage(0x66FF99);
+
+ // create a renderer instance
+ renderer = PIXI.autoDetectRenderer(400, 300);
+ console.log('Is PIXI.WebGLRenderer: ' + (renderer instanceof PIXI.WebGLRenderer));
+
+ // add the renderer view element to the DOM
+ document.body.appendChild(renderer.view);
+
+ requestAnimFrame( animate );
+
+ // create a texture from an image path
+ var texture = PIXI.Texture.fromImage(baseUri + "/bunny.png");
+ // create a new Sprite using the texture
+ bunny = new PIXI.Sprite(texture);
+
+ // center the sprites anchor point
+ bunny.anchor.x = 0.5;
+ bunny.anchor.y = 0.5;
+
+ // move the sprite t the center of the screen
+ bunny.position.x = 200;
+ bunny.position.y = 150;
+
+ stage.addChild(bunny);
+ }
+
+ it('assets loaded', function (done) {
+ var loader = new PIXI.AssetLoader([
+ baseUri + '/bunny.png',
+ baseUri + '/frame-30.png',
+ baseUri + '/frame-60.png',
+ baseUri + '/frame-90.png'
+ ]);
+ // loader.on('onProgress', function (event) {
+ // console.log(event.content);
+ // });
+ loader.on('onComplete', function (event) {
+ done();
+ initScene();
+ });
+ loader.load();
+ });
+
+ it('frame 30 should match', function (done) {
+ this.timeout(700);
+ onFrame(30, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-30.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 60 should match', function (done) {
+ this.timeout(1200);
+ onFrame(60, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-60.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 90 should match', function (done) {
+ this.timeout(1700);
+ onFrame(90, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-90.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ // it('capture something', function (done) {
+ // this.timeout(2000000);
+ // onFrame(30, function () {
+ // var img = new Image();
+ // img.src = renderer.view.toDataURL('image/png');
+ // document.body.appendChild(img);
+ // });
+ // });
+});
diff --git a/test/index.html b/test/index.html
deleted file mode 100644
index 9cbcac5..0000000
--- a/test/index.html
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
- Pixi.js Test Suite
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/test/karma.conf.js b/test/karma.conf.js
new file mode 100644
index 0000000..c66a696
--- /dev/null
+++ b/test/karma.conf.js
@@ -0,0 +1,82 @@
+module.exports = function(config) {
+ config.set({
+
+ // base path, that will be used to resolve files and exclude
+ basePath : '../',
+
+ frameworks : ['mocha'],
+
+ // list of files / patterns to load in the browser
+ files : [
+ 'node_modules/chai/chai.js',
+ 'bin/pixi.dev.js',
+ 'test/lib/**/*.js',
+ 'test/unit/**/*.js',
+ // 'test/functional/**/*.js',
+ {pattern: 'test/**/*.png', watched: false, included: false, served: true}
+ ],
+
+ // list of files to exclude
+ exclude : [],
+
+ // use dolts reporter, as travis terminal does not support escaping sequences
+ // possible values: 'dots', 'progress', 'junit', 'teamcity'
+ // CLI --reporters progress
+ reporters : ['progress'],
+
+ // web server port
+ // CLI --port 9876
+ port : 9876,
+
+ // cli runner port
+ // CLI --runner-port 9100
+ runnerPort : 9100,
+
+ // enable / disable colors in the output (reporters and logs)
+ // CLI --colors --no-colors
+ colors : true,
+
+ // level of logging
+ // possible values: karma.LOG_DISABLE || karma.LOG_ERROR || karma.LOG_WARN || karma.LOG_INFO || karma.LOG_DEBUG
+ // CLI --log-level debug
+ logLevel : config.LOG_DEBUG,
+
+ // enable / disable watching file and executing tests whenever any file changes
+ // CLI --auto-watch --no-auto-watch
+ autoWatch : false,
+
+ // Start these browsers, currently available:
+ // - Chrome
+ // - ChromeCanary
+ // - Firefox
+ // - Opera
+ // - Safari (only Mac)
+ // - PhantomJS
+ // - IE (only Windows)
+ // CLI --browsers Chrome,Firefox,Safari
+ browsers : ['Firefox'],
+
+ // If browser does not capture in given timeout [ms], kill it
+ // CLI --capture-timeout 5000
+ captureTimeout : 5000,
+
+ // Auto run tests on start (when browsers are captured) and exit
+ // CLI --single-run --no-single-run
+ singleRun : true,
+
+ // report which specs are slower than 500ms
+ // CLI --report-slower-than 500
+ reportSlowerThan : 1000,
+
+ preprocessors : {
+ // '**/client/js/*.js': 'coverage'
+ },
+
+ plugins : [
+ 'karma-mocha',
+ // 'karma-chrome-launcher',
+ 'karma-firefox-launcher',
+ // 'karma-phantomjs-launcher'
+ ]
+ });
+};
diff --git a/test/lib/pixi/core/Matrix.js b/test/lib/pixi/core/Matrix.js
new file mode 100644
index 0000000..d26386b
--- /dev/null
+++ b/test/lib/pixi/core/Matrix.js
@@ -0,0 +1,40 @@
+
+function pixi_core_Matrix_confirmNewMat3(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(1);
+ expect(matrix[5]).to.equal(0);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(1);
+}
+
+function pixi_core_Matrix_confirmNewMat4(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[0]).to.equal(1);
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(0);
+ expect(matrix[5]).to.equal(1);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(0);
+ expect(matrix[9]).to.equal(0);
+ expect(matrix[10]).to.equal(1);
+ expect(matrix[11]).to.equal(0);
+ expect(matrix[12]).to.equal(0);
+ expect(matrix[13]).to.equal(0);
+ expect(matrix[14]).to.equal(0);
+ expect(matrix[15]).to.equal(1);
+}
diff --git a/test/lib/pixi/core/Point.js b/test/lib/pixi/core/Point.js
new file mode 100644
index 0000000..e5df07b
--- /dev/null
+++ b/test/lib/pixi/core/Point.js
@@ -0,0 +1,10 @@
+
+function pixi_core_Point_confirm(obj, x, y) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Point);
+ expect(obj).to.respondTo('clone');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+}
diff --git a/test/lib/pixi/core/Rectangle.js b/test/lib/pixi/core/Rectangle.js
new file mode 100644
index 0000000..23f0d12
--- /dev/null
+++ b/test/lib/pixi/core/Rectangle.js
@@ -0,0 +1,13 @@
+
+function pixi_core_Rectangle_confirm(obj, x, y, width, height) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Rectangle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+ expect(obj).to.have.property('width', width);
+ expect(obj).to.have.property('height', height);
+}
diff --git a/test/lib/pixi/display/DisplayObject.js b/test/lib/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..1388a7f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObject.js
@@ -0,0 +1,43 @@
+
+function pixi_display_DisplayObject_confirmNew(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObject);
+ expect(obj).to.respondTo('setInteractive');
+ expect(obj).to.respondTo('addFilter');
+ expect(obj).to.respondTo('removeFilter');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.property('last', obj);
+ expect(obj).to.have.property('first', obj);
+
+ expect(obj).to.contain.property('position');
+ pixi_core_Point_confirm(obj.position, 0, 0);
+ expect(obj).to.contain.property('scale');
+ pixi_core_Point_confirm(obj.scale, 1, 1);
+ expect(obj).to.contain.property('pivot');
+ pixi_core_Point_confirm(obj.pivot, 0, 0);
+
+ expect(obj).to.have.property('rotation', 0);
+ expect(obj).to.have.property('alpha', 1);
+ expect(obj).to.have.property('visible', true);
+ expect(obj).to.have.property('buttonMode', false);
+ expect(obj).to.have.property('parent', null);
+ expect(obj).to.have.property('worldAlpha', 1);
+
+ expect(obj).to.have.property('hitArea');
+ expect(obj).to.have.property('interactive'); // TODO: Have a better default value
+ expect('mask' in obj).to.be.true; // TODO: Have a better default value
+ expect(obj.mask).to.be.undefined;
+
+ expect(obj).to.have.property('renderable');
+ expect(obj).to.have.property('stage');
+
+ expect(obj).to.have.deep.property('worldTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ expect(obj).to.have.deep.property('localTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.localTransform);
+
+ expect(obj).to.have.deep.property('color.length', 0);
+ expect(obj).to.have.property('dynamic', true);
+}
diff --git a/test/lib/pixi/display/DisplayObjectContainer.js b/test/lib/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..085c59f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,16 @@
+
+function pixi_display_DisplayObjectContainer_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObject_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObjectContainer);
+ expect(obj).to.respondTo('addChild');
+ expect(obj).to.respondTo('addChildAt');
+ expect(obj).to.respondTo('swapChildren');
+ expect(obj).to.respondTo('getChildAt');
+ expect(obj).to.respondTo('removeChild');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('children.length', 0);
+}
diff --git a/test/lib/pixi/display/Sprite.js b/test/lib/pixi/display/Sprite.js
new file mode 100644
index 0000000..cc7a2d6
--- /dev/null
+++ b/test/lib/pixi/display/Sprite.js
@@ -0,0 +1,28 @@
+
+function pixi_display_Sprite_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Sprite);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', true);
+ expect(obj).to.have.property('stage', null);
+
+ expect(obj).to.have.property('anchor');
+ pixi_core_Point_confirm(obj.anchor, 0, 0);
+
+ expect(obj).to.have.property('blendMode', PIXI.blendModes.NORMAL);
+ expect(obj).to.have.property('width', 1); // TODO: is 1 expected
+ expect(obj).to.have.property('height', 1); // TODO: is 1 expected
+
+ // FIXME: Just make this a boolean that is always there
+ expect(!!obj.updateFrame).to.equal(obj.texture.baseTexture.hasLoaded);
+
+ expect(obj).to.have.property('texture');
+ pixi_textures_Texture_confirmNew(obj.texture, done);
+}
diff --git a/test/lib/pixi/extras/Strip.js b/test/lib/pixi/extras/Strip.js
new file mode 100644
index 0000000..8927a8a
--- /dev/null
+++ b/test/lib/pixi/extras/Strip.js
@@ -0,0 +1,12 @@
+
+function pixi_extras_Strip_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Strip);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ // TODO: Test properties
+}
diff --git a/test/lib/pixi/textures/Texture.js b/test/lib/pixi/textures/Texture.js
new file mode 100644
index 0000000..d5867b6
--- /dev/null
+++ b/test/lib/pixi/textures/Texture.js
@@ -0,0 +1,31 @@
+
+function pixi_textures_Texture_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ function confirmFrameDone() {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, obj.baseTexture.width, obj.baseTexture.height);
+
+ expect(obj).to.have.property('width', obj.baseTexture.width);
+ expect(obj).to.have.property('height', obj.baseTexture.height);
+ done();
+ }
+
+ expect(obj).to.be.an.instanceof(PIXI.Texture);
+ pixi_utils_EventTarget_like(obj);
+
+ expect(obj).to.have.property('baseTexture')
+ .and.to.be.an.instanceof(PIXI.BaseTexture);
+
+ expect(obj).to.have.property('scope', obj);
+
+ expect(obj).to.have.property('trim');
+ pixi_core_Point_confirm(obj.trim, 0, 0);
+
+ expect(obj).to.have.property('frame');
+ if (obj.baseTexture.hasLoaded) {
+ confirmFrameDone();
+ } else {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, 1, 1);
+ obj.addEventListener('update', confirmFrameDone);
+ }
+}
diff --git a/test/lib/pixi/utils/EventTarget.js b/test/lib/pixi/utils/EventTarget.js
new file mode 100644
index 0000000..7b1dcfa
--- /dev/null
+++ b/test/lib/pixi/utils/EventTarget.js
@@ -0,0 +1,8 @@
+
+function pixi_utils_EventTarget_like(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.respondTo('addEventListener');
+ expect(obj).to.respondTo('dispatchEvent');
+ expect(obj).to.respondTo('removeEventListener');
+}
diff --git a/test/lib/qunit-1.11.0.css b/test/lib/qunit-1.11.0.css
deleted file mode 100644
index d7fc0c8..0000000
--- a/test/lib/qunit-1.11.0.css
+++ /dev/null
@@ -1,244 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-/** Font Family and Sizes */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
- font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
-}
-
-#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
-#qunit-tests { font-size: smaller; }
-
-
-/** Resets */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter {
- margin: 0;
- padding: 0;
-}
-
-
-/** Header */
-
-#qunit-header {
- padding: 0.5em 0 0.5em 1em;
-
- color: #8699a4;
- background-color: #0d3349;
-
- font-size: 1.5em;
- line-height: 1em;
- font-weight: normal;
-
- border-radius: 5px 5px 0 0;
- -moz-border-radius: 5px 5px 0 0;
- -webkit-border-top-right-radius: 5px;
- -webkit-border-top-left-radius: 5px;
-}
-
-#qunit-header a {
- text-decoration: none;
- color: #c2ccd1;
-}
-
-#qunit-header a:hover,
-#qunit-header a:focus {
- color: #fff;
-}
-
-#qunit-testrunner-toolbar label {
- display: inline-block;
- padding: 0 .5em 0 .1em;
-}
-
-#qunit-banner {
- height: 5px;
-}
-
-#qunit-testrunner-toolbar {
- padding: 0.5em 0 0.5em 2em;
- color: #5E740B;
- background-color: #eee;
- overflow: hidden;
-}
-
-#qunit-userAgent {
- padding: 0.5em 0 0.5em 2.5em;
- background-color: #2b81af;
- color: #fff;
- text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
-}
-
-#qunit-modulefilter-container {
- float: right;
-}
-
-/** Tests: Pass/Fail */
-
-#qunit-tests {
- list-style-position: inside;
-}
-
-#qunit-tests li {
- padding: 0.4em 0.5em 0.4em 2.5em;
- border-bottom: 1px solid #fff;
- list-style-position: inside;
-}
-
-#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running {
- display: none;
-}
-
-#qunit-tests li strong {
- cursor: pointer;
-}
-
-#qunit-tests li a {
- padding: 0.5em;
- color: #c2ccd1;
- text-decoration: none;
-}
-#qunit-tests li a:hover,
-#qunit-tests li a:focus {
- color: #000;
-}
-
-#qunit-tests li .runtime {
- float: right;
- font-size: smaller;
-}
-
-.qunit-assert-list {
- margin-top: 0.5em;
- padding: 0.5em;
-
- background-color: #fff;
-
- border-radius: 5px;
- -moz-border-radius: 5px;
- -webkit-border-radius: 5px;
-}
-
-.qunit-collapsed {
- display: none;
-}
-
-#qunit-tests table {
- border-collapse: collapse;
- margin-top: .2em;
-}
-
-#qunit-tests th {
- text-align: right;
- vertical-align: top;
- padding: 0 .5em 0 0;
-}
-
-#qunit-tests td {
- vertical-align: top;
-}
-
-#qunit-tests pre {
- margin: 0;
- white-space: pre-wrap;
- word-wrap: break-word;
-}
-
-#qunit-tests del {
- background-color: #e0f2be;
- color: #374e0c;
- text-decoration: none;
-}
-
-#qunit-tests ins {
- background-color: #ffcaca;
- color: #500;
- text-decoration: none;
-}
-
-/*** Test Counts */
-
-#qunit-tests b.counts { color: black; }
-#qunit-tests b.passed { color: #5E740B; }
-#qunit-tests b.failed { color: #710909; }
-
-#qunit-tests li li {
- padding: 5px;
- background-color: #fff;
- border-bottom: none;
- list-style-position: inside;
-}
-
-/*** Passing Styles */
-
-#qunit-tests li li.pass {
- color: #3c510c;
- background-color: #fff;
- border-left: 10px solid #C6E746;
-}
-
-#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
-#qunit-tests .pass .test-name { color: #366097; }
-
-#qunit-tests .pass .test-actual,
-#qunit-tests .pass .test-expected { color: #999999; }
-
-#qunit-banner.qunit-pass { background-color: #C6E746; }
-
-/*** Failing Styles */
-
-#qunit-tests li li.fail {
- color: #710909;
- background-color: #fff;
- border-left: 10px solid #EE5757;
- white-space: pre;
-}
-
-#qunit-tests > li:last-child {
- border-radius: 0 0 5px 5px;
- -moz-border-radius: 0 0 5px 5px;
- -webkit-border-bottom-right-radius: 5px;
- -webkit-border-bottom-left-radius: 5px;
-}
-
-#qunit-tests .fail { color: #000000; background-color: #EE5757; }
-#qunit-tests .fail .test-name,
-#qunit-tests .fail .module-name { color: #000000; }
-
-#qunit-tests .fail .test-actual { color: #EE5757; }
-#qunit-tests .fail .test-expected { color: green; }
-
-#qunit-banner.qunit-fail { background-color: #EE5757; }
-
-
-/** Result */
-
-#qunit-testresult {
- padding: 0.5em 0.5em 0.5em 2.5em;
-
- color: #2b81af;
- background-color: #D2E0E6;
-
- border-bottom: 1px solid white;
-}
-#qunit-testresult .module-name {
- font-weight: bold;
-}
-
-/** Fixture */
-
-#qunit-fixture {
- position: absolute;
- top: -10000px;
- left: -10000px;
- width: 1000px;
- height: 1000px;
-}
diff --git a/test/lib/qunit-1.11.0.js b/test/lib/qunit-1.11.0.js
deleted file mode 100644
index 302545f..0000000
--- a/test/lib/qunit-1.11.0.js
+++ /dev/null
@@ -1,2152 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-(function( window ) {
-
-var QUnit,
- assert,
- config,
- onErrorFnPrev,
- testId = 0,
- fileName = (sourceFromStacktrace( 0 ) || "" ).replace(/(:\d+)+\)?/, "").replace(/.+\//, ""),
- toString = Object.prototype.toString,
- hasOwn = Object.prototype.hasOwnProperty,
- // Keep a local reference to Date (GH-283)
- Date = window.Date,
- defined = {
- setTimeout: typeof window.setTimeout !== "undefined",
- sessionStorage: (function() {
- var x = "qunit-test-string";
- try {
- sessionStorage.setItem( x, x );
- sessionStorage.removeItem( x );
- return true;
- } catch( e ) {
- return false;
- }
- }())
- },
- /**
- * Provides a normalized error string, correcting an issue
- * with IE 7 (and prior) where Error.prototype.toString is
- * not properly implemented
- *
- * Based on http://es5.github.com/#x15.11.4.4
- *
- * @param {String|Error} error
- * @return {String} error message
- */
- errorString = function( error ) {
- var name, message,
- errorString = error.toString();
- if ( errorString.substring( 0, 7 ) === "[object" ) {
- name = error.name ? error.name.toString() : "Error";
- message = error.message ? error.message.toString() : "";
- if ( name && message ) {
- return name + ": " + message;
- } else if ( name ) {
- return name;
- } else if ( message ) {
- return message;
- } else {
- return "Error";
- }
- } else {
- return errorString;
- }
- },
- /**
- * Makes a clone of an object using only Array or Object as base,
- * and copies over the own enumerable properties.
- *
- * @param {Object} obj
- * @return {Object} New object with only the own properties (recursively).
- */
- objectValues = function( obj ) {
- // Grunt 0.3.x uses an older version of jshint that still has jshint/jshint#392.
- /*jshint newcap: false */
- var key, val,
- vals = QUnit.is( "array", obj ) ? [] : {};
- for ( key in obj ) {
- if ( hasOwn.call( obj, key ) ) {
- val = obj[key];
- vals[key] = val === Object(val) ? objectValues(val) : val;
- }
- }
- return vals;
- };
-
-function Test( settings ) {
- extend( this, settings );
- this.assertions = [];
- this.testNumber = ++Test.count;
-}
-
-Test.count = 0;
-
-Test.prototype = {
- init: function() {
- var a, b, li,
- tests = id( "qunit-tests" );
-
- if ( tests ) {
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml;
-
- // `a` initialized at top of scope
- a = document.createElement( "a" );
- a.innerHTML = "Rerun";
- a.href = QUnit.url({ testNumber: this.testNumber });
-
- li = document.createElement( "li" );
- li.appendChild( b );
- li.appendChild( a );
- li.className = "running";
- li.id = this.id = "qunit-test-output" + testId++;
-
- tests.appendChild( li );
- }
- },
- setup: function() {
- if ( this.module !== config.previousModule ) {
- if ( config.previousModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.previousModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
- config.previousModule = this.module;
- config.moduleStats = { all: 0, bad: 0 };
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- } else if ( config.autorun ) {
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- }
-
- config.current = this;
-
- this.testEnvironment = extend({
- setup: function() {},
- teardown: function() {}
- }, this.moduleTestEnvironment );
-
- this.started = +new Date();
- runLoggingCallbacks( "testStart", QUnit, {
- name: this.testName,
- module: this.module
- });
-
- // allow utility functions to access the current test environment
- // TODO why??
- QUnit.current_testEnvironment = this.testEnvironment;
-
- if ( !config.pollution ) {
- saveGlobal();
- }
- if ( config.notrycatch ) {
- this.testEnvironment.setup.call( this.testEnvironment );
- return;
- }
- try {
- this.testEnvironment.setup.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Setup failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- },
- run: function() {
- config.current = this;
-
- var running = id( "qunit-testresult" );
-
- if ( running ) {
- running.innerHTML = "Running:
" + this.nameHtml;
- }
-
- if ( this.async ) {
- QUnit.stop();
- }
-
- this.callbackStarted = +new Date();
-
- if ( config.notrycatch ) {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- return;
- }
-
- try {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- } catch( e ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
-
- QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + " " + this.stack + ": " + ( e.message || e ), extractStacktrace( e, 0 ) );
- // else next test will carry the responsibility
- saveGlobal();
-
- // Restart the tests if they're blocking
- if ( config.blocking ) {
- QUnit.start();
- }
- }
- },
- teardown: function() {
- config.current = this;
- if ( config.notrycatch ) {
- if ( typeof this.callbackRuntime === "undefined" ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
- }
- this.testEnvironment.teardown.call( this.testEnvironment );
- return;
- } else {
- try {
- this.testEnvironment.teardown.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Teardown failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- }
- checkPollution();
- },
- finish: function() {
- config.current = this;
- if ( config.requireExpects && this.expected === null ) {
- QUnit.pushFailure( "Expected number of assertions to be defined, but expect() was not called.", this.stack );
- } else if ( this.expected !== null && this.expected !== this.assertions.length ) {
- QUnit.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack );
- } else if ( this.expected === null && !this.assertions.length ) {
- QUnit.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions.", this.stack );
- }
-
- var i, assertion, a, b, time, li, ol,
- test = this,
- good = 0,
- bad = 0,
- tests = id( "qunit-tests" );
-
- this.runtime = +new Date() - this.started;
- config.stats.all += this.assertions.length;
- config.moduleStats.all += this.assertions.length;
-
- if ( tests ) {
- ol = document.createElement( "ol" );
- ol.className = "qunit-assert-list";
-
- for ( i = 0; i < this.assertions.length; i++ ) {
- assertion = this.assertions[i];
-
- li = document.createElement( "li" );
- li.className = assertion.result ? "pass" : "fail";
- li.innerHTML = assertion.message || ( assertion.result ? "okay" : "failed" );
- ol.appendChild( li );
-
- if ( assertion.result ) {
- good++;
- } else {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
-
- // store result when possible
- if ( QUnit.config.reorder && defined.sessionStorage ) {
- if ( bad ) {
- sessionStorage.setItem( "qunit-test-" + this.module + "-" + this.testName, bad );
- } else {
- sessionStorage.removeItem( "qunit-test-" + this.module + "-" + this.testName );
- }
- }
-
- if ( bad === 0 ) {
- addClass( ol, "qunit-collapsed" );
- }
-
- // `b` initialized at top of scope
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml + " (" + bad + ", " + good + ", " + this.assertions.length + ")";
-
- addEvent(b, "click", function() {
- var next = b.parentNode.lastChild,
- collapsed = hasClass( next, "qunit-collapsed" );
- ( collapsed ? removeClass : addClass )( next, "qunit-collapsed" );
- });
-
- addEvent(b, "dblclick", function( e ) {
- var target = e && e.target ? e.target : window.event.srcElement;
- if ( target.nodeName.toLowerCase() === "span" || target.nodeName.toLowerCase() === "b" ) {
- target = target.parentNode;
- }
- if ( window.location && target.nodeName.toLowerCase() === "strong" ) {
- window.location = QUnit.url({ testNumber: test.testNumber });
- }
- });
-
- // `time` initialized at top of scope
- time = document.createElement( "span" );
- time.className = "runtime";
- time.innerHTML = this.runtime + " ms";
-
- // `li` initialized at top of scope
- li = id( this.id );
- li.className = bad ? "fail" : "pass";
- li.removeChild( li.firstChild );
- a = li.firstChild;
- li.appendChild( b );
- li.appendChild( a );
- li.appendChild( time );
- li.appendChild( ol );
-
- } else {
- for ( i = 0; i < this.assertions.length; i++ ) {
- if ( !this.assertions[i].result ) {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
- }
-
- runLoggingCallbacks( "testDone", QUnit, {
- name: this.testName,
- module: this.module,
- failed: bad,
- passed: this.assertions.length - bad,
- total: this.assertions.length,
- duration: this.runtime
- });
-
- QUnit.reset();
-
- config.current = undefined;
- },
-
- queue: function() {
- var bad,
- test = this;
-
- synchronize(function() {
- test.init();
- });
- function run() {
- // each of these can by async
- synchronize(function() {
- test.setup();
- });
- synchronize(function() {
- test.run();
- });
- synchronize(function() {
- test.teardown();
- });
- synchronize(function() {
- test.finish();
- });
- }
-
- // `bad` initialized at top of scope
- // defer when previous test run passed, if storage is available
- bad = QUnit.config.reorder && defined.sessionStorage &&
- +sessionStorage.getItem( "qunit-test-" + this.module + "-" + this.testName );
-
- if ( bad ) {
- run();
- } else {
- synchronize( run, true );
- }
- }
-};
-
-// Root QUnit object.
-// `QUnit` initialized at top of scope
-QUnit = {
-
- // call on start of module test to prepend name to all tests
- module: function( name, testEnvironment ) {
- config.currentModule = name;
- config.currentModuleTestEnvironment = testEnvironment;
- config.modules[name] = true;
- },
-
- asyncTest: function( testName, expected, callback ) {
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- QUnit.test( testName, expected, callback, true );
- },
-
- test: function( testName, expected, callback, async ) {
- var test,
- nameHtml = "" + escapeText( testName ) + "";
-
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- if ( config.currentModule ) {
- nameHtml = "" + escapeText( config.currentModule ) + ": " + nameHtml;
- }
-
- test = new Test({
- nameHtml: nameHtml,
- testName: testName,
- expected: expected,
- async: async,
- callback: callback,
- module: config.currentModule,
- moduleTestEnvironment: config.currentModuleTestEnvironment,
- stack: sourceFromStacktrace( 2 )
- });
-
- if ( !validTest( test ) ) {
- return;
- }
-
- test.queue();
- },
-
- // Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through.
- expect: function( asserts ) {
- if (arguments.length === 1) {
- config.current.expected = asserts;
- } else {
- return config.current.expected;
- }
- },
-
- start: function( count ) {
- // QUnit hasn't been initialized yet.
- // Note: RequireJS (et al) may delay onLoad
- if ( config.semaphore === undefined ) {
- QUnit.begin(function() {
- // This is triggered at the top of QUnit.load, push start() to the event loop, to allow QUnit.load to finish first
- setTimeout(function() {
- QUnit.start( count );
- });
- });
- return;
- }
-
- config.semaphore -= count || 1;
- // don't start until equal number of stop-calls
- if ( config.semaphore > 0 ) {
- return;
- }
- // ignore if start is called more often then stop
- if ( config.semaphore < 0 ) {
- config.semaphore = 0;
- QUnit.pushFailure( "Called start() while already started (QUnit.config.semaphore was 0 already)", null, sourceFromStacktrace(2) );
- return;
- }
- // A slight delay, to avoid any current callbacks
- if ( defined.setTimeout ) {
- window.setTimeout(function() {
- if ( config.semaphore > 0 ) {
- return;
- }
- if ( config.timeout ) {
- clearTimeout( config.timeout );
- }
-
- config.blocking = false;
- process( true );
- }, 13);
- } else {
- config.blocking = false;
- process( true );
- }
- },
-
- stop: function( count ) {
- config.semaphore += count || 1;
- config.blocking = true;
-
- if ( config.testTimeout && defined.setTimeout ) {
- clearTimeout( config.timeout );
- config.timeout = window.setTimeout(function() {
- QUnit.ok( false, "Test timed out" );
- config.semaphore = 1;
- QUnit.start();
- }, config.testTimeout );
- }
- }
-};
-
-// `assert` initialized at top of scope
-// Asssert helpers
-// All of these must either call QUnit.push() or manually do:
-// - runLoggingCallbacks( "log", .. );
-// - config.current.assertions.push({ .. });
-// We attach it to the QUnit object *after* we expose the public API,
-// otherwise `assert` will become a global variable in browsers (#341).
-assert = {
- /**
- * Asserts rough true-ish result.
- * @name ok
- * @function
- * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" );
- */
- ok: function( result, msg ) {
- if ( !config.current ) {
- throw new Error( "ok() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
- result = !!result;
-
- var source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: msg
- };
-
- msg = escapeText( msg || (result ? "okay" : "failed" ) );
- msg = "" + msg + "";
-
- if ( !result ) {
- source = sourceFromStacktrace( 2 );
- if ( source ) {
- details.source = source;
- msg += "Source: | " + escapeText( source ) + " |
---|
";
- }
- }
- runLoggingCallbacks( "log", QUnit, details );
- config.current.assertions.push({
- result: result,
- message: msg
- });
- },
-
- /**
- * Assert that the first two arguments are equal, with an optional message.
- * Prints out both actual and expected values.
- * @name equal
- * @function
- * @example equal( format( "Received {0} bytes.", 2), "Received 2 bytes.", "format() replaces {0} with next argument" );
- */
- equal: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected == actual, actual, expected, message );
- },
-
- /**
- * @name notEqual
- * @function
- */
- notEqual: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected != actual, actual, expected, message );
- },
-
- /**
- * @name propEqual
- * @function
- */
- propEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notPropEqual
- * @function
- */
- notPropEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name deepEqual
- * @function
- */
- deepEqual: function( actual, expected, message ) {
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notDeepEqual
- * @function
- */
- notDeepEqual: function( actual, expected, message ) {
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name strictEqual
- * @function
- */
- strictEqual: function( actual, expected, message ) {
- QUnit.push( expected === actual, actual, expected, message );
- },
-
- /**
- * @name notStrictEqual
- * @function
- */
- notStrictEqual: function( actual, expected, message ) {
- QUnit.push( expected !== actual, actual, expected, message );
- },
-
- "throws": function( block, expected, message ) {
- var actual,
- expectedOutput = expected,
- ok = false;
-
- // 'expected' is optional
- if ( typeof expected === "string" ) {
- message = expected;
- expected = null;
- }
-
- config.current.ignoreGlobalErrors = true;
- try {
- block.call( config.current.testEnvironment );
- } catch (e) {
- actual = e;
- }
- config.current.ignoreGlobalErrors = false;
-
- if ( actual ) {
- // we don't want to validate thrown error
- if ( !expected ) {
- ok = true;
- expectedOutput = null;
- // expected is a regexp
- } else if ( QUnit.objectType( expected ) === "regexp" ) {
- ok = expected.test( errorString( actual ) );
- // expected is a constructor
- } else if ( actual instanceof expected ) {
- ok = true;
- // expected is a validation function which returns true is validation passed
- } else if ( expected.call( {}, actual ) === true ) {
- expectedOutput = null;
- ok = true;
- }
-
- QUnit.push( ok, actual, expectedOutput, message );
- } else {
- QUnit.pushFailure( message, null, 'No exception was thrown.' );
- }
- }
-};
-
-/**
- * @deprecate since 1.8.0
- * Kept assertion helpers in root for backwards compatibility.
- */
-extend( QUnit, assert );
-
-/**
- * @deprecated since 1.9.0
- * Kept root "raises()" for backwards compatibility.
- * (Note that we don't introduce assert.raises).
- */
-QUnit.raises = assert[ "throws" ];
-
-/**
- * @deprecated since 1.0.0, replaced with error pushes since 1.3.0
- * Kept to avoid TypeErrors for undefined methods.
- */
-QUnit.equals = function() {
- QUnit.push( false, false, false, "QUnit.equals has been deprecated since 2009 (e88049a0), use QUnit.equal instead" );
-};
-QUnit.same = function() {
- QUnit.push( false, false, false, "QUnit.same has been deprecated since 2009 (e88049a0), use QUnit.deepEqual instead" );
-};
-
-// We want access to the constructor's prototype
-(function() {
- function F() {}
- F.prototype = QUnit;
- QUnit = new F();
- // Make F QUnit's constructor so that we can add to the prototype later
- QUnit.constructor = F;
-}());
-
-/**
- * Config object: Maintain internal state
- * Later exposed as QUnit.config
- * `config` initialized at top of scope
- */
-config = {
- // The queue of tests to run
- queue: [],
-
- // block until document ready
- blocking: true,
-
- // when enabled, show only failing tests
- // gets persisted through sessionStorage and can be changed in UI via checkbox
- hidepassed: false,
-
- // by default, run previously failed tests first
- // very useful in combination with "Hide passed tests" checked
- reorder: true,
-
- // by default, modify document.title when suite is done
- altertitle: true,
-
- // when enabled, all tests must call expect()
- requireExpects: false,
-
- // add checkboxes that are persisted in the query-string
- // when enabled, the id is set to `true` as a `QUnit.config` property
- urlConfig: [
- {
- id: "noglobals",
- label: "Check for Globals",
- tooltip: "Enabling this will test if any test introduces new properties on the `window` object. Stored as query-strings."
- },
- {
- id: "notrycatch",
- label: "No try-catch",
- tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging exceptions in IE reasonable. Stored as query-strings."
- }
- ],
-
- // Set of all modules.
- modules: {},
-
- // logging callback queues
- begin: [],
- done: [],
- log: [],
- testStart: [],
- testDone: [],
- moduleStart: [],
- moduleDone: []
-};
-
-// Export global variables, unless an 'exports' object exists,
-// in that case we assume we're in CommonJS (dealt with on the bottom of the script)
-if ( typeof exports === "undefined" ) {
- extend( window, QUnit );
-
- // Expose QUnit object
- window.QUnit = QUnit;
-}
-
-// Initialize more QUnit.config and QUnit.urlParams
-(function() {
- var i,
- location = window.location || { search: "", protocol: "file:" },
- params = location.search.slice( 1 ).split( "&" ),
- length = params.length,
- urlParams = {},
- current;
-
- if ( params[ 0 ] ) {
- for ( i = 0; i < length; i++ ) {
- current = params[ i ].split( "=" );
- current[ 0 ] = decodeURIComponent( current[ 0 ] );
- // allow just a key to turn on a flag, e.g., test.html?noglobals
- current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true;
- urlParams[ current[ 0 ] ] = current[ 1 ];
- }
- }
-
- QUnit.urlParams = urlParams;
-
- // String search anywhere in moduleName+testName
- config.filter = urlParams.filter;
-
- // Exact match of the module name
- config.module = urlParams.module;
-
- config.testNumber = parseInt( urlParams.testNumber, 10 ) || null;
-
- // Figure out if we're running the tests from a server or not
- QUnit.isLocal = location.protocol === "file:";
-}());
-
-// Extend QUnit object,
-// these after set here because they should not be exposed as global functions
-extend( QUnit, {
- assert: assert,
-
- config: config,
-
- // Initialize the configuration options
- init: function() {
- extend( config, {
- stats: { all: 0, bad: 0 },
- moduleStats: { all: 0, bad: 0 },
- started: +new Date(),
- updateRate: 1000,
- blocking: false,
- autostart: true,
- autorun: false,
- filter: "",
- queue: [],
- semaphore: 1
- });
-
- var tests, banner, result,
- qunit = id( "qunit" );
-
- if ( qunit ) {
- qunit.innerHTML =
- "" +
- "" +
- "" +
- "" +
- "
";
- }
-
- tests = id( "qunit-tests" );
- banner = id( "qunit-banner" );
- result = id( "qunit-testresult" );
-
- if ( tests ) {
- tests.innerHTML = "";
- }
-
- if ( banner ) {
- banner.className = "";
- }
-
- if ( result ) {
- result.parentNode.removeChild( result );
- }
-
- if ( tests ) {
- result = document.createElement( "p" );
- result.id = "qunit-testresult";
- result.className = "result";
- tests.parentNode.insertBefore( result, tests );
- result.innerHTML = "Running...
";
- }
- },
-
- // Resets the test setup. Useful for tests that modify the DOM.
- reset: function() {
- var fixture = id( "qunit-fixture" );
- if ( fixture ) {
- fixture.innerHTML = config.fixture;
- }
- },
-
- // Trigger an event on an element.
- // @example triggerEvent( document.body, "click" );
- triggerEvent: function( elem, type, event ) {
- if ( document.createEvent ) {
- event = document.createEvent( "MouseEvents" );
- event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView,
- 0, 0, 0, 0, 0, false, false, false, false, 0, null);
-
- elem.dispatchEvent( event );
- } else if ( elem.fireEvent ) {
- elem.fireEvent( "on" + type );
- }
- },
-
- // Safe object type checking
- is: function( type, obj ) {
- return QUnit.objectType( obj ) === type;
- },
-
- objectType: function( obj ) {
- if ( typeof obj === "undefined" ) {
- return "undefined";
- // consider: typeof null === object
- }
- if ( obj === null ) {
- return "null";
- }
-
- var match = toString.call( obj ).match(/^\[object\s(.*)\]$/),
- type = match && match[1] || "";
-
- switch ( type ) {
- case "Number":
- if ( isNaN(obj) ) {
- return "nan";
- }
- return "number";
- case "String":
- case "Boolean":
- case "Array":
- case "Date":
- case "RegExp":
- case "Function":
- return type.toLowerCase();
- }
- if ( typeof obj === "object" ) {
- return "object";
- }
- return undefined;
- },
-
- push: function( result, actual, expected, message ) {
- if ( !config.current ) {
- throw new Error( "assertion outside test context, was " + sourceFromStacktrace() );
- }
-
- var output, source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: message,
- actual: actual,
- expected: expected
- };
-
- message = escapeText( message ) || ( result ? "okay" : "failed" );
- message = "" + message + "";
- output = message;
-
- if ( !result ) {
- expected = escapeText( QUnit.jsDump.parse(expected) );
- actual = escapeText( QUnit.jsDump.parse(actual) );
- output += "Expected: | " + expected + " |
";
-
- if ( actual !== expected ) {
- output += "Result: | " + actual + " |
";
- output += "Diff: | " + QUnit.diff( expected, actual ) + " |
";
- }
-
- source = sourceFromStacktrace();
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
- }
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: !!result,
- message: output
- });
- },
-
- pushFailure: function( message, source, actual ) {
- if ( !config.current ) {
- throw new Error( "pushFailure() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
-
- var output,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: false,
- message: message
- };
-
- message = escapeText( message ) || "error";
- message = "" + message + "";
- output = message;
-
- output += "";
-
- if ( actual ) {
- output += "Result: | " + escapeText( actual ) + " |
";
- }
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: false,
- message: output
- });
- },
-
- url: function( params ) {
- params = extend( extend( {}, QUnit.urlParams ), params );
- var key,
- querystring = "?";
-
- for ( key in params ) {
- if ( !hasOwn.call( params, key ) ) {
- continue;
- }
- querystring += encodeURIComponent( key ) + "=" +
- encodeURIComponent( params[ key ] ) + "&";
- }
- return window.location.protocol + "//" + window.location.host +
- window.location.pathname + querystring.slice( 0, -1 );
- },
-
- extend: extend,
- id: id,
- addEvent: addEvent
- // load, equiv, jsDump, diff: Attached later
-});
-
-/**
- * @deprecated: Created for backwards compatibility with test runner that set the hook function
- * into QUnit.{hook}, instead of invoking it and passing the hook function.
- * QUnit.constructor is set to the empty F() above so that we can add to it's prototype here.
- * Doing this allows us to tell if the following methods have been overwritten on the actual
- * QUnit object.
- */
-extend( QUnit.constructor.prototype, {
-
- // Logging callbacks; all receive a single argument with the listed properties
- // run test/logs.html for any related changes
- begin: registerLoggingCallback( "begin" ),
-
- // done: { failed, passed, total, runtime }
- done: registerLoggingCallback( "done" ),
-
- // log: { result, actual, expected, message }
- log: registerLoggingCallback( "log" ),
-
- // testStart: { name }
- testStart: registerLoggingCallback( "testStart" ),
-
- // testDone: { name, failed, passed, total, duration }
- testDone: registerLoggingCallback( "testDone" ),
-
- // moduleStart: { name }
- moduleStart: registerLoggingCallback( "moduleStart" ),
-
- // moduleDone: { name, failed, passed, total }
- moduleDone: registerLoggingCallback( "moduleDone" )
-});
-
-if ( typeof document === "undefined" || document.readyState === "complete" ) {
- config.autorun = true;
-}
-
-QUnit.load = function() {
- runLoggingCallbacks( "begin", QUnit, {} );
-
- // Initialize the config, saving the execution queue
- var banner, filter, i, label, len, main, ol, toolbar, userAgent, val,
- urlConfigCheckboxesContainer, urlConfigCheckboxes, moduleFilter,
- numModules = 0,
- moduleFilterHtml = "",
- urlConfigHtml = "",
- oldconfig = extend( {}, config );
-
- QUnit.init();
- extend(config, oldconfig);
-
- config.blocking = false;
-
- len = config.urlConfig.length;
-
- for ( i = 0; i < len; i++ ) {
- val = config.urlConfig[i];
- if ( typeof val === "string" ) {
- val = {
- id: val,
- label: val,
- tooltip: "[no tooltip available]"
- };
- }
- config[ val.id ] = QUnit.urlParams[ val.id ];
- urlConfigHtml += "";
- }
-
- moduleFilterHtml += "";
-
- // `userAgent` initialized at top of scope
- userAgent = id( "qunit-userAgent" );
- if ( userAgent ) {
- userAgent.innerHTML = navigator.userAgent;
- }
-
- // `banner` initialized at top of scope
- banner = id( "qunit-header" );
- if ( banner ) {
- banner.innerHTML = "" + banner.innerHTML + " ";
- }
-
- // `toolbar` initialized at top of scope
- toolbar = id( "qunit-testrunner-toolbar" );
- if ( toolbar ) {
- // `filter` initialized at top of scope
- filter = document.createElement( "input" );
- filter.type = "checkbox";
- filter.id = "qunit-filter-pass";
-
- addEvent( filter, "click", function() {
- var tmp,
- ol = document.getElementById( "qunit-tests" );
-
- if ( filter.checked ) {
- ol.className = ol.className + " hidepass";
- } else {
- tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " ";
- ol.className = tmp.replace( / hidepass /, " " );
- }
- if ( defined.sessionStorage ) {
- if (filter.checked) {
- sessionStorage.setItem( "qunit-filter-passed-tests", "true" );
- } else {
- sessionStorage.removeItem( "qunit-filter-passed-tests" );
- }
- }
- });
-
- if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem( "qunit-filter-passed-tests" ) ) {
- filter.checked = true;
- // `ol` initialized at top of scope
- ol = document.getElementById( "qunit-tests" );
- ol.className = ol.className + " hidepass";
- }
- toolbar.appendChild( filter );
-
- // `label` initialized at top of scope
- label = document.createElement( "label" );
- label.setAttribute( "for", "qunit-filter-pass" );
- label.setAttribute( "title", "Only show tests and assertons that fail. Stored in sessionStorage." );
- label.innerHTML = "Hide passed tests";
- toolbar.appendChild( label );
-
- urlConfigCheckboxesContainer = document.createElement("span");
- urlConfigCheckboxesContainer.innerHTML = urlConfigHtml;
- urlConfigCheckboxes = urlConfigCheckboxesContainer.getElementsByTagName("input");
- // For oldIE support:
- // * Add handlers to the individual elements instead of the container
- // * Use "click" instead of "change"
- // * Fallback from event.target to event.srcElement
- addEvents( urlConfigCheckboxes, "click", function( event ) {
- var params = {},
- target = event.target || event.srcElement;
- params[ target.name ] = target.checked ? true : undefined;
- window.location = QUnit.url( params );
- });
- toolbar.appendChild( urlConfigCheckboxesContainer );
-
- if (numModules > 1) {
- moduleFilter = document.createElement( 'span' );
- moduleFilter.setAttribute( 'id', 'qunit-modulefilter-container' );
- moduleFilter.innerHTML = moduleFilterHtml;
- addEvent( moduleFilter.lastChild, "change", function() {
- var selectBox = moduleFilter.getElementsByTagName("select")[0],
- selectedModule = decodeURIComponent(selectBox.options[selectBox.selectedIndex].value);
-
- window.location = QUnit.url( { module: ( selectedModule === "" ) ? undefined : selectedModule } );
- });
- toolbar.appendChild(moduleFilter);
- }
- }
-
- // `main` initialized at top of scope
- main = id( "qunit-fixture" );
- if ( main ) {
- config.fixture = main.innerHTML;
- }
-
- if ( config.autostart ) {
- QUnit.start();
- }
-};
-
-addEvent( window, "load", QUnit.load );
-
-// `onErrorFnPrev` initialized at top of scope
-// Preserve other handlers
-onErrorFnPrev = window.onerror;
-
-// Cover uncaught exceptions
-// Returning true will surpress the default browser handler,
-// returning false will let it run.
-window.onerror = function ( error, filePath, linerNr ) {
- var ret = false;
- if ( onErrorFnPrev ) {
- ret = onErrorFnPrev( error, filePath, linerNr );
- }
-
- // Treat return value as window.onerror itself does,
- // Only do our handling if not surpressed.
- if ( ret !== true ) {
- if ( QUnit.config.current ) {
- if ( QUnit.config.current.ignoreGlobalErrors ) {
- return true;
- }
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- } else {
- QUnit.test( "global failure", extend( function() {
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- }, { validTest: validTest } ) );
- }
- return false;
- }
-
- return ret;
-};
-
-function done() {
- config.autorun = true;
-
- // Log the last module results
- if ( config.currentModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.currentModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
-
- var i, key,
- banner = id( "qunit-banner" ),
- tests = id( "qunit-tests" ),
- runtime = +new Date() - config.started,
- passed = config.stats.all - config.stats.bad,
- html = [
- "Tests completed in ",
- runtime,
- " milliseconds.
",
- "",
- passed,
- " assertions of ",
- config.stats.all,
- " passed, ",
- config.stats.bad,
- " failed."
- ].join( "" );
-
- if ( banner ) {
- banner.className = ( config.stats.bad ? "qunit-fail" : "qunit-pass" );
- }
-
- if ( tests ) {
- id( "qunit-testresult" ).innerHTML = html;
- }
-
- if ( config.altertitle && typeof document !== "undefined" && document.title ) {
- // show ✖ for good, ✔ for bad suite result in title
- // use escape sequences in case file gets loaded with non-utf-8-charset
- document.title = [
- ( config.stats.bad ? "\u2716" : "\u2714" ),
- document.title.replace( /^[\u2714\u2716] /i, "" )
- ].join( " " );
- }
-
- // clear own sessionStorage items if all tests passed
- if ( config.reorder && defined.sessionStorage && config.stats.bad === 0 ) {
- // `key` & `i` initialized at top of scope
- for ( i = 0; i < sessionStorage.length; i++ ) {
- key = sessionStorage.key( i++ );
- if ( key.indexOf( "qunit-test-" ) === 0 ) {
- sessionStorage.removeItem( key );
- }
- }
- }
-
- // scroll back to top to show results
- if ( window.scrollTo ) {
- window.scrollTo(0, 0);
- }
-
- runLoggingCallbacks( "done", QUnit, {
- failed: config.stats.bad,
- passed: passed,
- total: config.stats.all,
- runtime: runtime
- });
-}
-
-/** @return Boolean: true if this test should be ran */
-function validTest( test ) {
- var include,
- filter = config.filter && config.filter.toLowerCase(),
- module = config.module && config.module.toLowerCase(),
- fullName = (test.module + ": " + test.testName).toLowerCase();
-
- // Internally-generated tests are always valid
- if ( test.callback && test.callback.validTest === validTest ) {
- delete test.callback.validTest;
- return true;
- }
-
- if ( config.testNumber ) {
- return test.testNumber === config.testNumber;
- }
-
- if ( module && ( !test.module || test.module.toLowerCase() !== module ) ) {
- return false;
- }
-
- if ( !filter ) {
- return true;
- }
-
- include = filter.charAt( 0 ) !== "!";
- if ( !include ) {
- filter = filter.slice( 1 );
- }
-
- // If the filter matches, we need to honour include
- if ( fullName.indexOf( filter ) !== -1 ) {
- return include;
- }
-
- // Otherwise, do the opposite
- return !include;
-}
-
-// so far supports only Firefox, Chrome and Opera (buggy), Safari (for real exceptions)
-// Later Safari and IE10 are supposed to support error.stack as well
-// See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack
-function extractStacktrace( e, offset ) {
- offset = offset === undefined ? 3 : offset;
-
- var stack, include, i;
-
- if ( e.stacktrace ) {
- // Opera
- return e.stacktrace.split( "\n" )[ offset + 3 ];
- } else if ( e.stack ) {
- // Firefox, Chrome
- stack = e.stack.split( "\n" );
- if (/^error$/i.test( stack[0] ) ) {
- stack.shift();
- }
- if ( fileName ) {
- include = [];
- for ( i = offset; i < stack.length; i++ ) {
- if ( stack[ i ].indexOf( fileName ) !== -1 ) {
- break;
- }
- include.push( stack[ i ] );
- }
- if ( include.length ) {
- return include.join( "\n" );
- }
- }
- return stack[ offset ];
- } else if ( e.sourceURL ) {
- // Safari, PhantomJS
- // hopefully one day Safari provides actual stacktraces
- // exclude useless self-reference for generated Error objects
- if ( /qunit.js$/.test( e.sourceURL ) ) {
- return;
- }
- // for actual exceptions, this is useful
- return e.sourceURL + ":" + e.line;
- }
-}
-function sourceFromStacktrace( offset ) {
- try {
- throw new Error();
- } catch ( e ) {
- return extractStacktrace( e, offset );
- }
-}
-
-/**
- * Escape text for attribute or text content.
- */
-function escapeText( s ) {
- if ( !s ) {
- return "";
- }
- s = s + "";
- // Both single quotes and double quotes (for attributes)
- return s.replace( /['"<>&]/g, function( s ) {
- switch( s ) {
- case '\'':
- return ''';
- case '"':
- return '"';
- case '<':
- return '<';
- case '>':
- return '>';
- case '&':
- return '&';
- }
- });
-}
-
-function synchronize( callback, last ) {
- config.queue.push( callback );
-
- if ( config.autorun && !config.blocking ) {
- process( last );
- }
-}
-
-function process( last ) {
- function next() {
- process( last );
- }
- var start = new Date().getTime();
- config.depth = config.depth ? config.depth + 1 : 1;
-
- while ( config.queue.length && !config.blocking ) {
- if ( !defined.setTimeout || config.updateRate <= 0 || ( ( new Date().getTime() - start ) < config.updateRate ) ) {
- config.queue.shift()();
- } else {
- window.setTimeout( next, 13 );
- break;
- }
- }
- config.depth--;
- if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) {
- done();
- }
-}
-
-function saveGlobal() {
- config.pollution = [];
-
- if ( config.noglobals ) {
- for ( var key in window ) {
- // in Opera sometimes DOM element ids show up here, ignore them
- if ( !hasOwn.call( window, key ) || /^qunit-test-output/.test( key ) ) {
- continue;
- }
- config.pollution.push( key );
- }
- }
-}
-
-function checkPollution() {
- var newGlobals,
- deletedGlobals,
- old = config.pollution;
-
- saveGlobal();
-
- newGlobals = diff( config.pollution, old );
- if ( newGlobals.length > 0 ) {
- QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join(", ") );
- }
-
- deletedGlobals = diff( old, config.pollution );
- if ( deletedGlobals.length > 0 ) {
- QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join(", ") );
- }
-}
-
-// returns a new Array with the elements that are in a but not in b
-function diff( a, b ) {
- var i, j,
- result = a.slice();
-
- for ( i = 0; i < result.length; i++ ) {
- for ( j = 0; j < b.length; j++ ) {
- if ( result[i] === b[j] ) {
- result.splice( i, 1 );
- i--;
- break;
- }
- }
- }
- return result;
-}
-
-function extend( a, b ) {
- for ( var prop in b ) {
- if ( b[ prop ] === undefined ) {
- delete a[ prop ];
-
- // Avoid "Member not found" error in IE8 caused by setting window.constructor
- } else if ( prop !== "constructor" || a !== window ) {
- a[ prop ] = b[ prop ];
- }
- }
-
- return a;
-}
-
-/**
- * @param {HTMLElement} elem
- * @param {string} type
- * @param {Function} fn
- */
-function addEvent( elem, type, fn ) {
- // Standards-based browsers
- if ( elem.addEventListener ) {
- elem.addEventListener( type, fn, false );
- // IE
- } else {
- elem.attachEvent( "on" + type, fn );
- }
-}
-
-/**
- * @param {Array|NodeList} elems
- * @param {string} type
- * @param {Function} fn
- */
-function addEvents( elems, type, fn ) {
- var i = elems.length;
- while ( i-- ) {
- addEvent( elems[i], type, fn );
- }
-}
-
-function hasClass( elem, name ) {
- return (" " + elem.className + " ").indexOf(" " + name + " ") > -1;
-}
-
-function addClass( elem, name ) {
- if ( !hasClass( elem, name ) ) {
- elem.className += (elem.className ? " " : "") + name;
- }
-}
-
-function removeClass( elem, name ) {
- var set = " " + elem.className + " ";
- // Class name may appear multiple times
- while ( set.indexOf(" " + name + " ") > -1 ) {
- set = set.replace(" " + name + " " , " ");
- }
- // If possible, trim it for prettiness, but not neccecarily
- elem.className = window.jQuery ? jQuery.trim( set ) : ( set.trim ? set.trim() : set );
-}
-
-function id( name ) {
- return !!( typeof document !== "undefined" && document && document.getElementById ) &&
- document.getElementById( name );
-}
-
-function registerLoggingCallback( key ) {
- return function( callback ) {
- config[key].push( callback );
- };
-}
-
-// Supports deprecated method of completely overwriting logging callbacks
-function runLoggingCallbacks( key, scope, args ) {
- var i, callbacks;
- if ( QUnit.hasOwnProperty( key ) ) {
- QUnit[ key ].call(scope, args );
- } else {
- callbacks = config[ key ];
- for ( i = 0; i < callbacks.length; i++ ) {
- callbacks[ i ].call( scope, args );
- }
- }
-}
-
-// Test for equality any JavaScript type.
-// Author: Philippe Rathé
-QUnit.equiv = (function() {
-
- // Call the o related callback with the given arguments.
- function bindCallbacks( o, callbacks, args ) {
- var prop = QUnit.objectType( o );
- if ( prop ) {
- if ( QUnit.objectType( callbacks[ prop ] ) === "function" ) {
- return callbacks[ prop ].apply( callbacks, args );
- } else {
- return callbacks[ prop ]; // or undefined
- }
- }
- }
-
- // the real equiv function
- var innerEquiv,
- // stack to decide between skip/abort functions
- callers = [],
- // stack to avoiding loops from circular referencing
- parents = [],
-
- getProto = Object.getPrototypeOf || function ( obj ) {
- return obj.__proto__;
- },
- callbacks = (function () {
-
- // for string, boolean, number and null
- function useStrictEquality( b, a ) {
- /*jshint eqeqeq:false */
- if ( b instanceof a.constructor || a instanceof b.constructor ) {
- // to catch short annotaion VS 'new' annotation of a
- // declaration
- // e.g. var i = 1;
- // var j = new Number(1);
- return a == b;
- } else {
- return a === b;
- }
- }
-
- return {
- "string": useStrictEquality,
- "boolean": useStrictEquality,
- "number": useStrictEquality,
- "null": useStrictEquality,
- "undefined": useStrictEquality,
-
- "nan": function( b ) {
- return isNaN( b );
- },
-
- "date": function( b, a ) {
- return QUnit.objectType( b ) === "date" && a.valueOf() === b.valueOf();
- },
-
- "regexp": function( b, a ) {
- return QUnit.objectType( b ) === "regexp" &&
- // the regex itself
- a.source === b.source &&
- // and its modifers
- a.global === b.global &&
- // (gmi) ...
- a.ignoreCase === b.ignoreCase &&
- a.multiline === b.multiline &&
- a.sticky === b.sticky;
- },
-
- // - skip when the property is a method of an instance (OOP)
- // - abort otherwise,
- // initial === would have catch identical references anyway
- "function": function() {
- var caller = callers[callers.length - 1];
- return caller !== Object && typeof caller !== "undefined";
- },
-
- "array": function( b, a ) {
- var i, j, len, loop;
-
- // b could be an object literal here
- if ( QUnit.objectType( b ) !== "array" ) {
- return false;
- }
-
- len = a.length;
- if ( len !== b.length ) {
- // safe and faster
- return false;
- }
-
- // track reference to avoid circular references
- parents.push( a );
- for ( i = 0; i < len; i++ ) {
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- loop = true;// dont rewalk array
- }
- }
- if ( !loop && !innerEquiv(a[i], b[i]) ) {
- parents.pop();
- return false;
- }
- }
- parents.pop();
- return true;
- },
-
- "object": function( b, a ) {
- var i, j, loop,
- // Default to true
- eq = true,
- aProperties = [],
- bProperties = [];
-
- // comparing constructors is more strict than using
- // instanceof
- if ( a.constructor !== b.constructor ) {
- // Allow objects with no prototype to be equivalent to
- // objects with Object as their constructor.
- if ( !(( getProto(a) === null && getProto(b) === Object.prototype ) ||
- ( getProto(b) === null && getProto(a) === Object.prototype ) ) ) {
- return false;
- }
- }
-
- // stack constructor before traversing properties
- callers.push( a.constructor );
- // track reference to avoid circular references
- parents.push( a );
-
- for ( i in a ) { // be strict: don't ensures hasOwnProperty
- // and go deep
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- // don't go down the same path twice
- loop = true;
- }
- }
- aProperties.push(i); // collect a's properties
-
- if (!loop && !innerEquiv( a[i], b[i] ) ) {
- eq = false;
- break;
- }
- }
-
- callers.pop(); // unstack, we are done
- parents.pop();
-
- for ( i in b ) {
- bProperties.push( i ); // collect b's properties
- }
-
- // Ensures identical properties name
- return eq && innerEquiv( aProperties.sort(), bProperties.sort() );
- }
- };
- }());
-
- innerEquiv = function() { // can take multiple arguments
- var args = [].slice.apply( arguments );
- if ( args.length < 2 ) {
- return true; // end transition
- }
-
- return (function( a, b ) {
- if ( a === b ) {
- return true; // catch the most you can
- } else if ( a === null || b === null || typeof a === "undefined" ||
- typeof b === "undefined" ||
- QUnit.objectType(a) !== QUnit.objectType(b) ) {
- return false; // don't lose time with error prone cases
- } else {
- return bindCallbacks(a, callbacks, [ b, a ]);
- }
-
- // apply transition with (1..n) arguments
- }( args[0], args[1] ) && arguments.callee.apply( this, args.splice(1, args.length - 1 )) );
- };
-
- return innerEquiv;
-}());
-
-/**
- * jsDump Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com |
- * http://flesler.blogspot.com Licensed under BSD
- * (http://www.opensource.org/licenses/bsd-license.php) Date: 5/15/2008
- *
- * @projectDescription Advanced and extensible data dumping for Javascript.
- * @version 1.0.0
- * @author Ariel Flesler
- * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html}
- */
-QUnit.jsDump = (function() {
- function quote( str ) {
- return '"' + str.toString().replace( /"/g, '\\"' ) + '"';
- }
- function literal( o ) {
- return o + "";
- }
- function join( pre, arr, post ) {
- var s = jsDump.separator(),
- base = jsDump.indent(),
- inner = jsDump.indent(1);
- if ( arr.join ) {
- arr = arr.join( "," + s + inner );
- }
- if ( !arr ) {
- return pre + post;
- }
- return [ pre, inner + arr, base + post ].join(s);
- }
- function array( arr, stack ) {
- var i = arr.length, ret = new Array(i);
- this.up();
- while ( i-- ) {
- ret[i] = this.parse( arr[i] , undefined , stack);
- }
- this.down();
- return join( "[", ret, "]" );
- }
-
- var reName = /^function (\w+)/,
- jsDump = {
- // type is used mostly internally, you can fix a (custom)type in advance
- parse: function( obj, type, stack ) {
- stack = stack || [ ];
- var inStack, res,
- parser = this.parsers[ type || this.typeOf(obj) ];
-
- type = typeof parser;
- inStack = inArray( obj, stack );
-
- if ( inStack !== -1 ) {
- return "recursion(" + (inStack - stack.length) + ")";
- }
- if ( type === "function" ) {
- stack.push( obj );
- res = parser.call( this, obj, stack );
- stack.pop();
- return res;
- }
- return ( type === "string" ) ? parser : this.parsers.error;
- },
- typeOf: function( obj ) {
- var type;
- if ( obj === null ) {
- type = "null";
- } else if ( typeof obj === "undefined" ) {
- type = "undefined";
- } else if ( QUnit.is( "regexp", obj) ) {
- type = "regexp";
- } else if ( QUnit.is( "date", obj) ) {
- type = "date";
- } else if ( QUnit.is( "function", obj) ) {
- type = "function";
- } else if ( typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined" ) {
- type = "window";
- } else if ( obj.nodeType === 9 ) {
- type = "document";
- } else if ( obj.nodeType ) {
- type = "node";
- } else if (
- // native arrays
- toString.call( obj ) === "[object Array]" ||
- // NodeList objects
- ( typeof obj.length === "number" && typeof obj.item !== "undefined" && ( obj.length ? obj.item(0) === obj[0] : ( obj.item( 0 ) === null && typeof obj[0] === "undefined" ) ) )
- ) {
- type = "array";
- } else if ( obj.constructor === Error.prototype.constructor ) {
- type = "error";
- } else {
- type = typeof obj;
- }
- return type;
- },
- separator: function() {
- return this.multiline ? this.HTML ? "
" : "\n" : this.HTML ? " " : " ";
- },
- // extra can be a number, shortcut for increasing-calling-decreasing
- indent: function( extra ) {
- if ( !this.multiline ) {
- return "";
- }
- var chr = this.indentChar;
- if ( this.HTML ) {
- chr = chr.replace( /\t/g, " " ).replace( / /g, " " );
- }
- return new Array( this._depth_ + (extra||0) ).join(chr);
- },
- up: function( a ) {
- this._depth_ += a || 1;
- },
- down: function( a ) {
- this._depth_ -= a || 1;
- },
- setParser: function( name, parser ) {
- this.parsers[name] = parser;
- },
- // The next 3 are exposed so you can use them
- quote: quote,
- literal: literal,
- join: join,
- //
- _depth_: 1,
- // This is the list of parsers, to modify them, use jsDump.setParser
- parsers: {
- window: "[Window]",
- document: "[Document]",
- error: function(error) {
- return "Error(\"" + error.message + "\")";
- },
- unknown: "[Unknown]",
- "null": "null",
- "undefined": "undefined",
- "function": function( fn ) {
- var ret = "function",
- // functions never have name in IE
- name = "name" in fn ? fn.name : (reName.exec(fn) || [])[1];
-
- if ( name ) {
- ret += " " + name;
- }
- ret += "( ";
-
- ret = [ ret, QUnit.jsDump.parse( fn, "functionArgs" ), "){" ].join( "" );
- return join( ret, QUnit.jsDump.parse(fn,"functionCode" ), "}" );
- },
- array: array,
- nodelist: array,
- "arguments": array,
- object: function( map, stack ) {
- var ret = [ ], keys, key, val, i;
- QUnit.jsDump.up();
- keys = [];
- for ( key in map ) {
- keys.push( key );
- }
- keys.sort();
- for ( i = 0; i < keys.length; i++ ) {
- key = keys[ i ];
- val = map[ key ];
- ret.push( QUnit.jsDump.parse( key, "key" ) + ": " + QUnit.jsDump.parse( val, undefined, stack ) );
- }
- QUnit.jsDump.down();
- return join( "{", ret, "}" );
- },
- node: function( node ) {
- var len, i, val,
- open = QUnit.jsDump.HTML ? "<" : "<",
- close = QUnit.jsDump.HTML ? ">" : ">",
- tag = node.nodeName.toLowerCase(),
- ret = open + tag,
- attrs = node.attributes;
-
- if ( attrs ) {
- for ( i = 0, len = attrs.length; i < len; i++ ) {
- val = attrs[i].nodeValue;
- // IE6 includes all attributes in .attributes, even ones not explicitly set.
- // Those have values like undefined, null, 0, false, "" or "inherit".
- if ( val && val !== "inherit" ) {
- ret += " " + attrs[i].nodeName + "=" + QUnit.jsDump.parse( val, "attribute" );
- }
- }
- }
- ret += close;
-
- // Show content of TextNode or CDATASection
- if ( node.nodeType === 3 || node.nodeType === 4 ) {
- ret += node.nodeValue;
- }
-
- return ret + open + "/" + tag + close;
- },
- // function calls it internally, it's the arguments part of the function
- functionArgs: function( fn ) {
- var args,
- l = fn.length;
-
- if ( !l ) {
- return "";
- }
-
- args = new Array(l);
- while ( l-- ) {
- // 97 is 'a'
- args[l] = String.fromCharCode(97+l);
- }
- return " " + args.join( ", " ) + " ";
- },
- // object calls it internally, the key part of an item in a map
- key: quote,
- // function calls it internally, it's the content of the function
- functionCode: "[code]",
- // node calls it internally, it's an html attribute value
- attribute: quote,
- string: quote,
- date: quote,
- regexp: literal,
- number: literal,
- "boolean": literal
- },
- // if true, entities are escaped ( <, >, \t, space and \n )
- HTML: false,
- // indentation unit
- indentChar: " ",
- // if true, items in a collection, are separated by a \n, else just a space.
- multiline: true
- };
-
- return jsDump;
-}());
-
-// from jquery.js
-function inArray( elem, array ) {
- if ( array.indexOf ) {
- return array.indexOf( elem );
- }
-
- for ( var i = 0, length = array.length; i < length; i++ ) {
- if ( array[ i ] === elem ) {
- return i;
- }
- }
-
- return -1;
-}
-
-/*
- * Javascript Diff Algorithm
- * By John Resig (http://ejohn.org/)
- * Modified by Chu Alan "sprite"
- *
- * Released under the MIT license.
- *
- * More Info:
- * http://ejohn.org/projects/javascript-diff-algorithm/
- *
- * Usage: QUnit.diff(expected, actual)
- *
- * QUnit.diff( "the quick brown fox jumped over", "the quick fox jumps over" ) == "the quick brown fox jumped jumps over"
- */
-QUnit.diff = (function() {
- /*jshint eqeqeq:false, eqnull:true */
- function diff( o, n ) {
- var i,
- ns = {},
- os = {};
-
- for ( i = 0; i < n.length; i++ ) {
- if ( !hasOwn.call( ns, n[i] ) ) {
- ns[ n[i] ] = {
- rows: [],
- o: null
- };
- }
- ns[ n[i] ].rows.push( i );
- }
-
- for ( i = 0; i < o.length; i++ ) {
- if ( !hasOwn.call( os, o[i] ) ) {
- os[ o[i] ] = {
- rows: [],
- n: null
- };
- }
- os[ o[i] ].rows.push( i );
- }
-
- for ( i in ns ) {
- if ( !hasOwn.call( ns, i ) ) {
- continue;
- }
- if ( ns[i].rows.length === 1 && hasOwn.call( os, i ) && os[i].rows.length === 1 ) {
- n[ ns[i].rows[0] ] = {
- text: n[ ns[i].rows[0] ],
- row: os[i].rows[0]
- };
- o[ os[i].rows[0] ] = {
- text: o[ os[i].rows[0] ],
- row: ns[i].rows[0]
- };
- }
- }
-
- for ( i = 0; i < n.length - 1; i++ ) {
- if ( n[i].text != null && n[ i + 1 ].text == null && n[i].row + 1 < o.length && o[ n[i].row + 1 ].text == null &&
- n[ i + 1 ] == o[ n[i].row + 1 ] ) {
-
- n[ i + 1 ] = {
- text: n[ i + 1 ],
- row: n[i].row + 1
- };
- o[ n[i].row + 1 ] = {
- text: o[ n[i].row + 1 ],
- row: i + 1
- };
- }
- }
-
- for ( i = n.length - 1; i > 0; i-- ) {
- if ( n[i].text != null && n[ i - 1 ].text == null && n[i].row > 0 && o[ n[i].row - 1 ].text == null &&
- n[ i - 1 ] == o[ n[i].row - 1 ]) {
-
- n[ i - 1 ] = {
- text: n[ i - 1 ],
- row: n[i].row - 1
- };
- o[ n[i].row - 1 ] = {
- text: o[ n[i].row - 1 ],
- row: i - 1
- };
- }
- }
-
- return {
- o: o,
- n: n
- };
- }
-
- return function( o, n ) {
- o = o.replace( /\s+$/, "" );
- n = n.replace( /\s+$/, "" );
-
- var i, pre,
- str = "",
- out = diff( o === "" ? [] : o.split(/\s+/), n === "" ? [] : n.split(/\s+/) ),
- oSpace = o.match(/\s+/g),
- nSpace = n.match(/\s+/g);
-
- if ( oSpace == null ) {
- oSpace = [ " " ];
- }
- else {
- oSpace.push( " " );
- }
-
- if ( nSpace == null ) {
- nSpace = [ " " ];
- }
- else {
- nSpace.push( " " );
- }
-
- if ( out.n.length === 0 ) {
- for ( i = 0; i < out.o.length; i++ ) {
- str += "" + out.o[i] + oSpace[i] + "";
- }
- }
- else {
- if ( out.n[0].text == null ) {
- for ( n = 0; n < out.o.length && out.o[n].text == null; n++ ) {
- str += "" + out.o[n] + oSpace[n] + "";
- }
- }
-
- for ( i = 0; i < out.n.length; i++ ) {
- if (out.n[i].text == null) {
- str += "" + out.n[i] + nSpace[i] + "";
- }
- else {
- // `pre` initialized at top of scope
- pre = "";
-
- for ( n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++ ) {
- pre += "" + out.o[n] + oSpace[n] + "";
- }
- str += " " + out.n[i].text + nSpace[i] + pre;
- }
- }
- }
-
- return str;
- };
-}());
-
-// for CommonJS enviroments, export everything
-if ( typeof exports !== "undefined" ) {
- extend( exports, QUnit );
-}
-
-// get at whatever the global object is, like window in browsers
-}( (function() {return this;}.call()) ));
diff --git a/test/lib/require.js b/test/lib/require.js
deleted file mode 100644
index 987f865..0000000
--- a/test/lib/require.js
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- RequireJS 2.1.5 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.
- Available via the MIT or new BSD license.
- see: http://github.com/jrburke/requirejs for details
-*/
-var requirejs,require,define;
-(function(aa){function I(b){return"[object Function]"===L.call(b)}function J(b){return"[object Array]"===L.call(b)}function y(b,c){if(b){var d;for(d=0;dthis.depCount&&!this.defined){if(I(n)){if(this.events.error)try{e=i.execCb(c,n,b,e)}catch(d){a=d}else e=i.execCb(c,n,b,e);this.map.isDefine&&((b=this.module)&&void 0!==b.exports&&b.exports!==this.exports?e=b.exports:void 0===e&&this.usingExports&&(e=this.exports));if(a)return a.requireMap=this.map,a.requireModules=[this.map.id],a.requireType="define",v(this.error=
-a)}else e=n;this.exports=e;if(this.map.isDefine&&!this.ignore&&(q[c]=e,l.onResourceLoad))l.onResourceLoad(i,this.map,this.depMaps);x(c);this.defined=!0}this.defining=!1;this.defined&&!this.defineEmitted&&(this.defineEmitted=!0,this.emit("defined",this.exports),this.defineEmitComplete=!0)}}else this.fetch()}},callPlugin:function(){var a=this.map,b=a.id,d=j(a.prefix);this.depMaps.push(d);t(d,"defined",u(this,function(e){var n,d;d=this.map.name;var g=this.map.parentMap?this.map.parentMap.name:null,h=
-i.makeRequire(a.parentMap,{enableBuildCallback:!0});if(this.map.unnormalized){if(e.normalize&&(d=e.normalize(d,function(a){return c(a,g,!0)})||""),e=j(a.prefix+"!"+d,this.map.parentMap),t(e,"defined",u(this,function(a){this.init([],function(){return a},null,{enabled:!0,ignore:!0})})),d=m(p,e.id)){this.depMaps.push(e);if(this.events.error)d.on("error",u(this,function(a){this.emit("error",a)}));d.enable()}}else n=u(this,function(a){this.init([],function(){return a},null,{enabled:!0})}),n.error=u(this,
-function(a){this.inited=!0;this.error=a;a.requireModules=[b];G(p,function(a){0===a.map.id.indexOf(b+"_unnormalized")&&x(a.map.id)});v(a)}),n.fromText=u(this,function(e,c){var d=a.name,g=j(d),C=O;c&&(e=c);C&&(O=!1);r(g);s(k.config,b)&&(k.config[d]=k.config[b]);try{l.exec(e)}catch(ca){return v(B("fromtexteval","fromText eval for "+b+" failed: "+ca,ca,[b]))}C&&(O=!0);this.depMaps.push(g);i.completeLoad(d);h([d],n)}),e.load(a.name,h,n,k)}));i.enable(d,this);this.pluginMaps[d.id]=d},enable:function(){V[this.map.id]=
-this;this.enabling=this.enabled=!0;y(this.depMaps,u(this,function(a,b){var c,e;if("string"===typeof a){a=j(a,this.map.isDefine?this.map:this.map.parentMap,!1,!this.skipMap);this.depMaps[b]=a;if(c=m(N,a.id)){this.depExports[b]=c(this);return}this.depCount+=1;t(a,"defined",u(this,function(a){this.defineDep(b,a);this.check()}));this.errback&&t(a,"error",this.errback)}c=a.id;e=p[c];!s(N,c)&&(e&&!e.enabled)&&i.enable(a,this)}));G(this.pluginMaps,u(this,function(a){var b=m(p,a.id);b&&!b.enabled&&i.enable(a,
-this)}));this.enabling=!1;this.check()},on:function(a,b){var c=this.events[a];c||(c=this.events[a]=[]);c.push(b)},emit:function(a,b){y(this.events[a],function(a){a(b)});"error"===a&&delete this.events[a]}};i={config:k,contextName:b,registry:p,defined:q,urlFetched:U,defQueue:H,Module:Z,makeModuleMap:j,nextTick:l.nextTick,onError:v,configure:function(a){a.baseUrl&&"/"!==a.baseUrl.charAt(a.baseUrl.length-1)&&(a.baseUrl+="/");var b=k.pkgs,c=k.shim,e={paths:!0,config:!0,map:!0};G(a,function(a,b){e[b]?
-"map"===b?(k.map||(k.map={}),R(k[b],a,!0,!0)):R(k[b],a,!0):k[b]=a});a.shim&&(G(a.shim,function(a,b){J(a)&&(a={deps:a});if((a.exports||a.init)&&!a.exportsFn)a.exportsFn=i.makeShimExports(a);c[b]=a}),k.shim=c);a.packages&&(y(a.packages,function(a){a="string"===typeof a?{name:a}:a;b[a.name]={name:a.name,location:a.location||a.name,main:(a.main||"main").replace(ja,"").replace(ea,"")}}),k.pkgs=b);G(p,function(a,b){!a.inited&&!a.map.unnormalized&&(a.map=j(b))});if(a.deps||a.callback)i.require(a.deps||[],
-a.callback)},makeShimExports:function(a){return function(){var b;a.init&&(b=a.init.apply(aa,arguments));return b||a.exports&&ba(a.exports)}},makeRequire:function(a,f){function d(e,c,h){var g,k;f.enableBuildCallback&&(c&&I(c))&&(c.__requireJsBuild=!0);if("string"===typeof e){if(I(c))return v(B("requireargs","Invalid require call"),h);if(a&&s(N,e))return N[e](p[a.id]);if(l.get)return l.get(i,e,a,d);g=j(e,a,!1,!0);g=g.id;return!s(q,g)?v(B("notloaded",'Module name "'+g+'" has not been loaded yet for context: '+
-b+(a?"":". Use require([])"))):q[g]}L();i.nextTick(function(){L();k=r(j(null,a));k.skipMap=f.skipMap;k.init(e,c,h,{enabled:!0});D()});return d}f=f||{};R(d,{isBrowser:A,toUrl:function(b){var d,f=b.lastIndexOf("."),g=b.split("/")[0];if(-1!==f&&(!("."===g||".."===g)||1h.attachEvent.toString().indexOf("[native code"))&&!Y?(O=!0,h.attachEvent("onreadystatechange",b.onScriptLoad)):(h.addEventListener("load",b.onScriptLoad,!1),h.addEventListener("error",b.onScriptError,!1)),h.src=d,K=h,D?x.insertBefore(h,D):x.appendChild(h),K=null,h;if(da)try{importScripts(d),b.completeLoad(c)}catch(j){b.onError(B("importscripts","importScripts failed for "+c+" at "+d,j,[c]))}};A&&M(document.getElementsByTagName("script"),function(b){x||(x=
-b.parentNode);if(t=b.getAttribute("data-main"))return r.baseUrl||(E=t.split("/"),Q=E.pop(),fa=E.length?E.join("/")+"/":"./",r.baseUrl=fa,t=Q),t=t.replace(ea,""),r.deps=r.deps?r.deps.concat(t):[t],!0});define=function(b,c,d){var l,h;"string"!==typeof b&&(d=c,c=b,b=null);J(c)||(d=c,c=[]);!c.length&&I(d)&&d.length&&(d.toString().replace(la,"").replace(ma,function(b,d){c.push(d)}),c=(1===d.length?["require"]:["require","exports","module"]).concat(c));if(O){if(!(l=K))P&&"interactive"===P.readyState||M(document.getElementsByTagName("script"),
-function(b){if("interactive"===b.readyState)return P=b}),l=P;l&&(b||(b=l.getAttribute("data-requiremodule")),h=F[l.getAttribute("data-requirecontext")])}(h?h.defQueue:T).push([b,c,d])};define.amd={jQuery:!0};l.exec=function(b){return eval(b)};l(r)}})(this);
diff --git a/test/lib/resemble.js b/test/lib/resemble.js
new file mode 100644
index 0000000..1cb8c29
--- /dev/null
+++ b/test/lib/resemble.js
@@ -0,0 +1,535 @@
+/*
+Author: James Cryer
+Company: Huddle
+Last updated date: 21 Feb 2013
+URL: https://github.com/Huddle/Resemble.js
+*/
+
+(function(_this){
+ 'use strict';
+
+ _this['resemble'] = function( fileData ){
+
+ var data = {};
+ var images = [];
+ var updateCallbackArray = [];
+
+ var tolerance = { // between 0 and 255
+ red: 16,
+ green: 16,
+ blue: 16,
+ minBrightness: 16,
+ maxBrightness: 240
+ };
+
+ var ignoreAntialiasing = false;
+ var ignoreColors = false;
+
+ function triggerDataUpdate(){
+ var len = updateCallbackArray.length;
+ var i;
+ for(i=0;i tolerance.maxBrightness;
+ }
+
+ function getHue(r,g,b){
+
+ r = r / 255;
+ g = g / 255;
+ b = b / 255;
+ var max = Math.max(r, g, b), min = Math.min(r, g, b);
+ var h;
+ var d;
+
+ if (max == min){
+ h = 0; // achromatic
+ } else{
+ d = max - min;
+ switch(max){
+ case r: h = (g - b) / d + (g < b ? 6 : 0); break;
+ case g: h = (b - r) / d + 2; break;
+ case b: h = (r - g) / d + 4; break;
+ }
+ h /= 6;
+ }
+
+ return h;
+ }
+
+ function isAntialiased(sourcePix, data, cacheSet, verticalPos, horizontalPos, width){
+ var offset;
+ var targetPix;
+ var distance = 1;
+ var i;
+ var j;
+ var hasHighContrastSibling = 0;
+ var hasSiblingWithDifferentHue = 0;
+ var hasEquivilantSibling = 0;
+
+ addHueInfo(sourcePix);
+
+ for (i = distance*-1; i <= distance; i++){
+ for (j = distance*-1; j <= distance; j++){
+
+ if(i===0 && j===0){
+ // ignore source pixel
+ } else {
+
+ offset = ((verticalPos+j)*width + (horizontalPos+i)) * 4;
+ targetPix = getPixelInfo(data, offset, cacheSet);
+
+ if(targetPix === null){
+ continue;
+ }
+
+ addBrightnessInfo(targetPix);
+ addHueInfo(targetPix);
+
+ if( isContrasting(sourcePix, targetPix) ){
+ hasHighContrastSibling++;
+ }
+
+ if( isRGBSame(sourcePix,targetPix) ){
+ hasEquivilantSibling++;
+ }
+
+ if( Math.abs(targetPix.h - sourcePix.h) > 0.3 ){
+ hasSiblingWithDifferentHue++;
+ }
+
+ if( hasSiblingWithDifferentHue > 1 || hasHighContrastSibling > 1){
+ return true;
+ }
+ }
+ }
+ }
+
+ if(hasEquivilantSibling < 2){
+ return true;
+ }
+
+ return false;
+ }
+
+ function errorPixel(px, offset){
+ px[offset] = 255; //r
+ px[offset + 1] = 0; //g
+ px[offset + 2] = 255; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyPixel(px, offset, data){
+ px[offset] = data.r; //r
+ px[offset + 1] = data.g; //g
+ px[offset + 2] = data.b; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyGrayScalePixel(px, offset, data){
+ px[offset] = data.brightness; //r
+ px[offset + 1] = data.brightness; //g
+ px[offset + 2] = data.brightness; //b
+ px[offset + 3] = 255; //a
+ }
+
+
+ function getPixelInfo(data, offset, cacheSet){
+ var r;
+ var g;
+ var b;
+ var d;
+
+ if(typeof data[offset] !== 'undefined'){
+ r = data[offset];
+ g = data[offset+1];
+ b = data[offset+2];
+ d = {
+ r: r,
+ g: g,
+ b: b
+ };
+
+ return d;
+ } else {
+ return null;
+ }
+ }
+
+ function addBrightnessInfo(data){
+ data.brightness = getBrightness(data.r,data.g,data.b); // 'corrected' lightness
+ }
+
+ function addHueInfo(data){
+ data.h = getHue(data.r,data.g,data.b);
+ }
+
+ function analyseImages(img1, img2, width, height){
+
+ var hiddenCanvas = document.createElement('canvas');
+
+ var data1 = img1.data;
+ var data2 = img2.data;
+
+ hiddenCanvas.width = width;
+ hiddenCanvas.height = height;
+
+ var context = hiddenCanvas.getContext('2d');
+ var imgd = context.createImageData(width,height);
+ var targetPix = imgd.data;
+
+ var mismatchCount = 0;
+
+ var time = Date.now();
+
+ var skip;
+
+ if( (width > 1200 || height > 1200) && ignoreAntialiasing){
+ skip = 6;
+ }
+
+ loop(height, width, function(verticalPos, horizontalPos){
+
+ if(skip){ // only skip if the image isn't small
+ if(verticalPos % skip === 0 || horizontalPos % skip === 0){
+ return;
+ }
+ }
+
+ var offset = (verticalPos*width + horizontalPos) * 4;
+ var pixel1 = getPixelInfo(data1, offset, 1);
+ var pixel2 = getPixelInfo(data2, offset, 2);
+
+ if(pixel1 === null || pixel2 === null){
+ return;
+ }
+
+ if (ignoreColors){
+
+ addBrightnessInfo(pixel1);
+ addBrightnessInfo(pixel2);
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ return;
+ }
+
+ if( isRGBSimilar(pixel1, pixel2) ){
+ copyPixel(targetPix, offset, pixel2);
+
+ } else if( ignoreAntialiasing && (
+ addBrightnessInfo(pixel1), // jit pixel info augmentation looks a little weird, sorry.
+ addBrightnessInfo(pixel2),
+ isAntialiased(pixel1, data1, 1, verticalPos, horizontalPos, width) ||
+ isAntialiased(pixel2, data2, 2, verticalPos, horizontalPos, width)
+ )){
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+
+ });
+
+ data.misMatchPercentage = (mismatchCount / (height*width) * 100).toFixed(2);
+ data.analysisTime = Date.now() - time;
+
+ data.getImageDataUrl = function(text){
+ var barHeight = 0;
+
+ if(text){
+ barHeight = addLabel(text,context,hiddenCanvas);
+ }
+
+ context.putImageData(imgd, 0, barHeight);
+
+ return hiddenCanvas.toDataURL("image/png");
+ };
+ }
+
+ function addLabel(text, context, hiddenCanvas){
+ var textPadding = 2;
+
+ context.font = '12px sans-serif';
+
+ var textWidth = context.measureText(text).width + textPadding*2;
+ var barHeight = 22;
+
+ if(textWidth > hiddenCanvas.width){
+ hiddenCanvas.width = textWidth;
+ }
+
+ hiddenCanvas.height += barHeight;
+
+ context.fillStyle = "#666";
+ context.fillRect(0,0,hiddenCanvas.width,barHeight -4);
+ context.fillStyle = "#fff";
+ context.fillRect(0,barHeight -4,hiddenCanvas.width, 4);
+
+ context.fillStyle = "#fff";
+ context.textBaseline = "top";
+ context.font = '12px sans-serif';
+ context.fillText(text, textPadding, 1);
+
+ return barHeight;
+ }
+
+ function normalise(img, w, h){
+ var c;
+ var context;
+
+ if(img.height < h || img.width < w){
+ c = document.createElement('canvas');
+ c.width = w;
+ c.height = h;
+ context = c.getContext('2d');
+ context.putImageData(img, 0, 0);
+ return context.getImageData(0, 0, w, h);
+ }
+
+ return img;
+ }
+
+ function compare(one, two){
+
+ function onceWeHaveBoth(){
+ var width;
+ var height;
+ if(images.length === 2){
+ width = images[0].width > images[1].width ? images[0].width : images[1].width;
+ height = images[0].height > images[1].height ? images[0].height : images[1].height;
+
+ if( (images[0].width === images[1].width) && (images[0].height === images[1].height) ){
+ data.isSameDimensions = true;
+ } else {
+ data.isSameDimensions = false;
+ }
+
+ analyseImages( normalise(images[0],width, height), normalise(images[1],width, height), width, height);
+
+ triggerDataUpdate();
+ }
+ }
+
+ images = [];
+ loadImageData(one, onceWeHaveBoth);
+ loadImageData(two, onceWeHaveBoth);
+ }
+
+ function getCompareApi(param){
+
+ var secondFileData,
+ hasMethod = typeof param === 'function';
+
+ if( !hasMethod ){
+ // assume it's file data
+ secondFileData = param;
+ }
+
+ var self = {
+ ignoreNothing: function(){
+
+ tolerance.red = 16;
+ tolerance.green = 16;
+ tolerance.blue = 16;
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreAntialiasing: function(){
+
+ tolerance.red = 32;
+ tolerance.green = 32;
+ tolerance.blue = 32;
+ tolerance.minBrightness = 64;
+ tolerance.maxBrightness = 96;
+
+ ignoreAntialiasing = true;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreColors: function(){
+
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = true;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ onComplete: function( callback ){
+
+ updateCallbackArray.push(callback);
+
+ var wrapper = function(){
+ compare(fileData, secondFileData);
+ };
+
+ wrapper();
+
+ return getCompareApi(wrapper);
+ }
+ };
+
+ return self;
+ }
+
+ return {
+ onComplete: function( callback ){
+ updateCallbackArray.push(callback);
+ loadImageData(fileData, function(imageData, width, height){
+ parseImage(imageData.data, width, height);
+ });
+ },
+ compareTo: function(secondFileData){
+ return getCompareApi(secondFileData);
+ }
+ };
+
+ };
+}(this));
\ No newline at end of file
diff --git a/test/testsuite.js b/test/testsuite.js
deleted file mode 100644
index b486acb..0000000
--- a/test/testsuite.js
+++ /dev/null
@@ -1,36 +0,0 @@
-requirejs.config({
- baseUrl: '/test/unit/'
-});
-
-define(function(require) {
- var testModules = [
- 'Pixi',
- 'Point',
- 'Rectangle',
- 'DisplayObject',
- 'DisplayObjectContainer',
- 'Sprite',
- 'MovieClip',
- 'InteractionManager',
- 'Stage',
- 'utils/Utils',
- 'utils/EventTarget',
- 'utils/Matrix',
- 'utils/Detector',
- 'renderers/WebGLShaders',
- 'renderers/WebGLRenderer',
- 'renderers/WebGLBatch',
- 'renderers/CanvasRenderer',
- 'extras/Strip',
- 'extras/Rope',
- 'textures/BaseTexture',
- 'textures/Texture',
- 'loaders/SpriteSheetLoader',
- 'loaders/AssetLoader'
- ];
-
- // Resolve all testModules and then start the Test Runner.
- require(testModules, function() {
- QUnit.start();
- });
-});
\ No newline at end of file
diff --git a/test/textures/SpriteSheet-Aliens.png b/test/textures/SpriteSheet-Aliens.png
new file mode 100644
index 0000000..210acb1
--- /dev/null
+++ b/test/textures/SpriteSheet-Aliens.png
Binary files differ
diff --git a/test/textures/SpriteSheet-Explosion.png b/test/textures/SpriteSheet-Explosion.png
new file mode 100755
index 0000000..79e1a69
--- /dev/null
+++ b/test/textures/SpriteSheet-Explosion.png
Binary files differ
diff --git a/test/textures/bunny.png b/test/textures/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/textures/bunny.png
Binary files differ
diff --git a/test/unit/DisplayObject.js b/test/unit/DisplayObject.js
deleted file mode 100644
index 5e7e72f..0000000
--- a/test/unit/DisplayObject.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObject');
-});
diff --git a/test/unit/DisplayObjectContainer.js b/test/unit/DisplayObjectContainer.js
deleted file mode 100644
index b323959..0000000
--- a/test/unit/DisplayObjectContainer.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObjectContainer');
-});
diff --git a/test/unit/InteractionManager.js b/test/unit/InteractionManager.js
deleted file mode 100644
index e751f52..0000000
--- a/test/unit/InteractionManager.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('InteractionManager');
-});
diff --git a/test/unit/MovieClip.js b/test/unit/MovieClip.js
deleted file mode 100644
index 37d9446..0000000
--- a/test/unit/MovieClip.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('MovieClip');
-});
diff --git a/test/unit/Pixi.js b/test/unit/Pixi.js
deleted file mode 100644
index 36eee73..0000000
--- a/test/unit/Pixi.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Pixi');
-});
diff --git a/test/unit/Point.js b/test/unit/Point.js
deleted file mode 100644
index 983ff6e..0000000
--- a/test/unit/Point.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Point');
-});
diff --git a/test/unit/Rectangle.js b/test/unit/Rectangle.js
deleted file mode 100644
index 3b439ba..0000000
--- a/test/unit/Rectangle.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Rectangle');
-});
diff --git a/test/unit/Sprite.js b/test/unit/Sprite.js
deleted file mode 100644
index ed4f596..0000000
--- a/test/unit/Sprite.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Sprite');
-});
diff --git a/test/unit/Stage.js b/test/unit/Stage.js
deleted file mode 100644
index 2d70291..0000000
--- a/test/unit/Stage.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Stage');
-});
diff --git a/test/unit/extras/Rope.js b/test/unit/extras/Rope.js
deleted file mode 100644
index 5606f14..0000000
--- a/test/unit/extras/Rope.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Rope');
-});
diff --git a/test/unit/extras/Strip.js b/test/unit/extras/Strip.js
deleted file mode 100644
index 0134d3a..0000000
--- a/test/unit/extras/Strip.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Strip');
-});
diff --git a/test/unit/loaders/AssetLoader.js b/test/unit/loaders/AssetLoader.js
deleted file mode 100644
index 13b8443..0000000
--- a/test/unit/loaders/AssetLoader.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('AssetLoader');
-});
diff --git a/test/unit/loaders/SpriteSheetLoader.js b/test/unit/loaders/SpriteSheetLoader.js
deleted file mode 100644
index 8bf0cb2..0000000
--- a/test/unit/loaders/SpriteSheetLoader.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('SpriteSheetLoader');
-});
diff --git a/test/unit/pixi/InteractionManager.js b/test/unit/pixi/InteractionManager.js
new file mode 100644
index 0000000..ed3001f
--- /dev/null
+++ b/test/unit/pixi/InteractionManager.js
@@ -0,0 +1,10 @@
+describe('pixi/InteractionManager', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var InteractionManager = PIXI.InteractionManager;
+
+ it('Module exists', function () {
+ expect(InteractionManager).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/Pixi.js b/test/unit/pixi/Pixi.js
new file mode 100644
index 0000000..27debc1
--- /dev/null
+++ b/test/unit/pixi/Pixi.js
@@ -0,0 +1,9 @@
+describe('pixi/Pixi', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+
+ it('Module exists', function () {
+ expect(global).to.have.property('PIXI').and.to.be.an('object');
+ });
+});
diff --git a/test/unit/pixi/core/Circle.js b/test/unit/pixi/core/Circle.js
new file mode 100644
index 0000000..93a4456
--- /dev/null
+++ b/test/unit/pixi/core/Circle.js
@@ -0,0 +1,22 @@
+describe('pixi/core/Circle', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Circle = PIXI.Circle;
+
+ it('Module exists', function () {
+ expect(Circle).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Circle();
+
+ expect(obj).to.be.an.instanceof(Circle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', 0);
+ expect(obj).to.have.property('y', 0);
+ expect(obj).to.have.property('radius', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Ellipse.js b/test/unit/pixi/core/Ellipse.js
new file mode 100644
index 0000000..026b56f
--- /dev/null
+++ b/test/unit/pixi/core/Ellipse.js
@@ -0,0 +1,24 @@
+describe('pixi/core/Ellipse', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Ellipse = PIXI.Ellipse;
+
+ it('Module exists', function () {
+ expect(Ellipse).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Ellipse();
+
+ expect(obj).to.be.an.instanceof(Ellipse);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+ expect(obj).to.respondTo('getBounds');
+
+ expect(obj).to.have.property('x', 0);
+ expect(obj).to.have.property('y', 0);
+ expect(obj).to.have.property('width', 0);
+ expect(obj).to.have.property('height', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Matrix.js b/test/unit/pixi/core/Matrix.js
new file mode 100644
index 0000000..b48989e
--- /dev/null
+++ b/test/unit/pixi/core/Matrix.js
@@ -0,0 +1,30 @@
+describe('pixi/core/Matrix', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var mat3 = PIXI.mat3;
+ var mat4 = PIXI.mat4;
+ var Matrix = PIXI.Matrix;
+
+ it('Ensure determineMatrixArrayType works', function () {
+ expect(Matrix).to.be.a('function');
+ });
+
+ it('mat3 exists', function () {
+ expect(mat3).to.be.an('object');
+ });
+
+ it('Confirm new mat3 matrix', function () {
+ var matrix = new mat3.create();
+ pixi_core_Matrix_confirmNewMat3(matrix);
+ });
+
+ it('mat3 exists', function () {
+ expect(mat4).to.be.an('object');
+ });
+
+ it('Confirm new mat4 matrix', function () {
+ var matrix = new mat4.create();
+ pixi_core_Matrix_confirmNewMat4(matrix);
+ });
+});
diff --git a/test/unit/pixi/core/Point.js b/test/unit/pixi/core/Point.js
new file mode 100644
index 0000000..c4d5163
--- /dev/null
+++ b/test/unit/pixi/core/Point.js
@@ -0,0 +1,15 @@
+describe('pixi/core/Point', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Point = PIXI.Point;
+
+ it('Module exists', function () {
+ expect(Point).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Point();
+ pixi_core_Point_confirm(obj, 0, 0);
+ });
+});
diff --git a/.gitignore b/.gitignore
index 12e1b62..0b88317 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
node_modules
.DS_Store
-.project
\ No newline at end of file
+.project
+*.log
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..63e4d7c
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,8 @@
+language: node_js
+node_js:
+ - 0.10
+
+before_script:
+ - npm install -g grunt-cli
+ - export DISPLAY=:99.0
+ - sh -e /etc/init.d/xvfb start
diff --git a/Gruntfile.js b/Gruntfile.js
index b083b49..103938c 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -1,10 +1,12 @@
+'use strict';
+
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-connect');
- grunt.loadNpmTasks('grunt-contrib-qunit');
grunt.loadNpmTasks('grunt-contrib-yuidoc');
+ grunt.loadTasks('tasks');
var root = 'src/pixi/',
debug = 'bin/pixi.dev.js',
@@ -79,7 +81,7 @@
},
files: {
srcBlob: '<%= dirs.src %>/**/*.js',
- testBlob: '<%= dirs.test %>/unit/**/*.js',
+ testBlob: '<%= dirs.test %>/{functional,lib/pixi,unit}/**/*.js',
build: '<%= dirs.build %>/pixi.dev.js',
buildMin: '<%= dirs.build %>/pixi.js'
},
@@ -94,7 +96,12 @@
},
jshint: {
beforeconcat: srcFiles,
- test: ['<%= files.testBlob %>'],
+ test: {
+ src: ['<%= files.testBlob %>'],
+ options: {
+ expr: true
+ }
+ },
options: {
asi: true,
smarttabs: true
@@ -128,12 +135,6 @@
]
},
connect: {
- qunit: {
- options: {
- port: grunt.option('port-test') || 9002,
- base: './'
- }
- },
test: {
options: {
port: grunt.option('port-test') || 9002,
@@ -142,13 +143,6 @@
}
}
},
- qunit: {
- all: {
- options: {
- urls: ['http://localhost:' + (grunt.option('port-test') || 9002) + '/test/index.html']
- }
- }
- },
yuidoc: {
compile: {
name: '<%= pkg.name %>',
@@ -161,6 +155,13 @@
outdir: '<%= dirs.docs %>'
}
}
+ },
+ karma: {
+ unit: {
+ configFile: 'test/karma.conf.js',
+ // browsers: ['Chrome'],
+ singleRun: true
+ }
}
});
@@ -182,9 +183,10 @@
}
)
- grunt.registerTask('default', ['concat', 'uglify', 'distribute']);
grunt.registerTask('build', ['concat', 'uglify', 'distribute']);
- grunt.registerTask('test', ['build', 'connect:qunit', 'qunit']);
+ grunt.registerTask('test', ['concat', 'jshint:test', 'karma']);
grunt.registerTask('docs', ['yuidoc']);
-
-}
\ No newline at end of file
+ grunt.registerTask('default', ['test', 'uglify', 'distribute']);
+ // Travis CI task.
+ grunt.registerTask('travis', ['test']);
+}
diff --git a/README.md b/README.md
index c62ef86..690cfe4 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,8 @@

+[](http://travis-ci.org/drkibitz/pixi.js)
+
#### JavaScript 2D Renderer ####
The aim of this project is to provide a fast lightweight 2D library that works
diff --git a/package.json b/package.json
index b373240..1246a68 100644
--- a/package.json
+++ b/package.json
@@ -18,14 +18,21 @@
"main": "bin/pixi.js",
+ "scripts": {
+ "test": "grunt travis --verbose"
+ },
+
"dependencies": {},
"devDependencies": {
"grunt": "~0.4.x",
- "grunt-contrib-jshint": "0.3.x",
+ "grunt-contrib-jshint": "0.6.x",
"grunt-contrib-uglify": "0.2.x",
- "grunt-contrib-connect": "0.2.x",
- "grunt-contrib-qunit": "0.2.x",
+ "grunt-contrib-connect": "0.3.x",
"grunt-contrib-yuidoc": "0.4.x",
- "grunt-contrib-concat": "0.1.x"
+ "grunt-contrib-concat": "0.3.x",
+ "chai": "~1.7.0",
+ "karma": "0.11.0",
+ "karma-firefox-launcher": "0.1.0",
+ "karma-mocha": "0.1.0"
}
}
diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js
index a7c520e..ee82bbd 100644
--- a/src/pixi/InteractionManager.js
+++ b/src/pixi/InteractionManager.js
@@ -62,7 +62,6 @@
this.onTouchEnd = this.onTouchEnd.bind(this);
this.onTouchMove = this.onTouchMove.bind(this);
-
this.last = 0;
}
diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js
index 1a95d20..eef1059 100644
--- a/src/pixi/core/Ellipse.js
+++ b/src/pixi/core/Ellipse.js
@@ -78,7 +78,7 @@
return (normx + normy < 0.25);
}
-PIXI.Ellipse.getBounds = function()
+PIXI.Ellipse.prototype.getBounds = function()
{
return new PIXI.Rectangle(this.x, this.y, this.width, this.height);
}
diff --git a/tasks/karma.js b/tasks/karma.js
new file mode 100644
index 0000000..c340485
--- /dev/null
+++ b/tasks/karma.js
@@ -0,0 +1,27 @@
+'use strict';
+
+var path = require('path');
+var server = require('karma').server;
+
+module.exports = function (grunt) {
+ grunt.registerMultiTask('karma', 'run karma.', function() {
+ var done = this.async();
+ var options = this.options({
+ background: false
+ });
+ var data = this.data;
+
+ //merge options onto data, with data taking precedence
+ data = grunt.util._.merge(options, data);
+ data.configFile = path.resolve(data.configFile);
+ if (data.configFile) {
+ data.configFile = grunt.template.process(data.configFile);
+ }
+
+ server.start(
+ data,
+ function(code) {
+ done(!code);
+ });
+ });
+};
diff --git a/test/functional/example-1-basics/bunny.png b/test/functional/example-1-basics/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/functional/example-1-basics/bunny.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-30.png b/test/functional/example-1-basics/frame-30.png
new file mode 100644
index 0000000..96e3409
--- /dev/null
+++ b/test/functional/example-1-basics/frame-30.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-60.png b/test/functional/example-1-basics/frame-60.png
new file mode 100644
index 0000000..af3f4ce
--- /dev/null
+++ b/test/functional/example-1-basics/frame-60.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-90.png b/test/functional/example-1-basics/frame-90.png
new file mode 100644
index 0000000..099b823
--- /dev/null
+++ b/test/functional/example-1-basics/frame-90.png
Binary files differ
diff --git a/test/functional/example-1-basics/index.js b/test/functional/example-1-basics/index.js
new file mode 100644
index 0000000..7ae7a98
--- /dev/null
+++ b/test/functional/example-1-basics/index.js
@@ -0,0 +1,133 @@
+describe('Example 1 - Basics', function () {
+ 'use strict';
+
+ var baseUri = '/base/test/functional/example-1-basics';
+ var expect = chai.expect;
+ var currentFrame = 0;
+ var frameEvents = {};
+ var stage;
+ var renderer;
+ var bunny;
+
+ function onFrame(frame, callback) {
+ frameEvents[frame] = callback;
+ }
+
+ function animate() {
+ currentFrame += 1;
+
+ requestAnimFrame( animate );
+
+ // just for fun, lets rotate mr rabbit a little
+ bunny.rotation += 0.1;
+
+ // render the stage
+ renderer.render(stage);
+
+ if (frameEvents[currentFrame])
+ frameEvents[currentFrame](currentFrame);
+ }
+
+ function initScene() {
+ // create an new instance of a pixi stage
+ stage = new PIXI.Stage(0x66FF99);
+
+ // create a renderer instance
+ renderer = PIXI.autoDetectRenderer(400, 300);
+ console.log('Is PIXI.WebGLRenderer: ' + (renderer instanceof PIXI.WebGLRenderer));
+
+ // add the renderer view element to the DOM
+ document.body.appendChild(renderer.view);
+
+ requestAnimFrame( animate );
+
+ // create a texture from an image path
+ var texture = PIXI.Texture.fromImage(baseUri + "/bunny.png");
+ // create a new Sprite using the texture
+ bunny = new PIXI.Sprite(texture);
+
+ // center the sprites anchor point
+ bunny.anchor.x = 0.5;
+ bunny.anchor.y = 0.5;
+
+ // move the sprite t the center of the screen
+ bunny.position.x = 200;
+ bunny.position.y = 150;
+
+ stage.addChild(bunny);
+ }
+
+ it('assets loaded', function (done) {
+ var loader = new PIXI.AssetLoader([
+ baseUri + '/bunny.png',
+ baseUri + '/frame-30.png',
+ baseUri + '/frame-60.png',
+ baseUri + '/frame-90.png'
+ ]);
+ // loader.on('onProgress', function (event) {
+ // console.log(event.content);
+ // });
+ loader.on('onComplete', function (event) {
+ done();
+ initScene();
+ });
+ loader.load();
+ });
+
+ it('frame 30 should match', function (done) {
+ this.timeout(700);
+ onFrame(30, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-30.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 60 should match', function (done) {
+ this.timeout(1200);
+ onFrame(60, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-60.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 90 should match', function (done) {
+ this.timeout(1700);
+ onFrame(90, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-90.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ // it('capture something', function (done) {
+ // this.timeout(2000000);
+ // onFrame(30, function () {
+ // var img = new Image();
+ // img.src = renderer.view.toDataURL('image/png');
+ // document.body.appendChild(img);
+ // });
+ // });
+});
diff --git a/test/index.html b/test/index.html
deleted file mode 100644
index 9cbcac5..0000000
--- a/test/index.html
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
- Pixi.js Test Suite
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/test/karma.conf.js b/test/karma.conf.js
new file mode 100644
index 0000000..c66a696
--- /dev/null
+++ b/test/karma.conf.js
@@ -0,0 +1,82 @@
+module.exports = function(config) {
+ config.set({
+
+ // base path, that will be used to resolve files and exclude
+ basePath : '../',
+
+ frameworks : ['mocha'],
+
+ // list of files / patterns to load in the browser
+ files : [
+ 'node_modules/chai/chai.js',
+ 'bin/pixi.dev.js',
+ 'test/lib/**/*.js',
+ 'test/unit/**/*.js',
+ // 'test/functional/**/*.js',
+ {pattern: 'test/**/*.png', watched: false, included: false, served: true}
+ ],
+
+ // list of files to exclude
+ exclude : [],
+
+ // use dolts reporter, as travis terminal does not support escaping sequences
+ // possible values: 'dots', 'progress', 'junit', 'teamcity'
+ // CLI --reporters progress
+ reporters : ['progress'],
+
+ // web server port
+ // CLI --port 9876
+ port : 9876,
+
+ // cli runner port
+ // CLI --runner-port 9100
+ runnerPort : 9100,
+
+ // enable / disable colors in the output (reporters and logs)
+ // CLI --colors --no-colors
+ colors : true,
+
+ // level of logging
+ // possible values: karma.LOG_DISABLE || karma.LOG_ERROR || karma.LOG_WARN || karma.LOG_INFO || karma.LOG_DEBUG
+ // CLI --log-level debug
+ logLevel : config.LOG_DEBUG,
+
+ // enable / disable watching file and executing tests whenever any file changes
+ // CLI --auto-watch --no-auto-watch
+ autoWatch : false,
+
+ // Start these browsers, currently available:
+ // - Chrome
+ // - ChromeCanary
+ // - Firefox
+ // - Opera
+ // - Safari (only Mac)
+ // - PhantomJS
+ // - IE (only Windows)
+ // CLI --browsers Chrome,Firefox,Safari
+ browsers : ['Firefox'],
+
+ // If browser does not capture in given timeout [ms], kill it
+ // CLI --capture-timeout 5000
+ captureTimeout : 5000,
+
+ // Auto run tests on start (when browsers are captured) and exit
+ // CLI --single-run --no-single-run
+ singleRun : true,
+
+ // report which specs are slower than 500ms
+ // CLI --report-slower-than 500
+ reportSlowerThan : 1000,
+
+ preprocessors : {
+ // '**/client/js/*.js': 'coverage'
+ },
+
+ plugins : [
+ 'karma-mocha',
+ // 'karma-chrome-launcher',
+ 'karma-firefox-launcher',
+ // 'karma-phantomjs-launcher'
+ ]
+ });
+};
diff --git a/test/lib/pixi/core/Matrix.js b/test/lib/pixi/core/Matrix.js
new file mode 100644
index 0000000..d26386b
--- /dev/null
+++ b/test/lib/pixi/core/Matrix.js
@@ -0,0 +1,40 @@
+
+function pixi_core_Matrix_confirmNewMat3(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(1);
+ expect(matrix[5]).to.equal(0);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(1);
+}
+
+function pixi_core_Matrix_confirmNewMat4(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[0]).to.equal(1);
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(0);
+ expect(matrix[5]).to.equal(1);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(0);
+ expect(matrix[9]).to.equal(0);
+ expect(matrix[10]).to.equal(1);
+ expect(matrix[11]).to.equal(0);
+ expect(matrix[12]).to.equal(0);
+ expect(matrix[13]).to.equal(0);
+ expect(matrix[14]).to.equal(0);
+ expect(matrix[15]).to.equal(1);
+}
diff --git a/test/lib/pixi/core/Point.js b/test/lib/pixi/core/Point.js
new file mode 100644
index 0000000..e5df07b
--- /dev/null
+++ b/test/lib/pixi/core/Point.js
@@ -0,0 +1,10 @@
+
+function pixi_core_Point_confirm(obj, x, y) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Point);
+ expect(obj).to.respondTo('clone');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+}
diff --git a/test/lib/pixi/core/Rectangle.js b/test/lib/pixi/core/Rectangle.js
new file mode 100644
index 0000000..23f0d12
--- /dev/null
+++ b/test/lib/pixi/core/Rectangle.js
@@ -0,0 +1,13 @@
+
+function pixi_core_Rectangle_confirm(obj, x, y, width, height) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Rectangle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+ expect(obj).to.have.property('width', width);
+ expect(obj).to.have.property('height', height);
+}
diff --git a/test/lib/pixi/display/DisplayObject.js b/test/lib/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..1388a7f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObject.js
@@ -0,0 +1,43 @@
+
+function pixi_display_DisplayObject_confirmNew(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObject);
+ expect(obj).to.respondTo('setInteractive');
+ expect(obj).to.respondTo('addFilter');
+ expect(obj).to.respondTo('removeFilter');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.property('last', obj);
+ expect(obj).to.have.property('first', obj);
+
+ expect(obj).to.contain.property('position');
+ pixi_core_Point_confirm(obj.position, 0, 0);
+ expect(obj).to.contain.property('scale');
+ pixi_core_Point_confirm(obj.scale, 1, 1);
+ expect(obj).to.contain.property('pivot');
+ pixi_core_Point_confirm(obj.pivot, 0, 0);
+
+ expect(obj).to.have.property('rotation', 0);
+ expect(obj).to.have.property('alpha', 1);
+ expect(obj).to.have.property('visible', true);
+ expect(obj).to.have.property('buttonMode', false);
+ expect(obj).to.have.property('parent', null);
+ expect(obj).to.have.property('worldAlpha', 1);
+
+ expect(obj).to.have.property('hitArea');
+ expect(obj).to.have.property('interactive'); // TODO: Have a better default value
+ expect('mask' in obj).to.be.true; // TODO: Have a better default value
+ expect(obj.mask).to.be.undefined;
+
+ expect(obj).to.have.property('renderable');
+ expect(obj).to.have.property('stage');
+
+ expect(obj).to.have.deep.property('worldTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ expect(obj).to.have.deep.property('localTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.localTransform);
+
+ expect(obj).to.have.deep.property('color.length', 0);
+ expect(obj).to.have.property('dynamic', true);
+}
diff --git a/test/lib/pixi/display/DisplayObjectContainer.js b/test/lib/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..085c59f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,16 @@
+
+function pixi_display_DisplayObjectContainer_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObject_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObjectContainer);
+ expect(obj).to.respondTo('addChild');
+ expect(obj).to.respondTo('addChildAt');
+ expect(obj).to.respondTo('swapChildren');
+ expect(obj).to.respondTo('getChildAt');
+ expect(obj).to.respondTo('removeChild');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('children.length', 0);
+}
diff --git a/test/lib/pixi/display/Sprite.js b/test/lib/pixi/display/Sprite.js
new file mode 100644
index 0000000..cc7a2d6
--- /dev/null
+++ b/test/lib/pixi/display/Sprite.js
@@ -0,0 +1,28 @@
+
+function pixi_display_Sprite_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Sprite);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', true);
+ expect(obj).to.have.property('stage', null);
+
+ expect(obj).to.have.property('anchor');
+ pixi_core_Point_confirm(obj.anchor, 0, 0);
+
+ expect(obj).to.have.property('blendMode', PIXI.blendModes.NORMAL);
+ expect(obj).to.have.property('width', 1); // TODO: is 1 expected
+ expect(obj).to.have.property('height', 1); // TODO: is 1 expected
+
+ // FIXME: Just make this a boolean that is always there
+ expect(!!obj.updateFrame).to.equal(obj.texture.baseTexture.hasLoaded);
+
+ expect(obj).to.have.property('texture');
+ pixi_textures_Texture_confirmNew(obj.texture, done);
+}
diff --git a/test/lib/pixi/extras/Strip.js b/test/lib/pixi/extras/Strip.js
new file mode 100644
index 0000000..8927a8a
--- /dev/null
+++ b/test/lib/pixi/extras/Strip.js
@@ -0,0 +1,12 @@
+
+function pixi_extras_Strip_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Strip);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ // TODO: Test properties
+}
diff --git a/test/lib/pixi/textures/Texture.js b/test/lib/pixi/textures/Texture.js
new file mode 100644
index 0000000..d5867b6
--- /dev/null
+++ b/test/lib/pixi/textures/Texture.js
@@ -0,0 +1,31 @@
+
+function pixi_textures_Texture_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ function confirmFrameDone() {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, obj.baseTexture.width, obj.baseTexture.height);
+
+ expect(obj).to.have.property('width', obj.baseTexture.width);
+ expect(obj).to.have.property('height', obj.baseTexture.height);
+ done();
+ }
+
+ expect(obj).to.be.an.instanceof(PIXI.Texture);
+ pixi_utils_EventTarget_like(obj);
+
+ expect(obj).to.have.property('baseTexture')
+ .and.to.be.an.instanceof(PIXI.BaseTexture);
+
+ expect(obj).to.have.property('scope', obj);
+
+ expect(obj).to.have.property('trim');
+ pixi_core_Point_confirm(obj.trim, 0, 0);
+
+ expect(obj).to.have.property('frame');
+ if (obj.baseTexture.hasLoaded) {
+ confirmFrameDone();
+ } else {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, 1, 1);
+ obj.addEventListener('update', confirmFrameDone);
+ }
+}
diff --git a/test/lib/pixi/utils/EventTarget.js b/test/lib/pixi/utils/EventTarget.js
new file mode 100644
index 0000000..7b1dcfa
--- /dev/null
+++ b/test/lib/pixi/utils/EventTarget.js
@@ -0,0 +1,8 @@
+
+function pixi_utils_EventTarget_like(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.respondTo('addEventListener');
+ expect(obj).to.respondTo('dispatchEvent');
+ expect(obj).to.respondTo('removeEventListener');
+}
diff --git a/test/lib/qunit-1.11.0.css b/test/lib/qunit-1.11.0.css
deleted file mode 100644
index d7fc0c8..0000000
--- a/test/lib/qunit-1.11.0.css
+++ /dev/null
@@ -1,244 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-/** Font Family and Sizes */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
- font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
-}
-
-#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
-#qunit-tests { font-size: smaller; }
-
-
-/** Resets */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter {
- margin: 0;
- padding: 0;
-}
-
-
-/** Header */
-
-#qunit-header {
- padding: 0.5em 0 0.5em 1em;
-
- color: #8699a4;
- background-color: #0d3349;
-
- font-size: 1.5em;
- line-height: 1em;
- font-weight: normal;
-
- border-radius: 5px 5px 0 0;
- -moz-border-radius: 5px 5px 0 0;
- -webkit-border-top-right-radius: 5px;
- -webkit-border-top-left-radius: 5px;
-}
-
-#qunit-header a {
- text-decoration: none;
- color: #c2ccd1;
-}
-
-#qunit-header a:hover,
-#qunit-header a:focus {
- color: #fff;
-}
-
-#qunit-testrunner-toolbar label {
- display: inline-block;
- padding: 0 .5em 0 .1em;
-}
-
-#qunit-banner {
- height: 5px;
-}
-
-#qunit-testrunner-toolbar {
- padding: 0.5em 0 0.5em 2em;
- color: #5E740B;
- background-color: #eee;
- overflow: hidden;
-}
-
-#qunit-userAgent {
- padding: 0.5em 0 0.5em 2.5em;
- background-color: #2b81af;
- color: #fff;
- text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
-}
-
-#qunit-modulefilter-container {
- float: right;
-}
-
-/** Tests: Pass/Fail */
-
-#qunit-tests {
- list-style-position: inside;
-}
-
-#qunit-tests li {
- padding: 0.4em 0.5em 0.4em 2.5em;
- border-bottom: 1px solid #fff;
- list-style-position: inside;
-}
-
-#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running {
- display: none;
-}
-
-#qunit-tests li strong {
- cursor: pointer;
-}
-
-#qunit-tests li a {
- padding: 0.5em;
- color: #c2ccd1;
- text-decoration: none;
-}
-#qunit-tests li a:hover,
-#qunit-tests li a:focus {
- color: #000;
-}
-
-#qunit-tests li .runtime {
- float: right;
- font-size: smaller;
-}
-
-.qunit-assert-list {
- margin-top: 0.5em;
- padding: 0.5em;
-
- background-color: #fff;
-
- border-radius: 5px;
- -moz-border-radius: 5px;
- -webkit-border-radius: 5px;
-}
-
-.qunit-collapsed {
- display: none;
-}
-
-#qunit-tests table {
- border-collapse: collapse;
- margin-top: .2em;
-}
-
-#qunit-tests th {
- text-align: right;
- vertical-align: top;
- padding: 0 .5em 0 0;
-}
-
-#qunit-tests td {
- vertical-align: top;
-}
-
-#qunit-tests pre {
- margin: 0;
- white-space: pre-wrap;
- word-wrap: break-word;
-}
-
-#qunit-tests del {
- background-color: #e0f2be;
- color: #374e0c;
- text-decoration: none;
-}
-
-#qunit-tests ins {
- background-color: #ffcaca;
- color: #500;
- text-decoration: none;
-}
-
-/*** Test Counts */
-
-#qunit-tests b.counts { color: black; }
-#qunit-tests b.passed { color: #5E740B; }
-#qunit-tests b.failed { color: #710909; }
-
-#qunit-tests li li {
- padding: 5px;
- background-color: #fff;
- border-bottom: none;
- list-style-position: inside;
-}
-
-/*** Passing Styles */
-
-#qunit-tests li li.pass {
- color: #3c510c;
- background-color: #fff;
- border-left: 10px solid #C6E746;
-}
-
-#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
-#qunit-tests .pass .test-name { color: #366097; }
-
-#qunit-tests .pass .test-actual,
-#qunit-tests .pass .test-expected { color: #999999; }
-
-#qunit-banner.qunit-pass { background-color: #C6E746; }
-
-/*** Failing Styles */
-
-#qunit-tests li li.fail {
- color: #710909;
- background-color: #fff;
- border-left: 10px solid #EE5757;
- white-space: pre;
-}
-
-#qunit-tests > li:last-child {
- border-radius: 0 0 5px 5px;
- -moz-border-radius: 0 0 5px 5px;
- -webkit-border-bottom-right-radius: 5px;
- -webkit-border-bottom-left-radius: 5px;
-}
-
-#qunit-tests .fail { color: #000000; background-color: #EE5757; }
-#qunit-tests .fail .test-name,
-#qunit-tests .fail .module-name { color: #000000; }
-
-#qunit-tests .fail .test-actual { color: #EE5757; }
-#qunit-tests .fail .test-expected { color: green; }
-
-#qunit-banner.qunit-fail { background-color: #EE5757; }
-
-
-/** Result */
-
-#qunit-testresult {
- padding: 0.5em 0.5em 0.5em 2.5em;
-
- color: #2b81af;
- background-color: #D2E0E6;
-
- border-bottom: 1px solid white;
-}
-#qunit-testresult .module-name {
- font-weight: bold;
-}
-
-/** Fixture */
-
-#qunit-fixture {
- position: absolute;
- top: -10000px;
- left: -10000px;
- width: 1000px;
- height: 1000px;
-}
diff --git a/test/lib/qunit-1.11.0.js b/test/lib/qunit-1.11.0.js
deleted file mode 100644
index 302545f..0000000
--- a/test/lib/qunit-1.11.0.js
+++ /dev/null
@@ -1,2152 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-(function( window ) {
-
-var QUnit,
- assert,
- config,
- onErrorFnPrev,
- testId = 0,
- fileName = (sourceFromStacktrace( 0 ) || "" ).replace(/(:\d+)+\)?/, "").replace(/.+\//, ""),
- toString = Object.prototype.toString,
- hasOwn = Object.prototype.hasOwnProperty,
- // Keep a local reference to Date (GH-283)
- Date = window.Date,
- defined = {
- setTimeout: typeof window.setTimeout !== "undefined",
- sessionStorage: (function() {
- var x = "qunit-test-string";
- try {
- sessionStorage.setItem( x, x );
- sessionStorage.removeItem( x );
- return true;
- } catch( e ) {
- return false;
- }
- }())
- },
- /**
- * Provides a normalized error string, correcting an issue
- * with IE 7 (and prior) where Error.prototype.toString is
- * not properly implemented
- *
- * Based on http://es5.github.com/#x15.11.4.4
- *
- * @param {String|Error} error
- * @return {String} error message
- */
- errorString = function( error ) {
- var name, message,
- errorString = error.toString();
- if ( errorString.substring( 0, 7 ) === "[object" ) {
- name = error.name ? error.name.toString() : "Error";
- message = error.message ? error.message.toString() : "";
- if ( name && message ) {
- return name + ": " + message;
- } else if ( name ) {
- return name;
- } else if ( message ) {
- return message;
- } else {
- return "Error";
- }
- } else {
- return errorString;
- }
- },
- /**
- * Makes a clone of an object using only Array or Object as base,
- * and copies over the own enumerable properties.
- *
- * @param {Object} obj
- * @return {Object} New object with only the own properties (recursively).
- */
- objectValues = function( obj ) {
- // Grunt 0.3.x uses an older version of jshint that still has jshint/jshint#392.
- /*jshint newcap: false */
- var key, val,
- vals = QUnit.is( "array", obj ) ? [] : {};
- for ( key in obj ) {
- if ( hasOwn.call( obj, key ) ) {
- val = obj[key];
- vals[key] = val === Object(val) ? objectValues(val) : val;
- }
- }
- return vals;
- };
-
-function Test( settings ) {
- extend( this, settings );
- this.assertions = [];
- this.testNumber = ++Test.count;
-}
-
-Test.count = 0;
-
-Test.prototype = {
- init: function() {
- var a, b, li,
- tests = id( "qunit-tests" );
-
- if ( tests ) {
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml;
-
- // `a` initialized at top of scope
- a = document.createElement( "a" );
- a.innerHTML = "Rerun";
- a.href = QUnit.url({ testNumber: this.testNumber });
-
- li = document.createElement( "li" );
- li.appendChild( b );
- li.appendChild( a );
- li.className = "running";
- li.id = this.id = "qunit-test-output" + testId++;
-
- tests.appendChild( li );
- }
- },
- setup: function() {
- if ( this.module !== config.previousModule ) {
- if ( config.previousModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.previousModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
- config.previousModule = this.module;
- config.moduleStats = { all: 0, bad: 0 };
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- } else if ( config.autorun ) {
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- }
-
- config.current = this;
-
- this.testEnvironment = extend({
- setup: function() {},
- teardown: function() {}
- }, this.moduleTestEnvironment );
-
- this.started = +new Date();
- runLoggingCallbacks( "testStart", QUnit, {
- name: this.testName,
- module: this.module
- });
-
- // allow utility functions to access the current test environment
- // TODO why??
- QUnit.current_testEnvironment = this.testEnvironment;
-
- if ( !config.pollution ) {
- saveGlobal();
- }
- if ( config.notrycatch ) {
- this.testEnvironment.setup.call( this.testEnvironment );
- return;
- }
- try {
- this.testEnvironment.setup.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Setup failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- },
- run: function() {
- config.current = this;
-
- var running = id( "qunit-testresult" );
-
- if ( running ) {
- running.innerHTML = "Running:
" + this.nameHtml;
- }
-
- if ( this.async ) {
- QUnit.stop();
- }
-
- this.callbackStarted = +new Date();
-
- if ( config.notrycatch ) {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- return;
- }
-
- try {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- } catch( e ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
-
- QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + " " + this.stack + ": " + ( e.message || e ), extractStacktrace( e, 0 ) );
- // else next test will carry the responsibility
- saveGlobal();
-
- // Restart the tests if they're blocking
- if ( config.blocking ) {
- QUnit.start();
- }
- }
- },
- teardown: function() {
- config.current = this;
- if ( config.notrycatch ) {
- if ( typeof this.callbackRuntime === "undefined" ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
- }
- this.testEnvironment.teardown.call( this.testEnvironment );
- return;
- } else {
- try {
- this.testEnvironment.teardown.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Teardown failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- }
- checkPollution();
- },
- finish: function() {
- config.current = this;
- if ( config.requireExpects && this.expected === null ) {
- QUnit.pushFailure( "Expected number of assertions to be defined, but expect() was not called.", this.stack );
- } else if ( this.expected !== null && this.expected !== this.assertions.length ) {
- QUnit.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack );
- } else if ( this.expected === null && !this.assertions.length ) {
- QUnit.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions.", this.stack );
- }
-
- var i, assertion, a, b, time, li, ol,
- test = this,
- good = 0,
- bad = 0,
- tests = id( "qunit-tests" );
-
- this.runtime = +new Date() - this.started;
- config.stats.all += this.assertions.length;
- config.moduleStats.all += this.assertions.length;
-
- if ( tests ) {
- ol = document.createElement( "ol" );
- ol.className = "qunit-assert-list";
-
- for ( i = 0; i < this.assertions.length; i++ ) {
- assertion = this.assertions[i];
-
- li = document.createElement( "li" );
- li.className = assertion.result ? "pass" : "fail";
- li.innerHTML = assertion.message || ( assertion.result ? "okay" : "failed" );
- ol.appendChild( li );
-
- if ( assertion.result ) {
- good++;
- } else {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
-
- // store result when possible
- if ( QUnit.config.reorder && defined.sessionStorage ) {
- if ( bad ) {
- sessionStorage.setItem( "qunit-test-" + this.module + "-" + this.testName, bad );
- } else {
- sessionStorage.removeItem( "qunit-test-" + this.module + "-" + this.testName );
- }
- }
-
- if ( bad === 0 ) {
- addClass( ol, "qunit-collapsed" );
- }
-
- // `b` initialized at top of scope
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml + " (" + bad + ", " + good + ", " + this.assertions.length + ")";
-
- addEvent(b, "click", function() {
- var next = b.parentNode.lastChild,
- collapsed = hasClass( next, "qunit-collapsed" );
- ( collapsed ? removeClass : addClass )( next, "qunit-collapsed" );
- });
-
- addEvent(b, "dblclick", function( e ) {
- var target = e && e.target ? e.target : window.event.srcElement;
- if ( target.nodeName.toLowerCase() === "span" || target.nodeName.toLowerCase() === "b" ) {
- target = target.parentNode;
- }
- if ( window.location && target.nodeName.toLowerCase() === "strong" ) {
- window.location = QUnit.url({ testNumber: test.testNumber });
- }
- });
-
- // `time` initialized at top of scope
- time = document.createElement( "span" );
- time.className = "runtime";
- time.innerHTML = this.runtime + " ms";
-
- // `li` initialized at top of scope
- li = id( this.id );
- li.className = bad ? "fail" : "pass";
- li.removeChild( li.firstChild );
- a = li.firstChild;
- li.appendChild( b );
- li.appendChild( a );
- li.appendChild( time );
- li.appendChild( ol );
-
- } else {
- for ( i = 0; i < this.assertions.length; i++ ) {
- if ( !this.assertions[i].result ) {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
- }
-
- runLoggingCallbacks( "testDone", QUnit, {
- name: this.testName,
- module: this.module,
- failed: bad,
- passed: this.assertions.length - bad,
- total: this.assertions.length,
- duration: this.runtime
- });
-
- QUnit.reset();
-
- config.current = undefined;
- },
-
- queue: function() {
- var bad,
- test = this;
-
- synchronize(function() {
- test.init();
- });
- function run() {
- // each of these can by async
- synchronize(function() {
- test.setup();
- });
- synchronize(function() {
- test.run();
- });
- synchronize(function() {
- test.teardown();
- });
- synchronize(function() {
- test.finish();
- });
- }
-
- // `bad` initialized at top of scope
- // defer when previous test run passed, if storage is available
- bad = QUnit.config.reorder && defined.sessionStorage &&
- +sessionStorage.getItem( "qunit-test-" + this.module + "-" + this.testName );
-
- if ( bad ) {
- run();
- } else {
- synchronize( run, true );
- }
- }
-};
-
-// Root QUnit object.
-// `QUnit` initialized at top of scope
-QUnit = {
-
- // call on start of module test to prepend name to all tests
- module: function( name, testEnvironment ) {
- config.currentModule = name;
- config.currentModuleTestEnvironment = testEnvironment;
- config.modules[name] = true;
- },
-
- asyncTest: function( testName, expected, callback ) {
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- QUnit.test( testName, expected, callback, true );
- },
-
- test: function( testName, expected, callback, async ) {
- var test,
- nameHtml = "" + escapeText( testName ) + "";
-
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- if ( config.currentModule ) {
- nameHtml = "" + escapeText( config.currentModule ) + ": " + nameHtml;
- }
-
- test = new Test({
- nameHtml: nameHtml,
- testName: testName,
- expected: expected,
- async: async,
- callback: callback,
- module: config.currentModule,
- moduleTestEnvironment: config.currentModuleTestEnvironment,
- stack: sourceFromStacktrace( 2 )
- });
-
- if ( !validTest( test ) ) {
- return;
- }
-
- test.queue();
- },
-
- // Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through.
- expect: function( asserts ) {
- if (arguments.length === 1) {
- config.current.expected = asserts;
- } else {
- return config.current.expected;
- }
- },
-
- start: function( count ) {
- // QUnit hasn't been initialized yet.
- // Note: RequireJS (et al) may delay onLoad
- if ( config.semaphore === undefined ) {
- QUnit.begin(function() {
- // This is triggered at the top of QUnit.load, push start() to the event loop, to allow QUnit.load to finish first
- setTimeout(function() {
- QUnit.start( count );
- });
- });
- return;
- }
-
- config.semaphore -= count || 1;
- // don't start until equal number of stop-calls
- if ( config.semaphore > 0 ) {
- return;
- }
- // ignore if start is called more often then stop
- if ( config.semaphore < 0 ) {
- config.semaphore = 0;
- QUnit.pushFailure( "Called start() while already started (QUnit.config.semaphore was 0 already)", null, sourceFromStacktrace(2) );
- return;
- }
- // A slight delay, to avoid any current callbacks
- if ( defined.setTimeout ) {
- window.setTimeout(function() {
- if ( config.semaphore > 0 ) {
- return;
- }
- if ( config.timeout ) {
- clearTimeout( config.timeout );
- }
-
- config.blocking = false;
- process( true );
- }, 13);
- } else {
- config.blocking = false;
- process( true );
- }
- },
-
- stop: function( count ) {
- config.semaphore += count || 1;
- config.blocking = true;
-
- if ( config.testTimeout && defined.setTimeout ) {
- clearTimeout( config.timeout );
- config.timeout = window.setTimeout(function() {
- QUnit.ok( false, "Test timed out" );
- config.semaphore = 1;
- QUnit.start();
- }, config.testTimeout );
- }
- }
-};
-
-// `assert` initialized at top of scope
-// Asssert helpers
-// All of these must either call QUnit.push() or manually do:
-// - runLoggingCallbacks( "log", .. );
-// - config.current.assertions.push({ .. });
-// We attach it to the QUnit object *after* we expose the public API,
-// otherwise `assert` will become a global variable in browsers (#341).
-assert = {
- /**
- * Asserts rough true-ish result.
- * @name ok
- * @function
- * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" );
- */
- ok: function( result, msg ) {
- if ( !config.current ) {
- throw new Error( "ok() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
- result = !!result;
-
- var source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: msg
- };
-
- msg = escapeText( msg || (result ? "okay" : "failed" ) );
- msg = "" + msg + "";
-
- if ( !result ) {
- source = sourceFromStacktrace( 2 );
- if ( source ) {
- details.source = source;
- msg += "Source: | " + escapeText( source ) + " |
---|
";
- }
- }
- runLoggingCallbacks( "log", QUnit, details );
- config.current.assertions.push({
- result: result,
- message: msg
- });
- },
-
- /**
- * Assert that the first two arguments are equal, with an optional message.
- * Prints out both actual and expected values.
- * @name equal
- * @function
- * @example equal( format( "Received {0} bytes.", 2), "Received 2 bytes.", "format() replaces {0} with next argument" );
- */
- equal: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected == actual, actual, expected, message );
- },
-
- /**
- * @name notEqual
- * @function
- */
- notEqual: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected != actual, actual, expected, message );
- },
-
- /**
- * @name propEqual
- * @function
- */
- propEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notPropEqual
- * @function
- */
- notPropEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name deepEqual
- * @function
- */
- deepEqual: function( actual, expected, message ) {
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notDeepEqual
- * @function
- */
- notDeepEqual: function( actual, expected, message ) {
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name strictEqual
- * @function
- */
- strictEqual: function( actual, expected, message ) {
- QUnit.push( expected === actual, actual, expected, message );
- },
-
- /**
- * @name notStrictEqual
- * @function
- */
- notStrictEqual: function( actual, expected, message ) {
- QUnit.push( expected !== actual, actual, expected, message );
- },
-
- "throws": function( block, expected, message ) {
- var actual,
- expectedOutput = expected,
- ok = false;
-
- // 'expected' is optional
- if ( typeof expected === "string" ) {
- message = expected;
- expected = null;
- }
-
- config.current.ignoreGlobalErrors = true;
- try {
- block.call( config.current.testEnvironment );
- } catch (e) {
- actual = e;
- }
- config.current.ignoreGlobalErrors = false;
-
- if ( actual ) {
- // we don't want to validate thrown error
- if ( !expected ) {
- ok = true;
- expectedOutput = null;
- // expected is a regexp
- } else if ( QUnit.objectType( expected ) === "regexp" ) {
- ok = expected.test( errorString( actual ) );
- // expected is a constructor
- } else if ( actual instanceof expected ) {
- ok = true;
- // expected is a validation function which returns true is validation passed
- } else if ( expected.call( {}, actual ) === true ) {
- expectedOutput = null;
- ok = true;
- }
-
- QUnit.push( ok, actual, expectedOutput, message );
- } else {
- QUnit.pushFailure( message, null, 'No exception was thrown.' );
- }
- }
-};
-
-/**
- * @deprecate since 1.8.0
- * Kept assertion helpers in root for backwards compatibility.
- */
-extend( QUnit, assert );
-
-/**
- * @deprecated since 1.9.0
- * Kept root "raises()" for backwards compatibility.
- * (Note that we don't introduce assert.raises).
- */
-QUnit.raises = assert[ "throws" ];
-
-/**
- * @deprecated since 1.0.0, replaced with error pushes since 1.3.0
- * Kept to avoid TypeErrors for undefined methods.
- */
-QUnit.equals = function() {
- QUnit.push( false, false, false, "QUnit.equals has been deprecated since 2009 (e88049a0), use QUnit.equal instead" );
-};
-QUnit.same = function() {
- QUnit.push( false, false, false, "QUnit.same has been deprecated since 2009 (e88049a0), use QUnit.deepEqual instead" );
-};
-
-// We want access to the constructor's prototype
-(function() {
- function F() {}
- F.prototype = QUnit;
- QUnit = new F();
- // Make F QUnit's constructor so that we can add to the prototype later
- QUnit.constructor = F;
-}());
-
-/**
- * Config object: Maintain internal state
- * Later exposed as QUnit.config
- * `config` initialized at top of scope
- */
-config = {
- // The queue of tests to run
- queue: [],
-
- // block until document ready
- blocking: true,
-
- // when enabled, show only failing tests
- // gets persisted through sessionStorage and can be changed in UI via checkbox
- hidepassed: false,
-
- // by default, run previously failed tests first
- // very useful in combination with "Hide passed tests" checked
- reorder: true,
-
- // by default, modify document.title when suite is done
- altertitle: true,
-
- // when enabled, all tests must call expect()
- requireExpects: false,
-
- // add checkboxes that are persisted in the query-string
- // when enabled, the id is set to `true` as a `QUnit.config` property
- urlConfig: [
- {
- id: "noglobals",
- label: "Check for Globals",
- tooltip: "Enabling this will test if any test introduces new properties on the `window` object. Stored as query-strings."
- },
- {
- id: "notrycatch",
- label: "No try-catch",
- tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging exceptions in IE reasonable. Stored as query-strings."
- }
- ],
-
- // Set of all modules.
- modules: {},
-
- // logging callback queues
- begin: [],
- done: [],
- log: [],
- testStart: [],
- testDone: [],
- moduleStart: [],
- moduleDone: []
-};
-
-// Export global variables, unless an 'exports' object exists,
-// in that case we assume we're in CommonJS (dealt with on the bottom of the script)
-if ( typeof exports === "undefined" ) {
- extend( window, QUnit );
-
- // Expose QUnit object
- window.QUnit = QUnit;
-}
-
-// Initialize more QUnit.config and QUnit.urlParams
-(function() {
- var i,
- location = window.location || { search: "", protocol: "file:" },
- params = location.search.slice( 1 ).split( "&" ),
- length = params.length,
- urlParams = {},
- current;
-
- if ( params[ 0 ] ) {
- for ( i = 0; i < length; i++ ) {
- current = params[ i ].split( "=" );
- current[ 0 ] = decodeURIComponent( current[ 0 ] );
- // allow just a key to turn on a flag, e.g., test.html?noglobals
- current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true;
- urlParams[ current[ 0 ] ] = current[ 1 ];
- }
- }
-
- QUnit.urlParams = urlParams;
-
- // String search anywhere in moduleName+testName
- config.filter = urlParams.filter;
-
- // Exact match of the module name
- config.module = urlParams.module;
-
- config.testNumber = parseInt( urlParams.testNumber, 10 ) || null;
-
- // Figure out if we're running the tests from a server or not
- QUnit.isLocal = location.protocol === "file:";
-}());
-
-// Extend QUnit object,
-// these after set here because they should not be exposed as global functions
-extend( QUnit, {
- assert: assert,
-
- config: config,
-
- // Initialize the configuration options
- init: function() {
- extend( config, {
- stats: { all: 0, bad: 0 },
- moduleStats: { all: 0, bad: 0 },
- started: +new Date(),
- updateRate: 1000,
- blocking: false,
- autostart: true,
- autorun: false,
- filter: "",
- queue: [],
- semaphore: 1
- });
-
- var tests, banner, result,
- qunit = id( "qunit" );
-
- if ( qunit ) {
- qunit.innerHTML =
- "" +
- "" +
- "" +
- "" +
- "
";
- }
-
- tests = id( "qunit-tests" );
- banner = id( "qunit-banner" );
- result = id( "qunit-testresult" );
-
- if ( tests ) {
- tests.innerHTML = "";
- }
-
- if ( banner ) {
- banner.className = "";
- }
-
- if ( result ) {
- result.parentNode.removeChild( result );
- }
-
- if ( tests ) {
- result = document.createElement( "p" );
- result.id = "qunit-testresult";
- result.className = "result";
- tests.parentNode.insertBefore( result, tests );
- result.innerHTML = "Running...
";
- }
- },
-
- // Resets the test setup. Useful for tests that modify the DOM.
- reset: function() {
- var fixture = id( "qunit-fixture" );
- if ( fixture ) {
- fixture.innerHTML = config.fixture;
- }
- },
-
- // Trigger an event on an element.
- // @example triggerEvent( document.body, "click" );
- triggerEvent: function( elem, type, event ) {
- if ( document.createEvent ) {
- event = document.createEvent( "MouseEvents" );
- event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView,
- 0, 0, 0, 0, 0, false, false, false, false, 0, null);
-
- elem.dispatchEvent( event );
- } else if ( elem.fireEvent ) {
- elem.fireEvent( "on" + type );
- }
- },
-
- // Safe object type checking
- is: function( type, obj ) {
- return QUnit.objectType( obj ) === type;
- },
-
- objectType: function( obj ) {
- if ( typeof obj === "undefined" ) {
- return "undefined";
- // consider: typeof null === object
- }
- if ( obj === null ) {
- return "null";
- }
-
- var match = toString.call( obj ).match(/^\[object\s(.*)\]$/),
- type = match && match[1] || "";
-
- switch ( type ) {
- case "Number":
- if ( isNaN(obj) ) {
- return "nan";
- }
- return "number";
- case "String":
- case "Boolean":
- case "Array":
- case "Date":
- case "RegExp":
- case "Function":
- return type.toLowerCase();
- }
- if ( typeof obj === "object" ) {
- return "object";
- }
- return undefined;
- },
-
- push: function( result, actual, expected, message ) {
- if ( !config.current ) {
- throw new Error( "assertion outside test context, was " + sourceFromStacktrace() );
- }
-
- var output, source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: message,
- actual: actual,
- expected: expected
- };
-
- message = escapeText( message ) || ( result ? "okay" : "failed" );
- message = "" + message + "";
- output = message;
-
- if ( !result ) {
- expected = escapeText( QUnit.jsDump.parse(expected) );
- actual = escapeText( QUnit.jsDump.parse(actual) );
- output += "Expected: | " + expected + " |
";
-
- if ( actual !== expected ) {
- output += "Result: | " + actual + " |
";
- output += "Diff: | " + QUnit.diff( expected, actual ) + " |
";
- }
-
- source = sourceFromStacktrace();
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
- }
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: !!result,
- message: output
- });
- },
-
- pushFailure: function( message, source, actual ) {
- if ( !config.current ) {
- throw new Error( "pushFailure() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
-
- var output,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: false,
- message: message
- };
-
- message = escapeText( message ) || "error";
- message = "" + message + "";
- output = message;
-
- output += "";
-
- if ( actual ) {
- output += "Result: | " + escapeText( actual ) + " |
";
- }
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: false,
- message: output
- });
- },
-
- url: function( params ) {
- params = extend( extend( {}, QUnit.urlParams ), params );
- var key,
- querystring = "?";
-
- for ( key in params ) {
- if ( !hasOwn.call( params, key ) ) {
- continue;
- }
- querystring += encodeURIComponent( key ) + "=" +
- encodeURIComponent( params[ key ] ) + "&";
- }
- return window.location.protocol + "//" + window.location.host +
- window.location.pathname + querystring.slice( 0, -1 );
- },
-
- extend: extend,
- id: id,
- addEvent: addEvent
- // load, equiv, jsDump, diff: Attached later
-});
-
-/**
- * @deprecated: Created for backwards compatibility with test runner that set the hook function
- * into QUnit.{hook}, instead of invoking it and passing the hook function.
- * QUnit.constructor is set to the empty F() above so that we can add to it's prototype here.
- * Doing this allows us to tell if the following methods have been overwritten on the actual
- * QUnit object.
- */
-extend( QUnit.constructor.prototype, {
-
- // Logging callbacks; all receive a single argument with the listed properties
- // run test/logs.html for any related changes
- begin: registerLoggingCallback( "begin" ),
-
- // done: { failed, passed, total, runtime }
- done: registerLoggingCallback( "done" ),
-
- // log: { result, actual, expected, message }
- log: registerLoggingCallback( "log" ),
-
- // testStart: { name }
- testStart: registerLoggingCallback( "testStart" ),
-
- // testDone: { name, failed, passed, total, duration }
- testDone: registerLoggingCallback( "testDone" ),
-
- // moduleStart: { name }
- moduleStart: registerLoggingCallback( "moduleStart" ),
-
- // moduleDone: { name, failed, passed, total }
- moduleDone: registerLoggingCallback( "moduleDone" )
-});
-
-if ( typeof document === "undefined" || document.readyState === "complete" ) {
- config.autorun = true;
-}
-
-QUnit.load = function() {
- runLoggingCallbacks( "begin", QUnit, {} );
-
- // Initialize the config, saving the execution queue
- var banner, filter, i, label, len, main, ol, toolbar, userAgent, val,
- urlConfigCheckboxesContainer, urlConfigCheckboxes, moduleFilter,
- numModules = 0,
- moduleFilterHtml = "",
- urlConfigHtml = "",
- oldconfig = extend( {}, config );
-
- QUnit.init();
- extend(config, oldconfig);
-
- config.blocking = false;
-
- len = config.urlConfig.length;
-
- for ( i = 0; i < len; i++ ) {
- val = config.urlConfig[i];
- if ( typeof val === "string" ) {
- val = {
- id: val,
- label: val,
- tooltip: "[no tooltip available]"
- };
- }
- config[ val.id ] = QUnit.urlParams[ val.id ];
- urlConfigHtml += "";
- }
-
- moduleFilterHtml += "";
-
- // `userAgent` initialized at top of scope
- userAgent = id( "qunit-userAgent" );
- if ( userAgent ) {
- userAgent.innerHTML = navigator.userAgent;
- }
-
- // `banner` initialized at top of scope
- banner = id( "qunit-header" );
- if ( banner ) {
- banner.innerHTML = "" + banner.innerHTML + " ";
- }
-
- // `toolbar` initialized at top of scope
- toolbar = id( "qunit-testrunner-toolbar" );
- if ( toolbar ) {
- // `filter` initialized at top of scope
- filter = document.createElement( "input" );
- filter.type = "checkbox";
- filter.id = "qunit-filter-pass";
-
- addEvent( filter, "click", function() {
- var tmp,
- ol = document.getElementById( "qunit-tests" );
-
- if ( filter.checked ) {
- ol.className = ol.className + " hidepass";
- } else {
- tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " ";
- ol.className = tmp.replace( / hidepass /, " " );
- }
- if ( defined.sessionStorage ) {
- if (filter.checked) {
- sessionStorage.setItem( "qunit-filter-passed-tests", "true" );
- } else {
- sessionStorage.removeItem( "qunit-filter-passed-tests" );
- }
- }
- });
-
- if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem( "qunit-filter-passed-tests" ) ) {
- filter.checked = true;
- // `ol` initialized at top of scope
- ol = document.getElementById( "qunit-tests" );
- ol.className = ol.className + " hidepass";
- }
- toolbar.appendChild( filter );
-
- // `label` initialized at top of scope
- label = document.createElement( "label" );
- label.setAttribute( "for", "qunit-filter-pass" );
- label.setAttribute( "title", "Only show tests and assertons that fail. Stored in sessionStorage." );
- label.innerHTML = "Hide passed tests";
- toolbar.appendChild( label );
-
- urlConfigCheckboxesContainer = document.createElement("span");
- urlConfigCheckboxesContainer.innerHTML = urlConfigHtml;
- urlConfigCheckboxes = urlConfigCheckboxesContainer.getElementsByTagName("input");
- // For oldIE support:
- // * Add handlers to the individual elements instead of the container
- // * Use "click" instead of "change"
- // * Fallback from event.target to event.srcElement
- addEvents( urlConfigCheckboxes, "click", function( event ) {
- var params = {},
- target = event.target || event.srcElement;
- params[ target.name ] = target.checked ? true : undefined;
- window.location = QUnit.url( params );
- });
- toolbar.appendChild( urlConfigCheckboxesContainer );
-
- if (numModules > 1) {
- moduleFilter = document.createElement( 'span' );
- moduleFilter.setAttribute( 'id', 'qunit-modulefilter-container' );
- moduleFilter.innerHTML = moduleFilterHtml;
- addEvent( moduleFilter.lastChild, "change", function() {
- var selectBox = moduleFilter.getElementsByTagName("select")[0],
- selectedModule = decodeURIComponent(selectBox.options[selectBox.selectedIndex].value);
-
- window.location = QUnit.url( { module: ( selectedModule === "" ) ? undefined : selectedModule } );
- });
- toolbar.appendChild(moduleFilter);
- }
- }
-
- // `main` initialized at top of scope
- main = id( "qunit-fixture" );
- if ( main ) {
- config.fixture = main.innerHTML;
- }
-
- if ( config.autostart ) {
- QUnit.start();
- }
-};
-
-addEvent( window, "load", QUnit.load );
-
-// `onErrorFnPrev` initialized at top of scope
-// Preserve other handlers
-onErrorFnPrev = window.onerror;
-
-// Cover uncaught exceptions
-// Returning true will surpress the default browser handler,
-// returning false will let it run.
-window.onerror = function ( error, filePath, linerNr ) {
- var ret = false;
- if ( onErrorFnPrev ) {
- ret = onErrorFnPrev( error, filePath, linerNr );
- }
-
- // Treat return value as window.onerror itself does,
- // Only do our handling if not surpressed.
- if ( ret !== true ) {
- if ( QUnit.config.current ) {
- if ( QUnit.config.current.ignoreGlobalErrors ) {
- return true;
- }
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- } else {
- QUnit.test( "global failure", extend( function() {
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- }, { validTest: validTest } ) );
- }
- return false;
- }
-
- return ret;
-};
-
-function done() {
- config.autorun = true;
-
- // Log the last module results
- if ( config.currentModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.currentModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
-
- var i, key,
- banner = id( "qunit-banner" ),
- tests = id( "qunit-tests" ),
- runtime = +new Date() - config.started,
- passed = config.stats.all - config.stats.bad,
- html = [
- "Tests completed in ",
- runtime,
- " milliseconds.
",
- "",
- passed,
- " assertions of ",
- config.stats.all,
- " passed, ",
- config.stats.bad,
- " failed."
- ].join( "" );
-
- if ( banner ) {
- banner.className = ( config.stats.bad ? "qunit-fail" : "qunit-pass" );
- }
-
- if ( tests ) {
- id( "qunit-testresult" ).innerHTML = html;
- }
-
- if ( config.altertitle && typeof document !== "undefined" && document.title ) {
- // show ✖ for good, ✔ for bad suite result in title
- // use escape sequences in case file gets loaded with non-utf-8-charset
- document.title = [
- ( config.stats.bad ? "\u2716" : "\u2714" ),
- document.title.replace( /^[\u2714\u2716] /i, "" )
- ].join( " " );
- }
-
- // clear own sessionStorage items if all tests passed
- if ( config.reorder && defined.sessionStorage && config.stats.bad === 0 ) {
- // `key` & `i` initialized at top of scope
- for ( i = 0; i < sessionStorage.length; i++ ) {
- key = sessionStorage.key( i++ );
- if ( key.indexOf( "qunit-test-" ) === 0 ) {
- sessionStorage.removeItem( key );
- }
- }
- }
-
- // scroll back to top to show results
- if ( window.scrollTo ) {
- window.scrollTo(0, 0);
- }
-
- runLoggingCallbacks( "done", QUnit, {
- failed: config.stats.bad,
- passed: passed,
- total: config.stats.all,
- runtime: runtime
- });
-}
-
-/** @return Boolean: true if this test should be ran */
-function validTest( test ) {
- var include,
- filter = config.filter && config.filter.toLowerCase(),
- module = config.module && config.module.toLowerCase(),
- fullName = (test.module + ": " + test.testName).toLowerCase();
-
- // Internally-generated tests are always valid
- if ( test.callback && test.callback.validTest === validTest ) {
- delete test.callback.validTest;
- return true;
- }
-
- if ( config.testNumber ) {
- return test.testNumber === config.testNumber;
- }
-
- if ( module && ( !test.module || test.module.toLowerCase() !== module ) ) {
- return false;
- }
-
- if ( !filter ) {
- return true;
- }
-
- include = filter.charAt( 0 ) !== "!";
- if ( !include ) {
- filter = filter.slice( 1 );
- }
-
- // If the filter matches, we need to honour include
- if ( fullName.indexOf( filter ) !== -1 ) {
- return include;
- }
-
- // Otherwise, do the opposite
- return !include;
-}
-
-// so far supports only Firefox, Chrome and Opera (buggy), Safari (for real exceptions)
-// Later Safari and IE10 are supposed to support error.stack as well
-// See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack
-function extractStacktrace( e, offset ) {
- offset = offset === undefined ? 3 : offset;
-
- var stack, include, i;
-
- if ( e.stacktrace ) {
- // Opera
- return e.stacktrace.split( "\n" )[ offset + 3 ];
- } else if ( e.stack ) {
- // Firefox, Chrome
- stack = e.stack.split( "\n" );
- if (/^error$/i.test( stack[0] ) ) {
- stack.shift();
- }
- if ( fileName ) {
- include = [];
- for ( i = offset; i < stack.length; i++ ) {
- if ( stack[ i ].indexOf( fileName ) !== -1 ) {
- break;
- }
- include.push( stack[ i ] );
- }
- if ( include.length ) {
- return include.join( "\n" );
- }
- }
- return stack[ offset ];
- } else if ( e.sourceURL ) {
- // Safari, PhantomJS
- // hopefully one day Safari provides actual stacktraces
- // exclude useless self-reference for generated Error objects
- if ( /qunit.js$/.test( e.sourceURL ) ) {
- return;
- }
- // for actual exceptions, this is useful
- return e.sourceURL + ":" + e.line;
- }
-}
-function sourceFromStacktrace( offset ) {
- try {
- throw new Error();
- } catch ( e ) {
- return extractStacktrace( e, offset );
- }
-}
-
-/**
- * Escape text for attribute or text content.
- */
-function escapeText( s ) {
- if ( !s ) {
- return "";
- }
- s = s + "";
- // Both single quotes and double quotes (for attributes)
- return s.replace( /['"<>&]/g, function( s ) {
- switch( s ) {
- case '\'':
- return ''';
- case '"':
- return '"';
- case '<':
- return '<';
- case '>':
- return '>';
- case '&':
- return '&';
- }
- });
-}
-
-function synchronize( callback, last ) {
- config.queue.push( callback );
-
- if ( config.autorun && !config.blocking ) {
- process( last );
- }
-}
-
-function process( last ) {
- function next() {
- process( last );
- }
- var start = new Date().getTime();
- config.depth = config.depth ? config.depth + 1 : 1;
-
- while ( config.queue.length && !config.blocking ) {
- if ( !defined.setTimeout || config.updateRate <= 0 || ( ( new Date().getTime() - start ) < config.updateRate ) ) {
- config.queue.shift()();
- } else {
- window.setTimeout( next, 13 );
- break;
- }
- }
- config.depth--;
- if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) {
- done();
- }
-}
-
-function saveGlobal() {
- config.pollution = [];
-
- if ( config.noglobals ) {
- for ( var key in window ) {
- // in Opera sometimes DOM element ids show up here, ignore them
- if ( !hasOwn.call( window, key ) || /^qunit-test-output/.test( key ) ) {
- continue;
- }
- config.pollution.push( key );
- }
- }
-}
-
-function checkPollution() {
- var newGlobals,
- deletedGlobals,
- old = config.pollution;
-
- saveGlobal();
-
- newGlobals = diff( config.pollution, old );
- if ( newGlobals.length > 0 ) {
- QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join(", ") );
- }
-
- deletedGlobals = diff( old, config.pollution );
- if ( deletedGlobals.length > 0 ) {
- QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join(", ") );
- }
-}
-
-// returns a new Array with the elements that are in a but not in b
-function diff( a, b ) {
- var i, j,
- result = a.slice();
-
- for ( i = 0; i < result.length; i++ ) {
- for ( j = 0; j < b.length; j++ ) {
- if ( result[i] === b[j] ) {
- result.splice( i, 1 );
- i--;
- break;
- }
- }
- }
- return result;
-}
-
-function extend( a, b ) {
- for ( var prop in b ) {
- if ( b[ prop ] === undefined ) {
- delete a[ prop ];
-
- // Avoid "Member not found" error in IE8 caused by setting window.constructor
- } else if ( prop !== "constructor" || a !== window ) {
- a[ prop ] = b[ prop ];
- }
- }
-
- return a;
-}
-
-/**
- * @param {HTMLElement} elem
- * @param {string} type
- * @param {Function} fn
- */
-function addEvent( elem, type, fn ) {
- // Standards-based browsers
- if ( elem.addEventListener ) {
- elem.addEventListener( type, fn, false );
- // IE
- } else {
- elem.attachEvent( "on" + type, fn );
- }
-}
-
-/**
- * @param {Array|NodeList} elems
- * @param {string} type
- * @param {Function} fn
- */
-function addEvents( elems, type, fn ) {
- var i = elems.length;
- while ( i-- ) {
- addEvent( elems[i], type, fn );
- }
-}
-
-function hasClass( elem, name ) {
- return (" " + elem.className + " ").indexOf(" " + name + " ") > -1;
-}
-
-function addClass( elem, name ) {
- if ( !hasClass( elem, name ) ) {
- elem.className += (elem.className ? " " : "") + name;
- }
-}
-
-function removeClass( elem, name ) {
- var set = " " + elem.className + " ";
- // Class name may appear multiple times
- while ( set.indexOf(" " + name + " ") > -1 ) {
- set = set.replace(" " + name + " " , " ");
- }
- // If possible, trim it for prettiness, but not neccecarily
- elem.className = window.jQuery ? jQuery.trim( set ) : ( set.trim ? set.trim() : set );
-}
-
-function id( name ) {
- return !!( typeof document !== "undefined" && document && document.getElementById ) &&
- document.getElementById( name );
-}
-
-function registerLoggingCallback( key ) {
- return function( callback ) {
- config[key].push( callback );
- };
-}
-
-// Supports deprecated method of completely overwriting logging callbacks
-function runLoggingCallbacks( key, scope, args ) {
- var i, callbacks;
- if ( QUnit.hasOwnProperty( key ) ) {
- QUnit[ key ].call(scope, args );
- } else {
- callbacks = config[ key ];
- for ( i = 0; i < callbacks.length; i++ ) {
- callbacks[ i ].call( scope, args );
- }
- }
-}
-
-// Test for equality any JavaScript type.
-// Author: Philippe Rathé
-QUnit.equiv = (function() {
-
- // Call the o related callback with the given arguments.
- function bindCallbacks( o, callbacks, args ) {
- var prop = QUnit.objectType( o );
- if ( prop ) {
- if ( QUnit.objectType( callbacks[ prop ] ) === "function" ) {
- return callbacks[ prop ].apply( callbacks, args );
- } else {
- return callbacks[ prop ]; // or undefined
- }
- }
- }
-
- // the real equiv function
- var innerEquiv,
- // stack to decide between skip/abort functions
- callers = [],
- // stack to avoiding loops from circular referencing
- parents = [],
-
- getProto = Object.getPrototypeOf || function ( obj ) {
- return obj.__proto__;
- },
- callbacks = (function () {
-
- // for string, boolean, number and null
- function useStrictEquality( b, a ) {
- /*jshint eqeqeq:false */
- if ( b instanceof a.constructor || a instanceof b.constructor ) {
- // to catch short annotaion VS 'new' annotation of a
- // declaration
- // e.g. var i = 1;
- // var j = new Number(1);
- return a == b;
- } else {
- return a === b;
- }
- }
-
- return {
- "string": useStrictEquality,
- "boolean": useStrictEquality,
- "number": useStrictEquality,
- "null": useStrictEquality,
- "undefined": useStrictEquality,
-
- "nan": function( b ) {
- return isNaN( b );
- },
-
- "date": function( b, a ) {
- return QUnit.objectType( b ) === "date" && a.valueOf() === b.valueOf();
- },
-
- "regexp": function( b, a ) {
- return QUnit.objectType( b ) === "regexp" &&
- // the regex itself
- a.source === b.source &&
- // and its modifers
- a.global === b.global &&
- // (gmi) ...
- a.ignoreCase === b.ignoreCase &&
- a.multiline === b.multiline &&
- a.sticky === b.sticky;
- },
-
- // - skip when the property is a method of an instance (OOP)
- // - abort otherwise,
- // initial === would have catch identical references anyway
- "function": function() {
- var caller = callers[callers.length - 1];
- return caller !== Object && typeof caller !== "undefined";
- },
-
- "array": function( b, a ) {
- var i, j, len, loop;
-
- // b could be an object literal here
- if ( QUnit.objectType( b ) !== "array" ) {
- return false;
- }
-
- len = a.length;
- if ( len !== b.length ) {
- // safe and faster
- return false;
- }
-
- // track reference to avoid circular references
- parents.push( a );
- for ( i = 0; i < len; i++ ) {
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- loop = true;// dont rewalk array
- }
- }
- if ( !loop && !innerEquiv(a[i], b[i]) ) {
- parents.pop();
- return false;
- }
- }
- parents.pop();
- return true;
- },
-
- "object": function( b, a ) {
- var i, j, loop,
- // Default to true
- eq = true,
- aProperties = [],
- bProperties = [];
-
- // comparing constructors is more strict than using
- // instanceof
- if ( a.constructor !== b.constructor ) {
- // Allow objects with no prototype to be equivalent to
- // objects with Object as their constructor.
- if ( !(( getProto(a) === null && getProto(b) === Object.prototype ) ||
- ( getProto(b) === null && getProto(a) === Object.prototype ) ) ) {
- return false;
- }
- }
-
- // stack constructor before traversing properties
- callers.push( a.constructor );
- // track reference to avoid circular references
- parents.push( a );
-
- for ( i in a ) { // be strict: don't ensures hasOwnProperty
- // and go deep
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- // don't go down the same path twice
- loop = true;
- }
- }
- aProperties.push(i); // collect a's properties
-
- if (!loop && !innerEquiv( a[i], b[i] ) ) {
- eq = false;
- break;
- }
- }
-
- callers.pop(); // unstack, we are done
- parents.pop();
-
- for ( i in b ) {
- bProperties.push( i ); // collect b's properties
- }
-
- // Ensures identical properties name
- return eq && innerEquiv( aProperties.sort(), bProperties.sort() );
- }
- };
- }());
-
- innerEquiv = function() { // can take multiple arguments
- var args = [].slice.apply( arguments );
- if ( args.length < 2 ) {
- return true; // end transition
- }
-
- return (function( a, b ) {
- if ( a === b ) {
- return true; // catch the most you can
- } else if ( a === null || b === null || typeof a === "undefined" ||
- typeof b === "undefined" ||
- QUnit.objectType(a) !== QUnit.objectType(b) ) {
- return false; // don't lose time with error prone cases
- } else {
- return bindCallbacks(a, callbacks, [ b, a ]);
- }
-
- // apply transition with (1..n) arguments
- }( args[0], args[1] ) && arguments.callee.apply( this, args.splice(1, args.length - 1 )) );
- };
-
- return innerEquiv;
-}());
-
-/**
- * jsDump Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com |
- * http://flesler.blogspot.com Licensed under BSD
- * (http://www.opensource.org/licenses/bsd-license.php) Date: 5/15/2008
- *
- * @projectDescription Advanced and extensible data dumping for Javascript.
- * @version 1.0.0
- * @author Ariel Flesler
- * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html}
- */
-QUnit.jsDump = (function() {
- function quote( str ) {
- return '"' + str.toString().replace( /"/g, '\\"' ) + '"';
- }
- function literal( o ) {
- return o + "";
- }
- function join( pre, arr, post ) {
- var s = jsDump.separator(),
- base = jsDump.indent(),
- inner = jsDump.indent(1);
- if ( arr.join ) {
- arr = arr.join( "," + s + inner );
- }
- if ( !arr ) {
- return pre + post;
- }
- return [ pre, inner + arr, base + post ].join(s);
- }
- function array( arr, stack ) {
- var i = arr.length, ret = new Array(i);
- this.up();
- while ( i-- ) {
- ret[i] = this.parse( arr[i] , undefined , stack);
- }
- this.down();
- return join( "[", ret, "]" );
- }
-
- var reName = /^function (\w+)/,
- jsDump = {
- // type is used mostly internally, you can fix a (custom)type in advance
- parse: function( obj, type, stack ) {
- stack = stack || [ ];
- var inStack, res,
- parser = this.parsers[ type || this.typeOf(obj) ];
-
- type = typeof parser;
- inStack = inArray( obj, stack );
-
- if ( inStack !== -1 ) {
- return "recursion(" + (inStack - stack.length) + ")";
- }
- if ( type === "function" ) {
- stack.push( obj );
- res = parser.call( this, obj, stack );
- stack.pop();
- return res;
- }
- return ( type === "string" ) ? parser : this.parsers.error;
- },
- typeOf: function( obj ) {
- var type;
- if ( obj === null ) {
- type = "null";
- } else if ( typeof obj === "undefined" ) {
- type = "undefined";
- } else if ( QUnit.is( "regexp", obj) ) {
- type = "regexp";
- } else if ( QUnit.is( "date", obj) ) {
- type = "date";
- } else if ( QUnit.is( "function", obj) ) {
- type = "function";
- } else if ( typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined" ) {
- type = "window";
- } else if ( obj.nodeType === 9 ) {
- type = "document";
- } else if ( obj.nodeType ) {
- type = "node";
- } else if (
- // native arrays
- toString.call( obj ) === "[object Array]" ||
- // NodeList objects
- ( typeof obj.length === "number" && typeof obj.item !== "undefined" && ( obj.length ? obj.item(0) === obj[0] : ( obj.item( 0 ) === null && typeof obj[0] === "undefined" ) ) )
- ) {
- type = "array";
- } else if ( obj.constructor === Error.prototype.constructor ) {
- type = "error";
- } else {
- type = typeof obj;
- }
- return type;
- },
- separator: function() {
- return this.multiline ? this.HTML ? "
" : "\n" : this.HTML ? " " : " ";
- },
- // extra can be a number, shortcut for increasing-calling-decreasing
- indent: function( extra ) {
- if ( !this.multiline ) {
- return "";
- }
- var chr = this.indentChar;
- if ( this.HTML ) {
- chr = chr.replace( /\t/g, " " ).replace( / /g, " " );
- }
- return new Array( this._depth_ + (extra||0) ).join(chr);
- },
- up: function( a ) {
- this._depth_ += a || 1;
- },
- down: function( a ) {
- this._depth_ -= a || 1;
- },
- setParser: function( name, parser ) {
- this.parsers[name] = parser;
- },
- // The next 3 are exposed so you can use them
- quote: quote,
- literal: literal,
- join: join,
- //
- _depth_: 1,
- // This is the list of parsers, to modify them, use jsDump.setParser
- parsers: {
- window: "[Window]",
- document: "[Document]",
- error: function(error) {
- return "Error(\"" + error.message + "\")";
- },
- unknown: "[Unknown]",
- "null": "null",
- "undefined": "undefined",
- "function": function( fn ) {
- var ret = "function",
- // functions never have name in IE
- name = "name" in fn ? fn.name : (reName.exec(fn) || [])[1];
-
- if ( name ) {
- ret += " " + name;
- }
- ret += "( ";
-
- ret = [ ret, QUnit.jsDump.parse( fn, "functionArgs" ), "){" ].join( "" );
- return join( ret, QUnit.jsDump.parse(fn,"functionCode" ), "}" );
- },
- array: array,
- nodelist: array,
- "arguments": array,
- object: function( map, stack ) {
- var ret = [ ], keys, key, val, i;
- QUnit.jsDump.up();
- keys = [];
- for ( key in map ) {
- keys.push( key );
- }
- keys.sort();
- for ( i = 0; i < keys.length; i++ ) {
- key = keys[ i ];
- val = map[ key ];
- ret.push( QUnit.jsDump.parse( key, "key" ) + ": " + QUnit.jsDump.parse( val, undefined, stack ) );
- }
- QUnit.jsDump.down();
- return join( "{", ret, "}" );
- },
- node: function( node ) {
- var len, i, val,
- open = QUnit.jsDump.HTML ? "<" : "<",
- close = QUnit.jsDump.HTML ? ">" : ">",
- tag = node.nodeName.toLowerCase(),
- ret = open + tag,
- attrs = node.attributes;
-
- if ( attrs ) {
- for ( i = 0, len = attrs.length; i < len; i++ ) {
- val = attrs[i].nodeValue;
- // IE6 includes all attributes in .attributes, even ones not explicitly set.
- // Those have values like undefined, null, 0, false, "" or "inherit".
- if ( val && val !== "inherit" ) {
- ret += " " + attrs[i].nodeName + "=" + QUnit.jsDump.parse( val, "attribute" );
- }
- }
- }
- ret += close;
-
- // Show content of TextNode or CDATASection
- if ( node.nodeType === 3 || node.nodeType === 4 ) {
- ret += node.nodeValue;
- }
-
- return ret + open + "/" + tag + close;
- },
- // function calls it internally, it's the arguments part of the function
- functionArgs: function( fn ) {
- var args,
- l = fn.length;
-
- if ( !l ) {
- return "";
- }
-
- args = new Array(l);
- while ( l-- ) {
- // 97 is 'a'
- args[l] = String.fromCharCode(97+l);
- }
- return " " + args.join( ", " ) + " ";
- },
- // object calls it internally, the key part of an item in a map
- key: quote,
- // function calls it internally, it's the content of the function
- functionCode: "[code]",
- // node calls it internally, it's an html attribute value
- attribute: quote,
- string: quote,
- date: quote,
- regexp: literal,
- number: literal,
- "boolean": literal
- },
- // if true, entities are escaped ( <, >, \t, space and \n )
- HTML: false,
- // indentation unit
- indentChar: " ",
- // if true, items in a collection, are separated by a \n, else just a space.
- multiline: true
- };
-
- return jsDump;
-}());
-
-// from jquery.js
-function inArray( elem, array ) {
- if ( array.indexOf ) {
- return array.indexOf( elem );
- }
-
- for ( var i = 0, length = array.length; i < length; i++ ) {
- if ( array[ i ] === elem ) {
- return i;
- }
- }
-
- return -1;
-}
-
-/*
- * Javascript Diff Algorithm
- * By John Resig (http://ejohn.org/)
- * Modified by Chu Alan "sprite"
- *
- * Released under the MIT license.
- *
- * More Info:
- * http://ejohn.org/projects/javascript-diff-algorithm/
- *
- * Usage: QUnit.diff(expected, actual)
- *
- * QUnit.diff( "the quick brown fox jumped over", "the quick fox jumps over" ) == "the quick brown fox jumped jumps over"
- */
-QUnit.diff = (function() {
- /*jshint eqeqeq:false, eqnull:true */
- function diff( o, n ) {
- var i,
- ns = {},
- os = {};
-
- for ( i = 0; i < n.length; i++ ) {
- if ( !hasOwn.call( ns, n[i] ) ) {
- ns[ n[i] ] = {
- rows: [],
- o: null
- };
- }
- ns[ n[i] ].rows.push( i );
- }
-
- for ( i = 0; i < o.length; i++ ) {
- if ( !hasOwn.call( os, o[i] ) ) {
- os[ o[i] ] = {
- rows: [],
- n: null
- };
- }
- os[ o[i] ].rows.push( i );
- }
-
- for ( i in ns ) {
- if ( !hasOwn.call( ns, i ) ) {
- continue;
- }
- if ( ns[i].rows.length === 1 && hasOwn.call( os, i ) && os[i].rows.length === 1 ) {
- n[ ns[i].rows[0] ] = {
- text: n[ ns[i].rows[0] ],
- row: os[i].rows[0]
- };
- o[ os[i].rows[0] ] = {
- text: o[ os[i].rows[0] ],
- row: ns[i].rows[0]
- };
- }
- }
-
- for ( i = 0; i < n.length - 1; i++ ) {
- if ( n[i].text != null && n[ i + 1 ].text == null && n[i].row + 1 < o.length && o[ n[i].row + 1 ].text == null &&
- n[ i + 1 ] == o[ n[i].row + 1 ] ) {
-
- n[ i + 1 ] = {
- text: n[ i + 1 ],
- row: n[i].row + 1
- };
- o[ n[i].row + 1 ] = {
- text: o[ n[i].row + 1 ],
- row: i + 1
- };
- }
- }
-
- for ( i = n.length - 1; i > 0; i-- ) {
- if ( n[i].text != null && n[ i - 1 ].text == null && n[i].row > 0 && o[ n[i].row - 1 ].text == null &&
- n[ i - 1 ] == o[ n[i].row - 1 ]) {
-
- n[ i - 1 ] = {
- text: n[ i - 1 ],
- row: n[i].row - 1
- };
- o[ n[i].row - 1 ] = {
- text: o[ n[i].row - 1 ],
- row: i - 1
- };
- }
- }
-
- return {
- o: o,
- n: n
- };
- }
-
- return function( o, n ) {
- o = o.replace( /\s+$/, "" );
- n = n.replace( /\s+$/, "" );
-
- var i, pre,
- str = "",
- out = diff( o === "" ? [] : o.split(/\s+/), n === "" ? [] : n.split(/\s+/) ),
- oSpace = o.match(/\s+/g),
- nSpace = n.match(/\s+/g);
-
- if ( oSpace == null ) {
- oSpace = [ " " ];
- }
- else {
- oSpace.push( " " );
- }
-
- if ( nSpace == null ) {
- nSpace = [ " " ];
- }
- else {
- nSpace.push( " " );
- }
-
- if ( out.n.length === 0 ) {
- for ( i = 0; i < out.o.length; i++ ) {
- str += "" + out.o[i] + oSpace[i] + "";
- }
- }
- else {
- if ( out.n[0].text == null ) {
- for ( n = 0; n < out.o.length && out.o[n].text == null; n++ ) {
- str += "" + out.o[n] + oSpace[n] + "";
- }
- }
-
- for ( i = 0; i < out.n.length; i++ ) {
- if (out.n[i].text == null) {
- str += "" + out.n[i] + nSpace[i] + "";
- }
- else {
- // `pre` initialized at top of scope
- pre = "";
-
- for ( n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++ ) {
- pre += "" + out.o[n] + oSpace[n] + "";
- }
- str += " " + out.n[i].text + nSpace[i] + pre;
- }
- }
- }
-
- return str;
- };
-}());
-
-// for CommonJS enviroments, export everything
-if ( typeof exports !== "undefined" ) {
- extend( exports, QUnit );
-}
-
-// get at whatever the global object is, like window in browsers
-}( (function() {return this;}.call()) ));
diff --git a/test/lib/require.js b/test/lib/require.js
deleted file mode 100644
index 987f865..0000000
--- a/test/lib/require.js
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- RequireJS 2.1.5 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.
- Available via the MIT or new BSD license.
- see: http://github.com/jrburke/requirejs for details
-*/
-var requirejs,require,define;
-(function(aa){function I(b){return"[object Function]"===L.call(b)}function J(b){return"[object Array]"===L.call(b)}function y(b,c){if(b){var d;for(d=0;dthis.depCount&&!this.defined){if(I(n)){if(this.events.error)try{e=i.execCb(c,n,b,e)}catch(d){a=d}else e=i.execCb(c,n,b,e);this.map.isDefine&&((b=this.module)&&void 0!==b.exports&&b.exports!==this.exports?e=b.exports:void 0===e&&this.usingExports&&(e=this.exports));if(a)return a.requireMap=this.map,a.requireModules=[this.map.id],a.requireType="define",v(this.error=
-a)}else e=n;this.exports=e;if(this.map.isDefine&&!this.ignore&&(q[c]=e,l.onResourceLoad))l.onResourceLoad(i,this.map,this.depMaps);x(c);this.defined=!0}this.defining=!1;this.defined&&!this.defineEmitted&&(this.defineEmitted=!0,this.emit("defined",this.exports),this.defineEmitComplete=!0)}}else this.fetch()}},callPlugin:function(){var a=this.map,b=a.id,d=j(a.prefix);this.depMaps.push(d);t(d,"defined",u(this,function(e){var n,d;d=this.map.name;var g=this.map.parentMap?this.map.parentMap.name:null,h=
-i.makeRequire(a.parentMap,{enableBuildCallback:!0});if(this.map.unnormalized){if(e.normalize&&(d=e.normalize(d,function(a){return c(a,g,!0)})||""),e=j(a.prefix+"!"+d,this.map.parentMap),t(e,"defined",u(this,function(a){this.init([],function(){return a},null,{enabled:!0,ignore:!0})})),d=m(p,e.id)){this.depMaps.push(e);if(this.events.error)d.on("error",u(this,function(a){this.emit("error",a)}));d.enable()}}else n=u(this,function(a){this.init([],function(){return a},null,{enabled:!0})}),n.error=u(this,
-function(a){this.inited=!0;this.error=a;a.requireModules=[b];G(p,function(a){0===a.map.id.indexOf(b+"_unnormalized")&&x(a.map.id)});v(a)}),n.fromText=u(this,function(e,c){var d=a.name,g=j(d),C=O;c&&(e=c);C&&(O=!1);r(g);s(k.config,b)&&(k.config[d]=k.config[b]);try{l.exec(e)}catch(ca){return v(B("fromtexteval","fromText eval for "+b+" failed: "+ca,ca,[b]))}C&&(O=!0);this.depMaps.push(g);i.completeLoad(d);h([d],n)}),e.load(a.name,h,n,k)}));i.enable(d,this);this.pluginMaps[d.id]=d},enable:function(){V[this.map.id]=
-this;this.enabling=this.enabled=!0;y(this.depMaps,u(this,function(a,b){var c,e;if("string"===typeof a){a=j(a,this.map.isDefine?this.map:this.map.parentMap,!1,!this.skipMap);this.depMaps[b]=a;if(c=m(N,a.id)){this.depExports[b]=c(this);return}this.depCount+=1;t(a,"defined",u(this,function(a){this.defineDep(b,a);this.check()}));this.errback&&t(a,"error",this.errback)}c=a.id;e=p[c];!s(N,c)&&(e&&!e.enabled)&&i.enable(a,this)}));G(this.pluginMaps,u(this,function(a){var b=m(p,a.id);b&&!b.enabled&&i.enable(a,
-this)}));this.enabling=!1;this.check()},on:function(a,b){var c=this.events[a];c||(c=this.events[a]=[]);c.push(b)},emit:function(a,b){y(this.events[a],function(a){a(b)});"error"===a&&delete this.events[a]}};i={config:k,contextName:b,registry:p,defined:q,urlFetched:U,defQueue:H,Module:Z,makeModuleMap:j,nextTick:l.nextTick,onError:v,configure:function(a){a.baseUrl&&"/"!==a.baseUrl.charAt(a.baseUrl.length-1)&&(a.baseUrl+="/");var b=k.pkgs,c=k.shim,e={paths:!0,config:!0,map:!0};G(a,function(a,b){e[b]?
-"map"===b?(k.map||(k.map={}),R(k[b],a,!0,!0)):R(k[b],a,!0):k[b]=a});a.shim&&(G(a.shim,function(a,b){J(a)&&(a={deps:a});if((a.exports||a.init)&&!a.exportsFn)a.exportsFn=i.makeShimExports(a);c[b]=a}),k.shim=c);a.packages&&(y(a.packages,function(a){a="string"===typeof a?{name:a}:a;b[a.name]={name:a.name,location:a.location||a.name,main:(a.main||"main").replace(ja,"").replace(ea,"")}}),k.pkgs=b);G(p,function(a,b){!a.inited&&!a.map.unnormalized&&(a.map=j(b))});if(a.deps||a.callback)i.require(a.deps||[],
-a.callback)},makeShimExports:function(a){return function(){var b;a.init&&(b=a.init.apply(aa,arguments));return b||a.exports&&ba(a.exports)}},makeRequire:function(a,f){function d(e,c,h){var g,k;f.enableBuildCallback&&(c&&I(c))&&(c.__requireJsBuild=!0);if("string"===typeof e){if(I(c))return v(B("requireargs","Invalid require call"),h);if(a&&s(N,e))return N[e](p[a.id]);if(l.get)return l.get(i,e,a,d);g=j(e,a,!1,!0);g=g.id;return!s(q,g)?v(B("notloaded",'Module name "'+g+'" has not been loaded yet for context: '+
-b+(a?"":". Use require([])"))):q[g]}L();i.nextTick(function(){L();k=r(j(null,a));k.skipMap=f.skipMap;k.init(e,c,h,{enabled:!0});D()});return d}f=f||{};R(d,{isBrowser:A,toUrl:function(b){var d,f=b.lastIndexOf("."),g=b.split("/")[0];if(-1!==f&&(!("."===g||".."===g)||1h.attachEvent.toString().indexOf("[native code"))&&!Y?(O=!0,h.attachEvent("onreadystatechange",b.onScriptLoad)):(h.addEventListener("load",b.onScriptLoad,!1),h.addEventListener("error",b.onScriptError,!1)),h.src=d,K=h,D?x.insertBefore(h,D):x.appendChild(h),K=null,h;if(da)try{importScripts(d),b.completeLoad(c)}catch(j){b.onError(B("importscripts","importScripts failed for "+c+" at "+d,j,[c]))}};A&&M(document.getElementsByTagName("script"),function(b){x||(x=
-b.parentNode);if(t=b.getAttribute("data-main"))return r.baseUrl||(E=t.split("/"),Q=E.pop(),fa=E.length?E.join("/")+"/":"./",r.baseUrl=fa,t=Q),t=t.replace(ea,""),r.deps=r.deps?r.deps.concat(t):[t],!0});define=function(b,c,d){var l,h;"string"!==typeof b&&(d=c,c=b,b=null);J(c)||(d=c,c=[]);!c.length&&I(d)&&d.length&&(d.toString().replace(la,"").replace(ma,function(b,d){c.push(d)}),c=(1===d.length?["require"]:["require","exports","module"]).concat(c));if(O){if(!(l=K))P&&"interactive"===P.readyState||M(document.getElementsByTagName("script"),
-function(b){if("interactive"===b.readyState)return P=b}),l=P;l&&(b||(b=l.getAttribute("data-requiremodule")),h=F[l.getAttribute("data-requirecontext")])}(h?h.defQueue:T).push([b,c,d])};define.amd={jQuery:!0};l.exec=function(b){return eval(b)};l(r)}})(this);
diff --git a/test/lib/resemble.js b/test/lib/resemble.js
new file mode 100644
index 0000000..1cb8c29
--- /dev/null
+++ b/test/lib/resemble.js
@@ -0,0 +1,535 @@
+/*
+Author: James Cryer
+Company: Huddle
+Last updated date: 21 Feb 2013
+URL: https://github.com/Huddle/Resemble.js
+*/
+
+(function(_this){
+ 'use strict';
+
+ _this['resemble'] = function( fileData ){
+
+ var data = {};
+ var images = [];
+ var updateCallbackArray = [];
+
+ var tolerance = { // between 0 and 255
+ red: 16,
+ green: 16,
+ blue: 16,
+ minBrightness: 16,
+ maxBrightness: 240
+ };
+
+ var ignoreAntialiasing = false;
+ var ignoreColors = false;
+
+ function triggerDataUpdate(){
+ var len = updateCallbackArray.length;
+ var i;
+ for(i=0;i tolerance.maxBrightness;
+ }
+
+ function getHue(r,g,b){
+
+ r = r / 255;
+ g = g / 255;
+ b = b / 255;
+ var max = Math.max(r, g, b), min = Math.min(r, g, b);
+ var h;
+ var d;
+
+ if (max == min){
+ h = 0; // achromatic
+ } else{
+ d = max - min;
+ switch(max){
+ case r: h = (g - b) / d + (g < b ? 6 : 0); break;
+ case g: h = (b - r) / d + 2; break;
+ case b: h = (r - g) / d + 4; break;
+ }
+ h /= 6;
+ }
+
+ return h;
+ }
+
+ function isAntialiased(sourcePix, data, cacheSet, verticalPos, horizontalPos, width){
+ var offset;
+ var targetPix;
+ var distance = 1;
+ var i;
+ var j;
+ var hasHighContrastSibling = 0;
+ var hasSiblingWithDifferentHue = 0;
+ var hasEquivilantSibling = 0;
+
+ addHueInfo(sourcePix);
+
+ for (i = distance*-1; i <= distance; i++){
+ for (j = distance*-1; j <= distance; j++){
+
+ if(i===0 && j===0){
+ // ignore source pixel
+ } else {
+
+ offset = ((verticalPos+j)*width + (horizontalPos+i)) * 4;
+ targetPix = getPixelInfo(data, offset, cacheSet);
+
+ if(targetPix === null){
+ continue;
+ }
+
+ addBrightnessInfo(targetPix);
+ addHueInfo(targetPix);
+
+ if( isContrasting(sourcePix, targetPix) ){
+ hasHighContrastSibling++;
+ }
+
+ if( isRGBSame(sourcePix,targetPix) ){
+ hasEquivilantSibling++;
+ }
+
+ if( Math.abs(targetPix.h - sourcePix.h) > 0.3 ){
+ hasSiblingWithDifferentHue++;
+ }
+
+ if( hasSiblingWithDifferentHue > 1 || hasHighContrastSibling > 1){
+ return true;
+ }
+ }
+ }
+ }
+
+ if(hasEquivilantSibling < 2){
+ return true;
+ }
+
+ return false;
+ }
+
+ function errorPixel(px, offset){
+ px[offset] = 255; //r
+ px[offset + 1] = 0; //g
+ px[offset + 2] = 255; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyPixel(px, offset, data){
+ px[offset] = data.r; //r
+ px[offset + 1] = data.g; //g
+ px[offset + 2] = data.b; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyGrayScalePixel(px, offset, data){
+ px[offset] = data.brightness; //r
+ px[offset + 1] = data.brightness; //g
+ px[offset + 2] = data.brightness; //b
+ px[offset + 3] = 255; //a
+ }
+
+
+ function getPixelInfo(data, offset, cacheSet){
+ var r;
+ var g;
+ var b;
+ var d;
+
+ if(typeof data[offset] !== 'undefined'){
+ r = data[offset];
+ g = data[offset+1];
+ b = data[offset+2];
+ d = {
+ r: r,
+ g: g,
+ b: b
+ };
+
+ return d;
+ } else {
+ return null;
+ }
+ }
+
+ function addBrightnessInfo(data){
+ data.brightness = getBrightness(data.r,data.g,data.b); // 'corrected' lightness
+ }
+
+ function addHueInfo(data){
+ data.h = getHue(data.r,data.g,data.b);
+ }
+
+ function analyseImages(img1, img2, width, height){
+
+ var hiddenCanvas = document.createElement('canvas');
+
+ var data1 = img1.data;
+ var data2 = img2.data;
+
+ hiddenCanvas.width = width;
+ hiddenCanvas.height = height;
+
+ var context = hiddenCanvas.getContext('2d');
+ var imgd = context.createImageData(width,height);
+ var targetPix = imgd.data;
+
+ var mismatchCount = 0;
+
+ var time = Date.now();
+
+ var skip;
+
+ if( (width > 1200 || height > 1200) && ignoreAntialiasing){
+ skip = 6;
+ }
+
+ loop(height, width, function(verticalPos, horizontalPos){
+
+ if(skip){ // only skip if the image isn't small
+ if(verticalPos % skip === 0 || horizontalPos % skip === 0){
+ return;
+ }
+ }
+
+ var offset = (verticalPos*width + horizontalPos) * 4;
+ var pixel1 = getPixelInfo(data1, offset, 1);
+ var pixel2 = getPixelInfo(data2, offset, 2);
+
+ if(pixel1 === null || pixel2 === null){
+ return;
+ }
+
+ if (ignoreColors){
+
+ addBrightnessInfo(pixel1);
+ addBrightnessInfo(pixel2);
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ return;
+ }
+
+ if( isRGBSimilar(pixel1, pixel2) ){
+ copyPixel(targetPix, offset, pixel2);
+
+ } else if( ignoreAntialiasing && (
+ addBrightnessInfo(pixel1), // jit pixel info augmentation looks a little weird, sorry.
+ addBrightnessInfo(pixel2),
+ isAntialiased(pixel1, data1, 1, verticalPos, horizontalPos, width) ||
+ isAntialiased(pixel2, data2, 2, verticalPos, horizontalPos, width)
+ )){
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+
+ });
+
+ data.misMatchPercentage = (mismatchCount / (height*width) * 100).toFixed(2);
+ data.analysisTime = Date.now() - time;
+
+ data.getImageDataUrl = function(text){
+ var barHeight = 0;
+
+ if(text){
+ barHeight = addLabel(text,context,hiddenCanvas);
+ }
+
+ context.putImageData(imgd, 0, barHeight);
+
+ return hiddenCanvas.toDataURL("image/png");
+ };
+ }
+
+ function addLabel(text, context, hiddenCanvas){
+ var textPadding = 2;
+
+ context.font = '12px sans-serif';
+
+ var textWidth = context.measureText(text).width + textPadding*2;
+ var barHeight = 22;
+
+ if(textWidth > hiddenCanvas.width){
+ hiddenCanvas.width = textWidth;
+ }
+
+ hiddenCanvas.height += barHeight;
+
+ context.fillStyle = "#666";
+ context.fillRect(0,0,hiddenCanvas.width,barHeight -4);
+ context.fillStyle = "#fff";
+ context.fillRect(0,barHeight -4,hiddenCanvas.width, 4);
+
+ context.fillStyle = "#fff";
+ context.textBaseline = "top";
+ context.font = '12px sans-serif';
+ context.fillText(text, textPadding, 1);
+
+ return barHeight;
+ }
+
+ function normalise(img, w, h){
+ var c;
+ var context;
+
+ if(img.height < h || img.width < w){
+ c = document.createElement('canvas');
+ c.width = w;
+ c.height = h;
+ context = c.getContext('2d');
+ context.putImageData(img, 0, 0);
+ return context.getImageData(0, 0, w, h);
+ }
+
+ return img;
+ }
+
+ function compare(one, two){
+
+ function onceWeHaveBoth(){
+ var width;
+ var height;
+ if(images.length === 2){
+ width = images[0].width > images[1].width ? images[0].width : images[1].width;
+ height = images[0].height > images[1].height ? images[0].height : images[1].height;
+
+ if( (images[0].width === images[1].width) && (images[0].height === images[1].height) ){
+ data.isSameDimensions = true;
+ } else {
+ data.isSameDimensions = false;
+ }
+
+ analyseImages( normalise(images[0],width, height), normalise(images[1],width, height), width, height);
+
+ triggerDataUpdate();
+ }
+ }
+
+ images = [];
+ loadImageData(one, onceWeHaveBoth);
+ loadImageData(two, onceWeHaveBoth);
+ }
+
+ function getCompareApi(param){
+
+ var secondFileData,
+ hasMethod = typeof param === 'function';
+
+ if( !hasMethod ){
+ // assume it's file data
+ secondFileData = param;
+ }
+
+ var self = {
+ ignoreNothing: function(){
+
+ tolerance.red = 16;
+ tolerance.green = 16;
+ tolerance.blue = 16;
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreAntialiasing: function(){
+
+ tolerance.red = 32;
+ tolerance.green = 32;
+ tolerance.blue = 32;
+ tolerance.minBrightness = 64;
+ tolerance.maxBrightness = 96;
+
+ ignoreAntialiasing = true;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreColors: function(){
+
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = true;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ onComplete: function( callback ){
+
+ updateCallbackArray.push(callback);
+
+ var wrapper = function(){
+ compare(fileData, secondFileData);
+ };
+
+ wrapper();
+
+ return getCompareApi(wrapper);
+ }
+ };
+
+ return self;
+ }
+
+ return {
+ onComplete: function( callback ){
+ updateCallbackArray.push(callback);
+ loadImageData(fileData, function(imageData, width, height){
+ parseImage(imageData.data, width, height);
+ });
+ },
+ compareTo: function(secondFileData){
+ return getCompareApi(secondFileData);
+ }
+ };
+
+ };
+}(this));
\ No newline at end of file
diff --git a/test/testsuite.js b/test/testsuite.js
deleted file mode 100644
index b486acb..0000000
--- a/test/testsuite.js
+++ /dev/null
@@ -1,36 +0,0 @@
-requirejs.config({
- baseUrl: '/test/unit/'
-});
-
-define(function(require) {
- var testModules = [
- 'Pixi',
- 'Point',
- 'Rectangle',
- 'DisplayObject',
- 'DisplayObjectContainer',
- 'Sprite',
- 'MovieClip',
- 'InteractionManager',
- 'Stage',
- 'utils/Utils',
- 'utils/EventTarget',
- 'utils/Matrix',
- 'utils/Detector',
- 'renderers/WebGLShaders',
- 'renderers/WebGLRenderer',
- 'renderers/WebGLBatch',
- 'renderers/CanvasRenderer',
- 'extras/Strip',
- 'extras/Rope',
- 'textures/BaseTexture',
- 'textures/Texture',
- 'loaders/SpriteSheetLoader',
- 'loaders/AssetLoader'
- ];
-
- // Resolve all testModules and then start the Test Runner.
- require(testModules, function() {
- QUnit.start();
- });
-});
\ No newline at end of file
diff --git a/test/textures/SpriteSheet-Aliens.png b/test/textures/SpriteSheet-Aliens.png
new file mode 100644
index 0000000..210acb1
--- /dev/null
+++ b/test/textures/SpriteSheet-Aliens.png
Binary files differ
diff --git a/test/textures/SpriteSheet-Explosion.png b/test/textures/SpriteSheet-Explosion.png
new file mode 100755
index 0000000..79e1a69
--- /dev/null
+++ b/test/textures/SpriteSheet-Explosion.png
Binary files differ
diff --git a/test/textures/bunny.png b/test/textures/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/textures/bunny.png
Binary files differ
diff --git a/test/unit/DisplayObject.js b/test/unit/DisplayObject.js
deleted file mode 100644
index 5e7e72f..0000000
--- a/test/unit/DisplayObject.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObject');
-});
diff --git a/test/unit/DisplayObjectContainer.js b/test/unit/DisplayObjectContainer.js
deleted file mode 100644
index b323959..0000000
--- a/test/unit/DisplayObjectContainer.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObjectContainer');
-});
diff --git a/test/unit/InteractionManager.js b/test/unit/InteractionManager.js
deleted file mode 100644
index e751f52..0000000
--- a/test/unit/InteractionManager.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('InteractionManager');
-});
diff --git a/test/unit/MovieClip.js b/test/unit/MovieClip.js
deleted file mode 100644
index 37d9446..0000000
--- a/test/unit/MovieClip.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('MovieClip');
-});
diff --git a/test/unit/Pixi.js b/test/unit/Pixi.js
deleted file mode 100644
index 36eee73..0000000
--- a/test/unit/Pixi.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Pixi');
-});
diff --git a/test/unit/Point.js b/test/unit/Point.js
deleted file mode 100644
index 983ff6e..0000000
--- a/test/unit/Point.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Point');
-});
diff --git a/test/unit/Rectangle.js b/test/unit/Rectangle.js
deleted file mode 100644
index 3b439ba..0000000
--- a/test/unit/Rectangle.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Rectangle');
-});
diff --git a/test/unit/Sprite.js b/test/unit/Sprite.js
deleted file mode 100644
index ed4f596..0000000
--- a/test/unit/Sprite.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Sprite');
-});
diff --git a/test/unit/Stage.js b/test/unit/Stage.js
deleted file mode 100644
index 2d70291..0000000
--- a/test/unit/Stage.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Stage');
-});
diff --git a/test/unit/extras/Rope.js b/test/unit/extras/Rope.js
deleted file mode 100644
index 5606f14..0000000
--- a/test/unit/extras/Rope.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Rope');
-});
diff --git a/test/unit/extras/Strip.js b/test/unit/extras/Strip.js
deleted file mode 100644
index 0134d3a..0000000
--- a/test/unit/extras/Strip.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Strip');
-});
diff --git a/test/unit/loaders/AssetLoader.js b/test/unit/loaders/AssetLoader.js
deleted file mode 100644
index 13b8443..0000000
--- a/test/unit/loaders/AssetLoader.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('AssetLoader');
-});
diff --git a/test/unit/loaders/SpriteSheetLoader.js b/test/unit/loaders/SpriteSheetLoader.js
deleted file mode 100644
index 8bf0cb2..0000000
--- a/test/unit/loaders/SpriteSheetLoader.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('SpriteSheetLoader');
-});
diff --git a/test/unit/pixi/InteractionManager.js b/test/unit/pixi/InteractionManager.js
new file mode 100644
index 0000000..ed3001f
--- /dev/null
+++ b/test/unit/pixi/InteractionManager.js
@@ -0,0 +1,10 @@
+describe('pixi/InteractionManager', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var InteractionManager = PIXI.InteractionManager;
+
+ it('Module exists', function () {
+ expect(InteractionManager).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/Pixi.js b/test/unit/pixi/Pixi.js
new file mode 100644
index 0000000..27debc1
--- /dev/null
+++ b/test/unit/pixi/Pixi.js
@@ -0,0 +1,9 @@
+describe('pixi/Pixi', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+
+ it('Module exists', function () {
+ expect(global).to.have.property('PIXI').and.to.be.an('object');
+ });
+});
diff --git a/test/unit/pixi/core/Circle.js b/test/unit/pixi/core/Circle.js
new file mode 100644
index 0000000..93a4456
--- /dev/null
+++ b/test/unit/pixi/core/Circle.js
@@ -0,0 +1,22 @@
+describe('pixi/core/Circle', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Circle = PIXI.Circle;
+
+ it('Module exists', function () {
+ expect(Circle).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Circle();
+
+ expect(obj).to.be.an.instanceof(Circle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', 0);
+ expect(obj).to.have.property('y', 0);
+ expect(obj).to.have.property('radius', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Ellipse.js b/test/unit/pixi/core/Ellipse.js
new file mode 100644
index 0000000..026b56f
--- /dev/null
+++ b/test/unit/pixi/core/Ellipse.js
@@ -0,0 +1,24 @@
+describe('pixi/core/Ellipse', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Ellipse = PIXI.Ellipse;
+
+ it('Module exists', function () {
+ expect(Ellipse).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Ellipse();
+
+ expect(obj).to.be.an.instanceof(Ellipse);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+ expect(obj).to.respondTo('getBounds');
+
+ expect(obj).to.have.property('x', 0);
+ expect(obj).to.have.property('y', 0);
+ expect(obj).to.have.property('width', 0);
+ expect(obj).to.have.property('height', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Matrix.js b/test/unit/pixi/core/Matrix.js
new file mode 100644
index 0000000..b48989e
--- /dev/null
+++ b/test/unit/pixi/core/Matrix.js
@@ -0,0 +1,30 @@
+describe('pixi/core/Matrix', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var mat3 = PIXI.mat3;
+ var mat4 = PIXI.mat4;
+ var Matrix = PIXI.Matrix;
+
+ it('Ensure determineMatrixArrayType works', function () {
+ expect(Matrix).to.be.a('function');
+ });
+
+ it('mat3 exists', function () {
+ expect(mat3).to.be.an('object');
+ });
+
+ it('Confirm new mat3 matrix', function () {
+ var matrix = new mat3.create();
+ pixi_core_Matrix_confirmNewMat3(matrix);
+ });
+
+ it('mat3 exists', function () {
+ expect(mat4).to.be.an('object');
+ });
+
+ it('Confirm new mat4 matrix', function () {
+ var matrix = new mat4.create();
+ pixi_core_Matrix_confirmNewMat4(matrix);
+ });
+});
diff --git a/test/unit/pixi/core/Point.js b/test/unit/pixi/core/Point.js
new file mode 100644
index 0000000..c4d5163
--- /dev/null
+++ b/test/unit/pixi/core/Point.js
@@ -0,0 +1,15 @@
+describe('pixi/core/Point', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Point = PIXI.Point;
+
+ it('Module exists', function () {
+ expect(Point).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Point();
+ pixi_core_Point_confirm(obj, 0, 0);
+ });
+});
diff --git a/test/unit/pixi/core/Polygon.js b/test/unit/pixi/core/Polygon.js
new file mode 100644
index 0000000..dc8c918
--- /dev/null
+++ b/test/unit/pixi/core/Polygon.js
@@ -0,0 +1,20 @@
+describe('pixi/core/Polygon', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Polygon = PIXI.Polygon;
+
+ it('Module exists', function () {
+ expect(Polygon).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Polygon();
+
+ expect(obj).to.be.an.instanceof(Polygon);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.deep.property('points.length', 0);
+ });
+});
diff --git a/.gitignore b/.gitignore
index 12e1b62..0b88317 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
node_modules
.DS_Store
-.project
\ No newline at end of file
+.project
+*.log
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..63e4d7c
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,8 @@
+language: node_js
+node_js:
+ - 0.10
+
+before_script:
+ - npm install -g grunt-cli
+ - export DISPLAY=:99.0
+ - sh -e /etc/init.d/xvfb start
diff --git a/Gruntfile.js b/Gruntfile.js
index b083b49..103938c 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -1,10 +1,12 @@
+'use strict';
+
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-connect');
- grunt.loadNpmTasks('grunt-contrib-qunit');
grunt.loadNpmTasks('grunt-contrib-yuidoc');
+ grunt.loadTasks('tasks');
var root = 'src/pixi/',
debug = 'bin/pixi.dev.js',
@@ -79,7 +81,7 @@
},
files: {
srcBlob: '<%= dirs.src %>/**/*.js',
- testBlob: '<%= dirs.test %>/unit/**/*.js',
+ testBlob: '<%= dirs.test %>/{functional,lib/pixi,unit}/**/*.js',
build: '<%= dirs.build %>/pixi.dev.js',
buildMin: '<%= dirs.build %>/pixi.js'
},
@@ -94,7 +96,12 @@
},
jshint: {
beforeconcat: srcFiles,
- test: ['<%= files.testBlob %>'],
+ test: {
+ src: ['<%= files.testBlob %>'],
+ options: {
+ expr: true
+ }
+ },
options: {
asi: true,
smarttabs: true
@@ -128,12 +135,6 @@
]
},
connect: {
- qunit: {
- options: {
- port: grunt.option('port-test') || 9002,
- base: './'
- }
- },
test: {
options: {
port: grunt.option('port-test') || 9002,
@@ -142,13 +143,6 @@
}
}
},
- qunit: {
- all: {
- options: {
- urls: ['http://localhost:' + (grunt.option('port-test') || 9002) + '/test/index.html']
- }
- }
- },
yuidoc: {
compile: {
name: '<%= pkg.name %>',
@@ -161,6 +155,13 @@
outdir: '<%= dirs.docs %>'
}
}
+ },
+ karma: {
+ unit: {
+ configFile: 'test/karma.conf.js',
+ // browsers: ['Chrome'],
+ singleRun: true
+ }
}
});
@@ -182,9 +183,10 @@
}
)
- grunt.registerTask('default', ['concat', 'uglify', 'distribute']);
grunt.registerTask('build', ['concat', 'uglify', 'distribute']);
- grunt.registerTask('test', ['build', 'connect:qunit', 'qunit']);
+ grunt.registerTask('test', ['concat', 'jshint:test', 'karma']);
grunt.registerTask('docs', ['yuidoc']);
-
-}
\ No newline at end of file
+ grunt.registerTask('default', ['test', 'uglify', 'distribute']);
+ // Travis CI task.
+ grunt.registerTask('travis', ['test']);
+}
diff --git a/README.md b/README.md
index c62ef86..690cfe4 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,8 @@

+[](http://travis-ci.org/drkibitz/pixi.js)
+
#### JavaScript 2D Renderer ####
The aim of this project is to provide a fast lightweight 2D library that works
diff --git a/package.json b/package.json
index b373240..1246a68 100644
--- a/package.json
+++ b/package.json
@@ -18,14 +18,21 @@
"main": "bin/pixi.js",
+ "scripts": {
+ "test": "grunt travis --verbose"
+ },
+
"dependencies": {},
"devDependencies": {
"grunt": "~0.4.x",
- "grunt-contrib-jshint": "0.3.x",
+ "grunt-contrib-jshint": "0.6.x",
"grunt-contrib-uglify": "0.2.x",
- "grunt-contrib-connect": "0.2.x",
- "grunt-contrib-qunit": "0.2.x",
+ "grunt-contrib-connect": "0.3.x",
"grunt-contrib-yuidoc": "0.4.x",
- "grunt-contrib-concat": "0.1.x"
+ "grunt-contrib-concat": "0.3.x",
+ "chai": "~1.7.0",
+ "karma": "0.11.0",
+ "karma-firefox-launcher": "0.1.0",
+ "karma-mocha": "0.1.0"
}
}
diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js
index a7c520e..ee82bbd 100644
--- a/src/pixi/InteractionManager.js
+++ b/src/pixi/InteractionManager.js
@@ -62,7 +62,6 @@
this.onTouchEnd = this.onTouchEnd.bind(this);
this.onTouchMove = this.onTouchMove.bind(this);
-
this.last = 0;
}
diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js
index 1a95d20..eef1059 100644
--- a/src/pixi/core/Ellipse.js
+++ b/src/pixi/core/Ellipse.js
@@ -78,7 +78,7 @@
return (normx + normy < 0.25);
}
-PIXI.Ellipse.getBounds = function()
+PIXI.Ellipse.prototype.getBounds = function()
{
return new PIXI.Rectangle(this.x, this.y, this.width, this.height);
}
diff --git a/tasks/karma.js b/tasks/karma.js
new file mode 100644
index 0000000..c340485
--- /dev/null
+++ b/tasks/karma.js
@@ -0,0 +1,27 @@
+'use strict';
+
+var path = require('path');
+var server = require('karma').server;
+
+module.exports = function (grunt) {
+ grunt.registerMultiTask('karma', 'run karma.', function() {
+ var done = this.async();
+ var options = this.options({
+ background: false
+ });
+ var data = this.data;
+
+ //merge options onto data, with data taking precedence
+ data = grunt.util._.merge(options, data);
+ data.configFile = path.resolve(data.configFile);
+ if (data.configFile) {
+ data.configFile = grunt.template.process(data.configFile);
+ }
+
+ server.start(
+ data,
+ function(code) {
+ done(!code);
+ });
+ });
+};
diff --git a/test/functional/example-1-basics/bunny.png b/test/functional/example-1-basics/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/functional/example-1-basics/bunny.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-30.png b/test/functional/example-1-basics/frame-30.png
new file mode 100644
index 0000000..96e3409
--- /dev/null
+++ b/test/functional/example-1-basics/frame-30.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-60.png b/test/functional/example-1-basics/frame-60.png
new file mode 100644
index 0000000..af3f4ce
--- /dev/null
+++ b/test/functional/example-1-basics/frame-60.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-90.png b/test/functional/example-1-basics/frame-90.png
new file mode 100644
index 0000000..099b823
--- /dev/null
+++ b/test/functional/example-1-basics/frame-90.png
Binary files differ
diff --git a/test/functional/example-1-basics/index.js b/test/functional/example-1-basics/index.js
new file mode 100644
index 0000000..7ae7a98
--- /dev/null
+++ b/test/functional/example-1-basics/index.js
@@ -0,0 +1,133 @@
+describe('Example 1 - Basics', function () {
+ 'use strict';
+
+ var baseUri = '/base/test/functional/example-1-basics';
+ var expect = chai.expect;
+ var currentFrame = 0;
+ var frameEvents = {};
+ var stage;
+ var renderer;
+ var bunny;
+
+ function onFrame(frame, callback) {
+ frameEvents[frame] = callback;
+ }
+
+ function animate() {
+ currentFrame += 1;
+
+ requestAnimFrame( animate );
+
+ // just for fun, lets rotate mr rabbit a little
+ bunny.rotation += 0.1;
+
+ // render the stage
+ renderer.render(stage);
+
+ if (frameEvents[currentFrame])
+ frameEvents[currentFrame](currentFrame);
+ }
+
+ function initScene() {
+ // create an new instance of a pixi stage
+ stage = new PIXI.Stage(0x66FF99);
+
+ // create a renderer instance
+ renderer = PIXI.autoDetectRenderer(400, 300);
+ console.log('Is PIXI.WebGLRenderer: ' + (renderer instanceof PIXI.WebGLRenderer));
+
+ // add the renderer view element to the DOM
+ document.body.appendChild(renderer.view);
+
+ requestAnimFrame( animate );
+
+ // create a texture from an image path
+ var texture = PIXI.Texture.fromImage(baseUri + "/bunny.png");
+ // create a new Sprite using the texture
+ bunny = new PIXI.Sprite(texture);
+
+ // center the sprites anchor point
+ bunny.anchor.x = 0.5;
+ bunny.anchor.y = 0.5;
+
+ // move the sprite t the center of the screen
+ bunny.position.x = 200;
+ bunny.position.y = 150;
+
+ stage.addChild(bunny);
+ }
+
+ it('assets loaded', function (done) {
+ var loader = new PIXI.AssetLoader([
+ baseUri + '/bunny.png',
+ baseUri + '/frame-30.png',
+ baseUri + '/frame-60.png',
+ baseUri + '/frame-90.png'
+ ]);
+ // loader.on('onProgress', function (event) {
+ // console.log(event.content);
+ // });
+ loader.on('onComplete', function (event) {
+ done();
+ initScene();
+ });
+ loader.load();
+ });
+
+ it('frame 30 should match', function (done) {
+ this.timeout(700);
+ onFrame(30, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-30.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 60 should match', function (done) {
+ this.timeout(1200);
+ onFrame(60, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-60.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 90 should match', function (done) {
+ this.timeout(1700);
+ onFrame(90, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-90.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ // it('capture something', function (done) {
+ // this.timeout(2000000);
+ // onFrame(30, function () {
+ // var img = new Image();
+ // img.src = renderer.view.toDataURL('image/png');
+ // document.body.appendChild(img);
+ // });
+ // });
+});
diff --git a/test/index.html b/test/index.html
deleted file mode 100644
index 9cbcac5..0000000
--- a/test/index.html
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
- Pixi.js Test Suite
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/test/karma.conf.js b/test/karma.conf.js
new file mode 100644
index 0000000..c66a696
--- /dev/null
+++ b/test/karma.conf.js
@@ -0,0 +1,82 @@
+module.exports = function(config) {
+ config.set({
+
+ // base path, that will be used to resolve files and exclude
+ basePath : '../',
+
+ frameworks : ['mocha'],
+
+ // list of files / patterns to load in the browser
+ files : [
+ 'node_modules/chai/chai.js',
+ 'bin/pixi.dev.js',
+ 'test/lib/**/*.js',
+ 'test/unit/**/*.js',
+ // 'test/functional/**/*.js',
+ {pattern: 'test/**/*.png', watched: false, included: false, served: true}
+ ],
+
+ // list of files to exclude
+ exclude : [],
+
+ // use dolts reporter, as travis terminal does not support escaping sequences
+ // possible values: 'dots', 'progress', 'junit', 'teamcity'
+ // CLI --reporters progress
+ reporters : ['progress'],
+
+ // web server port
+ // CLI --port 9876
+ port : 9876,
+
+ // cli runner port
+ // CLI --runner-port 9100
+ runnerPort : 9100,
+
+ // enable / disable colors in the output (reporters and logs)
+ // CLI --colors --no-colors
+ colors : true,
+
+ // level of logging
+ // possible values: karma.LOG_DISABLE || karma.LOG_ERROR || karma.LOG_WARN || karma.LOG_INFO || karma.LOG_DEBUG
+ // CLI --log-level debug
+ logLevel : config.LOG_DEBUG,
+
+ // enable / disable watching file and executing tests whenever any file changes
+ // CLI --auto-watch --no-auto-watch
+ autoWatch : false,
+
+ // Start these browsers, currently available:
+ // - Chrome
+ // - ChromeCanary
+ // - Firefox
+ // - Opera
+ // - Safari (only Mac)
+ // - PhantomJS
+ // - IE (only Windows)
+ // CLI --browsers Chrome,Firefox,Safari
+ browsers : ['Firefox'],
+
+ // If browser does not capture in given timeout [ms], kill it
+ // CLI --capture-timeout 5000
+ captureTimeout : 5000,
+
+ // Auto run tests on start (when browsers are captured) and exit
+ // CLI --single-run --no-single-run
+ singleRun : true,
+
+ // report which specs are slower than 500ms
+ // CLI --report-slower-than 500
+ reportSlowerThan : 1000,
+
+ preprocessors : {
+ // '**/client/js/*.js': 'coverage'
+ },
+
+ plugins : [
+ 'karma-mocha',
+ // 'karma-chrome-launcher',
+ 'karma-firefox-launcher',
+ // 'karma-phantomjs-launcher'
+ ]
+ });
+};
diff --git a/test/lib/pixi/core/Matrix.js b/test/lib/pixi/core/Matrix.js
new file mode 100644
index 0000000..d26386b
--- /dev/null
+++ b/test/lib/pixi/core/Matrix.js
@@ -0,0 +1,40 @@
+
+function pixi_core_Matrix_confirmNewMat3(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(1);
+ expect(matrix[5]).to.equal(0);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(1);
+}
+
+function pixi_core_Matrix_confirmNewMat4(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[0]).to.equal(1);
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(0);
+ expect(matrix[5]).to.equal(1);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(0);
+ expect(matrix[9]).to.equal(0);
+ expect(matrix[10]).to.equal(1);
+ expect(matrix[11]).to.equal(0);
+ expect(matrix[12]).to.equal(0);
+ expect(matrix[13]).to.equal(0);
+ expect(matrix[14]).to.equal(0);
+ expect(matrix[15]).to.equal(1);
+}
diff --git a/test/lib/pixi/core/Point.js b/test/lib/pixi/core/Point.js
new file mode 100644
index 0000000..e5df07b
--- /dev/null
+++ b/test/lib/pixi/core/Point.js
@@ -0,0 +1,10 @@
+
+function pixi_core_Point_confirm(obj, x, y) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Point);
+ expect(obj).to.respondTo('clone');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+}
diff --git a/test/lib/pixi/core/Rectangle.js b/test/lib/pixi/core/Rectangle.js
new file mode 100644
index 0000000..23f0d12
--- /dev/null
+++ b/test/lib/pixi/core/Rectangle.js
@@ -0,0 +1,13 @@
+
+function pixi_core_Rectangle_confirm(obj, x, y, width, height) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Rectangle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+ expect(obj).to.have.property('width', width);
+ expect(obj).to.have.property('height', height);
+}
diff --git a/test/lib/pixi/display/DisplayObject.js b/test/lib/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..1388a7f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObject.js
@@ -0,0 +1,43 @@
+
+function pixi_display_DisplayObject_confirmNew(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObject);
+ expect(obj).to.respondTo('setInteractive');
+ expect(obj).to.respondTo('addFilter');
+ expect(obj).to.respondTo('removeFilter');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.property('last', obj);
+ expect(obj).to.have.property('first', obj);
+
+ expect(obj).to.contain.property('position');
+ pixi_core_Point_confirm(obj.position, 0, 0);
+ expect(obj).to.contain.property('scale');
+ pixi_core_Point_confirm(obj.scale, 1, 1);
+ expect(obj).to.contain.property('pivot');
+ pixi_core_Point_confirm(obj.pivot, 0, 0);
+
+ expect(obj).to.have.property('rotation', 0);
+ expect(obj).to.have.property('alpha', 1);
+ expect(obj).to.have.property('visible', true);
+ expect(obj).to.have.property('buttonMode', false);
+ expect(obj).to.have.property('parent', null);
+ expect(obj).to.have.property('worldAlpha', 1);
+
+ expect(obj).to.have.property('hitArea');
+ expect(obj).to.have.property('interactive'); // TODO: Have a better default value
+ expect('mask' in obj).to.be.true; // TODO: Have a better default value
+ expect(obj.mask).to.be.undefined;
+
+ expect(obj).to.have.property('renderable');
+ expect(obj).to.have.property('stage');
+
+ expect(obj).to.have.deep.property('worldTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ expect(obj).to.have.deep.property('localTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.localTransform);
+
+ expect(obj).to.have.deep.property('color.length', 0);
+ expect(obj).to.have.property('dynamic', true);
+}
diff --git a/test/lib/pixi/display/DisplayObjectContainer.js b/test/lib/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..085c59f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,16 @@
+
+function pixi_display_DisplayObjectContainer_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObject_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObjectContainer);
+ expect(obj).to.respondTo('addChild');
+ expect(obj).to.respondTo('addChildAt');
+ expect(obj).to.respondTo('swapChildren');
+ expect(obj).to.respondTo('getChildAt');
+ expect(obj).to.respondTo('removeChild');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('children.length', 0);
+}
diff --git a/test/lib/pixi/display/Sprite.js b/test/lib/pixi/display/Sprite.js
new file mode 100644
index 0000000..cc7a2d6
--- /dev/null
+++ b/test/lib/pixi/display/Sprite.js
@@ -0,0 +1,28 @@
+
+function pixi_display_Sprite_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Sprite);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', true);
+ expect(obj).to.have.property('stage', null);
+
+ expect(obj).to.have.property('anchor');
+ pixi_core_Point_confirm(obj.anchor, 0, 0);
+
+ expect(obj).to.have.property('blendMode', PIXI.blendModes.NORMAL);
+ expect(obj).to.have.property('width', 1); // TODO: is 1 expected
+ expect(obj).to.have.property('height', 1); // TODO: is 1 expected
+
+ // FIXME: Just make this a boolean that is always there
+ expect(!!obj.updateFrame).to.equal(obj.texture.baseTexture.hasLoaded);
+
+ expect(obj).to.have.property('texture');
+ pixi_textures_Texture_confirmNew(obj.texture, done);
+}
diff --git a/test/lib/pixi/extras/Strip.js b/test/lib/pixi/extras/Strip.js
new file mode 100644
index 0000000..8927a8a
--- /dev/null
+++ b/test/lib/pixi/extras/Strip.js
@@ -0,0 +1,12 @@
+
+function pixi_extras_Strip_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Strip);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ // TODO: Test properties
+}
diff --git a/test/lib/pixi/textures/Texture.js b/test/lib/pixi/textures/Texture.js
new file mode 100644
index 0000000..d5867b6
--- /dev/null
+++ b/test/lib/pixi/textures/Texture.js
@@ -0,0 +1,31 @@
+
+function pixi_textures_Texture_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ function confirmFrameDone() {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, obj.baseTexture.width, obj.baseTexture.height);
+
+ expect(obj).to.have.property('width', obj.baseTexture.width);
+ expect(obj).to.have.property('height', obj.baseTexture.height);
+ done();
+ }
+
+ expect(obj).to.be.an.instanceof(PIXI.Texture);
+ pixi_utils_EventTarget_like(obj);
+
+ expect(obj).to.have.property('baseTexture')
+ .and.to.be.an.instanceof(PIXI.BaseTexture);
+
+ expect(obj).to.have.property('scope', obj);
+
+ expect(obj).to.have.property('trim');
+ pixi_core_Point_confirm(obj.trim, 0, 0);
+
+ expect(obj).to.have.property('frame');
+ if (obj.baseTexture.hasLoaded) {
+ confirmFrameDone();
+ } else {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, 1, 1);
+ obj.addEventListener('update', confirmFrameDone);
+ }
+}
diff --git a/test/lib/pixi/utils/EventTarget.js b/test/lib/pixi/utils/EventTarget.js
new file mode 100644
index 0000000..7b1dcfa
--- /dev/null
+++ b/test/lib/pixi/utils/EventTarget.js
@@ -0,0 +1,8 @@
+
+function pixi_utils_EventTarget_like(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.respondTo('addEventListener');
+ expect(obj).to.respondTo('dispatchEvent');
+ expect(obj).to.respondTo('removeEventListener');
+}
diff --git a/test/lib/qunit-1.11.0.css b/test/lib/qunit-1.11.0.css
deleted file mode 100644
index d7fc0c8..0000000
--- a/test/lib/qunit-1.11.0.css
+++ /dev/null
@@ -1,244 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-/** Font Family and Sizes */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
- font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
-}
-
-#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
-#qunit-tests { font-size: smaller; }
-
-
-/** Resets */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter {
- margin: 0;
- padding: 0;
-}
-
-
-/** Header */
-
-#qunit-header {
- padding: 0.5em 0 0.5em 1em;
-
- color: #8699a4;
- background-color: #0d3349;
-
- font-size: 1.5em;
- line-height: 1em;
- font-weight: normal;
-
- border-radius: 5px 5px 0 0;
- -moz-border-radius: 5px 5px 0 0;
- -webkit-border-top-right-radius: 5px;
- -webkit-border-top-left-radius: 5px;
-}
-
-#qunit-header a {
- text-decoration: none;
- color: #c2ccd1;
-}
-
-#qunit-header a:hover,
-#qunit-header a:focus {
- color: #fff;
-}
-
-#qunit-testrunner-toolbar label {
- display: inline-block;
- padding: 0 .5em 0 .1em;
-}
-
-#qunit-banner {
- height: 5px;
-}
-
-#qunit-testrunner-toolbar {
- padding: 0.5em 0 0.5em 2em;
- color: #5E740B;
- background-color: #eee;
- overflow: hidden;
-}
-
-#qunit-userAgent {
- padding: 0.5em 0 0.5em 2.5em;
- background-color: #2b81af;
- color: #fff;
- text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
-}
-
-#qunit-modulefilter-container {
- float: right;
-}
-
-/** Tests: Pass/Fail */
-
-#qunit-tests {
- list-style-position: inside;
-}
-
-#qunit-tests li {
- padding: 0.4em 0.5em 0.4em 2.5em;
- border-bottom: 1px solid #fff;
- list-style-position: inside;
-}
-
-#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running {
- display: none;
-}
-
-#qunit-tests li strong {
- cursor: pointer;
-}
-
-#qunit-tests li a {
- padding: 0.5em;
- color: #c2ccd1;
- text-decoration: none;
-}
-#qunit-tests li a:hover,
-#qunit-tests li a:focus {
- color: #000;
-}
-
-#qunit-tests li .runtime {
- float: right;
- font-size: smaller;
-}
-
-.qunit-assert-list {
- margin-top: 0.5em;
- padding: 0.5em;
-
- background-color: #fff;
-
- border-radius: 5px;
- -moz-border-radius: 5px;
- -webkit-border-radius: 5px;
-}
-
-.qunit-collapsed {
- display: none;
-}
-
-#qunit-tests table {
- border-collapse: collapse;
- margin-top: .2em;
-}
-
-#qunit-tests th {
- text-align: right;
- vertical-align: top;
- padding: 0 .5em 0 0;
-}
-
-#qunit-tests td {
- vertical-align: top;
-}
-
-#qunit-tests pre {
- margin: 0;
- white-space: pre-wrap;
- word-wrap: break-word;
-}
-
-#qunit-tests del {
- background-color: #e0f2be;
- color: #374e0c;
- text-decoration: none;
-}
-
-#qunit-tests ins {
- background-color: #ffcaca;
- color: #500;
- text-decoration: none;
-}
-
-/*** Test Counts */
-
-#qunit-tests b.counts { color: black; }
-#qunit-tests b.passed { color: #5E740B; }
-#qunit-tests b.failed { color: #710909; }
-
-#qunit-tests li li {
- padding: 5px;
- background-color: #fff;
- border-bottom: none;
- list-style-position: inside;
-}
-
-/*** Passing Styles */
-
-#qunit-tests li li.pass {
- color: #3c510c;
- background-color: #fff;
- border-left: 10px solid #C6E746;
-}
-
-#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
-#qunit-tests .pass .test-name { color: #366097; }
-
-#qunit-tests .pass .test-actual,
-#qunit-tests .pass .test-expected { color: #999999; }
-
-#qunit-banner.qunit-pass { background-color: #C6E746; }
-
-/*** Failing Styles */
-
-#qunit-tests li li.fail {
- color: #710909;
- background-color: #fff;
- border-left: 10px solid #EE5757;
- white-space: pre;
-}
-
-#qunit-tests > li:last-child {
- border-radius: 0 0 5px 5px;
- -moz-border-radius: 0 0 5px 5px;
- -webkit-border-bottom-right-radius: 5px;
- -webkit-border-bottom-left-radius: 5px;
-}
-
-#qunit-tests .fail { color: #000000; background-color: #EE5757; }
-#qunit-tests .fail .test-name,
-#qunit-tests .fail .module-name { color: #000000; }
-
-#qunit-tests .fail .test-actual { color: #EE5757; }
-#qunit-tests .fail .test-expected { color: green; }
-
-#qunit-banner.qunit-fail { background-color: #EE5757; }
-
-
-/** Result */
-
-#qunit-testresult {
- padding: 0.5em 0.5em 0.5em 2.5em;
-
- color: #2b81af;
- background-color: #D2E0E6;
-
- border-bottom: 1px solid white;
-}
-#qunit-testresult .module-name {
- font-weight: bold;
-}
-
-/** Fixture */
-
-#qunit-fixture {
- position: absolute;
- top: -10000px;
- left: -10000px;
- width: 1000px;
- height: 1000px;
-}
diff --git a/test/lib/qunit-1.11.0.js b/test/lib/qunit-1.11.0.js
deleted file mode 100644
index 302545f..0000000
--- a/test/lib/qunit-1.11.0.js
+++ /dev/null
@@ -1,2152 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-(function( window ) {
-
-var QUnit,
- assert,
- config,
- onErrorFnPrev,
- testId = 0,
- fileName = (sourceFromStacktrace( 0 ) || "" ).replace(/(:\d+)+\)?/, "").replace(/.+\//, ""),
- toString = Object.prototype.toString,
- hasOwn = Object.prototype.hasOwnProperty,
- // Keep a local reference to Date (GH-283)
- Date = window.Date,
- defined = {
- setTimeout: typeof window.setTimeout !== "undefined",
- sessionStorage: (function() {
- var x = "qunit-test-string";
- try {
- sessionStorage.setItem( x, x );
- sessionStorage.removeItem( x );
- return true;
- } catch( e ) {
- return false;
- }
- }())
- },
- /**
- * Provides a normalized error string, correcting an issue
- * with IE 7 (and prior) where Error.prototype.toString is
- * not properly implemented
- *
- * Based on http://es5.github.com/#x15.11.4.4
- *
- * @param {String|Error} error
- * @return {String} error message
- */
- errorString = function( error ) {
- var name, message,
- errorString = error.toString();
- if ( errorString.substring( 0, 7 ) === "[object" ) {
- name = error.name ? error.name.toString() : "Error";
- message = error.message ? error.message.toString() : "";
- if ( name && message ) {
- return name + ": " + message;
- } else if ( name ) {
- return name;
- } else if ( message ) {
- return message;
- } else {
- return "Error";
- }
- } else {
- return errorString;
- }
- },
- /**
- * Makes a clone of an object using only Array or Object as base,
- * and copies over the own enumerable properties.
- *
- * @param {Object} obj
- * @return {Object} New object with only the own properties (recursively).
- */
- objectValues = function( obj ) {
- // Grunt 0.3.x uses an older version of jshint that still has jshint/jshint#392.
- /*jshint newcap: false */
- var key, val,
- vals = QUnit.is( "array", obj ) ? [] : {};
- for ( key in obj ) {
- if ( hasOwn.call( obj, key ) ) {
- val = obj[key];
- vals[key] = val === Object(val) ? objectValues(val) : val;
- }
- }
- return vals;
- };
-
-function Test( settings ) {
- extend( this, settings );
- this.assertions = [];
- this.testNumber = ++Test.count;
-}
-
-Test.count = 0;
-
-Test.prototype = {
- init: function() {
- var a, b, li,
- tests = id( "qunit-tests" );
-
- if ( tests ) {
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml;
-
- // `a` initialized at top of scope
- a = document.createElement( "a" );
- a.innerHTML = "Rerun";
- a.href = QUnit.url({ testNumber: this.testNumber });
-
- li = document.createElement( "li" );
- li.appendChild( b );
- li.appendChild( a );
- li.className = "running";
- li.id = this.id = "qunit-test-output" + testId++;
-
- tests.appendChild( li );
- }
- },
- setup: function() {
- if ( this.module !== config.previousModule ) {
- if ( config.previousModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.previousModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
- config.previousModule = this.module;
- config.moduleStats = { all: 0, bad: 0 };
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- } else if ( config.autorun ) {
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- }
-
- config.current = this;
-
- this.testEnvironment = extend({
- setup: function() {},
- teardown: function() {}
- }, this.moduleTestEnvironment );
-
- this.started = +new Date();
- runLoggingCallbacks( "testStart", QUnit, {
- name: this.testName,
- module: this.module
- });
-
- // allow utility functions to access the current test environment
- // TODO why??
- QUnit.current_testEnvironment = this.testEnvironment;
-
- if ( !config.pollution ) {
- saveGlobal();
- }
- if ( config.notrycatch ) {
- this.testEnvironment.setup.call( this.testEnvironment );
- return;
- }
- try {
- this.testEnvironment.setup.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Setup failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- },
- run: function() {
- config.current = this;
-
- var running = id( "qunit-testresult" );
-
- if ( running ) {
- running.innerHTML = "Running:
" + this.nameHtml;
- }
-
- if ( this.async ) {
- QUnit.stop();
- }
-
- this.callbackStarted = +new Date();
-
- if ( config.notrycatch ) {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- return;
- }
-
- try {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- } catch( e ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
-
- QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + " " + this.stack + ": " + ( e.message || e ), extractStacktrace( e, 0 ) );
- // else next test will carry the responsibility
- saveGlobal();
-
- // Restart the tests if they're blocking
- if ( config.blocking ) {
- QUnit.start();
- }
- }
- },
- teardown: function() {
- config.current = this;
- if ( config.notrycatch ) {
- if ( typeof this.callbackRuntime === "undefined" ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
- }
- this.testEnvironment.teardown.call( this.testEnvironment );
- return;
- } else {
- try {
- this.testEnvironment.teardown.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Teardown failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- }
- checkPollution();
- },
- finish: function() {
- config.current = this;
- if ( config.requireExpects && this.expected === null ) {
- QUnit.pushFailure( "Expected number of assertions to be defined, but expect() was not called.", this.stack );
- } else if ( this.expected !== null && this.expected !== this.assertions.length ) {
- QUnit.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack );
- } else if ( this.expected === null && !this.assertions.length ) {
- QUnit.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions.", this.stack );
- }
-
- var i, assertion, a, b, time, li, ol,
- test = this,
- good = 0,
- bad = 0,
- tests = id( "qunit-tests" );
-
- this.runtime = +new Date() - this.started;
- config.stats.all += this.assertions.length;
- config.moduleStats.all += this.assertions.length;
-
- if ( tests ) {
- ol = document.createElement( "ol" );
- ol.className = "qunit-assert-list";
-
- for ( i = 0; i < this.assertions.length; i++ ) {
- assertion = this.assertions[i];
-
- li = document.createElement( "li" );
- li.className = assertion.result ? "pass" : "fail";
- li.innerHTML = assertion.message || ( assertion.result ? "okay" : "failed" );
- ol.appendChild( li );
-
- if ( assertion.result ) {
- good++;
- } else {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
-
- // store result when possible
- if ( QUnit.config.reorder && defined.sessionStorage ) {
- if ( bad ) {
- sessionStorage.setItem( "qunit-test-" + this.module + "-" + this.testName, bad );
- } else {
- sessionStorage.removeItem( "qunit-test-" + this.module + "-" + this.testName );
- }
- }
-
- if ( bad === 0 ) {
- addClass( ol, "qunit-collapsed" );
- }
-
- // `b` initialized at top of scope
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml + " (" + bad + ", " + good + ", " + this.assertions.length + ")";
-
- addEvent(b, "click", function() {
- var next = b.parentNode.lastChild,
- collapsed = hasClass( next, "qunit-collapsed" );
- ( collapsed ? removeClass : addClass )( next, "qunit-collapsed" );
- });
-
- addEvent(b, "dblclick", function( e ) {
- var target = e && e.target ? e.target : window.event.srcElement;
- if ( target.nodeName.toLowerCase() === "span" || target.nodeName.toLowerCase() === "b" ) {
- target = target.parentNode;
- }
- if ( window.location && target.nodeName.toLowerCase() === "strong" ) {
- window.location = QUnit.url({ testNumber: test.testNumber });
- }
- });
-
- // `time` initialized at top of scope
- time = document.createElement( "span" );
- time.className = "runtime";
- time.innerHTML = this.runtime + " ms";
-
- // `li` initialized at top of scope
- li = id( this.id );
- li.className = bad ? "fail" : "pass";
- li.removeChild( li.firstChild );
- a = li.firstChild;
- li.appendChild( b );
- li.appendChild( a );
- li.appendChild( time );
- li.appendChild( ol );
-
- } else {
- for ( i = 0; i < this.assertions.length; i++ ) {
- if ( !this.assertions[i].result ) {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
- }
-
- runLoggingCallbacks( "testDone", QUnit, {
- name: this.testName,
- module: this.module,
- failed: bad,
- passed: this.assertions.length - bad,
- total: this.assertions.length,
- duration: this.runtime
- });
-
- QUnit.reset();
-
- config.current = undefined;
- },
-
- queue: function() {
- var bad,
- test = this;
-
- synchronize(function() {
- test.init();
- });
- function run() {
- // each of these can by async
- synchronize(function() {
- test.setup();
- });
- synchronize(function() {
- test.run();
- });
- synchronize(function() {
- test.teardown();
- });
- synchronize(function() {
- test.finish();
- });
- }
-
- // `bad` initialized at top of scope
- // defer when previous test run passed, if storage is available
- bad = QUnit.config.reorder && defined.sessionStorage &&
- +sessionStorage.getItem( "qunit-test-" + this.module + "-" + this.testName );
-
- if ( bad ) {
- run();
- } else {
- synchronize( run, true );
- }
- }
-};
-
-// Root QUnit object.
-// `QUnit` initialized at top of scope
-QUnit = {
-
- // call on start of module test to prepend name to all tests
- module: function( name, testEnvironment ) {
- config.currentModule = name;
- config.currentModuleTestEnvironment = testEnvironment;
- config.modules[name] = true;
- },
-
- asyncTest: function( testName, expected, callback ) {
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- QUnit.test( testName, expected, callback, true );
- },
-
- test: function( testName, expected, callback, async ) {
- var test,
- nameHtml = "" + escapeText( testName ) + "";
-
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- if ( config.currentModule ) {
- nameHtml = "" + escapeText( config.currentModule ) + ": " + nameHtml;
- }
-
- test = new Test({
- nameHtml: nameHtml,
- testName: testName,
- expected: expected,
- async: async,
- callback: callback,
- module: config.currentModule,
- moduleTestEnvironment: config.currentModuleTestEnvironment,
- stack: sourceFromStacktrace( 2 )
- });
-
- if ( !validTest( test ) ) {
- return;
- }
-
- test.queue();
- },
-
- // Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through.
- expect: function( asserts ) {
- if (arguments.length === 1) {
- config.current.expected = asserts;
- } else {
- return config.current.expected;
- }
- },
-
- start: function( count ) {
- // QUnit hasn't been initialized yet.
- // Note: RequireJS (et al) may delay onLoad
- if ( config.semaphore === undefined ) {
- QUnit.begin(function() {
- // This is triggered at the top of QUnit.load, push start() to the event loop, to allow QUnit.load to finish first
- setTimeout(function() {
- QUnit.start( count );
- });
- });
- return;
- }
-
- config.semaphore -= count || 1;
- // don't start until equal number of stop-calls
- if ( config.semaphore > 0 ) {
- return;
- }
- // ignore if start is called more often then stop
- if ( config.semaphore < 0 ) {
- config.semaphore = 0;
- QUnit.pushFailure( "Called start() while already started (QUnit.config.semaphore was 0 already)", null, sourceFromStacktrace(2) );
- return;
- }
- // A slight delay, to avoid any current callbacks
- if ( defined.setTimeout ) {
- window.setTimeout(function() {
- if ( config.semaphore > 0 ) {
- return;
- }
- if ( config.timeout ) {
- clearTimeout( config.timeout );
- }
-
- config.blocking = false;
- process( true );
- }, 13);
- } else {
- config.blocking = false;
- process( true );
- }
- },
-
- stop: function( count ) {
- config.semaphore += count || 1;
- config.blocking = true;
-
- if ( config.testTimeout && defined.setTimeout ) {
- clearTimeout( config.timeout );
- config.timeout = window.setTimeout(function() {
- QUnit.ok( false, "Test timed out" );
- config.semaphore = 1;
- QUnit.start();
- }, config.testTimeout );
- }
- }
-};
-
-// `assert` initialized at top of scope
-// Asssert helpers
-// All of these must either call QUnit.push() or manually do:
-// - runLoggingCallbacks( "log", .. );
-// - config.current.assertions.push({ .. });
-// We attach it to the QUnit object *after* we expose the public API,
-// otherwise `assert` will become a global variable in browsers (#341).
-assert = {
- /**
- * Asserts rough true-ish result.
- * @name ok
- * @function
- * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" );
- */
- ok: function( result, msg ) {
- if ( !config.current ) {
- throw new Error( "ok() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
- result = !!result;
-
- var source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: msg
- };
-
- msg = escapeText( msg || (result ? "okay" : "failed" ) );
- msg = "" + msg + "";
-
- if ( !result ) {
- source = sourceFromStacktrace( 2 );
- if ( source ) {
- details.source = source;
- msg += "Source: | " + escapeText( source ) + " |
---|
";
- }
- }
- runLoggingCallbacks( "log", QUnit, details );
- config.current.assertions.push({
- result: result,
- message: msg
- });
- },
-
- /**
- * Assert that the first two arguments are equal, with an optional message.
- * Prints out both actual and expected values.
- * @name equal
- * @function
- * @example equal( format( "Received {0} bytes.", 2), "Received 2 bytes.", "format() replaces {0} with next argument" );
- */
- equal: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected == actual, actual, expected, message );
- },
-
- /**
- * @name notEqual
- * @function
- */
- notEqual: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected != actual, actual, expected, message );
- },
-
- /**
- * @name propEqual
- * @function
- */
- propEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notPropEqual
- * @function
- */
- notPropEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name deepEqual
- * @function
- */
- deepEqual: function( actual, expected, message ) {
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notDeepEqual
- * @function
- */
- notDeepEqual: function( actual, expected, message ) {
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name strictEqual
- * @function
- */
- strictEqual: function( actual, expected, message ) {
- QUnit.push( expected === actual, actual, expected, message );
- },
-
- /**
- * @name notStrictEqual
- * @function
- */
- notStrictEqual: function( actual, expected, message ) {
- QUnit.push( expected !== actual, actual, expected, message );
- },
-
- "throws": function( block, expected, message ) {
- var actual,
- expectedOutput = expected,
- ok = false;
-
- // 'expected' is optional
- if ( typeof expected === "string" ) {
- message = expected;
- expected = null;
- }
-
- config.current.ignoreGlobalErrors = true;
- try {
- block.call( config.current.testEnvironment );
- } catch (e) {
- actual = e;
- }
- config.current.ignoreGlobalErrors = false;
-
- if ( actual ) {
- // we don't want to validate thrown error
- if ( !expected ) {
- ok = true;
- expectedOutput = null;
- // expected is a regexp
- } else if ( QUnit.objectType( expected ) === "regexp" ) {
- ok = expected.test( errorString( actual ) );
- // expected is a constructor
- } else if ( actual instanceof expected ) {
- ok = true;
- // expected is a validation function which returns true is validation passed
- } else if ( expected.call( {}, actual ) === true ) {
- expectedOutput = null;
- ok = true;
- }
-
- QUnit.push( ok, actual, expectedOutput, message );
- } else {
- QUnit.pushFailure( message, null, 'No exception was thrown.' );
- }
- }
-};
-
-/**
- * @deprecate since 1.8.0
- * Kept assertion helpers in root for backwards compatibility.
- */
-extend( QUnit, assert );
-
-/**
- * @deprecated since 1.9.0
- * Kept root "raises()" for backwards compatibility.
- * (Note that we don't introduce assert.raises).
- */
-QUnit.raises = assert[ "throws" ];
-
-/**
- * @deprecated since 1.0.0, replaced with error pushes since 1.3.0
- * Kept to avoid TypeErrors for undefined methods.
- */
-QUnit.equals = function() {
- QUnit.push( false, false, false, "QUnit.equals has been deprecated since 2009 (e88049a0), use QUnit.equal instead" );
-};
-QUnit.same = function() {
- QUnit.push( false, false, false, "QUnit.same has been deprecated since 2009 (e88049a0), use QUnit.deepEqual instead" );
-};
-
-// We want access to the constructor's prototype
-(function() {
- function F() {}
- F.prototype = QUnit;
- QUnit = new F();
- // Make F QUnit's constructor so that we can add to the prototype later
- QUnit.constructor = F;
-}());
-
-/**
- * Config object: Maintain internal state
- * Later exposed as QUnit.config
- * `config` initialized at top of scope
- */
-config = {
- // The queue of tests to run
- queue: [],
-
- // block until document ready
- blocking: true,
-
- // when enabled, show only failing tests
- // gets persisted through sessionStorage and can be changed in UI via checkbox
- hidepassed: false,
-
- // by default, run previously failed tests first
- // very useful in combination with "Hide passed tests" checked
- reorder: true,
-
- // by default, modify document.title when suite is done
- altertitle: true,
-
- // when enabled, all tests must call expect()
- requireExpects: false,
-
- // add checkboxes that are persisted in the query-string
- // when enabled, the id is set to `true` as a `QUnit.config` property
- urlConfig: [
- {
- id: "noglobals",
- label: "Check for Globals",
- tooltip: "Enabling this will test if any test introduces new properties on the `window` object. Stored as query-strings."
- },
- {
- id: "notrycatch",
- label: "No try-catch",
- tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging exceptions in IE reasonable. Stored as query-strings."
- }
- ],
-
- // Set of all modules.
- modules: {},
-
- // logging callback queues
- begin: [],
- done: [],
- log: [],
- testStart: [],
- testDone: [],
- moduleStart: [],
- moduleDone: []
-};
-
-// Export global variables, unless an 'exports' object exists,
-// in that case we assume we're in CommonJS (dealt with on the bottom of the script)
-if ( typeof exports === "undefined" ) {
- extend( window, QUnit );
-
- // Expose QUnit object
- window.QUnit = QUnit;
-}
-
-// Initialize more QUnit.config and QUnit.urlParams
-(function() {
- var i,
- location = window.location || { search: "", protocol: "file:" },
- params = location.search.slice( 1 ).split( "&" ),
- length = params.length,
- urlParams = {},
- current;
-
- if ( params[ 0 ] ) {
- for ( i = 0; i < length; i++ ) {
- current = params[ i ].split( "=" );
- current[ 0 ] = decodeURIComponent( current[ 0 ] );
- // allow just a key to turn on a flag, e.g., test.html?noglobals
- current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true;
- urlParams[ current[ 0 ] ] = current[ 1 ];
- }
- }
-
- QUnit.urlParams = urlParams;
-
- // String search anywhere in moduleName+testName
- config.filter = urlParams.filter;
-
- // Exact match of the module name
- config.module = urlParams.module;
-
- config.testNumber = parseInt( urlParams.testNumber, 10 ) || null;
-
- // Figure out if we're running the tests from a server or not
- QUnit.isLocal = location.protocol === "file:";
-}());
-
-// Extend QUnit object,
-// these after set here because they should not be exposed as global functions
-extend( QUnit, {
- assert: assert,
-
- config: config,
-
- // Initialize the configuration options
- init: function() {
- extend( config, {
- stats: { all: 0, bad: 0 },
- moduleStats: { all: 0, bad: 0 },
- started: +new Date(),
- updateRate: 1000,
- blocking: false,
- autostart: true,
- autorun: false,
- filter: "",
- queue: [],
- semaphore: 1
- });
-
- var tests, banner, result,
- qunit = id( "qunit" );
-
- if ( qunit ) {
- qunit.innerHTML =
- "" +
- "" +
- "" +
- "" +
- "
";
- }
-
- tests = id( "qunit-tests" );
- banner = id( "qunit-banner" );
- result = id( "qunit-testresult" );
-
- if ( tests ) {
- tests.innerHTML = "";
- }
-
- if ( banner ) {
- banner.className = "";
- }
-
- if ( result ) {
- result.parentNode.removeChild( result );
- }
-
- if ( tests ) {
- result = document.createElement( "p" );
- result.id = "qunit-testresult";
- result.className = "result";
- tests.parentNode.insertBefore( result, tests );
- result.innerHTML = "Running...
";
- }
- },
-
- // Resets the test setup. Useful for tests that modify the DOM.
- reset: function() {
- var fixture = id( "qunit-fixture" );
- if ( fixture ) {
- fixture.innerHTML = config.fixture;
- }
- },
-
- // Trigger an event on an element.
- // @example triggerEvent( document.body, "click" );
- triggerEvent: function( elem, type, event ) {
- if ( document.createEvent ) {
- event = document.createEvent( "MouseEvents" );
- event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView,
- 0, 0, 0, 0, 0, false, false, false, false, 0, null);
-
- elem.dispatchEvent( event );
- } else if ( elem.fireEvent ) {
- elem.fireEvent( "on" + type );
- }
- },
-
- // Safe object type checking
- is: function( type, obj ) {
- return QUnit.objectType( obj ) === type;
- },
-
- objectType: function( obj ) {
- if ( typeof obj === "undefined" ) {
- return "undefined";
- // consider: typeof null === object
- }
- if ( obj === null ) {
- return "null";
- }
-
- var match = toString.call( obj ).match(/^\[object\s(.*)\]$/),
- type = match && match[1] || "";
-
- switch ( type ) {
- case "Number":
- if ( isNaN(obj) ) {
- return "nan";
- }
- return "number";
- case "String":
- case "Boolean":
- case "Array":
- case "Date":
- case "RegExp":
- case "Function":
- return type.toLowerCase();
- }
- if ( typeof obj === "object" ) {
- return "object";
- }
- return undefined;
- },
-
- push: function( result, actual, expected, message ) {
- if ( !config.current ) {
- throw new Error( "assertion outside test context, was " + sourceFromStacktrace() );
- }
-
- var output, source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: message,
- actual: actual,
- expected: expected
- };
-
- message = escapeText( message ) || ( result ? "okay" : "failed" );
- message = "" + message + "";
- output = message;
-
- if ( !result ) {
- expected = escapeText( QUnit.jsDump.parse(expected) );
- actual = escapeText( QUnit.jsDump.parse(actual) );
- output += "Expected: | " + expected + " |
";
-
- if ( actual !== expected ) {
- output += "Result: | " + actual + " |
";
- output += "Diff: | " + QUnit.diff( expected, actual ) + " |
";
- }
-
- source = sourceFromStacktrace();
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
- }
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: !!result,
- message: output
- });
- },
-
- pushFailure: function( message, source, actual ) {
- if ( !config.current ) {
- throw new Error( "pushFailure() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
-
- var output,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: false,
- message: message
- };
-
- message = escapeText( message ) || "error";
- message = "" + message + "";
- output = message;
-
- output += "";
-
- if ( actual ) {
- output += "Result: | " + escapeText( actual ) + " |
";
- }
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: false,
- message: output
- });
- },
-
- url: function( params ) {
- params = extend( extend( {}, QUnit.urlParams ), params );
- var key,
- querystring = "?";
-
- for ( key in params ) {
- if ( !hasOwn.call( params, key ) ) {
- continue;
- }
- querystring += encodeURIComponent( key ) + "=" +
- encodeURIComponent( params[ key ] ) + "&";
- }
- return window.location.protocol + "//" + window.location.host +
- window.location.pathname + querystring.slice( 0, -1 );
- },
-
- extend: extend,
- id: id,
- addEvent: addEvent
- // load, equiv, jsDump, diff: Attached later
-});
-
-/**
- * @deprecated: Created for backwards compatibility with test runner that set the hook function
- * into QUnit.{hook}, instead of invoking it and passing the hook function.
- * QUnit.constructor is set to the empty F() above so that we can add to it's prototype here.
- * Doing this allows us to tell if the following methods have been overwritten on the actual
- * QUnit object.
- */
-extend( QUnit.constructor.prototype, {
-
- // Logging callbacks; all receive a single argument with the listed properties
- // run test/logs.html for any related changes
- begin: registerLoggingCallback( "begin" ),
-
- // done: { failed, passed, total, runtime }
- done: registerLoggingCallback( "done" ),
-
- // log: { result, actual, expected, message }
- log: registerLoggingCallback( "log" ),
-
- // testStart: { name }
- testStart: registerLoggingCallback( "testStart" ),
-
- // testDone: { name, failed, passed, total, duration }
- testDone: registerLoggingCallback( "testDone" ),
-
- // moduleStart: { name }
- moduleStart: registerLoggingCallback( "moduleStart" ),
-
- // moduleDone: { name, failed, passed, total }
- moduleDone: registerLoggingCallback( "moduleDone" )
-});
-
-if ( typeof document === "undefined" || document.readyState === "complete" ) {
- config.autorun = true;
-}
-
-QUnit.load = function() {
- runLoggingCallbacks( "begin", QUnit, {} );
-
- // Initialize the config, saving the execution queue
- var banner, filter, i, label, len, main, ol, toolbar, userAgent, val,
- urlConfigCheckboxesContainer, urlConfigCheckboxes, moduleFilter,
- numModules = 0,
- moduleFilterHtml = "",
- urlConfigHtml = "",
- oldconfig = extend( {}, config );
-
- QUnit.init();
- extend(config, oldconfig);
-
- config.blocking = false;
-
- len = config.urlConfig.length;
-
- for ( i = 0; i < len; i++ ) {
- val = config.urlConfig[i];
- if ( typeof val === "string" ) {
- val = {
- id: val,
- label: val,
- tooltip: "[no tooltip available]"
- };
- }
- config[ val.id ] = QUnit.urlParams[ val.id ];
- urlConfigHtml += "";
- }
-
- moduleFilterHtml += "";
-
- // `userAgent` initialized at top of scope
- userAgent = id( "qunit-userAgent" );
- if ( userAgent ) {
- userAgent.innerHTML = navigator.userAgent;
- }
-
- // `banner` initialized at top of scope
- banner = id( "qunit-header" );
- if ( banner ) {
- banner.innerHTML = "" + banner.innerHTML + " ";
- }
-
- // `toolbar` initialized at top of scope
- toolbar = id( "qunit-testrunner-toolbar" );
- if ( toolbar ) {
- // `filter` initialized at top of scope
- filter = document.createElement( "input" );
- filter.type = "checkbox";
- filter.id = "qunit-filter-pass";
-
- addEvent( filter, "click", function() {
- var tmp,
- ol = document.getElementById( "qunit-tests" );
-
- if ( filter.checked ) {
- ol.className = ol.className + " hidepass";
- } else {
- tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " ";
- ol.className = tmp.replace( / hidepass /, " " );
- }
- if ( defined.sessionStorage ) {
- if (filter.checked) {
- sessionStorage.setItem( "qunit-filter-passed-tests", "true" );
- } else {
- sessionStorage.removeItem( "qunit-filter-passed-tests" );
- }
- }
- });
-
- if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem( "qunit-filter-passed-tests" ) ) {
- filter.checked = true;
- // `ol` initialized at top of scope
- ol = document.getElementById( "qunit-tests" );
- ol.className = ol.className + " hidepass";
- }
- toolbar.appendChild( filter );
-
- // `label` initialized at top of scope
- label = document.createElement( "label" );
- label.setAttribute( "for", "qunit-filter-pass" );
- label.setAttribute( "title", "Only show tests and assertons that fail. Stored in sessionStorage." );
- label.innerHTML = "Hide passed tests";
- toolbar.appendChild( label );
-
- urlConfigCheckboxesContainer = document.createElement("span");
- urlConfigCheckboxesContainer.innerHTML = urlConfigHtml;
- urlConfigCheckboxes = urlConfigCheckboxesContainer.getElementsByTagName("input");
- // For oldIE support:
- // * Add handlers to the individual elements instead of the container
- // * Use "click" instead of "change"
- // * Fallback from event.target to event.srcElement
- addEvents( urlConfigCheckboxes, "click", function( event ) {
- var params = {},
- target = event.target || event.srcElement;
- params[ target.name ] = target.checked ? true : undefined;
- window.location = QUnit.url( params );
- });
- toolbar.appendChild( urlConfigCheckboxesContainer );
-
- if (numModules > 1) {
- moduleFilter = document.createElement( 'span' );
- moduleFilter.setAttribute( 'id', 'qunit-modulefilter-container' );
- moduleFilter.innerHTML = moduleFilterHtml;
- addEvent( moduleFilter.lastChild, "change", function() {
- var selectBox = moduleFilter.getElementsByTagName("select")[0],
- selectedModule = decodeURIComponent(selectBox.options[selectBox.selectedIndex].value);
-
- window.location = QUnit.url( { module: ( selectedModule === "" ) ? undefined : selectedModule } );
- });
- toolbar.appendChild(moduleFilter);
- }
- }
-
- // `main` initialized at top of scope
- main = id( "qunit-fixture" );
- if ( main ) {
- config.fixture = main.innerHTML;
- }
-
- if ( config.autostart ) {
- QUnit.start();
- }
-};
-
-addEvent( window, "load", QUnit.load );
-
-// `onErrorFnPrev` initialized at top of scope
-// Preserve other handlers
-onErrorFnPrev = window.onerror;
-
-// Cover uncaught exceptions
-// Returning true will surpress the default browser handler,
-// returning false will let it run.
-window.onerror = function ( error, filePath, linerNr ) {
- var ret = false;
- if ( onErrorFnPrev ) {
- ret = onErrorFnPrev( error, filePath, linerNr );
- }
-
- // Treat return value as window.onerror itself does,
- // Only do our handling if not surpressed.
- if ( ret !== true ) {
- if ( QUnit.config.current ) {
- if ( QUnit.config.current.ignoreGlobalErrors ) {
- return true;
- }
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- } else {
- QUnit.test( "global failure", extend( function() {
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- }, { validTest: validTest } ) );
- }
- return false;
- }
-
- return ret;
-};
-
-function done() {
- config.autorun = true;
-
- // Log the last module results
- if ( config.currentModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.currentModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
-
- var i, key,
- banner = id( "qunit-banner" ),
- tests = id( "qunit-tests" ),
- runtime = +new Date() - config.started,
- passed = config.stats.all - config.stats.bad,
- html = [
- "Tests completed in ",
- runtime,
- " milliseconds.
",
- "",
- passed,
- " assertions of ",
- config.stats.all,
- " passed, ",
- config.stats.bad,
- " failed."
- ].join( "" );
-
- if ( banner ) {
- banner.className = ( config.stats.bad ? "qunit-fail" : "qunit-pass" );
- }
-
- if ( tests ) {
- id( "qunit-testresult" ).innerHTML = html;
- }
-
- if ( config.altertitle && typeof document !== "undefined" && document.title ) {
- // show ✖ for good, ✔ for bad suite result in title
- // use escape sequences in case file gets loaded with non-utf-8-charset
- document.title = [
- ( config.stats.bad ? "\u2716" : "\u2714" ),
- document.title.replace( /^[\u2714\u2716] /i, "" )
- ].join( " " );
- }
-
- // clear own sessionStorage items if all tests passed
- if ( config.reorder && defined.sessionStorage && config.stats.bad === 0 ) {
- // `key` & `i` initialized at top of scope
- for ( i = 0; i < sessionStorage.length; i++ ) {
- key = sessionStorage.key( i++ );
- if ( key.indexOf( "qunit-test-" ) === 0 ) {
- sessionStorage.removeItem( key );
- }
- }
- }
-
- // scroll back to top to show results
- if ( window.scrollTo ) {
- window.scrollTo(0, 0);
- }
-
- runLoggingCallbacks( "done", QUnit, {
- failed: config.stats.bad,
- passed: passed,
- total: config.stats.all,
- runtime: runtime
- });
-}
-
-/** @return Boolean: true if this test should be ran */
-function validTest( test ) {
- var include,
- filter = config.filter && config.filter.toLowerCase(),
- module = config.module && config.module.toLowerCase(),
- fullName = (test.module + ": " + test.testName).toLowerCase();
-
- // Internally-generated tests are always valid
- if ( test.callback && test.callback.validTest === validTest ) {
- delete test.callback.validTest;
- return true;
- }
-
- if ( config.testNumber ) {
- return test.testNumber === config.testNumber;
- }
-
- if ( module && ( !test.module || test.module.toLowerCase() !== module ) ) {
- return false;
- }
-
- if ( !filter ) {
- return true;
- }
-
- include = filter.charAt( 0 ) !== "!";
- if ( !include ) {
- filter = filter.slice( 1 );
- }
-
- // If the filter matches, we need to honour include
- if ( fullName.indexOf( filter ) !== -1 ) {
- return include;
- }
-
- // Otherwise, do the opposite
- return !include;
-}
-
-// so far supports only Firefox, Chrome and Opera (buggy), Safari (for real exceptions)
-// Later Safari and IE10 are supposed to support error.stack as well
-// See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack
-function extractStacktrace( e, offset ) {
- offset = offset === undefined ? 3 : offset;
-
- var stack, include, i;
-
- if ( e.stacktrace ) {
- // Opera
- return e.stacktrace.split( "\n" )[ offset + 3 ];
- } else if ( e.stack ) {
- // Firefox, Chrome
- stack = e.stack.split( "\n" );
- if (/^error$/i.test( stack[0] ) ) {
- stack.shift();
- }
- if ( fileName ) {
- include = [];
- for ( i = offset; i < stack.length; i++ ) {
- if ( stack[ i ].indexOf( fileName ) !== -1 ) {
- break;
- }
- include.push( stack[ i ] );
- }
- if ( include.length ) {
- return include.join( "\n" );
- }
- }
- return stack[ offset ];
- } else if ( e.sourceURL ) {
- // Safari, PhantomJS
- // hopefully one day Safari provides actual stacktraces
- // exclude useless self-reference for generated Error objects
- if ( /qunit.js$/.test( e.sourceURL ) ) {
- return;
- }
- // for actual exceptions, this is useful
- return e.sourceURL + ":" + e.line;
- }
-}
-function sourceFromStacktrace( offset ) {
- try {
- throw new Error();
- } catch ( e ) {
- return extractStacktrace( e, offset );
- }
-}
-
-/**
- * Escape text for attribute or text content.
- */
-function escapeText( s ) {
- if ( !s ) {
- return "";
- }
- s = s + "";
- // Both single quotes and double quotes (for attributes)
- return s.replace( /['"<>&]/g, function( s ) {
- switch( s ) {
- case '\'':
- return ''';
- case '"':
- return '"';
- case '<':
- return '<';
- case '>':
- return '>';
- case '&':
- return '&';
- }
- });
-}
-
-function synchronize( callback, last ) {
- config.queue.push( callback );
-
- if ( config.autorun && !config.blocking ) {
- process( last );
- }
-}
-
-function process( last ) {
- function next() {
- process( last );
- }
- var start = new Date().getTime();
- config.depth = config.depth ? config.depth + 1 : 1;
-
- while ( config.queue.length && !config.blocking ) {
- if ( !defined.setTimeout || config.updateRate <= 0 || ( ( new Date().getTime() - start ) < config.updateRate ) ) {
- config.queue.shift()();
- } else {
- window.setTimeout( next, 13 );
- break;
- }
- }
- config.depth--;
- if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) {
- done();
- }
-}
-
-function saveGlobal() {
- config.pollution = [];
-
- if ( config.noglobals ) {
- for ( var key in window ) {
- // in Opera sometimes DOM element ids show up here, ignore them
- if ( !hasOwn.call( window, key ) || /^qunit-test-output/.test( key ) ) {
- continue;
- }
- config.pollution.push( key );
- }
- }
-}
-
-function checkPollution() {
- var newGlobals,
- deletedGlobals,
- old = config.pollution;
-
- saveGlobal();
-
- newGlobals = diff( config.pollution, old );
- if ( newGlobals.length > 0 ) {
- QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join(", ") );
- }
-
- deletedGlobals = diff( old, config.pollution );
- if ( deletedGlobals.length > 0 ) {
- QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join(", ") );
- }
-}
-
-// returns a new Array with the elements that are in a but not in b
-function diff( a, b ) {
- var i, j,
- result = a.slice();
-
- for ( i = 0; i < result.length; i++ ) {
- for ( j = 0; j < b.length; j++ ) {
- if ( result[i] === b[j] ) {
- result.splice( i, 1 );
- i--;
- break;
- }
- }
- }
- return result;
-}
-
-function extend( a, b ) {
- for ( var prop in b ) {
- if ( b[ prop ] === undefined ) {
- delete a[ prop ];
-
- // Avoid "Member not found" error in IE8 caused by setting window.constructor
- } else if ( prop !== "constructor" || a !== window ) {
- a[ prop ] = b[ prop ];
- }
- }
-
- return a;
-}
-
-/**
- * @param {HTMLElement} elem
- * @param {string} type
- * @param {Function} fn
- */
-function addEvent( elem, type, fn ) {
- // Standards-based browsers
- if ( elem.addEventListener ) {
- elem.addEventListener( type, fn, false );
- // IE
- } else {
- elem.attachEvent( "on" + type, fn );
- }
-}
-
-/**
- * @param {Array|NodeList} elems
- * @param {string} type
- * @param {Function} fn
- */
-function addEvents( elems, type, fn ) {
- var i = elems.length;
- while ( i-- ) {
- addEvent( elems[i], type, fn );
- }
-}
-
-function hasClass( elem, name ) {
- return (" " + elem.className + " ").indexOf(" " + name + " ") > -1;
-}
-
-function addClass( elem, name ) {
- if ( !hasClass( elem, name ) ) {
- elem.className += (elem.className ? " " : "") + name;
- }
-}
-
-function removeClass( elem, name ) {
- var set = " " + elem.className + " ";
- // Class name may appear multiple times
- while ( set.indexOf(" " + name + " ") > -1 ) {
- set = set.replace(" " + name + " " , " ");
- }
- // If possible, trim it for prettiness, but not neccecarily
- elem.className = window.jQuery ? jQuery.trim( set ) : ( set.trim ? set.trim() : set );
-}
-
-function id( name ) {
- return !!( typeof document !== "undefined" && document && document.getElementById ) &&
- document.getElementById( name );
-}
-
-function registerLoggingCallback( key ) {
- return function( callback ) {
- config[key].push( callback );
- };
-}
-
-// Supports deprecated method of completely overwriting logging callbacks
-function runLoggingCallbacks( key, scope, args ) {
- var i, callbacks;
- if ( QUnit.hasOwnProperty( key ) ) {
- QUnit[ key ].call(scope, args );
- } else {
- callbacks = config[ key ];
- for ( i = 0; i < callbacks.length; i++ ) {
- callbacks[ i ].call( scope, args );
- }
- }
-}
-
-// Test for equality any JavaScript type.
-// Author: Philippe Rathé
-QUnit.equiv = (function() {
-
- // Call the o related callback with the given arguments.
- function bindCallbacks( o, callbacks, args ) {
- var prop = QUnit.objectType( o );
- if ( prop ) {
- if ( QUnit.objectType( callbacks[ prop ] ) === "function" ) {
- return callbacks[ prop ].apply( callbacks, args );
- } else {
- return callbacks[ prop ]; // or undefined
- }
- }
- }
-
- // the real equiv function
- var innerEquiv,
- // stack to decide between skip/abort functions
- callers = [],
- // stack to avoiding loops from circular referencing
- parents = [],
-
- getProto = Object.getPrototypeOf || function ( obj ) {
- return obj.__proto__;
- },
- callbacks = (function () {
-
- // for string, boolean, number and null
- function useStrictEquality( b, a ) {
- /*jshint eqeqeq:false */
- if ( b instanceof a.constructor || a instanceof b.constructor ) {
- // to catch short annotaion VS 'new' annotation of a
- // declaration
- // e.g. var i = 1;
- // var j = new Number(1);
- return a == b;
- } else {
- return a === b;
- }
- }
-
- return {
- "string": useStrictEquality,
- "boolean": useStrictEquality,
- "number": useStrictEquality,
- "null": useStrictEquality,
- "undefined": useStrictEquality,
-
- "nan": function( b ) {
- return isNaN( b );
- },
-
- "date": function( b, a ) {
- return QUnit.objectType( b ) === "date" && a.valueOf() === b.valueOf();
- },
-
- "regexp": function( b, a ) {
- return QUnit.objectType( b ) === "regexp" &&
- // the regex itself
- a.source === b.source &&
- // and its modifers
- a.global === b.global &&
- // (gmi) ...
- a.ignoreCase === b.ignoreCase &&
- a.multiline === b.multiline &&
- a.sticky === b.sticky;
- },
-
- // - skip when the property is a method of an instance (OOP)
- // - abort otherwise,
- // initial === would have catch identical references anyway
- "function": function() {
- var caller = callers[callers.length - 1];
- return caller !== Object && typeof caller !== "undefined";
- },
-
- "array": function( b, a ) {
- var i, j, len, loop;
-
- // b could be an object literal here
- if ( QUnit.objectType( b ) !== "array" ) {
- return false;
- }
-
- len = a.length;
- if ( len !== b.length ) {
- // safe and faster
- return false;
- }
-
- // track reference to avoid circular references
- parents.push( a );
- for ( i = 0; i < len; i++ ) {
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- loop = true;// dont rewalk array
- }
- }
- if ( !loop && !innerEquiv(a[i], b[i]) ) {
- parents.pop();
- return false;
- }
- }
- parents.pop();
- return true;
- },
-
- "object": function( b, a ) {
- var i, j, loop,
- // Default to true
- eq = true,
- aProperties = [],
- bProperties = [];
-
- // comparing constructors is more strict than using
- // instanceof
- if ( a.constructor !== b.constructor ) {
- // Allow objects with no prototype to be equivalent to
- // objects with Object as their constructor.
- if ( !(( getProto(a) === null && getProto(b) === Object.prototype ) ||
- ( getProto(b) === null && getProto(a) === Object.prototype ) ) ) {
- return false;
- }
- }
-
- // stack constructor before traversing properties
- callers.push( a.constructor );
- // track reference to avoid circular references
- parents.push( a );
-
- for ( i in a ) { // be strict: don't ensures hasOwnProperty
- // and go deep
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- // don't go down the same path twice
- loop = true;
- }
- }
- aProperties.push(i); // collect a's properties
-
- if (!loop && !innerEquiv( a[i], b[i] ) ) {
- eq = false;
- break;
- }
- }
-
- callers.pop(); // unstack, we are done
- parents.pop();
-
- for ( i in b ) {
- bProperties.push( i ); // collect b's properties
- }
-
- // Ensures identical properties name
- return eq && innerEquiv( aProperties.sort(), bProperties.sort() );
- }
- };
- }());
-
- innerEquiv = function() { // can take multiple arguments
- var args = [].slice.apply( arguments );
- if ( args.length < 2 ) {
- return true; // end transition
- }
-
- return (function( a, b ) {
- if ( a === b ) {
- return true; // catch the most you can
- } else if ( a === null || b === null || typeof a === "undefined" ||
- typeof b === "undefined" ||
- QUnit.objectType(a) !== QUnit.objectType(b) ) {
- return false; // don't lose time with error prone cases
- } else {
- return bindCallbacks(a, callbacks, [ b, a ]);
- }
-
- // apply transition with (1..n) arguments
- }( args[0], args[1] ) && arguments.callee.apply( this, args.splice(1, args.length - 1 )) );
- };
-
- return innerEquiv;
-}());
-
-/**
- * jsDump Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com |
- * http://flesler.blogspot.com Licensed under BSD
- * (http://www.opensource.org/licenses/bsd-license.php) Date: 5/15/2008
- *
- * @projectDescription Advanced and extensible data dumping for Javascript.
- * @version 1.0.0
- * @author Ariel Flesler
- * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html}
- */
-QUnit.jsDump = (function() {
- function quote( str ) {
- return '"' + str.toString().replace( /"/g, '\\"' ) + '"';
- }
- function literal( o ) {
- return o + "";
- }
- function join( pre, arr, post ) {
- var s = jsDump.separator(),
- base = jsDump.indent(),
- inner = jsDump.indent(1);
- if ( arr.join ) {
- arr = arr.join( "," + s + inner );
- }
- if ( !arr ) {
- return pre + post;
- }
- return [ pre, inner + arr, base + post ].join(s);
- }
- function array( arr, stack ) {
- var i = arr.length, ret = new Array(i);
- this.up();
- while ( i-- ) {
- ret[i] = this.parse( arr[i] , undefined , stack);
- }
- this.down();
- return join( "[", ret, "]" );
- }
-
- var reName = /^function (\w+)/,
- jsDump = {
- // type is used mostly internally, you can fix a (custom)type in advance
- parse: function( obj, type, stack ) {
- stack = stack || [ ];
- var inStack, res,
- parser = this.parsers[ type || this.typeOf(obj) ];
-
- type = typeof parser;
- inStack = inArray( obj, stack );
-
- if ( inStack !== -1 ) {
- return "recursion(" + (inStack - stack.length) + ")";
- }
- if ( type === "function" ) {
- stack.push( obj );
- res = parser.call( this, obj, stack );
- stack.pop();
- return res;
- }
- return ( type === "string" ) ? parser : this.parsers.error;
- },
- typeOf: function( obj ) {
- var type;
- if ( obj === null ) {
- type = "null";
- } else if ( typeof obj === "undefined" ) {
- type = "undefined";
- } else if ( QUnit.is( "regexp", obj) ) {
- type = "regexp";
- } else if ( QUnit.is( "date", obj) ) {
- type = "date";
- } else if ( QUnit.is( "function", obj) ) {
- type = "function";
- } else if ( typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined" ) {
- type = "window";
- } else if ( obj.nodeType === 9 ) {
- type = "document";
- } else if ( obj.nodeType ) {
- type = "node";
- } else if (
- // native arrays
- toString.call( obj ) === "[object Array]" ||
- // NodeList objects
- ( typeof obj.length === "number" && typeof obj.item !== "undefined" && ( obj.length ? obj.item(0) === obj[0] : ( obj.item( 0 ) === null && typeof obj[0] === "undefined" ) ) )
- ) {
- type = "array";
- } else if ( obj.constructor === Error.prototype.constructor ) {
- type = "error";
- } else {
- type = typeof obj;
- }
- return type;
- },
- separator: function() {
- return this.multiline ? this.HTML ? "
" : "\n" : this.HTML ? " " : " ";
- },
- // extra can be a number, shortcut for increasing-calling-decreasing
- indent: function( extra ) {
- if ( !this.multiline ) {
- return "";
- }
- var chr = this.indentChar;
- if ( this.HTML ) {
- chr = chr.replace( /\t/g, " " ).replace( / /g, " " );
- }
- return new Array( this._depth_ + (extra||0) ).join(chr);
- },
- up: function( a ) {
- this._depth_ += a || 1;
- },
- down: function( a ) {
- this._depth_ -= a || 1;
- },
- setParser: function( name, parser ) {
- this.parsers[name] = parser;
- },
- // The next 3 are exposed so you can use them
- quote: quote,
- literal: literal,
- join: join,
- //
- _depth_: 1,
- // This is the list of parsers, to modify them, use jsDump.setParser
- parsers: {
- window: "[Window]",
- document: "[Document]",
- error: function(error) {
- return "Error(\"" + error.message + "\")";
- },
- unknown: "[Unknown]",
- "null": "null",
- "undefined": "undefined",
- "function": function( fn ) {
- var ret = "function",
- // functions never have name in IE
- name = "name" in fn ? fn.name : (reName.exec(fn) || [])[1];
-
- if ( name ) {
- ret += " " + name;
- }
- ret += "( ";
-
- ret = [ ret, QUnit.jsDump.parse( fn, "functionArgs" ), "){" ].join( "" );
- return join( ret, QUnit.jsDump.parse(fn,"functionCode" ), "}" );
- },
- array: array,
- nodelist: array,
- "arguments": array,
- object: function( map, stack ) {
- var ret = [ ], keys, key, val, i;
- QUnit.jsDump.up();
- keys = [];
- for ( key in map ) {
- keys.push( key );
- }
- keys.sort();
- for ( i = 0; i < keys.length; i++ ) {
- key = keys[ i ];
- val = map[ key ];
- ret.push( QUnit.jsDump.parse( key, "key" ) + ": " + QUnit.jsDump.parse( val, undefined, stack ) );
- }
- QUnit.jsDump.down();
- return join( "{", ret, "}" );
- },
- node: function( node ) {
- var len, i, val,
- open = QUnit.jsDump.HTML ? "<" : "<",
- close = QUnit.jsDump.HTML ? ">" : ">",
- tag = node.nodeName.toLowerCase(),
- ret = open + tag,
- attrs = node.attributes;
-
- if ( attrs ) {
- for ( i = 0, len = attrs.length; i < len; i++ ) {
- val = attrs[i].nodeValue;
- // IE6 includes all attributes in .attributes, even ones not explicitly set.
- // Those have values like undefined, null, 0, false, "" or "inherit".
- if ( val && val !== "inherit" ) {
- ret += " " + attrs[i].nodeName + "=" + QUnit.jsDump.parse( val, "attribute" );
- }
- }
- }
- ret += close;
-
- // Show content of TextNode or CDATASection
- if ( node.nodeType === 3 || node.nodeType === 4 ) {
- ret += node.nodeValue;
- }
-
- return ret + open + "/" + tag + close;
- },
- // function calls it internally, it's the arguments part of the function
- functionArgs: function( fn ) {
- var args,
- l = fn.length;
-
- if ( !l ) {
- return "";
- }
-
- args = new Array(l);
- while ( l-- ) {
- // 97 is 'a'
- args[l] = String.fromCharCode(97+l);
- }
- return " " + args.join( ", " ) + " ";
- },
- // object calls it internally, the key part of an item in a map
- key: quote,
- // function calls it internally, it's the content of the function
- functionCode: "[code]",
- // node calls it internally, it's an html attribute value
- attribute: quote,
- string: quote,
- date: quote,
- regexp: literal,
- number: literal,
- "boolean": literal
- },
- // if true, entities are escaped ( <, >, \t, space and \n )
- HTML: false,
- // indentation unit
- indentChar: " ",
- // if true, items in a collection, are separated by a \n, else just a space.
- multiline: true
- };
-
- return jsDump;
-}());
-
-// from jquery.js
-function inArray( elem, array ) {
- if ( array.indexOf ) {
- return array.indexOf( elem );
- }
-
- for ( var i = 0, length = array.length; i < length; i++ ) {
- if ( array[ i ] === elem ) {
- return i;
- }
- }
-
- return -1;
-}
-
-/*
- * Javascript Diff Algorithm
- * By John Resig (http://ejohn.org/)
- * Modified by Chu Alan "sprite"
- *
- * Released under the MIT license.
- *
- * More Info:
- * http://ejohn.org/projects/javascript-diff-algorithm/
- *
- * Usage: QUnit.diff(expected, actual)
- *
- * QUnit.diff( "the quick brown fox jumped over", "the quick fox jumps over" ) == "the quick brown fox jumped jumps over"
- */
-QUnit.diff = (function() {
- /*jshint eqeqeq:false, eqnull:true */
- function diff( o, n ) {
- var i,
- ns = {},
- os = {};
-
- for ( i = 0; i < n.length; i++ ) {
- if ( !hasOwn.call( ns, n[i] ) ) {
- ns[ n[i] ] = {
- rows: [],
- o: null
- };
- }
- ns[ n[i] ].rows.push( i );
- }
-
- for ( i = 0; i < o.length; i++ ) {
- if ( !hasOwn.call( os, o[i] ) ) {
- os[ o[i] ] = {
- rows: [],
- n: null
- };
- }
- os[ o[i] ].rows.push( i );
- }
-
- for ( i in ns ) {
- if ( !hasOwn.call( ns, i ) ) {
- continue;
- }
- if ( ns[i].rows.length === 1 && hasOwn.call( os, i ) && os[i].rows.length === 1 ) {
- n[ ns[i].rows[0] ] = {
- text: n[ ns[i].rows[0] ],
- row: os[i].rows[0]
- };
- o[ os[i].rows[0] ] = {
- text: o[ os[i].rows[0] ],
- row: ns[i].rows[0]
- };
- }
- }
-
- for ( i = 0; i < n.length - 1; i++ ) {
- if ( n[i].text != null && n[ i + 1 ].text == null && n[i].row + 1 < o.length && o[ n[i].row + 1 ].text == null &&
- n[ i + 1 ] == o[ n[i].row + 1 ] ) {
-
- n[ i + 1 ] = {
- text: n[ i + 1 ],
- row: n[i].row + 1
- };
- o[ n[i].row + 1 ] = {
- text: o[ n[i].row + 1 ],
- row: i + 1
- };
- }
- }
-
- for ( i = n.length - 1; i > 0; i-- ) {
- if ( n[i].text != null && n[ i - 1 ].text == null && n[i].row > 0 && o[ n[i].row - 1 ].text == null &&
- n[ i - 1 ] == o[ n[i].row - 1 ]) {
-
- n[ i - 1 ] = {
- text: n[ i - 1 ],
- row: n[i].row - 1
- };
- o[ n[i].row - 1 ] = {
- text: o[ n[i].row - 1 ],
- row: i - 1
- };
- }
- }
-
- return {
- o: o,
- n: n
- };
- }
-
- return function( o, n ) {
- o = o.replace( /\s+$/, "" );
- n = n.replace( /\s+$/, "" );
-
- var i, pre,
- str = "",
- out = diff( o === "" ? [] : o.split(/\s+/), n === "" ? [] : n.split(/\s+/) ),
- oSpace = o.match(/\s+/g),
- nSpace = n.match(/\s+/g);
-
- if ( oSpace == null ) {
- oSpace = [ " " ];
- }
- else {
- oSpace.push( " " );
- }
-
- if ( nSpace == null ) {
- nSpace = [ " " ];
- }
- else {
- nSpace.push( " " );
- }
-
- if ( out.n.length === 0 ) {
- for ( i = 0; i < out.o.length; i++ ) {
- str += "" + out.o[i] + oSpace[i] + "";
- }
- }
- else {
- if ( out.n[0].text == null ) {
- for ( n = 0; n < out.o.length && out.o[n].text == null; n++ ) {
- str += "" + out.o[n] + oSpace[n] + "";
- }
- }
-
- for ( i = 0; i < out.n.length; i++ ) {
- if (out.n[i].text == null) {
- str += "" + out.n[i] + nSpace[i] + "";
- }
- else {
- // `pre` initialized at top of scope
- pre = "";
-
- for ( n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++ ) {
- pre += "" + out.o[n] + oSpace[n] + "";
- }
- str += " " + out.n[i].text + nSpace[i] + pre;
- }
- }
- }
-
- return str;
- };
-}());
-
-// for CommonJS enviroments, export everything
-if ( typeof exports !== "undefined" ) {
- extend( exports, QUnit );
-}
-
-// get at whatever the global object is, like window in browsers
-}( (function() {return this;}.call()) ));
diff --git a/test/lib/require.js b/test/lib/require.js
deleted file mode 100644
index 987f865..0000000
--- a/test/lib/require.js
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- RequireJS 2.1.5 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.
- Available via the MIT or new BSD license.
- see: http://github.com/jrburke/requirejs for details
-*/
-var requirejs,require,define;
-(function(aa){function I(b){return"[object Function]"===L.call(b)}function J(b){return"[object Array]"===L.call(b)}function y(b,c){if(b){var d;for(d=0;dthis.depCount&&!this.defined){if(I(n)){if(this.events.error)try{e=i.execCb(c,n,b,e)}catch(d){a=d}else e=i.execCb(c,n,b,e);this.map.isDefine&&((b=this.module)&&void 0!==b.exports&&b.exports!==this.exports?e=b.exports:void 0===e&&this.usingExports&&(e=this.exports));if(a)return a.requireMap=this.map,a.requireModules=[this.map.id],a.requireType="define",v(this.error=
-a)}else e=n;this.exports=e;if(this.map.isDefine&&!this.ignore&&(q[c]=e,l.onResourceLoad))l.onResourceLoad(i,this.map,this.depMaps);x(c);this.defined=!0}this.defining=!1;this.defined&&!this.defineEmitted&&(this.defineEmitted=!0,this.emit("defined",this.exports),this.defineEmitComplete=!0)}}else this.fetch()}},callPlugin:function(){var a=this.map,b=a.id,d=j(a.prefix);this.depMaps.push(d);t(d,"defined",u(this,function(e){var n,d;d=this.map.name;var g=this.map.parentMap?this.map.parentMap.name:null,h=
-i.makeRequire(a.parentMap,{enableBuildCallback:!0});if(this.map.unnormalized){if(e.normalize&&(d=e.normalize(d,function(a){return c(a,g,!0)})||""),e=j(a.prefix+"!"+d,this.map.parentMap),t(e,"defined",u(this,function(a){this.init([],function(){return a},null,{enabled:!0,ignore:!0})})),d=m(p,e.id)){this.depMaps.push(e);if(this.events.error)d.on("error",u(this,function(a){this.emit("error",a)}));d.enable()}}else n=u(this,function(a){this.init([],function(){return a},null,{enabled:!0})}),n.error=u(this,
-function(a){this.inited=!0;this.error=a;a.requireModules=[b];G(p,function(a){0===a.map.id.indexOf(b+"_unnormalized")&&x(a.map.id)});v(a)}),n.fromText=u(this,function(e,c){var d=a.name,g=j(d),C=O;c&&(e=c);C&&(O=!1);r(g);s(k.config,b)&&(k.config[d]=k.config[b]);try{l.exec(e)}catch(ca){return v(B("fromtexteval","fromText eval for "+b+" failed: "+ca,ca,[b]))}C&&(O=!0);this.depMaps.push(g);i.completeLoad(d);h([d],n)}),e.load(a.name,h,n,k)}));i.enable(d,this);this.pluginMaps[d.id]=d},enable:function(){V[this.map.id]=
-this;this.enabling=this.enabled=!0;y(this.depMaps,u(this,function(a,b){var c,e;if("string"===typeof a){a=j(a,this.map.isDefine?this.map:this.map.parentMap,!1,!this.skipMap);this.depMaps[b]=a;if(c=m(N,a.id)){this.depExports[b]=c(this);return}this.depCount+=1;t(a,"defined",u(this,function(a){this.defineDep(b,a);this.check()}));this.errback&&t(a,"error",this.errback)}c=a.id;e=p[c];!s(N,c)&&(e&&!e.enabled)&&i.enable(a,this)}));G(this.pluginMaps,u(this,function(a){var b=m(p,a.id);b&&!b.enabled&&i.enable(a,
-this)}));this.enabling=!1;this.check()},on:function(a,b){var c=this.events[a];c||(c=this.events[a]=[]);c.push(b)},emit:function(a,b){y(this.events[a],function(a){a(b)});"error"===a&&delete this.events[a]}};i={config:k,contextName:b,registry:p,defined:q,urlFetched:U,defQueue:H,Module:Z,makeModuleMap:j,nextTick:l.nextTick,onError:v,configure:function(a){a.baseUrl&&"/"!==a.baseUrl.charAt(a.baseUrl.length-1)&&(a.baseUrl+="/");var b=k.pkgs,c=k.shim,e={paths:!0,config:!0,map:!0};G(a,function(a,b){e[b]?
-"map"===b?(k.map||(k.map={}),R(k[b],a,!0,!0)):R(k[b],a,!0):k[b]=a});a.shim&&(G(a.shim,function(a,b){J(a)&&(a={deps:a});if((a.exports||a.init)&&!a.exportsFn)a.exportsFn=i.makeShimExports(a);c[b]=a}),k.shim=c);a.packages&&(y(a.packages,function(a){a="string"===typeof a?{name:a}:a;b[a.name]={name:a.name,location:a.location||a.name,main:(a.main||"main").replace(ja,"").replace(ea,"")}}),k.pkgs=b);G(p,function(a,b){!a.inited&&!a.map.unnormalized&&(a.map=j(b))});if(a.deps||a.callback)i.require(a.deps||[],
-a.callback)},makeShimExports:function(a){return function(){var b;a.init&&(b=a.init.apply(aa,arguments));return b||a.exports&&ba(a.exports)}},makeRequire:function(a,f){function d(e,c,h){var g,k;f.enableBuildCallback&&(c&&I(c))&&(c.__requireJsBuild=!0);if("string"===typeof e){if(I(c))return v(B("requireargs","Invalid require call"),h);if(a&&s(N,e))return N[e](p[a.id]);if(l.get)return l.get(i,e,a,d);g=j(e,a,!1,!0);g=g.id;return!s(q,g)?v(B("notloaded",'Module name "'+g+'" has not been loaded yet for context: '+
-b+(a?"":". Use require([])"))):q[g]}L();i.nextTick(function(){L();k=r(j(null,a));k.skipMap=f.skipMap;k.init(e,c,h,{enabled:!0});D()});return d}f=f||{};R(d,{isBrowser:A,toUrl:function(b){var d,f=b.lastIndexOf("."),g=b.split("/")[0];if(-1!==f&&(!("."===g||".."===g)||1h.attachEvent.toString().indexOf("[native code"))&&!Y?(O=!0,h.attachEvent("onreadystatechange",b.onScriptLoad)):(h.addEventListener("load",b.onScriptLoad,!1),h.addEventListener("error",b.onScriptError,!1)),h.src=d,K=h,D?x.insertBefore(h,D):x.appendChild(h),K=null,h;if(da)try{importScripts(d),b.completeLoad(c)}catch(j){b.onError(B("importscripts","importScripts failed for "+c+" at "+d,j,[c]))}};A&&M(document.getElementsByTagName("script"),function(b){x||(x=
-b.parentNode);if(t=b.getAttribute("data-main"))return r.baseUrl||(E=t.split("/"),Q=E.pop(),fa=E.length?E.join("/")+"/":"./",r.baseUrl=fa,t=Q),t=t.replace(ea,""),r.deps=r.deps?r.deps.concat(t):[t],!0});define=function(b,c,d){var l,h;"string"!==typeof b&&(d=c,c=b,b=null);J(c)||(d=c,c=[]);!c.length&&I(d)&&d.length&&(d.toString().replace(la,"").replace(ma,function(b,d){c.push(d)}),c=(1===d.length?["require"]:["require","exports","module"]).concat(c));if(O){if(!(l=K))P&&"interactive"===P.readyState||M(document.getElementsByTagName("script"),
-function(b){if("interactive"===b.readyState)return P=b}),l=P;l&&(b||(b=l.getAttribute("data-requiremodule")),h=F[l.getAttribute("data-requirecontext")])}(h?h.defQueue:T).push([b,c,d])};define.amd={jQuery:!0};l.exec=function(b){return eval(b)};l(r)}})(this);
diff --git a/test/lib/resemble.js b/test/lib/resemble.js
new file mode 100644
index 0000000..1cb8c29
--- /dev/null
+++ b/test/lib/resemble.js
@@ -0,0 +1,535 @@
+/*
+Author: James Cryer
+Company: Huddle
+Last updated date: 21 Feb 2013
+URL: https://github.com/Huddle/Resemble.js
+*/
+
+(function(_this){
+ 'use strict';
+
+ _this['resemble'] = function( fileData ){
+
+ var data = {};
+ var images = [];
+ var updateCallbackArray = [];
+
+ var tolerance = { // between 0 and 255
+ red: 16,
+ green: 16,
+ blue: 16,
+ minBrightness: 16,
+ maxBrightness: 240
+ };
+
+ var ignoreAntialiasing = false;
+ var ignoreColors = false;
+
+ function triggerDataUpdate(){
+ var len = updateCallbackArray.length;
+ var i;
+ for(i=0;i tolerance.maxBrightness;
+ }
+
+ function getHue(r,g,b){
+
+ r = r / 255;
+ g = g / 255;
+ b = b / 255;
+ var max = Math.max(r, g, b), min = Math.min(r, g, b);
+ var h;
+ var d;
+
+ if (max == min){
+ h = 0; // achromatic
+ } else{
+ d = max - min;
+ switch(max){
+ case r: h = (g - b) / d + (g < b ? 6 : 0); break;
+ case g: h = (b - r) / d + 2; break;
+ case b: h = (r - g) / d + 4; break;
+ }
+ h /= 6;
+ }
+
+ return h;
+ }
+
+ function isAntialiased(sourcePix, data, cacheSet, verticalPos, horizontalPos, width){
+ var offset;
+ var targetPix;
+ var distance = 1;
+ var i;
+ var j;
+ var hasHighContrastSibling = 0;
+ var hasSiblingWithDifferentHue = 0;
+ var hasEquivilantSibling = 0;
+
+ addHueInfo(sourcePix);
+
+ for (i = distance*-1; i <= distance; i++){
+ for (j = distance*-1; j <= distance; j++){
+
+ if(i===0 && j===0){
+ // ignore source pixel
+ } else {
+
+ offset = ((verticalPos+j)*width + (horizontalPos+i)) * 4;
+ targetPix = getPixelInfo(data, offset, cacheSet);
+
+ if(targetPix === null){
+ continue;
+ }
+
+ addBrightnessInfo(targetPix);
+ addHueInfo(targetPix);
+
+ if( isContrasting(sourcePix, targetPix) ){
+ hasHighContrastSibling++;
+ }
+
+ if( isRGBSame(sourcePix,targetPix) ){
+ hasEquivilantSibling++;
+ }
+
+ if( Math.abs(targetPix.h - sourcePix.h) > 0.3 ){
+ hasSiblingWithDifferentHue++;
+ }
+
+ if( hasSiblingWithDifferentHue > 1 || hasHighContrastSibling > 1){
+ return true;
+ }
+ }
+ }
+ }
+
+ if(hasEquivilantSibling < 2){
+ return true;
+ }
+
+ return false;
+ }
+
+ function errorPixel(px, offset){
+ px[offset] = 255; //r
+ px[offset + 1] = 0; //g
+ px[offset + 2] = 255; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyPixel(px, offset, data){
+ px[offset] = data.r; //r
+ px[offset + 1] = data.g; //g
+ px[offset + 2] = data.b; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyGrayScalePixel(px, offset, data){
+ px[offset] = data.brightness; //r
+ px[offset + 1] = data.brightness; //g
+ px[offset + 2] = data.brightness; //b
+ px[offset + 3] = 255; //a
+ }
+
+
+ function getPixelInfo(data, offset, cacheSet){
+ var r;
+ var g;
+ var b;
+ var d;
+
+ if(typeof data[offset] !== 'undefined'){
+ r = data[offset];
+ g = data[offset+1];
+ b = data[offset+2];
+ d = {
+ r: r,
+ g: g,
+ b: b
+ };
+
+ return d;
+ } else {
+ return null;
+ }
+ }
+
+ function addBrightnessInfo(data){
+ data.brightness = getBrightness(data.r,data.g,data.b); // 'corrected' lightness
+ }
+
+ function addHueInfo(data){
+ data.h = getHue(data.r,data.g,data.b);
+ }
+
+ function analyseImages(img1, img2, width, height){
+
+ var hiddenCanvas = document.createElement('canvas');
+
+ var data1 = img1.data;
+ var data2 = img2.data;
+
+ hiddenCanvas.width = width;
+ hiddenCanvas.height = height;
+
+ var context = hiddenCanvas.getContext('2d');
+ var imgd = context.createImageData(width,height);
+ var targetPix = imgd.data;
+
+ var mismatchCount = 0;
+
+ var time = Date.now();
+
+ var skip;
+
+ if( (width > 1200 || height > 1200) && ignoreAntialiasing){
+ skip = 6;
+ }
+
+ loop(height, width, function(verticalPos, horizontalPos){
+
+ if(skip){ // only skip if the image isn't small
+ if(verticalPos % skip === 0 || horizontalPos % skip === 0){
+ return;
+ }
+ }
+
+ var offset = (verticalPos*width + horizontalPos) * 4;
+ var pixel1 = getPixelInfo(data1, offset, 1);
+ var pixel2 = getPixelInfo(data2, offset, 2);
+
+ if(pixel1 === null || pixel2 === null){
+ return;
+ }
+
+ if (ignoreColors){
+
+ addBrightnessInfo(pixel1);
+ addBrightnessInfo(pixel2);
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ return;
+ }
+
+ if( isRGBSimilar(pixel1, pixel2) ){
+ copyPixel(targetPix, offset, pixel2);
+
+ } else if( ignoreAntialiasing && (
+ addBrightnessInfo(pixel1), // jit pixel info augmentation looks a little weird, sorry.
+ addBrightnessInfo(pixel2),
+ isAntialiased(pixel1, data1, 1, verticalPos, horizontalPos, width) ||
+ isAntialiased(pixel2, data2, 2, verticalPos, horizontalPos, width)
+ )){
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+
+ });
+
+ data.misMatchPercentage = (mismatchCount / (height*width) * 100).toFixed(2);
+ data.analysisTime = Date.now() - time;
+
+ data.getImageDataUrl = function(text){
+ var barHeight = 0;
+
+ if(text){
+ barHeight = addLabel(text,context,hiddenCanvas);
+ }
+
+ context.putImageData(imgd, 0, barHeight);
+
+ return hiddenCanvas.toDataURL("image/png");
+ };
+ }
+
+ function addLabel(text, context, hiddenCanvas){
+ var textPadding = 2;
+
+ context.font = '12px sans-serif';
+
+ var textWidth = context.measureText(text).width + textPadding*2;
+ var barHeight = 22;
+
+ if(textWidth > hiddenCanvas.width){
+ hiddenCanvas.width = textWidth;
+ }
+
+ hiddenCanvas.height += barHeight;
+
+ context.fillStyle = "#666";
+ context.fillRect(0,0,hiddenCanvas.width,barHeight -4);
+ context.fillStyle = "#fff";
+ context.fillRect(0,barHeight -4,hiddenCanvas.width, 4);
+
+ context.fillStyle = "#fff";
+ context.textBaseline = "top";
+ context.font = '12px sans-serif';
+ context.fillText(text, textPadding, 1);
+
+ return barHeight;
+ }
+
+ function normalise(img, w, h){
+ var c;
+ var context;
+
+ if(img.height < h || img.width < w){
+ c = document.createElement('canvas');
+ c.width = w;
+ c.height = h;
+ context = c.getContext('2d');
+ context.putImageData(img, 0, 0);
+ return context.getImageData(0, 0, w, h);
+ }
+
+ return img;
+ }
+
+ function compare(one, two){
+
+ function onceWeHaveBoth(){
+ var width;
+ var height;
+ if(images.length === 2){
+ width = images[0].width > images[1].width ? images[0].width : images[1].width;
+ height = images[0].height > images[1].height ? images[0].height : images[1].height;
+
+ if( (images[0].width === images[1].width) && (images[0].height === images[1].height) ){
+ data.isSameDimensions = true;
+ } else {
+ data.isSameDimensions = false;
+ }
+
+ analyseImages( normalise(images[0],width, height), normalise(images[1],width, height), width, height);
+
+ triggerDataUpdate();
+ }
+ }
+
+ images = [];
+ loadImageData(one, onceWeHaveBoth);
+ loadImageData(two, onceWeHaveBoth);
+ }
+
+ function getCompareApi(param){
+
+ var secondFileData,
+ hasMethod = typeof param === 'function';
+
+ if( !hasMethod ){
+ // assume it's file data
+ secondFileData = param;
+ }
+
+ var self = {
+ ignoreNothing: function(){
+
+ tolerance.red = 16;
+ tolerance.green = 16;
+ tolerance.blue = 16;
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreAntialiasing: function(){
+
+ tolerance.red = 32;
+ tolerance.green = 32;
+ tolerance.blue = 32;
+ tolerance.minBrightness = 64;
+ tolerance.maxBrightness = 96;
+
+ ignoreAntialiasing = true;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreColors: function(){
+
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = true;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ onComplete: function( callback ){
+
+ updateCallbackArray.push(callback);
+
+ var wrapper = function(){
+ compare(fileData, secondFileData);
+ };
+
+ wrapper();
+
+ return getCompareApi(wrapper);
+ }
+ };
+
+ return self;
+ }
+
+ return {
+ onComplete: function( callback ){
+ updateCallbackArray.push(callback);
+ loadImageData(fileData, function(imageData, width, height){
+ parseImage(imageData.data, width, height);
+ });
+ },
+ compareTo: function(secondFileData){
+ return getCompareApi(secondFileData);
+ }
+ };
+
+ };
+}(this));
\ No newline at end of file
diff --git a/test/testsuite.js b/test/testsuite.js
deleted file mode 100644
index b486acb..0000000
--- a/test/testsuite.js
+++ /dev/null
@@ -1,36 +0,0 @@
-requirejs.config({
- baseUrl: '/test/unit/'
-});
-
-define(function(require) {
- var testModules = [
- 'Pixi',
- 'Point',
- 'Rectangle',
- 'DisplayObject',
- 'DisplayObjectContainer',
- 'Sprite',
- 'MovieClip',
- 'InteractionManager',
- 'Stage',
- 'utils/Utils',
- 'utils/EventTarget',
- 'utils/Matrix',
- 'utils/Detector',
- 'renderers/WebGLShaders',
- 'renderers/WebGLRenderer',
- 'renderers/WebGLBatch',
- 'renderers/CanvasRenderer',
- 'extras/Strip',
- 'extras/Rope',
- 'textures/BaseTexture',
- 'textures/Texture',
- 'loaders/SpriteSheetLoader',
- 'loaders/AssetLoader'
- ];
-
- // Resolve all testModules and then start the Test Runner.
- require(testModules, function() {
- QUnit.start();
- });
-});
\ No newline at end of file
diff --git a/test/textures/SpriteSheet-Aliens.png b/test/textures/SpriteSheet-Aliens.png
new file mode 100644
index 0000000..210acb1
--- /dev/null
+++ b/test/textures/SpriteSheet-Aliens.png
Binary files differ
diff --git a/test/textures/SpriteSheet-Explosion.png b/test/textures/SpriteSheet-Explosion.png
new file mode 100755
index 0000000..79e1a69
--- /dev/null
+++ b/test/textures/SpriteSheet-Explosion.png
Binary files differ
diff --git a/test/textures/bunny.png b/test/textures/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/textures/bunny.png
Binary files differ
diff --git a/test/unit/DisplayObject.js b/test/unit/DisplayObject.js
deleted file mode 100644
index 5e7e72f..0000000
--- a/test/unit/DisplayObject.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObject');
-});
diff --git a/test/unit/DisplayObjectContainer.js b/test/unit/DisplayObjectContainer.js
deleted file mode 100644
index b323959..0000000
--- a/test/unit/DisplayObjectContainer.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObjectContainer');
-});
diff --git a/test/unit/InteractionManager.js b/test/unit/InteractionManager.js
deleted file mode 100644
index e751f52..0000000
--- a/test/unit/InteractionManager.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('InteractionManager');
-});
diff --git a/test/unit/MovieClip.js b/test/unit/MovieClip.js
deleted file mode 100644
index 37d9446..0000000
--- a/test/unit/MovieClip.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('MovieClip');
-});
diff --git a/test/unit/Pixi.js b/test/unit/Pixi.js
deleted file mode 100644
index 36eee73..0000000
--- a/test/unit/Pixi.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Pixi');
-});
diff --git a/test/unit/Point.js b/test/unit/Point.js
deleted file mode 100644
index 983ff6e..0000000
--- a/test/unit/Point.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Point');
-});
diff --git a/test/unit/Rectangle.js b/test/unit/Rectangle.js
deleted file mode 100644
index 3b439ba..0000000
--- a/test/unit/Rectangle.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Rectangle');
-});
diff --git a/test/unit/Sprite.js b/test/unit/Sprite.js
deleted file mode 100644
index ed4f596..0000000
--- a/test/unit/Sprite.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Sprite');
-});
diff --git a/test/unit/Stage.js b/test/unit/Stage.js
deleted file mode 100644
index 2d70291..0000000
--- a/test/unit/Stage.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Stage');
-});
diff --git a/test/unit/extras/Rope.js b/test/unit/extras/Rope.js
deleted file mode 100644
index 5606f14..0000000
--- a/test/unit/extras/Rope.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Rope');
-});
diff --git a/test/unit/extras/Strip.js b/test/unit/extras/Strip.js
deleted file mode 100644
index 0134d3a..0000000
--- a/test/unit/extras/Strip.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Strip');
-});
diff --git a/test/unit/loaders/AssetLoader.js b/test/unit/loaders/AssetLoader.js
deleted file mode 100644
index 13b8443..0000000
--- a/test/unit/loaders/AssetLoader.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('AssetLoader');
-});
diff --git a/test/unit/loaders/SpriteSheetLoader.js b/test/unit/loaders/SpriteSheetLoader.js
deleted file mode 100644
index 8bf0cb2..0000000
--- a/test/unit/loaders/SpriteSheetLoader.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('SpriteSheetLoader');
-});
diff --git a/test/unit/pixi/InteractionManager.js b/test/unit/pixi/InteractionManager.js
new file mode 100644
index 0000000..ed3001f
--- /dev/null
+++ b/test/unit/pixi/InteractionManager.js
@@ -0,0 +1,10 @@
+describe('pixi/InteractionManager', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var InteractionManager = PIXI.InteractionManager;
+
+ it('Module exists', function () {
+ expect(InteractionManager).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/Pixi.js b/test/unit/pixi/Pixi.js
new file mode 100644
index 0000000..27debc1
--- /dev/null
+++ b/test/unit/pixi/Pixi.js
@@ -0,0 +1,9 @@
+describe('pixi/Pixi', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+
+ it('Module exists', function () {
+ expect(global).to.have.property('PIXI').and.to.be.an('object');
+ });
+});
diff --git a/test/unit/pixi/core/Circle.js b/test/unit/pixi/core/Circle.js
new file mode 100644
index 0000000..93a4456
--- /dev/null
+++ b/test/unit/pixi/core/Circle.js
@@ -0,0 +1,22 @@
+describe('pixi/core/Circle', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Circle = PIXI.Circle;
+
+ it('Module exists', function () {
+ expect(Circle).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Circle();
+
+ expect(obj).to.be.an.instanceof(Circle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', 0);
+ expect(obj).to.have.property('y', 0);
+ expect(obj).to.have.property('radius', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Ellipse.js b/test/unit/pixi/core/Ellipse.js
new file mode 100644
index 0000000..026b56f
--- /dev/null
+++ b/test/unit/pixi/core/Ellipse.js
@@ -0,0 +1,24 @@
+describe('pixi/core/Ellipse', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Ellipse = PIXI.Ellipse;
+
+ it('Module exists', function () {
+ expect(Ellipse).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Ellipse();
+
+ expect(obj).to.be.an.instanceof(Ellipse);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+ expect(obj).to.respondTo('getBounds');
+
+ expect(obj).to.have.property('x', 0);
+ expect(obj).to.have.property('y', 0);
+ expect(obj).to.have.property('width', 0);
+ expect(obj).to.have.property('height', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Matrix.js b/test/unit/pixi/core/Matrix.js
new file mode 100644
index 0000000..b48989e
--- /dev/null
+++ b/test/unit/pixi/core/Matrix.js
@@ -0,0 +1,30 @@
+describe('pixi/core/Matrix', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var mat3 = PIXI.mat3;
+ var mat4 = PIXI.mat4;
+ var Matrix = PIXI.Matrix;
+
+ it('Ensure determineMatrixArrayType works', function () {
+ expect(Matrix).to.be.a('function');
+ });
+
+ it('mat3 exists', function () {
+ expect(mat3).to.be.an('object');
+ });
+
+ it('Confirm new mat3 matrix', function () {
+ var matrix = new mat3.create();
+ pixi_core_Matrix_confirmNewMat3(matrix);
+ });
+
+ it('mat3 exists', function () {
+ expect(mat4).to.be.an('object');
+ });
+
+ it('Confirm new mat4 matrix', function () {
+ var matrix = new mat4.create();
+ pixi_core_Matrix_confirmNewMat4(matrix);
+ });
+});
diff --git a/test/unit/pixi/core/Point.js b/test/unit/pixi/core/Point.js
new file mode 100644
index 0000000..c4d5163
--- /dev/null
+++ b/test/unit/pixi/core/Point.js
@@ -0,0 +1,15 @@
+describe('pixi/core/Point', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Point = PIXI.Point;
+
+ it('Module exists', function () {
+ expect(Point).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Point();
+ pixi_core_Point_confirm(obj, 0, 0);
+ });
+});
diff --git a/test/unit/pixi/core/Polygon.js b/test/unit/pixi/core/Polygon.js
new file mode 100644
index 0000000..dc8c918
--- /dev/null
+++ b/test/unit/pixi/core/Polygon.js
@@ -0,0 +1,20 @@
+describe('pixi/core/Polygon', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Polygon = PIXI.Polygon;
+
+ it('Module exists', function () {
+ expect(Polygon).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Polygon();
+
+ expect(obj).to.be.an.instanceof(Polygon);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.deep.property('points.length', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Rectangle.js b/test/unit/pixi/core/Rectangle.js
new file mode 100644
index 0000000..d43316e
--- /dev/null
+++ b/test/unit/pixi/core/Rectangle.js
@@ -0,0 +1,15 @@
+describe('pixi/core/Rectangle', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Rectangle = PIXI.Rectangle;
+
+ it('Module exists', function () {
+ expect(Rectangle).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var rect = new Rectangle();
+ pixi_core_Rectangle_confirm(rect, 0, 0, 0, 0);
+ });
+});
diff --git a/.gitignore b/.gitignore
index 12e1b62..0b88317 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
node_modules
.DS_Store
-.project
\ No newline at end of file
+.project
+*.log
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..63e4d7c
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,8 @@
+language: node_js
+node_js:
+ - 0.10
+
+before_script:
+ - npm install -g grunt-cli
+ - export DISPLAY=:99.0
+ - sh -e /etc/init.d/xvfb start
diff --git a/Gruntfile.js b/Gruntfile.js
index b083b49..103938c 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -1,10 +1,12 @@
+'use strict';
+
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-connect');
- grunt.loadNpmTasks('grunt-contrib-qunit');
grunt.loadNpmTasks('grunt-contrib-yuidoc');
+ grunt.loadTasks('tasks');
var root = 'src/pixi/',
debug = 'bin/pixi.dev.js',
@@ -79,7 +81,7 @@
},
files: {
srcBlob: '<%= dirs.src %>/**/*.js',
- testBlob: '<%= dirs.test %>/unit/**/*.js',
+ testBlob: '<%= dirs.test %>/{functional,lib/pixi,unit}/**/*.js',
build: '<%= dirs.build %>/pixi.dev.js',
buildMin: '<%= dirs.build %>/pixi.js'
},
@@ -94,7 +96,12 @@
},
jshint: {
beforeconcat: srcFiles,
- test: ['<%= files.testBlob %>'],
+ test: {
+ src: ['<%= files.testBlob %>'],
+ options: {
+ expr: true
+ }
+ },
options: {
asi: true,
smarttabs: true
@@ -128,12 +135,6 @@
]
},
connect: {
- qunit: {
- options: {
- port: grunt.option('port-test') || 9002,
- base: './'
- }
- },
test: {
options: {
port: grunt.option('port-test') || 9002,
@@ -142,13 +143,6 @@
}
}
},
- qunit: {
- all: {
- options: {
- urls: ['http://localhost:' + (grunt.option('port-test') || 9002) + '/test/index.html']
- }
- }
- },
yuidoc: {
compile: {
name: '<%= pkg.name %>',
@@ -161,6 +155,13 @@
outdir: '<%= dirs.docs %>'
}
}
+ },
+ karma: {
+ unit: {
+ configFile: 'test/karma.conf.js',
+ // browsers: ['Chrome'],
+ singleRun: true
+ }
}
});
@@ -182,9 +183,10 @@
}
)
- grunt.registerTask('default', ['concat', 'uglify', 'distribute']);
grunt.registerTask('build', ['concat', 'uglify', 'distribute']);
- grunt.registerTask('test', ['build', 'connect:qunit', 'qunit']);
+ grunt.registerTask('test', ['concat', 'jshint:test', 'karma']);
grunt.registerTask('docs', ['yuidoc']);
-
-}
\ No newline at end of file
+ grunt.registerTask('default', ['test', 'uglify', 'distribute']);
+ // Travis CI task.
+ grunt.registerTask('travis', ['test']);
+}
diff --git a/README.md b/README.md
index c62ef86..690cfe4 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,8 @@

+[](http://travis-ci.org/drkibitz/pixi.js)
+
#### JavaScript 2D Renderer ####
The aim of this project is to provide a fast lightweight 2D library that works
diff --git a/package.json b/package.json
index b373240..1246a68 100644
--- a/package.json
+++ b/package.json
@@ -18,14 +18,21 @@
"main": "bin/pixi.js",
+ "scripts": {
+ "test": "grunt travis --verbose"
+ },
+
"dependencies": {},
"devDependencies": {
"grunt": "~0.4.x",
- "grunt-contrib-jshint": "0.3.x",
+ "grunt-contrib-jshint": "0.6.x",
"grunt-contrib-uglify": "0.2.x",
- "grunt-contrib-connect": "0.2.x",
- "grunt-contrib-qunit": "0.2.x",
+ "grunt-contrib-connect": "0.3.x",
"grunt-contrib-yuidoc": "0.4.x",
- "grunt-contrib-concat": "0.1.x"
+ "grunt-contrib-concat": "0.3.x",
+ "chai": "~1.7.0",
+ "karma": "0.11.0",
+ "karma-firefox-launcher": "0.1.0",
+ "karma-mocha": "0.1.0"
}
}
diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js
index a7c520e..ee82bbd 100644
--- a/src/pixi/InteractionManager.js
+++ b/src/pixi/InteractionManager.js
@@ -62,7 +62,6 @@
this.onTouchEnd = this.onTouchEnd.bind(this);
this.onTouchMove = this.onTouchMove.bind(this);
-
this.last = 0;
}
diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js
index 1a95d20..eef1059 100644
--- a/src/pixi/core/Ellipse.js
+++ b/src/pixi/core/Ellipse.js
@@ -78,7 +78,7 @@
return (normx + normy < 0.25);
}
-PIXI.Ellipse.getBounds = function()
+PIXI.Ellipse.prototype.getBounds = function()
{
return new PIXI.Rectangle(this.x, this.y, this.width, this.height);
}
diff --git a/tasks/karma.js b/tasks/karma.js
new file mode 100644
index 0000000..c340485
--- /dev/null
+++ b/tasks/karma.js
@@ -0,0 +1,27 @@
+'use strict';
+
+var path = require('path');
+var server = require('karma').server;
+
+module.exports = function (grunt) {
+ grunt.registerMultiTask('karma', 'run karma.', function() {
+ var done = this.async();
+ var options = this.options({
+ background: false
+ });
+ var data = this.data;
+
+ //merge options onto data, with data taking precedence
+ data = grunt.util._.merge(options, data);
+ data.configFile = path.resolve(data.configFile);
+ if (data.configFile) {
+ data.configFile = grunt.template.process(data.configFile);
+ }
+
+ server.start(
+ data,
+ function(code) {
+ done(!code);
+ });
+ });
+};
diff --git a/test/functional/example-1-basics/bunny.png b/test/functional/example-1-basics/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/functional/example-1-basics/bunny.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-30.png b/test/functional/example-1-basics/frame-30.png
new file mode 100644
index 0000000..96e3409
--- /dev/null
+++ b/test/functional/example-1-basics/frame-30.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-60.png b/test/functional/example-1-basics/frame-60.png
new file mode 100644
index 0000000..af3f4ce
--- /dev/null
+++ b/test/functional/example-1-basics/frame-60.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-90.png b/test/functional/example-1-basics/frame-90.png
new file mode 100644
index 0000000..099b823
--- /dev/null
+++ b/test/functional/example-1-basics/frame-90.png
Binary files differ
diff --git a/test/functional/example-1-basics/index.js b/test/functional/example-1-basics/index.js
new file mode 100644
index 0000000..7ae7a98
--- /dev/null
+++ b/test/functional/example-1-basics/index.js
@@ -0,0 +1,133 @@
+describe('Example 1 - Basics', function () {
+ 'use strict';
+
+ var baseUri = '/base/test/functional/example-1-basics';
+ var expect = chai.expect;
+ var currentFrame = 0;
+ var frameEvents = {};
+ var stage;
+ var renderer;
+ var bunny;
+
+ function onFrame(frame, callback) {
+ frameEvents[frame] = callback;
+ }
+
+ function animate() {
+ currentFrame += 1;
+
+ requestAnimFrame( animate );
+
+ // just for fun, lets rotate mr rabbit a little
+ bunny.rotation += 0.1;
+
+ // render the stage
+ renderer.render(stage);
+
+ if (frameEvents[currentFrame])
+ frameEvents[currentFrame](currentFrame);
+ }
+
+ function initScene() {
+ // create an new instance of a pixi stage
+ stage = new PIXI.Stage(0x66FF99);
+
+ // create a renderer instance
+ renderer = PIXI.autoDetectRenderer(400, 300);
+ console.log('Is PIXI.WebGLRenderer: ' + (renderer instanceof PIXI.WebGLRenderer));
+
+ // add the renderer view element to the DOM
+ document.body.appendChild(renderer.view);
+
+ requestAnimFrame( animate );
+
+ // create a texture from an image path
+ var texture = PIXI.Texture.fromImage(baseUri + "/bunny.png");
+ // create a new Sprite using the texture
+ bunny = new PIXI.Sprite(texture);
+
+ // center the sprites anchor point
+ bunny.anchor.x = 0.5;
+ bunny.anchor.y = 0.5;
+
+ // move the sprite t the center of the screen
+ bunny.position.x = 200;
+ bunny.position.y = 150;
+
+ stage.addChild(bunny);
+ }
+
+ it('assets loaded', function (done) {
+ var loader = new PIXI.AssetLoader([
+ baseUri + '/bunny.png',
+ baseUri + '/frame-30.png',
+ baseUri + '/frame-60.png',
+ baseUri + '/frame-90.png'
+ ]);
+ // loader.on('onProgress', function (event) {
+ // console.log(event.content);
+ // });
+ loader.on('onComplete', function (event) {
+ done();
+ initScene();
+ });
+ loader.load();
+ });
+
+ it('frame 30 should match', function (done) {
+ this.timeout(700);
+ onFrame(30, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-30.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 60 should match', function (done) {
+ this.timeout(1200);
+ onFrame(60, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-60.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 90 should match', function (done) {
+ this.timeout(1700);
+ onFrame(90, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-90.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ // it('capture something', function (done) {
+ // this.timeout(2000000);
+ // onFrame(30, function () {
+ // var img = new Image();
+ // img.src = renderer.view.toDataURL('image/png');
+ // document.body.appendChild(img);
+ // });
+ // });
+});
diff --git a/test/index.html b/test/index.html
deleted file mode 100644
index 9cbcac5..0000000
--- a/test/index.html
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
- Pixi.js Test Suite
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/test/karma.conf.js b/test/karma.conf.js
new file mode 100644
index 0000000..c66a696
--- /dev/null
+++ b/test/karma.conf.js
@@ -0,0 +1,82 @@
+module.exports = function(config) {
+ config.set({
+
+ // base path, that will be used to resolve files and exclude
+ basePath : '../',
+
+ frameworks : ['mocha'],
+
+ // list of files / patterns to load in the browser
+ files : [
+ 'node_modules/chai/chai.js',
+ 'bin/pixi.dev.js',
+ 'test/lib/**/*.js',
+ 'test/unit/**/*.js',
+ // 'test/functional/**/*.js',
+ {pattern: 'test/**/*.png', watched: false, included: false, served: true}
+ ],
+
+ // list of files to exclude
+ exclude : [],
+
+ // use dolts reporter, as travis terminal does not support escaping sequences
+ // possible values: 'dots', 'progress', 'junit', 'teamcity'
+ // CLI --reporters progress
+ reporters : ['progress'],
+
+ // web server port
+ // CLI --port 9876
+ port : 9876,
+
+ // cli runner port
+ // CLI --runner-port 9100
+ runnerPort : 9100,
+
+ // enable / disable colors in the output (reporters and logs)
+ // CLI --colors --no-colors
+ colors : true,
+
+ // level of logging
+ // possible values: karma.LOG_DISABLE || karma.LOG_ERROR || karma.LOG_WARN || karma.LOG_INFO || karma.LOG_DEBUG
+ // CLI --log-level debug
+ logLevel : config.LOG_DEBUG,
+
+ // enable / disable watching file and executing tests whenever any file changes
+ // CLI --auto-watch --no-auto-watch
+ autoWatch : false,
+
+ // Start these browsers, currently available:
+ // - Chrome
+ // - ChromeCanary
+ // - Firefox
+ // - Opera
+ // - Safari (only Mac)
+ // - PhantomJS
+ // - IE (only Windows)
+ // CLI --browsers Chrome,Firefox,Safari
+ browsers : ['Firefox'],
+
+ // If browser does not capture in given timeout [ms], kill it
+ // CLI --capture-timeout 5000
+ captureTimeout : 5000,
+
+ // Auto run tests on start (when browsers are captured) and exit
+ // CLI --single-run --no-single-run
+ singleRun : true,
+
+ // report which specs are slower than 500ms
+ // CLI --report-slower-than 500
+ reportSlowerThan : 1000,
+
+ preprocessors : {
+ // '**/client/js/*.js': 'coverage'
+ },
+
+ plugins : [
+ 'karma-mocha',
+ // 'karma-chrome-launcher',
+ 'karma-firefox-launcher',
+ // 'karma-phantomjs-launcher'
+ ]
+ });
+};
diff --git a/test/lib/pixi/core/Matrix.js b/test/lib/pixi/core/Matrix.js
new file mode 100644
index 0000000..d26386b
--- /dev/null
+++ b/test/lib/pixi/core/Matrix.js
@@ -0,0 +1,40 @@
+
+function pixi_core_Matrix_confirmNewMat3(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(1);
+ expect(matrix[5]).to.equal(0);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(1);
+}
+
+function pixi_core_Matrix_confirmNewMat4(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[0]).to.equal(1);
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(0);
+ expect(matrix[5]).to.equal(1);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(0);
+ expect(matrix[9]).to.equal(0);
+ expect(matrix[10]).to.equal(1);
+ expect(matrix[11]).to.equal(0);
+ expect(matrix[12]).to.equal(0);
+ expect(matrix[13]).to.equal(0);
+ expect(matrix[14]).to.equal(0);
+ expect(matrix[15]).to.equal(1);
+}
diff --git a/test/lib/pixi/core/Point.js b/test/lib/pixi/core/Point.js
new file mode 100644
index 0000000..e5df07b
--- /dev/null
+++ b/test/lib/pixi/core/Point.js
@@ -0,0 +1,10 @@
+
+function pixi_core_Point_confirm(obj, x, y) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Point);
+ expect(obj).to.respondTo('clone');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+}
diff --git a/test/lib/pixi/core/Rectangle.js b/test/lib/pixi/core/Rectangle.js
new file mode 100644
index 0000000..23f0d12
--- /dev/null
+++ b/test/lib/pixi/core/Rectangle.js
@@ -0,0 +1,13 @@
+
+function pixi_core_Rectangle_confirm(obj, x, y, width, height) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Rectangle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+ expect(obj).to.have.property('width', width);
+ expect(obj).to.have.property('height', height);
+}
diff --git a/test/lib/pixi/display/DisplayObject.js b/test/lib/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..1388a7f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObject.js
@@ -0,0 +1,43 @@
+
+function pixi_display_DisplayObject_confirmNew(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObject);
+ expect(obj).to.respondTo('setInteractive');
+ expect(obj).to.respondTo('addFilter');
+ expect(obj).to.respondTo('removeFilter');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.property('last', obj);
+ expect(obj).to.have.property('first', obj);
+
+ expect(obj).to.contain.property('position');
+ pixi_core_Point_confirm(obj.position, 0, 0);
+ expect(obj).to.contain.property('scale');
+ pixi_core_Point_confirm(obj.scale, 1, 1);
+ expect(obj).to.contain.property('pivot');
+ pixi_core_Point_confirm(obj.pivot, 0, 0);
+
+ expect(obj).to.have.property('rotation', 0);
+ expect(obj).to.have.property('alpha', 1);
+ expect(obj).to.have.property('visible', true);
+ expect(obj).to.have.property('buttonMode', false);
+ expect(obj).to.have.property('parent', null);
+ expect(obj).to.have.property('worldAlpha', 1);
+
+ expect(obj).to.have.property('hitArea');
+ expect(obj).to.have.property('interactive'); // TODO: Have a better default value
+ expect('mask' in obj).to.be.true; // TODO: Have a better default value
+ expect(obj.mask).to.be.undefined;
+
+ expect(obj).to.have.property('renderable');
+ expect(obj).to.have.property('stage');
+
+ expect(obj).to.have.deep.property('worldTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ expect(obj).to.have.deep.property('localTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.localTransform);
+
+ expect(obj).to.have.deep.property('color.length', 0);
+ expect(obj).to.have.property('dynamic', true);
+}
diff --git a/test/lib/pixi/display/DisplayObjectContainer.js b/test/lib/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..085c59f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,16 @@
+
+function pixi_display_DisplayObjectContainer_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObject_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObjectContainer);
+ expect(obj).to.respondTo('addChild');
+ expect(obj).to.respondTo('addChildAt');
+ expect(obj).to.respondTo('swapChildren');
+ expect(obj).to.respondTo('getChildAt');
+ expect(obj).to.respondTo('removeChild');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('children.length', 0);
+}
diff --git a/test/lib/pixi/display/Sprite.js b/test/lib/pixi/display/Sprite.js
new file mode 100644
index 0000000..cc7a2d6
--- /dev/null
+++ b/test/lib/pixi/display/Sprite.js
@@ -0,0 +1,28 @@
+
+function pixi_display_Sprite_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Sprite);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', true);
+ expect(obj).to.have.property('stage', null);
+
+ expect(obj).to.have.property('anchor');
+ pixi_core_Point_confirm(obj.anchor, 0, 0);
+
+ expect(obj).to.have.property('blendMode', PIXI.blendModes.NORMAL);
+ expect(obj).to.have.property('width', 1); // TODO: is 1 expected
+ expect(obj).to.have.property('height', 1); // TODO: is 1 expected
+
+ // FIXME: Just make this a boolean that is always there
+ expect(!!obj.updateFrame).to.equal(obj.texture.baseTexture.hasLoaded);
+
+ expect(obj).to.have.property('texture');
+ pixi_textures_Texture_confirmNew(obj.texture, done);
+}
diff --git a/test/lib/pixi/extras/Strip.js b/test/lib/pixi/extras/Strip.js
new file mode 100644
index 0000000..8927a8a
--- /dev/null
+++ b/test/lib/pixi/extras/Strip.js
@@ -0,0 +1,12 @@
+
+function pixi_extras_Strip_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Strip);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ // TODO: Test properties
+}
diff --git a/test/lib/pixi/textures/Texture.js b/test/lib/pixi/textures/Texture.js
new file mode 100644
index 0000000..d5867b6
--- /dev/null
+++ b/test/lib/pixi/textures/Texture.js
@@ -0,0 +1,31 @@
+
+function pixi_textures_Texture_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ function confirmFrameDone() {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, obj.baseTexture.width, obj.baseTexture.height);
+
+ expect(obj).to.have.property('width', obj.baseTexture.width);
+ expect(obj).to.have.property('height', obj.baseTexture.height);
+ done();
+ }
+
+ expect(obj).to.be.an.instanceof(PIXI.Texture);
+ pixi_utils_EventTarget_like(obj);
+
+ expect(obj).to.have.property('baseTexture')
+ .and.to.be.an.instanceof(PIXI.BaseTexture);
+
+ expect(obj).to.have.property('scope', obj);
+
+ expect(obj).to.have.property('trim');
+ pixi_core_Point_confirm(obj.trim, 0, 0);
+
+ expect(obj).to.have.property('frame');
+ if (obj.baseTexture.hasLoaded) {
+ confirmFrameDone();
+ } else {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, 1, 1);
+ obj.addEventListener('update', confirmFrameDone);
+ }
+}
diff --git a/test/lib/pixi/utils/EventTarget.js b/test/lib/pixi/utils/EventTarget.js
new file mode 100644
index 0000000..7b1dcfa
--- /dev/null
+++ b/test/lib/pixi/utils/EventTarget.js
@@ -0,0 +1,8 @@
+
+function pixi_utils_EventTarget_like(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.respondTo('addEventListener');
+ expect(obj).to.respondTo('dispatchEvent');
+ expect(obj).to.respondTo('removeEventListener');
+}
diff --git a/test/lib/qunit-1.11.0.css b/test/lib/qunit-1.11.0.css
deleted file mode 100644
index d7fc0c8..0000000
--- a/test/lib/qunit-1.11.0.css
+++ /dev/null
@@ -1,244 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-/** Font Family and Sizes */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
- font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
-}
-
-#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
-#qunit-tests { font-size: smaller; }
-
-
-/** Resets */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter {
- margin: 0;
- padding: 0;
-}
-
-
-/** Header */
-
-#qunit-header {
- padding: 0.5em 0 0.5em 1em;
-
- color: #8699a4;
- background-color: #0d3349;
-
- font-size: 1.5em;
- line-height: 1em;
- font-weight: normal;
-
- border-radius: 5px 5px 0 0;
- -moz-border-radius: 5px 5px 0 0;
- -webkit-border-top-right-radius: 5px;
- -webkit-border-top-left-radius: 5px;
-}
-
-#qunit-header a {
- text-decoration: none;
- color: #c2ccd1;
-}
-
-#qunit-header a:hover,
-#qunit-header a:focus {
- color: #fff;
-}
-
-#qunit-testrunner-toolbar label {
- display: inline-block;
- padding: 0 .5em 0 .1em;
-}
-
-#qunit-banner {
- height: 5px;
-}
-
-#qunit-testrunner-toolbar {
- padding: 0.5em 0 0.5em 2em;
- color: #5E740B;
- background-color: #eee;
- overflow: hidden;
-}
-
-#qunit-userAgent {
- padding: 0.5em 0 0.5em 2.5em;
- background-color: #2b81af;
- color: #fff;
- text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
-}
-
-#qunit-modulefilter-container {
- float: right;
-}
-
-/** Tests: Pass/Fail */
-
-#qunit-tests {
- list-style-position: inside;
-}
-
-#qunit-tests li {
- padding: 0.4em 0.5em 0.4em 2.5em;
- border-bottom: 1px solid #fff;
- list-style-position: inside;
-}
-
-#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running {
- display: none;
-}
-
-#qunit-tests li strong {
- cursor: pointer;
-}
-
-#qunit-tests li a {
- padding: 0.5em;
- color: #c2ccd1;
- text-decoration: none;
-}
-#qunit-tests li a:hover,
-#qunit-tests li a:focus {
- color: #000;
-}
-
-#qunit-tests li .runtime {
- float: right;
- font-size: smaller;
-}
-
-.qunit-assert-list {
- margin-top: 0.5em;
- padding: 0.5em;
-
- background-color: #fff;
-
- border-radius: 5px;
- -moz-border-radius: 5px;
- -webkit-border-radius: 5px;
-}
-
-.qunit-collapsed {
- display: none;
-}
-
-#qunit-tests table {
- border-collapse: collapse;
- margin-top: .2em;
-}
-
-#qunit-tests th {
- text-align: right;
- vertical-align: top;
- padding: 0 .5em 0 0;
-}
-
-#qunit-tests td {
- vertical-align: top;
-}
-
-#qunit-tests pre {
- margin: 0;
- white-space: pre-wrap;
- word-wrap: break-word;
-}
-
-#qunit-tests del {
- background-color: #e0f2be;
- color: #374e0c;
- text-decoration: none;
-}
-
-#qunit-tests ins {
- background-color: #ffcaca;
- color: #500;
- text-decoration: none;
-}
-
-/*** Test Counts */
-
-#qunit-tests b.counts { color: black; }
-#qunit-tests b.passed { color: #5E740B; }
-#qunit-tests b.failed { color: #710909; }
-
-#qunit-tests li li {
- padding: 5px;
- background-color: #fff;
- border-bottom: none;
- list-style-position: inside;
-}
-
-/*** Passing Styles */
-
-#qunit-tests li li.pass {
- color: #3c510c;
- background-color: #fff;
- border-left: 10px solid #C6E746;
-}
-
-#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
-#qunit-tests .pass .test-name { color: #366097; }
-
-#qunit-tests .pass .test-actual,
-#qunit-tests .pass .test-expected { color: #999999; }
-
-#qunit-banner.qunit-pass { background-color: #C6E746; }
-
-/*** Failing Styles */
-
-#qunit-tests li li.fail {
- color: #710909;
- background-color: #fff;
- border-left: 10px solid #EE5757;
- white-space: pre;
-}
-
-#qunit-tests > li:last-child {
- border-radius: 0 0 5px 5px;
- -moz-border-radius: 0 0 5px 5px;
- -webkit-border-bottom-right-radius: 5px;
- -webkit-border-bottom-left-radius: 5px;
-}
-
-#qunit-tests .fail { color: #000000; background-color: #EE5757; }
-#qunit-tests .fail .test-name,
-#qunit-tests .fail .module-name { color: #000000; }
-
-#qunit-tests .fail .test-actual { color: #EE5757; }
-#qunit-tests .fail .test-expected { color: green; }
-
-#qunit-banner.qunit-fail { background-color: #EE5757; }
-
-
-/** Result */
-
-#qunit-testresult {
- padding: 0.5em 0.5em 0.5em 2.5em;
-
- color: #2b81af;
- background-color: #D2E0E6;
-
- border-bottom: 1px solid white;
-}
-#qunit-testresult .module-name {
- font-weight: bold;
-}
-
-/** Fixture */
-
-#qunit-fixture {
- position: absolute;
- top: -10000px;
- left: -10000px;
- width: 1000px;
- height: 1000px;
-}
diff --git a/test/lib/qunit-1.11.0.js b/test/lib/qunit-1.11.0.js
deleted file mode 100644
index 302545f..0000000
--- a/test/lib/qunit-1.11.0.js
+++ /dev/null
@@ -1,2152 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-(function( window ) {
-
-var QUnit,
- assert,
- config,
- onErrorFnPrev,
- testId = 0,
- fileName = (sourceFromStacktrace( 0 ) || "" ).replace(/(:\d+)+\)?/, "").replace(/.+\//, ""),
- toString = Object.prototype.toString,
- hasOwn = Object.prototype.hasOwnProperty,
- // Keep a local reference to Date (GH-283)
- Date = window.Date,
- defined = {
- setTimeout: typeof window.setTimeout !== "undefined",
- sessionStorage: (function() {
- var x = "qunit-test-string";
- try {
- sessionStorage.setItem( x, x );
- sessionStorage.removeItem( x );
- return true;
- } catch( e ) {
- return false;
- }
- }())
- },
- /**
- * Provides a normalized error string, correcting an issue
- * with IE 7 (and prior) where Error.prototype.toString is
- * not properly implemented
- *
- * Based on http://es5.github.com/#x15.11.4.4
- *
- * @param {String|Error} error
- * @return {String} error message
- */
- errorString = function( error ) {
- var name, message,
- errorString = error.toString();
- if ( errorString.substring( 0, 7 ) === "[object" ) {
- name = error.name ? error.name.toString() : "Error";
- message = error.message ? error.message.toString() : "";
- if ( name && message ) {
- return name + ": " + message;
- } else if ( name ) {
- return name;
- } else if ( message ) {
- return message;
- } else {
- return "Error";
- }
- } else {
- return errorString;
- }
- },
- /**
- * Makes a clone of an object using only Array or Object as base,
- * and copies over the own enumerable properties.
- *
- * @param {Object} obj
- * @return {Object} New object with only the own properties (recursively).
- */
- objectValues = function( obj ) {
- // Grunt 0.3.x uses an older version of jshint that still has jshint/jshint#392.
- /*jshint newcap: false */
- var key, val,
- vals = QUnit.is( "array", obj ) ? [] : {};
- for ( key in obj ) {
- if ( hasOwn.call( obj, key ) ) {
- val = obj[key];
- vals[key] = val === Object(val) ? objectValues(val) : val;
- }
- }
- return vals;
- };
-
-function Test( settings ) {
- extend( this, settings );
- this.assertions = [];
- this.testNumber = ++Test.count;
-}
-
-Test.count = 0;
-
-Test.prototype = {
- init: function() {
- var a, b, li,
- tests = id( "qunit-tests" );
-
- if ( tests ) {
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml;
-
- // `a` initialized at top of scope
- a = document.createElement( "a" );
- a.innerHTML = "Rerun";
- a.href = QUnit.url({ testNumber: this.testNumber });
-
- li = document.createElement( "li" );
- li.appendChild( b );
- li.appendChild( a );
- li.className = "running";
- li.id = this.id = "qunit-test-output" + testId++;
-
- tests.appendChild( li );
- }
- },
- setup: function() {
- if ( this.module !== config.previousModule ) {
- if ( config.previousModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.previousModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
- config.previousModule = this.module;
- config.moduleStats = { all: 0, bad: 0 };
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- } else if ( config.autorun ) {
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- }
-
- config.current = this;
-
- this.testEnvironment = extend({
- setup: function() {},
- teardown: function() {}
- }, this.moduleTestEnvironment );
-
- this.started = +new Date();
- runLoggingCallbacks( "testStart", QUnit, {
- name: this.testName,
- module: this.module
- });
-
- // allow utility functions to access the current test environment
- // TODO why??
- QUnit.current_testEnvironment = this.testEnvironment;
-
- if ( !config.pollution ) {
- saveGlobal();
- }
- if ( config.notrycatch ) {
- this.testEnvironment.setup.call( this.testEnvironment );
- return;
- }
- try {
- this.testEnvironment.setup.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Setup failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- },
- run: function() {
- config.current = this;
-
- var running = id( "qunit-testresult" );
-
- if ( running ) {
- running.innerHTML = "Running:
" + this.nameHtml;
- }
-
- if ( this.async ) {
- QUnit.stop();
- }
-
- this.callbackStarted = +new Date();
-
- if ( config.notrycatch ) {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- return;
- }
-
- try {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- } catch( e ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
-
- QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + " " + this.stack + ": " + ( e.message || e ), extractStacktrace( e, 0 ) );
- // else next test will carry the responsibility
- saveGlobal();
-
- // Restart the tests if they're blocking
- if ( config.blocking ) {
- QUnit.start();
- }
- }
- },
- teardown: function() {
- config.current = this;
- if ( config.notrycatch ) {
- if ( typeof this.callbackRuntime === "undefined" ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
- }
- this.testEnvironment.teardown.call( this.testEnvironment );
- return;
- } else {
- try {
- this.testEnvironment.teardown.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Teardown failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- }
- checkPollution();
- },
- finish: function() {
- config.current = this;
- if ( config.requireExpects && this.expected === null ) {
- QUnit.pushFailure( "Expected number of assertions to be defined, but expect() was not called.", this.stack );
- } else if ( this.expected !== null && this.expected !== this.assertions.length ) {
- QUnit.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack );
- } else if ( this.expected === null && !this.assertions.length ) {
- QUnit.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions.", this.stack );
- }
-
- var i, assertion, a, b, time, li, ol,
- test = this,
- good = 0,
- bad = 0,
- tests = id( "qunit-tests" );
-
- this.runtime = +new Date() - this.started;
- config.stats.all += this.assertions.length;
- config.moduleStats.all += this.assertions.length;
-
- if ( tests ) {
- ol = document.createElement( "ol" );
- ol.className = "qunit-assert-list";
-
- for ( i = 0; i < this.assertions.length; i++ ) {
- assertion = this.assertions[i];
-
- li = document.createElement( "li" );
- li.className = assertion.result ? "pass" : "fail";
- li.innerHTML = assertion.message || ( assertion.result ? "okay" : "failed" );
- ol.appendChild( li );
-
- if ( assertion.result ) {
- good++;
- } else {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
-
- // store result when possible
- if ( QUnit.config.reorder && defined.sessionStorage ) {
- if ( bad ) {
- sessionStorage.setItem( "qunit-test-" + this.module + "-" + this.testName, bad );
- } else {
- sessionStorage.removeItem( "qunit-test-" + this.module + "-" + this.testName );
- }
- }
-
- if ( bad === 0 ) {
- addClass( ol, "qunit-collapsed" );
- }
-
- // `b` initialized at top of scope
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml + " (" + bad + ", " + good + ", " + this.assertions.length + ")";
-
- addEvent(b, "click", function() {
- var next = b.parentNode.lastChild,
- collapsed = hasClass( next, "qunit-collapsed" );
- ( collapsed ? removeClass : addClass )( next, "qunit-collapsed" );
- });
-
- addEvent(b, "dblclick", function( e ) {
- var target = e && e.target ? e.target : window.event.srcElement;
- if ( target.nodeName.toLowerCase() === "span" || target.nodeName.toLowerCase() === "b" ) {
- target = target.parentNode;
- }
- if ( window.location && target.nodeName.toLowerCase() === "strong" ) {
- window.location = QUnit.url({ testNumber: test.testNumber });
- }
- });
-
- // `time` initialized at top of scope
- time = document.createElement( "span" );
- time.className = "runtime";
- time.innerHTML = this.runtime + " ms";
-
- // `li` initialized at top of scope
- li = id( this.id );
- li.className = bad ? "fail" : "pass";
- li.removeChild( li.firstChild );
- a = li.firstChild;
- li.appendChild( b );
- li.appendChild( a );
- li.appendChild( time );
- li.appendChild( ol );
-
- } else {
- for ( i = 0; i < this.assertions.length; i++ ) {
- if ( !this.assertions[i].result ) {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
- }
-
- runLoggingCallbacks( "testDone", QUnit, {
- name: this.testName,
- module: this.module,
- failed: bad,
- passed: this.assertions.length - bad,
- total: this.assertions.length,
- duration: this.runtime
- });
-
- QUnit.reset();
-
- config.current = undefined;
- },
-
- queue: function() {
- var bad,
- test = this;
-
- synchronize(function() {
- test.init();
- });
- function run() {
- // each of these can by async
- synchronize(function() {
- test.setup();
- });
- synchronize(function() {
- test.run();
- });
- synchronize(function() {
- test.teardown();
- });
- synchronize(function() {
- test.finish();
- });
- }
-
- // `bad` initialized at top of scope
- // defer when previous test run passed, if storage is available
- bad = QUnit.config.reorder && defined.sessionStorage &&
- +sessionStorage.getItem( "qunit-test-" + this.module + "-" + this.testName );
-
- if ( bad ) {
- run();
- } else {
- synchronize( run, true );
- }
- }
-};
-
-// Root QUnit object.
-// `QUnit` initialized at top of scope
-QUnit = {
-
- // call on start of module test to prepend name to all tests
- module: function( name, testEnvironment ) {
- config.currentModule = name;
- config.currentModuleTestEnvironment = testEnvironment;
- config.modules[name] = true;
- },
-
- asyncTest: function( testName, expected, callback ) {
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- QUnit.test( testName, expected, callback, true );
- },
-
- test: function( testName, expected, callback, async ) {
- var test,
- nameHtml = "" + escapeText( testName ) + "";
-
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- if ( config.currentModule ) {
- nameHtml = "" + escapeText( config.currentModule ) + ": " + nameHtml;
- }
-
- test = new Test({
- nameHtml: nameHtml,
- testName: testName,
- expected: expected,
- async: async,
- callback: callback,
- module: config.currentModule,
- moduleTestEnvironment: config.currentModuleTestEnvironment,
- stack: sourceFromStacktrace( 2 )
- });
-
- if ( !validTest( test ) ) {
- return;
- }
-
- test.queue();
- },
-
- // Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through.
- expect: function( asserts ) {
- if (arguments.length === 1) {
- config.current.expected = asserts;
- } else {
- return config.current.expected;
- }
- },
-
- start: function( count ) {
- // QUnit hasn't been initialized yet.
- // Note: RequireJS (et al) may delay onLoad
- if ( config.semaphore === undefined ) {
- QUnit.begin(function() {
- // This is triggered at the top of QUnit.load, push start() to the event loop, to allow QUnit.load to finish first
- setTimeout(function() {
- QUnit.start( count );
- });
- });
- return;
- }
-
- config.semaphore -= count || 1;
- // don't start until equal number of stop-calls
- if ( config.semaphore > 0 ) {
- return;
- }
- // ignore if start is called more often then stop
- if ( config.semaphore < 0 ) {
- config.semaphore = 0;
- QUnit.pushFailure( "Called start() while already started (QUnit.config.semaphore was 0 already)", null, sourceFromStacktrace(2) );
- return;
- }
- // A slight delay, to avoid any current callbacks
- if ( defined.setTimeout ) {
- window.setTimeout(function() {
- if ( config.semaphore > 0 ) {
- return;
- }
- if ( config.timeout ) {
- clearTimeout( config.timeout );
- }
-
- config.blocking = false;
- process( true );
- }, 13);
- } else {
- config.blocking = false;
- process( true );
- }
- },
-
- stop: function( count ) {
- config.semaphore += count || 1;
- config.blocking = true;
-
- if ( config.testTimeout && defined.setTimeout ) {
- clearTimeout( config.timeout );
- config.timeout = window.setTimeout(function() {
- QUnit.ok( false, "Test timed out" );
- config.semaphore = 1;
- QUnit.start();
- }, config.testTimeout );
- }
- }
-};
-
-// `assert` initialized at top of scope
-// Asssert helpers
-// All of these must either call QUnit.push() or manually do:
-// - runLoggingCallbacks( "log", .. );
-// - config.current.assertions.push({ .. });
-// We attach it to the QUnit object *after* we expose the public API,
-// otherwise `assert` will become a global variable in browsers (#341).
-assert = {
- /**
- * Asserts rough true-ish result.
- * @name ok
- * @function
- * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" );
- */
- ok: function( result, msg ) {
- if ( !config.current ) {
- throw new Error( "ok() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
- result = !!result;
-
- var source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: msg
- };
-
- msg = escapeText( msg || (result ? "okay" : "failed" ) );
- msg = "" + msg + "";
-
- if ( !result ) {
- source = sourceFromStacktrace( 2 );
- if ( source ) {
- details.source = source;
- msg += "Source: | " + escapeText( source ) + " |
---|
";
- }
- }
- runLoggingCallbacks( "log", QUnit, details );
- config.current.assertions.push({
- result: result,
- message: msg
- });
- },
-
- /**
- * Assert that the first two arguments are equal, with an optional message.
- * Prints out both actual and expected values.
- * @name equal
- * @function
- * @example equal( format( "Received {0} bytes.", 2), "Received 2 bytes.", "format() replaces {0} with next argument" );
- */
- equal: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected == actual, actual, expected, message );
- },
-
- /**
- * @name notEqual
- * @function
- */
- notEqual: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected != actual, actual, expected, message );
- },
-
- /**
- * @name propEqual
- * @function
- */
- propEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notPropEqual
- * @function
- */
- notPropEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name deepEqual
- * @function
- */
- deepEqual: function( actual, expected, message ) {
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notDeepEqual
- * @function
- */
- notDeepEqual: function( actual, expected, message ) {
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name strictEqual
- * @function
- */
- strictEqual: function( actual, expected, message ) {
- QUnit.push( expected === actual, actual, expected, message );
- },
-
- /**
- * @name notStrictEqual
- * @function
- */
- notStrictEqual: function( actual, expected, message ) {
- QUnit.push( expected !== actual, actual, expected, message );
- },
-
- "throws": function( block, expected, message ) {
- var actual,
- expectedOutput = expected,
- ok = false;
-
- // 'expected' is optional
- if ( typeof expected === "string" ) {
- message = expected;
- expected = null;
- }
-
- config.current.ignoreGlobalErrors = true;
- try {
- block.call( config.current.testEnvironment );
- } catch (e) {
- actual = e;
- }
- config.current.ignoreGlobalErrors = false;
-
- if ( actual ) {
- // we don't want to validate thrown error
- if ( !expected ) {
- ok = true;
- expectedOutput = null;
- // expected is a regexp
- } else if ( QUnit.objectType( expected ) === "regexp" ) {
- ok = expected.test( errorString( actual ) );
- // expected is a constructor
- } else if ( actual instanceof expected ) {
- ok = true;
- // expected is a validation function which returns true is validation passed
- } else if ( expected.call( {}, actual ) === true ) {
- expectedOutput = null;
- ok = true;
- }
-
- QUnit.push( ok, actual, expectedOutput, message );
- } else {
- QUnit.pushFailure( message, null, 'No exception was thrown.' );
- }
- }
-};
-
-/**
- * @deprecate since 1.8.0
- * Kept assertion helpers in root for backwards compatibility.
- */
-extend( QUnit, assert );
-
-/**
- * @deprecated since 1.9.0
- * Kept root "raises()" for backwards compatibility.
- * (Note that we don't introduce assert.raises).
- */
-QUnit.raises = assert[ "throws" ];
-
-/**
- * @deprecated since 1.0.0, replaced with error pushes since 1.3.0
- * Kept to avoid TypeErrors for undefined methods.
- */
-QUnit.equals = function() {
- QUnit.push( false, false, false, "QUnit.equals has been deprecated since 2009 (e88049a0), use QUnit.equal instead" );
-};
-QUnit.same = function() {
- QUnit.push( false, false, false, "QUnit.same has been deprecated since 2009 (e88049a0), use QUnit.deepEqual instead" );
-};
-
-// We want access to the constructor's prototype
-(function() {
- function F() {}
- F.prototype = QUnit;
- QUnit = new F();
- // Make F QUnit's constructor so that we can add to the prototype later
- QUnit.constructor = F;
-}());
-
-/**
- * Config object: Maintain internal state
- * Later exposed as QUnit.config
- * `config` initialized at top of scope
- */
-config = {
- // The queue of tests to run
- queue: [],
-
- // block until document ready
- blocking: true,
-
- // when enabled, show only failing tests
- // gets persisted through sessionStorage and can be changed in UI via checkbox
- hidepassed: false,
-
- // by default, run previously failed tests first
- // very useful in combination with "Hide passed tests" checked
- reorder: true,
-
- // by default, modify document.title when suite is done
- altertitle: true,
-
- // when enabled, all tests must call expect()
- requireExpects: false,
-
- // add checkboxes that are persisted in the query-string
- // when enabled, the id is set to `true` as a `QUnit.config` property
- urlConfig: [
- {
- id: "noglobals",
- label: "Check for Globals",
- tooltip: "Enabling this will test if any test introduces new properties on the `window` object. Stored as query-strings."
- },
- {
- id: "notrycatch",
- label: "No try-catch",
- tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging exceptions in IE reasonable. Stored as query-strings."
- }
- ],
-
- // Set of all modules.
- modules: {},
-
- // logging callback queues
- begin: [],
- done: [],
- log: [],
- testStart: [],
- testDone: [],
- moduleStart: [],
- moduleDone: []
-};
-
-// Export global variables, unless an 'exports' object exists,
-// in that case we assume we're in CommonJS (dealt with on the bottom of the script)
-if ( typeof exports === "undefined" ) {
- extend( window, QUnit );
-
- // Expose QUnit object
- window.QUnit = QUnit;
-}
-
-// Initialize more QUnit.config and QUnit.urlParams
-(function() {
- var i,
- location = window.location || { search: "", protocol: "file:" },
- params = location.search.slice( 1 ).split( "&" ),
- length = params.length,
- urlParams = {},
- current;
-
- if ( params[ 0 ] ) {
- for ( i = 0; i < length; i++ ) {
- current = params[ i ].split( "=" );
- current[ 0 ] = decodeURIComponent( current[ 0 ] );
- // allow just a key to turn on a flag, e.g., test.html?noglobals
- current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true;
- urlParams[ current[ 0 ] ] = current[ 1 ];
- }
- }
-
- QUnit.urlParams = urlParams;
-
- // String search anywhere in moduleName+testName
- config.filter = urlParams.filter;
-
- // Exact match of the module name
- config.module = urlParams.module;
-
- config.testNumber = parseInt( urlParams.testNumber, 10 ) || null;
-
- // Figure out if we're running the tests from a server or not
- QUnit.isLocal = location.protocol === "file:";
-}());
-
-// Extend QUnit object,
-// these after set here because they should not be exposed as global functions
-extend( QUnit, {
- assert: assert,
-
- config: config,
-
- // Initialize the configuration options
- init: function() {
- extend( config, {
- stats: { all: 0, bad: 0 },
- moduleStats: { all: 0, bad: 0 },
- started: +new Date(),
- updateRate: 1000,
- blocking: false,
- autostart: true,
- autorun: false,
- filter: "",
- queue: [],
- semaphore: 1
- });
-
- var tests, banner, result,
- qunit = id( "qunit" );
-
- if ( qunit ) {
- qunit.innerHTML =
- "" +
- "" +
- "" +
- "" +
- "
";
- }
-
- tests = id( "qunit-tests" );
- banner = id( "qunit-banner" );
- result = id( "qunit-testresult" );
-
- if ( tests ) {
- tests.innerHTML = "";
- }
-
- if ( banner ) {
- banner.className = "";
- }
-
- if ( result ) {
- result.parentNode.removeChild( result );
- }
-
- if ( tests ) {
- result = document.createElement( "p" );
- result.id = "qunit-testresult";
- result.className = "result";
- tests.parentNode.insertBefore( result, tests );
- result.innerHTML = "Running...
";
- }
- },
-
- // Resets the test setup. Useful for tests that modify the DOM.
- reset: function() {
- var fixture = id( "qunit-fixture" );
- if ( fixture ) {
- fixture.innerHTML = config.fixture;
- }
- },
-
- // Trigger an event on an element.
- // @example triggerEvent( document.body, "click" );
- triggerEvent: function( elem, type, event ) {
- if ( document.createEvent ) {
- event = document.createEvent( "MouseEvents" );
- event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView,
- 0, 0, 0, 0, 0, false, false, false, false, 0, null);
-
- elem.dispatchEvent( event );
- } else if ( elem.fireEvent ) {
- elem.fireEvent( "on" + type );
- }
- },
-
- // Safe object type checking
- is: function( type, obj ) {
- return QUnit.objectType( obj ) === type;
- },
-
- objectType: function( obj ) {
- if ( typeof obj === "undefined" ) {
- return "undefined";
- // consider: typeof null === object
- }
- if ( obj === null ) {
- return "null";
- }
-
- var match = toString.call( obj ).match(/^\[object\s(.*)\]$/),
- type = match && match[1] || "";
-
- switch ( type ) {
- case "Number":
- if ( isNaN(obj) ) {
- return "nan";
- }
- return "number";
- case "String":
- case "Boolean":
- case "Array":
- case "Date":
- case "RegExp":
- case "Function":
- return type.toLowerCase();
- }
- if ( typeof obj === "object" ) {
- return "object";
- }
- return undefined;
- },
-
- push: function( result, actual, expected, message ) {
- if ( !config.current ) {
- throw new Error( "assertion outside test context, was " + sourceFromStacktrace() );
- }
-
- var output, source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: message,
- actual: actual,
- expected: expected
- };
-
- message = escapeText( message ) || ( result ? "okay" : "failed" );
- message = "" + message + "";
- output = message;
-
- if ( !result ) {
- expected = escapeText( QUnit.jsDump.parse(expected) );
- actual = escapeText( QUnit.jsDump.parse(actual) );
- output += "Expected: | " + expected + " |
";
-
- if ( actual !== expected ) {
- output += "Result: | " + actual + " |
";
- output += "Diff: | " + QUnit.diff( expected, actual ) + " |
";
- }
-
- source = sourceFromStacktrace();
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
- }
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: !!result,
- message: output
- });
- },
-
- pushFailure: function( message, source, actual ) {
- if ( !config.current ) {
- throw new Error( "pushFailure() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
-
- var output,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: false,
- message: message
- };
-
- message = escapeText( message ) || "error";
- message = "" + message + "";
- output = message;
-
- output += "";
-
- if ( actual ) {
- output += "Result: | " + escapeText( actual ) + " |
";
- }
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: false,
- message: output
- });
- },
-
- url: function( params ) {
- params = extend( extend( {}, QUnit.urlParams ), params );
- var key,
- querystring = "?";
-
- for ( key in params ) {
- if ( !hasOwn.call( params, key ) ) {
- continue;
- }
- querystring += encodeURIComponent( key ) + "=" +
- encodeURIComponent( params[ key ] ) + "&";
- }
- return window.location.protocol + "//" + window.location.host +
- window.location.pathname + querystring.slice( 0, -1 );
- },
-
- extend: extend,
- id: id,
- addEvent: addEvent
- // load, equiv, jsDump, diff: Attached later
-});
-
-/**
- * @deprecated: Created for backwards compatibility with test runner that set the hook function
- * into QUnit.{hook}, instead of invoking it and passing the hook function.
- * QUnit.constructor is set to the empty F() above so that we can add to it's prototype here.
- * Doing this allows us to tell if the following methods have been overwritten on the actual
- * QUnit object.
- */
-extend( QUnit.constructor.prototype, {
-
- // Logging callbacks; all receive a single argument with the listed properties
- // run test/logs.html for any related changes
- begin: registerLoggingCallback( "begin" ),
-
- // done: { failed, passed, total, runtime }
- done: registerLoggingCallback( "done" ),
-
- // log: { result, actual, expected, message }
- log: registerLoggingCallback( "log" ),
-
- // testStart: { name }
- testStart: registerLoggingCallback( "testStart" ),
-
- // testDone: { name, failed, passed, total, duration }
- testDone: registerLoggingCallback( "testDone" ),
-
- // moduleStart: { name }
- moduleStart: registerLoggingCallback( "moduleStart" ),
-
- // moduleDone: { name, failed, passed, total }
- moduleDone: registerLoggingCallback( "moduleDone" )
-});
-
-if ( typeof document === "undefined" || document.readyState === "complete" ) {
- config.autorun = true;
-}
-
-QUnit.load = function() {
- runLoggingCallbacks( "begin", QUnit, {} );
-
- // Initialize the config, saving the execution queue
- var banner, filter, i, label, len, main, ol, toolbar, userAgent, val,
- urlConfigCheckboxesContainer, urlConfigCheckboxes, moduleFilter,
- numModules = 0,
- moduleFilterHtml = "",
- urlConfigHtml = "",
- oldconfig = extend( {}, config );
-
- QUnit.init();
- extend(config, oldconfig);
-
- config.blocking = false;
-
- len = config.urlConfig.length;
-
- for ( i = 0; i < len; i++ ) {
- val = config.urlConfig[i];
- if ( typeof val === "string" ) {
- val = {
- id: val,
- label: val,
- tooltip: "[no tooltip available]"
- };
- }
- config[ val.id ] = QUnit.urlParams[ val.id ];
- urlConfigHtml += "";
- }
-
- moduleFilterHtml += "";
-
- // `userAgent` initialized at top of scope
- userAgent = id( "qunit-userAgent" );
- if ( userAgent ) {
- userAgent.innerHTML = navigator.userAgent;
- }
-
- // `banner` initialized at top of scope
- banner = id( "qunit-header" );
- if ( banner ) {
- banner.innerHTML = "" + banner.innerHTML + " ";
- }
-
- // `toolbar` initialized at top of scope
- toolbar = id( "qunit-testrunner-toolbar" );
- if ( toolbar ) {
- // `filter` initialized at top of scope
- filter = document.createElement( "input" );
- filter.type = "checkbox";
- filter.id = "qunit-filter-pass";
-
- addEvent( filter, "click", function() {
- var tmp,
- ol = document.getElementById( "qunit-tests" );
-
- if ( filter.checked ) {
- ol.className = ol.className + " hidepass";
- } else {
- tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " ";
- ol.className = tmp.replace( / hidepass /, " " );
- }
- if ( defined.sessionStorage ) {
- if (filter.checked) {
- sessionStorage.setItem( "qunit-filter-passed-tests", "true" );
- } else {
- sessionStorage.removeItem( "qunit-filter-passed-tests" );
- }
- }
- });
-
- if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem( "qunit-filter-passed-tests" ) ) {
- filter.checked = true;
- // `ol` initialized at top of scope
- ol = document.getElementById( "qunit-tests" );
- ol.className = ol.className + " hidepass";
- }
- toolbar.appendChild( filter );
-
- // `label` initialized at top of scope
- label = document.createElement( "label" );
- label.setAttribute( "for", "qunit-filter-pass" );
- label.setAttribute( "title", "Only show tests and assertons that fail. Stored in sessionStorage." );
- label.innerHTML = "Hide passed tests";
- toolbar.appendChild( label );
-
- urlConfigCheckboxesContainer = document.createElement("span");
- urlConfigCheckboxesContainer.innerHTML = urlConfigHtml;
- urlConfigCheckboxes = urlConfigCheckboxesContainer.getElementsByTagName("input");
- // For oldIE support:
- // * Add handlers to the individual elements instead of the container
- // * Use "click" instead of "change"
- // * Fallback from event.target to event.srcElement
- addEvents( urlConfigCheckboxes, "click", function( event ) {
- var params = {},
- target = event.target || event.srcElement;
- params[ target.name ] = target.checked ? true : undefined;
- window.location = QUnit.url( params );
- });
- toolbar.appendChild( urlConfigCheckboxesContainer );
-
- if (numModules > 1) {
- moduleFilter = document.createElement( 'span' );
- moduleFilter.setAttribute( 'id', 'qunit-modulefilter-container' );
- moduleFilter.innerHTML = moduleFilterHtml;
- addEvent( moduleFilter.lastChild, "change", function() {
- var selectBox = moduleFilter.getElementsByTagName("select")[0],
- selectedModule = decodeURIComponent(selectBox.options[selectBox.selectedIndex].value);
-
- window.location = QUnit.url( { module: ( selectedModule === "" ) ? undefined : selectedModule } );
- });
- toolbar.appendChild(moduleFilter);
- }
- }
-
- // `main` initialized at top of scope
- main = id( "qunit-fixture" );
- if ( main ) {
- config.fixture = main.innerHTML;
- }
-
- if ( config.autostart ) {
- QUnit.start();
- }
-};
-
-addEvent( window, "load", QUnit.load );
-
-// `onErrorFnPrev` initialized at top of scope
-// Preserve other handlers
-onErrorFnPrev = window.onerror;
-
-// Cover uncaught exceptions
-// Returning true will surpress the default browser handler,
-// returning false will let it run.
-window.onerror = function ( error, filePath, linerNr ) {
- var ret = false;
- if ( onErrorFnPrev ) {
- ret = onErrorFnPrev( error, filePath, linerNr );
- }
-
- // Treat return value as window.onerror itself does,
- // Only do our handling if not surpressed.
- if ( ret !== true ) {
- if ( QUnit.config.current ) {
- if ( QUnit.config.current.ignoreGlobalErrors ) {
- return true;
- }
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- } else {
- QUnit.test( "global failure", extend( function() {
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- }, { validTest: validTest } ) );
- }
- return false;
- }
-
- return ret;
-};
-
-function done() {
- config.autorun = true;
-
- // Log the last module results
- if ( config.currentModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.currentModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
-
- var i, key,
- banner = id( "qunit-banner" ),
- tests = id( "qunit-tests" ),
- runtime = +new Date() - config.started,
- passed = config.stats.all - config.stats.bad,
- html = [
- "Tests completed in ",
- runtime,
- " milliseconds.
",
- "",
- passed,
- " assertions of ",
- config.stats.all,
- " passed, ",
- config.stats.bad,
- " failed."
- ].join( "" );
-
- if ( banner ) {
- banner.className = ( config.stats.bad ? "qunit-fail" : "qunit-pass" );
- }
-
- if ( tests ) {
- id( "qunit-testresult" ).innerHTML = html;
- }
-
- if ( config.altertitle && typeof document !== "undefined" && document.title ) {
- // show ✖ for good, ✔ for bad suite result in title
- // use escape sequences in case file gets loaded with non-utf-8-charset
- document.title = [
- ( config.stats.bad ? "\u2716" : "\u2714" ),
- document.title.replace( /^[\u2714\u2716] /i, "" )
- ].join( " " );
- }
-
- // clear own sessionStorage items if all tests passed
- if ( config.reorder && defined.sessionStorage && config.stats.bad === 0 ) {
- // `key` & `i` initialized at top of scope
- for ( i = 0; i < sessionStorage.length; i++ ) {
- key = sessionStorage.key( i++ );
- if ( key.indexOf( "qunit-test-" ) === 0 ) {
- sessionStorage.removeItem( key );
- }
- }
- }
-
- // scroll back to top to show results
- if ( window.scrollTo ) {
- window.scrollTo(0, 0);
- }
-
- runLoggingCallbacks( "done", QUnit, {
- failed: config.stats.bad,
- passed: passed,
- total: config.stats.all,
- runtime: runtime
- });
-}
-
-/** @return Boolean: true if this test should be ran */
-function validTest( test ) {
- var include,
- filter = config.filter && config.filter.toLowerCase(),
- module = config.module && config.module.toLowerCase(),
- fullName = (test.module + ": " + test.testName).toLowerCase();
-
- // Internally-generated tests are always valid
- if ( test.callback && test.callback.validTest === validTest ) {
- delete test.callback.validTest;
- return true;
- }
-
- if ( config.testNumber ) {
- return test.testNumber === config.testNumber;
- }
-
- if ( module && ( !test.module || test.module.toLowerCase() !== module ) ) {
- return false;
- }
-
- if ( !filter ) {
- return true;
- }
-
- include = filter.charAt( 0 ) !== "!";
- if ( !include ) {
- filter = filter.slice( 1 );
- }
-
- // If the filter matches, we need to honour include
- if ( fullName.indexOf( filter ) !== -1 ) {
- return include;
- }
-
- // Otherwise, do the opposite
- return !include;
-}
-
-// so far supports only Firefox, Chrome and Opera (buggy), Safari (for real exceptions)
-// Later Safari and IE10 are supposed to support error.stack as well
-// See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack
-function extractStacktrace( e, offset ) {
- offset = offset === undefined ? 3 : offset;
-
- var stack, include, i;
-
- if ( e.stacktrace ) {
- // Opera
- return e.stacktrace.split( "\n" )[ offset + 3 ];
- } else if ( e.stack ) {
- // Firefox, Chrome
- stack = e.stack.split( "\n" );
- if (/^error$/i.test( stack[0] ) ) {
- stack.shift();
- }
- if ( fileName ) {
- include = [];
- for ( i = offset; i < stack.length; i++ ) {
- if ( stack[ i ].indexOf( fileName ) !== -1 ) {
- break;
- }
- include.push( stack[ i ] );
- }
- if ( include.length ) {
- return include.join( "\n" );
- }
- }
- return stack[ offset ];
- } else if ( e.sourceURL ) {
- // Safari, PhantomJS
- // hopefully one day Safari provides actual stacktraces
- // exclude useless self-reference for generated Error objects
- if ( /qunit.js$/.test( e.sourceURL ) ) {
- return;
- }
- // for actual exceptions, this is useful
- return e.sourceURL + ":" + e.line;
- }
-}
-function sourceFromStacktrace( offset ) {
- try {
- throw new Error();
- } catch ( e ) {
- return extractStacktrace( e, offset );
- }
-}
-
-/**
- * Escape text for attribute or text content.
- */
-function escapeText( s ) {
- if ( !s ) {
- return "";
- }
- s = s + "";
- // Both single quotes and double quotes (for attributes)
- return s.replace( /['"<>&]/g, function( s ) {
- switch( s ) {
- case '\'':
- return ''';
- case '"':
- return '"';
- case '<':
- return '<';
- case '>':
- return '>';
- case '&':
- return '&';
- }
- });
-}
-
-function synchronize( callback, last ) {
- config.queue.push( callback );
-
- if ( config.autorun && !config.blocking ) {
- process( last );
- }
-}
-
-function process( last ) {
- function next() {
- process( last );
- }
- var start = new Date().getTime();
- config.depth = config.depth ? config.depth + 1 : 1;
-
- while ( config.queue.length && !config.blocking ) {
- if ( !defined.setTimeout || config.updateRate <= 0 || ( ( new Date().getTime() - start ) < config.updateRate ) ) {
- config.queue.shift()();
- } else {
- window.setTimeout( next, 13 );
- break;
- }
- }
- config.depth--;
- if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) {
- done();
- }
-}
-
-function saveGlobal() {
- config.pollution = [];
-
- if ( config.noglobals ) {
- for ( var key in window ) {
- // in Opera sometimes DOM element ids show up here, ignore them
- if ( !hasOwn.call( window, key ) || /^qunit-test-output/.test( key ) ) {
- continue;
- }
- config.pollution.push( key );
- }
- }
-}
-
-function checkPollution() {
- var newGlobals,
- deletedGlobals,
- old = config.pollution;
-
- saveGlobal();
-
- newGlobals = diff( config.pollution, old );
- if ( newGlobals.length > 0 ) {
- QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join(", ") );
- }
-
- deletedGlobals = diff( old, config.pollution );
- if ( deletedGlobals.length > 0 ) {
- QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join(", ") );
- }
-}
-
-// returns a new Array with the elements that are in a but not in b
-function diff( a, b ) {
- var i, j,
- result = a.slice();
-
- for ( i = 0; i < result.length; i++ ) {
- for ( j = 0; j < b.length; j++ ) {
- if ( result[i] === b[j] ) {
- result.splice( i, 1 );
- i--;
- break;
- }
- }
- }
- return result;
-}
-
-function extend( a, b ) {
- for ( var prop in b ) {
- if ( b[ prop ] === undefined ) {
- delete a[ prop ];
-
- // Avoid "Member not found" error in IE8 caused by setting window.constructor
- } else if ( prop !== "constructor" || a !== window ) {
- a[ prop ] = b[ prop ];
- }
- }
-
- return a;
-}
-
-/**
- * @param {HTMLElement} elem
- * @param {string} type
- * @param {Function} fn
- */
-function addEvent( elem, type, fn ) {
- // Standards-based browsers
- if ( elem.addEventListener ) {
- elem.addEventListener( type, fn, false );
- // IE
- } else {
- elem.attachEvent( "on" + type, fn );
- }
-}
-
-/**
- * @param {Array|NodeList} elems
- * @param {string} type
- * @param {Function} fn
- */
-function addEvents( elems, type, fn ) {
- var i = elems.length;
- while ( i-- ) {
- addEvent( elems[i], type, fn );
- }
-}
-
-function hasClass( elem, name ) {
- return (" " + elem.className + " ").indexOf(" " + name + " ") > -1;
-}
-
-function addClass( elem, name ) {
- if ( !hasClass( elem, name ) ) {
- elem.className += (elem.className ? " " : "") + name;
- }
-}
-
-function removeClass( elem, name ) {
- var set = " " + elem.className + " ";
- // Class name may appear multiple times
- while ( set.indexOf(" " + name + " ") > -1 ) {
- set = set.replace(" " + name + " " , " ");
- }
- // If possible, trim it for prettiness, but not neccecarily
- elem.className = window.jQuery ? jQuery.trim( set ) : ( set.trim ? set.trim() : set );
-}
-
-function id( name ) {
- return !!( typeof document !== "undefined" && document && document.getElementById ) &&
- document.getElementById( name );
-}
-
-function registerLoggingCallback( key ) {
- return function( callback ) {
- config[key].push( callback );
- };
-}
-
-// Supports deprecated method of completely overwriting logging callbacks
-function runLoggingCallbacks( key, scope, args ) {
- var i, callbacks;
- if ( QUnit.hasOwnProperty( key ) ) {
- QUnit[ key ].call(scope, args );
- } else {
- callbacks = config[ key ];
- for ( i = 0; i < callbacks.length; i++ ) {
- callbacks[ i ].call( scope, args );
- }
- }
-}
-
-// Test for equality any JavaScript type.
-// Author: Philippe Rathé
-QUnit.equiv = (function() {
-
- // Call the o related callback with the given arguments.
- function bindCallbacks( o, callbacks, args ) {
- var prop = QUnit.objectType( o );
- if ( prop ) {
- if ( QUnit.objectType( callbacks[ prop ] ) === "function" ) {
- return callbacks[ prop ].apply( callbacks, args );
- } else {
- return callbacks[ prop ]; // or undefined
- }
- }
- }
-
- // the real equiv function
- var innerEquiv,
- // stack to decide between skip/abort functions
- callers = [],
- // stack to avoiding loops from circular referencing
- parents = [],
-
- getProto = Object.getPrototypeOf || function ( obj ) {
- return obj.__proto__;
- },
- callbacks = (function () {
-
- // for string, boolean, number and null
- function useStrictEquality( b, a ) {
- /*jshint eqeqeq:false */
- if ( b instanceof a.constructor || a instanceof b.constructor ) {
- // to catch short annotaion VS 'new' annotation of a
- // declaration
- // e.g. var i = 1;
- // var j = new Number(1);
- return a == b;
- } else {
- return a === b;
- }
- }
-
- return {
- "string": useStrictEquality,
- "boolean": useStrictEquality,
- "number": useStrictEquality,
- "null": useStrictEquality,
- "undefined": useStrictEquality,
-
- "nan": function( b ) {
- return isNaN( b );
- },
-
- "date": function( b, a ) {
- return QUnit.objectType( b ) === "date" && a.valueOf() === b.valueOf();
- },
-
- "regexp": function( b, a ) {
- return QUnit.objectType( b ) === "regexp" &&
- // the regex itself
- a.source === b.source &&
- // and its modifers
- a.global === b.global &&
- // (gmi) ...
- a.ignoreCase === b.ignoreCase &&
- a.multiline === b.multiline &&
- a.sticky === b.sticky;
- },
-
- // - skip when the property is a method of an instance (OOP)
- // - abort otherwise,
- // initial === would have catch identical references anyway
- "function": function() {
- var caller = callers[callers.length - 1];
- return caller !== Object && typeof caller !== "undefined";
- },
-
- "array": function( b, a ) {
- var i, j, len, loop;
-
- // b could be an object literal here
- if ( QUnit.objectType( b ) !== "array" ) {
- return false;
- }
-
- len = a.length;
- if ( len !== b.length ) {
- // safe and faster
- return false;
- }
-
- // track reference to avoid circular references
- parents.push( a );
- for ( i = 0; i < len; i++ ) {
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- loop = true;// dont rewalk array
- }
- }
- if ( !loop && !innerEquiv(a[i], b[i]) ) {
- parents.pop();
- return false;
- }
- }
- parents.pop();
- return true;
- },
-
- "object": function( b, a ) {
- var i, j, loop,
- // Default to true
- eq = true,
- aProperties = [],
- bProperties = [];
-
- // comparing constructors is more strict than using
- // instanceof
- if ( a.constructor !== b.constructor ) {
- // Allow objects with no prototype to be equivalent to
- // objects with Object as their constructor.
- if ( !(( getProto(a) === null && getProto(b) === Object.prototype ) ||
- ( getProto(b) === null && getProto(a) === Object.prototype ) ) ) {
- return false;
- }
- }
-
- // stack constructor before traversing properties
- callers.push( a.constructor );
- // track reference to avoid circular references
- parents.push( a );
-
- for ( i in a ) { // be strict: don't ensures hasOwnProperty
- // and go deep
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- // don't go down the same path twice
- loop = true;
- }
- }
- aProperties.push(i); // collect a's properties
-
- if (!loop && !innerEquiv( a[i], b[i] ) ) {
- eq = false;
- break;
- }
- }
-
- callers.pop(); // unstack, we are done
- parents.pop();
-
- for ( i in b ) {
- bProperties.push( i ); // collect b's properties
- }
-
- // Ensures identical properties name
- return eq && innerEquiv( aProperties.sort(), bProperties.sort() );
- }
- };
- }());
-
- innerEquiv = function() { // can take multiple arguments
- var args = [].slice.apply( arguments );
- if ( args.length < 2 ) {
- return true; // end transition
- }
-
- return (function( a, b ) {
- if ( a === b ) {
- return true; // catch the most you can
- } else if ( a === null || b === null || typeof a === "undefined" ||
- typeof b === "undefined" ||
- QUnit.objectType(a) !== QUnit.objectType(b) ) {
- return false; // don't lose time with error prone cases
- } else {
- return bindCallbacks(a, callbacks, [ b, a ]);
- }
-
- // apply transition with (1..n) arguments
- }( args[0], args[1] ) && arguments.callee.apply( this, args.splice(1, args.length - 1 )) );
- };
-
- return innerEquiv;
-}());
-
-/**
- * jsDump Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com |
- * http://flesler.blogspot.com Licensed under BSD
- * (http://www.opensource.org/licenses/bsd-license.php) Date: 5/15/2008
- *
- * @projectDescription Advanced and extensible data dumping for Javascript.
- * @version 1.0.0
- * @author Ariel Flesler
- * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html}
- */
-QUnit.jsDump = (function() {
- function quote( str ) {
- return '"' + str.toString().replace( /"/g, '\\"' ) + '"';
- }
- function literal( o ) {
- return o + "";
- }
- function join( pre, arr, post ) {
- var s = jsDump.separator(),
- base = jsDump.indent(),
- inner = jsDump.indent(1);
- if ( arr.join ) {
- arr = arr.join( "," + s + inner );
- }
- if ( !arr ) {
- return pre + post;
- }
- return [ pre, inner + arr, base + post ].join(s);
- }
- function array( arr, stack ) {
- var i = arr.length, ret = new Array(i);
- this.up();
- while ( i-- ) {
- ret[i] = this.parse( arr[i] , undefined , stack);
- }
- this.down();
- return join( "[", ret, "]" );
- }
-
- var reName = /^function (\w+)/,
- jsDump = {
- // type is used mostly internally, you can fix a (custom)type in advance
- parse: function( obj, type, stack ) {
- stack = stack || [ ];
- var inStack, res,
- parser = this.parsers[ type || this.typeOf(obj) ];
-
- type = typeof parser;
- inStack = inArray( obj, stack );
-
- if ( inStack !== -1 ) {
- return "recursion(" + (inStack - stack.length) + ")";
- }
- if ( type === "function" ) {
- stack.push( obj );
- res = parser.call( this, obj, stack );
- stack.pop();
- return res;
- }
- return ( type === "string" ) ? parser : this.parsers.error;
- },
- typeOf: function( obj ) {
- var type;
- if ( obj === null ) {
- type = "null";
- } else if ( typeof obj === "undefined" ) {
- type = "undefined";
- } else if ( QUnit.is( "regexp", obj) ) {
- type = "regexp";
- } else if ( QUnit.is( "date", obj) ) {
- type = "date";
- } else if ( QUnit.is( "function", obj) ) {
- type = "function";
- } else if ( typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined" ) {
- type = "window";
- } else if ( obj.nodeType === 9 ) {
- type = "document";
- } else if ( obj.nodeType ) {
- type = "node";
- } else if (
- // native arrays
- toString.call( obj ) === "[object Array]" ||
- // NodeList objects
- ( typeof obj.length === "number" && typeof obj.item !== "undefined" && ( obj.length ? obj.item(0) === obj[0] : ( obj.item( 0 ) === null && typeof obj[0] === "undefined" ) ) )
- ) {
- type = "array";
- } else if ( obj.constructor === Error.prototype.constructor ) {
- type = "error";
- } else {
- type = typeof obj;
- }
- return type;
- },
- separator: function() {
- return this.multiline ? this.HTML ? "
" : "\n" : this.HTML ? " " : " ";
- },
- // extra can be a number, shortcut for increasing-calling-decreasing
- indent: function( extra ) {
- if ( !this.multiline ) {
- return "";
- }
- var chr = this.indentChar;
- if ( this.HTML ) {
- chr = chr.replace( /\t/g, " " ).replace( / /g, " " );
- }
- return new Array( this._depth_ + (extra||0) ).join(chr);
- },
- up: function( a ) {
- this._depth_ += a || 1;
- },
- down: function( a ) {
- this._depth_ -= a || 1;
- },
- setParser: function( name, parser ) {
- this.parsers[name] = parser;
- },
- // The next 3 are exposed so you can use them
- quote: quote,
- literal: literal,
- join: join,
- //
- _depth_: 1,
- // This is the list of parsers, to modify them, use jsDump.setParser
- parsers: {
- window: "[Window]",
- document: "[Document]",
- error: function(error) {
- return "Error(\"" + error.message + "\")";
- },
- unknown: "[Unknown]",
- "null": "null",
- "undefined": "undefined",
- "function": function( fn ) {
- var ret = "function",
- // functions never have name in IE
- name = "name" in fn ? fn.name : (reName.exec(fn) || [])[1];
-
- if ( name ) {
- ret += " " + name;
- }
- ret += "( ";
-
- ret = [ ret, QUnit.jsDump.parse( fn, "functionArgs" ), "){" ].join( "" );
- return join( ret, QUnit.jsDump.parse(fn,"functionCode" ), "}" );
- },
- array: array,
- nodelist: array,
- "arguments": array,
- object: function( map, stack ) {
- var ret = [ ], keys, key, val, i;
- QUnit.jsDump.up();
- keys = [];
- for ( key in map ) {
- keys.push( key );
- }
- keys.sort();
- for ( i = 0; i < keys.length; i++ ) {
- key = keys[ i ];
- val = map[ key ];
- ret.push( QUnit.jsDump.parse( key, "key" ) + ": " + QUnit.jsDump.parse( val, undefined, stack ) );
- }
- QUnit.jsDump.down();
- return join( "{", ret, "}" );
- },
- node: function( node ) {
- var len, i, val,
- open = QUnit.jsDump.HTML ? "<" : "<",
- close = QUnit.jsDump.HTML ? ">" : ">",
- tag = node.nodeName.toLowerCase(),
- ret = open + tag,
- attrs = node.attributes;
-
- if ( attrs ) {
- for ( i = 0, len = attrs.length; i < len; i++ ) {
- val = attrs[i].nodeValue;
- // IE6 includes all attributes in .attributes, even ones not explicitly set.
- // Those have values like undefined, null, 0, false, "" or "inherit".
- if ( val && val !== "inherit" ) {
- ret += " " + attrs[i].nodeName + "=" + QUnit.jsDump.parse( val, "attribute" );
- }
- }
- }
- ret += close;
-
- // Show content of TextNode or CDATASection
- if ( node.nodeType === 3 || node.nodeType === 4 ) {
- ret += node.nodeValue;
- }
-
- return ret + open + "/" + tag + close;
- },
- // function calls it internally, it's the arguments part of the function
- functionArgs: function( fn ) {
- var args,
- l = fn.length;
-
- if ( !l ) {
- return "";
- }
-
- args = new Array(l);
- while ( l-- ) {
- // 97 is 'a'
- args[l] = String.fromCharCode(97+l);
- }
- return " " + args.join( ", " ) + " ";
- },
- // object calls it internally, the key part of an item in a map
- key: quote,
- // function calls it internally, it's the content of the function
- functionCode: "[code]",
- // node calls it internally, it's an html attribute value
- attribute: quote,
- string: quote,
- date: quote,
- regexp: literal,
- number: literal,
- "boolean": literal
- },
- // if true, entities are escaped ( <, >, \t, space and \n )
- HTML: false,
- // indentation unit
- indentChar: " ",
- // if true, items in a collection, are separated by a \n, else just a space.
- multiline: true
- };
-
- return jsDump;
-}());
-
-// from jquery.js
-function inArray( elem, array ) {
- if ( array.indexOf ) {
- return array.indexOf( elem );
- }
-
- for ( var i = 0, length = array.length; i < length; i++ ) {
- if ( array[ i ] === elem ) {
- return i;
- }
- }
-
- return -1;
-}
-
-/*
- * Javascript Diff Algorithm
- * By John Resig (http://ejohn.org/)
- * Modified by Chu Alan "sprite"
- *
- * Released under the MIT license.
- *
- * More Info:
- * http://ejohn.org/projects/javascript-diff-algorithm/
- *
- * Usage: QUnit.diff(expected, actual)
- *
- * QUnit.diff( "the quick brown fox jumped over", "the quick fox jumps over" ) == "the quick brown fox jumped jumps over"
- */
-QUnit.diff = (function() {
- /*jshint eqeqeq:false, eqnull:true */
- function diff( o, n ) {
- var i,
- ns = {},
- os = {};
-
- for ( i = 0; i < n.length; i++ ) {
- if ( !hasOwn.call( ns, n[i] ) ) {
- ns[ n[i] ] = {
- rows: [],
- o: null
- };
- }
- ns[ n[i] ].rows.push( i );
- }
-
- for ( i = 0; i < o.length; i++ ) {
- if ( !hasOwn.call( os, o[i] ) ) {
- os[ o[i] ] = {
- rows: [],
- n: null
- };
- }
- os[ o[i] ].rows.push( i );
- }
-
- for ( i in ns ) {
- if ( !hasOwn.call( ns, i ) ) {
- continue;
- }
- if ( ns[i].rows.length === 1 && hasOwn.call( os, i ) && os[i].rows.length === 1 ) {
- n[ ns[i].rows[0] ] = {
- text: n[ ns[i].rows[0] ],
- row: os[i].rows[0]
- };
- o[ os[i].rows[0] ] = {
- text: o[ os[i].rows[0] ],
- row: ns[i].rows[0]
- };
- }
- }
-
- for ( i = 0; i < n.length - 1; i++ ) {
- if ( n[i].text != null && n[ i + 1 ].text == null && n[i].row + 1 < o.length && o[ n[i].row + 1 ].text == null &&
- n[ i + 1 ] == o[ n[i].row + 1 ] ) {
-
- n[ i + 1 ] = {
- text: n[ i + 1 ],
- row: n[i].row + 1
- };
- o[ n[i].row + 1 ] = {
- text: o[ n[i].row + 1 ],
- row: i + 1
- };
- }
- }
-
- for ( i = n.length - 1; i > 0; i-- ) {
- if ( n[i].text != null && n[ i - 1 ].text == null && n[i].row > 0 && o[ n[i].row - 1 ].text == null &&
- n[ i - 1 ] == o[ n[i].row - 1 ]) {
-
- n[ i - 1 ] = {
- text: n[ i - 1 ],
- row: n[i].row - 1
- };
- o[ n[i].row - 1 ] = {
- text: o[ n[i].row - 1 ],
- row: i - 1
- };
- }
- }
-
- return {
- o: o,
- n: n
- };
- }
-
- return function( o, n ) {
- o = o.replace( /\s+$/, "" );
- n = n.replace( /\s+$/, "" );
-
- var i, pre,
- str = "",
- out = diff( o === "" ? [] : o.split(/\s+/), n === "" ? [] : n.split(/\s+/) ),
- oSpace = o.match(/\s+/g),
- nSpace = n.match(/\s+/g);
-
- if ( oSpace == null ) {
- oSpace = [ " " ];
- }
- else {
- oSpace.push( " " );
- }
-
- if ( nSpace == null ) {
- nSpace = [ " " ];
- }
- else {
- nSpace.push( " " );
- }
-
- if ( out.n.length === 0 ) {
- for ( i = 0; i < out.o.length; i++ ) {
- str += "" + out.o[i] + oSpace[i] + "";
- }
- }
- else {
- if ( out.n[0].text == null ) {
- for ( n = 0; n < out.o.length && out.o[n].text == null; n++ ) {
- str += "" + out.o[n] + oSpace[n] + "";
- }
- }
-
- for ( i = 0; i < out.n.length; i++ ) {
- if (out.n[i].text == null) {
- str += "" + out.n[i] + nSpace[i] + "";
- }
- else {
- // `pre` initialized at top of scope
- pre = "";
-
- for ( n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++ ) {
- pre += "" + out.o[n] + oSpace[n] + "";
- }
- str += " " + out.n[i].text + nSpace[i] + pre;
- }
- }
- }
-
- return str;
- };
-}());
-
-// for CommonJS enviroments, export everything
-if ( typeof exports !== "undefined" ) {
- extend( exports, QUnit );
-}
-
-// get at whatever the global object is, like window in browsers
-}( (function() {return this;}.call()) ));
diff --git a/test/lib/require.js b/test/lib/require.js
deleted file mode 100644
index 987f865..0000000
--- a/test/lib/require.js
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- RequireJS 2.1.5 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.
- Available via the MIT or new BSD license.
- see: http://github.com/jrburke/requirejs for details
-*/
-var requirejs,require,define;
-(function(aa){function I(b){return"[object Function]"===L.call(b)}function J(b){return"[object Array]"===L.call(b)}function y(b,c){if(b){var d;for(d=0;dthis.depCount&&!this.defined){if(I(n)){if(this.events.error)try{e=i.execCb(c,n,b,e)}catch(d){a=d}else e=i.execCb(c,n,b,e);this.map.isDefine&&((b=this.module)&&void 0!==b.exports&&b.exports!==this.exports?e=b.exports:void 0===e&&this.usingExports&&(e=this.exports));if(a)return a.requireMap=this.map,a.requireModules=[this.map.id],a.requireType="define",v(this.error=
-a)}else e=n;this.exports=e;if(this.map.isDefine&&!this.ignore&&(q[c]=e,l.onResourceLoad))l.onResourceLoad(i,this.map,this.depMaps);x(c);this.defined=!0}this.defining=!1;this.defined&&!this.defineEmitted&&(this.defineEmitted=!0,this.emit("defined",this.exports),this.defineEmitComplete=!0)}}else this.fetch()}},callPlugin:function(){var a=this.map,b=a.id,d=j(a.prefix);this.depMaps.push(d);t(d,"defined",u(this,function(e){var n,d;d=this.map.name;var g=this.map.parentMap?this.map.parentMap.name:null,h=
-i.makeRequire(a.parentMap,{enableBuildCallback:!0});if(this.map.unnormalized){if(e.normalize&&(d=e.normalize(d,function(a){return c(a,g,!0)})||""),e=j(a.prefix+"!"+d,this.map.parentMap),t(e,"defined",u(this,function(a){this.init([],function(){return a},null,{enabled:!0,ignore:!0})})),d=m(p,e.id)){this.depMaps.push(e);if(this.events.error)d.on("error",u(this,function(a){this.emit("error",a)}));d.enable()}}else n=u(this,function(a){this.init([],function(){return a},null,{enabled:!0})}),n.error=u(this,
-function(a){this.inited=!0;this.error=a;a.requireModules=[b];G(p,function(a){0===a.map.id.indexOf(b+"_unnormalized")&&x(a.map.id)});v(a)}),n.fromText=u(this,function(e,c){var d=a.name,g=j(d),C=O;c&&(e=c);C&&(O=!1);r(g);s(k.config,b)&&(k.config[d]=k.config[b]);try{l.exec(e)}catch(ca){return v(B("fromtexteval","fromText eval for "+b+" failed: "+ca,ca,[b]))}C&&(O=!0);this.depMaps.push(g);i.completeLoad(d);h([d],n)}),e.load(a.name,h,n,k)}));i.enable(d,this);this.pluginMaps[d.id]=d},enable:function(){V[this.map.id]=
-this;this.enabling=this.enabled=!0;y(this.depMaps,u(this,function(a,b){var c,e;if("string"===typeof a){a=j(a,this.map.isDefine?this.map:this.map.parentMap,!1,!this.skipMap);this.depMaps[b]=a;if(c=m(N,a.id)){this.depExports[b]=c(this);return}this.depCount+=1;t(a,"defined",u(this,function(a){this.defineDep(b,a);this.check()}));this.errback&&t(a,"error",this.errback)}c=a.id;e=p[c];!s(N,c)&&(e&&!e.enabled)&&i.enable(a,this)}));G(this.pluginMaps,u(this,function(a){var b=m(p,a.id);b&&!b.enabled&&i.enable(a,
-this)}));this.enabling=!1;this.check()},on:function(a,b){var c=this.events[a];c||(c=this.events[a]=[]);c.push(b)},emit:function(a,b){y(this.events[a],function(a){a(b)});"error"===a&&delete this.events[a]}};i={config:k,contextName:b,registry:p,defined:q,urlFetched:U,defQueue:H,Module:Z,makeModuleMap:j,nextTick:l.nextTick,onError:v,configure:function(a){a.baseUrl&&"/"!==a.baseUrl.charAt(a.baseUrl.length-1)&&(a.baseUrl+="/");var b=k.pkgs,c=k.shim,e={paths:!0,config:!0,map:!0};G(a,function(a,b){e[b]?
-"map"===b?(k.map||(k.map={}),R(k[b],a,!0,!0)):R(k[b],a,!0):k[b]=a});a.shim&&(G(a.shim,function(a,b){J(a)&&(a={deps:a});if((a.exports||a.init)&&!a.exportsFn)a.exportsFn=i.makeShimExports(a);c[b]=a}),k.shim=c);a.packages&&(y(a.packages,function(a){a="string"===typeof a?{name:a}:a;b[a.name]={name:a.name,location:a.location||a.name,main:(a.main||"main").replace(ja,"").replace(ea,"")}}),k.pkgs=b);G(p,function(a,b){!a.inited&&!a.map.unnormalized&&(a.map=j(b))});if(a.deps||a.callback)i.require(a.deps||[],
-a.callback)},makeShimExports:function(a){return function(){var b;a.init&&(b=a.init.apply(aa,arguments));return b||a.exports&&ba(a.exports)}},makeRequire:function(a,f){function d(e,c,h){var g,k;f.enableBuildCallback&&(c&&I(c))&&(c.__requireJsBuild=!0);if("string"===typeof e){if(I(c))return v(B("requireargs","Invalid require call"),h);if(a&&s(N,e))return N[e](p[a.id]);if(l.get)return l.get(i,e,a,d);g=j(e,a,!1,!0);g=g.id;return!s(q,g)?v(B("notloaded",'Module name "'+g+'" has not been loaded yet for context: '+
-b+(a?"":". Use require([])"))):q[g]}L();i.nextTick(function(){L();k=r(j(null,a));k.skipMap=f.skipMap;k.init(e,c,h,{enabled:!0});D()});return d}f=f||{};R(d,{isBrowser:A,toUrl:function(b){var d,f=b.lastIndexOf("."),g=b.split("/")[0];if(-1!==f&&(!("."===g||".."===g)||1h.attachEvent.toString().indexOf("[native code"))&&!Y?(O=!0,h.attachEvent("onreadystatechange",b.onScriptLoad)):(h.addEventListener("load",b.onScriptLoad,!1),h.addEventListener("error",b.onScriptError,!1)),h.src=d,K=h,D?x.insertBefore(h,D):x.appendChild(h),K=null,h;if(da)try{importScripts(d),b.completeLoad(c)}catch(j){b.onError(B("importscripts","importScripts failed for "+c+" at "+d,j,[c]))}};A&&M(document.getElementsByTagName("script"),function(b){x||(x=
-b.parentNode);if(t=b.getAttribute("data-main"))return r.baseUrl||(E=t.split("/"),Q=E.pop(),fa=E.length?E.join("/")+"/":"./",r.baseUrl=fa,t=Q),t=t.replace(ea,""),r.deps=r.deps?r.deps.concat(t):[t],!0});define=function(b,c,d){var l,h;"string"!==typeof b&&(d=c,c=b,b=null);J(c)||(d=c,c=[]);!c.length&&I(d)&&d.length&&(d.toString().replace(la,"").replace(ma,function(b,d){c.push(d)}),c=(1===d.length?["require"]:["require","exports","module"]).concat(c));if(O){if(!(l=K))P&&"interactive"===P.readyState||M(document.getElementsByTagName("script"),
-function(b){if("interactive"===b.readyState)return P=b}),l=P;l&&(b||(b=l.getAttribute("data-requiremodule")),h=F[l.getAttribute("data-requirecontext")])}(h?h.defQueue:T).push([b,c,d])};define.amd={jQuery:!0};l.exec=function(b){return eval(b)};l(r)}})(this);
diff --git a/test/lib/resemble.js b/test/lib/resemble.js
new file mode 100644
index 0000000..1cb8c29
--- /dev/null
+++ b/test/lib/resemble.js
@@ -0,0 +1,535 @@
+/*
+Author: James Cryer
+Company: Huddle
+Last updated date: 21 Feb 2013
+URL: https://github.com/Huddle/Resemble.js
+*/
+
+(function(_this){
+ 'use strict';
+
+ _this['resemble'] = function( fileData ){
+
+ var data = {};
+ var images = [];
+ var updateCallbackArray = [];
+
+ var tolerance = { // between 0 and 255
+ red: 16,
+ green: 16,
+ blue: 16,
+ minBrightness: 16,
+ maxBrightness: 240
+ };
+
+ var ignoreAntialiasing = false;
+ var ignoreColors = false;
+
+ function triggerDataUpdate(){
+ var len = updateCallbackArray.length;
+ var i;
+ for(i=0;i tolerance.maxBrightness;
+ }
+
+ function getHue(r,g,b){
+
+ r = r / 255;
+ g = g / 255;
+ b = b / 255;
+ var max = Math.max(r, g, b), min = Math.min(r, g, b);
+ var h;
+ var d;
+
+ if (max == min){
+ h = 0; // achromatic
+ } else{
+ d = max - min;
+ switch(max){
+ case r: h = (g - b) / d + (g < b ? 6 : 0); break;
+ case g: h = (b - r) / d + 2; break;
+ case b: h = (r - g) / d + 4; break;
+ }
+ h /= 6;
+ }
+
+ return h;
+ }
+
+ function isAntialiased(sourcePix, data, cacheSet, verticalPos, horizontalPos, width){
+ var offset;
+ var targetPix;
+ var distance = 1;
+ var i;
+ var j;
+ var hasHighContrastSibling = 0;
+ var hasSiblingWithDifferentHue = 0;
+ var hasEquivilantSibling = 0;
+
+ addHueInfo(sourcePix);
+
+ for (i = distance*-1; i <= distance; i++){
+ for (j = distance*-1; j <= distance; j++){
+
+ if(i===0 && j===0){
+ // ignore source pixel
+ } else {
+
+ offset = ((verticalPos+j)*width + (horizontalPos+i)) * 4;
+ targetPix = getPixelInfo(data, offset, cacheSet);
+
+ if(targetPix === null){
+ continue;
+ }
+
+ addBrightnessInfo(targetPix);
+ addHueInfo(targetPix);
+
+ if( isContrasting(sourcePix, targetPix) ){
+ hasHighContrastSibling++;
+ }
+
+ if( isRGBSame(sourcePix,targetPix) ){
+ hasEquivilantSibling++;
+ }
+
+ if( Math.abs(targetPix.h - sourcePix.h) > 0.3 ){
+ hasSiblingWithDifferentHue++;
+ }
+
+ if( hasSiblingWithDifferentHue > 1 || hasHighContrastSibling > 1){
+ return true;
+ }
+ }
+ }
+ }
+
+ if(hasEquivilantSibling < 2){
+ return true;
+ }
+
+ return false;
+ }
+
+ function errorPixel(px, offset){
+ px[offset] = 255; //r
+ px[offset + 1] = 0; //g
+ px[offset + 2] = 255; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyPixel(px, offset, data){
+ px[offset] = data.r; //r
+ px[offset + 1] = data.g; //g
+ px[offset + 2] = data.b; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyGrayScalePixel(px, offset, data){
+ px[offset] = data.brightness; //r
+ px[offset + 1] = data.brightness; //g
+ px[offset + 2] = data.brightness; //b
+ px[offset + 3] = 255; //a
+ }
+
+
+ function getPixelInfo(data, offset, cacheSet){
+ var r;
+ var g;
+ var b;
+ var d;
+
+ if(typeof data[offset] !== 'undefined'){
+ r = data[offset];
+ g = data[offset+1];
+ b = data[offset+2];
+ d = {
+ r: r,
+ g: g,
+ b: b
+ };
+
+ return d;
+ } else {
+ return null;
+ }
+ }
+
+ function addBrightnessInfo(data){
+ data.brightness = getBrightness(data.r,data.g,data.b); // 'corrected' lightness
+ }
+
+ function addHueInfo(data){
+ data.h = getHue(data.r,data.g,data.b);
+ }
+
+ function analyseImages(img1, img2, width, height){
+
+ var hiddenCanvas = document.createElement('canvas');
+
+ var data1 = img1.data;
+ var data2 = img2.data;
+
+ hiddenCanvas.width = width;
+ hiddenCanvas.height = height;
+
+ var context = hiddenCanvas.getContext('2d');
+ var imgd = context.createImageData(width,height);
+ var targetPix = imgd.data;
+
+ var mismatchCount = 0;
+
+ var time = Date.now();
+
+ var skip;
+
+ if( (width > 1200 || height > 1200) && ignoreAntialiasing){
+ skip = 6;
+ }
+
+ loop(height, width, function(verticalPos, horizontalPos){
+
+ if(skip){ // only skip if the image isn't small
+ if(verticalPos % skip === 0 || horizontalPos % skip === 0){
+ return;
+ }
+ }
+
+ var offset = (verticalPos*width + horizontalPos) * 4;
+ var pixel1 = getPixelInfo(data1, offset, 1);
+ var pixel2 = getPixelInfo(data2, offset, 2);
+
+ if(pixel1 === null || pixel2 === null){
+ return;
+ }
+
+ if (ignoreColors){
+
+ addBrightnessInfo(pixel1);
+ addBrightnessInfo(pixel2);
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ return;
+ }
+
+ if( isRGBSimilar(pixel1, pixel2) ){
+ copyPixel(targetPix, offset, pixel2);
+
+ } else if( ignoreAntialiasing && (
+ addBrightnessInfo(pixel1), // jit pixel info augmentation looks a little weird, sorry.
+ addBrightnessInfo(pixel2),
+ isAntialiased(pixel1, data1, 1, verticalPos, horizontalPos, width) ||
+ isAntialiased(pixel2, data2, 2, verticalPos, horizontalPos, width)
+ )){
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+
+ });
+
+ data.misMatchPercentage = (mismatchCount / (height*width) * 100).toFixed(2);
+ data.analysisTime = Date.now() - time;
+
+ data.getImageDataUrl = function(text){
+ var barHeight = 0;
+
+ if(text){
+ barHeight = addLabel(text,context,hiddenCanvas);
+ }
+
+ context.putImageData(imgd, 0, barHeight);
+
+ return hiddenCanvas.toDataURL("image/png");
+ };
+ }
+
+ function addLabel(text, context, hiddenCanvas){
+ var textPadding = 2;
+
+ context.font = '12px sans-serif';
+
+ var textWidth = context.measureText(text).width + textPadding*2;
+ var barHeight = 22;
+
+ if(textWidth > hiddenCanvas.width){
+ hiddenCanvas.width = textWidth;
+ }
+
+ hiddenCanvas.height += barHeight;
+
+ context.fillStyle = "#666";
+ context.fillRect(0,0,hiddenCanvas.width,barHeight -4);
+ context.fillStyle = "#fff";
+ context.fillRect(0,barHeight -4,hiddenCanvas.width, 4);
+
+ context.fillStyle = "#fff";
+ context.textBaseline = "top";
+ context.font = '12px sans-serif';
+ context.fillText(text, textPadding, 1);
+
+ return barHeight;
+ }
+
+ function normalise(img, w, h){
+ var c;
+ var context;
+
+ if(img.height < h || img.width < w){
+ c = document.createElement('canvas');
+ c.width = w;
+ c.height = h;
+ context = c.getContext('2d');
+ context.putImageData(img, 0, 0);
+ return context.getImageData(0, 0, w, h);
+ }
+
+ return img;
+ }
+
+ function compare(one, two){
+
+ function onceWeHaveBoth(){
+ var width;
+ var height;
+ if(images.length === 2){
+ width = images[0].width > images[1].width ? images[0].width : images[1].width;
+ height = images[0].height > images[1].height ? images[0].height : images[1].height;
+
+ if( (images[0].width === images[1].width) && (images[0].height === images[1].height) ){
+ data.isSameDimensions = true;
+ } else {
+ data.isSameDimensions = false;
+ }
+
+ analyseImages( normalise(images[0],width, height), normalise(images[1],width, height), width, height);
+
+ triggerDataUpdate();
+ }
+ }
+
+ images = [];
+ loadImageData(one, onceWeHaveBoth);
+ loadImageData(two, onceWeHaveBoth);
+ }
+
+ function getCompareApi(param){
+
+ var secondFileData,
+ hasMethod = typeof param === 'function';
+
+ if( !hasMethod ){
+ // assume it's file data
+ secondFileData = param;
+ }
+
+ var self = {
+ ignoreNothing: function(){
+
+ tolerance.red = 16;
+ tolerance.green = 16;
+ tolerance.blue = 16;
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreAntialiasing: function(){
+
+ tolerance.red = 32;
+ tolerance.green = 32;
+ tolerance.blue = 32;
+ tolerance.minBrightness = 64;
+ tolerance.maxBrightness = 96;
+
+ ignoreAntialiasing = true;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreColors: function(){
+
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = true;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ onComplete: function( callback ){
+
+ updateCallbackArray.push(callback);
+
+ var wrapper = function(){
+ compare(fileData, secondFileData);
+ };
+
+ wrapper();
+
+ return getCompareApi(wrapper);
+ }
+ };
+
+ return self;
+ }
+
+ return {
+ onComplete: function( callback ){
+ updateCallbackArray.push(callback);
+ loadImageData(fileData, function(imageData, width, height){
+ parseImage(imageData.data, width, height);
+ });
+ },
+ compareTo: function(secondFileData){
+ return getCompareApi(secondFileData);
+ }
+ };
+
+ };
+}(this));
\ No newline at end of file
diff --git a/test/testsuite.js b/test/testsuite.js
deleted file mode 100644
index b486acb..0000000
--- a/test/testsuite.js
+++ /dev/null
@@ -1,36 +0,0 @@
-requirejs.config({
- baseUrl: '/test/unit/'
-});
-
-define(function(require) {
- var testModules = [
- 'Pixi',
- 'Point',
- 'Rectangle',
- 'DisplayObject',
- 'DisplayObjectContainer',
- 'Sprite',
- 'MovieClip',
- 'InteractionManager',
- 'Stage',
- 'utils/Utils',
- 'utils/EventTarget',
- 'utils/Matrix',
- 'utils/Detector',
- 'renderers/WebGLShaders',
- 'renderers/WebGLRenderer',
- 'renderers/WebGLBatch',
- 'renderers/CanvasRenderer',
- 'extras/Strip',
- 'extras/Rope',
- 'textures/BaseTexture',
- 'textures/Texture',
- 'loaders/SpriteSheetLoader',
- 'loaders/AssetLoader'
- ];
-
- // Resolve all testModules and then start the Test Runner.
- require(testModules, function() {
- QUnit.start();
- });
-});
\ No newline at end of file
diff --git a/test/textures/SpriteSheet-Aliens.png b/test/textures/SpriteSheet-Aliens.png
new file mode 100644
index 0000000..210acb1
--- /dev/null
+++ b/test/textures/SpriteSheet-Aliens.png
Binary files differ
diff --git a/test/textures/SpriteSheet-Explosion.png b/test/textures/SpriteSheet-Explosion.png
new file mode 100755
index 0000000..79e1a69
--- /dev/null
+++ b/test/textures/SpriteSheet-Explosion.png
Binary files differ
diff --git a/test/textures/bunny.png b/test/textures/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/textures/bunny.png
Binary files differ
diff --git a/test/unit/DisplayObject.js b/test/unit/DisplayObject.js
deleted file mode 100644
index 5e7e72f..0000000
--- a/test/unit/DisplayObject.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObject');
-});
diff --git a/test/unit/DisplayObjectContainer.js b/test/unit/DisplayObjectContainer.js
deleted file mode 100644
index b323959..0000000
--- a/test/unit/DisplayObjectContainer.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObjectContainer');
-});
diff --git a/test/unit/InteractionManager.js b/test/unit/InteractionManager.js
deleted file mode 100644
index e751f52..0000000
--- a/test/unit/InteractionManager.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('InteractionManager');
-});
diff --git a/test/unit/MovieClip.js b/test/unit/MovieClip.js
deleted file mode 100644
index 37d9446..0000000
--- a/test/unit/MovieClip.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('MovieClip');
-});
diff --git a/test/unit/Pixi.js b/test/unit/Pixi.js
deleted file mode 100644
index 36eee73..0000000
--- a/test/unit/Pixi.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Pixi');
-});
diff --git a/test/unit/Point.js b/test/unit/Point.js
deleted file mode 100644
index 983ff6e..0000000
--- a/test/unit/Point.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Point');
-});
diff --git a/test/unit/Rectangle.js b/test/unit/Rectangle.js
deleted file mode 100644
index 3b439ba..0000000
--- a/test/unit/Rectangle.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Rectangle');
-});
diff --git a/test/unit/Sprite.js b/test/unit/Sprite.js
deleted file mode 100644
index ed4f596..0000000
--- a/test/unit/Sprite.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Sprite');
-});
diff --git a/test/unit/Stage.js b/test/unit/Stage.js
deleted file mode 100644
index 2d70291..0000000
--- a/test/unit/Stage.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Stage');
-});
diff --git a/test/unit/extras/Rope.js b/test/unit/extras/Rope.js
deleted file mode 100644
index 5606f14..0000000
--- a/test/unit/extras/Rope.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Rope');
-});
diff --git a/test/unit/extras/Strip.js b/test/unit/extras/Strip.js
deleted file mode 100644
index 0134d3a..0000000
--- a/test/unit/extras/Strip.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Strip');
-});
diff --git a/test/unit/loaders/AssetLoader.js b/test/unit/loaders/AssetLoader.js
deleted file mode 100644
index 13b8443..0000000
--- a/test/unit/loaders/AssetLoader.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('AssetLoader');
-});
diff --git a/test/unit/loaders/SpriteSheetLoader.js b/test/unit/loaders/SpriteSheetLoader.js
deleted file mode 100644
index 8bf0cb2..0000000
--- a/test/unit/loaders/SpriteSheetLoader.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('SpriteSheetLoader');
-});
diff --git a/test/unit/pixi/InteractionManager.js b/test/unit/pixi/InteractionManager.js
new file mode 100644
index 0000000..ed3001f
--- /dev/null
+++ b/test/unit/pixi/InteractionManager.js
@@ -0,0 +1,10 @@
+describe('pixi/InteractionManager', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var InteractionManager = PIXI.InteractionManager;
+
+ it('Module exists', function () {
+ expect(InteractionManager).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/Pixi.js b/test/unit/pixi/Pixi.js
new file mode 100644
index 0000000..27debc1
--- /dev/null
+++ b/test/unit/pixi/Pixi.js
@@ -0,0 +1,9 @@
+describe('pixi/Pixi', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+
+ it('Module exists', function () {
+ expect(global).to.have.property('PIXI').and.to.be.an('object');
+ });
+});
diff --git a/test/unit/pixi/core/Circle.js b/test/unit/pixi/core/Circle.js
new file mode 100644
index 0000000..93a4456
--- /dev/null
+++ b/test/unit/pixi/core/Circle.js
@@ -0,0 +1,22 @@
+describe('pixi/core/Circle', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Circle = PIXI.Circle;
+
+ it('Module exists', function () {
+ expect(Circle).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Circle();
+
+ expect(obj).to.be.an.instanceof(Circle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', 0);
+ expect(obj).to.have.property('y', 0);
+ expect(obj).to.have.property('radius', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Ellipse.js b/test/unit/pixi/core/Ellipse.js
new file mode 100644
index 0000000..026b56f
--- /dev/null
+++ b/test/unit/pixi/core/Ellipse.js
@@ -0,0 +1,24 @@
+describe('pixi/core/Ellipse', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Ellipse = PIXI.Ellipse;
+
+ it('Module exists', function () {
+ expect(Ellipse).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Ellipse();
+
+ expect(obj).to.be.an.instanceof(Ellipse);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+ expect(obj).to.respondTo('getBounds');
+
+ expect(obj).to.have.property('x', 0);
+ expect(obj).to.have.property('y', 0);
+ expect(obj).to.have.property('width', 0);
+ expect(obj).to.have.property('height', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Matrix.js b/test/unit/pixi/core/Matrix.js
new file mode 100644
index 0000000..b48989e
--- /dev/null
+++ b/test/unit/pixi/core/Matrix.js
@@ -0,0 +1,30 @@
+describe('pixi/core/Matrix', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var mat3 = PIXI.mat3;
+ var mat4 = PIXI.mat4;
+ var Matrix = PIXI.Matrix;
+
+ it('Ensure determineMatrixArrayType works', function () {
+ expect(Matrix).to.be.a('function');
+ });
+
+ it('mat3 exists', function () {
+ expect(mat3).to.be.an('object');
+ });
+
+ it('Confirm new mat3 matrix', function () {
+ var matrix = new mat3.create();
+ pixi_core_Matrix_confirmNewMat3(matrix);
+ });
+
+ it('mat3 exists', function () {
+ expect(mat4).to.be.an('object');
+ });
+
+ it('Confirm new mat4 matrix', function () {
+ var matrix = new mat4.create();
+ pixi_core_Matrix_confirmNewMat4(matrix);
+ });
+});
diff --git a/test/unit/pixi/core/Point.js b/test/unit/pixi/core/Point.js
new file mode 100644
index 0000000..c4d5163
--- /dev/null
+++ b/test/unit/pixi/core/Point.js
@@ -0,0 +1,15 @@
+describe('pixi/core/Point', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Point = PIXI.Point;
+
+ it('Module exists', function () {
+ expect(Point).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Point();
+ pixi_core_Point_confirm(obj, 0, 0);
+ });
+});
diff --git a/test/unit/pixi/core/Polygon.js b/test/unit/pixi/core/Polygon.js
new file mode 100644
index 0000000..dc8c918
--- /dev/null
+++ b/test/unit/pixi/core/Polygon.js
@@ -0,0 +1,20 @@
+describe('pixi/core/Polygon', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Polygon = PIXI.Polygon;
+
+ it('Module exists', function () {
+ expect(Polygon).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Polygon();
+
+ expect(obj).to.be.an.instanceof(Polygon);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.deep.property('points.length', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Rectangle.js b/test/unit/pixi/core/Rectangle.js
new file mode 100644
index 0000000..d43316e
--- /dev/null
+++ b/test/unit/pixi/core/Rectangle.js
@@ -0,0 +1,15 @@
+describe('pixi/core/Rectangle', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Rectangle = PIXI.Rectangle;
+
+ it('Module exists', function () {
+ expect(Rectangle).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var rect = new Rectangle();
+ pixi_core_Rectangle_confirm(rect, 0, 0, 0, 0);
+ });
+});
diff --git a/test/unit/pixi/display/DisplayObject.js b/test/unit/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..40c6fbc
--- /dev/null
+++ b/test/unit/pixi/display/DisplayObject.js
@@ -0,0 +1,21 @@
+describe('pixi/display/DisplayObject', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var DisplayObject = PIXI.DisplayObject;
+
+ it('Module exists', function () {
+ expect(DisplayObject).to.be.a('function');
+ expect(PIXI).to.have.property('visibleCount', 0);
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new DisplayObject();
+
+ pixi_display_DisplayObject_confirmNew(obj);
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', false);
+ expect(obj).to.have.property('stage', null);
+ });
+});
diff --git a/.gitignore b/.gitignore
index 12e1b62..0b88317 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
node_modules
.DS_Store
-.project
\ No newline at end of file
+.project
+*.log
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..63e4d7c
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,8 @@
+language: node_js
+node_js:
+ - 0.10
+
+before_script:
+ - npm install -g grunt-cli
+ - export DISPLAY=:99.0
+ - sh -e /etc/init.d/xvfb start
diff --git a/Gruntfile.js b/Gruntfile.js
index b083b49..103938c 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -1,10 +1,12 @@
+'use strict';
+
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-connect');
- grunt.loadNpmTasks('grunt-contrib-qunit');
grunt.loadNpmTasks('grunt-contrib-yuidoc');
+ grunt.loadTasks('tasks');
var root = 'src/pixi/',
debug = 'bin/pixi.dev.js',
@@ -79,7 +81,7 @@
},
files: {
srcBlob: '<%= dirs.src %>/**/*.js',
- testBlob: '<%= dirs.test %>/unit/**/*.js',
+ testBlob: '<%= dirs.test %>/{functional,lib/pixi,unit}/**/*.js',
build: '<%= dirs.build %>/pixi.dev.js',
buildMin: '<%= dirs.build %>/pixi.js'
},
@@ -94,7 +96,12 @@
},
jshint: {
beforeconcat: srcFiles,
- test: ['<%= files.testBlob %>'],
+ test: {
+ src: ['<%= files.testBlob %>'],
+ options: {
+ expr: true
+ }
+ },
options: {
asi: true,
smarttabs: true
@@ -128,12 +135,6 @@
]
},
connect: {
- qunit: {
- options: {
- port: grunt.option('port-test') || 9002,
- base: './'
- }
- },
test: {
options: {
port: grunt.option('port-test') || 9002,
@@ -142,13 +143,6 @@
}
}
},
- qunit: {
- all: {
- options: {
- urls: ['http://localhost:' + (grunt.option('port-test') || 9002) + '/test/index.html']
- }
- }
- },
yuidoc: {
compile: {
name: '<%= pkg.name %>',
@@ -161,6 +155,13 @@
outdir: '<%= dirs.docs %>'
}
}
+ },
+ karma: {
+ unit: {
+ configFile: 'test/karma.conf.js',
+ // browsers: ['Chrome'],
+ singleRun: true
+ }
}
});
@@ -182,9 +183,10 @@
}
)
- grunt.registerTask('default', ['concat', 'uglify', 'distribute']);
grunt.registerTask('build', ['concat', 'uglify', 'distribute']);
- grunt.registerTask('test', ['build', 'connect:qunit', 'qunit']);
+ grunt.registerTask('test', ['concat', 'jshint:test', 'karma']);
grunt.registerTask('docs', ['yuidoc']);
-
-}
\ No newline at end of file
+ grunt.registerTask('default', ['test', 'uglify', 'distribute']);
+ // Travis CI task.
+ grunt.registerTask('travis', ['test']);
+}
diff --git a/README.md b/README.md
index c62ef86..690cfe4 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,8 @@

+[](http://travis-ci.org/drkibitz/pixi.js)
+
#### JavaScript 2D Renderer ####
The aim of this project is to provide a fast lightweight 2D library that works
diff --git a/package.json b/package.json
index b373240..1246a68 100644
--- a/package.json
+++ b/package.json
@@ -18,14 +18,21 @@
"main": "bin/pixi.js",
+ "scripts": {
+ "test": "grunt travis --verbose"
+ },
+
"dependencies": {},
"devDependencies": {
"grunt": "~0.4.x",
- "grunt-contrib-jshint": "0.3.x",
+ "grunt-contrib-jshint": "0.6.x",
"grunt-contrib-uglify": "0.2.x",
- "grunt-contrib-connect": "0.2.x",
- "grunt-contrib-qunit": "0.2.x",
+ "grunt-contrib-connect": "0.3.x",
"grunt-contrib-yuidoc": "0.4.x",
- "grunt-contrib-concat": "0.1.x"
+ "grunt-contrib-concat": "0.3.x",
+ "chai": "~1.7.0",
+ "karma": "0.11.0",
+ "karma-firefox-launcher": "0.1.0",
+ "karma-mocha": "0.1.0"
}
}
diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js
index a7c520e..ee82bbd 100644
--- a/src/pixi/InteractionManager.js
+++ b/src/pixi/InteractionManager.js
@@ -62,7 +62,6 @@
this.onTouchEnd = this.onTouchEnd.bind(this);
this.onTouchMove = this.onTouchMove.bind(this);
-
this.last = 0;
}
diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js
index 1a95d20..eef1059 100644
--- a/src/pixi/core/Ellipse.js
+++ b/src/pixi/core/Ellipse.js
@@ -78,7 +78,7 @@
return (normx + normy < 0.25);
}
-PIXI.Ellipse.getBounds = function()
+PIXI.Ellipse.prototype.getBounds = function()
{
return new PIXI.Rectangle(this.x, this.y, this.width, this.height);
}
diff --git a/tasks/karma.js b/tasks/karma.js
new file mode 100644
index 0000000..c340485
--- /dev/null
+++ b/tasks/karma.js
@@ -0,0 +1,27 @@
+'use strict';
+
+var path = require('path');
+var server = require('karma').server;
+
+module.exports = function (grunt) {
+ grunt.registerMultiTask('karma', 'run karma.', function() {
+ var done = this.async();
+ var options = this.options({
+ background: false
+ });
+ var data = this.data;
+
+ //merge options onto data, with data taking precedence
+ data = grunt.util._.merge(options, data);
+ data.configFile = path.resolve(data.configFile);
+ if (data.configFile) {
+ data.configFile = grunt.template.process(data.configFile);
+ }
+
+ server.start(
+ data,
+ function(code) {
+ done(!code);
+ });
+ });
+};
diff --git a/test/functional/example-1-basics/bunny.png b/test/functional/example-1-basics/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/functional/example-1-basics/bunny.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-30.png b/test/functional/example-1-basics/frame-30.png
new file mode 100644
index 0000000..96e3409
--- /dev/null
+++ b/test/functional/example-1-basics/frame-30.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-60.png b/test/functional/example-1-basics/frame-60.png
new file mode 100644
index 0000000..af3f4ce
--- /dev/null
+++ b/test/functional/example-1-basics/frame-60.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-90.png b/test/functional/example-1-basics/frame-90.png
new file mode 100644
index 0000000..099b823
--- /dev/null
+++ b/test/functional/example-1-basics/frame-90.png
Binary files differ
diff --git a/test/functional/example-1-basics/index.js b/test/functional/example-1-basics/index.js
new file mode 100644
index 0000000..7ae7a98
--- /dev/null
+++ b/test/functional/example-1-basics/index.js
@@ -0,0 +1,133 @@
+describe('Example 1 - Basics', function () {
+ 'use strict';
+
+ var baseUri = '/base/test/functional/example-1-basics';
+ var expect = chai.expect;
+ var currentFrame = 0;
+ var frameEvents = {};
+ var stage;
+ var renderer;
+ var bunny;
+
+ function onFrame(frame, callback) {
+ frameEvents[frame] = callback;
+ }
+
+ function animate() {
+ currentFrame += 1;
+
+ requestAnimFrame( animate );
+
+ // just for fun, lets rotate mr rabbit a little
+ bunny.rotation += 0.1;
+
+ // render the stage
+ renderer.render(stage);
+
+ if (frameEvents[currentFrame])
+ frameEvents[currentFrame](currentFrame);
+ }
+
+ function initScene() {
+ // create an new instance of a pixi stage
+ stage = new PIXI.Stage(0x66FF99);
+
+ // create a renderer instance
+ renderer = PIXI.autoDetectRenderer(400, 300);
+ console.log('Is PIXI.WebGLRenderer: ' + (renderer instanceof PIXI.WebGLRenderer));
+
+ // add the renderer view element to the DOM
+ document.body.appendChild(renderer.view);
+
+ requestAnimFrame( animate );
+
+ // create a texture from an image path
+ var texture = PIXI.Texture.fromImage(baseUri + "/bunny.png");
+ // create a new Sprite using the texture
+ bunny = new PIXI.Sprite(texture);
+
+ // center the sprites anchor point
+ bunny.anchor.x = 0.5;
+ bunny.anchor.y = 0.5;
+
+ // move the sprite t the center of the screen
+ bunny.position.x = 200;
+ bunny.position.y = 150;
+
+ stage.addChild(bunny);
+ }
+
+ it('assets loaded', function (done) {
+ var loader = new PIXI.AssetLoader([
+ baseUri + '/bunny.png',
+ baseUri + '/frame-30.png',
+ baseUri + '/frame-60.png',
+ baseUri + '/frame-90.png'
+ ]);
+ // loader.on('onProgress', function (event) {
+ // console.log(event.content);
+ // });
+ loader.on('onComplete', function (event) {
+ done();
+ initScene();
+ });
+ loader.load();
+ });
+
+ it('frame 30 should match', function (done) {
+ this.timeout(700);
+ onFrame(30, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-30.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 60 should match', function (done) {
+ this.timeout(1200);
+ onFrame(60, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-60.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 90 should match', function (done) {
+ this.timeout(1700);
+ onFrame(90, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-90.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ // it('capture something', function (done) {
+ // this.timeout(2000000);
+ // onFrame(30, function () {
+ // var img = new Image();
+ // img.src = renderer.view.toDataURL('image/png');
+ // document.body.appendChild(img);
+ // });
+ // });
+});
diff --git a/test/index.html b/test/index.html
deleted file mode 100644
index 9cbcac5..0000000
--- a/test/index.html
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
- Pixi.js Test Suite
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/test/karma.conf.js b/test/karma.conf.js
new file mode 100644
index 0000000..c66a696
--- /dev/null
+++ b/test/karma.conf.js
@@ -0,0 +1,82 @@
+module.exports = function(config) {
+ config.set({
+
+ // base path, that will be used to resolve files and exclude
+ basePath : '../',
+
+ frameworks : ['mocha'],
+
+ // list of files / patterns to load in the browser
+ files : [
+ 'node_modules/chai/chai.js',
+ 'bin/pixi.dev.js',
+ 'test/lib/**/*.js',
+ 'test/unit/**/*.js',
+ // 'test/functional/**/*.js',
+ {pattern: 'test/**/*.png', watched: false, included: false, served: true}
+ ],
+
+ // list of files to exclude
+ exclude : [],
+
+ // use dolts reporter, as travis terminal does not support escaping sequences
+ // possible values: 'dots', 'progress', 'junit', 'teamcity'
+ // CLI --reporters progress
+ reporters : ['progress'],
+
+ // web server port
+ // CLI --port 9876
+ port : 9876,
+
+ // cli runner port
+ // CLI --runner-port 9100
+ runnerPort : 9100,
+
+ // enable / disable colors in the output (reporters and logs)
+ // CLI --colors --no-colors
+ colors : true,
+
+ // level of logging
+ // possible values: karma.LOG_DISABLE || karma.LOG_ERROR || karma.LOG_WARN || karma.LOG_INFO || karma.LOG_DEBUG
+ // CLI --log-level debug
+ logLevel : config.LOG_DEBUG,
+
+ // enable / disable watching file and executing tests whenever any file changes
+ // CLI --auto-watch --no-auto-watch
+ autoWatch : false,
+
+ // Start these browsers, currently available:
+ // - Chrome
+ // - ChromeCanary
+ // - Firefox
+ // - Opera
+ // - Safari (only Mac)
+ // - PhantomJS
+ // - IE (only Windows)
+ // CLI --browsers Chrome,Firefox,Safari
+ browsers : ['Firefox'],
+
+ // If browser does not capture in given timeout [ms], kill it
+ // CLI --capture-timeout 5000
+ captureTimeout : 5000,
+
+ // Auto run tests on start (when browsers are captured) and exit
+ // CLI --single-run --no-single-run
+ singleRun : true,
+
+ // report which specs are slower than 500ms
+ // CLI --report-slower-than 500
+ reportSlowerThan : 1000,
+
+ preprocessors : {
+ // '**/client/js/*.js': 'coverage'
+ },
+
+ plugins : [
+ 'karma-mocha',
+ // 'karma-chrome-launcher',
+ 'karma-firefox-launcher',
+ // 'karma-phantomjs-launcher'
+ ]
+ });
+};
diff --git a/test/lib/pixi/core/Matrix.js b/test/lib/pixi/core/Matrix.js
new file mode 100644
index 0000000..d26386b
--- /dev/null
+++ b/test/lib/pixi/core/Matrix.js
@@ -0,0 +1,40 @@
+
+function pixi_core_Matrix_confirmNewMat3(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(1);
+ expect(matrix[5]).to.equal(0);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(1);
+}
+
+function pixi_core_Matrix_confirmNewMat4(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[0]).to.equal(1);
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(0);
+ expect(matrix[5]).to.equal(1);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(0);
+ expect(matrix[9]).to.equal(0);
+ expect(matrix[10]).to.equal(1);
+ expect(matrix[11]).to.equal(0);
+ expect(matrix[12]).to.equal(0);
+ expect(matrix[13]).to.equal(0);
+ expect(matrix[14]).to.equal(0);
+ expect(matrix[15]).to.equal(1);
+}
diff --git a/test/lib/pixi/core/Point.js b/test/lib/pixi/core/Point.js
new file mode 100644
index 0000000..e5df07b
--- /dev/null
+++ b/test/lib/pixi/core/Point.js
@@ -0,0 +1,10 @@
+
+function pixi_core_Point_confirm(obj, x, y) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Point);
+ expect(obj).to.respondTo('clone');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+}
diff --git a/test/lib/pixi/core/Rectangle.js b/test/lib/pixi/core/Rectangle.js
new file mode 100644
index 0000000..23f0d12
--- /dev/null
+++ b/test/lib/pixi/core/Rectangle.js
@@ -0,0 +1,13 @@
+
+function pixi_core_Rectangle_confirm(obj, x, y, width, height) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Rectangle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+ expect(obj).to.have.property('width', width);
+ expect(obj).to.have.property('height', height);
+}
diff --git a/test/lib/pixi/display/DisplayObject.js b/test/lib/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..1388a7f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObject.js
@@ -0,0 +1,43 @@
+
+function pixi_display_DisplayObject_confirmNew(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObject);
+ expect(obj).to.respondTo('setInteractive');
+ expect(obj).to.respondTo('addFilter');
+ expect(obj).to.respondTo('removeFilter');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.property('last', obj);
+ expect(obj).to.have.property('first', obj);
+
+ expect(obj).to.contain.property('position');
+ pixi_core_Point_confirm(obj.position, 0, 0);
+ expect(obj).to.contain.property('scale');
+ pixi_core_Point_confirm(obj.scale, 1, 1);
+ expect(obj).to.contain.property('pivot');
+ pixi_core_Point_confirm(obj.pivot, 0, 0);
+
+ expect(obj).to.have.property('rotation', 0);
+ expect(obj).to.have.property('alpha', 1);
+ expect(obj).to.have.property('visible', true);
+ expect(obj).to.have.property('buttonMode', false);
+ expect(obj).to.have.property('parent', null);
+ expect(obj).to.have.property('worldAlpha', 1);
+
+ expect(obj).to.have.property('hitArea');
+ expect(obj).to.have.property('interactive'); // TODO: Have a better default value
+ expect('mask' in obj).to.be.true; // TODO: Have a better default value
+ expect(obj.mask).to.be.undefined;
+
+ expect(obj).to.have.property('renderable');
+ expect(obj).to.have.property('stage');
+
+ expect(obj).to.have.deep.property('worldTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ expect(obj).to.have.deep.property('localTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.localTransform);
+
+ expect(obj).to.have.deep.property('color.length', 0);
+ expect(obj).to.have.property('dynamic', true);
+}
diff --git a/test/lib/pixi/display/DisplayObjectContainer.js b/test/lib/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..085c59f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,16 @@
+
+function pixi_display_DisplayObjectContainer_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObject_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObjectContainer);
+ expect(obj).to.respondTo('addChild');
+ expect(obj).to.respondTo('addChildAt');
+ expect(obj).to.respondTo('swapChildren');
+ expect(obj).to.respondTo('getChildAt');
+ expect(obj).to.respondTo('removeChild');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('children.length', 0);
+}
diff --git a/test/lib/pixi/display/Sprite.js b/test/lib/pixi/display/Sprite.js
new file mode 100644
index 0000000..cc7a2d6
--- /dev/null
+++ b/test/lib/pixi/display/Sprite.js
@@ -0,0 +1,28 @@
+
+function pixi_display_Sprite_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Sprite);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', true);
+ expect(obj).to.have.property('stage', null);
+
+ expect(obj).to.have.property('anchor');
+ pixi_core_Point_confirm(obj.anchor, 0, 0);
+
+ expect(obj).to.have.property('blendMode', PIXI.blendModes.NORMAL);
+ expect(obj).to.have.property('width', 1); // TODO: is 1 expected
+ expect(obj).to.have.property('height', 1); // TODO: is 1 expected
+
+ // FIXME: Just make this a boolean that is always there
+ expect(!!obj.updateFrame).to.equal(obj.texture.baseTexture.hasLoaded);
+
+ expect(obj).to.have.property('texture');
+ pixi_textures_Texture_confirmNew(obj.texture, done);
+}
diff --git a/test/lib/pixi/extras/Strip.js b/test/lib/pixi/extras/Strip.js
new file mode 100644
index 0000000..8927a8a
--- /dev/null
+++ b/test/lib/pixi/extras/Strip.js
@@ -0,0 +1,12 @@
+
+function pixi_extras_Strip_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Strip);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ // TODO: Test properties
+}
diff --git a/test/lib/pixi/textures/Texture.js b/test/lib/pixi/textures/Texture.js
new file mode 100644
index 0000000..d5867b6
--- /dev/null
+++ b/test/lib/pixi/textures/Texture.js
@@ -0,0 +1,31 @@
+
+function pixi_textures_Texture_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ function confirmFrameDone() {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, obj.baseTexture.width, obj.baseTexture.height);
+
+ expect(obj).to.have.property('width', obj.baseTexture.width);
+ expect(obj).to.have.property('height', obj.baseTexture.height);
+ done();
+ }
+
+ expect(obj).to.be.an.instanceof(PIXI.Texture);
+ pixi_utils_EventTarget_like(obj);
+
+ expect(obj).to.have.property('baseTexture')
+ .and.to.be.an.instanceof(PIXI.BaseTexture);
+
+ expect(obj).to.have.property('scope', obj);
+
+ expect(obj).to.have.property('trim');
+ pixi_core_Point_confirm(obj.trim, 0, 0);
+
+ expect(obj).to.have.property('frame');
+ if (obj.baseTexture.hasLoaded) {
+ confirmFrameDone();
+ } else {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, 1, 1);
+ obj.addEventListener('update', confirmFrameDone);
+ }
+}
diff --git a/test/lib/pixi/utils/EventTarget.js b/test/lib/pixi/utils/EventTarget.js
new file mode 100644
index 0000000..7b1dcfa
--- /dev/null
+++ b/test/lib/pixi/utils/EventTarget.js
@@ -0,0 +1,8 @@
+
+function pixi_utils_EventTarget_like(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.respondTo('addEventListener');
+ expect(obj).to.respondTo('dispatchEvent');
+ expect(obj).to.respondTo('removeEventListener');
+}
diff --git a/test/lib/qunit-1.11.0.css b/test/lib/qunit-1.11.0.css
deleted file mode 100644
index d7fc0c8..0000000
--- a/test/lib/qunit-1.11.0.css
+++ /dev/null
@@ -1,244 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-/** Font Family and Sizes */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
- font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
-}
-
-#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
-#qunit-tests { font-size: smaller; }
-
-
-/** Resets */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter {
- margin: 0;
- padding: 0;
-}
-
-
-/** Header */
-
-#qunit-header {
- padding: 0.5em 0 0.5em 1em;
-
- color: #8699a4;
- background-color: #0d3349;
-
- font-size: 1.5em;
- line-height: 1em;
- font-weight: normal;
-
- border-radius: 5px 5px 0 0;
- -moz-border-radius: 5px 5px 0 0;
- -webkit-border-top-right-radius: 5px;
- -webkit-border-top-left-radius: 5px;
-}
-
-#qunit-header a {
- text-decoration: none;
- color: #c2ccd1;
-}
-
-#qunit-header a:hover,
-#qunit-header a:focus {
- color: #fff;
-}
-
-#qunit-testrunner-toolbar label {
- display: inline-block;
- padding: 0 .5em 0 .1em;
-}
-
-#qunit-banner {
- height: 5px;
-}
-
-#qunit-testrunner-toolbar {
- padding: 0.5em 0 0.5em 2em;
- color: #5E740B;
- background-color: #eee;
- overflow: hidden;
-}
-
-#qunit-userAgent {
- padding: 0.5em 0 0.5em 2.5em;
- background-color: #2b81af;
- color: #fff;
- text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
-}
-
-#qunit-modulefilter-container {
- float: right;
-}
-
-/** Tests: Pass/Fail */
-
-#qunit-tests {
- list-style-position: inside;
-}
-
-#qunit-tests li {
- padding: 0.4em 0.5em 0.4em 2.5em;
- border-bottom: 1px solid #fff;
- list-style-position: inside;
-}
-
-#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running {
- display: none;
-}
-
-#qunit-tests li strong {
- cursor: pointer;
-}
-
-#qunit-tests li a {
- padding: 0.5em;
- color: #c2ccd1;
- text-decoration: none;
-}
-#qunit-tests li a:hover,
-#qunit-tests li a:focus {
- color: #000;
-}
-
-#qunit-tests li .runtime {
- float: right;
- font-size: smaller;
-}
-
-.qunit-assert-list {
- margin-top: 0.5em;
- padding: 0.5em;
-
- background-color: #fff;
-
- border-radius: 5px;
- -moz-border-radius: 5px;
- -webkit-border-radius: 5px;
-}
-
-.qunit-collapsed {
- display: none;
-}
-
-#qunit-tests table {
- border-collapse: collapse;
- margin-top: .2em;
-}
-
-#qunit-tests th {
- text-align: right;
- vertical-align: top;
- padding: 0 .5em 0 0;
-}
-
-#qunit-tests td {
- vertical-align: top;
-}
-
-#qunit-tests pre {
- margin: 0;
- white-space: pre-wrap;
- word-wrap: break-word;
-}
-
-#qunit-tests del {
- background-color: #e0f2be;
- color: #374e0c;
- text-decoration: none;
-}
-
-#qunit-tests ins {
- background-color: #ffcaca;
- color: #500;
- text-decoration: none;
-}
-
-/*** Test Counts */
-
-#qunit-tests b.counts { color: black; }
-#qunit-tests b.passed { color: #5E740B; }
-#qunit-tests b.failed { color: #710909; }
-
-#qunit-tests li li {
- padding: 5px;
- background-color: #fff;
- border-bottom: none;
- list-style-position: inside;
-}
-
-/*** Passing Styles */
-
-#qunit-tests li li.pass {
- color: #3c510c;
- background-color: #fff;
- border-left: 10px solid #C6E746;
-}
-
-#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
-#qunit-tests .pass .test-name { color: #366097; }
-
-#qunit-tests .pass .test-actual,
-#qunit-tests .pass .test-expected { color: #999999; }
-
-#qunit-banner.qunit-pass { background-color: #C6E746; }
-
-/*** Failing Styles */
-
-#qunit-tests li li.fail {
- color: #710909;
- background-color: #fff;
- border-left: 10px solid #EE5757;
- white-space: pre;
-}
-
-#qunit-tests > li:last-child {
- border-radius: 0 0 5px 5px;
- -moz-border-radius: 0 0 5px 5px;
- -webkit-border-bottom-right-radius: 5px;
- -webkit-border-bottom-left-radius: 5px;
-}
-
-#qunit-tests .fail { color: #000000; background-color: #EE5757; }
-#qunit-tests .fail .test-name,
-#qunit-tests .fail .module-name { color: #000000; }
-
-#qunit-tests .fail .test-actual { color: #EE5757; }
-#qunit-tests .fail .test-expected { color: green; }
-
-#qunit-banner.qunit-fail { background-color: #EE5757; }
-
-
-/** Result */
-
-#qunit-testresult {
- padding: 0.5em 0.5em 0.5em 2.5em;
-
- color: #2b81af;
- background-color: #D2E0E6;
-
- border-bottom: 1px solid white;
-}
-#qunit-testresult .module-name {
- font-weight: bold;
-}
-
-/** Fixture */
-
-#qunit-fixture {
- position: absolute;
- top: -10000px;
- left: -10000px;
- width: 1000px;
- height: 1000px;
-}
diff --git a/test/lib/qunit-1.11.0.js b/test/lib/qunit-1.11.0.js
deleted file mode 100644
index 302545f..0000000
--- a/test/lib/qunit-1.11.0.js
+++ /dev/null
@@ -1,2152 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-(function( window ) {
-
-var QUnit,
- assert,
- config,
- onErrorFnPrev,
- testId = 0,
- fileName = (sourceFromStacktrace( 0 ) || "" ).replace(/(:\d+)+\)?/, "").replace(/.+\//, ""),
- toString = Object.prototype.toString,
- hasOwn = Object.prototype.hasOwnProperty,
- // Keep a local reference to Date (GH-283)
- Date = window.Date,
- defined = {
- setTimeout: typeof window.setTimeout !== "undefined",
- sessionStorage: (function() {
- var x = "qunit-test-string";
- try {
- sessionStorage.setItem( x, x );
- sessionStorage.removeItem( x );
- return true;
- } catch( e ) {
- return false;
- }
- }())
- },
- /**
- * Provides a normalized error string, correcting an issue
- * with IE 7 (and prior) where Error.prototype.toString is
- * not properly implemented
- *
- * Based on http://es5.github.com/#x15.11.4.4
- *
- * @param {String|Error} error
- * @return {String} error message
- */
- errorString = function( error ) {
- var name, message,
- errorString = error.toString();
- if ( errorString.substring( 0, 7 ) === "[object" ) {
- name = error.name ? error.name.toString() : "Error";
- message = error.message ? error.message.toString() : "";
- if ( name && message ) {
- return name + ": " + message;
- } else if ( name ) {
- return name;
- } else if ( message ) {
- return message;
- } else {
- return "Error";
- }
- } else {
- return errorString;
- }
- },
- /**
- * Makes a clone of an object using only Array or Object as base,
- * and copies over the own enumerable properties.
- *
- * @param {Object} obj
- * @return {Object} New object with only the own properties (recursively).
- */
- objectValues = function( obj ) {
- // Grunt 0.3.x uses an older version of jshint that still has jshint/jshint#392.
- /*jshint newcap: false */
- var key, val,
- vals = QUnit.is( "array", obj ) ? [] : {};
- for ( key in obj ) {
- if ( hasOwn.call( obj, key ) ) {
- val = obj[key];
- vals[key] = val === Object(val) ? objectValues(val) : val;
- }
- }
- return vals;
- };
-
-function Test( settings ) {
- extend( this, settings );
- this.assertions = [];
- this.testNumber = ++Test.count;
-}
-
-Test.count = 0;
-
-Test.prototype = {
- init: function() {
- var a, b, li,
- tests = id( "qunit-tests" );
-
- if ( tests ) {
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml;
-
- // `a` initialized at top of scope
- a = document.createElement( "a" );
- a.innerHTML = "Rerun";
- a.href = QUnit.url({ testNumber: this.testNumber });
-
- li = document.createElement( "li" );
- li.appendChild( b );
- li.appendChild( a );
- li.className = "running";
- li.id = this.id = "qunit-test-output" + testId++;
-
- tests.appendChild( li );
- }
- },
- setup: function() {
- if ( this.module !== config.previousModule ) {
- if ( config.previousModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.previousModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
- config.previousModule = this.module;
- config.moduleStats = { all: 0, bad: 0 };
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- } else if ( config.autorun ) {
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- }
-
- config.current = this;
-
- this.testEnvironment = extend({
- setup: function() {},
- teardown: function() {}
- }, this.moduleTestEnvironment );
-
- this.started = +new Date();
- runLoggingCallbacks( "testStart", QUnit, {
- name: this.testName,
- module: this.module
- });
-
- // allow utility functions to access the current test environment
- // TODO why??
- QUnit.current_testEnvironment = this.testEnvironment;
-
- if ( !config.pollution ) {
- saveGlobal();
- }
- if ( config.notrycatch ) {
- this.testEnvironment.setup.call( this.testEnvironment );
- return;
- }
- try {
- this.testEnvironment.setup.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Setup failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- },
- run: function() {
- config.current = this;
-
- var running = id( "qunit-testresult" );
-
- if ( running ) {
- running.innerHTML = "Running:
" + this.nameHtml;
- }
-
- if ( this.async ) {
- QUnit.stop();
- }
-
- this.callbackStarted = +new Date();
-
- if ( config.notrycatch ) {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- return;
- }
-
- try {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- } catch( e ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
-
- QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + " " + this.stack + ": " + ( e.message || e ), extractStacktrace( e, 0 ) );
- // else next test will carry the responsibility
- saveGlobal();
-
- // Restart the tests if they're blocking
- if ( config.blocking ) {
- QUnit.start();
- }
- }
- },
- teardown: function() {
- config.current = this;
- if ( config.notrycatch ) {
- if ( typeof this.callbackRuntime === "undefined" ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
- }
- this.testEnvironment.teardown.call( this.testEnvironment );
- return;
- } else {
- try {
- this.testEnvironment.teardown.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Teardown failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- }
- checkPollution();
- },
- finish: function() {
- config.current = this;
- if ( config.requireExpects && this.expected === null ) {
- QUnit.pushFailure( "Expected number of assertions to be defined, but expect() was not called.", this.stack );
- } else if ( this.expected !== null && this.expected !== this.assertions.length ) {
- QUnit.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack );
- } else if ( this.expected === null && !this.assertions.length ) {
- QUnit.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions.", this.stack );
- }
-
- var i, assertion, a, b, time, li, ol,
- test = this,
- good = 0,
- bad = 0,
- tests = id( "qunit-tests" );
-
- this.runtime = +new Date() - this.started;
- config.stats.all += this.assertions.length;
- config.moduleStats.all += this.assertions.length;
-
- if ( tests ) {
- ol = document.createElement( "ol" );
- ol.className = "qunit-assert-list";
-
- for ( i = 0; i < this.assertions.length; i++ ) {
- assertion = this.assertions[i];
-
- li = document.createElement( "li" );
- li.className = assertion.result ? "pass" : "fail";
- li.innerHTML = assertion.message || ( assertion.result ? "okay" : "failed" );
- ol.appendChild( li );
-
- if ( assertion.result ) {
- good++;
- } else {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
-
- // store result when possible
- if ( QUnit.config.reorder && defined.sessionStorage ) {
- if ( bad ) {
- sessionStorage.setItem( "qunit-test-" + this.module + "-" + this.testName, bad );
- } else {
- sessionStorage.removeItem( "qunit-test-" + this.module + "-" + this.testName );
- }
- }
-
- if ( bad === 0 ) {
- addClass( ol, "qunit-collapsed" );
- }
-
- // `b` initialized at top of scope
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml + " (" + bad + ", " + good + ", " + this.assertions.length + ")";
-
- addEvent(b, "click", function() {
- var next = b.parentNode.lastChild,
- collapsed = hasClass( next, "qunit-collapsed" );
- ( collapsed ? removeClass : addClass )( next, "qunit-collapsed" );
- });
-
- addEvent(b, "dblclick", function( e ) {
- var target = e && e.target ? e.target : window.event.srcElement;
- if ( target.nodeName.toLowerCase() === "span" || target.nodeName.toLowerCase() === "b" ) {
- target = target.parentNode;
- }
- if ( window.location && target.nodeName.toLowerCase() === "strong" ) {
- window.location = QUnit.url({ testNumber: test.testNumber });
- }
- });
-
- // `time` initialized at top of scope
- time = document.createElement( "span" );
- time.className = "runtime";
- time.innerHTML = this.runtime + " ms";
-
- // `li` initialized at top of scope
- li = id( this.id );
- li.className = bad ? "fail" : "pass";
- li.removeChild( li.firstChild );
- a = li.firstChild;
- li.appendChild( b );
- li.appendChild( a );
- li.appendChild( time );
- li.appendChild( ol );
-
- } else {
- for ( i = 0; i < this.assertions.length; i++ ) {
- if ( !this.assertions[i].result ) {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
- }
-
- runLoggingCallbacks( "testDone", QUnit, {
- name: this.testName,
- module: this.module,
- failed: bad,
- passed: this.assertions.length - bad,
- total: this.assertions.length,
- duration: this.runtime
- });
-
- QUnit.reset();
-
- config.current = undefined;
- },
-
- queue: function() {
- var bad,
- test = this;
-
- synchronize(function() {
- test.init();
- });
- function run() {
- // each of these can by async
- synchronize(function() {
- test.setup();
- });
- synchronize(function() {
- test.run();
- });
- synchronize(function() {
- test.teardown();
- });
- synchronize(function() {
- test.finish();
- });
- }
-
- // `bad` initialized at top of scope
- // defer when previous test run passed, if storage is available
- bad = QUnit.config.reorder && defined.sessionStorage &&
- +sessionStorage.getItem( "qunit-test-" + this.module + "-" + this.testName );
-
- if ( bad ) {
- run();
- } else {
- synchronize( run, true );
- }
- }
-};
-
-// Root QUnit object.
-// `QUnit` initialized at top of scope
-QUnit = {
-
- // call on start of module test to prepend name to all tests
- module: function( name, testEnvironment ) {
- config.currentModule = name;
- config.currentModuleTestEnvironment = testEnvironment;
- config.modules[name] = true;
- },
-
- asyncTest: function( testName, expected, callback ) {
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- QUnit.test( testName, expected, callback, true );
- },
-
- test: function( testName, expected, callback, async ) {
- var test,
- nameHtml = "" + escapeText( testName ) + "";
-
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- if ( config.currentModule ) {
- nameHtml = "" + escapeText( config.currentModule ) + ": " + nameHtml;
- }
-
- test = new Test({
- nameHtml: nameHtml,
- testName: testName,
- expected: expected,
- async: async,
- callback: callback,
- module: config.currentModule,
- moduleTestEnvironment: config.currentModuleTestEnvironment,
- stack: sourceFromStacktrace( 2 )
- });
-
- if ( !validTest( test ) ) {
- return;
- }
-
- test.queue();
- },
-
- // Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through.
- expect: function( asserts ) {
- if (arguments.length === 1) {
- config.current.expected = asserts;
- } else {
- return config.current.expected;
- }
- },
-
- start: function( count ) {
- // QUnit hasn't been initialized yet.
- // Note: RequireJS (et al) may delay onLoad
- if ( config.semaphore === undefined ) {
- QUnit.begin(function() {
- // This is triggered at the top of QUnit.load, push start() to the event loop, to allow QUnit.load to finish first
- setTimeout(function() {
- QUnit.start( count );
- });
- });
- return;
- }
-
- config.semaphore -= count || 1;
- // don't start until equal number of stop-calls
- if ( config.semaphore > 0 ) {
- return;
- }
- // ignore if start is called more often then stop
- if ( config.semaphore < 0 ) {
- config.semaphore = 0;
- QUnit.pushFailure( "Called start() while already started (QUnit.config.semaphore was 0 already)", null, sourceFromStacktrace(2) );
- return;
- }
- // A slight delay, to avoid any current callbacks
- if ( defined.setTimeout ) {
- window.setTimeout(function() {
- if ( config.semaphore > 0 ) {
- return;
- }
- if ( config.timeout ) {
- clearTimeout( config.timeout );
- }
-
- config.blocking = false;
- process( true );
- }, 13);
- } else {
- config.blocking = false;
- process( true );
- }
- },
-
- stop: function( count ) {
- config.semaphore += count || 1;
- config.blocking = true;
-
- if ( config.testTimeout && defined.setTimeout ) {
- clearTimeout( config.timeout );
- config.timeout = window.setTimeout(function() {
- QUnit.ok( false, "Test timed out" );
- config.semaphore = 1;
- QUnit.start();
- }, config.testTimeout );
- }
- }
-};
-
-// `assert` initialized at top of scope
-// Asssert helpers
-// All of these must either call QUnit.push() or manually do:
-// - runLoggingCallbacks( "log", .. );
-// - config.current.assertions.push({ .. });
-// We attach it to the QUnit object *after* we expose the public API,
-// otherwise `assert` will become a global variable in browsers (#341).
-assert = {
- /**
- * Asserts rough true-ish result.
- * @name ok
- * @function
- * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" );
- */
- ok: function( result, msg ) {
- if ( !config.current ) {
- throw new Error( "ok() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
- result = !!result;
-
- var source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: msg
- };
-
- msg = escapeText( msg || (result ? "okay" : "failed" ) );
- msg = "" + msg + "";
-
- if ( !result ) {
- source = sourceFromStacktrace( 2 );
- if ( source ) {
- details.source = source;
- msg += "Source: | " + escapeText( source ) + " |
---|
";
- }
- }
- runLoggingCallbacks( "log", QUnit, details );
- config.current.assertions.push({
- result: result,
- message: msg
- });
- },
-
- /**
- * Assert that the first two arguments are equal, with an optional message.
- * Prints out both actual and expected values.
- * @name equal
- * @function
- * @example equal( format( "Received {0} bytes.", 2), "Received 2 bytes.", "format() replaces {0} with next argument" );
- */
- equal: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected == actual, actual, expected, message );
- },
-
- /**
- * @name notEqual
- * @function
- */
- notEqual: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected != actual, actual, expected, message );
- },
-
- /**
- * @name propEqual
- * @function
- */
- propEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notPropEqual
- * @function
- */
- notPropEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name deepEqual
- * @function
- */
- deepEqual: function( actual, expected, message ) {
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notDeepEqual
- * @function
- */
- notDeepEqual: function( actual, expected, message ) {
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name strictEqual
- * @function
- */
- strictEqual: function( actual, expected, message ) {
- QUnit.push( expected === actual, actual, expected, message );
- },
-
- /**
- * @name notStrictEqual
- * @function
- */
- notStrictEqual: function( actual, expected, message ) {
- QUnit.push( expected !== actual, actual, expected, message );
- },
-
- "throws": function( block, expected, message ) {
- var actual,
- expectedOutput = expected,
- ok = false;
-
- // 'expected' is optional
- if ( typeof expected === "string" ) {
- message = expected;
- expected = null;
- }
-
- config.current.ignoreGlobalErrors = true;
- try {
- block.call( config.current.testEnvironment );
- } catch (e) {
- actual = e;
- }
- config.current.ignoreGlobalErrors = false;
-
- if ( actual ) {
- // we don't want to validate thrown error
- if ( !expected ) {
- ok = true;
- expectedOutput = null;
- // expected is a regexp
- } else if ( QUnit.objectType( expected ) === "regexp" ) {
- ok = expected.test( errorString( actual ) );
- // expected is a constructor
- } else if ( actual instanceof expected ) {
- ok = true;
- // expected is a validation function which returns true is validation passed
- } else if ( expected.call( {}, actual ) === true ) {
- expectedOutput = null;
- ok = true;
- }
-
- QUnit.push( ok, actual, expectedOutput, message );
- } else {
- QUnit.pushFailure( message, null, 'No exception was thrown.' );
- }
- }
-};
-
-/**
- * @deprecate since 1.8.0
- * Kept assertion helpers in root for backwards compatibility.
- */
-extend( QUnit, assert );
-
-/**
- * @deprecated since 1.9.0
- * Kept root "raises()" for backwards compatibility.
- * (Note that we don't introduce assert.raises).
- */
-QUnit.raises = assert[ "throws" ];
-
-/**
- * @deprecated since 1.0.0, replaced with error pushes since 1.3.0
- * Kept to avoid TypeErrors for undefined methods.
- */
-QUnit.equals = function() {
- QUnit.push( false, false, false, "QUnit.equals has been deprecated since 2009 (e88049a0), use QUnit.equal instead" );
-};
-QUnit.same = function() {
- QUnit.push( false, false, false, "QUnit.same has been deprecated since 2009 (e88049a0), use QUnit.deepEqual instead" );
-};
-
-// We want access to the constructor's prototype
-(function() {
- function F() {}
- F.prototype = QUnit;
- QUnit = new F();
- // Make F QUnit's constructor so that we can add to the prototype later
- QUnit.constructor = F;
-}());
-
-/**
- * Config object: Maintain internal state
- * Later exposed as QUnit.config
- * `config` initialized at top of scope
- */
-config = {
- // The queue of tests to run
- queue: [],
-
- // block until document ready
- blocking: true,
-
- // when enabled, show only failing tests
- // gets persisted through sessionStorage and can be changed in UI via checkbox
- hidepassed: false,
-
- // by default, run previously failed tests first
- // very useful in combination with "Hide passed tests" checked
- reorder: true,
-
- // by default, modify document.title when suite is done
- altertitle: true,
-
- // when enabled, all tests must call expect()
- requireExpects: false,
-
- // add checkboxes that are persisted in the query-string
- // when enabled, the id is set to `true` as a `QUnit.config` property
- urlConfig: [
- {
- id: "noglobals",
- label: "Check for Globals",
- tooltip: "Enabling this will test if any test introduces new properties on the `window` object. Stored as query-strings."
- },
- {
- id: "notrycatch",
- label: "No try-catch",
- tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging exceptions in IE reasonable. Stored as query-strings."
- }
- ],
-
- // Set of all modules.
- modules: {},
-
- // logging callback queues
- begin: [],
- done: [],
- log: [],
- testStart: [],
- testDone: [],
- moduleStart: [],
- moduleDone: []
-};
-
-// Export global variables, unless an 'exports' object exists,
-// in that case we assume we're in CommonJS (dealt with on the bottom of the script)
-if ( typeof exports === "undefined" ) {
- extend( window, QUnit );
-
- // Expose QUnit object
- window.QUnit = QUnit;
-}
-
-// Initialize more QUnit.config and QUnit.urlParams
-(function() {
- var i,
- location = window.location || { search: "", protocol: "file:" },
- params = location.search.slice( 1 ).split( "&" ),
- length = params.length,
- urlParams = {},
- current;
-
- if ( params[ 0 ] ) {
- for ( i = 0; i < length; i++ ) {
- current = params[ i ].split( "=" );
- current[ 0 ] = decodeURIComponent( current[ 0 ] );
- // allow just a key to turn on a flag, e.g., test.html?noglobals
- current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true;
- urlParams[ current[ 0 ] ] = current[ 1 ];
- }
- }
-
- QUnit.urlParams = urlParams;
-
- // String search anywhere in moduleName+testName
- config.filter = urlParams.filter;
-
- // Exact match of the module name
- config.module = urlParams.module;
-
- config.testNumber = parseInt( urlParams.testNumber, 10 ) || null;
-
- // Figure out if we're running the tests from a server or not
- QUnit.isLocal = location.protocol === "file:";
-}());
-
-// Extend QUnit object,
-// these after set here because they should not be exposed as global functions
-extend( QUnit, {
- assert: assert,
-
- config: config,
-
- // Initialize the configuration options
- init: function() {
- extend( config, {
- stats: { all: 0, bad: 0 },
- moduleStats: { all: 0, bad: 0 },
- started: +new Date(),
- updateRate: 1000,
- blocking: false,
- autostart: true,
- autorun: false,
- filter: "",
- queue: [],
- semaphore: 1
- });
-
- var tests, banner, result,
- qunit = id( "qunit" );
-
- if ( qunit ) {
- qunit.innerHTML =
- "" +
- "" +
- "" +
- "" +
- "
";
- }
-
- tests = id( "qunit-tests" );
- banner = id( "qunit-banner" );
- result = id( "qunit-testresult" );
-
- if ( tests ) {
- tests.innerHTML = "";
- }
-
- if ( banner ) {
- banner.className = "";
- }
-
- if ( result ) {
- result.parentNode.removeChild( result );
- }
-
- if ( tests ) {
- result = document.createElement( "p" );
- result.id = "qunit-testresult";
- result.className = "result";
- tests.parentNode.insertBefore( result, tests );
- result.innerHTML = "Running...
";
- }
- },
-
- // Resets the test setup. Useful for tests that modify the DOM.
- reset: function() {
- var fixture = id( "qunit-fixture" );
- if ( fixture ) {
- fixture.innerHTML = config.fixture;
- }
- },
-
- // Trigger an event on an element.
- // @example triggerEvent( document.body, "click" );
- triggerEvent: function( elem, type, event ) {
- if ( document.createEvent ) {
- event = document.createEvent( "MouseEvents" );
- event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView,
- 0, 0, 0, 0, 0, false, false, false, false, 0, null);
-
- elem.dispatchEvent( event );
- } else if ( elem.fireEvent ) {
- elem.fireEvent( "on" + type );
- }
- },
-
- // Safe object type checking
- is: function( type, obj ) {
- return QUnit.objectType( obj ) === type;
- },
-
- objectType: function( obj ) {
- if ( typeof obj === "undefined" ) {
- return "undefined";
- // consider: typeof null === object
- }
- if ( obj === null ) {
- return "null";
- }
-
- var match = toString.call( obj ).match(/^\[object\s(.*)\]$/),
- type = match && match[1] || "";
-
- switch ( type ) {
- case "Number":
- if ( isNaN(obj) ) {
- return "nan";
- }
- return "number";
- case "String":
- case "Boolean":
- case "Array":
- case "Date":
- case "RegExp":
- case "Function":
- return type.toLowerCase();
- }
- if ( typeof obj === "object" ) {
- return "object";
- }
- return undefined;
- },
-
- push: function( result, actual, expected, message ) {
- if ( !config.current ) {
- throw new Error( "assertion outside test context, was " + sourceFromStacktrace() );
- }
-
- var output, source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: message,
- actual: actual,
- expected: expected
- };
-
- message = escapeText( message ) || ( result ? "okay" : "failed" );
- message = "" + message + "";
- output = message;
-
- if ( !result ) {
- expected = escapeText( QUnit.jsDump.parse(expected) );
- actual = escapeText( QUnit.jsDump.parse(actual) );
- output += "Expected: | " + expected + " |
";
-
- if ( actual !== expected ) {
- output += "Result: | " + actual + " |
";
- output += "Diff: | " + QUnit.diff( expected, actual ) + " |
";
- }
-
- source = sourceFromStacktrace();
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
- }
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: !!result,
- message: output
- });
- },
-
- pushFailure: function( message, source, actual ) {
- if ( !config.current ) {
- throw new Error( "pushFailure() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
-
- var output,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: false,
- message: message
- };
-
- message = escapeText( message ) || "error";
- message = "" + message + "";
- output = message;
-
- output += "";
-
- if ( actual ) {
- output += "Result: | " + escapeText( actual ) + " |
";
- }
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: false,
- message: output
- });
- },
-
- url: function( params ) {
- params = extend( extend( {}, QUnit.urlParams ), params );
- var key,
- querystring = "?";
-
- for ( key in params ) {
- if ( !hasOwn.call( params, key ) ) {
- continue;
- }
- querystring += encodeURIComponent( key ) + "=" +
- encodeURIComponent( params[ key ] ) + "&";
- }
- return window.location.protocol + "//" + window.location.host +
- window.location.pathname + querystring.slice( 0, -1 );
- },
-
- extend: extend,
- id: id,
- addEvent: addEvent
- // load, equiv, jsDump, diff: Attached later
-});
-
-/**
- * @deprecated: Created for backwards compatibility with test runner that set the hook function
- * into QUnit.{hook}, instead of invoking it and passing the hook function.
- * QUnit.constructor is set to the empty F() above so that we can add to it's prototype here.
- * Doing this allows us to tell if the following methods have been overwritten on the actual
- * QUnit object.
- */
-extend( QUnit.constructor.prototype, {
-
- // Logging callbacks; all receive a single argument with the listed properties
- // run test/logs.html for any related changes
- begin: registerLoggingCallback( "begin" ),
-
- // done: { failed, passed, total, runtime }
- done: registerLoggingCallback( "done" ),
-
- // log: { result, actual, expected, message }
- log: registerLoggingCallback( "log" ),
-
- // testStart: { name }
- testStart: registerLoggingCallback( "testStart" ),
-
- // testDone: { name, failed, passed, total, duration }
- testDone: registerLoggingCallback( "testDone" ),
-
- // moduleStart: { name }
- moduleStart: registerLoggingCallback( "moduleStart" ),
-
- // moduleDone: { name, failed, passed, total }
- moduleDone: registerLoggingCallback( "moduleDone" )
-});
-
-if ( typeof document === "undefined" || document.readyState === "complete" ) {
- config.autorun = true;
-}
-
-QUnit.load = function() {
- runLoggingCallbacks( "begin", QUnit, {} );
-
- // Initialize the config, saving the execution queue
- var banner, filter, i, label, len, main, ol, toolbar, userAgent, val,
- urlConfigCheckboxesContainer, urlConfigCheckboxes, moduleFilter,
- numModules = 0,
- moduleFilterHtml = "",
- urlConfigHtml = "",
- oldconfig = extend( {}, config );
-
- QUnit.init();
- extend(config, oldconfig);
-
- config.blocking = false;
-
- len = config.urlConfig.length;
-
- for ( i = 0; i < len; i++ ) {
- val = config.urlConfig[i];
- if ( typeof val === "string" ) {
- val = {
- id: val,
- label: val,
- tooltip: "[no tooltip available]"
- };
- }
- config[ val.id ] = QUnit.urlParams[ val.id ];
- urlConfigHtml += "";
- }
-
- moduleFilterHtml += "";
-
- // `userAgent` initialized at top of scope
- userAgent = id( "qunit-userAgent" );
- if ( userAgent ) {
- userAgent.innerHTML = navigator.userAgent;
- }
-
- // `banner` initialized at top of scope
- banner = id( "qunit-header" );
- if ( banner ) {
- banner.innerHTML = "" + banner.innerHTML + " ";
- }
-
- // `toolbar` initialized at top of scope
- toolbar = id( "qunit-testrunner-toolbar" );
- if ( toolbar ) {
- // `filter` initialized at top of scope
- filter = document.createElement( "input" );
- filter.type = "checkbox";
- filter.id = "qunit-filter-pass";
-
- addEvent( filter, "click", function() {
- var tmp,
- ol = document.getElementById( "qunit-tests" );
-
- if ( filter.checked ) {
- ol.className = ol.className + " hidepass";
- } else {
- tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " ";
- ol.className = tmp.replace( / hidepass /, " " );
- }
- if ( defined.sessionStorage ) {
- if (filter.checked) {
- sessionStorage.setItem( "qunit-filter-passed-tests", "true" );
- } else {
- sessionStorage.removeItem( "qunit-filter-passed-tests" );
- }
- }
- });
-
- if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem( "qunit-filter-passed-tests" ) ) {
- filter.checked = true;
- // `ol` initialized at top of scope
- ol = document.getElementById( "qunit-tests" );
- ol.className = ol.className + " hidepass";
- }
- toolbar.appendChild( filter );
-
- // `label` initialized at top of scope
- label = document.createElement( "label" );
- label.setAttribute( "for", "qunit-filter-pass" );
- label.setAttribute( "title", "Only show tests and assertons that fail. Stored in sessionStorage." );
- label.innerHTML = "Hide passed tests";
- toolbar.appendChild( label );
-
- urlConfigCheckboxesContainer = document.createElement("span");
- urlConfigCheckboxesContainer.innerHTML = urlConfigHtml;
- urlConfigCheckboxes = urlConfigCheckboxesContainer.getElementsByTagName("input");
- // For oldIE support:
- // * Add handlers to the individual elements instead of the container
- // * Use "click" instead of "change"
- // * Fallback from event.target to event.srcElement
- addEvents( urlConfigCheckboxes, "click", function( event ) {
- var params = {},
- target = event.target || event.srcElement;
- params[ target.name ] = target.checked ? true : undefined;
- window.location = QUnit.url( params );
- });
- toolbar.appendChild( urlConfigCheckboxesContainer );
-
- if (numModules > 1) {
- moduleFilter = document.createElement( 'span' );
- moduleFilter.setAttribute( 'id', 'qunit-modulefilter-container' );
- moduleFilter.innerHTML = moduleFilterHtml;
- addEvent( moduleFilter.lastChild, "change", function() {
- var selectBox = moduleFilter.getElementsByTagName("select")[0],
- selectedModule = decodeURIComponent(selectBox.options[selectBox.selectedIndex].value);
-
- window.location = QUnit.url( { module: ( selectedModule === "" ) ? undefined : selectedModule } );
- });
- toolbar.appendChild(moduleFilter);
- }
- }
-
- // `main` initialized at top of scope
- main = id( "qunit-fixture" );
- if ( main ) {
- config.fixture = main.innerHTML;
- }
-
- if ( config.autostart ) {
- QUnit.start();
- }
-};
-
-addEvent( window, "load", QUnit.load );
-
-// `onErrorFnPrev` initialized at top of scope
-// Preserve other handlers
-onErrorFnPrev = window.onerror;
-
-// Cover uncaught exceptions
-// Returning true will surpress the default browser handler,
-// returning false will let it run.
-window.onerror = function ( error, filePath, linerNr ) {
- var ret = false;
- if ( onErrorFnPrev ) {
- ret = onErrorFnPrev( error, filePath, linerNr );
- }
-
- // Treat return value as window.onerror itself does,
- // Only do our handling if not surpressed.
- if ( ret !== true ) {
- if ( QUnit.config.current ) {
- if ( QUnit.config.current.ignoreGlobalErrors ) {
- return true;
- }
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- } else {
- QUnit.test( "global failure", extend( function() {
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- }, { validTest: validTest } ) );
- }
- return false;
- }
-
- return ret;
-};
-
-function done() {
- config.autorun = true;
-
- // Log the last module results
- if ( config.currentModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.currentModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
-
- var i, key,
- banner = id( "qunit-banner" ),
- tests = id( "qunit-tests" ),
- runtime = +new Date() - config.started,
- passed = config.stats.all - config.stats.bad,
- html = [
- "Tests completed in ",
- runtime,
- " milliseconds.
",
- "",
- passed,
- " assertions of ",
- config.stats.all,
- " passed, ",
- config.stats.bad,
- " failed."
- ].join( "" );
-
- if ( banner ) {
- banner.className = ( config.stats.bad ? "qunit-fail" : "qunit-pass" );
- }
-
- if ( tests ) {
- id( "qunit-testresult" ).innerHTML = html;
- }
-
- if ( config.altertitle && typeof document !== "undefined" && document.title ) {
- // show ✖ for good, ✔ for bad suite result in title
- // use escape sequences in case file gets loaded with non-utf-8-charset
- document.title = [
- ( config.stats.bad ? "\u2716" : "\u2714" ),
- document.title.replace( /^[\u2714\u2716] /i, "" )
- ].join( " " );
- }
-
- // clear own sessionStorage items if all tests passed
- if ( config.reorder && defined.sessionStorage && config.stats.bad === 0 ) {
- // `key` & `i` initialized at top of scope
- for ( i = 0; i < sessionStorage.length; i++ ) {
- key = sessionStorage.key( i++ );
- if ( key.indexOf( "qunit-test-" ) === 0 ) {
- sessionStorage.removeItem( key );
- }
- }
- }
-
- // scroll back to top to show results
- if ( window.scrollTo ) {
- window.scrollTo(0, 0);
- }
-
- runLoggingCallbacks( "done", QUnit, {
- failed: config.stats.bad,
- passed: passed,
- total: config.stats.all,
- runtime: runtime
- });
-}
-
-/** @return Boolean: true if this test should be ran */
-function validTest( test ) {
- var include,
- filter = config.filter && config.filter.toLowerCase(),
- module = config.module && config.module.toLowerCase(),
- fullName = (test.module + ": " + test.testName).toLowerCase();
-
- // Internally-generated tests are always valid
- if ( test.callback && test.callback.validTest === validTest ) {
- delete test.callback.validTest;
- return true;
- }
-
- if ( config.testNumber ) {
- return test.testNumber === config.testNumber;
- }
-
- if ( module && ( !test.module || test.module.toLowerCase() !== module ) ) {
- return false;
- }
-
- if ( !filter ) {
- return true;
- }
-
- include = filter.charAt( 0 ) !== "!";
- if ( !include ) {
- filter = filter.slice( 1 );
- }
-
- // If the filter matches, we need to honour include
- if ( fullName.indexOf( filter ) !== -1 ) {
- return include;
- }
-
- // Otherwise, do the opposite
- return !include;
-}
-
-// so far supports only Firefox, Chrome and Opera (buggy), Safari (for real exceptions)
-// Later Safari and IE10 are supposed to support error.stack as well
-// See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack
-function extractStacktrace( e, offset ) {
- offset = offset === undefined ? 3 : offset;
-
- var stack, include, i;
-
- if ( e.stacktrace ) {
- // Opera
- return e.stacktrace.split( "\n" )[ offset + 3 ];
- } else if ( e.stack ) {
- // Firefox, Chrome
- stack = e.stack.split( "\n" );
- if (/^error$/i.test( stack[0] ) ) {
- stack.shift();
- }
- if ( fileName ) {
- include = [];
- for ( i = offset; i < stack.length; i++ ) {
- if ( stack[ i ].indexOf( fileName ) !== -1 ) {
- break;
- }
- include.push( stack[ i ] );
- }
- if ( include.length ) {
- return include.join( "\n" );
- }
- }
- return stack[ offset ];
- } else if ( e.sourceURL ) {
- // Safari, PhantomJS
- // hopefully one day Safari provides actual stacktraces
- // exclude useless self-reference for generated Error objects
- if ( /qunit.js$/.test( e.sourceURL ) ) {
- return;
- }
- // for actual exceptions, this is useful
- return e.sourceURL + ":" + e.line;
- }
-}
-function sourceFromStacktrace( offset ) {
- try {
- throw new Error();
- } catch ( e ) {
- return extractStacktrace( e, offset );
- }
-}
-
-/**
- * Escape text for attribute or text content.
- */
-function escapeText( s ) {
- if ( !s ) {
- return "";
- }
- s = s + "";
- // Both single quotes and double quotes (for attributes)
- return s.replace( /['"<>&]/g, function( s ) {
- switch( s ) {
- case '\'':
- return ''';
- case '"':
- return '"';
- case '<':
- return '<';
- case '>':
- return '>';
- case '&':
- return '&';
- }
- });
-}
-
-function synchronize( callback, last ) {
- config.queue.push( callback );
-
- if ( config.autorun && !config.blocking ) {
- process( last );
- }
-}
-
-function process( last ) {
- function next() {
- process( last );
- }
- var start = new Date().getTime();
- config.depth = config.depth ? config.depth + 1 : 1;
-
- while ( config.queue.length && !config.blocking ) {
- if ( !defined.setTimeout || config.updateRate <= 0 || ( ( new Date().getTime() - start ) < config.updateRate ) ) {
- config.queue.shift()();
- } else {
- window.setTimeout( next, 13 );
- break;
- }
- }
- config.depth--;
- if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) {
- done();
- }
-}
-
-function saveGlobal() {
- config.pollution = [];
-
- if ( config.noglobals ) {
- for ( var key in window ) {
- // in Opera sometimes DOM element ids show up here, ignore them
- if ( !hasOwn.call( window, key ) || /^qunit-test-output/.test( key ) ) {
- continue;
- }
- config.pollution.push( key );
- }
- }
-}
-
-function checkPollution() {
- var newGlobals,
- deletedGlobals,
- old = config.pollution;
-
- saveGlobal();
-
- newGlobals = diff( config.pollution, old );
- if ( newGlobals.length > 0 ) {
- QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join(", ") );
- }
-
- deletedGlobals = diff( old, config.pollution );
- if ( deletedGlobals.length > 0 ) {
- QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join(", ") );
- }
-}
-
-// returns a new Array with the elements that are in a but not in b
-function diff( a, b ) {
- var i, j,
- result = a.slice();
-
- for ( i = 0; i < result.length; i++ ) {
- for ( j = 0; j < b.length; j++ ) {
- if ( result[i] === b[j] ) {
- result.splice( i, 1 );
- i--;
- break;
- }
- }
- }
- return result;
-}
-
-function extend( a, b ) {
- for ( var prop in b ) {
- if ( b[ prop ] === undefined ) {
- delete a[ prop ];
-
- // Avoid "Member not found" error in IE8 caused by setting window.constructor
- } else if ( prop !== "constructor" || a !== window ) {
- a[ prop ] = b[ prop ];
- }
- }
-
- return a;
-}
-
-/**
- * @param {HTMLElement} elem
- * @param {string} type
- * @param {Function} fn
- */
-function addEvent( elem, type, fn ) {
- // Standards-based browsers
- if ( elem.addEventListener ) {
- elem.addEventListener( type, fn, false );
- // IE
- } else {
- elem.attachEvent( "on" + type, fn );
- }
-}
-
-/**
- * @param {Array|NodeList} elems
- * @param {string} type
- * @param {Function} fn
- */
-function addEvents( elems, type, fn ) {
- var i = elems.length;
- while ( i-- ) {
- addEvent( elems[i], type, fn );
- }
-}
-
-function hasClass( elem, name ) {
- return (" " + elem.className + " ").indexOf(" " + name + " ") > -1;
-}
-
-function addClass( elem, name ) {
- if ( !hasClass( elem, name ) ) {
- elem.className += (elem.className ? " " : "") + name;
- }
-}
-
-function removeClass( elem, name ) {
- var set = " " + elem.className + " ";
- // Class name may appear multiple times
- while ( set.indexOf(" " + name + " ") > -1 ) {
- set = set.replace(" " + name + " " , " ");
- }
- // If possible, trim it for prettiness, but not neccecarily
- elem.className = window.jQuery ? jQuery.trim( set ) : ( set.trim ? set.trim() : set );
-}
-
-function id( name ) {
- return !!( typeof document !== "undefined" && document && document.getElementById ) &&
- document.getElementById( name );
-}
-
-function registerLoggingCallback( key ) {
- return function( callback ) {
- config[key].push( callback );
- };
-}
-
-// Supports deprecated method of completely overwriting logging callbacks
-function runLoggingCallbacks( key, scope, args ) {
- var i, callbacks;
- if ( QUnit.hasOwnProperty( key ) ) {
- QUnit[ key ].call(scope, args );
- } else {
- callbacks = config[ key ];
- for ( i = 0; i < callbacks.length; i++ ) {
- callbacks[ i ].call( scope, args );
- }
- }
-}
-
-// Test for equality any JavaScript type.
-// Author: Philippe Rathé
-QUnit.equiv = (function() {
-
- // Call the o related callback with the given arguments.
- function bindCallbacks( o, callbacks, args ) {
- var prop = QUnit.objectType( o );
- if ( prop ) {
- if ( QUnit.objectType( callbacks[ prop ] ) === "function" ) {
- return callbacks[ prop ].apply( callbacks, args );
- } else {
- return callbacks[ prop ]; // or undefined
- }
- }
- }
-
- // the real equiv function
- var innerEquiv,
- // stack to decide between skip/abort functions
- callers = [],
- // stack to avoiding loops from circular referencing
- parents = [],
-
- getProto = Object.getPrototypeOf || function ( obj ) {
- return obj.__proto__;
- },
- callbacks = (function () {
-
- // for string, boolean, number and null
- function useStrictEquality( b, a ) {
- /*jshint eqeqeq:false */
- if ( b instanceof a.constructor || a instanceof b.constructor ) {
- // to catch short annotaion VS 'new' annotation of a
- // declaration
- // e.g. var i = 1;
- // var j = new Number(1);
- return a == b;
- } else {
- return a === b;
- }
- }
-
- return {
- "string": useStrictEquality,
- "boolean": useStrictEquality,
- "number": useStrictEquality,
- "null": useStrictEquality,
- "undefined": useStrictEquality,
-
- "nan": function( b ) {
- return isNaN( b );
- },
-
- "date": function( b, a ) {
- return QUnit.objectType( b ) === "date" && a.valueOf() === b.valueOf();
- },
-
- "regexp": function( b, a ) {
- return QUnit.objectType( b ) === "regexp" &&
- // the regex itself
- a.source === b.source &&
- // and its modifers
- a.global === b.global &&
- // (gmi) ...
- a.ignoreCase === b.ignoreCase &&
- a.multiline === b.multiline &&
- a.sticky === b.sticky;
- },
-
- // - skip when the property is a method of an instance (OOP)
- // - abort otherwise,
- // initial === would have catch identical references anyway
- "function": function() {
- var caller = callers[callers.length - 1];
- return caller !== Object && typeof caller !== "undefined";
- },
-
- "array": function( b, a ) {
- var i, j, len, loop;
-
- // b could be an object literal here
- if ( QUnit.objectType( b ) !== "array" ) {
- return false;
- }
-
- len = a.length;
- if ( len !== b.length ) {
- // safe and faster
- return false;
- }
-
- // track reference to avoid circular references
- parents.push( a );
- for ( i = 0; i < len; i++ ) {
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- loop = true;// dont rewalk array
- }
- }
- if ( !loop && !innerEquiv(a[i], b[i]) ) {
- parents.pop();
- return false;
- }
- }
- parents.pop();
- return true;
- },
-
- "object": function( b, a ) {
- var i, j, loop,
- // Default to true
- eq = true,
- aProperties = [],
- bProperties = [];
-
- // comparing constructors is more strict than using
- // instanceof
- if ( a.constructor !== b.constructor ) {
- // Allow objects with no prototype to be equivalent to
- // objects with Object as their constructor.
- if ( !(( getProto(a) === null && getProto(b) === Object.prototype ) ||
- ( getProto(b) === null && getProto(a) === Object.prototype ) ) ) {
- return false;
- }
- }
-
- // stack constructor before traversing properties
- callers.push( a.constructor );
- // track reference to avoid circular references
- parents.push( a );
-
- for ( i in a ) { // be strict: don't ensures hasOwnProperty
- // and go deep
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- // don't go down the same path twice
- loop = true;
- }
- }
- aProperties.push(i); // collect a's properties
-
- if (!loop && !innerEquiv( a[i], b[i] ) ) {
- eq = false;
- break;
- }
- }
-
- callers.pop(); // unstack, we are done
- parents.pop();
-
- for ( i in b ) {
- bProperties.push( i ); // collect b's properties
- }
-
- // Ensures identical properties name
- return eq && innerEquiv( aProperties.sort(), bProperties.sort() );
- }
- };
- }());
-
- innerEquiv = function() { // can take multiple arguments
- var args = [].slice.apply( arguments );
- if ( args.length < 2 ) {
- return true; // end transition
- }
-
- return (function( a, b ) {
- if ( a === b ) {
- return true; // catch the most you can
- } else if ( a === null || b === null || typeof a === "undefined" ||
- typeof b === "undefined" ||
- QUnit.objectType(a) !== QUnit.objectType(b) ) {
- return false; // don't lose time with error prone cases
- } else {
- return bindCallbacks(a, callbacks, [ b, a ]);
- }
-
- // apply transition with (1..n) arguments
- }( args[0], args[1] ) && arguments.callee.apply( this, args.splice(1, args.length - 1 )) );
- };
-
- return innerEquiv;
-}());
-
-/**
- * jsDump Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com |
- * http://flesler.blogspot.com Licensed under BSD
- * (http://www.opensource.org/licenses/bsd-license.php) Date: 5/15/2008
- *
- * @projectDescription Advanced and extensible data dumping for Javascript.
- * @version 1.0.0
- * @author Ariel Flesler
- * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html}
- */
-QUnit.jsDump = (function() {
- function quote( str ) {
- return '"' + str.toString().replace( /"/g, '\\"' ) + '"';
- }
- function literal( o ) {
- return o + "";
- }
- function join( pre, arr, post ) {
- var s = jsDump.separator(),
- base = jsDump.indent(),
- inner = jsDump.indent(1);
- if ( arr.join ) {
- arr = arr.join( "," + s + inner );
- }
- if ( !arr ) {
- return pre + post;
- }
- return [ pre, inner + arr, base + post ].join(s);
- }
- function array( arr, stack ) {
- var i = arr.length, ret = new Array(i);
- this.up();
- while ( i-- ) {
- ret[i] = this.parse( arr[i] , undefined , stack);
- }
- this.down();
- return join( "[", ret, "]" );
- }
-
- var reName = /^function (\w+)/,
- jsDump = {
- // type is used mostly internally, you can fix a (custom)type in advance
- parse: function( obj, type, stack ) {
- stack = stack || [ ];
- var inStack, res,
- parser = this.parsers[ type || this.typeOf(obj) ];
-
- type = typeof parser;
- inStack = inArray( obj, stack );
-
- if ( inStack !== -1 ) {
- return "recursion(" + (inStack - stack.length) + ")";
- }
- if ( type === "function" ) {
- stack.push( obj );
- res = parser.call( this, obj, stack );
- stack.pop();
- return res;
- }
- return ( type === "string" ) ? parser : this.parsers.error;
- },
- typeOf: function( obj ) {
- var type;
- if ( obj === null ) {
- type = "null";
- } else if ( typeof obj === "undefined" ) {
- type = "undefined";
- } else if ( QUnit.is( "regexp", obj) ) {
- type = "regexp";
- } else if ( QUnit.is( "date", obj) ) {
- type = "date";
- } else if ( QUnit.is( "function", obj) ) {
- type = "function";
- } else if ( typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined" ) {
- type = "window";
- } else if ( obj.nodeType === 9 ) {
- type = "document";
- } else if ( obj.nodeType ) {
- type = "node";
- } else if (
- // native arrays
- toString.call( obj ) === "[object Array]" ||
- // NodeList objects
- ( typeof obj.length === "number" && typeof obj.item !== "undefined" && ( obj.length ? obj.item(0) === obj[0] : ( obj.item( 0 ) === null && typeof obj[0] === "undefined" ) ) )
- ) {
- type = "array";
- } else if ( obj.constructor === Error.prototype.constructor ) {
- type = "error";
- } else {
- type = typeof obj;
- }
- return type;
- },
- separator: function() {
- return this.multiline ? this.HTML ? "
" : "\n" : this.HTML ? " " : " ";
- },
- // extra can be a number, shortcut for increasing-calling-decreasing
- indent: function( extra ) {
- if ( !this.multiline ) {
- return "";
- }
- var chr = this.indentChar;
- if ( this.HTML ) {
- chr = chr.replace( /\t/g, " " ).replace( / /g, " " );
- }
- return new Array( this._depth_ + (extra||0) ).join(chr);
- },
- up: function( a ) {
- this._depth_ += a || 1;
- },
- down: function( a ) {
- this._depth_ -= a || 1;
- },
- setParser: function( name, parser ) {
- this.parsers[name] = parser;
- },
- // The next 3 are exposed so you can use them
- quote: quote,
- literal: literal,
- join: join,
- //
- _depth_: 1,
- // This is the list of parsers, to modify them, use jsDump.setParser
- parsers: {
- window: "[Window]",
- document: "[Document]",
- error: function(error) {
- return "Error(\"" + error.message + "\")";
- },
- unknown: "[Unknown]",
- "null": "null",
- "undefined": "undefined",
- "function": function( fn ) {
- var ret = "function",
- // functions never have name in IE
- name = "name" in fn ? fn.name : (reName.exec(fn) || [])[1];
-
- if ( name ) {
- ret += " " + name;
- }
- ret += "( ";
-
- ret = [ ret, QUnit.jsDump.parse( fn, "functionArgs" ), "){" ].join( "" );
- return join( ret, QUnit.jsDump.parse(fn,"functionCode" ), "}" );
- },
- array: array,
- nodelist: array,
- "arguments": array,
- object: function( map, stack ) {
- var ret = [ ], keys, key, val, i;
- QUnit.jsDump.up();
- keys = [];
- for ( key in map ) {
- keys.push( key );
- }
- keys.sort();
- for ( i = 0; i < keys.length; i++ ) {
- key = keys[ i ];
- val = map[ key ];
- ret.push( QUnit.jsDump.parse( key, "key" ) + ": " + QUnit.jsDump.parse( val, undefined, stack ) );
- }
- QUnit.jsDump.down();
- return join( "{", ret, "}" );
- },
- node: function( node ) {
- var len, i, val,
- open = QUnit.jsDump.HTML ? "<" : "<",
- close = QUnit.jsDump.HTML ? ">" : ">",
- tag = node.nodeName.toLowerCase(),
- ret = open + tag,
- attrs = node.attributes;
-
- if ( attrs ) {
- for ( i = 0, len = attrs.length; i < len; i++ ) {
- val = attrs[i].nodeValue;
- // IE6 includes all attributes in .attributes, even ones not explicitly set.
- // Those have values like undefined, null, 0, false, "" or "inherit".
- if ( val && val !== "inherit" ) {
- ret += " " + attrs[i].nodeName + "=" + QUnit.jsDump.parse( val, "attribute" );
- }
- }
- }
- ret += close;
-
- // Show content of TextNode or CDATASection
- if ( node.nodeType === 3 || node.nodeType === 4 ) {
- ret += node.nodeValue;
- }
-
- return ret + open + "/" + tag + close;
- },
- // function calls it internally, it's the arguments part of the function
- functionArgs: function( fn ) {
- var args,
- l = fn.length;
-
- if ( !l ) {
- return "";
- }
-
- args = new Array(l);
- while ( l-- ) {
- // 97 is 'a'
- args[l] = String.fromCharCode(97+l);
- }
- return " " + args.join( ", " ) + " ";
- },
- // object calls it internally, the key part of an item in a map
- key: quote,
- // function calls it internally, it's the content of the function
- functionCode: "[code]",
- // node calls it internally, it's an html attribute value
- attribute: quote,
- string: quote,
- date: quote,
- regexp: literal,
- number: literal,
- "boolean": literal
- },
- // if true, entities are escaped ( <, >, \t, space and \n )
- HTML: false,
- // indentation unit
- indentChar: " ",
- // if true, items in a collection, are separated by a \n, else just a space.
- multiline: true
- };
-
- return jsDump;
-}());
-
-// from jquery.js
-function inArray( elem, array ) {
- if ( array.indexOf ) {
- return array.indexOf( elem );
- }
-
- for ( var i = 0, length = array.length; i < length; i++ ) {
- if ( array[ i ] === elem ) {
- return i;
- }
- }
-
- return -1;
-}
-
-/*
- * Javascript Diff Algorithm
- * By John Resig (http://ejohn.org/)
- * Modified by Chu Alan "sprite"
- *
- * Released under the MIT license.
- *
- * More Info:
- * http://ejohn.org/projects/javascript-diff-algorithm/
- *
- * Usage: QUnit.diff(expected, actual)
- *
- * QUnit.diff( "the quick brown fox jumped over", "the quick fox jumps over" ) == "the quick brown fox jumped jumps over"
- */
-QUnit.diff = (function() {
- /*jshint eqeqeq:false, eqnull:true */
- function diff( o, n ) {
- var i,
- ns = {},
- os = {};
-
- for ( i = 0; i < n.length; i++ ) {
- if ( !hasOwn.call( ns, n[i] ) ) {
- ns[ n[i] ] = {
- rows: [],
- o: null
- };
- }
- ns[ n[i] ].rows.push( i );
- }
-
- for ( i = 0; i < o.length; i++ ) {
- if ( !hasOwn.call( os, o[i] ) ) {
- os[ o[i] ] = {
- rows: [],
- n: null
- };
- }
- os[ o[i] ].rows.push( i );
- }
-
- for ( i in ns ) {
- if ( !hasOwn.call( ns, i ) ) {
- continue;
- }
- if ( ns[i].rows.length === 1 && hasOwn.call( os, i ) && os[i].rows.length === 1 ) {
- n[ ns[i].rows[0] ] = {
- text: n[ ns[i].rows[0] ],
- row: os[i].rows[0]
- };
- o[ os[i].rows[0] ] = {
- text: o[ os[i].rows[0] ],
- row: ns[i].rows[0]
- };
- }
- }
-
- for ( i = 0; i < n.length - 1; i++ ) {
- if ( n[i].text != null && n[ i + 1 ].text == null && n[i].row + 1 < o.length && o[ n[i].row + 1 ].text == null &&
- n[ i + 1 ] == o[ n[i].row + 1 ] ) {
-
- n[ i + 1 ] = {
- text: n[ i + 1 ],
- row: n[i].row + 1
- };
- o[ n[i].row + 1 ] = {
- text: o[ n[i].row + 1 ],
- row: i + 1
- };
- }
- }
-
- for ( i = n.length - 1; i > 0; i-- ) {
- if ( n[i].text != null && n[ i - 1 ].text == null && n[i].row > 0 && o[ n[i].row - 1 ].text == null &&
- n[ i - 1 ] == o[ n[i].row - 1 ]) {
-
- n[ i - 1 ] = {
- text: n[ i - 1 ],
- row: n[i].row - 1
- };
- o[ n[i].row - 1 ] = {
- text: o[ n[i].row - 1 ],
- row: i - 1
- };
- }
- }
-
- return {
- o: o,
- n: n
- };
- }
-
- return function( o, n ) {
- o = o.replace( /\s+$/, "" );
- n = n.replace( /\s+$/, "" );
-
- var i, pre,
- str = "",
- out = diff( o === "" ? [] : o.split(/\s+/), n === "" ? [] : n.split(/\s+/) ),
- oSpace = o.match(/\s+/g),
- nSpace = n.match(/\s+/g);
-
- if ( oSpace == null ) {
- oSpace = [ " " ];
- }
- else {
- oSpace.push( " " );
- }
-
- if ( nSpace == null ) {
- nSpace = [ " " ];
- }
- else {
- nSpace.push( " " );
- }
-
- if ( out.n.length === 0 ) {
- for ( i = 0; i < out.o.length; i++ ) {
- str += "" + out.o[i] + oSpace[i] + "";
- }
- }
- else {
- if ( out.n[0].text == null ) {
- for ( n = 0; n < out.o.length && out.o[n].text == null; n++ ) {
- str += "" + out.o[n] + oSpace[n] + "";
- }
- }
-
- for ( i = 0; i < out.n.length; i++ ) {
- if (out.n[i].text == null) {
- str += "" + out.n[i] + nSpace[i] + "";
- }
- else {
- // `pre` initialized at top of scope
- pre = "";
-
- for ( n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++ ) {
- pre += "" + out.o[n] + oSpace[n] + "";
- }
- str += " " + out.n[i].text + nSpace[i] + pre;
- }
- }
- }
-
- return str;
- };
-}());
-
-// for CommonJS enviroments, export everything
-if ( typeof exports !== "undefined" ) {
- extend( exports, QUnit );
-}
-
-// get at whatever the global object is, like window in browsers
-}( (function() {return this;}.call()) ));
diff --git a/test/lib/require.js b/test/lib/require.js
deleted file mode 100644
index 987f865..0000000
--- a/test/lib/require.js
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- RequireJS 2.1.5 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.
- Available via the MIT or new BSD license.
- see: http://github.com/jrburke/requirejs for details
-*/
-var requirejs,require,define;
-(function(aa){function I(b){return"[object Function]"===L.call(b)}function J(b){return"[object Array]"===L.call(b)}function y(b,c){if(b){var d;for(d=0;dthis.depCount&&!this.defined){if(I(n)){if(this.events.error)try{e=i.execCb(c,n,b,e)}catch(d){a=d}else e=i.execCb(c,n,b,e);this.map.isDefine&&((b=this.module)&&void 0!==b.exports&&b.exports!==this.exports?e=b.exports:void 0===e&&this.usingExports&&(e=this.exports));if(a)return a.requireMap=this.map,a.requireModules=[this.map.id],a.requireType="define",v(this.error=
-a)}else e=n;this.exports=e;if(this.map.isDefine&&!this.ignore&&(q[c]=e,l.onResourceLoad))l.onResourceLoad(i,this.map,this.depMaps);x(c);this.defined=!0}this.defining=!1;this.defined&&!this.defineEmitted&&(this.defineEmitted=!0,this.emit("defined",this.exports),this.defineEmitComplete=!0)}}else this.fetch()}},callPlugin:function(){var a=this.map,b=a.id,d=j(a.prefix);this.depMaps.push(d);t(d,"defined",u(this,function(e){var n,d;d=this.map.name;var g=this.map.parentMap?this.map.parentMap.name:null,h=
-i.makeRequire(a.parentMap,{enableBuildCallback:!0});if(this.map.unnormalized){if(e.normalize&&(d=e.normalize(d,function(a){return c(a,g,!0)})||""),e=j(a.prefix+"!"+d,this.map.parentMap),t(e,"defined",u(this,function(a){this.init([],function(){return a},null,{enabled:!0,ignore:!0})})),d=m(p,e.id)){this.depMaps.push(e);if(this.events.error)d.on("error",u(this,function(a){this.emit("error",a)}));d.enable()}}else n=u(this,function(a){this.init([],function(){return a},null,{enabled:!0})}),n.error=u(this,
-function(a){this.inited=!0;this.error=a;a.requireModules=[b];G(p,function(a){0===a.map.id.indexOf(b+"_unnormalized")&&x(a.map.id)});v(a)}),n.fromText=u(this,function(e,c){var d=a.name,g=j(d),C=O;c&&(e=c);C&&(O=!1);r(g);s(k.config,b)&&(k.config[d]=k.config[b]);try{l.exec(e)}catch(ca){return v(B("fromtexteval","fromText eval for "+b+" failed: "+ca,ca,[b]))}C&&(O=!0);this.depMaps.push(g);i.completeLoad(d);h([d],n)}),e.load(a.name,h,n,k)}));i.enable(d,this);this.pluginMaps[d.id]=d},enable:function(){V[this.map.id]=
-this;this.enabling=this.enabled=!0;y(this.depMaps,u(this,function(a,b){var c,e;if("string"===typeof a){a=j(a,this.map.isDefine?this.map:this.map.parentMap,!1,!this.skipMap);this.depMaps[b]=a;if(c=m(N,a.id)){this.depExports[b]=c(this);return}this.depCount+=1;t(a,"defined",u(this,function(a){this.defineDep(b,a);this.check()}));this.errback&&t(a,"error",this.errback)}c=a.id;e=p[c];!s(N,c)&&(e&&!e.enabled)&&i.enable(a,this)}));G(this.pluginMaps,u(this,function(a){var b=m(p,a.id);b&&!b.enabled&&i.enable(a,
-this)}));this.enabling=!1;this.check()},on:function(a,b){var c=this.events[a];c||(c=this.events[a]=[]);c.push(b)},emit:function(a,b){y(this.events[a],function(a){a(b)});"error"===a&&delete this.events[a]}};i={config:k,contextName:b,registry:p,defined:q,urlFetched:U,defQueue:H,Module:Z,makeModuleMap:j,nextTick:l.nextTick,onError:v,configure:function(a){a.baseUrl&&"/"!==a.baseUrl.charAt(a.baseUrl.length-1)&&(a.baseUrl+="/");var b=k.pkgs,c=k.shim,e={paths:!0,config:!0,map:!0};G(a,function(a,b){e[b]?
-"map"===b?(k.map||(k.map={}),R(k[b],a,!0,!0)):R(k[b],a,!0):k[b]=a});a.shim&&(G(a.shim,function(a,b){J(a)&&(a={deps:a});if((a.exports||a.init)&&!a.exportsFn)a.exportsFn=i.makeShimExports(a);c[b]=a}),k.shim=c);a.packages&&(y(a.packages,function(a){a="string"===typeof a?{name:a}:a;b[a.name]={name:a.name,location:a.location||a.name,main:(a.main||"main").replace(ja,"").replace(ea,"")}}),k.pkgs=b);G(p,function(a,b){!a.inited&&!a.map.unnormalized&&(a.map=j(b))});if(a.deps||a.callback)i.require(a.deps||[],
-a.callback)},makeShimExports:function(a){return function(){var b;a.init&&(b=a.init.apply(aa,arguments));return b||a.exports&&ba(a.exports)}},makeRequire:function(a,f){function d(e,c,h){var g,k;f.enableBuildCallback&&(c&&I(c))&&(c.__requireJsBuild=!0);if("string"===typeof e){if(I(c))return v(B("requireargs","Invalid require call"),h);if(a&&s(N,e))return N[e](p[a.id]);if(l.get)return l.get(i,e,a,d);g=j(e,a,!1,!0);g=g.id;return!s(q,g)?v(B("notloaded",'Module name "'+g+'" has not been loaded yet for context: '+
-b+(a?"":". Use require([])"))):q[g]}L();i.nextTick(function(){L();k=r(j(null,a));k.skipMap=f.skipMap;k.init(e,c,h,{enabled:!0});D()});return d}f=f||{};R(d,{isBrowser:A,toUrl:function(b){var d,f=b.lastIndexOf("."),g=b.split("/")[0];if(-1!==f&&(!("."===g||".."===g)||1h.attachEvent.toString().indexOf("[native code"))&&!Y?(O=!0,h.attachEvent("onreadystatechange",b.onScriptLoad)):(h.addEventListener("load",b.onScriptLoad,!1),h.addEventListener("error",b.onScriptError,!1)),h.src=d,K=h,D?x.insertBefore(h,D):x.appendChild(h),K=null,h;if(da)try{importScripts(d),b.completeLoad(c)}catch(j){b.onError(B("importscripts","importScripts failed for "+c+" at "+d,j,[c]))}};A&&M(document.getElementsByTagName("script"),function(b){x||(x=
-b.parentNode);if(t=b.getAttribute("data-main"))return r.baseUrl||(E=t.split("/"),Q=E.pop(),fa=E.length?E.join("/")+"/":"./",r.baseUrl=fa,t=Q),t=t.replace(ea,""),r.deps=r.deps?r.deps.concat(t):[t],!0});define=function(b,c,d){var l,h;"string"!==typeof b&&(d=c,c=b,b=null);J(c)||(d=c,c=[]);!c.length&&I(d)&&d.length&&(d.toString().replace(la,"").replace(ma,function(b,d){c.push(d)}),c=(1===d.length?["require"]:["require","exports","module"]).concat(c));if(O){if(!(l=K))P&&"interactive"===P.readyState||M(document.getElementsByTagName("script"),
-function(b){if("interactive"===b.readyState)return P=b}),l=P;l&&(b||(b=l.getAttribute("data-requiremodule")),h=F[l.getAttribute("data-requirecontext")])}(h?h.defQueue:T).push([b,c,d])};define.amd={jQuery:!0};l.exec=function(b){return eval(b)};l(r)}})(this);
diff --git a/test/lib/resemble.js b/test/lib/resemble.js
new file mode 100644
index 0000000..1cb8c29
--- /dev/null
+++ b/test/lib/resemble.js
@@ -0,0 +1,535 @@
+/*
+Author: James Cryer
+Company: Huddle
+Last updated date: 21 Feb 2013
+URL: https://github.com/Huddle/Resemble.js
+*/
+
+(function(_this){
+ 'use strict';
+
+ _this['resemble'] = function( fileData ){
+
+ var data = {};
+ var images = [];
+ var updateCallbackArray = [];
+
+ var tolerance = { // between 0 and 255
+ red: 16,
+ green: 16,
+ blue: 16,
+ minBrightness: 16,
+ maxBrightness: 240
+ };
+
+ var ignoreAntialiasing = false;
+ var ignoreColors = false;
+
+ function triggerDataUpdate(){
+ var len = updateCallbackArray.length;
+ var i;
+ for(i=0;i tolerance.maxBrightness;
+ }
+
+ function getHue(r,g,b){
+
+ r = r / 255;
+ g = g / 255;
+ b = b / 255;
+ var max = Math.max(r, g, b), min = Math.min(r, g, b);
+ var h;
+ var d;
+
+ if (max == min){
+ h = 0; // achromatic
+ } else{
+ d = max - min;
+ switch(max){
+ case r: h = (g - b) / d + (g < b ? 6 : 0); break;
+ case g: h = (b - r) / d + 2; break;
+ case b: h = (r - g) / d + 4; break;
+ }
+ h /= 6;
+ }
+
+ return h;
+ }
+
+ function isAntialiased(sourcePix, data, cacheSet, verticalPos, horizontalPos, width){
+ var offset;
+ var targetPix;
+ var distance = 1;
+ var i;
+ var j;
+ var hasHighContrastSibling = 0;
+ var hasSiblingWithDifferentHue = 0;
+ var hasEquivilantSibling = 0;
+
+ addHueInfo(sourcePix);
+
+ for (i = distance*-1; i <= distance; i++){
+ for (j = distance*-1; j <= distance; j++){
+
+ if(i===0 && j===0){
+ // ignore source pixel
+ } else {
+
+ offset = ((verticalPos+j)*width + (horizontalPos+i)) * 4;
+ targetPix = getPixelInfo(data, offset, cacheSet);
+
+ if(targetPix === null){
+ continue;
+ }
+
+ addBrightnessInfo(targetPix);
+ addHueInfo(targetPix);
+
+ if( isContrasting(sourcePix, targetPix) ){
+ hasHighContrastSibling++;
+ }
+
+ if( isRGBSame(sourcePix,targetPix) ){
+ hasEquivilantSibling++;
+ }
+
+ if( Math.abs(targetPix.h - sourcePix.h) > 0.3 ){
+ hasSiblingWithDifferentHue++;
+ }
+
+ if( hasSiblingWithDifferentHue > 1 || hasHighContrastSibling > 1){
+ return true;
+ }
+ }
+ }
+ }
+
+ if(hasEquivilantSibling < 2){
+ return true;
+ }
+
+ return false;
+ }
+
+ function errorPixel(px, offset){
+ px[offset] = 255; //r
+ px[offset + 1] = 0; //g
+ px[offset + 2] = 255; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyPixel(px, offset, data){
+ px[offset] = data.r; //r
+ px[offset + 1] = data.g; //g
+ px[offset + 2] = data.b; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyGrayScalePixel(px, offset, data){
+ px[offset] = data.brightness; //r
+ px[offset + 1] = data.brightness; //g
+ px[offset + 2] = data.brightness; //b
+ px[offset + 3] = 255; //a
+ }
+
+
+ function getPixelInfo(data, offset, cacheSet){
+ var r;
+ var g;
+ var b;
+ var d;
+
+ if(typeof data[offset] !== 'undefined'){
+ r = data[offset];
+ g = data[offset+1];
+ b = data[offset+2];
+ d = {
+ r: r,
+ g: g,
+ b: b
+ };
+
+ return d;
+ } else {
+ return null;
+ }
+ }
+
+ function addBrightnessInfo(data){
+ data.brightness = getBrightness(data.r,data.g,data.b); // 'corrected' lightness
+ }
+
+ function addHueInfo(data){
+ data.h = getHue(data.r,data.g,data.b);
+ }
+
+ function analyseImages(img1, img2, width, height){
+
+ var hiddenCanvas = document.createElement('canvas');
+
+ var data1 = img1.data;
+ var data2 = img2.data;
+
+ hiddenCanvas.width = width;
+ hiddenCanvas.height = height;
+
+ var context = hiddenCanvas.getContext('2d');
+ var imgd = context.createImageData(width,height);
+ var targetPix = imgd.data;
+
+ var mismatchCount = 0;
+
+ var time = Date.now();
+
+ var skip;
+
+ if( (width > 1200 || height > 1200) && ignoreAntialiasing){
+ skip = 6;
+ }
+
+ loop(height, width, function(verticalPos, horizontalPos){
+
+ if(skip){ // only skip if the image isn't small
+ if(verticalPos % skip === 0 || horizontalPos % skip === 0){
+ return;
+ }
+ }
+
+ var offset = (verticalPos*width + horizontalPos) * 4;
+ var pixel1 = getPixelInfo(data1, offset, 1);
+ var pixel2 = getPixelInfo(data2, offset, 2);
+
+ if(pixel1 === null || pixel2 === null){
+ return;
+ }
+
+ if (ignoreColors){
+
+ addBrightnessInfo(pixel1);
+ addBrightnessInfo(pixel2);
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ return;
+ }
+
+ if( isRGBSimilar(pixel1, pixel2) ){
+ copyPixel(targetPix, offset, pixel2);
+
+ } else if( ignoreAntialiasing && (
+ addBrightnessInfo(pixel1), // jit pixel info augmentation looks a little weird, sorry.
+ addBrightnessInfo(pixel2),
+ isAntialiased(pixel1, data1, 1, verticalPos, horizontalPos, width) ||
+ isAntialiased(pixel2, data2, 2, verticalPos, horizontalPos, width)
+ )){
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+
+ });
+
+ data.misMatchPercentage = (mismatchCount / (height*width) * 100).toFixed(2);
+ data.analysisTime = Date.now() - time;
+
+ data.getImageDataUrl = function(text){
+ var barHeight = 0;
+
+ if(text){
+ barHeight = addLabel(text,context,hiddenCanvas);
+ }
+
+ context.putImageData(imgd, 0, barHeight);
+
+ return hiddenCanvas.toDataURL("image/png");
+ };
+ }
+
+ function addLabel(text, context, hiddenCanvas){
+ var textPadding = 2;
+
+ context.font = '12px sans-serif';
+
+ var textWidth = context.measureText(text).width + textPadding*2;
+ var barHeight = 22;
+
+ if(textWidth > hiddenCanvas.width){
+ hiddenCanvas.width = textWidth;
+ }
+
+ hiddenCanvas.height += barHeight;
+
+ context.fillStyle = "#666";
+ context.fillRect(0,0,hiddenCanvas.width,barHeight -4);
+ context.fillStyle = "#fff";
+ context.fillRect(0,barHeight -4,hiddenCanvas.width, 4);
+
+ context.fillStyle = "#fff";
+ context.textBaseline = "top";
+ context.font = '12px sans-serif';
+ context.fillText(text, textPadding, 1);
+
+ return barHeight;
+ }
+
+ function normalise(img, w, h){
+ var c;
+ var context;
+
+ if(img.height < h || img.width < w){
+ c = document.createElement('canvas');
+ c.width = w;
+ c.height = h;
+ context = c.getContext('2d');
+ context.putImageData(img, 0, 0);
+ return context.getImageData(0, 0, w, h);
+ }
+
+ return img;
+ }
+
+ function compare(one, two){
+
+ function onceWeHaveBoth(){
+ var width;
+ var height;
+ if(images.length === 2){
+ width = images[0].width > images[1].width ? images[0].width : images[1].width;
+ height = images[0].height > images[1].height ? images[0].height : images[1].height;
+
+ if( (images[0].width === images[1].width) && (images[0].height === images[1].height) ){
+ data.isSameDimensions = true;
+ } else {
+ data.isSameDimensions = false;
+ }
+
+ analyseImages( normalise(images[0],width, height), normalise(images[1],width, height), width, height);
+
+ triggerDataUpdate();
+ }
+ }
+
+ images = [];
+ loadImageData(one, onceWeHaveBoth);
+ loadImageData(two, onceWeHaveBoth);
+ }
+
+ function getCompareApi(param){
+
+ var secondFileData,
+ hasMethod = typeof param === 'function';
+
+ if( !hasMethod ){
+ // assume it's file data
+ secondFileData = param;
+ }
+
+ var self = {
+ ignoreNothing: function(){
+
+ tolerance.red = 16;
+ tolerance.green = 16;
+ tolerance.blue = 16;
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreAntialiasing: function(){
+
+ tolerance.red = 32;
+ tolerance.green = 32;
+ tolerance.blue = 32;
+ tolerance.minBrightness = 64;
+ tolerance.maxBrightness = 96;
+
+ ignoreAntialiasing = true;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreColors: function(){
+
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = true;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ onComplete: function( callback ){
+
+ updateCallbackArray.push(callback);
+
+ var wrapper = function(){
+ compare(fileData, secondFileData);
+ };
+
+ wrapper();
+
+ return getCompareApi(wrapper);
+ }
+ };
+
+ return self;
+ }
+
+ return {
+ onComplete: function( callback ){
+ updateCallbackArray.push(callback);
+ loadImageData(fileData, function(imageData, width, height){
+ parseImage(imageData.data, width, height);
+ });
+ },
+ compareTo: function(secondFileData){
+ return getCompareApi(secondFileData);
+ }
+ };
+
+ };
+}(this));
\ No newline at end of file
diff --git a/test/testsuite.js b/test/testsuite.js
deleted file mode 100644
index b486acb..0000000
--- a/test/testsuite.js
+++ /dev/null
@@ -1,36 +0,0 @@
-requirejs.config({
- baseUrl: '/test/unit/'
-});
-
-define(function(require) {
- var testModules = [
- 'Pixi',
- 'Point',
- 'Rectangle',
- 'DisplayObject',
- 'DisplayObjectContainer',
- 'Sprite',
- 'MovieClip',
- 'InteractionManager',
- 'Stage',
- 'utils/Utils',
- 'utils/EventTarget',
- 'utils/Matrix',
- 'utils/Detector',
- 'renderers/WebGLShaders',
- 'renderers/WebGLRenderer',
- 'renderers/WebGLBatch',
- 'renderers/CanvasRenderer',
- 'extras/Strip',
- 'extras/Rope',
- 'textures/BaseTexture',
- 'textures/Texture',
- 'loaders/SpriteSheetLoader',
- 'loaders/AssetLoader'
- ];
-
- // Resolve all testModules and then start the Test Runner.
- require(testModules, function() {
- QUnit.start();
- });
-});
\ No newline at end of file
diff --git a/test/textures/SpriteSheet-Aliens.png b/test/textures/SpriteSheet-Aliens.png
new file mode 100644
index 0000000..210acb1
--- /dev/null
+++ b/test/textures/SpriteSheet-Aliens.png
Binary files differ
diff --git a/test/textures/SpriteSheet-Explosion.png b/test/textures/SpriteSheet-Explosion.png
new file mode 100755
index 0000000..79e1a69
--- /dev/null
+++ b/test/textures/SpriteSheet-Explosion.png
Binary files differ
diff --git a/test/textures/bunny.png b/test/textures/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/textures/bunny.png
Binary files differ
diff --git a/test/unit/DisplayObject.js b/test/unit/DisplayObject.js
deleted file mode 100644
index 5e7e72f..0000000
--- a/test/unit/DisplayObject.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObject');
-});
diff --git a/test/unit/DisplayObjectContainer.js b/test/unit/DisplayObjectContainer.js
deleted file mode 100644
index b323959..0000000
--- a/test/unit/DisplayObjectContainer.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObjectContainer');
-});
diff --git a/test/unit/InteractionManager.js b/test/unit/InteractionManager.js
deleted file mode 100644
index e751f52..0000000
--- a/test/unit/InteractionManager.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('InteractionManager');
-});
diff --git a/test/unit/MovieClip.js b/test/unit/MovieClip.js
deleted file mode 100644
index 37d9446..0000000
--- a/test/unit/MovieClip.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('MovieClip');
-});
diff --git a/test/unit/Pixi.js b/test/unit/Pixi.js
deleted file mode 100644
index 36eee73..0000000
--- a/test/unit/Pixi.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Pixi');
-});
diff --git a/test/unit/Point.js b/test/unit/Point.js
deleted file mode 100644
index 983ff6e..0000000
--- a/test/unit/Point.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Point');
-});
diff --git a/test/unit/Rectangle.js b/test/unit/Rectangle.js
deleted file mode 100644
index 3b439ba..0000000
--- a/test/unit/Rectangle.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Rectangle');
-});
diff --git a/test/unit/Sprite.js b/test/unit/Sprite.js
deleted file mode 100644
index ed4f596..0000000
--- a/test/unit/Sprite.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Sprite');
-});
diff --git a/test/unit/Stage.js b/test/unit/Stage.js
deleted file mode 100644
index 2d70291..0000000
--- a/test/unit/Stage.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Stage');
-});
diff --git a/test/unit/extras/Rope.js b/test/unit/extras/Rope.js
deleted file mode 100644
index 5606f14..0000000
--- a/test/unit/extras/Rope.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Rope');
-});
diff --git a/test/unit/extras/Strip.js b/test/unit/extras/Strip.js
deleted file mode 100644
index 0134d3a..0000000
--- a/test/unit/extras/Strip.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Strip');
-});
diff --git a/test/unit/loaders/AssetLoader.js b/test/unit/loaders/AssetLoader.js
deleted file mode 100644
index 13b8443..0000000
--- a/test/unit/loaders/AssetLoader.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('AssetLoader');
-});
diff --git a/test/unit/loaders/SpriteSheetLoader.js b/test/unit/loaders/SpriteSheetLoader.js
deleted file mode 100644
index 8bf0cb2..0000000
--- a/test/unit/loaders/SpriteSheetLoader.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('SpriteSheetLoader');
-});
diff --git a/test/unit/pixi/InteractionManager.js b/test/unit/pixi/InteractionManager.js
new file mode 100644
index 0000000..ed3001f
--- /dev/null
+++ b/test/unit/pixi/InteractionManager.js
@@ -0,0 +1,10 @@
+describe('pixi/InteractionManager', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var InteractionManager = PIXI.InteractionManager;
+
+ it('Module exists', function () {
+ expect(InteractionManager).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/Pixi.js b/test/unit/pixi/Pixi.js
new file mode 100644
index 0000000..27debc1
--- /dev/null
+++ b/test/unit/pixi/Pixi.js
@@ -0,0 +1,9 @@
+describe('pixi/Pixi', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+
+ it('Module exists', function () {
+ expect(global).to.have.property('PIXI').and.to.be.an('object');
+ });
+});
diff --git a/test/unit/pixi/core/Circle.js b/test/unit/pixi/core/Circle.js
new file mode 100644
index 0000000..93a4456
--- /dev/null
+++ b/test/unit/pixi/core/Circle.js
@@ -0,0 +1,22 @@
+describe('pixi/core/Circle', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Circle = PIXI.Circle;
+
+ it('Module exists', function () {
+ expect(Circle).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Circle();
+
+ expect(obj).to.be.an.instanceof(Circle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', 0);
+ expect(obj).to.have.property('y', 0);
+ expect(obj).to.have.property('radius', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Ellipse.js b/test/unit/pixi/core/Ellipse.js
new file mode 100644
index 0000000..026b56f
--- /dev/null
+++ b/test/unit/pixi/core/Ellipse.js
@@ -0,0 +1,24 @@
+describe('pixi/core/Ellipse', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Ellipse = PIXI.Ellipse;
+
+ it('Module exists', function () {
+ expect(Ellipse).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Ellipse();
+
+ expect(obj).to.be.an.instanceof(Ellipse);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+ expect(obj).to.respondTo('getBounds');
+
+ expect(obj).to.have.property('x', 0);
+ expect(obj).to.have.property('y', 0);
+ expect(obj).to.have.property('width', 0);
+ expect(obj).to.have.property('height', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Matrix.js b/test/unit/pixi/core/Matrix.js
new file mode 100644
index 0000000..b48989e
--- /dev/null
+++ b/test/unit/pixi/core/Matrix.js
@@ -0,0 +1,30 @@
+describe('pixi/core/Matrix', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var mat3 = PIXI.mat3;
+ var mat4 = PIXI.mat4;
+ var Matrix = PIXI.Matrix;
+
+ it('Ensure determineMatrixArrayType works', function () {
+ expect(Matrix).to.be.a('function');
+ });
+
+ it('mat3 exists', function () {
+ expect(mat3).to.be.an('object');
+ });
+
+ it('Confirm new mat3 matrix', function () {
+ var matrix = new mat3.create();
+ pixi_core_Matrix_confirmNewMat3(matrix);
+ });
+
+ it('mat3 exists', function () {
+ expect(mat4).to.be.an('object');
+ });
+
+ it('Confirm new mat4 matrix', function () {
+ var matrix = new mat4.create();
+ pixi_core_Matrix_confirmNewMat4(matrix);
+ });
+});
diff --git a/test/unit/pixi/core/Point.js b/test/unit/pixi/core/Point.js
new file mode 100644
index 0000000..c4d5163
--- /dev/null
+++ b/test/unit/pixi/core/Point.js
@@ -0,0 +1,15 @@
+describe('pixi/core/Point', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Point = PIXI.Point;
+
+ it('Module exists', function () {
+ expect(Point).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Point();
+ pixi_core_Point_confirm(obj, 0, 0);
+ });
+});
diff --git a/test/unit/pixi/core/Polygon.js b/test/unit/pixi/core/Polygon.js
new file mode 100644
index 0000000..dc8c918
--- /dev/null
+++ b/test/unit/pixi/core/Polygon.js
@@ -0,0 +1,20 @@
+describe('pixi/core/Polygon', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Polygon = PIXI.Polygon;
+
+ it('Module exists', function () {
+ expect(Polygon).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Polygon();
+
+ expect(obj).to.be.an.instanceof(Polygon);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.deep.property('points.length', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Rectangle.js b/test/unit/pixi/core/Rectangle.js
new file mode 100644
index 0000000..d43316e
--- /dev/null
+++ b/test/unit/pixi/core/Rectangle.js
@@ -0,0 +1,15 @@
+describe('pixi/core/Rectangle', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Rectangle = PIXI.Rectangle;
+
+ it('Module exists', function () {
+ expect(Rectangle).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var rect = new Rectangle();
+ pixi_core_Rectangle_confirm(rect, 0, 0, 0, 0);
+ });
+});
diff --git a/test/unit/pixi/display/DisplayObject.js b/test/unit/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..40c6fbc
--- /dev/null
+++ b/test/unit/pixi/display/DisplayObject.js
@@ -0,0 +1,21 @@
+describe('pixi/display/DisplayObject', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var DisplayObject = PIXI.DisplayObject;
+
+ it('Module exists', function () {
+ expect(DisplayObject).to.be.a('function');
+ expect(PIXI).to.have.property('visibleCount', 0);
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new DisplayObject();
+
+ pixi_display_DisplayObject_confirmNew(obj);
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', false);
+ expect(obj).to.have.property('stage', null);
+ });
+});
diff --git a/test/unit/pixi/display/DisplayObjectContainer.js b/test/unit/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..ce7f02f
--- /dev/null
+++ b/test/unit/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,20 @@
+describe('pixi/display/DisplayObjectContainer', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var DisplayObjectContainer = PIXI.DisplayObjectContainer;
+
+ it('Module exists', function () {
+ expect(DisplayObjectContainer).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new DisplayObjectContainer();
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', false);
+ expect(obj).to.have.property('stage', null);
+ });
+});
diff --git a/.gitignore b/.gitignore
index 12e1b62..0b88317 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
node_modules
.DS_Store
-.project
\ No newline at end of file
+.project
+*.log
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..63e4d7c
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,8 @@
+language: node_js
+node_js:
+ - 0.10
+
+before_script:
+ - npm install -g grunt-cli
+ - export DISPLAY=:99.0
+ - sh -e /etc/init.d/xvfb start
diff --git a/Gruntfile.js b/Gruntfile.js
index b083b49..103938c 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -1,10 +1,12 @@
+'use strict';
+
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-connect');
- grunt.loadNpmTasks('grunt-contrib-qunit');
grunt.loadNpmTasks('grunt-contrib-yuidoc');
+ grunt.loadTasks('tasks');
var root = 'src/pixi/',
debug = 'bin/pixi.dev.js',
@@ -79,7 +81,7 @@
},
files: {
srcBlob: '<%= dirs.src %>/**/*.js',
- testBlob: '<%= dirs.test %>/unit/**/*.js',
+ testBlob: '<%= dirs.test %>/{functional,lib/pixi,unit}/**/*.js',
build: '<%= dirs.build %>/pixi.dev.js',
buildMin: '<%= dirs.build %>/pixi.js'
},
@@ -94,7 +96,12 @@
},
jshint: {
beforeconcat: srcFiles,
- test: ['<%= files.testBlob %>'],
+ test: {
+ src: ['<%= files.testBlob %>'],
+ options: {
+ expr: true
+ }
+ },
options: {
asi: true,
smarttabs: true
@@ -128,12 +135,6 @@
]
},
connect: {
- qunit: {
- options: {
- port: grunt.option('port-test') || 9002,
- base: './'
- }
- },
test: {
options: {
port: grunt.option('port-test') || 9002,
@@ -142,13 +143,6 @@
}
}
},
- qunit: {
- all: {
- options: {
- urls: ['http://localhost:' + (grunt.option('port-test') || 9002) + '/test/index.html']
- }
- }
- },
yuidoc: {
compile: {
name: '<%= pkg.name %>',
@@ -161,6 +155,13 @@
outdir: '<%= dirs.docs %>'
}
}
+ },
+ karma: {
+ unit: {
+ configFile: 'test/karma.conf.js',
+ // browsers: ['Chrome'],
+ singleRun: true
+ }
}
});
@@ -182,9 +183,10 @@
}
)
- grunt.registerTask('default', ['concat', 'uglify', 'distribute']);
grunt.registerTask('build', ['concat', 'uglify', 'distribute']);
- grunt.registerTask('test', ['build', 'connect:qunit', 'qunit']);
+ grunt.registerTask('test', ['concat', 'jshint:test', 'karma']);
grunt.registerTask('docs', ['yuidoc']);
-
-}
\ No newline at end of file
+ grunt.registerTask('default', ['test', 'uglify', 'distribute']);
+ // Travis CI task.
+ grunt.registerTask('travis', ['test']);
+}
diff --git a/README.md b/README.md
index c62ef86..690cfe4 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,8 @@

+[](http://travis-ci.org/drkibitz/pixi.js)
+
#### JavaScript 2D Renderer ####
The aim of this project is to provide a fast lightweight 2D library that works
diff --git a/package.json b/package.json
index b373240..1246a68 100644
--- a/package.json
+++ b/package.json
@@ -18,14 +18,21 @@
"main": "bin/pixi.js",
+ "scripts": {
+ "test": "grunt travis --verbose"
+ },
+
"dependencies": {},
"devDependencies": {
"grunt": "~0.4.x",
- "grunt-contrib-jshint": "0.3.x",
+ "grunt-contrib-jshint": "0.6.x",
"grunt-contrib-uglify": "0.2.x",
- "grunt-contrib-connect": "0.2.x",
- "grunt-contrib-qunit": "0.2.x",
+ "grunt-contrib-connect": "0.3.x",
"grunt-contrib-yuidoc": "0.4.x",
- "grunt-contrib-concat": "0.1.x"
+ "grunt-contrib-concat": "0.3.x",
+ "chai": "~1.7.0",
+ "karma": "0.11.0",
+ "karma-firefox-launcher": "0.1.0",
+ "karma-mocha": "0.1.0"
}
}
diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js
index a7c520e..ee82bbd 100644
--- a/src/pixi/InteractionManager.js
+++ b/src/pixi/InteractionManager.js
@@ -62,7 +62,6 @@
this.onTouchEnd = this.onTouchEnd.bind(this);
this.onTouchMove = this.onTouchMove.bind(this);
-
this.last = 0;
}
diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js
index 1a95d20..eef1059 100644
--- a/src/pixi/core/Ellipse.js
+++ b/src/pixi/core/Ellipse.js
@@ -78,7 +78,7 @@
return (normx + normy < 0.25);
}
-PIXI.Ellipse.getBounds = function()
+PIXI.Ellipse.prototype.getBounds = function()
{
return new PIXI.Rectangle(this.x, this.y, this.width, this.height);
}
diff --git a/tasks/karma.js b/tasks/karma.js
new file mode 100644
index 0000000..c340485
--- /dev/null
+++ b/tasks/karma.js
@@ -0,0 +1,27 @@
+'use strict';
+
+var path = require('path');
+var server = require('karma').server;
+
+module.exports = function (grunt) {
+ grunt.registerMultiTask('karma', 'run karma.', function() {
+ var done = this.async();
+ var options = this.options({
+ background: false
+ });
+ var data = this.data;
+
+ //merge options onto data, with data taking precedence
+ data = grunt.util._.merge(options, data);
+ data.configFile = path.resolve(data.configFile);
+ if (data.configFile) {
+ data.configFile = grunt.template.process(data.configFile);
+ }
+
+ server.start(
+ data,
+ function(code) {
+ done(!code);
+ });
+ });
+};
diff --git a/test/functional/example-1-basics/bunny.png b/test/functional/example-1-basics/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/functional/example-1-basics/bunny.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-30.png b/test/functional/example-1-basics/frame-30.png
new file mode 100644
index 0000000..96e3409
--- /dev/null
+++ b/test/functional/example-1-basics/frame-30.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-60.png b/test/functional/example-1-basics/frame-60.png
new file mode 100644
index 0000000..af3f4ce
--- /dev/null
+++ b/test/functional/example-1-basics/frame-60.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-90.png b/test/functional/example-1-basics/frame-90.png
new file mode 100644
index 0000000..099b823
--- /dev/null
+++ b/test/functional/example-1-basics/frame-90.png
Binary files differ
diff --git a/test/functional/example-1-basics/index.js b/test/functional/example-1-basics/index.js
new file mode 100644
index 0000000..7ae7a98
--- /dev/null
+++ b/test/functional/example-1-basics/index.js
@@ -0,0 +1,133 @@
+describe('Example 1 - Basics', function () {
+ 'use strict';
+
+ var baseUri = '/base/test/functional/example-1-basics';
+ var expect = chai.expect;
+ var currentFrame = 0;
+ var frameEvents = {};
+ var stage;
+ var renderer;
+ var bunny;
+
+ function onFrame(frame, callback) {
+ frameEvents[frame] = callback;
+ }
+
+ function animate() {
+ currentFrame += 1;
+
+ requestAnimFrame( animate );
+
+ // just for fun, lets rotate mr rabbit a little
+ bunny.rotation += 0.1;
+
+ // render the stage
+ renderer.render(stage);
+
+ if (frameEvents[currentFrame])
+ frameEvents[currentFrame](currentFrame);
+ }
+
+ function initScene() {
+ // create an new instance of a pixi stage
+ stage = new PIXI.Stage(0x66FF99);
+
+ // create a renderer instance
+ renderer = PIXI.autoDetectRenderer(400, 300);
+ console.log('Is PIXI.WebGLRenderer: ' + (renderer instanceof PIXI.WebGLRenderer));
+
+ // add the renderer view element to the DOM
+ document.body.appendChild(renderer.view);
+
+ requestAnimFrame( animate );
+
+ // create a texture from an image path
+ var texture = PIXI.Texture.fromImage(baseUri + "/bunny.png");
+ // create a new Sprite using the texture
+ bunny = new PIXI.Sprite(texture);
+
+ // center the sprites anchor point
+ bunny.anchor.x = 0.5;
+ bunny.anchor.y = 0.5;
+
+ // move the sprite t the center of the screen
+ bunny.position.x = 200;
+ bunny.position.y = 150;
+
+ stage.addChild(bunny);
+ }
+
+ it('assets loaded', function (done) {
+ var loader = new PIXI.AssetLoader([
+ baseUri + '/bunny.png',
+ baseUri + '/frame-30.png',
+ baseUri + '/frame-60.png',
+ baseUri + '/frame-90.png'
+ ]);
+ // loader.on('onProgress', function (event) {
+ // console.log(event.content);
+ // });
+ loader.on('onComplete', function (event) {
+ done();
+ initScene();
+ });
+ loader.load();
+ });
+
+ it('frame 30 should match', function (done) {
+ this.timeout(700);
+ onFrame(30, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-30.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 60 should match', function (done) {
+ this.timeout(1200);
+ onFrame(60, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-60.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 90 should match', function (done) {
+ this.timeout(1700);
+ onFrame(90, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-90.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ // it('capture something', function (done) {
+ // this.timeout(2000000);
+ // onFrame(30, function () {
+ // var img = new Image();
+ // img.src = renderer.view.toDataURL('image/png');
+ // document.body.appendChild(img);
+ // });
+ // });
+});
diff --git a/test/index.html b/test/index.html
deleted file mode 100644
index 9cbcac5..0000000
--- a/test/index.html
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
- Pixi.js Test Suite
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/test/karma.conf.js b/test/karma.conf.js
new file mode 100644
index 0000000..c66a696
--- /dev/null
+++ b/test/karma.conf.js
@@ -0,0 +1,82 @@
+module.exports = function(config) {
+ config.set({
+
+ // base path, that will be used to resolve files and exclude
+ basePath : '../',
+
+ frameworks : ['mocha'],
+
+ // list of files / patterns to load in the browser
+ files : [
+ 'node_modules/chai/chai.js',
+ 'bin/pixi.dev.js',
+ 'test/lib/**/*.js',
+ 'test/unit/**/*.js',
+ // 'test/functional/**/*.js',
+ {pattern: 'test/**/*.png', watched: false, included: false, served: true}
+ ],
+
+ // list of files to exclude
+ exclude : [],
+
+ // use dolts reporter, as travis terminal does not support escaping sequences
+ // possible values: 'dots', 'progress', 'junit', 'teamcity'
+ // CLI --reporters progress
+ reporters : ['progress'],
+
+ // web server port
+ // CLI --port 9876
+ port : 9876,
+
+ // cli runner port
+ // CLI --runner-port 9100
+ runnerPort : 9100,
+
+ // enable / disable colors in the output (reporters and logs)
+ // CLI --colors --no-colors
+ colors : true,
+
+ // level of logging
+ // possible values: karma.LOG_DISABLE || karma.LOG_ERROR || karma.LOG_WARN || karma.LOG_INFO || karma.LOG_DEBUG
+ // CLI --log-level debug
+ logLevel : config.LOG_DEBUG,
+
+ // enable / disable watching file and executing tests whenever any file changes
+ // CLI --auto-watch --no-auto-watch
+ autoWatch : false,
+
+ // Start these browsers, currently available:
+ // - Chrome
+ // - ChromeCanary
+ // - Firefox
+ // - Opera
+ // - Safari (only Mac)
+ // - PhantomJS
+ // - IE (only Windows)
+ // CLI --browsers Chrome,Firefox,Safari
+ browsers : ['Firefox'],
+
+ // If browser does not capture in given timeout [ms], kill it
+ // CLI --capture-timeout 5000
+ captureTimeout : 5000,
+
+ // Auto run tests on start (when browsers are captured) and exit
+ // CLI --single-run --no-single-run
+ singleRun : true,
+
+ // report which specs are slower than 500ms
+ // CLI --report-slower-than 500
+ reportSlowerThan : 1000,
+
+ preprocessors : {
+ // '**/client/js/*.js': 'coverage'
+ },
+
+ plugins : [
+ 'karma-mocha',
+ // 'karma-chrome-launcher',
+ 'karma-firefox-launcher',
+ // 'karma-phantomjs-launcher'
+ ]
+ });
+};
diff --git a/test/lib/pixi/core/Matrix.js b/test/lib/pixi/core/Matrix.js
new file mode 100644
index 0000000..d26386b
--- /dev/null
+++ b/test/lib/pixi/core/Matrix.js
@@ -0,0 +1,40 @@
+
+function pixi_core_Matrix_confirmNewMat3(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(1);
+ expect(matrix[5]).to.equal(0);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(1);
+}
+
+function pixi_core_Matrix_confirmNewMat4(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[0]).to.equal(1);
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(0);
+ expect(matrix[5]).to.equal(1);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(0);
+ expect(matrix[9]).to.equal(0);
+ expect(matrix[10]).to.equal(1);
+ expect(matrix[11]).to.equal(0);
+ expect(matrix[12]).to.equal(0);
+ expect(matrix[13]).to.equal(0);
+ expect(matrix[14]).to.equal(0);
+ expect(matrix[15]).to.equal(1);
+}
diff --git a/test/lib/pixi/core/Point.js b/test/lib/pixi/core/Point.js
new file mode 100644
index 0000000..e5df07b
--- /dev/null
+++ b/test/lib/pixi/core/Point.js
@@ -0,0 +1,10 @@
+
+function pixi_core_Point_confirm(obj, x, y) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Point);
+ expect(obj).to.respondTo('clone');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+}
diff --git a/test/lib/pixi/core/Rectangle.js b/test/lib/pixi/core/Rectangle.js
new file mode 100644
index 0000000..23f0d12
--- /dev/null
+++ b/test/lib/pixi/core/Rectangle.js
@@ -0,0 +1,13 @@
+
+function pixi_core_Rectangle_confirm(obj, x, y, width, height) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Rectangle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+ expect(obj).to.have.property('width', width);
+ expect(obj).to.have.property('height', height);
+}
diff --git a/test/lib/pixi/display/DisplayObject.js b/test/lib/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..1388a7f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObject.js
@@ -0,0 +1,43 @@
+
+function pixi_display_DisplayObject_confirmNew(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObject);
+ expect(obj).to.respondTo('setInteractive');
+ expect(obj).to.respondTo('addFilter');
+ expect(obj).to.respondTo('removeFilter');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.property('last', obj);
+ expect(obj).to.have.property('first', obj);
+
+ expect(obj).to.contain.property('position');
+ pixi_core_Point_confirm(obj.position, 0, 0);
+ expect(obj).to.contain.property('scale');
+ pixi_core_Point_confirm(obj.scale, 1, 1);
+ expect(obj).to.contain.property('pivot');
+ pixi_core_Point_confirm(obj.pivot, 0, 0);
+
+ expect(obj).to.have.property('rotation', 0);
+ expect(obj).to.have.property('alpha', 1);
+ expect(obj).to.have.property('visible', true);
+ expect(obj).to.have.property('buttonMode', false);
+ expect(obj).to.have.property('parent', null);
+ expect(obj).to.have.property('worldAlpha', 1);
+
+ expect(obj).to.have.property('hitArea');
+ expect(obj).to.have.property('interactive'); // TODO: Have a better default value
+ expect('mask' in obj).to.be.true; // TODO: Have a better default value
+ expect(obj.mask).to.be.undefined;
+
+ expect(obj).to.have.property('renderable');
+ expect(obj).to.have.property('stage');
+
+ expect(obj).to.have.deep.property('worldTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ expect(obj).to.have.deep.property('localTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.localTransform);
+
+ expect(obj).to.have.deep.property('color.length', 0);
+ expect(obj).to.have.property('dynamic', true);
+}
diff --git a/test/lib/pixi/display/DisplayObjectContainer.js b/test/lib/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..085c59f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,16 @@
+
+function pixi_display_DisplayObjectContainer_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObject_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObjectContainer);
+ expect(obj).to.respondTo('addChild');
+ expect(obj).to.respondTo('addChildAt');
+ expect(obj).to.respondTo('swapChildren');
+ expect(obj).to.respondTo('getChildAt');
+ expect(obj).to.respondTo('removeChild');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('children.length', 0);
+}
diff --git a/test/lib/pixi/display/Sprite.js b/test/lib/pixi/display/Sprite.js
new file mode 100644
index 0000000..cc7a2d6
--- /dev/null
+++ b/test/lib/pixi/display/Sprite.js
@@ -0,0 +1,28 @@
+
+function pixi_display_Sprite_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Sprite);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', true);
+ expect(obj).to.have.property('stage', null);
+
+ expect(obj).to.have.property('anchor');
+ pixi_core_Point_confirm(obj.anchor, 0, 0);
+
+ expect(obj).to.have.property('blendMode', PIXI.blendModes.NORMAL);
+ expect(obj).to.have.property('width', 1); // TODO: is 1 expected
+ expect(obj).to.have.property('height', 1); // TODO: is 1 expected
+
+ // FIXME: Just make this a boolean that is always there
+ expect(!!obj.updateFrame).to.equal(obj.texture.baseTexture.hasLoaded);
+
+ expect(obj).to.have.property('texture');
+ pixi_textures_Texture_confirmNew(obj.texture, done);
+}
diff --git a/test/lib/pixi/extras/Strip.js b/test/lib/pixi/extras/Strip.js
new file mode 100644
index 0000000..8927a8a
--- /dev/null
+++ b/test/lib/pixi/extras/Strip.js
@@ -0,0 +1,12 @@
+
+function pixi_extras_Strip_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Strip);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ // TODO: Test properties
+}
diff --git a/test/lib/pixi/textures/Texture.js b/test/lib/pixi/textures/Texture.js
new file mode 100644
index 0000000..d5867b6
--- /dev/null
+++ b/test/lib/pixi/textures/Texture.js
@@ -0,0 +1,31 @@
+
+function pixi_textures_Texture_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ function confirmFrameDone() {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, obj.baseTexture.width, obj.baseTexture.height);
+
+ expect(obj).to.have.property('width', obj.baseTexture.width);
+ expect(obj).to.have.property('height', obj.baseTexture.height);
+ done();
+ }
+
+ expect(obj).to.be.an.instanceof(PIXI.Texture);
+ pixi_utils_EventTarget_like(obj);
+
+ expect(obj).to.have.property('baseTexture')
+ .and.to.be.an.instanceof(PIXI.BaseTexture);
+
+ expect(obj).to.have.property('scope', obj);
+
+ expect(obj).to.have.property('trim');
+ pixi_core_Point_confirm(obj.trim, 0, 0);
+
+ expect(obj).to.have.property('frame');
+ if (obj.baseTexture.hasLoaded) {
+ confirmFrameDone();
+ } else {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, 1, 1);
+ obj.addEventListener('update', confirmFrameDone);
+ }
+}
diff --git a/test/lib/pixi/utils/EventTarget.js b/test/lib/pixi/utils/EventTarget.js
new file mode 100644
index 0000000..7b1dcfa
--- /dev/null
+++ b/test/lib/pixi/utils/EventTarget.js
@@ -0,0 +1,8 @@
+
+function pixi_utils_EventTarget_like(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.respondTo('addEventListener');
+ expect(obj).to.respondTo('dispatchEvent');
+ expect(obj).to.respondTo('removeEventListener');
+}
diff --git a/test/lib/qunit-1.11.0.css b/test/lib/qunit-1.11.0.css
deleted file mode 100644
index d7fc0c8..0000000
--- a/test/lib/qunit-1.11.0.css
+++ /dev/null
@@ -1,244 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-/** Font Family and Sizes */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
- font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
-}
-
-#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
-#qunit-tests { font-size: smaller; }
-
-
-/** Resets */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter {
- margin: 0;
- padding: 0;
-}
-
-
-/** Header */
-
-#qunit-header {
- padding: 0.5em 0 0.5em 1em;
-
- color: #8699a4;
- background-color: #0d3349;
-
- font-size: 1.5em;
- line-height: 1em;
- font-weight: normal;
-
- border-radius: 5px 5px 0 0;
- -moz-border-radius: 5px 5px 0 0;
- -webkit-border-top-right-radius: 5px;
- -webkit-border-top-left-radius: 5px;
-}
-
-#qunit-header a {
- text-decoration: none;
- color: #c2ccd1;
-}
-
-#qunit-header a:hover,
-#qunit-header a:focus {
- color: #fff;
-}
-
-#qunit-testrunner-toolbar label {
- display: inline-block;
- padding: 0 .5em 0 .1em;
-}
-
-#qunit-banner {
- height: 5px;
-}
-
-#qunit-testrunner-toolbar {
- padding: 0.5em 0 0.5em 2em;
- color: #5E740B;
- background-color: #eee;
- overflow: hidden;
-}
-
-#qunit-userAgent {
- padding: 0.5em 0 0.5em 2.5em;
- background-color: #2b81af;
- color: #fff;
- text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
-}
-
-#qunit-modulefilter-container {
- float: right;
-}
-
-/** Tests: Pass/Fail */
-
-#qunit-tests {
- list-style-position: inside;
-}
-
-#qunit-tests li {
- padding: 0.4em 0.5em 0.4em 2.5em;
- border-bottom: 1px solid #fff;
- list-style-position: inside;
-}
-
-#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running {
- display: none;
-}
-
-#qunit-tests li strong {
- cursor: pointer;
-}
-
-#qunit-tests li a {
- padding: 0.5em;
- color: #c2ccd1;
- text-decoration: none;
-}
-#qunit-tests li a:hover,
-#qunit-tests li a:focus {
- color: #000;
-}
-
-#qunit-tests li .runtime {
- float: right;
- font-size: smaller;
-}
-
-.qunit-assert-list {
- margin-top: 0.5em;
- padding: 0.5em;
-
- background-color: #fff;
-
- border-radius: 5px;
- -moz-border-radius: 5px;
- -webkit-border-radius: 5px;
-}
-
-.qunit-collapsed {
- display: none;
-}
-
-#qunit-tests table {
- border-collapse: collapse;
- margin-top: .2em;
-}
-
-#qunit-tests th {
- text-align: right;
- vertical-align: top;
- padding: 0 .5em 0 0;
-}
-
-#qunit-tests td {
- vertical-align: top;
-}
-
-#qunit-tests pre {
- margin: 0;
- white-space: pre-wrap;
- word-wrap: break-word;
-}
-
-#qunit-tests del {
- background-color: #e0f2be;
- color: #374e0c;
- text-decoration: none;
-}
-
-#qunit-tests ins {
- background-color: #ffcaca;
- color: #500;
- text-decoration: none;
-}
-
-/*** Test Counts */
-
-#qunit-tests b.counts { color: black; }
-#qunit-tests b.passed { color: #5E740B; }
-#qunit-tests b.failed { color: #710909; }
-
-#qunit-tests li li {
- padding: 5px;
- background-color: #fff;
- border-bottom: none;
- list-style-position: inside;
-}
-
-/*** Passing Styles */
-
-#qunit-tests li li.pass {
- color: #3c510c;
- background-color: #fff;
- border-left: 10px solid #C6E746;
-}
-
-#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
-#qunit-tests .pass .test-name { color: #366097; }
-
-#qunit-tests .pass .test-actual,
-#qunit-tests .pass .test-expected { color: #999999; }
-
-#qunit-banner.qunit-pass { background-color: #C6E746; }
-
-/*** Failing Styles */
-
-#qunit-tests li li.fail {
- color: #710909;
- background-color: #fff;
- border-left: 10px solid #EE5757;
- white-space: pre;
-}
-
-#qunit-tests > li:last-child {
- border-radius: 0 0 5px 5px;
- -moz-border-radius: 0 0 5px 5px;
- -webkit-border-bottom-right-radius: 5px;
- -webkit-border-bottom-left-radius: 5px;
-}
-
-#qunit-tests .fail { color: #000000; background-color: #EE5757; }
-#qunit-tests .fail .test-name,
-#qunit-tests .fail .module-name { color: #000000; }
-
-#qunit-tests .fail .test-actual { color: #EE5757; }
-#qunit-tests .fail .test-expected { color: green; }
-
-#qunit-banner.qunit-fail { background-color: #EE5757; }
-
-
-/** Result */
-
-#qunit-testresult {
- padding: 0.5em 0.5em 0.5em 2.5em;
-
- color: #2b81af;
- background-color: #D2E0E6;
-
- border-bottom: 1px solid white;
-}
-#qunit-testresult .module-name {
- font-weight: bold;
-}
-
-/** Fixture */
-
-#qunit-fixture {
- position: absolute;
- top: -10000px;
- left: -10000px;
- width: 1000px;
- height: 1000px;
-}
diff --git a/test/lib/qunit-1.11.0.js b/test/lib/qunit-1.11.0.js
deleted file mode 100644
index 302545f..0000000
--- a/test/lib/qunit-1.11.0.js
+++ /dev/null
@@ -1,2152 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-(function( window ) {
-
-var QUnit,
- assert,
- config,
- onErrorFnPrev,
- testId = 0,
- fileName = (sourceFromStacktrace( 0 ) || "" ).replace(/(:\d+)+\)?/, "").replace(/.+\//, ""),
- toString = Object.prototype.toString,
- hasOwn = Object.prototype.hasOwnProperty,
- // Keep a local reference to Date (GH-283)
- Date = window.Date,
- defined = {
- setTimeout: typeof window.setTimeout !== "undefined",
- sessionStorage: (function() {
- var x = "qunit-test-string";
- try {
- sessionStorage.setItem( x, x );
- sessionStorage.removeItem( x );
- return true;
- } catch( e ) {
- return false;
- }
- }())
- },
- /**
- * Provides a normalized error string, correcting an issue
- * with IE 7 (and prior) where Error.prototype.toString is
- * not properly implemented
- *
- * Based on http://es5.github.com/#x15.11.4.4
- *
- * @param {String|Error} error
- * @return {String} error message
- */
- errorString = function( error ) {
- var name, message,
- errorString = error.toString();
- if ( errorString.substring( 0, 7 ) === "[object" ) {
- name = error.name ? error.name.toString() : "Error";
- message = error.message ? error.message.toString() : "";
- if ( name && message ) {
- return name + ": " + message;
- } else if ( name ) {
- return name;
- } else if ( message ) {
- return message;
- } else {
- return "Error";
- }
- } else {
- return errorString;
- }
- },
- /**
- * Makes a clone of an object using only Array or Object as base,
- * and copies over the own enumerable properties.
- *
- * @param {Object} obj
- * @return {Object} New object with only the own properties (recursively).
- */
- objectValues = function( obj ) {
- // Grunt 0.3.x uses an older version of jshint that still has jshint/jshint#392.
- /*jshint newcap: false */
- var key, val,
- vals = QUnit.is( "array", obj ) ? [] : {};
- for ( key in obj ) {
- if ( hasOwn.call( obj, key ) ) {
- val = obj[key];
- vals[key] = val === Object(val) ? objectValues(val) : val;
- }
- }
- return vals;
- };
-
-function Test( settings ) {
- extend( this, settings );
- this.assertions = [];
- this.testNumber = ++Test.count;
-}
-
-Test.count = 0;
-
-Test.prototype = {
- init: function() {
- var a, b, li,
- tests = id( "qunit-tests" );
-
- if ( tests ) {
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml;
-
- // `a` initialized at top of scope
- a = document.createElement( "a" );
- a.innerHTML = "Rerun";
- a.href = QUnit.url({ testNumber: this.testNumber });
-
- li = document.createElement( "li" );
- li.appendChild( b );
- li.appendChild( a );
- li.className = "running";
- li.id = this.id = "qunit-test-output" + testId++;
-
- tests.appendChild( li );
- }
- },
- setup: function() {
- if ( this.module !== config.previousModule ) {
- if ( config.previousModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.previousModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
- config.previousModule = this.module;
- config.moduleStats = { all: 0, bad: 0 };
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- } else if ( config.autorun ) {
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- }
-
- config.current = this;
-
- this.testEnvironment = extend({
- setup: function() {},
- teardown: function() {}
- }, this.moduleTestEnvironment );
-
- this.started = +new Date();
- runLoggingCallbacks( "testStart", QUnit, {
- name: this.testName,
- module: this.module
- });
-
- // allow utility functions to access the current test environment
- // TODO why??
- QUnit.current_testEnvironment = this.testEnvironment;
-
- if ( !config.pollution ) {
- saveGlobal();
- }
- if ( config.notrycatch ) {
- this.testEnvironment.setup.call( this.testEnvironment );
- return;
- }
- try {
- this.testEnvironment.setup.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Setup failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- },
- run: function() {
- config.current = this;
-
- var running = id( "qunit-testresult" );
-
- if ( running ) {
- running.innerHTML = "Running:
" + this.nameHtml;
- }
-
- if ( this.async ) {
- QUnit.stop();
- }
-
- this.callbackStarted = +new Date();
-
- if ( config.notrycatch ) {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- return;
- }
-
- try {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- } catch( e ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
-
- QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + " " + this.stack + ": " + ( e.message || e ), extractStacktrace( e, 0 ) );
- // else next test will carry the responsibility
- saveGlobal();
-
- // Restart the tests if they're blocking
- if ( config.blocking ) {
- QUnit.start();
- }
- }
- },
- teardown: function() {
- config.current = this;
- if ( config.notrycatch ) {
- if ( typeof this.callbackRuntime === "undefined" ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
- }
- this.testEnvironment.teardown.call( this.testEnvironment );
- return;
- } else {
- try {
- this.testEnvironment.teardown.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Teardown failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- }
- checkPollution();
- },
- finish: function() {
- config.current = this;
- if ( config.requireExpects && this.expected === null ) {
- QUnit.pushFailure( "Expected number of assertions to be defined, but expect() was not called.", this.stack );
- } else if ( this.expected !== null && this.expected !== this.assertions.length ) {
- QUnit.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack );
- } else if ( this.expected === null && !this.assertions.length ) {
- QUnit.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions.", this.stack );
- }
-
- var i, assertion, a, b, time, li, ol,
- test = this,
- good = 0,
- bad = 0,
- tests = id( "qunit-tests" );
-
- this.runtime = +new Date() - this.started;
- config.stats.all += this.assertions.length;
- config.moduleStats.all += this.assertions.length;
-
- if ( tests ) {
- ol = document.createElement( "ol" );
- ol.className = "qunit-assert-list";
-
- for ( i = 0; i < this.assertions.length; i++ ) {
- assertion = this.assertions[i];
-
- li = document.createElement( "li" );
- li.className = assertion.result ? "pass" : "fail";
- li.innerHTML = assertion.message || ( assertion.result ? "okay" : "failed" );
- ol.appendChild( li );
-
- if ( assertion.result ) {
- good++;
- } else {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
-
- // store result when possible
- if ( QUnit.config.reorder && defined.sessionStorage ) {
- if ( bad ) {
- sessionStorage.setItem( "qunit-test-" + this.module + "-" + this.testName, bad );
- } else {
- sessionStorage.removeItem( "qunit-test-" + this.module + "-" + this.testName );
- }
- }
-
- if ( bad === 0 ) {
- addClass( ol, "qunit-collapsed" );
- }
-
- // `b` initialized at top of scope
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml + " (" + bad + ", " + good + ", " + this.assertions.length + ")";
-
- addEvent(b, "click", function() {
- var next = b.parentNode.lastChild,
- collapsed = hasClass( next, "qunit-collapsed" );
- ( collapsed ? removeClass : addClass )( next, "qunit-collapsed" );
- });
-
- addEvent(b, "dblclick", function( e ) {
- var target = e && e.target ? e.target : window.event.srcElement;
- if ( target.nodeName.toLowerCase() === "span" || target.nodeName.toLowerCase() === "b" ) {
- target = target.parentNode;
- }
- if ( window.location && target.nodeName.toLowerCase() === "strong" ) {
- window.location = QUnit.url({ testNumber: test.testNumber });
- }
- });
-
- // `time` initialized at top of scope
- time = document.createElement( "span" );
- time.className = "runtime";
- time.innerHTML = this.runtime + " ms";
-
- // `li` initialized at top of scope
- li = id( this.id );
- li.className = bad ? "fail" : "pass";
- li.removeChild( li.firstChild );
- a = li.firstChild;
- li.appendChild( b );
- li.appendChild( a );
- li.appendChild( time );
- li.appendChild( ol );
-
- } else {
- for ( i = 0; i < this.assertions.length; i++ ) {
- if ( !this.assertions[i].result ) {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
- }
-
- runLoggingCallbacks( "testDone", QUnit, {
- name: this.testName,
- module: this.module,
- failed: bad,
- passed: this.assertions.length - bad,
- total: this.assertions.length,
- duration: this.runtime
- });
-
- QUnit.reset();
-
- config.current = undefined;
- },
-
- queue: function() {
- var bad,
- test = this;
-
- synchronize(function() {
- test.init();
- });
- function run() {
- // each of these can by async
- synchronize(function() {
- test.setup();
- });
- synchronize(function() {
- test.run();
- });
- synchronize(function() {
- test.teardown();
- });
- synchronize(function() {
- test.finish();
- });
- }
-
- // `bad` initialized at top of scope
- // defer when previous test run passed, if storage is available
- bad = QUnit.config.reorder && defined.sessionStorage &&
- +sessionStorage.getItem( "qunit-test-" + this.module + "-" + this.testName );
-
- if ( bad ) {
- run();
- } else {
- synchronize( run, true );
- }
- }
-};
-
-// Root QUnit object.
-// `QUnit` initialized at top of scope
-QUnit = {
-
- // call on start of module test to prepend name to all tests
- module: function( name, testEnvironment ) {
- config.currentModule = name;
- config.currentModuleTestEnvironment = testEnvironment;
- config.modules[name] = true;
- },
-
- asyncTest: function( testName, expected, callback ) {
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- QUnit.test( testName, expected, callback, true );
- },
-
- test: function( testName, expected, callback, async ) {
- var test,
- nameHtml = "" + escapeText( testName ) + "";
-
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- if ( config.currentModule ) {
- nameHtml = "" + escapeText( config.currentModule ) + ": " + nameHtml;
- }
-
- test = new Test({
- nameHtml: nameHtml,
- testName: testName,
- expected: expected,
- async: async,
- callback: callback,
- module: config.currentModule,
- moduleTestEnvironment: config.currentModuleTestEnvironment,
- stack: sourceFromStacktrace( 2 )
- });
-
- if ( !validTest( test ) ) {
- return;
- }
-
- test.queue();
- },
-
- // Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through.
- expect: function( asserts ) {
- if (arguments.length === 1) {
- config.current.expected = asserts;
- } else {
- return config.current.expected;
- }
- },
-
- start: function( count ) {
- // QUnit hasn't been initialized yet.
- // Note: RequireJS (et al) may delay onLoad
- if ( config.semaphore === undefined ) {
- QUnit.begin(function() {
- // This is triggered at the top of QUnit.load, push start() to the event loop, to allow QUnit.load to finish first
- setTimeout(function() {
- QUnit.start( count );
- });
- });
- return;
- }
-
- config.semaphore -= count || 1;
- // don't start until equal number of stop-calls
- if ( config.semaphore > 0 ) {
- return;
- }
- // ignore if start is called more often then stop
- if ( config.semaphore < 0 ) {
- config.semaphore = 0;
- QUnit.pushFailure( "Called start() while already started (QUnit.config.semaphore was 0 already)", null, sourceFromStacktrace(2) );
- return;
- }
- // A slight delay, to avoid any current callbacks
- if ( defined.setTimeout ) {
- window.setTimeout(function() {
- if ( config.semaphore > 0 ) {
- return;
- }
- if ( config.timeout ) {
- clearTimeout( config.timeout );
- }
-
- config.blocking = false;
- process( true );
- }, 13);
- } else {
- config.blocking = false;
- process( true );
- }
- },
-
- stop: function( count ) {
- config.semaphore += count || 1;
- config.blocking = true;
-
- if ( config.testTimeout && defined.setTimeout ) {
- clearTimeout( config.timeout );
- config.timeout = window.setTimeout(function() {
- QUnit.ok( false, "Test timed out" );
- config.semaphore = 1;
- QUnit.start();
- }, config.testTimeout );
- }
- }
-};
-
-// `assert` initialized at top of scope
-// Asssert helpers
-// All of these must either call QUnit.push() or manually do:
-// - runLoggingCallbacks( "log", .. );
-// - config.current.assertions.push({ .. });
-// We attach it to the QUnit object *after* we expose the public API,
-// otherwise `assert` will become a global variable in browsers (#341).
-assert = {
- /**
- * Asserts rough true-ish result.
- * @name ok
- * @function
- * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" );
- */
- ok: function( result, msg ) {
- if ( !config.current ) {
- throw new Error( "ok() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
- result = !!result;
-
- var source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: msg
- };
-
- msg = escapeText( msg || (result ? "okay" : "failed" ) );
- msg = "" + msg + "";
-
- if ( !result ) {
- source = sourceFromStacktrace( 2 );
- if ( source ) {
- details.source = source;
- msg += "Source: | " + escapeText( source ) + " |
---|
";
- }
- }
- runLoggingCallbacks( "log", QUnit, details );
- config.current.assertions.push({
- result: result,
- message: msg
- });
- },
-
- /**
- * Assert that the first two arguments are equal, with an optional message.
- * Prints out both actual and expected values.
- * @name equal
- * @function
- * @example equal( format( "Received {0} bytes.", 2), "Received 2 bytes.", "format() replaces {0} with next argument" );
- */
- equal: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected == actual, actual, expected, message );
- },
-
- /**
- * @name notEqual
- * @function
- */
- notEqual: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected != actual, actual, expected, message );
- },
-
- /**
- * @name propEqual
- * @function
- */
- propEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notPropEqual
- * @function
- */
- notPropEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name deepEqual
- * @function
- */
- deepEqual: function( actual, expected, message ) {
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notDeepEqual
- * @function
- */
- notDeepEqual: function( actual, expected, message ) {
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name strictEqual
- * @function
- */
- strictEqual: function( actual, expected, message ) {
- QUnit.push( expected === actual, actual, expected, message );
- },
-
- /**
- * @name notStrictEqual
- * @function
- */
- notStrictEqual: function( actual, expected, message ) {
- QUnit.push( expected !== actual, actual, expected, message );
- },
-
- "throws": function( block, expected, message ) {
- var actual,
- expectedOutput = expected,
- ok = false;
-
- // 'expected' is optional
- if ( typeof expected === "string" ) {
- message = expected;
- expected = null;
- }
-
- config.current.ignoreGlobalErrors = true;
- try {
- block.call( config.current.testEnvironment );
- } catch (e) {
- actual = e;
- }
- config.current.ignoreGlobalErrors = false;
-
- if ( actual ) {
- // we don't want to validate thrown error
- if ( !expected ) {
- ok = true;
- expectedOutput = null;
- // expected is a regexp
- } else if ( QUnit.objectType( expected ) === "regexp" ) {
- ok = expected.test( errorString( actual ) );
- // expected is a constructor
- } else if ( actual instanceof expected ) {
- ok = true;
- // expected is a validation function which returns true is validation passed
- } else if ( expected.call( {}, actual ) === true ) {
- expectedOutput = null;
- ok = true;
- }
-
- QUnit.push( ok, actual, expectedOutput, message );
- } else {
- QUnit.pushFailure( message, null, 'No exception was thrown.' );
- }
- }
-};
-
-/**
- * @deprecate since 1.8.0
- * Kept assertion helpers in root for backwards compatibility.
- */
-extend( QUnit, assert );
-
-/**
- * @deprecated since 1.9.0
- * Kept root "raises()" for backwards compatibility.
- * (Note that we don't introduce assert.raises).
- */
-QUnit.raises = assert[ "throws" ];
-
-/**
- * @deprecated since 1.0.0, replaced with error pushes since 1.3.0
- * Kept to avoid TypeErrors for undefined methods.
- */
-QUnit.equals = function() {
- QUnit.push( false, false, false, "QUnit.equals has been deprecated since 2009 (e88049a0), use QUnit.equal instead" );
-};
-QUnit.same = function() {
- QUnit.push( false, false, false, "QUnit.same has been deprecated since 2009 (e88049a0), use QUnit.deepEqual instead" );
-};
-
-// We want access to the constructor's prototype
-(function() {
- function F() {}
- F.prototype = QUnit;
- QUnit = new F();
- // Make F QUnit's constructor so that we can add to the prototype later
- QUnit.constructor = F;
-}());
-
-/**
- * Config object: Maintain internal state
- * Later exposed as QUnit.config
- * `config` initialized at top of scope
- */
-config = {
- // The queue of tests to run
- queue: [],
-
- // block until document ready
- blocking: true,
-
- // when enabled, show only failing tests
- // gets persisted through sessionStorage and can be changed in UI via checkbox
- hidepassed: false,
-
- // by default, run previously failed tests first
- // very useful in combination with "Hide passed tests" checked
- reorder: true,
-
- // by default, modify document.title when suite is done
- altertitle: true,
-
- // when enabled, all tests must call expect()
- requireExpects: false,
-
- // add checkboxes that are persisted in the query-string
- // when enabled, the id is set to `true` as a `QUnit.config` property
- urlConfig: [
- {
- id: "noglobals",
- label: "Check for Globals",
- tooltip: "Enabling this will test if any test introduces new properties on the `window` object. Stored as query-strings."
- },
- {
- id: "notrycatch",
- label: "No try-catch",
- tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging exceptions in IE reasonable. Stored as query-strings."
- }
- ],
-
- // Set of all modules.
- modules: {},
-
- // logging callback queues
- begin: [],
- done: [],
- log: [],
- testStart: [],
- testDone: [],
- moduleStart: [],
- moduleDone: []
-};
-
-// Export global variables, unless an 'exports' object exists,
-// in that case we assume we're in CommonJS (dealt with on the bottom of the script)
-if ( typeof exports === "undefined" ) {
- extend( window, QUnit );
-
- // Expose QUnit object
- window.QUnit = QUnit;
-}
-
-// Initialize more QUnit.config and QUnit.urlParams
-(function() {
- var i,
- location = window.location || { search: "", protocol: "file:" },
- params = location.search.slice( 1 ).split( "&" ),
- length = params.length,
- urlParams = {},
- current;
-
- if ( params[ 0 ] ) {
- for ( i = 0; i < length; i++ ) {
- current = params[ i ].split( "=" );
- current[ 0 ] = decodeURIComponent( current[ 0 ] );
- // allow just a key to turn on a flag, e.g., test.html?noglobals
- current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true;
- urlParams[ current[ 0 ] ] = current[ 1 ];
- }
- }
-
- QUnit.urlParams = urlParams;
-
- // String search anywhere in moduleName+testName
- config.filter = urlParams.filter;
-
- // Exact match of the module name
- config.module = urlParams.module;
-
- config.testNumber = parseInt( urlParams.testNumber, 10 ) || null;
-
- // Figure out if we're running the tests from a server or not
- QUnit.isLocal = location.protocol === "file:";
-}());
-
-// Extend QUnit object,
-// these after set here because they should not be exposed as global functions
-extend( QUnit, {
- assert: assert,
-
- config: config,
-
- // Initialize the configuration options
- init: function() {
- extend( config, {
- stats: { all: 0, bad: 0 },
- moduleStats: { all: 0, bad: 0 },
- started: +new Date(),
- updateRate: 1000,
- blocking: false,
- autostart: true,
- autorun: false,
- filter: "",
- queue: [],
- semaphore: 1
- });
-
- var tests, banner, result,
- qunit = id( "qunit" );
-
- if ( qunit ) {
- qunit.innerHTML =
- "" +
- "" +
- "" +
- "" +
- "
";
- }
-
- tests = id( "qunit-tests" );
- banner = id( "qunit-banner" );
- result = id( "qunit-testresult" );
-
- if ( tests ) {
- tests.innerHTML = "";
- }
-
- if ( banner ) {
- banner.className = "";
- }
-
- if ( result ) {
- result.parentNode.removeChild( result );
- }
-
- if ( tests ) {
- result = document.createElement( "p" );
- result.id = "qunit-testresult";
- result.className = "result";
- tests.parentNode.insertBefore( result, tests );
- result.innerHTML = "Running...
";
- }
- },
-
- // Resets the test setup. Useful for tests that modify the DOM.
- reset: function() {
- var fixture = id( "qunit-fixture" );
- if ( fixture ) {
- fixture.innerHTML = config.fixture;
- }
- },
-
- // Trigger an event on an element.
- // @example triggerEvent( document.body, "click" );
- triggerEvent: function( elem, type, event ) {
- if ( document.createEvent ) {
- event = document.createEvent( "MouseEvents" );
- event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView,
- 0, 0, 0, 0, 0, false, false, false, false, 0, null);
-
- elem.dispatchEvent( event );
- } else if ( elem.fireEvent ) {
- elem.fireEvent( "on" + type );
- }
- },
-
- // Safe object type checking
- is: function( type, obj ) {
- return QUnit.objectType( obj ) === type;
- },
-
- objectType: function( obj ) {
- if ( typeof obj === "undefined" ) {
- return "undefined";
- // consider: typeof null === object
- }
- if ( obj === null ) {
- return "null";
- }
-
- var match = toString.call( obj ).match(/^\[object\s(.*)\]$/),
- type = match && match[1] || "";
-
- switch ( type ) {
- case "Number":
- if ( isNaN(obj) ) {
- return "nan";
- }
- return "number";
- case "String":
- case "Boolean":
- case "Array":
- case "Date":
- case "RegExp":
- case "Function":
- return type.toLowerCase();
- }
- if ( typeof obj === "object" ) {
- return "object";
- }
- return undefined;
- },
-
- push: function( result, actual, expected, message ) {
- if ( !config.current ) {
- throw new Error( "assertion outside test context, was " + sourceFromStacktrace() );
- }
-
- var output, source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: message,
- actual: actual,
- expected: expected
- };
-
- message = escapeText( message ) || ( result ? "okay" : "failed" );
- message = "" + message + "";
- output = message;
-
- if ( !result ) {
- expected = escapeText( QUnit.jsDump.parse(expected) );
- actual = escapeText( QUnit.jsDump.parse(actual) );
- output += "Expected: | " + expected + " |
";
-
- if ( actual !== expected ) {
- output += "Result: | " + actual + " |
";
- output += "Diff: | " + QUnit.diff( expected, actual ) + " |
";
- }
-
- source = sourceFromStacktrace();
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
- }
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: !!result,
- message: output
- });
- },
-
- pushFailure: function( message, source, actual ) {
- if ( !config.current ) {
- throw new Error( "pushFailure() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
-
- var output,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: false,
- message: message
- };
-
- message = escapeText( message ) || "error";
- message = "" + message + "";
- output = message;
-
- output += "";
-
- if ( actual ) {
- output += "Result: | " + escapeText( actual ) + " |
";
- }
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: false,
- message: output
- });
- },
-
- url: function( params ) {
- params = extend( extend( {}, QUnit.urlParams ), params );
- var key,
- querystring = "?";
-
- for ( key in params ) {
- if ( !hasOwn.call( params, key ) ) {
- continue;
- }
- querystring += encodeURIComponent( key ) + "=" +
- encodeURIComponent( params[ key ] ) + "&";
- }
- return window.location.protocol + "//" + window.location.host +
- window.location.pathname + querystring.slice( 0, -1 );
- },
-
- extend: extend,
- id: id,
- addEvent: addEvent
- // load, equiv, jsDump, diff: Attached later
-});
-
-/**
- * @deprecated: Created for backwards compatibility with test runner that set the hook function
- * into QUnit.{hook}, instead of invoking it and passing the hook function.
- * QUnit.constructor is set to the empty F() above so that we can add to it's prototype here.
- * Doing this allows us to tell if the following methods have been overwritten on the actual
- * QUnit object.
- */
-extend( QUnit.constructor.prototype, {
-
- // Logging callbacks; all receive a single argument with the listed properties
- // run test/logs.html for any related changes
- begin: registerLoggingCallback( "begin" ),
-
- // done: { failed, passed, total, runtime }
- done: registerLoggingCallback( "done" ),
-
- // log: { result, actual, expected, message }
- log: registerLoggingCallback( "log" ),
-
- // testStart: { name }
- testStart: registerLoggingCallback( "testStart" ),
-
- // testDone: { name, failed, passed, total, duration }
- testDone: registerLoggingCallback( "testDone" ),
-
- // moduleStart: { name }
- moduleStart: registerLoggingCallback( "moduleStart" ),
-
- // moduleDone: { name, failed, passed, total }
- moduleDone: registerLoggingCallback( "moduleDone" )
-});
-
-if ( typeof document === "undefined" || document.readyState === "complete" ) {
- config.autorun = true;
-}
-
-QUnit.load = function() {
- runLoggingCallbacks( "begin", QUnit, {} );
-
- // Initialize the config, saving the execution queue
- var banner, filter, i, label, len, main, ol, toolbar, userAgent, val,
- urlConfigCheckboxesContainer, urlConfigCheckboxes, moduleFilter,
- numModules = 0,
- moduleFilterHtml = "",
- urlConfigHtml = "",
- oldconfig = extend( {}, config );
-
- QUnit.init();
- extend(config, oldconfig);
-
- config.blocking = false;
-
- len = config.urlConfig.length;
-
- for ( i = 0; i < len; i++ ) {
- val = config.urlConfig[i];
- if ( typeof val === "string" ) {
- val = {
- id: val,
- label: val,
- tooltip: "[no tooltip available]"
- };
- }
- config[ val.id ] = QUnit.urlParams[ val.id ];
- urlConfigHtml += "";
- }
-
- moduleFilterHtml += "";
-
- // `userAgent` initialized at top of scope
- userAgent = id( "qunit-userAgent" );
- if ( userAgent ) {
- userAgent.innerHTML = navigator.userAgent;
- }
-
- // `banner` initialized at top of scope
- banner = id( "qunit-header" );
- if ( banner ) {
- banner.innerHTML = "" + banner.innerHTML + " ";
- }
-
- // `toolbar` initialized at top of scope
- toolbar = id( "qunit-testrunner-toolbar" );
- if ( toolbar ) {
- // `filter` initialized at top of scope
- filter = document.createElement( "input" );
- filter.type = "checkbox";
- filter.id = "qunit-filter-pass";
-
- addEvent( filter, "click", function() {
- var tmp,
- ol = document.getElementById( "qunit-tests" );
-
- if ( filter.checked ) {
- ol.className = ol.className + " hidepass";
- } else {
- tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " ";
- ol.className = tmp.replace( / hidepass /, " " );
- }
- if ( defined.sessionStorage ) {
- if (filter.checked) {
- sessionStorage.setItem( "qunit-filter-passed-tests", "true" );
- } else {
- sessionStorage.removeItem( "qunit-filter-passed-tests" );
- }
- }
- });
-
- if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem( "qunit-filter-passed-tests" ) ) {
- filter.checked = true;
- // `ol` initialized at top of scope
- ol = document.getElementById( "qunit-tests" );
- ol.className = ol.className + " hidepass";
- }
- toolbar.appendChild( filter );
-
- // `label` initialized at top of scope
- label = document.createElement( "label" );
- label.setAttribute( "for", "qunit-filter-pass" );
- label.setAttribute( "title", "Only show tests and assertons that fail. Stored in sessionStorage." );
- label.innerHTML = "Hide passed tests";
- toolbar.appendChild( label );
-
- urlConfigCheckboxesContainer = document.createElement("span");
- urlConfigCheckboxesContainer.innerHTML = urlConfigHtml;
- urlConfigCheckboxes = urlConfigCheckboxesContainer.getElementsByTagName("input");
- // For oldIE support:
- // * Add handlers to the individual elements instead of the container
- // * Use "click" instead of "change"
- // * Fallback from event.target to event.srcElement
- addEvents( urlConfigCheckboxes, "click", function( event ) {
- var params = {},
- target = event.target || event.srcElement;
- params[ target.name ] = target.checked ? true : undefined;
- window.location = QUnit.url( params );
- });
- toolbar.appendChild( urlConfigCheckboxesContainer );
-
- if (numModules > 1) {
- moduleFilter = document.createElement( 'span' );
- moduleFilter.setAttribute( 'id', 'qunit-modulefilter-container' );
- moduleFilter.innerHTML = moduleFilterHtml;
- addEvent( moduleFilter.lastChild, "change", function() {
- var selectBox = moduleFilter.getElementsByTagName("select")[0],
- selectedModule = decodeURIComponent(selectBox.options[selectBox.selectedIndex].value);
-
- window.location = QUnit.url( { module: ( selectedModule === "" ) ? undefined : selectedModule } );
- });
- toolbar.appendChild(moduleFilter);
- }
- }
-
- // `main` initialized at top of scope
- main = id( "qunit-fixture" );
- if ( main ) {
- config.fixture = main.innerHTML;
- }
-
- if ( config.autostart ) {
- QUnit.start();
- }
-};
-
-addEvent( window, "load", QUnit.load );
-
-// `onErrorFnPrev` initialized at top of scope
-// Preserve other handlers
-onErrorFnPrev = window.onerror;
-
-// Cover uncaught exceptions
-// Returning true will surpress the default browser handler,
-// returning false will let it run.
-window.onerror = function ( error, filePath, linerNr ) {
- var ret = false;
- if ( onErrorFnPrev ) {
- ret = onErrorFnPrev( error, filePath, linerNr );
- }
-
- // Treat return value as window.onerror itself does,
- // Only do our handling if not surpressed.
- if ( ret !== true ) {
- if ( QUnit.config.current ) {
- if ( QUnit.config.current.ignoreGlobalErrors ) {
- return true;
- }
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- } else {
- QUnit.test( "global failure", extend( function() {
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- }, { validTest: validTest } ) );
- }
- return false;
- }
-
- return ret;
-};
-
-function done() {
- config.autorun = true;
-
- // Log the last module results
- if ( config.currentModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.currentModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
-
- var i, key,
- banner = id( "qunit-banner" ),
- tests = id( "qunit-tests" ),
- runtime = +new Date() - config.started,
- passed = config.stats.all - config.stats.bad,
- html = [
- "Tests completed in ",
- runtime,
- " milliseconds.
",
- "",
- passed,
- " assertions of ",
- config.stats.all,
- " passed, ",
- config.stats.bad,
- " failed."
- ].join( "" );
-
- if ( banner ) {
- banner.className = ( config.stats.bad ? "qunit-fail" : "qunit-pass" );
- }
-
- if ( tests ) {
- id( "qunit-testresult" ).innerHTML = html;
- }
-
- if ( config.altertitle && typeof document !== "undefined" && document.title ) {
- // show ✖ for good, ✔ for bad suite result in title
- // use escape sequences in case file gets loaded with non-utf-8-charset
- document.title = [
- ( config.stats.bad ? "\u2716" : "\u2714" ),
- document.title.replace( /^[\u2714\u2716] /i, "" )
- ].join( " " );
- }
-
- // clear own sessionStorage items if all tests passed
- if ( config.reorder && defined.sessionStorage && config.stats.bad === 0 ) {
- // `key` & `i` initialized at top of scope
- for ( i = 0; i < sessionStorage.length; i++ ) {
- key = sessionStorage.key( i++ );
- if ( key.indexOf( "qunit-test-" ) === 0 ) {
- sessionStorage.removeItem( key );
- }
- }
- }
-
- // scroll back to top to show results
- if ( window.scrollTo ) {
- window.scrollTo(0, 0);
- }
-
- runLoggingCallbacks( "done", QUnit, {
- failed: config.stats.bad,
- passed: passed,
- total: config.stats.all,
- runtime: runtime
- });
-}
-
-/** @return Boolean: true if this test should be ran */
-function validTest( test ) {
- var include,
- filter = config.filter && config.filter.toLowerCase(),
- module = config.module && config.module.toLowerCase(),
- fullName = (test.module + ": " + test.testName).toLowerCase();
-
- // Internally-generated tests are always valid
- if ( test.callback && test.callback.validTest === validTest ) {
- delete test.callback.validTest;
- return true;
- }
-
- if ( config.testNumber ) {
- return test.testNumber === config.testNumber;
- }
-
- if ( module && ( !test.module || test.module.toLowerCase() !== module ) ) {
- return false;
- }
-
- if ( !filter ) {
- return true;
- }
-
- include = filter.charAt( 0 ) !== "!";
- if ( !include ) {
- filter = filter.slice( 1 );
- }
-
- // If the filter matches, we need to honour include
- if ( fullName.indexOf( filter ) !== -1 ) {
- return include;
- }
-
- // Otherwise, do the opposite
- return !include;
-}
-
-// so far supports only Firefox, Chrome and Opera (buggy), Safari (for real exceptions)
-// Later Safari and IE10 are supposed to support error.stack as well
-// See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack
-function extractStacktrace( e, offset ) {
- offset = offset === undefined ? 3 : offset;
-
- var stack, include, i;
-
- if ( e.stacktrace ) {
- // Opera
- return e.stacktrace.split( "\n" )[ offset + 3 ];
- } else if ( e.stack ) {
- // Firefox, Chrome
- stack = e.stack.split( "\n" );
- if (/^error$/i.test( stack[0] ) ) {
- stack.shift();
- }
- if ( fileName ) {
- include = [];
- for ( i = offset; i < stack.length; i++ ) {
- if ( stack[ i ].indexOf( fileName ) !== -1 ) {
- break;
- }
- include.push( stack[ i ] );
- }
- if ( include.length ) {
- return include.join( "\n" );
- }
- }
- return stack[ offset ];
- } else if ( e.sourceURL ) {
- // Safari, PhantomJS
- // hopefully one day Safari provides actual stacktraces
- // exclude useless self-reference for generated Error objects
- if ( /qunit.js$/.test( e.sourceURL ) ) {
- return;
- }
- // for actual exceptions, this is useful
- return e.sourceURL + ":" + e.line;
- }
-}
-function sourceFromStacktrace( offset ) {
- try {
- throw new Error();
- } catch ( e ) {
- return extractStacktrace( e, offset );
- }
-}
-
-/**
- * Escape text for attribute or text content.
- */
-function escapeText( s ) {
- if ( !s ) {
- return "";
- }
- s = s + "";
- // Both single quotes and double quotes (for attributes)
- return s.replace( /['"<>&]/g, function( s ) {
- switch( s ) {
- case '\'':
- return ''';
- case '"':
- return '"';
- case '<':
- return '<';
- case '>':
- return '>';
- case '&':
- return '&';
- }
- });
-}
-
-function synchronize( callback, last ) {
- config.queue.push( callback );
-
- if ( config.autorun && !config.blocking ) {
- process( last );
- }
-}
-
-function process( last ) {
- function next() {
- process( last );
- }
- var start = new Date().getTime();
- config.depth = config.depth ? config.depth + 1 : 1;
-
- while ( config.queue.length && !config.blocking ) {
- if ( !defined.setTimeout || config.updateRate <= 0 || ( ( new Date().getTime() - start ) < config.updateRate ) ) {
- config.queue.shift()();
- } else {
- window.setTimeout( next, 13 );
- break;
- }
- }
- config.depth--;
- if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) {
- done();
- }
-}
-
-function saveGlobal() {
- config.pollution = [];
-
- if ( config.noglobals ) {
- for ( var key in window ) {
- // in Opera sometimes DOM element ids show up here, ignore them
- if ( !hasOwn.call( window, key ) || /^qunit-test-output/.test( key ) ) {
- continue;
- }
- config.pollution.push( key );
- }
- }
-}
-
-function checkPollution() {
- var newGlobals,
- deletedGlobals,
- old = config.pollution;
-
- saveGlobal();
-
- newGlobals = diff( config.pollution, old );
- if ( newGlobals.length > 0 ) {
- QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join(", ") );
- }
-
- deletedGlobals = diff( old, config.pollution );
- if ( deletedGlobals.length > 0 ) {
- QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join(", ") );
- }
-}
-
-// returns a new Array with the elements that are in a but not in b
-function diff( a, b ) {
- var i, j,
- result = a.slice();
-
- for ( i = 0; i < result.length; i++ ) {
- for ( j = 0; j < b.length; j++ ) {
- if ( result[i] === b[j] ) {
- result.splice( i, 1 );
- i--;
- break;
- }
- }
- }
- return result;
-}
-
-function extend( a, b ) {
- for ( var prop in b ) {
- if ( b[ prop ] === undefined ) {
- delete a[ prop ];
-
- // Avoid "Member not found" error in IE8 caused by setting window.constructor
- } else if ( prop !== "constructor" || a !== window ) {
- a[ prop ] = b[ prop ];
- }
- }
-
- return a;
-}
-
-/**
- * @param {HTMLElement} elem
- * @param {string} type
- * @param {Function} fn
- */
-function addEvent( elem, type, fn ) {
- // Standards-based browsers
- if ( elem.addEventListener ) {
- elem.addEventListener( type, fn, false );
- // IE
- } else {
- elem.attachEvent( "on" + type, fn );
- }
-}
-
-/**
- * @param {Array|NodeList} elems
- * @param {string} type
- * @param {Function} fn
- */
-function addEvents( elems, type, fn ) {
- var i = elems.length;
- while ( i-- ) {
- addEvent( elems[i], type, fn );
- }
-}
-
-function hasClass( elem, name ) {
- return (" " + elem.className + " ").indexOf(" " + name + " ") > -1;
-}
-
-function addClass( elem, name ) {
- if ( !hasClass( elem, name ) ) {
- elem.className += (elem.className ? " " : "") + name;
- }
-}
-
-function removeClass( elem, name ) {
- var set = " " + elem.className + " ";
- // Class name may appear multiple times
- while ( set.indexOf(" " + name + " ") > -1 ) {
- set = set.replace(" " + name + " " , " ");
- }
- // If possible, trim it for prettiness, but not neccecarily
- elem.className = window.jQuery ? jQuery.trim( set ) : ( set.trim ? set.trim() : set );
-}
-
-function id( name ) {
- return !!( typeof document !== "undefined" && document && document.getElementById ) &&
- document.getElementById( name );
-}
-
-function registerLoggingCallback( key ) {
- return function( callback ) {
- config[key].push( callback );
- };
-}
-
-// Supports deprecated method of completely overwriting logging callbacks
-function runLoggingCallbacks( key, scope, args ) {
- var i, callbacks;
- if ( QUnit.hasOwnProperty( key ) ) {
- QUnit[ key ].call(scope, args );
- } else {
- callbacks = config[ key ];
- for ( i = 0; i < callbacks.length; i++ ) {
- callbacks[ i ].call( scope, args );
- }
- }
-}
-
-// Test for equality any JavaScript type.
-// Author: Philippe Rathé
-QUnit.equiv = (function() {
-
- // Call the o related callback with the given arguments.
- function bindCallbacks( o, callbacks, args ) {
- var prop = QUnit.objectType( o );
- if ( prop ) {
- if ( QUnit.objectType( callbacks[ prop ] ) === "function" ) {
- return callbacks[ prop ].apply( callbacks, args );
- } else {
- return callbacks[ prop ]; // or undefined
- }
- }
- }
-
- // the real equiv function
- var innerEquiv,
- // stack to decide between skip/abort functions
- callers = [],
- // stack to avoiding loops from circular referencing
- parents = [],
-
- getProto = Object.getPrototypeOf || function ( obj ) {
- return obj.__proto__;
- },
- callbacks = (function () {
-
- // for string, boolean, number and null
- function useStrictEquality( b, a ) {
- /*jshint eqeqeq:false */
- if ( b instanceof a.constructor || a instanceof b.constructor ) {
- // to catch short annotaion VS 'new' annotation of a
- // declaration
- // e.g. var i = 1;
- // var j = new Number(1);
- return a == b;
- } else {
- return a === b;
- }
- }
-
- return {
- "string": useStrictEquality,
- "boolean": useStrictEquality,
- "number": useStrictEquality,
- "null": useStrictEquality,
- "undefined": useStrictEquality,
-
- "nan": function( b ) {
- return isNaN( b );
- },
-
- "date": function( b, a ) {
- return QUnit.objectType( b ) === "date" && a.valueOf() === b.valueOf();
- },
-
- "regexp": function( b, a ) {
- return QUnit.objectType( b ) === "regexp" &&
- // the regex itself
- a.source === b.source &&
- // and its modifers
- a.global === b.global &&
- // (gmi) ...
- a.ignoreCase === b.ignoreCase &&
- a.multiline === b.multiline &&
- a.sticky === b.sticky;
- },
-
- // - skip when the property is a method of an instance (OOP)
- // - abort otherwise,
- // initial === would have catch identical references anyway
- "function": function() {
- var caller = callers[callers.length - 1];
- return caller !== Object && typeof caller !== "undefined";
- },
-
- "array": function( b, a ) {
- var i, j, len, loop;
-
- // b could be an object literal here
- if ( QUnit.objectType( b ) !== "array" ) {
- return false;
- }
-
- len = a.length;
- if ( len !== b.length ) {
- // safe and faster
- return false;
- }
-
- // track reference to avoid circular references
- parents.push( a );
- for ( i = 0; i < len; i++ ) {
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- loop = true;// dont rewalk array
- }
- }
- if ( !loop && !innerEquiv(a[i], b[i]) ) {
- parents.pop();
- return false;
- }
- }
- parents.pop();
- return true;
- },
-
- "object": function( b, a ) {
- var i, j, loop,
- // Default to true
- eq = true,
- aProperties = [],
- bProperties = [];
-
- // comparing constructors is more strict than using
- // instanceof
- if ( a.constructor !== b.constructor ) {
- // Allow objects with no prototype to be equivalent to
- // objects with Object as their constructor.
- if ( !(( getProto(a) === null && getProto(b) === Object.prototype ) ||
- ( getProto(b) === null && getProto(a) === Object.prototype ) ) ) {
- return false;
- }
- }
-
- // stack constructor before traversing properties
- callers.push( a.constructor );
- // track reference to avoid circular references
- parents.push( a );
-
- for ( i in a ) { // be strict: don't ensures hasOwnProperty
- // and go deep
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- // don't go down the same path twice
- loop = true;
- }
- }
- aProperties.push(i); // collect a's properties
-
- if (!loop && !innerEquiv( a[i], b[i] ) ) {
- eq = false;
- break;
- }
- }
-
- callers.pop(); // unstack, we are done
- parents.pop();
-
- for ( i in b ) {
- bProperties.push( i ); // collect b's properties
- }
-
- // Ensures identical properties name
- return eq && innerEquiv( aProperties.sort(), bProperties.sort() );
- }
- };
- }());
-
- innerEquiv = function() { // can take multiple arguments
- var args = [].slice.apply( arguments );
- if ( args.length < 2 ) {
- return true; // end transition
- }
-
- return (function( a, b ) {
- if ( a === b ) {
- return true; // catch the most you can
- } else if ( a === null || b === null || typeof a === "undefined" ||
- typeof b === "undefined" ||
- QUnit.objectType(a) !== QUnit.objectType(b) ) {
- return false; // don't lose time with error prone cases
- } else {
- return bindCallbacks(a, callbacks, [ b, a ]);
- }
-
- // apply transition with (1..n) arguments
- }( args[0], args[1] ) && arguments.callee.apply( this, args.splice(1, args.length - 1 )) );
- };
-
- return innerEquiv;
-}());
-
-/**
- * jsDump Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com |
- * http://flesler.blogspot.com Licensed under BSD
- * (http://www.opensource.org/licenses/bsd-license.php) Date: 5/15/2008
- *
- * @projectDescription Advanced and extensible data dumping for Javascript.
- * @version 1.0.0
- * @author Ariel Flesler
- * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html}
- */
-QUnit.jsDump = (function() {
- function quote( str ) {
- return '"' + str.toString().replace( /"/g, '\\"' ) + '"';
- }
- function literal( o ) {
- return o + "";
- }
- function join( pre, arr, post ) {
- var s = jsDump.separator(),
- base = jsDump.indent(),
- inner = jsDump.indent(1);
- if ( arr.join ) {
- arr = arr.join( "," + s + inner );
- }
- if ( !arr ) {
- return pre + post;
- }
- return [ pre, inner + arr, base + post ].join(s);
- }
- function array( arr, stack ) {
- var i = arr.length, ret = new Array(i);
- this.up();
- while ( i-- ) {
- ret[i] = this.parse( arr[i] , undefined , stack);
- }
- this.down();
- return join( "[", ret, "]" );
- }
-
- var reName = /^function (\w+)/,
- jsDump = {
- // type is used mostly internally, you can fix a (custom)type in advance
- parse: function( obj, type, stack ) {
- stack = stack || [ ];
- var inStack, res,
- parser = this.parsers[ type || this.typeOf(obj) ];
-
- type = typeof parser;
- inStack = inArray( obj, stack );
-
- if ( inStack !== -1 ) {
- return "recursion(" + (inStack - stack.length) + ")";
- }
- if ( type === "function" ) {
- stack.push( obj );
- res = parser.call( this, obj, stack );
- stack.pop();
- return res;
- }
- return ( type === "string" ) ? parser : this.parsers.error;
- },
- typeOf: function( obj ) {
- var type;
- if ( obj === null ) {
- type = "null";
- } else if ( typeof obj === "undefined" ) {
- type = "undefined";
- } else if ( QUnit.is( "regexp", obj) ) {
- type = "regexp";
- } else if ( QUnit.is( "date", obj) ) {
- type = "date";
- } else if ( QUnit.is( "function", obj) ) {
- type = "function";
- } else if ( typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined" ) {
- type = "window";
- } else if ( obj.nodeType === 9 ) {
- type = "document";
- } else if ( obj.nodeType ) {
- type = "node";
- } else if (
- // native arrays
- toString.call( obj ) === "[object Array]" ||
- // NodeList objects
- ( typeof obj.length === "number" && typeof obj.item !== "undefined" && ( obj.length ? obj.item(0) === obj[0] : ( obj.item( 0 ) === null && typeof obj[0] === "undefined" ) ) )
- ) {
- type = "array";
- } else if ( obj.constructor === Error.prototype.constructor ) {
- type = "error";
- } else {
- type = typeof obj;
- }
- return type;
- },
- separator: function() {
- return this.multiline ? this.HTML ? "
" : "\n" : this.HTML ? " " : " ";
- },
- // extra can be a number, shortcut for increasing-calling-decreasing
- indent: function( extra ) {
- if ( !this.multiline ) {
- return "";
- }
- var chr = this.indentChar;
- if ( this.HTML ) {
- chr = chr.replace( /\t/g, " " ).replace( / /g, " " );
- }
- return new Array( this._depth_ + (extra||0) ).join(chr);
- },
- up: function( a ) {
- this._depth_ += a || 1;
- },
- down: function( a ) {
- this._depth_ -= a || 1;
- },
- setParser: function( name, parser ) {
- this.parsers[name] = parser;
- },
- // The next 3 are exposed so you can use them
- quote: quote,
- literal: literal,
- join: join,
- //
- _depth_: 1,
- // This is the list of parsers, to modify them, use jsDump.setParser
- parsers: {
- window: "[Window]",
- document: "[Document]",
- error: function(error) {
- return "Error(\"" + error.message + "\")";
- },
- unknown: "[Unknown]",
- "null": "null",
- "undefined": "undefined",
- "function": function( fn ) {
- var ret = "function",
- // functions never have name in IE
- name = "name" in fn ? fn.name : (reName.exec(fn) || [])[1];
-
- if ( name ) {
- ret += " " + name;
- }
- ret += "( ";
-
- ret = [ ret, QUnit.jsDump.parse( fn, "functionArgs" ), "){" ].join( "" );
- return join( ret, QUnit.jsDump.parse(fn,"functionCode" ), "}" );
- },
- array: array,
- nodelist: array,
- "arguments": array,
- object: function( map, stack ) {
- var ret = [ ], keys, key, val, i;
- QUnit.jsDump.up();
- keys = [];
- for ( key in map ) {
- keys.push( key );
- }
- keys.sort();
- for ( i = 0; i < keys.length; i++ ) {
- key = keys[ i ];
- val = map[ key ];
- ret.push( QUnit.jsDump.parse( key, "key" ) + ": " + QUnit.jsDump.parse( val, undefined, stack ) );
- }
- QUnit.jsDump.down();
- return join( "{", ret, "}" );
- },
- node: function( node ) {
- var len, i, val,
- open = QUnit.jsDump.HTML ? "<" : "<",
- close = QUnit.jsDump.HTML ? ">" : ">",
- tag = node.nodeName.toLowerCase(),
- ret = open + tag,
- attrs = node.attributes;
-
- if ( attrs ) {
- for ( i = 0, len = attrs.length; i < len; i++ ) {
- val = attrs[i].nodeValue;
- // IE6 includes all attributes in .attributes, even ones not explicitly set.
- // Those have values like undefined, null, 0, false, "" or "inherit".
- if ( val && val !== "inherit" ) {
- ret += " " + attrs[i].nodeName + "=" + QUnit.jsDump.parse( val, "attribute" );
- }
- }
- }
- ret += close;
-
- // Show content of TextNode or CDATASection
- if ( node.nodeType === 3 || node.nodeType === 4 ) {
- ret += node.nodeValue;
- }
-
- return ret + open + "/" + tag + close;
- },
- // function calls it internally, it's the arguments part of the function
- functionArgs: function( fn ) {
- var args,
- l = fn.length;
-
- if ( !l ) {
- return "";
- }
-
- args = new Array(l);
- while ( l-- ) {
- // 97 is 'a'
- args[l] = String.fromCharCode(97+l);
- }
- return " " + args.join( ", " ) + " ";
- },
- // object calls it internally, the key part of an item in a map
- key: quote,
- // function calls it internally, it's the content of the function
- functionCode: "[code]",
- // node calls it internally, it's an html attribute value
- attribute: quote,
- string: quote,
- date: quote,
- regexp: literal,
- number: literal,
- "boolean": literal
- },
- // if true, entities are escaped ( <, >, \t, space and \n )
- HTML: false,
- // indentation unit
- indentChar: " ",
- // if true, items in a collection, are separated by a \n, else just a space.
- multiline: true
- };
-
- return jsDump;
-}());
-
-// from jquery.js
-function inArray( elem, array ) {
- if ( array.indexOf ) {
- return array.indexOf( elem );
- }
-
- for ( var i = 0, length = array.length; i < length; i++ ) {
- if ( array[ i ] === elem ) {
- return i;
- }
- }
-
- return -1;
-}
-
-/*
- * Javascript Diff Algorithm
- * By John Resig (http://ejohn.org/)
- * Modified by Chu Alan "sprite"
- *
- * Released under the MIT license.
- *
- * More Info:
- * http://ejohn.org/projects/javascript-diff-algorithm/
- *
- * Usage: QUnit.diff(expected, actual)
- *
- * QUnit.diff( "the quick brown fox jumped over", "the quick fox jumps over" ) == "the quick brown fox jumped jumps over"
- */
-QUnit.diff = (function() {
- /*jshint eqeqeq:false, eqnull:true */
- function diff( o, n ) {
- var i,
- ns = {},
- os = {};
-
- for ( i = 0; i < n.length; i++ ) {
- if ( !hasOwn.call( ns, n[i] ) ) {
- ns[ n[i] ] = {
- rows: [],
- o: null
- };
- }
- ns[ n[i] ].rows.push( i );
- }
-
- for ( i = 0; i < o.length; i++ ) {
- if ( !hasOwn.call( os, o[i] ) ) {
- os[ o[i] ] = {
- rows: [],
- n: null
- };
- }
- os[ o[i] ].rows.push( i );
- }
-
- for ( i in ns ) {
- if ( !hasOwn.call( ns, i ) ) {
- continue;
- }
- if ( ns[i].rows.length === 1 && hasOwn.call( os, i ) && os[i].rows.length === 1 ) {
- n[ ns[i].rows[0] ] = {
- text: n[ ns[i].rows[0] ],
- row: os[i].rows[0]
- };
- o[ os[i].rows[0] ] = {
- text: o[ os[i].rows[0] ],
- row: ns[i].rows[0]
- };
- }
- }
-
- for ( i = 0; i < n.length - 1; i++ ) {
- if ( n[i].text != null && n[ i + 1 ].text == null && n[i].row + 1 < o.length && o[ n[i].row + 1 ].text == null &&
- n[ i + 1 ] == o[ n[i].row + 1 ] ) {
-
- n[ i + 1 ] = {
- text: n[ i + 1 ],
- row: n[i].row + 1
- };
- o[ n[i].row + 1 ] = {
- text: o[ n[i].row + 1 ],
- row: i + 1
- };
- }
- }
-
- for ( i = n.length - 1; i > 0; i-- ) {
- if ( n[i].text != null && n[ i - 1 ].text == null && n[i].row > 0 && o[ n[i].row - 1 ].text == null &&
- n[ i - 1 ] == o[ n[i].row - 1 ]) {
-
- n[ i - 1 ] = {
- text: n[ i - 1 ],
- row: n[i].row - 1
- };
- o[ n[i].row - 1 ] = {
- text: o[ n[i].row - 1 ],
- row: i - 1
- };
- }
- }
-
- return {
- o: o,
- n: n
- };
- }
-
- return function( o, n ) {
- o = o.replace( /\s+$/, "" );
- n = n.replace( /\s+$/, "" );
-
- var i, pre,
- str = "",
- out = diff( o === "" ? [] : o.split(/\s+/), n === "" ? [] : n.split(/\s+/) ),
- oSpace = o.match(/\s+/g),
- nSpace = n.match(/\s+/g);
-
- if ( oSpace == null ) {
- oSpace = [ " " ];
- }
- else {
- oSpace.push( " " );
- }
-
- if ( nSpace == null ) {
- nSpace = [ " " ];
- }
- else {
- nSpace.push( " " );
- }
-
- if ( out.n.length === 0 ) {
- for ( i = 0; i < out.o.length; i++ ) {
- str += "" + out.o[i] + oSpace[i] + "";
- }
- }
- else {
- if ( out.n[0].text == null ) {
- for ( n = 0; n < out.o.length && out.o[n].text == null; n++ ) {
- str += "" + out.o[n] + oSpace[n] + "";
- }
- }
-
- for ( i = 0; i < out.n.length; i++ ) {
- if (out.n[i].text == null) {
- str += "" + out.n[i] + nSpace[i] + "";
- }
- else {
- // `pre` initialized at top of scope
- pre = "";
-
- for ( n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++ ) {
- pre += "" + out.o[n] + oSpace[n] + "";
- }
- str += " " + out.n[i].text + nSpace[i] + pre;
- }
- }
- }
-
- return str;
- };
-}());
-
-// for CommonJS enviroments, export everything
-if ( typeof exports !== "undefined" ) {
- extend( exports, QUnit );
-}
-
-// get at whatever the global object is, like window in browsers
-}( (function() {return this;}.call()) ));
diff --git a/test/lib/require.js b/test/lib/require.js
deleted file mode 100644
index 987f865..0000000
--- a/test/lib/require.js
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- RequireJS 2.1.5 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.
- Available via the MIT or new BSD license.
- see: http://github.com/jrburke/requirejs for details
-*/
-var requirejs,require,define;
-(function(aa){function I(b){return"[object Function]"===L.call(b)}function J(b){return"[object Array]"===L.call(b)}function y(b,c){if(b){var d;for(d=0;dthis.depCount&&!this.defined){if(I(n)){if(this.events.error)try{e=i.execCb(c,n,b,e)}catch(d){a=d}else e=i.execCb(c,n,b,e);this.map.isDefine&&((b=this.module)&&void 0!==b.exports&&b.exports!==this.exports?e=b.exports:void 0===e&&this.usingExports&&(e=this.exports));if(a)return a.requireMap=this.map,a.requireModules=[this.map.id],a.requireType="define",v(this.error=
-a)}else e=n;this.exports=e;if(this.map.isDefine&&!this.ignore&&(q[c]=e,l.onResourceLoad))l.onResourceLoad(i,this.map,this.depMaps);x(c);this.defined=!0}this.defining=!1;this.defined&&!this.defineEmitted&&(this.defineEmitted=!0,this.emit("defined",this.exports),this.defineEmitComplete=!0)}}else this.fetch()}},callPlugin:function(){var a=this.map,b=a.id,d=j(a.prefix);this.depMaps.push(d);t(d,"defined",u(this,function(e){var n,d;d=this.map.name;var g=this.map.parentMap?this.map.parentMap.name:null,h=
-i.makeRequire(a.parentMap,{enableBuildCallback:!0});if(this.map.unnormalized){if(e.normalize&&(d=e.normalize(d,function(a){return c(a,g,!0)})||""),e=j(a.prefix+"!"+d,this.map.parentMap),t(e,"defined",u(this,function(a){this.init([],function(){return a},null,{enabled:!0,ignore:!0})})),d=m(p,e.id)){this.depMaps.push(e);if(this.events.error)d.on("error",u(this,function(a){this.emit("error",a)}));d.enable()}}else n=u(this,function(a){this.init([],function(){return a},null,{enabled:!0})}),n.error=u(this,
-function(a){this.inited=!0;this.error=a;a.requireModules=[b];G(p,function(a){0===a.map.id.indexOf(b+"_unnormalized")&&x(a.map.id)});v(a)}),n.fromText=u(this,function(e,c){var d=a.name,g=j(d),C=O;c&&(e=c);C&&(O=!1);r(g);s(k.config,b)&&(k.config[d]=k.config[b]);try{l.exec(e)}catch(ca){return v(B("fromtexteval","fromText eval for "+b+" failed: "+ca,ca,[b]))}C&&(O=!0);this.depMaps.push(g);i.completeLoad(d);h([d],n)}),e.load(a.name,h,n,k)}));i.enable(d,this);this.pluginMaps[d.id]=d},enable:function(){V[this.map.id]=
-this;this.enabling=this.enabled=!0;y(this.depMaps,u(this,function(a,b){var c,e;if("string"===typeof a){a=j(a,this.map.isDefine?this.map:this.map.parentMap,!1,!this.skipMap);this.depMaps[b]=a;if(c=m(N,a.id)){this.depExports[b]=c(this);return}this.depCount+=1;t(a,"defined",u(this,function(a){this.defineDep(b,a);this.check()}));this.errback&&t(a,"error",this.errback)}c=a.id;e=p[c];!s(N,c)&&(e&&!e.enabled)&&i.enable(a,this)}));G(this.pluginMaps,u(this,function(a){var b=m(p,a.id);b&&!b.enabled&&i.enable(a,
-this)}));this.enabling=!1;this.check()},on:function(a,b){var c=this.events[a];c||(c=this.events[a]=[]);c.push(b)},emit:function(a,b){y(this.events[a],function(a){a(b)});"error"===a&&delete this.events[a]}};i={config:k,contextName:b,registry:p,defined:q,urlFetched:U,defQueue:H,Module:Z,makeModuleMap:j,nextTick:l.nextTick,onError:v,configure:function(a){a.baseUrl&&"/"!==a.baseUrl.charAt(a.baseUrl.length-1)&&(a.baseUrl+="/");var b=k.pkgs,c=k.shim,e={paths:!0,config:!0,map:!0};G(a,function(a,b){e[b]?
-"map"===b?(k.map||(k.map={}),R(k[b],a,!0,!0)):R(k[b],a,!0):k[b]=a});a.shim&&(G(a.shim,function(a,b){J(a)&&(a={deps:a});if((a.exports||a.init)&&!a.exportsFn)a.exportsFn=i.makeShimExports(a);c[b]=a}),k.shim=c);a.packages&&(y(a.packages,function(a){a="string"===typeof a?{name:a}:a;b[a.name]={name:a.name,location:a.location||a.name,main:(a.main||"main").replace(ja,"").replace(ea,"")}}),k.pkgs=b);G(p,function(a,b){!a.inited&&!a.map.unnormalized&&(a.map=j(b))});if(a.deps||a.callback)i.require(a.deps||[],
-a.callback)},makeShimExports:function(a){return function(){var b;a.init&&(b=a.init.apply(aa,arguments));return b||a.exports&&ba(a.exports)}},makeRequire:function(a,f){function d(e,c,h){var g,k;f.enableBuildCallback&&(c&&I(c))&&(c.__requireJsBuild=!0);if("string"===typeof e){if(I(c))return v(B("requireargs","Invalid require call"),h);if(a&&s(N,e))return N[e](p[a.id]);if(l.get)return l.get(i,e,a,d);g=j(e,a,!1,!0);g=g.id;return!s(q,g)?v(B("notloaded",'Module name "'+g+'" has not been loaded yet for context: '+
-b+(a?"":". Use require([])"))):q[g]}L();i.nextTick(function(){L();k=r(j(null,a));k.skipMap=f.skipMap;k.init(e,c,h,{enabled:!0});D()});return d}f=f||{};R(d,{isBrowser:A,toUrl:function(b){var d,f=b.lastIndexOf("."),g=b.split("/")[0];if(-1!==f&&(!("."===g||".."===g)||1h.attachEvent.toString().indexOf("[native code"))&&!Y?(O=!0,h.attachEvent("onreadystatechange",b.onScriptLoad)):(h.addEventListener("load",b.onScriptLoad,!1),h.addEventListener("error",b.onScriptError,!1)),h.src=d,K=h,D?x.insertBefore(h,D):x.appendChild(h),K=null,h;if(da)try{importScripts(d),b.completeLoad(c)}catch(j){b.onError(B("importscripts","importScripts failed for "+c+" at "+d,j,[c]))}};A&&M(document.getElementsByTagName("script"),function(b){x||(x=
-b.parentNode);if(t=b.getAttribute("data-main"))return r.baseUrl||(E=t.split("/"),Q=E.pop(),fa=E.length?E.join("/")+"/":"./",r.baseUrl=fa,t=Q),t=t.replace(ea,""),r.deps=r.deps?r.deps.concat(t):[t],!0});define=function(b,c,d){var l,h;"string"!==typeof b&&(d=c,c=b,b=null);J(c)||(d=c,c=[]);!c.length&&I(d)&&d.length&&(d.toString().replace(la,"").replace(ma,function(b,d){c.push(d)}),c=(1===d.length?["require"]:["require","exports","module"]).concat(c));if(O){if(!(l=K))P&&"interactive"===P.readyState||M(document.getElementsByTagName("script"),
-function(b){if("interactive"===b.readyState)return P=b}),l=P;l&&(b||(b=l.getAttribute("data-requiremodule")),h=F[l.getAttribute("data-requirecontext")])}(h?h.defQueue:T).push([b,c,d])};define.amd={jQuery:!0};l.exec=function(b){return eval(b)};l(r)}})(this);
diff --git a/test/lib/resemble.js b/test/lib/resemble.js
new file mode 100644
index 0000000..1cb8c29
--- /dev/null
+++ b/test/lib/resemble.js
@@ -0,0 +1,535 @@
+/*
+Author: James Cryer
+Company: Huddle
+Last updated date: 21 Feb 2013
+URL: https://github.com/Huddle/Resemble.js
+*/
+
+(function(_this){
+ 'use strict';
+
+ _this['resemble'] = function( fileData ){
+
+ var data = {};
+ var images = [];
+ var updateCallbackArray = [];
+
+ var tolerance = { // between 0 and 255
+ red: 16,
+ green: 16,
+ blue: 16,
+ minBrightness: 16,
+ maxBrightness: 240
+ };
+
+ var ignoreAntialiasing = false;
+ var ignoreColors = false;
+
+ function triggerDataUpdate(){
+ var len = updateCallbackArray.length;
+ var i;
+ for(i=0;i tolerance.maxBrightness;
+ }
+
+ function getHue(r,g,b){
+
+ r = r / 255;
+ g = g / 255;
+ b = b / 255;
+ var max = Math.max(r, g, b), min = Math.min(r, g, b);
+ var h;
+ var d;
+
+ if (max == min){
+ h = 0; // achromatic
+ } else{
+ d = max - min;
+ switch(max){
+ case r: h = (g - b) / d + (g < b ? 6 : 0); break;
+ case g: h = (b - r) / d + 2; break;
+ case b: h = (r - g) / d + 4; break;
+ }
+ h /= 6;
+ }
+
+ return h;
+ }
+
+ function isAntialiased(sourcePix, data, cacheSet, verticalPos, horizontalPos, width){
+ var offset;
+ var targetPix;
+ var distance = 1;
+ var i;
+ var j;
+ var hasHighContrastSibling = 0;
+ var hasSiblingWithDifferentHue = 0;
+ var hasEquivilantSibling = 0;
+
+ addHueInfo(sourcePix);
+
+ for (i = distance*-1; i <= distance; i++){
+ for (j = distance*-1; j <= distance; j++){
+
+ if(i===0 && j===0){
+ // ignore source pixel
+ } else {
+
+ offset = ((verticalPos+j)*width + (horizontalPos+i)) * 4;
+ targetPix = getPixelInfo(data, offset, cacheSet);
+
+ if(targetPix === null){
+ continue;
+ }
+
+ addBrightnessInfo(targetPix);
+ addHueInfo(targetPix);
+
+ if( isContrasting(sourcePix, targetPix) ){
+ hasHighContrastSibling++;
+ }
+
+ if( isRGBSame(sourcePix,targetPix) ){
+ hasEquivilantSibling++;
+ }
+
+ if( Math.abs(targetPix.h - sourcePix.h) > 0.3 ){
+ hasSiblingWithDifferentHue++;
+ }
+
+ if( hasSiblingWithDifferentHue > 1 || hasHighContrastSibling > 1){
+ return true;
+ }
+ }
+ }
+ }
+
+ if(hasEquivilantSibling < 2){
+ return true;
+ }
+
+ return false;
+ }
+
+ function errorPixel(px, offset){
+ px[offset] = 255; //r
+ px[offset + 1] = 0; //g
+ px[offset + 2] = 255; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyPixel(px, offset, data){
+ px[offset] = data.r; //r
+ px[offset + 1] = data.g; //g
+ px[offset + 2] = data.b; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyGrayScalePixel(px, offset, data){
+ px[offset] = data.brightness; //r
+ px[offset + 1] = data.brightness; //g
+ px[offset + 2] = data.brightness; //b
+ px[offset + 3] = 255; //a
+ }
+
+
+ function getPixelInfo(data, offset, cacheSet){
+ var r;
+ var g;
+ var b;
+ var d;
+
+ if(typeof data[offset] !== 'undefined'){
+ r = data[offset];
+ g = data[offset+1];
+ b = data[offset+2];
+ d = {
+ r: r,
+ g: g,
+ b: b
+ };
+
+ return d;
+ } else {
+ return null;
+ }
+ }
+
+ function addBrightnessInfo(data){
+ data.brightness = getBrightness(data.r,data.g,data.b); // 'corrected' lightness
+ }
+
+ function addHueInfo(data){
+ data.h = getHue(data.r,data.g,data.b);
+ }
+
+ function analyseImages(img1, img2, width, height){
+
+ var hiddenCanvas = document.createElement('canvas');
+
+ var data1 = img1.data;
+ var data2 = img2.data;
+
+ hiddenCanvas.width = width;
+ hiddenCanvas.height = height;
+
+ var context = hiddenCanvas.getContext('2d');
+ var imgd = context.createImageData(width,height);
+ var targetPix = imgd.data;
+
+ var mismatchCount = 0;
+
+ var time = Date.now();
+
+ var skip;
+
+ if( (width > 1200 || height > 1200) && ignoreAntialiasing){
+ skip = 6;
+ }
+
+ loop(height, width, function(verticalPos, horizontalPos){
+
+ if(skip){ // only skip if the image isn't small
+ if(verticalPos % skip === 0 || horizontalPos % skip === 0){
+ return;
+ }
+ }
+
+ var offset = (verticalPos*width + horizontalPos) * 4;
+ var pixel1 = getPixelInfo(data1, offset, 1);
+ var pixel2 = getPixelInfo(data2, offset, 2);
+
+ if(pixel1 === null || pixel2 === null){
+ return;
+ }
+
+ if (ignoreColors){
+
+ addBrightnessInfo(pixel1);
+ addBrightnessInfo(pixel2);
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ return;
+ }
+
+ if( isRGBSimilar(pixel1, pixel2) ){
+ copyPixel(targetPix, offset, pixel2);
+
+ } else if( ignoreAntialiasing && (
+ addBrightnessInfo(pixel1), // jit pixel info augmentation looks a little weird, sorry.
+ addBrightnessInfo(pixel2),
+ isAntialiased(pixel1, data1, 1, verticalPos, horizontalPos, width) ||
+ isAntialiased(pixel2, data2, 2, verticalPos, horizontalPos, width)
+ )){
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+
+ });
+
+ data.misMatchPercentage = (mismatchCount / (height*width) * 100).toFixed(2);
+ data.analysisTime = Date.now() - time;
+
+ data.getImageDataUrl = function(text){
+ var barHeight = 0;
+
+ if(text){
+ barHeight = addLabel(text,context,hiddenCanvas);
+ }
+
+ context.putImageData(imgd, 0, barHeight);
+
+ return hiddenCanvas.toDataURL("image/png");
+ };
+ }
+
+ function addLabel(text, context, hiddenCanvas){
+ var textPadding = 2;
+
+ context.font = '12px sans-serif';
+
+ var textWidth = context.measureText(text).width + textPadding*2;
+ var barHeight = 22;
+
+ if(textWidth > hiddenCanvas.width){
+ hiddenCanvas.width = textWidth;
+ }
+
+ hiddenCanvas.height += barHeight;
+
+ context.fillStyle = "#666";
+ context.fillRect(0,0,hiddenCanvas.width,barHeight -4);
+ context.fillStyle = "#fff";
+ context.fillRect(0,barHeight -4,hiddenCanvas.width, 4);
+
+ context.fillStyle = "#fff";
+ context.textBaseline = "top";
+ context.font = '12px sans-serif';
+ context.fillText(text, textPadding, 1);
+
+ return barHeight;
+ }
+
+ function normalise(img, w, h){
+ var c;
+ var context;
+
+ if(img.height < h || img.width < w){
+ c = document.createElement('canvas');
+ c.width = w;
+ c.height = h;
+ context = c.getContext('2d');
+ context.putImageData(img, 0, 0);
+ return context.getImageData(0, 0, w, h);
+ }
+
+ return img;
+ }
+
+ function compare(one, two){
+
+ function onceWeHaveBoth(){
+ var width;
+ var height;
+ if(images.length === 2){
+ width = images[0].width > images[1].width ? images[0].width : images[1].width;
+ height = images[0].height > images[1].height ? images[0].height : images[1].height;
+
+ if( (images[0].width === images[1].width) && (images[0].height === images[1].height) ){
+ data.isSameDimensions = true;
+ } else {
+ data.isSameDimensions = false;
+ }
+
+ analyseImages( normalise(images[0],width, height), normalise(images[1],width, height), width, height);
+
+ triggerDataUpdate();
+ }
+ }
+
+ images = [];
+ loadImageData(one, onceWeHaveBoth);
+ loadImageData(two, onceWeHaveBoth);
+ }
+
+ function getCompareApi(param){
+
+ var secondFileData,
+ hasMethod = typeof param === 'function';
+
+ if( !hasMethod ){
+ // assume it's file data
+ secondFileData = param;
+ }
+
+ var self = {
+ ignoreNothing: function(){
+
+ tolerance.red = 16;
+ tolerance.green = 16;
+ tolerance.blue = 16;
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreAntialiasing: function(){
+
+ tolerance.red = 32;
+ tolerance.green = 32;
+ tolerance.blue = 32;
+ tolerance.minBrightness = 64;
+ tolerance.maxBrightness = 96;
+
+ ignoreAntialiasing = true;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreColors: function(){
+
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = true;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ onComplete: function( callback ){
+
+ updateCallbackArray.push(callback);
+
+ var wrapper = function(){
+ compare(fileData, secondFileData);
+ };
+
+ wrapper();
+
+ return getCompareApi(wrapper);
+ }
+ };
+
+ return self;
+ }
+
+ return {
+ onComplete: function( callback ){
+ updateCallbackArray.push(callback);
+ loadImageData(fileData, function(imageData, width, height){
+ parseImage(imageData.data, width, height);
+ });
+ },
+ compareTo: function(secondFileData){
+ return getCompareApi(secondFileData);
+ }
+ };
+
+ };
+}(this));
\ No newline at end of file
diff --git a/test/testsuite.js b/test/testsuite.js
deleted file mode 100644
index b486acb..0000000
--- a/test/testsuite.js
+++ /dev/null
@@ -1,36 +0,0 @@
-requirejs.config({
- baseUrl: '/test/unit/'
-});
-
-define(function(require) {
- var testModules = [
- 'Pixi',
- 'Point',
- 'Rectangle',
- 'DisplayObject',
- 'DisplayObjectContainer',
- 'Sprite',
- 'MovieClip',
- 'InteractionManager',
- 'Stage',
- 'utils/Utils',
- 'utils/EventTarget',
- 'utils/Matrix',
- 'utils/Detector',
- 'renderers/WebGLShaders',
- 'renderers/WebGLRenderer',
- 'renderers/WebGLBatch',
- 'renderers/CanvasRenderer',
- 'extras/Strip',
- 'extras/Rope',
- 'textures/BaseTexture',
- 'textures/Texture',
- 'loaders/SpriteSheetLoader',
- 'loaders/AssetLoader'
- ];
-
- // Resolve all testModules and then start the Test Runner.
- require(testModules, function() {
- QUnit.start();
- });
-});
\ No newline at end of file
diff --git a/test/textures/SpriteSheet-Aliens.png b/test/textures/SpriteSheet-Aliens.png
new file mode 100644
index 0000000..210acb1
--- /dev/null
+++ b/test/textures/SpriteSheet-Aliens.png
Binary files differ
diff --git a/test/textures/SpriteSheet-Explosion.png b/test/textures/SpriteSheet-Explosion.png
new file mode 100755
index 0000000..79e1a69
--- /dev/null
+++ b/test/textures/SpriteSheet-Explosion.png
Binary files differ
diff --git a/test/textures/bunny.png b/test/textures/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/textures/bunny.png
Binary files differ
diff --git a/test/unit/DisplayObject.js b/test/unit/DisplayObject.js
deleted file mode 100644
index 5e7e72f..0000000
--- a/test/unit/DisplayObject.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObject');
-});
diff --git a/test/unit/DisplayObjectContainer.js b/test/unit/DisplayObjectContainer.js
deleted file mode 100644
index b323959..0000000
--- a/test/unit/DisplayObjectContainer.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObjectContainer');
-});
diff --git a/test/unit/InteractionManager.js b/test/unit/InteractionManager.js
deleted file mode 100644
index e751f52..0000000
--- a/test/unit/InteractionManager.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('InteractionManager');
-});
diff --git a/test/unit/MovieClip.js b/test/unit/MovieClip.js
deleted file mode 100644
index 37d9446..0000000
--- a/test/unit/MovieClip.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('MovieClip');
-});
diff --git a/test/unit/Pixi.js b/test/unit/Pixi.js
deleted file mode 100644
index 36eee73..0000000
--- a/test/unit/Pixi.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Pixi');
-});
diff --git a/test/unit/Point.js b/test/unit/Point.js
deleted file mode 100644
index 983ff6e..0000000
--- a/test/unit/Point.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Point');
-});
diff --git a/test/unit/Rectangle.js b/test/unit/Rectangle.js
deleted file mode 100644
index 3b439ba..0000000
--- a/test/unit/Rectangle.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Rectangle');
-});
diff --git a/test/unit/Sprite.js b/test/unit/Sprite.js
deleted file mode 100644
index ed4f596..0000000
--- a/test/unit/Sprite.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Sprite');
-});
diff --git a/test/unit/Stage.js b/test/unit/Stage.js
deleted file mode 100644
index 2d70291..0000000
--- a/test/unit/Stage.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Stage');
-});
diff --git a/test/unit/extras/Rope.js b/test/unit/extras/Rope.js
deleted file mode 100644
index 5606f14..0000000
--- a/test/unit/extras/Rope.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Rope');
-});
diff --git a/test/unit/extras/Strip.js b/test/unit/extras/Strip.js
deleted file mode 100644
index 0134d3a..0000000
--- a/test/unit/extras/Strip.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Strip');
-});
diff --git a/test/unit/loaders/AssetLoader.js b/test/unit/loaders/AssetLoader.js
deleted file mode 100644
index 13b8443..0000000
--- a/test/unit/loaders/AssetLoader.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('AssetLoader');
-});
diff --git a/test/unit/loaders/SpriteSheetLoader.js b/test/unit/loaders/SpriteSheetLoader.js
deleted file mode 100644
index 8bf0cb2..0000000
--- a/test/unit/loaders/SpriteSheetLoader.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('SpriteSheetLoader');
-});
diff --git a/test/unit/pixi/InteractionManager.js b/test/unit/pixi/InteractionManager.js
new file mode 100644
index 0000000..ed3001f
--- /dev/null
+++ b/test/unit/pixi/InteractionManager.js
@@ -0,0 +1,10 @@
+describe('pixi/InteractionManager', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var InteractionManager = PIXI.InteractionManager;
+
+ it('Module exists', function () {
+ expect(InteractionManager).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/Pixi.js b/test/unit/pixi/Pixi.js
new file mode 100644
index 0000000..27debc1
--- /dev/null
+++ b/test/unit/pixi/Pixi.js
@@ -0,0 +1,9 @@
+describe('pixi/Pixi', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+
+ it('Module exists', function () {
+ expect(global).to.have.property('PIXI').and.to.be.an('object');
+ });
+});
diff --git a/test/unit/pixi/core/Circle.js b/test/unit/pixi/core/Circle.js
new file mode 100644
index 0000000..93a4456
--- /dev/null
+++ b/test/unit/pixi/core/Circle.js
@@ -0,0 +1,22 @@
+describe('pixi/core/Circle', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Circle = PIXI.Circle;
+
+ it('Module exists', function () {
+ expect(Circle).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Circle();
+
+ expect(obj).to.be.an.instanceof(Circle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', 0);
+ expect(obj).to.have.property('y', 0);
+ expect(obj).to.have.property('radius', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Ellipse.js b/test/unit/pixi/core/Ellipse.js
new file mode 100644
index 0000000..026b56f
--- /dev/null
+++ b/test/unit/pixi/core/Ellipse.js
@@ -0,0 +1,24 @@
+describe('pixi/core/Ellipse', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Ellipse = PIXI.Ellipse;
+
+ it('Module exists', function () {
+ expect(Ellipse).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Ellipse();
+
+ expect(obj).to.be.an.instanceof(Ellipse);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+ expect(obj).to.respondTo('getBounds');
+
+ expect(obj).to.have.property('x', 0);
+ expect(obj).to.have.property('y', 0);
+ expect(obj).to.have.property('width', 0);
+ expect(obj).to.have.property('height', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Matrix.js b/test/unit/pixi/core/Matrix.js
new file mode 100644
index 0000000..b48989e
--- /dev/null
+++ b/test/unit/pixi/core/Matrix.js
@@ -0,0 +1,30 @@
+describe('pixi/core/Matrix', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var mat3 = PIXI.mat3;
+ var mat4 = PIXI.mat4;
+ var Matrix = PIXI.Matrix;
+
+ it('Ensure determineMatrixArrayType works', function () {
+ expect(Matrix).to.be.a('function');
+ });
+
+ it('mat3 exists', function () {
+ expect(mat3).to.be.an('object');
+ });
+
+ it('Confirm new mat3 matrix', function () {
+ var matrix = new mat3.create();
+ pixi_core_Matrix_confirmNewMat3(matrix);
+ });
+
+ it('mat3 exists', function () {
+ expect(mat4).to.be.an('object');
+ });
+
+ it('Confirm new mat4 matrix', function () {
+ var matrix = new mat4.create();
+ pixi_core_Matrix_confirmNewMat4(matrix);
+ });
+});
diff --git a/test/unit/pixi/core/Point.js b/test/unit/pixi/core/Point.js
new file mode 100644
index 0000000..c4d5163
--- /dev/null
+++ b/test/unit/pixi/core/Point.js
@@ -0,0 +1,15 @@
+describe('pixi/core/Point', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Point = PIXI.Point;
+
+ it('Module exists', function () {
+ expect(Point).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Point();
+ pixi_core_Point_confirm(obj, 0, 0);
+ });
+});
diff --git a/test/unit/pixi/core/Polygon.js b/test/unit/pixi/core/Polygon.js
new file mode 100644
index 0000000..dc8c918
--- /dev/null
+++ b/test/unit/pixi/core/Polygon.js
@@ -0,0 +1,20 @@
+describe('pixi/core/Polygon', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Polygon = PIXI.Polygon;
+
+ it('Module exists', function () {
+ expect(Polygon).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Polygon();
+
+ expect(obj).to.be.an.instanceof(Polygon);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.deep.property('points.length', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Rectangle.js b/test/unit/pixi/core/Rectangle.js
new file mode 100644
index 0000000..d43316e
--- /dev/null
+++ b/test/unit/pixi/core/Rectangle.js
@@ -0,0 +1,15 @@
+describe('pixi/core/Rectangle', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Rectangle = PIXI.Rectangle;
+
+ it('Module exists', function () {
+ expect(Rectangle).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var rect = new Rectangle();
+ pixi_core_Rectangle_confirm(rect, 0, 0, 0, 0);
+ });
+});
diff --git a/test/unit/pixi/display/DisplayObject.js b/test/unit/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..40c6fbc
--- /dev/null
+++ b/test/unit/pixi/display/DisplayObject.js
@@ -0,0 +1,21 @@
+describe('pixi/display/DisplayObject', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var DisplayObject = PIXI.DisplayObject;
+
+ it('Module exists', function () {
+ expect(DisplayObject).to.be.a('function');
+ expect(PIXI).to.have.property('visibleCount', 0);
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new DisplayObject();
+
+ pixi_display_DisplayObject_confirmNew(obj);
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', false);
+ expect(obj).to.have.property('stage', null);
+ });
+});
diff --git a/test/unit/pixi/display/DisplayObjectContainer.js b/test/unit/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..ce7f02f
--- /dev/null
+++ b/test/unit/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,20 @@
+describe('pixi/display/DisplayObjectContainer', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var DisplayObjectContainer = PIXI.DisplayObjectContainer;
+
+ it('Module exists', function () {
+ expect(DisplayObjectContainer).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new DisplayObjectContainer();
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', false);
+ expect(obj).to.have.property('stage', null);
+ });
+});
diff --git a/test/unit/pixi/display/MovieClip.js b/test/unit/pixi/display/MovieClip.js
new file mode 100644
index 0000000..f3c6c6a
--- /dev/null
+++ b/test/unit/pixi/display/MovieClip.js
@@ -0,0 +1,33 @@
+describe('pixi/display/MovieClip', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var MovieClip = PIXI.MovieClip;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(MovieClip).to.be.a('function');
+ });
+
+ it('Confirm new instance', function (done) {
+ var texture = Texture.fromImage('/base/test/textures/SpriteSheet-Explosion.png');
+ var obj = new MovieClip([texture]);
+
+ pixi_display_Sprite_confirmNew(obj, done);
+
+ expect(obj).to.be.an.instanceof(MovieClip);
+ expect(obj).to.respondTo('stop');
+ expect(obj).to.respondTo('play');
+ expect(obj).to.respondTo('gotoAndStop');
+ expect(obj).to.respondTo('gotoAndPlay');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('textures.length', 1);
+ expect(obj).to.have.deep.property('textures[0]', texture);
+ expect(obj).to.have.property('animationSpeed', 1);
+ expect(obj).to.have.property('loop', true);
+ expect(obj).to.have.property('onComplete', null);
+ expect(obj).to.have.property('currentFrame', 0);
+ expect(obj).to.have.property('playing', false);
+ });
+});
diff --git a/.gitignore b/.gitignore
index 12e1b62..0b88317 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
node_modules
.DS_Store
-.project
\ No newline at end of file
+.project
+*.log
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..63e4d7c
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,8 @@
+language: node_js
+node_js:
+ - 0.10
+
+before_script:
+ - npm install -g grunt-cli
+ - export DISPLAY=:99.0
+ - sh -e /etc/init.d/xvfb start
diff --git a/Gruntfile.js b/Gruntfile.js
index b083b49..103938c 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -1,10 +1,12 @@
+'use strict';
+
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-connect');
- grunt.loadNpmTasks('grunt-contrib-qunit');
grunt.loadNpmTasks('grunt-contrib-yuidoc');
+ grunt.loadTasks('tasks');
var root = 'src/pixi/',
debug = 'bin/pixi.dev.js',
@@ -79,7 +81,7 @@
},
files: {
srcBlob: '<%= dirs.src %>/**/*.js',
- testBlob: '<%= dirs.test %>/unit/**/*.js',
+ testBlob: '<%= dirs.test %>/{functional,lib/pixi,unit}/**/*.js',
build: '<%= dirs.build %>/pixi.dev.js',
buildMin: '<%= dirs.build %>/pixi.js'
},
@@ -94,7 +96,12 @@
},
jshint: {
beforeconcat: srcFiles,
- test: ['<%= files.testBlob %>'],
+ test: {
+ src: ['<%= files.testBlob %>'],
+ options: {
+ expr: true
+ }
+ },
options: {
asi: true,
smarttabs: true
@@ -128,12 +135,6 @@
]
},
connect: {
- qunit: {
- options: {
- port: grunt.option('port-test') || 9002,
- base: './'
- }
- },
test: {
options: {
port: grunt.option('port-test') || 9002,
@@ -142,13 +143,6 @@
}
}
},
- qunit: {
- all: {
- options: {
- urls: ['http://localhost:' + (grunt.option('port-test') || 9002) + '/test/index.html']
- }
- }
- },
yuidoc: {
compile: {
name: '<%= pkg.name %>',
@@ -161,6 +155,13 @@
outdir: '<%= dirs.docs %>'
}
}
+ },
+ karma: {
+ unit: {
+ configFile: 'test/karma.conf.js',
+ // browsers: ['Chrome'],
+ singleRun: true
+ }
}
});
@@ -182,9 +183,10 @@
}
)
- grunt.registerTask('default', ['concat', 'uglify', 'distribute']);
grunt.registerTask('build', ['concat', 'uglify', 'distribute']);
- grunt.registerTask('test', ['build', 'connect:qunit', 'qunit']);
+ grunt.registerTask('test', ['concat', 'jshint:test', 'karma']);
grunt.registerTask('docs', ['yuidoc']);
-
-}
\ No newline at end of file
+ grunt.registerTask('default', ['test', 'uglify', 'distribute']);
+ // Travis CI task.
+ grunt.registerTask('travis', ['test']);
+}
diff --git a/README.md b/README.md
index c62ef86..690cfe4 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,8 @@

+[](http://travis-ci.org/drkibitz/pixi.js)
+
#### JavaScript 2D Renderer ####
The aim of this project is to provide a fast lightweight 2D library that works
diff --git a/package.json b/package.json
index b373240..1246a68 100644
--- a/package.json
+++ b/package.json
@@ -18,14 +18,21 @@
"main": "bin/pixi.js",
+ "scripts": {
+ "test": "grunt travis --verbose"
+ },
+
"dependencies": {},
"devDependencies": {
"grunt": "~0.4.x",
- "grunt-contrib-jshint": "0.3.x",
+ "grunt-contrib-jshint": "0.6.x",
"grunt-contrib-uglify": "0.2.x",
- "grunt-contrib-connect": "0.2.x",
- "grunt-contrib-qunit": "0.2.x",
+ "grunt-contrib-connect": "0.3.x",
"grunt-contrib-yuidoc": "0.4.x",
- "grunt-contrib-concat": "0.1.x"
+ "grunt-contrib-concat": "0.3.x",
+ "chai": "~1.7.0",
+ "karma": "0.11.0",
+ "karma-firefox-launcher": "0.1.0",
+ "karma-mocha": "0.1.0"
}
}
diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js
index a7c520e..ee82bbd 100644
--- a/src/pixi/InteractionManager.js
+++ b/src/pixi/InteractionManager.js
@@ -62,7 +62,6 @@
this.onTouchEnd = this.onTouchEnd.bind(this);
this.onTouchMove = this.onTouchMove.bind(this);
-
this.last = 0;
}
diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js
index 1a95d20..eef1059 100644
--- a/src/pixi/core/Ellipse.js
+++ b/src/pixi/core/Ellipse.js
@@ -78,7 +78,7 @@
return (normx + normy < 0.25);
}
-PIXI.Ellipse.getBounds = function()
+PIXI.Ellipse.prototype.getBounds = function()
{
return new PIXI.Rectangle(this.x, this.y, this.width, this.height);
}
diff --git a/tasks/karma.js b/tasks/karma.js
new file mode 100644
index 0000000..c340485
--- /dev/null
+++ b/tasks/karma.js
@@ -0,0 +1,27 @@
+'use strict';
+
+var path = require('path');
+var server = require('karma').server;
+
+module.exports = function (grunt) {
+ grunt.registerMultiTask('karma', 'run karma.', function() {
+ var done = this.async();
+ var options = this.options({
+ background: false
+ });
+ var data = this.data;
+
+ //merge options onto data, with data taking precedence
+ data = grunt.util._.merge(options, data);
+ data.configFile = path.resolve(data.configFile);
+ if (data.configFile) {
+ data.configFile = grunt.template.process(data.configFile);
+ }
+
+ server.start(
+ data,
+ function(code) {
+ done(!code);
+ });
+ });
+};
diff --git a/test/functional/example-1-basics/bunny.png b/test/functional/example-1-basics/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/functional/example-1-basics/bunny.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-30.png b/test/functional/example-1-basics/frame-30.png
new file mode 100644
index 0000000..96e3409
--- /dev/null
+++ b/test/functional/example-1-basics/frame-30.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-60.png b/test/functional/example-1-basics/frame-60.png
new file mode 100644
index 0000000..af3f4ce
--- /dev/null
+++ b/test/functional/example-1-basics/frame-60.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-90.png b/test/functional/example-1-basics/frame-90.png
new file mode 100644
index 0000000..099b823
--- /dev/null
+++ b/test/functional/example-1-basics/frame-90.png
Binary files differ
diff --git a/test/functional/example-1-basics/index.js b/test/functional/example-1-basics/index.js
new file mode 100644
index 0000000..7ae7a98
--- /dev/null
+++ b/test/functional/example-1-basics/index.js
@@ -0,0 +1,133 @@
+describe('Example 1 - Basics', function () {
+ 'use strict';
+
+ var baseUri = '/base/test/functional/example-1-basics';
+ var expect = chai.expect;
+ var currentFrame = 0;
+ var frameEvents = {};
+ var stage;
+ var renderer;
+ var bunny;
+
+ function onFrame(frame, callback) {
+ frameEvents[frame] = callback;
+ }
+
+ function animate() {
+ currentFrame += 1;
+
+ requestAnimFrame( animate );
+
+ // just for fun, lets rotate mr rabbit a little
+ bunny.rotation += 0.1;
+
+ // render the stage
+ renderer.render(stage);
+
+ if (frameEvents[currentFrame])
+ frameEvents[currentFrame](currentFrame);
+ }
+
+ function initScene() {
+ // create an new instance of a pixi stage
+ stage = new PIXI.Stage(0x66FF99);
+
+ // create a renderer instance
+ renderer = PIXI.autoDetectRenderer(400, 300);
+ console.log('Is PIXI.WebGLRenderer: ' + (renderer instanceof PIXI.WebGLRenderer));
+
+ // add the renderer view element to the DOM
+ document.body.appendChild(renderer.view);
+
+ requestAnimFrame( animate );
+
+ // create a texture from an image path
+ var texture = PIXI.Texture.fromImage(baseUri + "/bunny.png");
+ // create a new Sprite using the texture
+ bunny = new PIXI.Sprite(texture);
+
+ // center the sprites anchor point
+ bunny.anchor.x = 0.5;
+ bunny.anchor.y = 0.5;
+
+ // move the sprite t the center of the screen
+ bunny.position.x = 200;
+ bunny.position.y = 150;
+
+ stage.addChild(bunny);
+ }
+
+ it('assets loaded', function (done) {
+ var loader = new PIXI.AssetLoader([
+ baseUri + '/bunny.png',
+ baseUri + '/frame-30.png',
+ baseUri + '/frame-60.png',
+ baseUri + '/frame-90.png'
+ ]);
+ // loader.on('onProgress', function (event) {
+ // console.log(event.content);
+ // });
+ loader.on('onComplete', function (event) {
+ done();
+ initScene();
+ });
+ loader.load();
+ });
+
+ it('frame 30 should match', function (done) {
+ this.timeout(700);
+ onFrame(30, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-30.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 60 should match', function (done) {
+ this.timeout(1200);
+ onFrame(60, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-60.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 90 should match', function (done) {
+ this.timeout(1700);
+ onFrame(90, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-90.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ // it('capture something', function (done) {
+ // this.timeout(2000000);
+ // onFrame(30, function () {
+ // var img = new Image();
+ // img.src = renderer.view.toDataURL('image/png');
+ // document.body.appendChild(img);
+ // });
+ // });
+});
diff --git a/test/index.html b/test/index.html
deleted file mode 100644
index 9cbcac5..0000000
--- a/test/index.html
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
- Pixi.js Test Suite
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/test/karma.conf.js b/test/karma.conf.js
new file mode 100644
index 0000000..c66a696
--- /dev/null
+++ b/test/karma.conf.js
@@ -0,0 +1,82 @@
+module.exports = function(config) {
+ config.set({
+
+ // base path, that will be used to resolve files and exclude
+ basePath : '../',
+
+ frameworks : ['mocha'],
+
+ // list of files / patterns to load in the browser
+ files : [
+ 'node_modules/chai/chai.js',
+ 'bin/pixi.dev.js',
+ 'test/lib/**/*.js',
+ 'test/unit/**/*.js',
+ // 'test/functional/**/*.js',
+ {pattern: 'test/**/*.png', watched: false, included: false, served: true}
+ ],
+
+ // list of files to exclude
+ exclude : [],
+
+ // use dolts reporter, as travis terminal does not support escaping sequences
+ // possible values: 'dots', 'progress', 'junit', 'teamcity'
+ // CLI --reporters progress
+ reporters : ['progress'],
+
+ // web server port
+ // CLI --port 9876
+ port : 9876,
+
+ // cli runner port
+ // CLI --runner-port 9100
+ runnerPort : 9100,
+
+ // enable / disable colors in the output (reporters and logs)
+ // CLI --colors --no-colors
+ colors : true,
+
+ // level of logging
+ // possible values: karma.LOG_DISABLE || karma.LOG_ERROR || karma.LOG_WARN || karma.LOG_INFO || karma.LOG_DEBUG
+ // CLI --log-level debug
+ logLevel : config.LOG_DEBUG,
+
+ // enable / disable watching file and executing tests whenever any file changes
+ // CLI --auto-watch --no-auto-watch
+ autoWatch : false,
+
+ // Start these browsers, currently available:
+ // - Chrome
+ // - ChromeCanary
+ // - Firefox
+ // - Opera
+ // - Safari (only Mac)
+ // - PhantomJS
+ // - IE (only Windows)
+ // CLI --browsers Chrome,Firefox,Safari
+ browsers : ['Firefox'],
+
+ // If browser does not capture in given timeout [ms], kill it
+ // CLI --capture-timeout 5000
+ captureTimeout : 5000,
+
+ // Auto run tests on start (when browsers are captured) and exit
+ // CLI --single-run --no-single-run
+ singleRun : true,
+
+ // report which specs are slower than 500ms
+ // CLI --report-slower-than 500
+ reportSlowerThan : 1000,
+
+ preprocessors : {
+ // '**/client/js/*.js': 'coverage'
+ },
+
+ plugins : [
+ 'karma-mocha',
+ // 'karma-chrome-launcher',
+ 'karma-firefox-launcher',
+ // 'karma-phantomjs-launcher'
+ ]
+ });
+};
diff --git a/test/lib/pixi/core/Matrix.js b/test/lib/pixi/core/Matrix.js
new file mode 100644
index 0000000..d26386b
--- /dev/null
+++ b/test/lib/pixi/core/Matrix.js
@@ -0,0 +1,40 @@
+
+function pixi_core_Matrix_confirmNewMat3(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(1);
+ expect(matrix[5]).to.equal(0);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(1);
+}
+
+function pixi_core_Matrix_confirmNewMat4(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[0]).to.equal(1);
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(0);
+ expect(matrix[5]).to.equal(1);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(0);
+ expect(matrix[9]).to.equal(0);
+ expect(matrix[10]).to.equal(1);
+ expect(matrix[11]).to.equal(0);
+ expect(matrix[12]).to.equal(0);
+ expect(matrix[13]).to.equal(0);
+ expect(matrix[14]).to.equal(0);
+ expect(matrix[15]).to.equal(1);
+}
diff --git a/test/lib/pixi/core/Point.js b/test/lib/pixi/core/Point.js
new file mode 100644
index 0000000..e5df07b
--- /dev/null
+++ b/test/lib/pixi/core/Point.js
@@ -0,0 +1,10 @@
+
+function pixi_core_Point_confirm(obj, x, y) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Point);
+ expect(obj).to.respondTo('clone');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+}
diff --git a/test/lib/pixi/core/Rectangle.js b/test/lib/pixi/core/Rectangle.js
new file mode 100644
index 0000000..23f0d12
--- /dev/null
+++ b/test/lib/pixi/core/Rectangle.js
@@ -0,0 +1,13 @@
+
+function pixi_core_Rectangle_confirm(obj, x, y, width, height) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Rectangle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+ expect(obj).to.have.property('width', width);
+ expect(obj).to.have.property('height', height);
+}
diff --git a/test/lib/pixi/display/DisplayObject.js b/test/lib/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..1388a7f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObject.js
@@ -0,0 +1,43 @@
+
+function pixi_display_DisplayObject_confirmNew(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObject);
+ expect(obj).to.respondTo('setInteractive');
+ expect(obj).to.respondTo('addFilter');
+ expect(obj).to.respondTo('removeFilter');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.property('last', obj);
+ expect(obj).to.have.property('first', obj);
+
+ expect(obj).to.contain.property('position');
+ pixi_core_Point_confirm(obj.position, 0, 0);
+ expect(obj).to.contain.property('scale');
+ pixi_core_Point_confirm(obj.scale, 1, 1);
+ expect(obj).to.contain.property('pivot');
+ pixi_core_Point_confirm(obj.pivot, 0, 0);
+
+ expect(obj).to.have.property('rotation', 0);
+ expect(obj).to.have.property('alpha', 1);
+ expect(obj).to.have.property('visible', true);
+ expect(obj).to.have.property('buttonMode', false);
+ expect(obj).to.have.property('parent', null);
+ expect(obj).to.have.property('worldAlpha', 1);
+
+ expect(obj).to.have.property('hitArea');
+ expect(obj).to.have.property('interactive'); // TODO: Have a better default value
+ expect('mask' in obj).to.be.true; // TODO: Have a better default value
+ expect(obj.mask).to.be.undefined;
+
+ expect(obj).to.have.property('renderable');
+ expect(obj).to.have.property('stage');
+
+ expect(obj).to.have.deep.property('worldTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ expect(obj).to.have.deep.property('localTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.localTransform);
+
+ expect(obj).to.have.deep.property('color.length', 0);
+ expect(obj).to.have.property('dynamic', true);
+}
diff --git a/test/lib/pixi/display/DisplayObjectContainer.js b/test/lib/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..085c59f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,16 @@
+
+function pixi_display_DisplayObjectContainer_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObject_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObjectContainer);
+ expect(obj).to.respondTo('addChild');
+ expect(obj).to.respondTo('addChildAt');
+ expect(obj).to.respondTo('swapChildren');
+ expect(obj).to.respondTo('getChildAt');
+ expect(obj).to.respondTo('removeChild');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('children.length', 0);
+}
diff --git a/test/lib/pixi/display/Sprite.js b/test/lib/pixi/display/Sprite.js
new file mode 100644
index 0000000..cc7a2d6
--- /dev/null
+++ b/test/lib/pixi/display/Sprite.js
@@ -0,0 +1,28 @@
+
+function pixi_display_Sprite_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Sprite);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', true);
+ expect(obj).to.have.property('stage', null);
+
+ expect(obj).to.have.property('anchor');
+ pixi_core_Point_confirm(obj.anchor, 0, 0);
+
+ expect(obj).to.have.property('blendMode', PIXI.blendModes.NORMAL);
+ expect(obj).to.have.property('width', 1); // TODO: is 1 expected
+ expect(obj).to.have.property('height', 1); // TODO: is 1 expected
+
+ // FIXME: Just make this a boolean that is always there
+ expect(!!obj.updateFrame).to.equal(obj.texture.baseTexture.hasLoaded);
+
+ expect(obj).to.have.property('texture');
+ pixi_textures_Texture_confirmNew(obj.texture, done);
+}
diff --git a/test/lib/pixi/extras/Strip.js b/test/lib/pixi/extras/Strip.js
new file mode 100644
index 0000000..8927a8a
--- /dev/null
+++ b/test/lib/pixi/extras/Strip.js
@@ -0,0 +1,12 @@
+
+function pixi_extras_Strip_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Strip);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ // TODO: Test properties
+}
diff --git a/test/lib/pixi/textures/Texture.js b/test/lib/pixi/textures/Texture.js
new file mode 100644
index 0000000..d5867b6
--- /dev/null
+++ b/test/lib/pixi/textures/Texture.js
@@ -0,0 +1,31 @@
+
+function pixi_textures_Texture_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ function confirmFrameDone() {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, obj.baseTexture.width, obj.baseTexture.height);
+
+ expect(obj).to.have.property('width', obj.baseTexture.width);
+ expect(obj).to.have.property('height', obj.baseTexture.height);
+ done();
+ }
+
+ expect(obj).to.be.an.instanceof(PIXI.Texture);
+ pixi_utils_EventTarget_like(obj);
+
+ expect(obj).to.have.property('baseTexture')
+ .and.to.be.an.instanceof(PIXI.BaseTexture);
+
+ expect(obj).to.have.property('scope', obj);
+
+ expect(obj).to.have.property('trim');
+ pixi_core_Point_confirm(obj.trim, 0, 0);
+
+ expect(obj).to.have.property('frame');
+ if (obj.baseTexture.hasLoaded) {
+ confirmFrameDone();
+ } else {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, 1, 1);
+ obj.addEventListener('update', confirmFrameDone);
+ }
+}
diff --git a/test/lib/pixi/utils/EventTarget.js b/test/lib/pixi/utils/EventTarget.js
new file mode 100644
index 0000000..7b1dcfa
--- /dev/null
+++ b/test/lib/pixi/utils/EventTarget.js
@@ -0,0 +1,8 @@
+
+function pixi_utils_EventTarget_like(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.respondTo('addEventListener');
+ expect(obj).to.respondTo('dispatchEvent');
+ expect(obj).to.respondTo('removeEventListener');
+}
diff --git a/test/lib/qunit-1.11.0.css b/test/lib/qunit-1.11.0.css
deleted file mode 100644
index d7fc0c8..0000000
--- a/test/lib/qunit-1.11.0.css
+++ /dev/null
@@ -1,244 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-/** Font Family and Sizes */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
- font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
-}
-
-#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
-#qunit-tests { font-size: smaller; }
-
-
-/** Resets */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter {
- margin: 0;
- padding: 0;
-}
-
-
-/** Header */
-
-#qunit-header {
- padding: 0.5em 0 0.5em 1em;
-
- color: #8699a4;
- background-color: #0d3349;
-
- font-size: 1.5em;
- line-height: 1em;
- font-weight: normal;
-
- border-radius: 5px 5px 0 0;
- -moz-border-radius: 5px 5px 0 0;
- -webkit-border-top-right-radius: 5px;
- -webkit-border-top-left-radius: 5px;
-}
-
-#qunit-header a {
- text-decoration: none;
- color: #c2ccd1;
-}
-
-#qunit-header a:hover,
-#qunit-header a:focus {
- color: #fff;
-}
-
-#qunit-testrunner-toolbar label {
- display: inline-block;
- padding: 0 .5em 0 .1em;
-}
-
-#qunit-banner {
- height: 5px;
-}
-
-#qunit-testrunner-toolbar {
- padding: 0.5em 0 0.5em 2em;
- color: #5E740B;
- background-color: #eee;
- overflow: hidden;
-}
-
-#qunit-userAgent {
- padding: 0.5em 0 0.5em 2.5em;
- background-color: #2b81af;
- color: #fff;
- text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
-}
-
-#qunit-modulefilter-container {
- float: right;
-}
-
-/** Tests: Pass/Fail */
-
-#qunit-tests {
- list-style-position: inside;
-}
-
-#qunit-tests li {
- padding: 0.4em 0.5em 0.4em 2.5em;
- border-bottom: 1px solid #fff;
- list-style-position: inside;
-}
-
-#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running {
- display: none;
-}
-
-#qunit-tests li strong {
- cursor: pointer;
-}
-
-#qunit-tests li a {
- padding: 0.5em;
- color: #c2ccd1;
- text-decoration: none;
-}
-#qunit-tests li a:hover,
-#qunit-tests li a:focus {
- color: #000;
-}
-
-#qunit-tests li .runtime {
- float: right;
- font-size: smaller;
-}
-
-.qunit-assert-list {
- margin-top: 0.5em;
- padding: 0.5em;
-
- background-color: #fff;
-
- border-radius: 5px;
- -moz-border-radius: 5px;
- -webkit-border-radius: 5px;
-}
-
-.qunit-collapsed {
- display: none;
-}
-
-#qunit-tests table {
- border-collapse: collapse;
- margin-top: .2em;
-}
-
-#qunit-tests th {
- text-align: right;
- vertical-align: top;
- padding: 0 .5em 0 0;
-}
-
-#qunit-tests td {
- vertical-align: top;
-}
-
-#qunit-tests pre {
- margin: 0;
- white-space: pre-wrap;
- word-wrap: break-word;
-}
-
-#qunit-tests del {
- background-color: #e0f2be;
- color: #374e0c;
- text-decoration: none;
-}
-
-#qunit-tests ins {
- background-color: #ffcaca;
- color: #500;
- text-decoration: none;
-}
-
-/*** Test Counts */
-
-#qunit-tests b.counts { color: black; }
-#qunit-tests b.passed { color: #5E740B; }
-#qunit-tests b.failed { color: #710909; }
-
-#qunit-tests li li {
- padding: 5px;
- background-color: #fff;
- border-bottom: none;
- list-style-position: inside;
-}
-
-/*** Passing Styles */
-
-#qunit-tests li li.pass {
- color: #3c510c;
- background-color: #fff;
- border-left: 10px solid #C6E746;
-}
-
-#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
-#qunit-tests .pass .test-name { color: #366097; }
-
-#qunit-tests .pass .test-actual,
-#qunit-tests .pass .test-expected { color: #999999; }
-
-#qunit-banner.qunit-pass { background-color: #C6E746; }
-
-/*** Failing Styles */
-
-#qunit-tests li li.fail {
- color: #710909;
- background-color: #fff;
- border-left: 10px solid #EE5757;
- white-space: pre;
-}
-
-#qunit-tests > li:last-child {
- border-radius: 0 0 5px 5px;
- -moz-border-radius: 0 0 5px 5px;
- -webkit-border-bottom-right-radius: 5px;
- -webkit-border-bottom-left-radius: 5px;
-}
-
-#qunit-tests .fail { color: #000000; background-color: #EE5757; }
-#qunit-tests .fail .test-name,
-#qunit-tests .fail .module-name { color: #000000; }
-
-#qunit-tests .fail .test-actual { color: #EE5757; }
-#qunit-tests .fail .test-expected { color: green; }
-
-#qunit-banner.qunit-fail { background-color: #EE5757; }
-
-
-/** Result */
-
-#qunit-testresult {
- padding: 0.5em 0.5em 0.5em 2.5em;
-
- color: #2b81af;
- background-color: #D2E0E6;
-
- border-bottom: 1px solid white;
-}
-#qunit-testresult .module-name {
- font-weight: bold;
-}
-
-/** Fixture */
-
-#qunit-fixture {
- position: absolute;
- top: -10000px;
- left: -10000px;
- width: 1000px;
- height: 1000px;
-}
diff --git a/test/lib/qunit-1.11.0.js b/test/lib/qunit-1.11.0.js
deleted file mode 100644
index 302545f..0000000
--- a/test/lib/qunit-1.11.0.js
+++ /dev/null
@@ -1,2152 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-(function( window ) {
-
-var QUnit,
- assert,
- config,
- onErrorFnPrev,
- testId = 0,
- fileName = (sourceFromStacktrace( 0 ) || "" ).replace(/(:\d+)+\)?/, "").replace(/.+\//, ""),
- toString = Object.prototype.toString,
- hasOwn = Object.prototype.hasOwnProperty,
- // Keep a local reference to Date (GH-283)
- Date = window.Date,
- defined = {
- setTimeout: typeof window.setTimeout !== "undefined",
- sessionStorage: (function() {
- var x = "qunit-test-string";
- try {
- sessionStorage.setItem( x, x );
- sessionStorage.removeItem( x );
- return true;
- } catch( e ) {
- return false;
- }
- }())
- },
- /**
- * Provides a normalized error string, correcting an issue
- * with IE 7 (and prior) where Error.prototype.toString is
- * not properly implemented
- *
- * Based on http://es5.github.com/#x15.11.4.4
- *
- * @param {String|Error} error
- * @return {String} error message
- */
- errorString = function( error ) {
- var name, message,
- errorString = error.toString();
- if ( errorString.substring( 0, 7 ) === "[object" ) {
- name = error.name ? error.name.toString() : "Error";
- message = error.message ? error.message.toString() : "";
- if ( name && message ) {
- return name + ": " + message;
- } else if ( name ) {
- return name;
- } else if ( message ) {
- return message;
- } else {
- return "Error";
- }
- } else {
- return errorString;
- }
- },
- /**
- * Makes a clone of an object using only Array or Object as base,
- * and copies over the own enumerable properties.
- *
- * @param {Object} obj
- * @return {Object} New object with only the own properties (recursively).
- */
- objectValues = function( obj ) {
- // Grunt 0.3.x uses an older version of jshint that still has jshint/jshint#392.
- /*jshint newcap: false */
- var key, val,
- vals = QUnit.is( "array", obj ) ? [] : {};
- for ( key in obj ) {
- if ( hasOwn.call( obj, key ) ) {
- val = obj[key];
- vals[key] = val === Object(val) ? objectValues(val) : val;
- }
- }
- return vals;
- };
-
-function Test( settings ) {
- extend( this, settings );
- this.assertions = [];
- this.testNumber = ++Test.count;
-}
-
-Test.count = 0;
-
-Test.prototype = {
- init: function() {
- var a, b, li,
- tests = id( "qunit-tests" );
-
- if ( tests ) {
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml;
-
- // `a` initialized at top of scope
- a = document.createElement( "a" );
- a.innerHTML = "Rerun";
- a.href = QUnit.url({ testNumber: this.testNumber });
-
- li = document.createElement( "li" );
- li.appendChild( b );
- li.appendChild( a );
- li.className = "running";
- li.id = this.id = "qunit-test-output" + testId++;
-
- tests.appendChild( li );
- }
- },
- setup: function() {
- if ( this.module !== config.previousModule ) {
- if ( config.previousModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.previousModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
- config.previousModule = this.module;
- config.moduleStats = { all: 0, bad: 0 };
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- } else if ( config.autorun ) {
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- }
-
- config.current = this;
-
- this.testEnvironment = extend({
- setup: function() {},
- teardown: function() {}
- }, this.moduleTestEnvironment );
-
- this.started = +new Date();
- runLoggingCallbacks( "testStart", QUnit, {
- name: this.testName,
- module: this.module
- });
-
- // allow utility functions to access the current test environment
- // TODO why??
- QUnit.current_testEnvironment = this.testEnvironment;
-
- if ( !config.pollution ) {
- saveGlobal();
- }
- if ( config.notrycatch ) {
- this.testEnvironment.setup.call( this.testEnvironment );
- return;
- }
- try {
- this.testEnvironment.setup.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Setup failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- },
- run: function() {
- config.current = this;
-
- var running = id( "qunit-testresult" );
-
- if ( running ) {
- running.innerHTML = "Running:
" + this.nameHtml;
- }
-
- if ( this.async ) {
- QUnit.stop();
- }
-
- this.callbackStarted = +new Date();
-
- if ( config.notrycatch ) {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- return;
- }
-
- try {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- } catch( e ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
-
- QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + " " + this.stack + ": " + ( e.message || e ), extractStacktrace( e, 0 ) );
- // else next test will carry the responsibility
- saveGlobal();
-
- // Restart the tests if they're blocking
- if ( config.blocking ) {
- QUnit.start();
- }
- }
- },
- teardown: function() {
- config.current = this;
- if ( config.notrycatch ) {
- if ( typeof this.callbackRuntime === "undefined" ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
- }
- this.testEnvironment.teardown.call( this.testEnvironment );
- return;
- } else {
- try {
- this.testEnvironment.teardown.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Teardown failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- }
- checkPollution();
- },
- finish: function() {
- config.current = this;
- if ( config.requireExpects && this.expected === null ) {
- QUnit.pushFailure( "Expected number of assertions to be defined, but expect() was not called.", this.stack );
- } else if ( this.expected !== null && this.expected !== this.assertions.length ) {
- QUnit.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack );
- } else if ( this.expected === null && !this.assertions.length ) {
- QUnit.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions.", this.stack );
- }
-
- var i, assertion, a, b, time, li, ol,
- test = this,
- good = 0,
- bad = 0,
- tests = id( "qunit-tests" );
-
- this.runtime = +new Date() - this.started;
- config.stats.all += this.assertions.length;
- config.moduleStats.all += this.assertions.length;
-
- if ( tests ) {
- ol = document.createElement( "ol" );
- ol.className = "qunit-assert-list";
-
- for ( i = 0; i < this.assertions.length; i++ ) {
- assertion = this.assertions[i];
-
- li = document.createElement( "li" );
- li.className = assertion.result ? "pass" : "fail";
- li.innerHTML = assertion.message || ( assertion.result ? "okay" : "failed" );
- ol.appendChild( li );
-
- if ( assertion.result ) {
- good++;
- } else {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
-
- // store result when possible
- if ( QUnit.config.reorder && defined.sessionStorage ) {
- if ( bad ) {
- sessionStorage.setItem( "qunit-test-" + this.module + "-" + this.testName, bad );
- } else {
- sessionStorage.removeItem( "qunit-test-" + this.module + "-" + this.testName );
- }
- }
-
- if ( bad === 0 ) {
- addClass( ol, "qunit-collapsed" );
- }
-
- // `b` initialized at top of scope
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml + " (" + bad + ", " + good + ", " + this.assertions.length + ")";
-
- addEvent(b, "click", function() {
- var next = b.parentNode.lastChild,
- collapsed = hasClass( next, "qunit-collapsed" );
- ( collapsed ? removeClass : addClass )( next, "qunit-collapsed" );
- });
-
- addEvent(b, "dblclick", function( e ) {
- var target = e && e.target ? e.target : window.event.srcElement;
- if ( target.nodeName.toLowerCase() === "span" || target.nodeName.toLowerCase() === "b" ) {
- target = target.parentNode;
- }
- if ( window.location && target.nodeName.toLowerCase() === "strong" ) {
- window.location = QUnit.url({ testNumber: test.testNumber });
- }
- });
-
- // `time` initialized at top of scope
- time = document.createElement( "span" );
- time.className = "runtime";
- time.innerHTML = this.runtime + " ms";
-
- // `li` initialized at top of scope
- li = id( this.id );
- li.className = bad ? "fail" : "pass";
- li.removeChild( li.firstChild );
- a = li.firstChild;
- li.appendChild( b );
- li.appendChild( a );
- li.appendChild( time );
- li.appendChild( ol );
-
- } else {
- for ( i = 0; i < this.assertions.length; i++ ) {
- if ( !this.assertions[i].result ) {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
- }
-
- runLoggingCallbacks( "testDone", QUnit, {
- name: this.testName,
- module: this.module,
- failed: bad,
- passed: this.assertions.length - bad,
- total: this.assertions.length,
- duration: this.runtime
- });
-
- QUnit.reset();
-
- config.current = undefined;
- },
-
- queue: function() {
- var bad,
- test = this;
-
- synchronize(function() {
- test.init();
- });
- function run() {
- // each of these can by async
- synchronize(function() {
- test.setup();
- });
- synchronize(function() {
- test.run();
- });
- synchronize(function() {
- test.teardown();
- });
- synchronize(function() {
- test.finish();
- });
- }
-
- // `bad` initialized at top of scope
- // defer when previous test run passed, if storage is available
- bad = QUnit.config.reorder && defined.sessionStorage &&
- +sessionStorage.getItem( "qunit-test-" + this.module + "-" + this.testName );
-
- if ( bad ) {
- run();
- } else {
- synchronize( run, true );
- }
- }
-};
-
-// Root QUnit object.
-// `QUnit` initialized at top of scope
-QUnit = {
-
- // call on start of module test to prepend name to all tests
- module: function( name, testEnvironment ) {
- config.currentModule = name;
- config.currentModuleTestEnvironment = testEnvironment;
- config.modules[name] = true;
- },
-
- asyncTest: function( testName, expected, callback ) {
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- QUnit.test( testName, expected, callback, true );
- },
-
- test: function( testName, expected, callback, async ) {
- var test,
- nameHtml = "" + escapeText( testName ) + "";
-
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- if ( config.currentModule ) {
- nameHtml = "" + escapeText( config.currentModule ) + ": " + nameHtml;
- }
-
- test = new Test({
- nameHtml: nameHtml,
- testName: testName,
- expected: expected,
- async: async,
- callback: callback,
- module: config.currentModule,
- moduleTestEnvironment: config.currentModuleTestEnvironment,
- stack: sourceFromStacktrace( 2 )
- });
-
- if ( !validTest( test ) ) {
- return;
- }
-
- test.queue();
- },
-
- // Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through.
- expect: function( asserts ) {
- if (arguments.length === 1) {
- config.current.expected = asserts;
- } else {
- return config.current.expected;
- }
- },
-
- start: function( count ) {
- // QUnit hasn't been initialized yet.
- // Note: RequireJS (et al) may delay onLoad
- if ( config.semaphore === undefined ) {
- QUnit.begin(function() {
- // This is triggered at the top of QUnit.load, push start() to the event loop, to allow QUnit.load to finish first
- setTimeout(function() {
- QUnit.start( count );
- });
- });
- return;
- }
-
- config.semaphore -= count || 1;
- // don't start until equal number of stop-calls
- if ( config.semaphore > 0 ) {
- return;
- }
- // ignore if start is called more often then stop
- if ( config.semaphore < 0 ) {
- config.semaphore = 0;
- QUnit.pushFailure( "Called start() while already started (QUnit.config.semaphore was 0 already)", null, sourceFromStacktrace(2) );
- return;
- }
- // A slight delay, to avoid any current callbacks
- if ( defined.setTimeout ) {
- window.setTimeout(function() {
- if ( config.semaphore > 0 ) {
- return;
- }
- if ( config.timeout ) {
- clearTimeout( config.timeout );
- }
-
- config.blocking = false;
- process( true );
- }, 13);
- } else {
- config.blocking = false;
- process( true );
- }
- },
-
- stop: function( count ) {
- config.semaphore += count || 1;
- config.blocking = true;
-
- if ( config.testTimeout && defined.setTimeout ) {
- clearTimeout( config.timeout );
- config.timeout = window.setTimeout(function() {
- QUnit.ok( false, "Test timed out" );
- config.semaphore = 1;
- QUnit.start();
- }, config.testTimeout );
- }
- }
-};
-
-// `assert` initialized at top of scope
-// Asssert helpers
-// All of these must either call QUnit.push() or manually do:
-// - runLoggingCallbacks( "log", .. );
-// - config.current.assertions.push({ .. });
-// We attach it to the QUnit object *after* we expose the public API,
-// otherwise `assert` will become a global variable in browsers (#341).
-assert = {
- /**
- * Asserts rough true-ish result.
- * @name ok
- * @function
- * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" );
- */
- ok: function( result, msg ) {
- if ( !config.current ) {
- throw new Error( "ok() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
- result = !!result;
-
- var source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: msg
- };
-
- msg = escapeText( msg || (result ? "okay" : "failed" ) );
- msg = "" + msg + "";
-
- if ( !result ) {
- source = sourceFromStacktrace( 2 );
- if ( source ) {
- details.source = source;
- msg += "Source: | " + escapeText( source ) + " |
---|
";
- }
- }
- runLoggingCallbacks( "log", QUnit, details );
- config.current.assertions.push({
- result: result,
- message: msg
- });
- },
-
- /**
- * Assert that the first two arguments are equal, with an optional message.
- * Prints out both actual and expected values.
- * @name equal
- * @function
- * @example equal( format( "Received {0} bytes.", 2), "Received 2 bytes.", "format() replaces {0} with next argument" );
- */
- equal: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected == actual, actual, expected, message );
- },
-
- /**
- * @name notEqual
- * @function
- */
- notEqual: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected != actual, actual, expected, message );
- },
-
- /**
- * @name propEqual
- * @function
- */
- propEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notPropEqual
- * @function
- */
- notPropEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name deepEqual
- * @function
- */
- deepEqual: function( actual, expected, message ) {
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notDeepEqual
- * @function
- */
- notDeepEqual: function( actual, expected, message ) {
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name strictEqual
- * @function
- */
- strictEqual: function( actual, expected, message ) {
- QUnit.push( expected === actual, actual, expected, message );
- },
-
- /**
- * @name notStrictEqual
- * @function
- */
- notStrictEqual: function( actual, expected, message ) {
- QUnit.push( expected !== actual, actual, expected, message );
- },
-
- "throws": function( block, expected, message ) {
- var actual,
- expectedOutput = expected,
- ok = false;
-
- // 'expected' is optional
- if ( typeof expected === "string" ) {
- message = expected;
- expected = null;
- }
-
- config.current.ignoreGlobalErrors = true;
- try {
- block.call( config.current.testEnvironment );
- } catch (e) {
- actual = e;
- }
- config.current.ignoreGlobalErrors = false;
-
- if ( actual ) {
- // we don't want to validate thrown error
- if ( !expected ) {
- ok = true;
- expectedOutput = null;
- // expected is a regexp
- } else if ( QUnit.objectType( expected ) === "regexp" ) {
- ok = expected.test( errorString( actual ) );
- // expected is a constructor
- } else if ( actual instanceof expected ) {
- ok = true;
- // expected is a validation function which returns true is validation passed
- } else if ( expected.call( {}, actual ) === true ) {
- expectedOutput = null;
- ok = true;
- }
-
- QUnit.push( ok, actual, expectedOutput, message );
- } else {
- QUnit.pushFailure( message, null, 'No exception was thrown.' );
- }
- }
-};
-
-/**
- * @deprecate since 1.8.0
- * Kept assertion helpers in root for backwards compatibility.
- */
-extend( QUnit, assert );
-
-/**
- * @deprecated since 1.9.0
- * Kept root "raises()" for backwards compatibility.
- * (Note that we don't introduce assert.raises).
- */
-QUnit.raises = assert[ "throws" ];
-
-/**
- * @deprecated since 1.0.0, replaced with error pushes since 1.3.0
- * Kept to avoid TypeErrors for undefined methods.
- */
-QUnit.equals = function() {
- QUnit.push( false, false, false, "QUnit.equals has been deprecated since 2009 (e88049a0), use QUnit.equal instead" );
-};
-QUnit.same = function() {
- QUnit.push( false, false, false, "QUnit.same has been deprecated since 2009 (e88049a0), use QUnit.deepEqual instead" );
-};
-
-// We want access to the constructor's prototype
-(function() {
- function F() {}
- F.prototype = QUnit;
- QUnit = new F();
- // Make F QUnit's constructor so that we can add to the prototype later
- QUnit.constructor = F;
-}());
-
-/**
- * Config object: Maintain internal state
- * Later exposed as QUnit.config
- * `config` initialized at top of scope
- */
-config = {
- // The queue of tests to run
- queue: [],
-
- // block until document ready
- blocking: true,
-
- // when enabled, show only failing tests
- // gets persisted through sessionStorage and can be changed in UI via checkbox
- hidepassed: false,
-
- // by default, run previously failed tests first
- // very useful in combination with "Hide passed tests" checked
- reorder: true,
-
- // by default, modify document.title when suite is done
- altertitle: true,
-
- // when enabled, all tests must call expect()
- requireExpects: false,
-
- // add checkboxes that are persisted in the query-string
- // when enabled, the id is set to `true` as a `QUnit.config` property
- urlConfig: [
- {
- id: "noglobals",
- label: "Check for Globals",
- tooltip: "Enabling this will test if any test introduces new properties on the `window` object. Stored as query-strings."
- },
- {
- id: "notrycatch",
- label: "No try-catch",
- tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging exceptions in IE reasonable. Stored as query-strings."
- }
- ],
-
- // Set of all modules.
- modules: {},
-
- // logging callback queues
- begin: [],
- done: [],
- log: [],
- testStart: [],
- testDone: [],
- moduleStart: [],
- moduleDone: []
-};
-
-// Export global variables, unless an 'exports' object exists,
-// in that case we assume we're in CommonJS (dealt with on the bottom of the script)
-if ( typeof exports === "undefined" ) {
- extend( window, QUnit );
-
- // Expose QUnit object
- window.QUnit = QUnit;
-}
-
-// Initialize more QUnit.config and QUnit.urlParams
-(function() {
- var i,
- location = window.location || { search: "", protocol: "file:" },
- params = location.search.slice( 1 ).split( "&" ),
- length = params.length,
- urlParams = {},
- current;
-
- if ( params[ 0 ] ) {
- for ( i = 0; i < length; i++ ) {
- current = params[ i ].split( "=" );
- current[ 0 ] = decodeURIComponent( current[ 0 ] );
- // allow just a key to turn on a flag, e.g., test.html?noglobals
- current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true;
- urlParams[ current[ 0 ] ] = current[ 1 ];
- }
- }
-
- QUnit.urlParams = urlParams;
-
- // String search anywhere in moduleName+testName
- config.filter = urlParams.filter;
-
- // Exact match of the module name
- config.module = urlParams.module;
-
- config.testNumber = parseInt( urlParams.testNumber, 10 ) || null;
-
- // Figure out if we're running the tests from a server or not
- QUnit.isLocal = location.protocol === "file:";
-}());
-
-// Extend QUnit object,
-// these after set here because they should not be exposed as global functions
-extend( QUnit, {
- assert: assert,
-
- config: config,
-
- // Initialize the configuration options
- init: function() {
- extend( config, {
- stats: { all: 0, bad: 0 },
- moduleStats: { all: 0, bad: 0 },
- started: +new Date(),
- updateRate: 1000,
- blocking: false,
- autostart: true,
- autorun: false,
- filter: "",
- queue: [],
- semaphore: 1
- });
-
- var tests, banner, result,
- qunit = id( "qunit" );
-
- if ( qunit ) {
- qunit.innerHTML =
- "" +
- "" +
- "" +
- "" +
- "
";
- }
-
- tests = id( "qunit-tests" );
- banner = id( "qunit-banner" );
- result = id( "qunit-testresult" );
-
- if ( tests ) {
- tests.innerHTML = "";
- }
-
- if ( banner ) {
- banner.className = "";
- }
-
- if ( result ) {
- result.parentNode.removeChild( result );
- }
-
- if ( tests ) {
- result = document.createElement( "p" );
- result.id = "qunit-testresult";
- result.className = "result";
- tests.parentNode.insertBefore( result, tests );
- result.innerHTML = "Running...
";
- }
- },
-
- // Resets the test setup. Useful for tests that modify the DOM.
- reset: function() {
- var fixture = id( "qunit-fixture" );
- if ( fixture ) {
- fixture.innerHTML = config.fixture;
- }
- },
-
- // Trigger an event on an element.
- // @example triggerEvent( document.body, "click" );
- triggerEvent: function( elem, type, event ) {
- if ( document.createEvent ) {
- event = document.createEvent( "MouseEvents" );
- event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView,
- 0, 0, 0, 0, 0, false, false, false, false, 0, null);
-
- elem.dispatchEvent( event );
- } else if ( elem.fireEvent ) {
- elem.fireEvent( "on" + type );
- }
- },
-
- // Safe object type checking
- is: function( type, obj ) {
- return QUnit.objectType( obj ) === type;
- },
-
- objectType: function( obj ) {
- if ( typeof obj === "undefined" ) {
- return "undefined";
- // consider: typeof null === object
- }
- if ( obj === null ) {
- return "null";
- }
-
- var match = toString.call( obj ).match(/^\[object\s(.*)\]$/),
- type = match && match[1] || "";
-
- switch ( type ) {
- case "Number":
- if ( isNaN(obj) ) {
- return "nan";
- }
- return "number";
- case "String":
- case "Boolean":
- case "Array":
- case "Date":
- case "RegExp":
- case "Function":
- return type.toLowerCase();
- }
- if ( typeof obj === "object" ) {
- return "object";
- }
- return undefined;
- },
-
- push: function( result, actual, expected, message ) {
- if ( !config.current ) {
- throw new Error( "assertion outside test context, was " + sourceFromStacktrace() );
- }
-
- var output, source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: message,
- actual: actual,
- expected: expected
- };
-
- message = escapeText( message ) || ( result ? "okay" : "failed" );
- message = "" + message + "";
- output = message;
-
- if ( !result ) {
- expected = escapeText( QUnit.jsDump.parse(expected) );
- actual = escapeText( QUnit.jsDump.parse(actual) );
- output += "Expected: | " + expected + " |
";
-
- if ( actual !== expected ) {
- output += "Result: | " + actual + " |
";
- output += "Diff: | " + QUnit.diff( expected, actual ) + " |
";
- }
-
- source = sourceFromStacktrace();
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
- }
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: !!result,
- message: output
- });
- },
-
- pushFailure: function( message, source, actual ) {
- if ( !config.current ) {
- throw new Error( "pushFailure() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
-
- var output,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: false,
- message: message
- };
-
- message = escapeText( message ) || "error";
- message = "" + message + "";
- output = message;
-
- output += "";
-
- if ( actual ) {
- output += "Result: | " + escapeText( actual ) + " |
";
- }
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: false,
- message: output
- });
- },
-
- url: function( params ) {
- params = extend( extend( {}, QUnit.urlParams ), params );
- var key,
- querystring = "?";
-
- for ( key in params ) {
- if ( !hasOwn.call( params, key ) ) {
- continue;
- }
- querystring += encodeURIComponent( key ) + "=" +
- encodeURIComponent( params[ key ] ) + "&";
- }
- return window.location.protocol + "//" + window.location.host +
- window.location.pathname + querystring.slice( 0, -1 );
- },
-
- extend: extend,
- id: id,
- addEvent: addEvent
- // load, equiv, jsDump, diff: Attached later
-});
-
-/**
- * @deprecated: Created for backwards compatibility with test runner that set the hook function
- * into QUnit.{hook}, instead of invoking it and passing the hook function.
- * QUnit.constructor is set to the empty F() above so that we can add to it's prototype here.
- * Doing this allows us to tell if the following methods have been overwritten on the actual
- * QUnit object.
- */
-extend( QUnit.constructor.prototype, {
-
- // Logging callbacks; all receive a single argument with the listed properties
- // run test/logs.html for any related changes
- begin: registerLoggingCallback( "begin" ),
-
- // done: { failed, passed, total, runtime }
- done: registerLoggingCallback( "done" ),
-
- // log: { result, actual, expected, message }
- log: registerLoggingCallback( "log" ),
-
- // testStart: { name }
- testStart: registerLoggingCallback( "testStart" ),
-
- // testDone: { name, failed, passed, total, duration }
- testDone: registerLoggingCallback( "testDone" ),
-
- // moduleStart: { name }
- moduleStart: registerLoggingCallback( "moduleStart" ),
-
- // moduleDone: { name, failed, passed, total }
- moduleDone: registerLoggingCallback( "moduleDone" )
-});
-
-if ( typeof document === "undefined" || document.readyState === "complete" ) {
- config.autorun = true;
-}
-
-QUnit.load = function() {
- runLoggingCallbacks( "begin", QUnit, {} );
-
- // Initialize the config, saving the execution queue
- var banner, filter, i, label, len, main, ol, toolbar, userAgent, val,
- urlConfigCheckboxesContainer, urlConfigCheckboxes, moduleFilter,
- numModules = 0,
- moduleFilterHtml = "",
- urlConfigHtml = "",
- oldconfig = extend( {}, config );
-
- QUnit.init();
- extend(config, oldconfig);
-
- config.blocking = false;
-
- len = config.urlConfig.length;
-
- for ( i = 0; i < len; i++ ) {
- val = config.urlConfig[i];
- if ( typeof val === "string" ) {
- val = {
- id: val,
- label: val,
- tooltip: "[no tooltip available]"
- };
- }
- config[ val.id ] = QUnit.urlParams[ val.id ];
- urlConfigHtml += "";
- }
-
- moduleFilterHtml += "";
-
- // `userAgent` initialized at top of scope
- userAgent = id( "qunit-userAgent" );
- if ( userAgent ) {
- userAgent.innerHTML = navigator.userAgent;
- }
-
- // `banner` initialized at top of scope
- banner = id( "qunit-header" );
- if ( banner ) {
- banner.innerHTML = "" + banner.innerHTML + " ";
- }
-
- // `toolbar` initialized at top of scope
- toolbar = id( "qunit-testrunner-toolbar" );
- if ( toolbar ) {
- // `filter` initialized at top of scope
- filter = document.createElement( "input" );
- filter.type = "checkbox";
- filter.id = "qunit-filter-pass";
-
- addEvent( filter, "click", function() {
- var tmp,
- ol = document.getElementById( "qunit-tests" );
-
- if ( filter.checked ) {
- ol.className = ol.className + " hidepass";
- } else {
- tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " ";
- ol.className = tmp.replace( / hidepass /, " " );
- }
- if ( defined.sessionStorage ) {
- if (filter.checked) {
- sessionStorage.setItem( "qunit-filter-passed-tests", "true" );
- } else {
- sessionStorage.removeItem( "qunit-filter-passed-tests" );
- }
- }
- });
-
- if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem( "qunit-filter-passed-tests" ) ) {
- filter.checked = true;
- // `ol` initialized at top of scope
- ol = document.getElementById( "qunit-tests" );
- ol.className = ol.className + " hidepass";
- }
- toolbar.appendChild( filter );
-
- // `label` initialized at top of scope
- label = document.createElement( "label" );
- label.setAttribute( "for", "qunit-filter-pass" );
- label.setAttribute( "title", "Only show tests and assertons that fail. Stored in sessionStorage." );
- label.innerHTML = "Hide passed tests";
- toolbar.appendChild( label );
-
- urlConfigCheckboxesContainer = document.createElement("span");
- urlConfigCheckboxesContainer.innerHTML = urlConfigHtml;
- urlConfigCheckboxes = urlConfigCheckboxesContainer.getElementsByTagName("input");
- // For oldIE support:
- // * Add handlers to the individual elements instead of the container
- // * Use "click" instead of "change"
- // * Fallback from event.target to event.srcElement
- addEvents( urlConfigCheckboxes, "click", function( event ) {
- var params = {},
- target = event.target || event.srcElement;
- params[ target.name ] = target.checked ? true : undefined;
- window.location = QUnit.url( params );
- });
- toolbar.appendChild( urlConfigCheckboxesContainer );
-
- if (numModules > 1) {
- moduleFilter = document.createElement( 'span' );
- moduleFilter.setAttribute( 'id', 'qunit-modulefilter-container' );
- moduleFilter.innerHTML = moduleFilterHtml;
- addEvent( moduleFilter.lastChild, "change", function() {
- var selectBox = moduleFilter.getElementsByTagName("select")[0],
- selectedModule = decodeURIComponent(selectBox.options[selectBox.selectedIndex].value);
-
- window.location = QUnit.url( { module: ( selectedModule === "" ) ? undefined : selectedModule } );
- });
- toolbar.appendChild(moduleFilter);
- }
- }
-
- // `main` initialized at top of scope
- main = id( "qunit-fixture" );
- if ( main ) {
- config.fixture = main.innerHTML;
- }
-
- if ( config.autostart ) {
- QUnit.start();
- }
-};
-
-addEvent( window, "load", QUnit.load );
-
-// `onErrorFnPrev` initialized at top of scope
-// Preserve other handlers
-onErrorFnPrev = window.onerror;
-
-// Cover uncaught exceptions
-// Returning true will surpress the default browser handler,
-// returning false will let it run.
-window.onerror = function ( error, filePath, linerNr ) {
- var ret = false;
- if ( onErrorFnPrev ) {
- ret = onErrorFnPrev( error, filePath, linerNr );
- }
-
- // Treat return value as window.onerror itself does,
- // Only do our handling if not surpressed.
- if ( ret !== true ) {
- if ( QUnit.config.current ) {
- if ( QUnit.config.current.ignoreGlobalErrors ) {
- return true;
- }
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- } else {
- QUnit.test( "global failure", extend( function() {
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- }, { validTest: validTest } ) );
- }
- return false;
- }
-
- return ret;
-};
-
-function done() {
- config.autorun = true;
-
- // Log the last module results
- if ( config.currentModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.currentModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
-
- var i, key,
- banner = id( "qunit-banner" ),
- tests = id( "qunit-tests" ),
- runtime = +new Date() - config.started,
- passed = config.stats.all - config.stats.bad,
- html = [
- "Tests completed in ",
- runtime,
- " milliseconds.
",
- "",
- passed,
- " assertions of ",
- config.stats.all,
- " passed, ",
- config.stats.bad,
- " failed."
- ].join( "" );
-
- if ( banner ) {
- banner.className = ( config.stats.bad ? "qunit-fail" : "qunit-pass" );
- }
-
- if ( tests ) {
- id( "qunit-testresult" ).innerHTML = html;
- }
-
- if ( config.altertitle && typeof document !== "undefined" && document.title ) {
- // show ✖ for good, ✔ for bad suite result in title
- // use escape sequences in case file gets loaded with non-utf-8-charset
- document.title = [
- ( config.stats.bad ? "\u2716" : "\u2714" ),
- document.title.replace( /^[\u2714\u2716] /i, "" )
- ].join( " " );
- }
-
- // clear own sessionStorage items if all tests passed
- if ( config.reorder && defined.sessionStorage && config.stats.bad === 0 ) {
- // `key` & `i` initialized at top of scope
- for ( i = 0; i < sessionStorage.length; i++ ) {
- key = sessionStorage.key( i++ );
- if ( key.indexOf( "qunit-test-" ) === 0 ) {
- sessionStorage.removeItem( key );
- }
- }
- }
-
- // scroll back to top to show results
- if ( window.scrollTo ) {
- window.scrollTo(0, 0);
- }
-
- runLoggingCallbacks( "done", QUnit, {
- failed: config.stats.bad,
- passed: passed,
- total: config.stats.all,
- runtime: runtime
- });
-}
-
-/** @return Boolean: true if this test should be ran */
-function validTest( test ) {
- var include,
- filter = config.filter && config.filter.toLowerCase(),
- module = config.module && config.module.toLowerCase(),
- fullName = (test.module + ": " + test.testName).toLowerCase();
-
- // Internally-generated tests are always valid
- if ( test.callback && test.callback.validTest === validTest ) {
- delete test.callback.validTest;
- return true;
- }
-
- if ( config.testNumber ) {
- return test.testNumber === config.testNumber;
- }
-
- if ( module && ( !test.module || test.module.toLowerCase() !== module ) ) {
- return false;
- }
-
- if ( !filter ) {
- return true;
- }
-
- include = filter.charAt( 0 ) !== "!";
- if ( !include ) {
- filter = filter.slice( 1 );
- }
-
- // If the filter matches, we need to honour include
- if ( fullName.indexOf( filter ) !== -1 ) {
- return include;
- }
-
- // Otherwise, do the opposite
- return !include;
-}
-
-// so far supports only Firefox, Chrome and Opera (buggy), Safari (for real exceptions)
-// Later Safari and IE10 are supposed to support error.stack as well
-// See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack
-function extractStacktrace( e, offset ) {
- offset = offset === undefined ? 3 : offset;
-
- var stack, include, i;
-
- if ( e.stacktrace ) {
- // Opera
- return e.stacktrace.split( "\n" )[ offset + 3 ];
- } else if ( e.stack ) {
- // Firefox, Chrome
- stack = e.stack.split( "\n" );
- if (/^error$/i.test( stack[0] ) ) {
- stack.shift();
- }
- if ( fileName ) {
- include = [];
- for ( i = offset; i < stack.length; i++ ) {
- if ( stack[ i ].indexOf( fileName ) !== -1 ) {
- break;
- }
- include.push( stack[ i ] );
- }
- if ( include.length ) {
- return include.join( "\n" );
- }
- }
- return stack[ offset ];
- } else if ( e.sourceURL ) {
- // Safari, PhantomJS
- // hopefully one day Safari provides actual stacktraces
- // exclude useless self-reference for generated Error objects
- if ( /qunit.js$/.test( e.sourceURL ) ) {
- return;
- }
- // for actual exceptions, this is useful
- return e.sourceURL + ":" + e.line;
- }
-}
-function sourceFromStacktrace( offset ) {
- try {
- throw new Error();
- } catch ( e ) {
- return extractStacktrace( e, offset );
- }
-}
-
-/**
- * Escape text for attribute or text content.
- */
-function escapeText( s ) {
- if ( !s ) {
- return "";
- }
- s = s + "";
- // Both single quotes and double quotes (for attributes)
- return s.replace( /['"<>&]/g, function( s ) {
- switch( s ) {
- case '\'':
- return ''';
- case '"':
- return '"';
- case '<':
- return '<';
- case '>':
- return '>';
- case '&':
- return '&';
- }
- });
-}
-
-function synchronize( callback, last ) {
- config.queue.push( callback );
-
- if ( config.autorun && !config.blocking ) {
- process( last );
- }
-}
-
-function process( last ) {
- function next() {
- process( last );
- }
- var start = new Date().getTime();
- config.depth = config.depth ? config.depth + 1 : 1;
-
- while ( config.queue.length && !config.blocking ) {
- if ( !defined.setTimeout || config.updateRate <= 0 || ( ( new Date().getTime() - start ) < config.updateRate ) ) {
- config.queue.shift()();
- } else {
- window.setTimeout( next, 13 );
- break;
- }
- }
- config.depth--;
- if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) {
- done();
- }
-}
-
-function saveGlobal() {
- config.pollution = [];
-
- if ( config.noglobals ) {
- for ( var key in window ) {
- // in Opera sometimes DOM element ids show up here, ignore them
- if ( !hasOwn.call( window, key ) || /^qunit-test-output/.test( key ) ) {
- continue;
- }
- config.pollution.push( key );
- }
- }
-}
-
-function checkPollution() {
- var newGlobals,
- deletedGlobals,
- old = config.pollution;
-
- saveGlobal();
-
- newGlobals = diff( config.pollution, old );
- if ( newGlobals.length > 0 ) {
- QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join(", ") );
- }
-
- deletedGlobals = diff( old, config.pollution );
- if ( deletedGlobals.length > 0 ) {
- QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join(", ") );
- }
-}
-
-// returns a new Array with the elements that are in a but not in b
-function diff( a, b ) {
- var i, j,
- result = a.slice();
-
- for ( i = 0; i < result.length; i++ ) {
- for ( j = 0; j < b.length; j++ ) {
- if ( result[i] === b[j] ) {
- result.splice( i, 1 );
- i--;
- break;
- }
- }
- }
- return result;
-}
-
-function extend( a, b ) {
- for ( var prop in b ) {
- if ( b[ prop ] === undefined ) {
- delete a[ prop ];
-
- // Avoid "Member not found" error in IE8 caused by setting window.constructor
- } else if ( prop !== "constructor" || a !== window ) {
- a[ prop ] = b[ prop ];
- }
- }
-
- return a;
-}
-
-/**
- * @param {HTMLElement} elem
- * @param {string} type
- * @param {Function} fn
- */
-function addEvent( elem, type, fn ) {
- // Standards-based browsers
- if ( elem.addEventListener ) {
- elem.addEventListener( type, fn, false );
- // IE
- } else {
- elem.attachEvent( "on" + type, fn );
- }
-}
-
-/**
- * @param {Array|NodeList} elems
- * @param {string} type
- * @param {Function} fn
- */
-function addEvents( elems, type, fn ) {
- var i = elems.length;
- while ( i-- ) {
- addEvent( elems[i], type, fn );
- }
-}
-
-function hasClass( elem, name ) {
- return (" " + elem.className + " ").indexOf(" " + name + " ") > -1;
-}
-
-function addClass( elem, name ) {
- if ( !hasClass( elem, name ) ) {
- elem.className += (elem.className ? " " : "") + name;
- }
-}
-
-function removeClass( elem, name ) {
- var set = " " + elem.className + " ";
- // Class name may appear multiple times
- while ( set.indexOf(" " + name + " ") > -1 ) {
- set = set.replace(" " + name + " " , " ");
- }
- // If possible, trim it for prettiness, but not neccecarily
- elem.className = window.jQuery ? jQuery.trim( set ) : ( set.trim ? set.trim() : set );
-}
-
-function id( name ) {
- return !!( typeof document !== "undefined" && document && document.getElementById ) &&
- document.getElementById( name );
-}
-
-function registerLoggingCallback( key ) {
- return function( callback ) {
- config[key].push( callback );
- };
-}
-
-// Supports deprecated method of completely overwriting logging callbacks
-function runLoggingCallbacks( key, scope, args ) {
- var i, callbacks;
- if ( QUnit.hasOwnProperty( key ) ) {
- QUnit[ key ].call(scope, args );
- } else {
- callbacks = config[ key ];
- for ( i = 0; i < callbacks.length; i++ ) {
- callbacks[ i ].call( scope, args );
- }
- }
-}
-
-// Test for equality any JavaScript type.
-// Author: Philippe Rathé
-QUnit.equiv = (function() {
-
- // Call the o related callback with the given arguments.
- function bindCallbacks( o, callbacks, args ) {
- var prop = QUnit.objectType( o );
- if ( prop ) {
- if ( QUnit.objectType( callbacks[ prop ] ) === "function" ) {
- return callbacks[ prop ].apply( callbacks, args );
- } else {
- return callbacks[ prop ]; // or undefined
- }
- }
- }
-
- // the real equiv function
- var innerEquiv,
- // stack to decide between skip/abort functions
- callers = [],
- // stack to avoiding loops from circular referencing
- parents = [],
-
- getProto = Object.getPrototypeOf || function ( obj ) {
- return obj.__proto__;
- },
- callbacks = (function () {
-
- // for string, boolean, number and null
- function useStrictEquality( b, a ) {
- /*jshint eqeqeq:false */
- if ( b instanceof a.constructor || a instanceof b.constructor ) {
- // to catch short annotaion VS 'new' annotation of a
- // declaration
- // e.g. var i = 1;
- // var j = new Number(1);
- return a == b;
- } else {
- return a === b;
- }
- }
-
- return {
- "string": useStrictEquality,
- "boolean": useStrictEquality,
- "number": useStrictEquality,
- "null": useStrictEquality,
- "undefined": useStrictEquality,
-
- "nan": function( b ) {
- return isNaN( b );
- },
-
- "date": function( b, a ) {
- return QUnit.objectType( b ) === "date" && a.valueOf() === b.valueOf();
- },
-
- "regexp": function( b, a ) {
- return QUnit.objectType( b ) === "regexp" &&
- // the regex itself
- a.source === b.source &&
- // and its modifers
- a.global === b.global &&
- // (gmi) ...
- a.ignoreCase === b.ignoreCase &&
- a.multiline === b.multiline &&
- a.sticky === b.sticky;
- },
-
- // - skip when the property is a method of an instance (OOP)
- // - abort otherwise,
- // initial === would have catch identical references anyway
- "function": function() {
- var caller = callers[callers.length - 1];
- return caller !== Object && typeof caller !== "undefined";
- },
-
- "array": function( b, a ) {
- var i, j, len, loop;
-
- // b could be an object literal here
- if ( QUnit.objectType( b ) !== "array" ) {
- return false;
- }
-
- len = a.length;
- if ( len !== b.length ) {
- // safe and faster
- return false;
- }
-
- // track reference to avoid circular references
- parents.push( a );
- for ( i = 0; i < len; i++ ) {
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- loop = true;// dont rewalk array
- }
- }
- if ( !loop && !innerEquiv(a[i], b[i]) ) {
- parents.pop();
- return false;
- }
- }
- parents.pop();
- return true;
- },
-
- "object": function( b, a ) {
- var i, j, loop,
- // Default to true
- eq = true,
- aProperties = [],
- bProperties = [];
-
- // comparing constructors is more strict than using
- // instanceof
- if ( a.constructor !== b.constructor ) {
- // Allow objects with no prototype to be equivalent to
- // objects with Object as their constructor.
- if ( !(( getProto(a) === null && getProto(b) === Object.prototype ) ||
- ( getProto(b) === null && getProto(a) === Object.prototype ) ) ) {
- return false;
- }
- }
-
- // stack constructor before traversing properties
- callers.push( a.constructor );
- // track reference to avoid circular references
- parents.push( a );
-
- for ( i in a ) { // be strict: don't ensures hasOwnProperty
- // and go deep
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- // don't go down the same path twice
- loop = true;
- }
- }
- aProperties.push(i); // collect a's properties
-
- if (!loop && !innerEquiv( a[i], b[i] ) ) {
- eq = false;
- break;
- }
- }
-
- callers.pop(); // unstack, we are done
- parents.pop();
-
- for ( i in b ) {
- bProperties.push( i ); // collect b's properties
- }
-
- // Ensures identical properties name
- return eq && innerEquiv( aProperties.sort(), bProperties.sort() );
- }
- };
- }());
-
- innerEquiv = function() { // can take multiple arguments
- var args = [].slice.apply( arguments );
- if ( args.length < 2 ) {
- return true; // end transition
- }
-
- return (function( a, b ) {
- if ( a === b ) {
- return true; // catch the most you can
- } else if ( a === null || b === null || typeof a === "undefined" ||
- typeof b === "undefined" ||
- QUnit.objectType(a) !== QUnit.objectType(b) ) {
- return false; // don't lose time with error prone cases
- } else {
- return bindCallbacks(a, callbacks, [ b, a ]);
- }
-
- // apply transition with (1..n) arguments
- }( args[0], args[1] ) && arguments.callee.apply( this, args.splice(1, args.length - 1 )) );
- };
-
- return innerEquiv;
-}());
-
-/**
- * jsDump Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com |
- * http://flesler.blogspot.com Licensed under BSD
- * (http://www.opensource.org/licenses/bsd-license.php) Date: 5/15/2008
- *
- * @projectDescription Advanced and extensible data dumping for Javascript.
- * @version 1.0.0
- * @author Ariel Flesler
- * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html}
- */
-QUnit.jsDump = (function() {
- function quote( str ) {
- return '"' + str.toString().replace( /"/g, '\\"' ) + '"';
- }
- function literal( o ) {
- return o + "";
- }
- function join( pre, arr, post ) {
- var s = jsDump.separator(),
- base = jsDump.indent(),
- inner = jsDump.indent(1);
- if ( arr.join ) {
- arr = arr.join( "," + s + inner );
- }
- if ( !arr ) {
- return pre + post;
- }
- return [ pre, inner + arr, base + post ].join(s);
- }
- function array( arr, stack ) {
- var i = arr.length, ret = new Array(i);
- this.up();
- while ( i-- ) {
- ret[i] = this.parse( arr[i] , undefined , stack);
- }
- this.down();
- return join( "[", ret, "]" );
- }
-
- var reName = /^function (\w+)/,
- jsDump = {
- // type is used mostly internally, you can fix a (custom)type in advance
- parse: function( obj, type, stack ) {
- stack = stack || [ ];
- var inStack, res,
- parser = this.parsers[ type || this.typeOf(obj) ];
-
- type = typeof parser;
- inStack = inArray( obj, stack );
-
- if ( inStack !== -1 ) {
- return "recursion(" + (inStack - stack.length) + ")";
- }
- if ( type === "function" ) {
- stack.push( obj );
- res = parser.call( this, obj, stack );
- stack.pop();
- return res;
- }
- return ( type === "string" ) ? parser : this.parsers.error;
- },
- typeOf: function( obj ) {
- var type;
- if ( obj === null ) {
- type = "null";
- } else if ( typeof obj === "undefined" ) {
- type = "undefined";
- } else if ( QUnit.is( "regexp", obj) ) {
- type = "regexp";
- } else if ( QUnit.is( "date", obj) ) {
- type = "date";
- } else if ( QUnit.is( "function", obj) ) {
- type = "function";
- } else if ( typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined" ) {
- type = "window";
- } else if ( obj.nodeType === 9 ) {
- type = "document";
- } else if ( obj.nodeType ) {
- type = "node";
- } else if (
- // native arrays
- toString.call( obj ) === "[object Array]" ||
- // NodeList objects
- ( typeof obj.length === "number" && typeof obj.item !== "undefined" && ( obj.length ? obj.item(0) === obj[0] : ( obj.item( 0 ) === null && typeof obj[0] === "undefined" ) ) )
- ) {
- type = "array";
- } else if ( obj.constructor === Error.prototype.constructor ) {
- type = "error";
- } else {
- type = typeof obj;
- }
- return type;
- },
- separator: function() {
- return this.multiline ? this.HTML ? "
" : "\n" : this.HTML ? " " : " ";
- },
- // extra can be a number, shortcut for increasing-calling-decreasing
- indent: function( extra ) {
- if ( !this.multiline ) {
- return "";
- }
- var chr = this.indentChar;
- if ( this.HTML ) {
- chr = chr.replace( /\t/g, " " ).replace( / /g, " " );
- }
- return new Array( this._depth_ + (extra||0) ).join(chr);
- },
- up: function( a ) {
- this._depth_ += a || 1;
- },
- down: function( a ) {
- this._depth_ -= a || 1;
- },
- setParser: function( name, parser ) {
- this.parsers[name] = parser;
- },
- // The next 3 are exposed so you can use them
- quote: quote,
- literal: literal,
- join: join,
- //
- _depth_: 1,
- // This is the list of parsers, to modify them, use jsDump.setParser
- parsers: {
- window: "[Window]",
- document: "[Document]",
- error: function(error) {
- return "Error(\"" + error.message + "\")";
- },
- unknown: "[Unknown]",
- "null": "null",
- "undefined": "undefined",
- "function": function( fn ) {
- var ret = "function",
- // functions never have name in IE
- name = "name" in fn ? fn.name : (reName.exec(fn) || [])[1];
-
- if ( name ) {
- ret += " " + name;
- }
- ret += "( ";
-
- ret = [ ret, QUnit.jsDump.parse( fn, "functionArgs" ), "){" ].join( "" );
- return join( ret, QUnit.jsDump.parse(fn,"functionCode" ), "}" );
- },
- array: array,
- nodelist: array,
- "arguments": array,
- object: function( map, stack ) {
- var ret = [ ], keys, key, val, i;
- QUnit.jsDump.up();
- keys = [];
- for ( key in map ) {
- keys.push( key );
- }
- keys.sort();
- for ( i = 0; i < keys.length; i++ ) {
- key = keys[ i ];
- val = map[ key ];
- ret.push( QUnit.jsDump.parse( key, "key" ) + ": " + QUnit.jsDump.parse( val, undefined, stack ) );
- }
- QUnit.jsDump.down();
- return join( "{", ret, "}" );
- },
- node: function( node ) {
- var len, i, val,
- open = QUnit.jsDump.HTML ? "<" : "<",
- close = QUnit.jsDump.HTML ? ">" : ">",
- tag = node.nodeName.toLowerCase(),
- ret = open + tag,
- attrs = node.attributes;
-
- if ( attrs ) {
- for ( i = 0, len = attrs.length; i < len; i++ ) {
- val = attrs[i].nodeValue;
- // IE6 includes all attributes in .attributes, even ones not explicitly set.
- // Those have values like undefined, null, 0, false, "" or "inherit".
- if ( val && val !== "inherit" ) {
- ret += " " + attrs[i].nodeName + "=" + QUnit.jsDump.parse( val, "attribute" );
- }
- }
- }
- ret += close;
-
- // Show content of TextNode or CDATASection
- if ( node.nodeType === 3 || node.nodeType === 4 ) {
- ret += node.nodeValue;
- }
-
- return ret + open + "/" + tag + close;
- },
- // function calls it internally, it's the arguments part of the function
- functionArgs: function( fn ) {
- var args,
- l = fn.length;
-
- if ( !l ) {
- return "";
- }
-
- args = new Array(l);
- while ( l-- ) {
- // 97 is 'a'
- args[l] = String.fromCharCode(97+l);
- }
- return " " + args.join( ", " ) + " ";
- },
- // object calls it internally, the key part of an item in a map
- key: quote,
- // function calls it internally, it's the content of the function
- functionCode: "[code]",
- // node calls it internally, it's an html attribute value
- attribute: quote,
- string: quote,
- date: quote,
- regexp: literal,
- number: literal,
- "boolean": literal
- },
- // if true, entities are escaped ( <, >, \t, space and \n )
- HTML: false,
- // indentation unit
- indentChar: " ",
- // if true, items in a collection, are separated by a \n, else just a space.
- multiline: true
- };
-
- return jsDump;
-}());
-
-// from jquery.js
-function inArray( elem, array ) {
- if ( array.indexOf ) {
- return array.indexOf( elem );
- }
-
- for ( var i = 0, length = array.length; i < length; i++ ) {
- if ( array[ i ] === elem ) {
- return i;
- }
- }
-
- return -1;
-}
-
-/*
- * Javascript Diff Algorithm
- * By John Resig (http://ejohn.org/)
- * Modified by Chu Alan "sprite"
- *
- * Released under the MIT license.
- *
- * More Info:
- * http://ejohn.org/projects/javascript-diff-algorithm/
- *
- * Usage: QUnit.diff(expected, actual)
- *
- * QUnit.diff( "the quick brown fox jumped over", "the quick fox jumps over" ) == "the quick brown fox jumped jumps over"
- */
-QUnit.diff = (function() {
- /*jshint eqeqeq:false, eqnull:true */
- function diff( o, n ) {
- var i,
- ns = {},
- os = {};
-
- for ( i = 0; i < n.length; i++ ) {
- if ( !hasOwn.call( ns, n[i] ) ) {
- ns[ n[i] ] = {
- rows: [],
- o: null
- };
- }
- ns[ n[i] ].rows.push( i );
- }
-
- for ( i = 0; i < o.length; i++ ) {
- if ( !hasOwn.call( os, o[i] ) ) {
- os[ o[i] ] = {
- rows: [],
- n: null
- };
- }
- os[ o[i] ].rows.push( i );
- }
-
- for ( i in ns ) {
- if ( !hasOwn.call( ns, i ) ) {
- continue;
- }
- if ( ns[i].rows.length === 1 && hasOwn.call( os, i ) && os[i].rows.length === 1 ) {
- n[ ns[i].rows[0] ] = {
- text: n[ ns[i].rows[0] ],
- row: os[i].rows[0]
- };
- o[ os[i].rows[0] ] = {
- text: o[ os[i].rows[0] ],
- row: ns[i].rows[0]
- };
- }
- }
-
- for ( i = 0; i < n.length - 1; i++ ) {
- if ( n[i].text != null && n[ i + 1 ].text == null && n[i].row + 1 < o.length && o[ n[i].row + 1 ].text == null &&
- n[ i + 1 ] == o[ n[i].row + 1 ] ) {
-
- n[ i + 1 ] = {
- text: n[ i + 1 ],
- row: n[i].row + 1
- };
- o[ n[i].row + 1 ] = {
- text: o[ n[i].row + 1 ],
- row: i + 1
- };
- }
- }
-
- for ( i = n.length - 1; i > 0; i-- ) {
- if ( n[i].text != null && n[ i - 1 ].text == null && n[i].row > 0 && o[ n[i].row - 1 ].text == null &&
- n[ i - 1 ] == o[ n[i].row - 1 ]) {
-
- n[ i - 1 ] = {
- text: n[ i - 1 ],
- row: n[i].row - 1
- };
- o[ n[i].row - 1 ] = {
- text: o[ n[i].row - 1 ],
- row: i - 1
- };
- }
- }
-
- return {
- o: o,
- n: n
- };
- }
-
- return function( o, n ) {
- o = o.replace( /\s+$/, "" );
- n = n.replace( /\s+$/, "" );
-
- var i, pre,
- str = "",
- out = diff( o === "" ? [] : o.split(/\s+/), n === "" ? [] : n.split(/\s+/) ),
- oSpace = o.match(/\s+/g),
- nSpace = n.match(/\s+/g);
-
- if ( oSpace == null ) {
- oSpace = [ " " ];
- }
- else {
- oSpace.push( " " );
- }
-
- if ( nSpace == null ) {
- nSpace = [ " " ];
- }
- else {
- nSpace.push( " " );
- }
-
- if ( out.n.length === 0 ) {
- for ( i = 0; i < out.o.length; i++ ) {
- str += "" + out.o[i] + oSpace[i] + "";
- }
- }
- else {
- if ( out.n[0].text == null ) {
- for ( n = 0; n < out.o.length && out.o[n].text == null; n++ ) {
- str += "" + out.o[n] + oSpace[n] + "";
- }
- }
-
- for ( i = 0; i < out.n.length; i++ ) {
- if (out.n[i].text == null) {
- str += "" + out.n[i] + nSpace[i] + "";
- }
- else {
- // `pre` initialized at top of scope
- pre = "";
-
- for ( n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++ ) {
- pre += "" + out.o[n] + oSpace[n] + "";
- }
- str += " " + out.n[i].text + nSpace[i] + pre;
- }
- }
- }
-
- return str;
- };
-}());
-
-// for CommonJS enviroments, export everything
-if ( typeof exports !== "undefined" ) {
- extend( exports, QUnit );
-}
-
-// get at whatever the global object is, like window in browsers
-}( (function() {return this;}.call()) ));
diff --git a/test/lib/require.js b/test/lib/require.js
deleted file mode 100644
index 987f865..0000000
--- a/test/lib/require.js
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- RequireJS 2.1.5 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.
- Available via the MIT or new BSD license.
- see: http://github.com/jrburke/requirejs for details
-*/
-var requirejs,require,define;
-(function(aa){function I(b){return"[object Function]"===L.call(b)}function J(b){return"[object Array]"===L.call(b)}function y(b,c){if(b){var d;for(d=0;dthis.depCount&&!this.defined){if(I(n)){if(this.events.error)try{e=i.execCb(c,n,b,e)}catch(d){a=d}else e=i.execCb(c,n,b,e);this.map.isDefine&&((b=this.module)&&void 0!==b.exports&&b.exports!==this.exports?e=b.exports:void 0===e&&this.usingExports&&(e=this.exports));if(a)return a.requireMap=this.map,a.requireModules=[this.map.id],a.requireType="define",v(this.error=
-a)}else e=n;this.exports=e;if(this.map.isDefine&&!this.ignore&&(q[c]=e,l.onResourceLoad))l.onResourceLoad(i,this.map,this.depMaps);x(c);this.defined=!0}this.defining=!1;this.defined&&!this.defineEmitted&&(this.defineEmitted=!0,this.emit("defined",this.exports),this.defineEmitComplete=!0)}}else this.fetch()}},callPlugin:function(){var a=this.map,b=a.id,d=j(a.prefix);this.depMaps.push(d);t(d,"defined",u(this,function(e){var n,d;d=this.map.name;var g=this.map.parentMap?this.map.parentMap.name:null,h=
-i.makeRequire(a.parentMap,{enableBuildCallback:!0});if(this.map.unnormalized){if(e.normalize&&(d=e.normalize(d,function(a){return c(a,g,!0)})||""),e=j(a.prefix+"!"+d,this.map.parentMap),t(e,"defined",u(this,function(a){this.init([],function(){return a},null,{enabled:!0,ignore:!0})})),d=m(p,e.id)){this.depMaps.push(e);if(this.events.error)d.on("error",u(this,function(a){this.emit("error",a)}));d.enable()}}else n=u(this,function(a){this.init([],function(){return a},null,{enabled:!0})}),n.error=u(this,
-function(a){this.inited=!0;this.error=a;a.requireModules=[b];G(p,function(a){0===a.map.id.indexOf(b+"_unnormalized")&&x(a.map.id)});v(a)}),n.fromText=u(this,function(e,c){var d=a.name,g=j(d),C=O;c&&(e=c);C&&(O=!1);r(g);s(k.config,b)&&(k.config[d]=k.config[b]);try{l.exec(e)}catch(ca){return v(B("fromtexteval","fromText eval for "+b+" failed: "+ca,ca,[b]))}C&&(O=!0);this.depMaps.push(g);i.completeLoad(d);h([d],n)}),e.load(a.name,h,n,k)}));i.enable(d,this);this.pluginMaps[d.id]=d},enable:function(){V[this.map.id]=
-this;this.enabling=this.enabled=!0;y(this.depMaps,u(this,function(a,b){var c,e;if("string"===typeof a){a=j(a,this.map.isDefine?this.map:this.map.parentMap,!1,!this.skipMap);this.depMaps[b]=a;if(c=m(N,a.id)){this.depExports[b]=c(this);return}this.depCount+=1;t(a,"defined",u(this,function(a){this.defineDep(b,a);this.check()}));this.errback&&t(a,"error",this.errback)}c=a.id;e=p[c];!s(N,c)&&(e&&!e.enabled)&&i.enable(a,this)}));G(this.pluginMaps,u(this,function(a){var b=m(p,a.id);b&&!b.enabled&&i.enable(a,
-this)}));this.enabling=!1;this.check()},on:function(a,b){var c=this.events[a];c||(c=this.events[a]=[]);c.push(b)},emit:function(a,b){y(this.events[a],function(a){a(b)});"error"===a&&delete this.events[a]}};i={config:k,contextName:b,registry:p,defined:q,urlFetched:U,defQueue:H,Module:Z,makeModuleMap:j,nextTick:l.nextTick,onError:v,configure:function(a){a.baseUrl&&"/"!==a.baseUrl.charAt(a.baseUrl.length-1)&&(a.baseUrl+="/");var b=k.pkgs,c=k.shim,e={paths:!0,config:!0,map:!0};G(a,function(a,b){e[b]?
-"map"===b?(k.map||(k.map={}),R(k[b],a,!0,!0)):R(k[b],a,!0):k[b]=a});a.shim&&(G(a.shim,function(a,b){J(a)&&(a={deps:a});if((a.exports||a.init)&&!a.exportsFn)a.exportsFn=i.makeShimExports(a);c[b]=a}),k.shim=c);a.packages&&(y(a.packages,function(a){a="string"===typeof a?{name:a}:a;b[a.name]={name:a.name,location:a.location||a.name,main:(a.main||"main").replace(ja,"").replace(ea,"")}}),k.pkgs=b);G(p,function(a,b){!a.inited&&!a.map.unnormalized&&(a.map=j(b))});if(a.deps||a.callback)i.require(a.deps||[],
-a.callback)},makeShimExports:function(a){return function(){var b;a.init&&(b=a.init.apply(aa,arguments));return b||a.exports&&ba(a.exports)}},makeRequire:function(a,f){function d(e,c,h){var g,k;f.enableBuildCallback&&(c&&I(c))&&(c.__requireJsBuild=!0);if("string"===typeof e){if(I(c))return v(B("requireargs","Invalid require call"),h);if(a&&s(N,e))return N[e](p[a.id]);if(l.get)return l.get(i,e,a,d);g=j(e,a,!1,!0);g=g.id;return!s(q,g)?v(B("notloaded",'Module name "'+g+'" has not been loaded yet for context: '+
-b+(a?"":". Use require([])"))):q[g]}L();i.nextTick(function(){L();k=r(j(null,a));k.skipMap=f.skipMap;k.init(e,c,h,{enabled:!0});D()});return d}f=f||{};R(d,{isBrowser:A,toUrl:function(b){var d,f=b.lastIndexOf("."),g=b.split("/")[0];if(-1!==f&&(!("."===g||".."===g)||1h.attachEvent.toString().indexOf("[native code"))&&!Y?(O=!0,h.attachEvent("onreadystatechange",b.onScriptLoad)):(h.addEventListener("load",b.onScriptLoad,!1),h.addEventListener("error",b.onScriptError,!1)),h.src=d,K=h,D?x.insertBefore(h,D):x.appendChild(h),K=null,h;if(da)try{importScripts(d),b.completeLoad(c)}catch(j){b.onError(B("importscripts","importScripts failed for "+c+" at "+d,j,[c]))}};A&&M(document.getElementsByTagName("script"),function(b){x||(x=
-b.parentNode);if(t=b.getAttribute("data-main"))return r.baseUrl||(E=t.split("/"),Q=E.pop(),fa=E.length?E.join("/")+"/":"./",r.baseUrl=fa,t=Q),t=t.replace(ea,""),r.deps=r.deps?r.deps.concat(t):[t],!0});define=function(b,c,d){var l,h;"string"!==typeof b&&(d=c,c=b,b=null);J(c)||(d=c,c=[]);!c.length&&I(d)&&d.length&&(d.toString().replace(la,"").replace(ma,function(b,d){c.push(d)}),c=(1===d.length?["require"]:["require","exports","module"]).concat(c));if(O){if(!(l=K))P&&"interactive"===P.readyState||M(document.getElementsByTagName("script"),
-function(b){if("interactive"===b.readyState)return P=b}),l=P;l&&(b||(b=l.getAttribute("data-requiremodule")),h=F[l.getAttribute("data-requirecontext")])}(h?h.defQueue:T).push([b,c,d])};define.amd={jQuery:!0};l.exec=function(b){return eval(b)};l(r)}})(this);
diff --git a/test/lib/resemble.js b/test/lib/resemble.js
new file mode 100644
index 0000000..1cb8c29
--- /dev/null
+++ b/test/lib/resemble.js
@@ -0,0 +1,535 @@
+/*
+Author: James Cryer
+Company: Huddle
+Last updated date: 21 Feb 2013
+URL: https://github.com/Huddle/Resemble.js
+*/
+
+(function(_this){
+ 'use strict';
+
+ _this['resemble'] = function( fileData ){
+
+ var data = {};
+ var images = [];
+ var updateCallbackArray = [];
+
+ var tolerance = { // between 0 and 255
+ red: 16,
+ green: 16,
+ blue: 16,
+ minBrightness: 16,
+ maxBrightness: 240
+ };
+
+ var ignoreAntialiasing = false;
+ var ignoreColors = false;
+
+ function triggerDataUpdate(){
+ var len = updateCallbackArray.length;
+ var i;
+ for(i=0;i tolerance.maxBrightness;
+ }
+
+ function getHue(r,g,b){
+
+ r = r / 255;
+ g = g / 255;
+ b = b / 255;
+ var max = Math.max(r, g, b), min = Math.min(r, g, b);
+ var h;
+ var d;
+
+ if (max == min){
+ h = 0; // achromatic
+ } else{
+ d = max - min;
+ switch(max){
+ case r: h = (g - b) / d + (g < b ? 6 : 0); break;
+ case g: h = (b - r) / d + 2; break;
+ case b: h = (r - g) / d + 4; break;
+ }
+ h /= 6;
+ }
+
+ return h;
+ }
+
+ function isAntialiased(sourcePix, data, cacheSet, verticalPos, horizontalPos, width){
+ var offset;
+ var targetPix;
+ var distance = 1;
+ var i;
+ var j;
+ var hasHighContrastSibling = 0;
+ var hasSiblingWithDifferentHue = 0;
+ var hasEquivilantSibling = 0;
+
+ addHueInfo(sourcePix);
+
+ for (i = distance*-1; i <= distance; i++){
+ for (j = distance*-1; j <= distance; j++){
+
+ if(i===0 && j===0){
+ // ignore source pixel
+ } else {
+
+ offset = ((verticalPos+j)*width + (horizontalPos+i)) * 4;
+ targetPix = getPixelInfo(data, offset, cacheSet);
+
+ if(targetPix === null){
+ continue;
+ }
+
+ addBrightnessInfo(targetPix);
+ addHueInfo(targetPix);
+
+ if( isContrasting(sourcePix, targetPix) ){
+ hasHighContrastSibling++;
+ }
+
+ if( isRGBSame(sourcePix,targetPix) ){
+ hasEquivilantSibling++;
+ }
+
+ if( Math.abs(targetPix.h - sourcePix.h) > 0.3 ){
+ hasSiblingWithDifferentHue++;
+ }
+
+ if( hasSiblingWithDifferentHue > 1 || hasHighContrastSibling > 1){
+ return true;
+ }
+ }
+ }
+ }
+
+ if(hasEquivilantSibling < 2){
+ return true;
+ }
+
+ return false;
+ }
+
+ function errorPixel(px, offset){
+ px[offset] = 255; //r
+ px[offset + 1] = 0; //g
+ px[offset + 2] = 255; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyPixel(px, offset, data){
+ px[offset] = data.r; //r
+ px[offset + 1] = data.g; //g
+ px[offset + 2] = data.b; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyGrayScalePixel(px, offset, data){
+ px[offset] = data.brightness; //r
+ px[offset + 1] = data.brightness; //g
+ px[offset + 2] = data.brightness; //b
+ px[offset + 3] = 255; //a
+ }
+
+
+ function getPixelInfo(data, offset, cacheSet){
+ var r;
+ var g;
+ var b;
+ var d;
+
+ if(typeof data[offset] !== 'undefined'){
+ r = data[offset];
+ g = data[offset+1];
+ b = data[offset+2];
+ d = {
+ r: r,
+ g: g,
+ b: b
+ };
+
+ return d;
+ } else {
+ return null;
+ }
+ }
+
+ function addBrightnessInfo(data){
+ data.brightness = getBrightness(data.r,data.g,data.b); // 'corrected' lightness
+ }
+
+ function addHueInfo(data){
+ data.h = getHue(data.r,data.g,data.b);
+ }
+
+ function analyseImages(img1, img2, width, height){
+
+ var hiddenCanvas = document.createElement('canvas');
+
+ var data1 = img1.data;
+ var data2 = img2.data;
+
+ hiddenCanvas.width = width;
+ hiddenCanvas.height = height;
+
+ var context = hiddenCanvas.getContext('2d');
+ var imgd = context.createImageData(width,height);
+ var targetPix = imgd.data;
+
+ var mismatchCount = 0;
+
+ var time = Date.now();
+
+ var skip;
+
+ if( (width > 1200 || height > 1200) && ignoreAntialiasing){
+ skip = 6;
+ }
+
+ loop(height, width, function(verticalPos, horizontalPos){
+
+ if(skip){ // only skip if the image isn't small
+ if(verticalPos % skip === 0 || horizontalPos % skip === 0){
+ return;
+ }
+ }
+
+ var offset = (verticalPos*width + horizontalPos) * 4;
+ var pixel1 = getPixelInfo(data1, offset, 1);
+ var pixel2 = getPixelInfo(data2, offset, 2);
+
+ if(pixel1 === null || pixel2 === null){
+ return;
+ }
+
+ if (ignoreColors){
+
+ addBrightnessInfo(pixel1);
+ addBrightnessInfo(pixel2);
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ return;
+ }
+
+ if( isRGBSimilar(pixel1, pixel2) ){
+ copyPixel(targetPix, offset, pixel2);
+
+ } else if( ignoreAntialiasing && (
+ addBrightnessInfo(pixel1), // jit pixel info augmentation looks a little weird, sorry.
+ addBrightnessInfo(pixel2),
+ isAntialiased(pixel1, data1, 1, verticalPos, horizontalPos, width) ||
+ isAntialiased(pixel2, data2, 2, verticalPos, horizontalPos, width)
+ )){
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+
+ });
+
+ data.misMatchPercentage = (mismatchCount / (height*width) * 100).toFixed(2);
+ data.analysisTime = Date.now() - time;
+
+ data.getImageDataUrl = function(text){
+ var barHeight = 0;
+
+ if(text){
+ barHeight = addLabel(text,context,hiddenCanvas);
+ }
+
+ context.putImageData(imgd, 0, barHeight);
+
+ return hiddenCanvas.toDataURL("image/png");
+ };
+ }
+
+ function addLabel(text, context, hiddenCanvas){
+ var textPadding = 2;
+
+ context.font = '12px sans-serif';
+
+ var textWidth = context.measureText(text).width + textPadding*2;
+ var barHeight = 22;
+
+ if(textWidth > hiddenCanvas.width){
+ hiddenCanvas.width = textWidth;
+ }
+
+ hiddenCanvas.height += barHeight;
+
+ context.fillStyle = "#666";
+ context.fillRect(0,0,hiddenCanvas.width,barHeight -4);
+ context.fillStyle = "#fff";
+ context.fillRect(0,barHeight -4,hiddenCanvas.width, 4);
+
+ context.fillStyle = "#fff";
+ context.textBaseline = "top";
+ context.font = '12px sans-serif';
+ context.fillText(text, textPadding, 1);
+
+ return barHeight;
+ }
+
+ function normalise(img, w, h){
+ var c;
+ var context;
+
+ if(img.height < h || img.width < w){
+ c = document.createElement('canvas');
+ c.width = w;
+ c.height = h;
+ context = c.getContext('2d');
+ context.putImageData(img, 0, 0);
+ return context.getImageData(0, 0, w, h);
+ }
+
+ return img;
+ }
+
+ function compare(one, two){
+
+ function onceWeHaveBoth(){
+ var width;
+ var height;
+ if(images.length === 2){
+ width = images[0].width > images[1].width ? images[0].width : images[1].width;
+ height = images[0].height > images[1].height ? images[0].height : images[1].height;
+
+ if( (images[0].width === images[1].width) && (images[0].height === images[1].height) ){
+ data.isSameDimensions = true;
+ } else {
+ data.isSameDimensions = false;
+ }
+
+ analyseImages( normalise(images[0],width, height), normalise(images[1],width, height), width, height);
+
+ triggerDataUpdate();
+ }
+ }
+
+ images = [];
+ loadImageData(one, onceWeHaveBoth);
+ loadImageData(two, onceWeHaveBoth);
+ }
+
+ function getCompareApi(param){
+
+ var secondFileData,
+ hasMethod = typeof param === 'function';
+
+ if( !hasMethod ){
+ // assume it's file data
+ secondFileData = param;
+ }
+
+ var self = {
+ ignoreNothing: function(){
+
+ tolerance.red = 16;
+ tolerance.green = 16;
+ tolerance.blue = 16;
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreAntialiasing: function(){
+
+ tolerance.red = 32;
+ tolerance.green = 32;
+ tolerance.blue = 32;
+ tolerance.minBrightness = 64;
+ tolerance.maxBrightness = 96;
+
+ ignoreAntialiasing = true;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreColors: function(){
+
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = true;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ onComplete: function( callback ){
+
+ updateCallbackArray.push(callback);
+
+ var wrapper = function(){
+ compare(fileData, secondFileData);
+ };
+
+ wrapper();
+
+ return getCompareApi(wrapper);
+ }
+ };
+
+ return self;
+ }
+
+ return {
+ onComplete: function( callback ){
+ updateCallbackArray.push(callback);
+ loadImageData(fileData, function(imageData, width, height){
+ parseImage(imageData.data, width, height);
+ });
+ },
+ compareTo: function(secondFileData){
+ return getCompareApi(secondFileData);
+ }
+ };
+
+ };
+}(this));
\ No newline at end of file
diff --git a/test/testsuite.js b/test/testsuite.js
deleted file mode 100644
index b486acb..0000000
--- a/test/testsuite.js
+++ /dev/null
@@ -1,36 +0,0 @@
-requirejs.config({
- baseUrl: '/test/unit/'
-});
-
-define(function(require) {
- var testModules = [
- 'Pixi',
- 'Point',
- 'Rectangle',
- 'DisplayObject',
- 'DisplayObjectContainer',
- 'Sprite',
- 'MovieClip',
- 'InteractionManager',
- 'Stage',
- 'utils/Utils',
- 'utils/EventTarget',
- 'utils/Matrix',
- 'utils/Detector',
- 'renderers/WebGLShaders',
- 'renderers/WebGLRenderer',
- 'renderers/WebGLBatch',
- 'renderers/CanvasRenderer',
- 'extras/Strip',
- 'extras/Rope',
- 'textures/BaseTexture',
- 'textures/Texture',
- 'loaders/SpriteSheetLoader',
- 'loaders/AssetLoader'
- ];
-
- // Resolve all testModules and then start the Test Runner.
- require(testModules, function() {
- QUnit.start();
- });
-});
\ No newline at end of file
diff --git a/test/textures/SpriteSheet-Aliens.png b/test/textures/SpriteSheet-Aliens.png
new file mode 100644
index 0000000..210acb1
--- /dev/null
+++ b/test/textures/SpriteSheet-Aliens.png
Binary files differ
diff --git a/test/textures/SpriteSheet-Explosion.png b/test/textures/SpriteSheet-Explosion.png
new file mode 100755
index 0000000..79e1a69
--- /dev/null
+++ b/test/textures/SpriteSheet-Explosion.png
Binary files differ
diff --git a/test/textures/bunny.png b/test/textures/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/textures/bunny.png
Binary files differ
diff --git a/test/unit/DisplayObject.js b/test/unit/DisplayObject.js
deleted file mode 100644
index 5e7e72f..0000000
--- a/test/unit/DisplayObject.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObject');
-});
diff --git a/test/unit/DisplayObjectContainer.js b/test/unit/DisplayObjectContainer.js
deleted file mode 100644
index b323959..0000000
--- a/test/unit/DisplayObjectContainer.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObjectContainer');
-});
diff --git a/test/unit/InteractionManager.js b/test/unit/InteractionManager.js
deleted file mode 100644
index e751f52..0000000
--- a/test/unit/InteractionManager.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('InteractionManager');
-});
diff --git a/test/unit/MovieClip.js b/test/unit/MovieClip.js
deleted file mode 100644
index 37d9446..0000000
--- a/test/unit/MovieClip.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('MovieClip');
-});
diff --git a/test/unit/Pixi.js b/test/unit/Pixi.js
deleted file mode 100644
index 36eee73..0000000
--- a/test/unit/Pixi.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Pixi');
-});
diff --git a/test/unit/Point.js b/test/unit/Point.js
deleted file mode 100644
index 983ff6e..0000000
--- a/test/unit/Point.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Point');
-});
diff --git a/test/unit/Rectangle.js b/test/unit/Rectangle.js
deleted file mode 100644
index 3b439ba..0000000
--- a/test/unit/Rectangle.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Rectangle');
-});
diff --git a/test/unit/Sprite.js b/test/unit/Sprite.js
deleted file mode 100644
index ed4f596..0000000
--- a/test/unit/Sprite.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Sprite');
-});
diff --git a/test/unit/Stage.js b/test/unit/Stage.js
deleted file mode 100644
index 2d70291..0000000
--- a/test/unit/Stage.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Stage');
-});
diff --git a/test/unit/extras/Rope.js b/test/unit/extras/Rope.js
deleted file mode 100644
index 5606f14..0000000
--- a/test/unit/extras/Rope.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Rope');
-});
diff --git a/test/unit/extras/Strip.js b/test/unit/extras/Strip.js
deleted file mode 100644
index 0134d3a..0000000
--- a/test/unit/extras/Strip.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Strip');
-});
diff --git a/test/unit/loaders/AssetLoader.js b/test/unit/loaders/AssetLoader.js
deleted file mode 100644
index 13b8443..0000000
--- a/test/unit/loaders/AssetLoader.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('AssetLoader');
-});
diff --git a/test/unit/loaders/SpriteSheetLoader.js b/test/unit/loaders/SpriteSheetLoader.js
deleted file mode 100644
index 8bf0cb2..0000000
--- a/test/unit/loaders/SpriteSheetLoader.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('SpriteSheetLoader');
-});
diff --git a/test/unit/pixi/InteractionManager.js b/test/unit/pixi/InteractionManager.js
new file mode 100644
index 0000000..ed3001f
--- /dev/null
+++ b/test/unit/pixi/InteractionManager.js
@@ -0,0 +1,10 @@
+describe('pixi/InteractionManager', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var InteractionManager = PIXI.InteractionManager;
+
+ it('Module exists', function () {
+ expect(InteractionManager).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/Pixi.js b/test/unit/pixi/Pixi.js
new file mode 100644
index 0000000..27debc1
--- /dev/null
+++ b/test/unit/pixi/Pixi.js
@@ -0,0 +1,9 @@
+describe('pixi/Pixi', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+
+ it('Module exists', function () {
+ expect(global).to.have.property('PIXI').and.to.be.an('object');
+ });
+});
diff --git a/test/unit/pixi/core/Circle.js b/test/unit/pixi/core/Circle.js
new file mode 100644
index 0000000..93a4456
--- /dev/null
+++ b/test/unit/pixi/core/Circle.js
@@ -0,0 +1,22 @@
+describe('pixi/core/Circle', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Circle = PIXI.Circle;
+
+ it('Module exists', function () {
+ expect(Circle).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Circle();
+
+ expect(obj).to.be.an.instanceof(Circle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', 0);
+ expect(obj).to.have.property('y', 0);
+ expect(obj).to.have.property('radius', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Ellipse.js b/test/unit/pixi/core/Ellipse.js
new file mode 100644
index 0000000..026b56f
--- /dev/null
+++ b/test/unit/pixi/core/Ellipse.js
@@ -0,0 +1,24 @@
+describe('pixi/core/Ellipse', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Ellipse = PIXI.Ellipse;
+
+ it('Module exists', function () {
+ expect(Ellipse).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Ellipse();
+
+ expect(obj).to.be.an.instanceof(Ellipse);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+ expect(obj).to.respondTo('getBounds');
+
+ expect(obj).to.have.property('x', 0);
+ expect(obj).to.have.property('y', 0);
+ expect(obj).to.have.property('width', 0);
+ expect(obj).to.have.property('height', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Matrix.js b/test/unit/pixi/core/Matrix.js
new file mode 100644
index 0000000..b48989e
--- /dev/null
+++ b/test/unit/pixi/core/Matrix.js
@@ -0,0 +1,30 @@
+describe('pixi/core/Matrix', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var mat3 = PIXI.mat3;
+ var mat4 = PIXI.mat4;
+ var Matrix = PIXI.Matrix;
+
+ it('Ensure determineMatrixArrayType works', function () {
+ expect(Matrix).to.be.a('function');
+ });
+
+ it('mat3 exists', function () {
+ expect(mat3).to.be.an('object');
+ });
+
+ it('Confirm new mat3 matrix', function () {
+ var matrix = new mat3.create();
+ pixi_core_Matrix_confirmNewMat3(matrix);
+ });
+
+ it('mat3 exists', function () {
+ expect(mat4).to.be.an('object');
+ });
+
+ it('Confirm new mat4 matrix', function () {
+ var matrix = new mat4.create();
+ pixi_core_Matrix_confirmNewMat4(matrix);
+ });
+});
diff --git a/test/unit/pixi/core/Point.js b/test/unit/pixi/core/Point.js
new file mode 100644
index 0000000..c4d5163
--- /dev/null
+++ b/test/unit/pixi/core/Point.js
@@ -0,0 +1,15 @@
+describe('pixi/core/Point', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Point = PIXI.Point;
+
+ it('Module exists', function () {
+ expect(Point).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Point();
+ pixi_core_Point_confirm(obj, 0, 0);
+ });
+});
diff --git a/test/unit/pixi/core/Polygon.js b/test/unit/pixi/core/Polygon.js
new file mode 100644
index 0000000..dc8c918
--- /dev/null
+++ b/test/unit/pixi/core/Polygon.js
@@ -0,0 +1,20 @@
+describe('pixi/core/Polygon', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Polygon = PIXI.Polygon;
+
+ it('Module exists', function () {
+ expect(Polygon).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Polygon();
+
+ expect(obj).to.be.an.instanceof(Polygon);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.deep.property('points.length', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Rectangle.js b/test/unit/pixi/core/Rectangle.js
new file mode 100644
index 0000000..d43316e
--- /dev/null
+++ b/test/unit/pixi/core/Rectangle.js
@@ -0,0 +1,15 @@
+describe('pixi/core/Rectangle', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Rectangle = PIXI.Rectangle;
+
+ it('Module exists', function () {
+ expect(Rectangle).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var rect = new Rectangle();
+ pixi_core_Rectangle_confirm(rect, 0, 0, 0, 0);
+ });
+});
diff --git a/test/unit/pixi/display/DisplayObject.js b/test/unit/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..40c6fbc
--- /dev/null
+++ b/test/unit/pixi/display/DisplayObject.js
@@ -0,0 +1,21 @@
+describe('pixi/display/DisplayObject', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var DisplayObject = PIXI.DisplayObject;
+
+ it('Module exists', function () {
+ expect(DisplayObject).to.be.a('function');
+ expect(PIXI).to.have.property('visibleCount', 0);
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new DisplayObject();
+
+ pixi_display_DisplayObject_confirmNew(obj);
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', false);
+ expect(obj).to.have.property('stage', null);
+ });
+});
diff --git a/test/unit/pixi/display/DisplayObjectContainer.js b/test/unit/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..ce7f02f
--- /dev/null
+++ b/test/unit/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,20 @@
+describe('pixi/display/DisplayObjectContainer', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var DisplayObjectContainer = PIXI.DisplayObjectContainer;
+
+ it('Module exists', function () {
+ expect(DisplayObjectContainer).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new DisplayObjectContainer();
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', false);
+ expect(obj).to.have.property('stage', null);
+ });
+});
diff --git a/test/unit/pixi/display/MovieClip.js b/test/unit/pixi/display/MovieClip.js
new file mode 100644
index 0000000..f3c6c6a
--- /dev/null
+++ b/test/unit/pixi/display/MovieClip.js
@@ -0,0 +1,33 @@
+describe('pixi/display/MovieClip', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var MovieClip = PIXI.MovieClip;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(MovieClip).to.be.a('function');
+ });
+
+ it('Confirm new instance', function (done) {
+ var texture = Texture.fromImage('/base/test/textures/SpriteSheet-Explosion.png');
+ var obj = new MovieClip([texture]);
+
+ pixi_display_Sprite_confirmNew(obj, done);
+
+ expect(obj).to.be.an.instanceof(MovieClip);
+ expect(obj).to.respondTo('stop');
+ expect(obj).to.respondTo('play');
+ expect(obj).to.respondTo('gotoAndStop');
+ expect(obj).to.respondTo('gotoAndPlay');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('textures.length', 1);
+ expect(obj).to.have.deep.property('textures[0]', texture);
+ expect(obj).to.have.property('animationSpeed', 1);
+ expect(obj).to.have.property('loop', true);
+ expect(obj).to.have.property('onComplete', null);
+ expect(obj).to.have.property('currentFrame', 0);
+ expect(obj).to.have.property('playing', false);
+ });
+});
diff --git a/test/unit/pixi/display/Sprite.js b/test/unit/pixi/display/Sprite.js
new file mode 100644
index 0000000..54e914f
--- /dev/null
+++ b/test/unit/pixi/display/Sprite.js
@@ -0,0 +1,25 @@
+describe('pixi/display/Sprite', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Sprite = PIXI.Sprite;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(Sprite).to.be.a('function');
+ expect(PIXI).to.have.deep.property('blendModes.NORMAL', 0);
+ expect(PIXI).to.have.deep.property('blendModes.SCREEN', 1);
+ });
+
+ it('Members exist', function () {
+ expect(Sprite).itself.to.respondTo('fromImage');
+ expect(Sprite).itself.to.respondTo('fromFrame');
+ });
+
+ it('Confirm new instance', function (done) {
+ var texture = Texture.fromImage('/base/test/textures/SpriteSheet-Aliens.png');
+ var obj = new Sprite(texture);
+
+ pixi_display_Sprite_confirmNew(obj, done);
+ });
+});
diff --git a/.gitignore b/.gitignore
index 12e1b62..0b88317 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
node_modules
.DS_Store
-.project
\ No newline at end of file
+.project
+*.log
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..63e4d7c
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,8 @@
+language: node_js
+node_js:
+ - 0.10
+
+before_script:
+ - npm install -g grunt-cli
+ - export DISPLAY=:99.0
+ - sh -e /etc/init.d/xvfb start
diff --git a/Gruntfile.js b/Gruntfile.js
index b083b49..103938c 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -1,10 +1,12 @@
+'use strict';
+
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-connect');
- grunt.loadNpmTasks('grunt-contrib-qunit');
grunt.loadNpmTasks('grunt-contrib-yuidoc');
+ grunt.loadTasks('tasks');
var root = 'src/pixi/',
debug = 'bin/pixi.dev.js',
@@ -79,7 +81,7 @@
},
files: {
srcBlob: '<%= dirs.src %>/**/*.js',
- testBlob: '<%= dirs.test %>/unit/**/*.js',
+ testBlob: '<%= dirs.test %>/{functional,lib/pixi,unit}/**/*.js',
build: '<%= dirs.build %>/pixi.dev.js',
buildMin: '<%= dirs.build %>/pixi.js'
},
@@ -94,7 +96,12 @@
},
jshint: {
beforeconcat: srcFiles,
- test: ['<%= files.testBlob %>'],
+ test: {
+ src: ['<%= files.testBlob %>'],
+ options: {
+ expr: true
+ }
+ },
options: {
asi: true,
smarttabs: true
@@ -128,12 +135,6 @@
]
},
connect: {
- qunit: {
- options: {
- port: grunt.option('port-test') || 9002,
- base: './'
- }
- },
test: {
options: {
port: grunt.option('port-test') || 9002,
@@ -142,13 +143,6 @@
}
}
},
- qunit: {
- all: {
- options: {
- urls: ['http://localhost:' + (grunt.option('port-test') || 9002) + '/test/index.html']
- }
- }
- },
yuidoc: {
compile: {
name: '<%= pkg.name %>',
@@ -161,6 +155,13 @@
outdir: '<%= dirs.docs %>'
}
}
+ },
+ karma: {
+ unit: {
+ configFile: 'test/karma.conf.js',
+ // browsers: ['Chrome'],
+ singleRun: true
+ }
}
});
@@ -182,9 +183,10 @@
}
)
- grunt.registerTask('default', ['concat', 'uglify', 'distribute']);
grunt.registerTask('build', ['concat', 'uglify', 'distribute']);
- grunt.registerTask('test', ['build', 'connect:qunit', 'qunit']);
+ grunt.registerTask('test', ['concat', 'jshint:test', 'karma']);
grunt.registerTask('docs', ['yuidoc']);
-
-}
\ No newline at end of file
+ grunt.registerTask('default', ['test', 'uglify', 'distribute']);
+ // Travis CI task.
+ grunt.registerTask('travis', ['test']);
+}
diff --git a/README.md b/README.md
index c62ef86..690cfe4 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,8 @@

+[](http://travis-ci.org/drkibitz/pixi.js)
+
#### JavaScript 2D Renderer ####
The aim of this project is to provide a fast lightweight 2D library that works
diff --git a/package.json b/package.json
index b373240..1246a68 100644
--- a/package.json
+++ b/package.json
@@ -18,14 +18,21 @@
"main": "bin/pixi.js",
+ "scripts": {
+ "test": "grunt travis --verbose"
+ },
+
"dependencies": {},
"devDependencies": {
"grunt": "~0.4.x",
- "grunt-contrib-jshint": "0.3.x",
+ "grunt-contrib-jshint": "0.6.x",
"grunt-contrib-uglify": "0.2.x",
- "grunt-contrib-connect": "0.2.x",
- "grunt-contrib-qunit": "0.2.x",
+ "grunt-contrib-connect": "0.3.x",
"grunt-contrib-yuidoc": "0.4.x",
- "grunt-contrib-concat": "0.1.x"
+ "grunt-contrib-concat": "0.3.x",
+ "chai": "~1.7.0",
+ "karma": "0.11.0",
+ "karma-firefox-launcher": "0.1.0",
+ "karma-mocha": "0.1.0"
}
}
diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js
index a7c520e..ee82bbd 100644
--- a/src/pixi/InteractionManager.js
+++ b/src/pixi/InteractionManager.js
@@ -62,7 +62,6 @@
this.onTouchEnd = this.onTouchEnd.bind(this);
this.onTouchMove = this.onTouchMove.bind(this);
-
this.last = 0;
}
diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js
index 1a95d20..eef1059 100644
--- a/src/pixi/core/Ellipse.js
+++ b/src/pixi/core/Ellipse.js
@@ -78,7 +78,7 @@
return (normx + normy < 0.25);
}
-PIXI.Ellipse.getBounds = function()
+PIXI.Ellipse.prototype.getBounds = function()
{
return new PIXI.Rectangle(this.x, this.y, this.width, this.height);
}
diff --git a/tasks/karma.js b/tasks/karma.js
new file mode 100644
index 0000000..c340485
--- /dev/null
+++ b/tasks/karma.js
@@ -0,0 +1,27 @@
+'use strict';
+
+var path = require('path');
+var server = require('karma').server;
+
+module.exports = function (grunt) {
+ grunt.registerMultiTask('karma', 'run karma.', function() {
+ var done = this.async();
+ var options = this.options({
+ background: false
+ });
+ var data = this.data;
+
+ //merge options onto data, with data taking precedence
+ data = grunt.util._.merge(options, data);
+ data.configFile = path.resolve(data.configFile);
+ if (data.configFile) {
+ data.configFile = grunt.template.process(data.configFile);
+ }
+
+ server.start(
+ data,
+ function(code) {
+ done(!code);
+ });
+ });
+};
diff --git a/test/functional/example-1-basics/bunny.png b/test/functional/example-1-basics/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/functional/example-1-basics/bunny.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-30.png b/test/functional/example-1-basics/frame-30.png
new file mode 100644
index 0000000..96e3409
--- /dev/null
+++ b/test/functional/example-1-basics/frame-30.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-60.png b/test/functional/example-1-basics/frame-60.png
new file mode 100644
index 0000000..af3f4ce
--- /dev/null
+++ b/test/functional/example-1-basics/frame-60.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-90.png b/test/functional/example-1-basics/frame-90.png
new file mode 100644
index 0000000..099b823
--- /dev/null
+++ b/test/functional/example-1-basics/frame-90.png
Binary files differ
diff --git a/test/functional/example-1-basics/index.js b/test/functional/example-1-basics/index.js
new file mode 100644
index 0000000..7ae7a98
--- /dev/null
+++ b/test/functional/example-1-basics/index.js
@@ -0,0 +1,133 @@
+describe('Example 1 - Basics', function () {
+ 'use strict';
+
+ var baseUri = '/base/test/functional/example-1-basics';
+ var expect = chai.expect;
+ var currentFrame = 0;
+ var frameEvents = {};
+ var stage;
+ var renderer;
+ var bunny;
+
+ function onFrame(frame, callback) {
+ frameEvents[frame] = callback;
+ }
+
+ function animate() {
+ currentFrame += 1;
+
+ requestAnimFrame( animate );
+
+ // just for fun, lets rotate mr rabbit a little
+ bunny.rotation += 0.1;
+
+ // render the stage
+ renderer.render(stage);
+
+ if (frameEvents[currentFrame])
+ frameEvents[currentFrame](currentFrame);
+ }
+
+ function initScene() {
+ // create an new instance of a pixi stage
+ stage = new PIXI.Stage(0x66FF99);
+
+ // create a renderer instance
+ renderer = PIXI.autoDetectRenderer(400, 300);
+ console.log('Is PIXI.WebGLRenderer: ' + (renderer instanceof PIXI.WebGLRenderer));
+
+ // add the renderer view element to the DOM
+ document.body.appendChild(renderer.view);
+
+ requestAnimFrame( animate );
+
+ // create a texture from an image path
+ var texture = PIXI.Texture.fromImage(baseUri + "/bunny.png");
+ // create a new Sprite using the texture
+ bunny = new PIXI.Sprite(texture);
+
+ // center the sprites anchor point
+ bunny.anchor.x = 0.5;
+ bunny.anchor.y = 0.5;
+
+ // move the sprite t the center of the screen
+ bunny.position.x = 200;
+ bunny.position.y = 150;
+
+ stage.addChild(bunny);
+ }
+
+ it('assets loaded', function (done) {
+ var loader = new PIXI.AssetLoader([
+ baseUri + '/bunny.png',
+ baseUri + '/frame-30.png',
+ baseUri + '/frame-60.png',
+ baseUri + '/frame-90.png'
+ ]);
+ // loader.on('onProgress', function (event) {
+ // console.log(event.content);
+ // });
+ loader.on('onComplete', function (event) {
+ done();
+ initScene();
+ });
+ loader.load();
+ });
+
+ it('frame 30 should match', function (done) {
+ this.timeout(700);
+ onFrame(30, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-30.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 60 should match', function (done) {
+ this.timeout(1200);
+ onFrame(60, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-60.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 90 should match', function (done) {
+ this.timeout(1700);
+ onFrame(90, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-90.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ // it('capture something', function (done) {
+ // this.timeout(2000000);
+ // onFrame(30, function () {
+ // var img = new Image();
+ // img.src = renderer.view.toDataURL('image/png');
+ // document.body.appendChild(img);
+ // });
+ // });
+});
diff --git a/test/index.html b/test/index.html
deleted file mode 100644
index 9cbcac5..0000000
--- a/test/index.html
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
- Pixi.js Test Suite
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/test/karma.conf.js b/test/karma.conf.js
new file mode 100644
index 0000000..c66a696
--- /dev/null
+++ b/test/karma.conf.js
@@ -0,0 +1,82 @@
+module.exports = function(config) {
+ config.set({
+
+ // base path, that will be used to resolve files and exclude
+ basePath : '../',
+
+ frameworks : ['mocha'],
+
+ // list of files / patterns to load in the browser
+ files : [
+ 'node_modules/chai/chai.js',
+ 'bin/pixi.dev.js',
+ 'test/lib/**/*.js',
+ 'test/unit/**/*.js',
+ // 'test/functional/**/*.js',
+ {pattern: 'test/**/*.png', watched: false, included: false, served: true}
+ ],
+
+ // list of files to exclude
+ exclude : [],
+
+ // use dolts reporter, as travis terminal does not support escaping sequences
+ // possible values: 'dots', 'progress', 'junit', 'teamcity'
+ // CLI --reporters progress
+ reporters : ['progress'],
+
+ // web server port
+ // CLI --port 9876
+ port : 9876,
+
+ // cli runner port
+ // CLI --runner-port 9100
+ runnerPort : 9100,
+
+ // enable / disable colors in the output (reporters and logs)
+ // CLI --colors --no-colors
+ colors : true,
+
+ // level of logging
+ // possible values: karma.LOG_DISABLE || karma.LOG_ERROR || karma.LOG_WARN || karma.LOG_INFO || karma.LOG_DEBUG
+ // CLI --log-level debug
+ logLevel : config.LOG_DEBUG,
+
+ // enable / disable watching file and executing tests whenever any file changes
+ // CLI --auto-watch --no-auto-watch
+ autoWatch : false,
+
+ // Start these browsers, currently available:
+ // - Chrome
+ // - ChromeCanary
+ // - Firefox
+ // - Opera
+ // - Safari (only Mac)
+ // - PhantomJS
+ // - IE (only Windows)
+ // CLI --browsers Chrome,Firefox,Safari
+ browsers : ['Firefox'],
+
+ // If browser does not capture in given timeout [ms], kill it
+ // CLI --capture-timeout 5000
+ captureTimeout : 5000,
+
+ // Auto run tests on start (when browsers are captured) and exit
+ // CLI --single-run --no-single-run
+ singleRun : true,
+
+ // report which specs are slower than 500ms
+ // CLI --report-slower-than 500
+ reportSlowerThan : 1000,
+
+ preprocessors : {
+ // '**/client/js/*.js': 'coverage'
+ },
+
+ plugins : [
+ 'karma-mocha',
+ // 'karma-chrome-launcher',
+ 'karma-firefox-launcher',
+ // 'karma-phantomjs-launcher'
+ ]
+ });
+};
diff --git a/test/lib/pixi/core/Matrix.js b/test/lib/pixi/core/Matrix.js
new file mode 100644
index 0000000..d26386b
--- /dev/null
+++ b/test/lib/pixi/core/Matrix.js
@@ -0,0 +1,40 @@
+
+function pixi_core_Matrix_confirmNewMat3(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(1);
+ expect(matrix[5]).to.equal(0);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(1);
+}
+
+function pixi_core_Matrix_confirmNewMat4(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[0]).to.equal(1);
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(0);
+ expect(matrix[5]).to.equal(1);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(0);
+ expect(matrix[9]).to.equal(0);
+ expect(matrix[10]).to.equal(1);
+ expect(matrix[11]).to.equal(0);
+ expect(matrix[12]).to.equal(0);
+ expect(matrix[13]).to.equal(0);
+ expect(matrix[14]).to.equal(0);
+ expect(matrix[15]).to.equal(1);
+}
diff --git a/test/lib/pixi/core/Point.js b/test/lib/pixi/core/Point.js
new file mode 100644
index 0000000..e5df07b
--- /dev/null
+++ b/test/lib/pixi/core/Point.js
@@ -0,0 +1,10 @@
+
+function pixi_core_Point_confirm(obj, x, y) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Point);
+ expect(obj).to.respondTo('clone');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+}
diff --git a/test/lib/pixi/core/Rectangle.js b/test/lib/pixi/core/Rectangle.js
new file mode 100644
index 0000000..23f0d12
--- /dev/null
+++ b/test/lib/pixi/core/Rectangle.js
@@ -0,0 +1,13 @@
+
+function pixi_core_Rectangle_confirm(obj, x, y, width, height) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Rectangle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+ expect(obj).to.have.property('width', width);
+ expect(obj).to.have.property('height', height);
+}
diff --git a/test/lib/pixi/display/DisplayObject.js b/test/lib/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..1388a7f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObject.js
@@ -0,0 +1,43 @@
+
+function pixi_display_DisplayObject_confirmNew(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObject);
+ expect(obj).to.respondTo('setInteractive');
+ expect(obj).to.respondTo('addFilter');
+ expect(obj).to.respondTo('removeFilter');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.property('last', obj);
+ expect(obj).to.have.property('first', obj);
+
+ expect(obj).to.contain.property('position');
+ pixi_core_Point_confirm(obj.position, 0, 0);
+ expect(obj).to.contain.property('scale');
+ pixi_core_Point_confirm(obj.scale, 1, 1);
+ expect(obj).to.contain.property('pivot');
+ pixi_core_Point_confirm(obj.pivot, 0, 0);
+
+ expect(obj).to.have.property('rotation', 0);
+ expect(obj).to.have.property('alpha', 1);
+ expect(obj).to.have.property('visible', true);
+ expect(obj).to.have.property('buttonMode', false);
+ expect(obj).to.have.property('parent', null);
+ expect(obj).to.have.property('worldAlpha', 1);
+
+ expect(obj).to.have.property('hitArea');
+ expect(obj).to.have.property('interactive'); // TODO: Have a better default value
+ expect('mask' in obj).to.be.true; // TODO: Have a better default value
+ expect(obj.mask).to.be.undefined;
+
+ expect(obj).to.have.property('renderable');
+ expect(obj).to.have.property('stage');
+
+ expect(obj).to.have.deep.property('worldTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ expect(obj).to.have.deep.property('localTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.localTransform);
+
+ expect(obj).to.have.deep.property('color.length', 0);
+ expect(obj).to.have.property('dynamic', true);
+}
diff --git a/test/lib/pixi/display/DisplayObjectContainer.js b/test/lib/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..085c59f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,16 @@
+
+function pixi_display_DisplayObjectContainer_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObject_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObjectContainer);
+ expect(obj).to.respondTo('addChild');
+ expect(obj).to.respondTo('addChildAt');
+ expect(obj).to.respondTo('swapChildren');
+ expect(obj).to.respondTo('getChildAt');
+ expect(obj).to.respondTo('removeChild');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('children.length', 0);
+}
diff --git a/test/lib/pixi/display/Sprite.js b/test/lib/pixi/display/Sprite.js
new file mode 100644
index 0000000..cc7a2d6
--- /dev/null
+++ b/test/lib/pixi/display/Sprite.js
@@ -0,0 +1,28 @@
+
+function pixi_display_Sprite_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Sprite);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', true);
+ expect(obj).to.have.property('stage', null);
+
+ expect(obj).to.have.property('anchor');
+ pixi_core_Point_confirm(obj.anchor, 0, 0);
+
+ expect(obj).to.have.property('blendMode', PIXI.blendModes.NORMAL);
+ expect(obj).to.have.property('width', 1); // TODO: is 1 expected
+ expect(obj).to.have.property('height', 1); // TODO: is 1 expected
+
+ // FIXME: Just make this a boolean that is always there
+ expect(!!obj.updateFrame).to.equal(obj.texture.baseTexture.hasLoaded);
+
+ expect(obj).to.have.property('texture');
+ pixi_textures_Texture_confirmNew(obj.texture, done);
+}
diff --git a/test/lib/pixi/extras/Strip.js b/test/lib/pixi/extras/Strip.js
new file mode 100644
index 0000000..8927a8a
--- /dev/null
+++ b/test/lib/pixi/extras/Strip.js
@@ -0,0 +1,12 @@
+
+function pixi_extras_Strip_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Strip);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ // TODO: Test properties
+}
diff --git a/test/lib/pixi/textures/Texture.js b/test/lib/pixi/textures/Texture.js
new file mode 100644
index 0000000..d5867b6
--- /dev/null
+++ b/test/lib/pixi/textures/Texture.js
@@ -0,0 +1,31 @@
+
+function pixi_textures_Texture_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ function confirmFrameDone() {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, obj.baseTexture.width, obj.baseTexture.height);
+
+ expect(obj).to.have.property('width', obj.baseTexture.width);
+ expect(obj).to.have.property('height', obj.baseTexture.height);
+ done();
+ }
+
+ expect(obj).to.be.an.instanceof(PIXI.Texture);
+ pixi_utils_EventTarget_like(obj);
+
+ expect(obj).to.have.property('baseTexture')
+ .and.to.be.an.instanceof(PIXI.BaseTexture);
+
+ expect(obj).to.have.property('scope', obj);
+
+ expect(obj).to.have.property('trim');
+ pixi_core_Point_confirm(obj.trim, 0, 0);
+
+ expect(obj).to.have.property('frame');
+ if (obj.baseTexture.hasLoaded) {
+ confirmFrameDone();
+ } else {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, 1, 1);
+ obj.addEventListener('update', confirmFrameDone);
+ }
+}
diff --git a/test/lib/pixi/utils/EventTarget.js b/test/lib/pixi/utils/EventTarget.js
new file mode 100644
index 0000000..7b1dcfa
--- /dev/null
+++ b/test/lib/pixi/utils/EventTarget.js
@@ -0,0 +1,8 @@
+
+function pixi_utils_EventTarget_like(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.respondTo('addEventListener');
+ expect(obj).to.respondTo('dispatchEvent');
+ expect(obj).to.respondTo('removeEventListener');
+}
diff --git a/test/lib/qunit-1.11.0.css b/test/lib/qunit-1.11.0.css
deleted file mode 100644
index d7fc0c8..0000000
--- a/test/lib/qunit-1.11.0.css
+++ /dev/null
@@ -1,244 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-/** Font Family and Sizes */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
- font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
-}
-
-#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
-#qunit-tests { font-size: smaller; }
-
-
-/** Resets */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter {
- margin: 0;
- padding: 0;
-}
-
-
-/** Header */
-
-#qunit-header {
- padding: 0.5em 0 0.5em 1em;
-
- color: #8699a4;
- background-color: #0d3349;
-
- font-size: 1.5em;
- line-height: 1em;
- font-weight: normal;
-
- border-radius: 5px 5px 0 0;
- -moz-border-radius: 5px 5px 0 0;
- -webkit-border-top-right-radius: 5px;
- -webkit-border-top-left-radius: 5px;
-}
-
-#qunit-header a {
- text-decoration: none;
- color: #c2ccd1;
-}
-
-#qunit-header a:hover,
-#qunit-header a:focus {
- color: #fff;
-}
-
-#qunit-testrunner-toolbar label {
- display: inline-block;
- padding: 0 .5em 0 .1em;
-}
-
-#qunit-banner {
- height: 5px;
-}
-
-#qunit-testrunner-toolbar {
- padding: 0.5em 0 0.5em 2em;
- color: #5E740B;
- background-color: #eee;
- overflow: hidden;
-}
-
-#qunit-userAgent {
- padding: 0.5em 0 0.5em 2.5em;
- background-color: #2b81af;
- color: #fff;
- text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
-}
-
-#qunit-modulefilter-container {
- float: right;
-}
-
-/** Tests: Pass/Fail */
-
-#qunit-tests {
- list-style-position: inside;
-}
-
-#qunit-tests li {
- padding: 0.4em 0.5em 0.4em 2.5em;
- border-bottom: 1px solid #fff;
- list-style-position: inside;
-}
-
-#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running {
- display: none;
-}
-
-#qunit-tests li strong {
- cursor: pointer;
-}
-
-#qunit-tests li a {
- padding: 0.5em;
- color: #c2ccd1;
- text-decoration: none;
-}
-#qunit-tests li a:hover,
-#qunit-tests li a:focus {
- color: #000;
-}
-
-#qunit-tests li .runtime {
- float: right;
- font-size: smaller;
-}
-
-.qunit-assert-list {
- margin-top: 0.5em;
- padding: 0.5em;
-
- background-color: #fff;
-
- border-radius: 5px;
- -moz-border-radius: 5px;
- -webkit-border-radius: 5px;
-}
-
-.qunit-collapsed {
- display: none;
-}
-
-#qunit-tests table {
- border-collapse: collapse;
- margin-top: .2em;
-}
-
-#qunit-tests th {
- text-align: right;
- vertical-align: top;
- padding: 0 .5em 0 0;
-}
-
-#qunit-tests td {
- vertical-align: top;
-}
-
-#qunit-tests pre {
- margin: 0;
- white-space: pre-wrap;
- word-wrap: break-word;
-}
-
-#qunit-tests del {
- background-color: #e0f2be;
- color: #374e0c;
- text-decoration: none;
-}
-
-#qunit-tests ins {
- background-color: #ffcaca;
- color: #500;
- text-decoration: none;
-}
-
-/*** Test Counts */
-
-#qunit-tests b.counts { color: black; }
-#qunit-tests b.passed { color: #5E740B; }
-#qunit-tests b.failed { color: #710909; }
-
-#qunit-tests li li {
- padding: 5px;
- background-color: #fff;
- border-bottom: none;
- list-style-position: inside;
-}
-
-/*** Passing Styles */
-
-#qunit-tests li li.pass {
- color: #3c510c;
- background-color: #fff;
- border-left: 10px solid #C6E746;
-}
-
-#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
-#qunit-tests .pass .test-name { color: #366097; }
-
-#qunit-tests .pass .test-actual,
-#qunit-tests .pass .test-expected { color: #999999; }
-
-#qunit-banner.qunit-pass { background-color: #C6E746; }
-
-/*** Failing Styles */
-
-#qunit-tests li li.fail {
- color: #710909;
- background-color: #fff;
- border-left: 10px solid #EE5757;
- white-space: pre;
-}
-
-#qunit-tests > li:last-child {
- border-radius: 0 0 5px 5px;
- -moz-border-radius: 0 0 5px 5px;
- -webkit-border-bottom-right-radius: 5px;
- -webkit-border-bottom-left-radius: 5px;
-}
-
-#qunit-tests .fail { color: #000000; background-color: #EE5757; }
-#qunit-tests .fail .test-name,
-#qunit-tests .fail .module-name { color: #000000; }
-
-#qunit-tests .fail .test-actual { color: #EE5757; }
-#qunit-tests .fail .test-expected { color: green; }
-
-#qunit-banner.qunit-fail { background-color: #EE5757; }
-
-
-/** Result */
-
-#qunit-testresult {
- padding: 0.5em 0.5em 0.5em 2.5em;
-
- color: #2b81af;
- background-color: #D2E0E6;
-
- border-bottom: 1px solid white;
-}
-#qunit-testresult .module-name {
- font-weight: bold;
-}
-
-/** Fixture */
-
-#qunit-fixture {
- position: absolute;
- top: -10000px;
- left: -10000px;
- width: 1000px;
- height: 1000px;
-}
diff --git a/test/lib/qunit-1.11.0.js b/test/lib/qunit-1.11.0.js
deleted file mode 100644
index 302545f..0000000
--- a/test/lib/qunit-1.11.0.js
+++ /dev/null
@@ -1,2152 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-(function( window ) {
-
-var QUnit,
- assert,
- config,
- onErrorFnPrev,
- testId = 0,
- fileName = (sourceFromStacktrace( 0 ) || "" ).replace(/(:\d+)+\)?/, "").replace(/.+\//, ""),
- toString = Object.prototype.toString,
- hasOwn = Object.prototype.hasOwnProperty,
- // Keep a local reference to Date (GH-283)
- Date = window.Date,
- defined = {
- setTimeout: typeof window.setTimeout !== "undefined",
- sessionStorage: (function() {
- var x = "qunit-test-string";
- try {
- sessionStorage.setItem( x, x );
- sessionStorage.removeItem( x );
- return true;
- } catch( e ) {
- return false;
- }
- }())
- },
- /**
- * Provides a normalized error string, correcting an issue
- * with IE 7 (and prior) where Error.prototype.toString is
- * not properly implemented
- *
- * Based on http://es5.github.com/#x15.11.4.4
- *
- * @param {String|Error} error
- * @return {String} error message
- */
- errorString = function( error ) {
- var name, message,
- errorString = error.toString();
- if ( errorString.substring( 0, 7 ) === "[object" ) {
- name = error.name ? error.name.toString() : "Error";
- message = error.message ? error.message.toString() : "";
- if ( name && message ) {
- return name + ": " + message;
- } else if ( name ) {
- return name;
- } else if ( message ) {
- return message;
- } else {
- return "Error";
- }
- } else {
- return errorString;
- }
- },
- /**
- * Makes a clone of an object using only Array or Object as base,
- * and copies over the own enumerable properties.
- *
- * @param {Object} obj
- * @return {Object} New object with only the own properties (recursively).
- */
- objectValues = function( obj ) {
- // Grunt 0.3.x uses an older version of jshint that still has jshint/jshint#392.
- /*jshint newcap: false */
- var key, val,
- vals = QUnit.is( "array", obj ) ? [] : {};
- for ( key in obj ) {
- if ( hasOwn.call( obj, key ) ) {
- val = obj[key];
- vals[key] = val === Object(val) ? objectValues(val) : val;
- }
- }
- return vals;
- };
-
-function Test( settings ) {
- extend( this, settings );
- this.assertions = [];
- this.testNumber = ++Test.count;
-}
-
-Test.count = 0;
-
-Test.prototype = {
- init: function() {
- var a, b, li,
- tests = id( "qunit-tests" );
-
- if ( tests ) {
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml;
-
- // `a` initialized at top of scope
- a = document.createElement( "a" );
- a.innerHTML = "Rerun";
- a.href = QUnit.url({ testNumber: this.testNumber });
-
- li = document.createElement( "li" );
- li.appendChild( b );
- li.appendChild( a );
- li.className = "running";
- li.id = this.id = "qunit-test-output" + testId++;
-
- tests.appendChild( li );
- }
- },
- setup: function() {
- if ( this.module !== config.previousModule ) {
- if ( config.previousModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.previousModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
- config.previousModule = this.module;
- config.moduleStats = { all: 0, bad: 0 };
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- } else if ( config.autorun ) {
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- }
-
- config.current = this;
-
- this.testEnvironment = extend({
- setup: function() {},
- teardown: function() {}
- }, this.moduleTestEnvironment );
-
- this.started = +new Date();
- runLoggingCallbacks( "testStart", QUnit, {
- name: this.testName,
- module: this.module
- });
-
- // allow utility functions to access the current test environment
- // TODO why??
- QUnit.current_testEnvironment = this.testEnvironment;
-
- if ( !config.pollution ) {
- saveGlobal();
- }
- if ( config.notrycatch ) {
- this.testEnvironment.setup.call( this.testEnvironment );
- return;
- }
- try {
- this.testEnvironment.setup.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Setup failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- },
- run: function() {
- config.current = this;
-
- var running = id( "qunit-testresult" );
-
- if ( running ) {
- running.innerHTML = "Running:
" + this.nameHtml;
- }
-
- if ( this.async ) {
- QUnit.stop();
- }
-
- this.callbackStarted = +new Date();
-
- if ( config.notrycatch ) {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- return;
- }
-
- try {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- } catch( e ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
-
- QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + " " + this.stack + ": " + ( e.message || e ), extractStacktrace( e, 0 ) );
- // else next test will carry the responsibility
- saveGlobal();
-
- // Restart the tests if they're blocking
- if ( config.blocking ) {
- QUnit.start();
- }
- }
- },
- teardown: function() {
- config.current = this;
- if ( config.notrycatch ) {
- if ( typeof this.callbackRuntime === "undefined" ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
- }
- this.testEnvironment.teardown.call( this.testEnvironment );
- return;
- } else {
- try {
- this.testEnvironment.teardown.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Teardown failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- }
- checkPollution();
- },
- finish: function() {
- config.current = this;
- if ( config.requireExpects && this.expected === null ) {
- QUnit.pushFailure( "Expected number of assertions to be defined, but expect() was not called.", this.stack );
- } else if ( this.expected !== null && this.expected !== this.assertions.length ) {
- QUnit.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack );
- } else if ( this.expected === null && !this.assertions.length ) {
- QUnit.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions.", this.stack );
- }
-
- var i, assertion, a, b, time, li, ol,
- test = this,
- good = 0,
- bad = 0,
- tests = id( "qunit-tests" );
-
- this.runtime = +new Date() - this.started;
- config.stats.all += this.assertions.length;
- config.moduleStats.all += this.assertions.length;
-
- if ( tests ) {
- ol = document.createElement( "ol" );
- ol.className = "qunit-assert-list";
-
- for ( i = 0; i < this.assertions.length; i++ ) {
- assertion = this.assertions[i];
-
- li = document.createElement( "li" );
- li.className = assertion.result ? "pass" : "fail";
- li.innerHTML = assertion.message || ( assertion.result ? "okay" : "failed" );
- ol.appendChild( li );
-
- if ( assertion.result ) {
- good++;
- } else {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
-
- // store result when possible
- if ( QUnit.config.reorder && defined.sessionStorage ) {
- if ( bad ) {
- sessionStorage.setItem( "qunit-test-" + this.module + "-" + this.testName, bad );
- } else {
- sessionStorage.removeItem( "qunit-test-" + this.module + "-" + this.testName );
- }
- }
-
- if ( bad === 0 ) {
- addClass( ol, "qunit-collapsed" );
- }
-
- // `b` initialized at top of scope
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml + " (" + bad + ", " + good + ", " + this.assertions.length + ")";
-
- addEvent(b, "click", function() {
- var next = b.parentNode.lastChild,
- collapsed = hasClass( next, "qunit-collapsed" );
- ( collapsed ? removeClass : addClass )( next, "qunit-collapsed" );
- });
-
- addEvent(b, "dblclick", function( e ) {
- var target = e && e.target ? e.target : window.event.srcElement;
- if ( target.nodeName.toLowerCase() === "span" || target.nodeName.toLowerCase() === "b" ) {
- target = target.parentNode;
- }
- if ( window.location && target.nodeName.toLowerCase() === "strong" ) {
- window.location = QUnit.url({ testNumber: test.testNumber });
- }
- });
-
- // `time` initialized at top of scope
- time = document.createElement( "span" );
- time.className = "runtime";
- time.innerHTML = this.runtime + " ms";
-
- // `li` initialized at top of scope
- li = id( this.id );
- li.className = bad ? "fail" : "pass";
- li.removeChild( li.firstChild );
- a = li.firstChild;
- li.appendChild( b );
- li.appendChild( a );
- li.appendChild( time );
- li.appendChild( ol );
-
- } else {
- for ( i = 0; i < this.assertions.length; i++ ) {
- if ( !this.assertions[i].result ) {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
- }
-
- runLoggingCallbacks( "testDone", QUnit, {
- name: this.testName,
- module: this.module,
- failed: bad,
- passed: this.assertions.length - bad,
- total: this.assertions.length,
- duration: this.runtime
- });
-
- QUnit.reset();
-
- config.current = undefined;
- },
-
- queue: function() {
- var bad,
- test = this;
-
- synchronize(function() {
- test.init();
- });
- function run() {
- // each of these can by async
- synchronize(function() {
- test.setup();
- });
- synchronize(function() {
- test.run();
- });
- synchronize(function() {
- test.teardown();
- });
- synchronize(function() {
- test.finish();
- });
- }
-
- // `bad` initialized at top of scope
- // defer when previous test run passed, if storage is available
- bad = QUnit.config.reorder && defined.sessionStorage &&
- +sessionStorage.getItem( "qunit-test-" + this.module + "-" + this.testName );
-
- if ( bad ) {
- run();
- } else {
- synchronize( run, true );
- }
- }
-};
-
-// Root QUnit object.
-// `QUnit` initialized at top of scope
-QUnit = {
-
- // call on start of module test to prepend name to all tests
- module: function( name, testEnvironment ) {
- config.currentModule = name;
- config.currentModuleTestEnvironment = testEnvironment;
- config.modules[name] = true;
- },
-
- asyncTest: function( testName, expected, callback ) {
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- QUnit.test( testName, expected, callback, true );
- },
-
- test: function( testName, expected, callback, async ) {
- var test,
- nameHtml = "" + escapeText( testName ) + "";
-
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- if ( config.currentModule ) {
- nameHtml = "" + escapeText( config.currentModule ) + ": " + nameHtml;
- }
-
- test = new Test({
- nameHtml: nameHtml,
- testName: testName,
- expected: expected,
- async: async,
- callback: callback,
- module: config.currentModule,
- moduleTestEnvironment: config.currentModuleTestEnvironment,
- stack: sourceFromStacktrace( 2 )
- });
-
- if ( !validTest( test ) ) {
- return;
- }
-
- test.queue();
- },
-
- // Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through.
- expect: function( asserts ) {
- if (arguments.length === 1) {
- config.current.expected = asserts;
- } else {
- return config.current.expected;
- }
- },
-
- start: function( count ) {
- // QUnit hasn't been initialized yet.
- // Note: RequireJS (et al) may delay onLoad
- if ( config.semaphore === undefined ) {
- QUnit.begin(function() {
- // This is triggered at the top of QUnit.load, push start() to the event loop, to allow QUnit.load to finish first
- setTimeout(function() {
- QUnit.start( count );
- });
- });
- return;
- }
-
- config.semaphore -= count || 1;
- // don't start until equal number of stop-calls
- if ( config.semaphore > 0 ) {
- return;
- }
- // ignore if start is called more often then stop
- if ( config.semaphore < 0 ) {
- config.semaphore = 0;
- QUnit.pushFailure( "Called start() while already started (QUnit.config.semaphore was 0 already)", null, sourceFromStacktrace(2) );
- return;
- }
- // A slight delay, to avoid any current callbacks
- if ( defined.setTimeout ) {
- window.setTimeout(function() {
- if ( config.semaphore > 0 ) {
- return;
- }
- if ( config.timeout ) {
- clearTimeout( config.timeout );
- }
-
- config.blocking = false;
- process( true );
- }, 13);
- } else {
- config.blocking = false;
- process( true );
- }
- },
-
- stop: function( count ) {
- config.semaphore += count || 1;
- config.blocking = true;
-
- if ( config.testTimeout && defined.setTimeout ) {
- clearTimeout( config.timeout );
- config.timeout = window.setTimeout(function() {
- QUnit.ok( false, "Test timed out" );
- config.semaphore = 1;
- QUnit.start();
- }, config.testTimeout );
- }
- }
-};
-
-// `assert` initialized at top of scope
-// Asssert helpers
-// All of these must either call QUnit.push() or manually do:
-// - runLoggingCallbacks( "log", .. );
-// - config.current.assertions.push({ .. });
-// We attach it to the QUnit object *after* we expose the public API,
-// otherwise `assert` will become a global variable in browsers (#341).
-assert = {
- /**
- * Asserts rough true-ish result.
- * @name ok
- * @function
- * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" );
- */
- ok: function( result, msg ) {
- if ( !config.current ) {
- throw new Error( "ok() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
- result = !!result;
-
- var source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: msg
- };
-
- msg = escapeText( msg || (result ? "okay" : "failed" ) );
- msg = "" + msg + "";
-
- if ( !result ) {
- source = sourceFromStacktrace( 2 );
- if ( source ) {
- details.source = source;
- msg += "Source: | " + escapeText( source ) + " |
---|
";
- }
- }
- runLoggingCallbacks( "log", QUnit, details );
- config.current.assertions.push({
- result: result,
- message: msg
- });
- },
-
- /**
- * Assert that the first two arguments are equal, with an optional message.
- * Prints out both actual and expected values.
- * @name equal
- * @function
- * @example equal( format( "Received {0} bytes.", 2), "Received 2 bytes.", "format() replaces {0} with next argument" );
- */
- equal: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected == actual, actual, expected, message );
- },
-
- /**
- * @name notEqual
- * @function
- */
- notEqual: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected != actual, actual, expected, message );
- },
-
- /**
- * @name propEqual
- * @function
- */
- propEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notPropEqual
- * @function
- */
- notPropEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name deepEqual
- * @function
- */
- deepEqual: function( actual, expected, message ) {
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notDeepEqual
- * @function
- */
- notDeepEqual: function( actual, expected, message ) {
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name strictEqual
- * @function
- */
- strictEqual: function( actual, expected, message ) {
- QUnit.push( expected === actual, actual, expected, message );
- },
-
- /**
- * @name notStrictEqual
- * @function
- */
- notStrictEqual: function( actual, expected, message ) {
- QUnit.push( expected !== actual, actual, expected, message );
- },
-
- "throws": function( block, expected, message ) {
- var actual,
- expectedOutput = expected,
- ok = false;
-
- // 'expected' is optional
- if ( typeof expected === "string" ) {
- message = expected;
- expected = null;
- }
-
- config.current.ignoreGlobalErrors = true;
- try {
- block.call( config.current.testEnvironment );
- } catch (e) {
- actual = e;
- }
- config.current.ignoreGlobalErrors = false;
-
- if ( actual ) {
- // we don't want to validate thrown error
- if ( !expected ) {
- ok = true;
- expectedOutput = null;
- // expected is a regexp
- } else if ( QUnit.objectType( expected ) === "regexp" ) {
- ok = expected.test( errorString( actual ) );
- // expected is a constructor
- } else if ( actual instanceof expected ) {
- ok = true;
- // expected is a validation function which returns true is validation passed
- } else if ( expected.call( {}, actual ) === true ) {
- expectedOutput = null;
- ok = true;
- }
-
- QUnit.push( ok, actual, expectedOutput, message );
- } else {
- QUnit.pushFailure( message, null, 'No exception was thrown.' );
- }
- }
-};
-
-/**
- * @deprecate since 1.8.0
- * Kept assertion helpers in root for backwards compatibility.
- */
-extend( QUnit, assert );
-
-/**
- * @deprecated since 1.9.0
- * Kept root "raises()" for backwards compatibility.
- * (Note that we don't introduce assert.raises).
- */
-QUnit.raises = assert[ "throws" ];
-
-/**
- * @deprecated since 1.0.0, replaced with error pushes since 1.3.0
- * Kept to avoid TypeErrors for undefined methods.
- */
-QUnit.equals = function() {
- QUnit.push( false, false, false, "QUnit.equals has been deprecated since 2009 (e88049a0), use QUnit.equal instead" );
-};
-QUnit.same = function() {
- QUnit.push( false, false, false, "QUnit.same has been deprecated since 2009 (e88049a0), use QUnit.deepEqual instead" );
-};
-
-// We want access to the constructor's prototype
-(function() {
- function F() {}
- F.prototype = QUnit;
- QUnit = new F();
- // Make F QUnit's constructor so that we can add to the prototype later
- QUnit.constructor = F;
-}());
-
-/**
- * Config object: Maintain internal state
- * Later exposed as QUnit.config
- * `config` initialized at top of scope
- */
-config = {
- // The queue of tests to run
- queue: [],
-
- // block until document ready
- blocking: true,
-
- // when enabled, show only failing tests
- // gets persisted through sessionStorage and can be changed in UI via checkbox
- hidepassed: false,
-
- // by default, run previously failed tests first
- // very useful in combination with "Hide passed tests" checked
- reorder: true,
-
- // by default, modify document.title when suite is done
- altertitle: true,
-
- // when enabled, all tests must call expect()
- requireExpects: false,
-
- // add checkboxes that are persisted in the query-string
- // when enabled, the id is set to `true` as a `QUnit.config` property
- urlConfig: [
- {
- id: "noglobals",
- label: "Check for Globals",
- tooltip: "Enabling this will test if any test introduces new properties on the `window` object. Stored as query-strings."
- },
- {
- id: "notrycatch",
- label: "No try-catch",
- tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging exceptions in IE reasonable. Stored as query-strings."
- }
- ],
-
- // Set of all modules.
- modules: {},
-
- // logging callback queues
- begin: [],
- done: [],
- log: [],
- testStart: [],
- testDone: [],
- moduleStart: [],
- moduleDone: []
-};
-
-// Export global variables, unless an 'exports' object exists,
-// in that case we assume we're in CommonJS (dealt with on the bottom of the script)
-if ( typeof exports === "undefined" ) {
- extend( window, QUnit );
-
- // Expose QUnit object
- window.QUnit = QUnit;
-}
-
-// Initialize more QUnit.config and QUnit.urlParams
-(function() {
- var i,
- location = window.location || { search: "", protocol: "file:" },
- params = location.search.slice( 1 ).split( "&" ),
- length = params.length,
- urlParams = {},
- current;
-
- if ( params[ 0 ] ) {
- for ( i = 0; i < length; i++ ) {
- current = params[ i ].split( "=" );
- current[ 0 ] = decodeURIComponent( current[ 0 ] );
- // allow just a key to turn on a flag, e.g., test.html?noglobals
- current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true;
- urlParams[ current[ 0 ] ] = current[ 1 ];
- }
- }
-
- QUnit.urlParams = urlParams;
-
- // String search anywhere in moduleName+testName
- config.filter = urlParams.filter;
-
- // Exact match of the module name
- config.module = urlParams.module;
-
- config.testNumber = parseInt( urlParams.testNumber, 10 ) || null;
-
- // Figure out if we're running the tests from a server or not
- QUnit.isLocal = location.protocol === "file:";
-}());
-
-// Extend QUnit object,
-// these after set here because they should not be exposed as global functions
-extend( QUnit, {
- assert: assert,
-
- config: config,
-
- // Initialize the configuration options
- init: function() {
- extend( config, {
- stats: { all: 0, bad: 0 },
- moduleStats: { all: 0, bad: 0 },
- started: +new Date(),
- updateRate: 1000,
- blocking: false,
- autostart: true,
- autorun: false,
- filter: "",
- queue: [],
- semaphore: 1
- });
-
- var tests, banner, result,
- qunit = id( "qunit" );
-
- if ( qunit ) {
- qunit.innerHTML =
- "" +
- "" +
- "" +
- "" +
- "
";
- }
-
- tests = id( "qunit-tests" );
- banner = id( "qunit-banner" );
- result = id( "qunit-testresult" );
-
- if ( tests ) {
- tests.innerHTML = "";
- }
-
- if ( banner ) {
- banner.className = "";
- }
-
- if ( result ) {
- result.parentNode.removeChild( result );
- }
-
- if ( tests ) {
- result = document.createElement( "p" );
- result.id = "qunit-testresult";
- result.className = "result";
- tests.parentNode.insertBefore( result, tests );
- result.innerHTML = "Running...
";
- }
- },
-
- // Resets the test setup. Useful for tests that modify the DOM.
- reset: function() {
- var fixture = id( "qunit-fixture" );
- if ( fixture ) {
- fixture.innerHTML = config.fixture;
- }
- },
-
- // Trigger an event on an element.
- // @example triggerEvent( document.body, "click" );
- triggerEvent: function( elem, type, event ) {
- if ( document.createEvent ) {
- event = document.createEvent( "MouseEvents" );
- event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView,
- 0, 0, 0, 0, 0, false, false, false, false, 0, null);
-
- elem.dispatchEvent( event );
- } else if ( elem.fireEvent ) {
- elem.fireEvent( "on" + type );
- }
- },
-
- // Safe object type checking
- is: function( type, obj ) {
- return QUnit.objectType( obj ) === type;
- },
-
- objectType: function( obj ) {
- if ( typeof obj === "undefined" ) {
- return "undefined";
- // consider: typeof null === object
- }
- if ( obj === null ) {
- return "null";
- }
-
- var match = toString.call( obj ).match(/^\[object\s(.*)\]$/),
- type = match && match[1] || "";
-
- switch ( type ) {
- case "Number":
- if ( isNaN(obj) ) {
- return "nan";
- }
- return "number";
- case "String":
- case "Boolean":
- case "Array":
- case "Date":
- case "RegExp":
- case "Function":
- return type.toLowerCase();
- }
- if ( typeof obj === "object" ) {
- return "object";
- }
- return undefined;
- },
-
- push: function( result, actual, expected, message ) {
- if ( !config.current ) {
- throw new Error( "assertion outside test context, was " + sourceFromStacktrace() );
- }
-
- var output, source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: message,
- actual: actual,
- expected: expected
- };
-
- message = escapeText( message ) || ( result ? "okay" : "failed" );
- message = "" + message + "";
- output = message;
-
- if ( !result ) {
- expected = escapeText( QUnit.jsDump.parse(expected) );
- actual = escapeText( QUnit.jsDump.parse(actual) );
- output += "Expected: | " + expected + " |
";
-
- if ( actual !== expected ) {
- output += "Result: | " + actual + " |
";
- output += "Diff: | " + QUnit.diff( expected, actual ) + " |
";
- }
-
- source = sourceFromStacktrace();
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
- }
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: !!result,
- message: output
- });
- },
-
- pushFailure: function( message, source, actual ) {
- if ( !config.current ) {
- throw new Error( "pushFailure() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
-
- var output,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: false,
- message: message
- };
-
- message = escapeText( message ) || "error";
- message = "" + message + "";
- output = message;
-
- output += "";
-
- if ( actual ) {
- output += "Result: | " + escapeText( actual ) + " |
";
- }
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: false,
- message: output
- });
- },
-
- url: function( params ) {
- params = extend( extend( {}, QUnit.urlParams ), params );
- var key,
- querystring = "?";
-
- for ( key in params ) {
- if ( !hasOwn.call( params, key ) ) {
- continue;
- }
- querystring += encodeURIComponent( key ) + "=" +
- encodeURIComponent( params[ key ] ) + "&";
- }
- return window.location.protocol + "//" + window.location.host +
- window.location.pathname + querystring.slice( 0, -1 );
- },
-
- extend: extend,
- id: id,
- addEvent: addEvent
- // load, equiv, jsDump, diff: Attached later
-});
-
-/**
- * @deprecated: Created for backwards compatibility with test runner that set the hook function
- * into QUnit.{hook}, instead of invoking it and passing the hook function.
- * QUnit.constructor is set to the empty F() above so that we can add to it's prototype here.
- * Doing this allows us to tell if the following methods have been overwritten on the actual
- * QUnit object.
- */
-extend( QUnit.constructor.prototype, {
-
- // Logging callbacks; all receive a single argument with the listed properties
- // run test/logs.html for any related changes
- begin: registerLoggingCallback( "begin" ),
-
- // done: { failed, passed, total, runtime }
- done: registerLoggingCallback( "done" ),
-
- // log: { result, actual, expected, message }
- log: registerLoggingCallback( "log" ),
-
- // testStart: { name }
- testStart: registerLoggingCallback( "testStart" ),
-
- // testDone: { name, failed, passed, total, duration }
- testDone: registerLoggingCallback( "testDone" ),
-
- // moduleStart: { name }
- moduleStart: registerLoggingCallback( "moduleStart" ),
-
- // moduleDone: { name, failed, passed, total }
- moduleDone: registerLoggingCallback( "moduleDone" )
-});
-
-if ( typeof document === "undefined" || document.readyState === "complete" ) {
- config.autorun = true;
-}
-
-QUnit.load = function() {
- runLoggingCallbacks( "begin", QUnit, {} );
-
- // Initialize the config, saving the execution queue
- var banner, filter, i, label, len, main, ol, toolbar, userAgent, val,
- urlConfigCheckboxesContainer, urlConfigCheckboxes, moduleFilter,
- numModules = 0,
- moduleFilterHtml = "",
- urlConfigHtml = "",
- oldconfig = extend( {}, config );
-
- QUnit.init();
- extend(config, oldconfig);
-
- config.blocking = false;
-
- len = config.urlConfig.length;
-
- for ( i = 0; i < len; i++ ) {
- val = config.urlConfig[i];
- if ( typeof val === "string" ) {
- val = {
- id: val,
- label: val,
- tooltip: "[no tooltip available]"
- };
- }
- config[ val.id ] = QUnit.urlParams[ val.id ];
- urlConfigHtml += "";
- }
-
- moduleFilterHtml += "";
-
- // `userAgent` initialized at top of scope
- userAgent = id( "qunit-userAgent" );
- if ( userAgent ) {
- userAgent.innerHTML = navigator.userAgent;
- }
-
- // `banner` initialized at top of scope
- banner = id( "qunit-header" );
- if ( banner ) {
- banner.innerHTML = "" + banner.innerHTML + " ";
- }
-
- // `toolbar` initialized at top of scope
- toolbar = id( "qunit-testrunner-toolbar" );
- if ( toolbar ) {
- // `filter` initialized at top of scope
- filter = document.createElement( "input" );
- filter.type = "checkbox";
- filter.id = "qunit-filter-pass";
-
- addEvent( filter, "click", function() {
- var tmp,
- ol = document.getElementById( "qunit-tests" );
-
- if ( filter.checked ) {
- ol.className = ol.className + " hidepass";
- } else {
- tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " ";
- ol.className = tmp.replace( / hidepass /, " " );
- }
- if ( defined.sessionStorage ) {
- if (filter.checked) {
- sessionStorage.setItem( "qunit-filter-passed-tests", "true" );
- } else {
- sessionStorage.removeItem( "qunit-filter-passed-tests" );
- }
- }
- });
-
- if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem( "qunit-filter-passed-tests" ) ) {
- filter.checked = true;
- // `ol` initialized at top of scope
- ol = document.getElementById( "qunit-tests" );
- ol.className = ol.className + " hidepass";
- }
- toolbar.appendChild( filter );
-
- // `label` initialized at top of scope
- label = document.createElement( "label" );
- label.setAttribute( "for", "qunit-filter-pass" );
- label.setAttribute( "title", "Only show tests and assertons that fail. Stored in sessionStorage." );
- label.innerHTML = "Hide passed tests";
- toolbar.appendChild( label );
-
- urlConfigCheckboxesContainer = document.createElement("span");
- urlConfigCheckboxesContainer.innerHTML = urlConfigHtml;
- urlConfigCheckboxes = urlConfigCheckboxesContainer.getElementsByTagName("input");
- // For oldIE support:
- // * Add handlers to the individual elements instead of the container
- // * Use "click" instead of "change"
- // * Fallback from event.target to event.srcElement
- addEvents( urlConfigCheckboxes, "click", function( event ) {
- var params = {},
- target = event.target || event.srcElement;
- params[ target.name ] = target.checked ? true : undefined;
- window.location = QUnit.url( params );
- });
- toolbar.appendChild( urlConfigCheckboxesContainer );
-
- if (numModules > 1) {
- moduleFilter = document.createElement( 'span' );
- moduleFilter.setAttribute( 'id', 'qunit-modulefilter-container' );
- moduleFilter.innerHTML = moduleFilterHtml;
- addEvent( moduleFilter.lastChild, "change", function() {
- var selectBox = moduleFilter.getElementsByTagName("select")[0],
- selectedModule = decodeURIComponent(selectBox.options[selectBox.selectedIndex].value);
-
- window.location = QUnit.url( { module: ( selectedModule === "" ) ? undefined : selectedModule } );
- });
- toolbar.appendChild(moduleFilter);
- }
- }
-
- // `main` initialized at top of scope
- main = id( "qunit-fixture" );
- if ( main ) {
- config.fixture = main.innerHTML;
- }
-
- if ( config.autostart ) {
- QUnit.start();
- }
-};
-
-addEvent( window, "load", QUnit.load );
-
-// `onErrorFnPrev` initialized at top of scope
-// Preserve other handlers
-onErrorFnPrev = window.onerror;
-
-// Cover uncaught exceptions
-// Returning true will surpress the default browser handler,
-// returning false will let it run.
-window.onerror = function ( error, filePath, linerNr ) {
- var ret = false;
- if ( onErrorFnPrev ) {
- ret = onErrorFnPrev( error, filePath, linerNr );
- }
-
- // Treat return value as window.onerror itself does,
- // Only do our handling if not surpressed.
- if ( ret !== true ) {
- if ( QUnit.config.current ) {
- if ( QUnit.config.current.ignoreGlobalErrors ) {
- return true;
- }
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- } else {
- QUnit.test( "global failure", extend( function() {
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- }, { validTest: validTest } ) );
- }
- return false;
- }
-
- return ret;
-};
-
-function done() {
- config.autorun = true;
-
- // Log the last module results
- if ( config.currentModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.currentModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
-
- var i, key,
- banner = id( "qunit-banner" ),
- tests = id( "qunit-tests" ),
- runtime = +new Date() - config.started,
- passed = config.stats.all - config.stats.bad,
- html = [
- "Tests completed in ",
- runtime,
- " milliseconds.
",
- "",
- passed,
- " assertions of ",
- config.stats.all,
- " passed, ",
- config.stats.bad,
- " failed."
- ].join( "" );
-
- if ( banner ) {
- banner.className = ( config.stats.bad ? "qunit-fail" : "qunit-pass" );
- }
-
- if ( tests ) {
- id( "qunit-testresult" ).innerHTML = html;
- }
-
- if ( config.altertitle && typeof document !== "undefined" && document.title ) {
- // show ✖ for good, ✔ for bad suite result in title
- // use escape sequences in case file gets loaded with non-utf-8-charset
- document.title = [
- ( config.stats.bad ? "\u2716" : "\u2714" ),
- document.title.replace( /^[\u2714\u2716] /i, "" )
- ].join( " " );
- }
-
- // clear own sessionStorage items if all tests passed
- if ( config.reorder && defined.sessionStorage && config.stats.bad === 0 ) {
- // `key` & `i` initialized at top of scope
- for ( i = 0; i < sessionStorage.length; i++ ) {
- key = sessionStorage.key( i++ );
- if ( key.indexOf( "qunit-test-" ) === 0 ) {
- sessionStorage.removeItem( key );
- }
- }
- }
-
- // scroll back to top to show results
- if ( window.scrollTo ) {
- window.scrollTo(0, 0);
- }
-
- runLoggingCallbacks( "done", QUnit, {
- failed: config.stats.bad,
- passed: passed,
- total: config.stats.all,
- runtime: runtime
- });
-}
-
-/** @return Boolean: true if this test should be ran */
-function validTest( test ) {
- var include,
- filter = config.filter && config.filter.toLowerCase(),
- module = config.module && config.module.toLowerCase(),
- fullName = (test.module + ": " + test.testName).toLowerCase();
-
- // Internally-generated tests are always valid
- if ( test.callback && test.callback.validTest === validTest ) {
- delete test.callback.validTest;
- return true;
- }
-
- if ( config.testNumber ) {
- return test.testNumber === config.testNumber;
- }
-
- if ( module && ( !test.module || test.module.toLowerCase() !== module ) ) {
- return false;
- }
-
- if ( !filter ) {
- return true;
- }
-
- include = filter.charAt( 0 ) !== "!";
- if ( !include ) {
- filter = filter.slice( 1 );
- }
-
- // If the filter matches, we need to honour include
- if ( fullName.indexOf( filter ) !== -1 ) {
- return include;
- }
-
- // Otherwise, do the opposite
- return !include;
-}
-
-// so far supports only Firefox, Chrome and Opera (buggy), Safari (for real exceptions)
-// Later Safari and IE10 are supposed to support error.stack as well
-// See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack
-function extractStacktrace( e, offset ) {
- offset = offset === undefined ? 3 : offset;
-
- var stack, include, i;
-
- if ( e.stacktrace ) {
- // Opera
- return e.stacktrace.split( "\n" )[ offset + 3 ];
- } else if ( e.stack ) {
- // Firefox, Chrome
- stack = e.stack.split( "\n" );
- if (/^error$/i.test( stack[0] ) ) {
- stack.shift();
- }
- if ( fileName ) {
- include = [];
- for ( i = offset; i < stack.length; i++ ) {
- if ( stack[ i ].indexOf( fileName ) !== -1 ) {
- break;
- }
- include.push( stack[ i ] );
- }
- if ( include.length ) {
- return include.join( "\n" );
- }
- }
- return stack[ offset ];
- } else if ( e.sourceURL ) {
- // Safari, PhantomJS
- // hopefully one day Safari provides actual stacktraces
- // exclude useless self-reference for generated Error objects
- if ( /qunit.js$/.test( e.sourceURL ) ) {
- return;
- }
- // for actual exceptions, this is useful
- return e.sourceURL + ":" + e.line;
- }
-}
-function sourceFromStacktrace( offset ) {
- try {
- throw new Error();
- } catch ( e ) {
- return extractStacktrace( e, offset );
- }
-}
-
-/**
- * Escape text for attribute or text content.
- */
-function escapeText( s ) {
- if ( !s ) {
- return "";
- }
- s = s + "";
- // Both single quotes and double quotes (for attributes)
- return s.replace( /['"<>&]/g, function( s ) {
- switch( s ) {
- case '\'':
- return ''';
- case '"':
- return '"';
- case '<':
- return '<';
- case '>':
- return '>';
- case '&':
- return '&';
- }
- });
-}
-
-function synchronize( callback, last ) {
- config.queue.push( callback );
-
- if ( config.autorun && !config.blocking ) {
- process( last );
- }
-}
-
-function process( last ) {
- function next() {
- process( last );
- }
- var start = new Date().getTime();
- config.depth = config.depth ? config.depth + 1 : 1;
-
- while ( config.queue.length && !config.blocking ) {
- if ( !defined.setTimeout || config.updateRate <= 0 || ( ( new Date().getTime() - start ) < config.updateRate ) ) {
- config.queue.shift()();
- } else {
- window.setTimeout( next, 13 );
- break;
- }
- }
- config.depth--;
- if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) {
- done();
- }
-}
-
-function saveGlobal() {
- config.pollution = [];
-
- if ( config.noglobals ) {
- for ( var key in window ) {
- // in Opera sometimes DOM element ids show up here, ignore them
- if ( !hasOwn.call( window, key ) || /^qunit-test-output/.test( key ) ) {
- continue;
- }
- config.pollution.push( key );
- }
- }
-}
-
-function checkPollution() {
- var newGlobals,
- deletedGlobals,
- old = config.pollution;
-
- saveGlobal();
-
- newGlobals = diff( config.pollution, old );
- if ( newGlobals.length > 0 ) {
- QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join(", ") );
- }
-
- deletedGlobals = diff( old, config.pollution );
- if ( deletedGlobals.length > 0 ) {
- QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join(", ") );
- }
-}
-
-// returns a new Array with the elements that are in a but not in b
-function diff( a, b ) {
- var i, j,
- result = a.slice();
-
- for ( i = 0; i < result.length; i++ ) {
- for ( j = 0; j < b.length; j++ ) {
- if ( result[i] === b[j] ) {
- result.splice( i, 1 );
- i--;
- break;
- }
- }
- }
- return result;
-}
-
-function extend( a, b ) {
- for ( var prop in b ) {
- if ( b[ prop ] === undefined ) {
- delete a[ prop ];
-
- // Avoid "Member not found" error in IE8 caused by setting window.constructor
- } else if ( prop !== "constructor" || a !== window ) {
- a[ prop ] = b[ prop ];
- }
- }
-
- return a;
-}
-
-/**
- * @param {HTMLElement} elem
- * @param {string} type
- * @param {Function} fn
- */
-function addEvent( elem, type, fn ) {
- // Standards-based browsers
- if ( elem.addEventListener ) {
- elem.addEventListener( type, fn, false );
- // IE
- } else {
- elem.attachEvent( "on" + type, fn );
- }
-}
-
-/**
- * @param {Array|NodeList} elems
- * @param {string} type
- * @param {Function} fn
- */
-function addEvents( elems, type, fn ) {
- var i = elems.length;
- while ( i-- ) {
- addEvent( elems[i], type, fn );
- }
-}
-
-function hasClass( elem, name ) {
- return (" " + elem.className + " ").indexOf(" " + name + " ") > -1;
-}
-
-function addClass( elem, name ) {
- if ( !hasClass( elem, name ) ) {
- elem.className += (elem.className ? " " : "") + name;
- }
-}
-
-function removeClass( elem, name ) {
- var set = " " + elem.className + " ";
- // Class name may appear multiple times
- while ( set.indexOf(" " + name + " ") > -1 ) {
- set = set.replace(" " + name + " " , " ");
- }
- // If possible, trim it for prettiness, but not neccecarily
- elem.className = window.jQuery ? jQuery.trim( set ) : ( set.trim ? set.trim() : set );
-}
-
-function id( name ) {
- return !!( typeof document !== "undefined" && document && document.getElementById ) &&
- document.getElementById( name );
-}
-
-function registerLoggingCallback( key ) {
- return function( callback ) {
- config[key].push( callback );
- };
-}
-
-// Supports deprecated method of completely overwriting logging callbacks
-function runLoggingCallbacks( key, scope, args ) {
- var i, callbacks;
- if ( QUnit.hasOwnProperty( key ) ) {
- QUnit[ key ].call(scope, args );
- } else {
- callbacks = config[ key ];
- for ( i = 0; i < callbacks.length; i++ ) {
- callbacks[ i ].call( scope, args );
- }
- }
-}
-
-// Test for equality any JavaScript type.
-// Author: Philippe Rathé
-QUnit.equiv = (function() {
-
- // Call the o related callback with the given arguments.
- function bindCallbacks( o, callbacks, args ) {
- var prop = QUnit.objectType( o );
- if ( prop ) {
- if ( QUnit.objectType( callbacks[ prop ] ) === "function" ) {
- return callbacks[ prop ].apply( callbacks, args );
- } else {
- return callbacks[ prop ]; // or undefined
- }
- }
- }
-
- // the real equiv function
- var innerEquiv,
- // stack to decide between skip/abort functions
- callers = [],
- // stack to avoiding loops from circular referencing
- parents = [],
-
- getProto = Object.getPrototypeOf || function ( obj ) {
- return obj.__proto__;
- },
- callbacks = (function () {
-
- // for string, boolean, number and null
- function useStrictEquality( b, a ) {
- /*jshint eqeqeq:false */
- if ( b instanceof a.constructor || a instanceof b.constructor ) {
- // to catch short annotaion VS 'new' annotation of a
- // declaration
- // e.g. var i = 1;
- // var j = new Number(1);
- return a == b;
- } else {
- return a === b;
- }
- }
-
- return {
- "string": useStrictEquality,
- "boolean": useStrictEquality,
- "number": useStrictEquality,
- "null": useStrictEquality,
- "undefined": useStrictEquality,
-
- "nan": function( b ) {
- return isNaN( b );
- },
-
- "date": function( b, a ) {
- return QUnit.objectType( b ) === "date" && a.valueOf() === b.valueOf();
- },
-
- "regexp": function( b, a ) {
- return QUnit.objectType( b ) === "regexp" &&
- // the regex itself
- a.source === b.source &&
- // and its modifers
- a.global === b.global &&
- // (gmi) ...
- a.ignoreCase === b.ignoreCase &&
- a.multiline === b.multiline &&
- a.sticky === b.sticky;
- },
-
- // - skip when the property is a method of an instance (OOP)
- // - abort otherwise,
- // initial === would have catch identical references anyway
- "function": function() {
- var caller = callers[callers.length - 1];
- return caller !== Object && typeof caller !== "undefined";
- },
-
- "array": function( b, a ) {
- var i, j, len, loop;
-
- // b could be an object literal here
- if ( QUnit.objectType( b ) !== "array" ) {
- return false;
- }
-
- len = a.length;
- if ( len !== b.length ) {
- // safe and faster
- return false;
- }
-
- // track reference to avoid circular references
- parents.push( a );
- for ( i = 0; i < len; i++ ) {
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- loop = true;// dont rewalk array
- }
- }
- if ( !loop && !innerEquiv(a[i], b[i]) ) {
- parents.pop();
- return false;
- }
- }
- parents.pop();
- return true;
- },
-
- "object": function( b, a ) {
- var i, j, loop,
- // Default to true
- eq = true,
- aProperties = [],
- bProperties = [];
-
- // comparing constructors is more strict than using
- // instanceof
- if ( a.constructor !== b.constructor ) {
- // Allow objects with no prototype to be equivalent to
- // objects with Object as their constructor.
- if ( !(( getProto(a) === null && getProto(b) === Object.prototype ) ||
- ( getProto(b) === null && getProto(a) === Object.prototype ) ) ) {
- return false;
- }
- }
-
- // stack constructor before traversing properties
- callers.push( a.constructor );
- // track reference to avoid circular references
- parents.push( a );
-
- for ( i in a ) { // be strict: don't ensures hasOwnProperty
- // and go deep
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- // don't go down the same path twice
- loop = true;
- }
- }
- aProperties.push(i); // collect a's properties
-
- if (!loop && !innerEquiv( a[i], b[i] ) ) {
- eq = false;
- break;
- }
- }
-
- callers.pop(); // unstack, we are done
- parents.pop();
-
- for ( i in b ) {
- bProperties.push( i ); // collect b's properties
- }
-
- // Ensures identical properties name
- return eq && innerEquiv( aProperties.sort(), bProperties.sort() );
- }
- };
- }());
-
- innerEquiv = function() { // can take multiple arguments
- var args = [].slice.apply( arguments );
- if ( args.length < 2 ) {
- return true; // end transition
- }
-
- return (function( a, b ) {
- if ( a === b ) {
- return true; // catch the most you can
- } else if ( a === null || b === null || typeof a === "undefined" ||
- typeof b === "undefined" ||
- QUnit.objectType(a) !== QUnit.objectType(b) ) {
- return false; // don't lose time with error prone cases
- } else {
- return bindCallbacks(a, callbacks, [ b, a ]);
- }
-
- // apply transition with (1..n) arguments
- }( args[0], args[1] ) && arguments.callee.apply( this, args.splice(1, args.length - 1 )) );
- };
-
- return innerEquiv;
-}());
-
-/**
- * jsDump Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com |
- * http://flesler.blogspot.com Licensed under BSD
- * (http://www.opensource.org/licenses/bsd-license.php) Date: 5/15/2008
- *
- * @projectDescription Advanced and extensible data dumping for Javascript.
- * @version 1.0.0
- * @author Ariel Flesler
- * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html}
- */
-QUnit.jsDump = (function() {
- function quote( str ) {
- return '"' + str.toString().replace( /"/g, '\\"' ) + '"';
- }
- function literal( o ) {
- return o + "";
- }
- function join( pre, arr, post ) {
- var s = jsDump.separator(),
- base = jsDump.indent(),
- inner = jsDump.indent(1);
- if ( arr.join ) {
- arr = arr.join( "," + s + inner );
- }
- if ( !arr ) {
- return pre + post;
- }
- return [ pre, inner + arr, base + post ].join(s);
- }
- function array( arr, stack ) {
- var i = arr.length, ret = new Array(i);
- this.up();
- while ( i-- ) {
- ret[i] = this.parse( arr[i] , undefined , stack);
- }
- this.down();
- return join( "[", ret, "]" );
- }
-
- var reName = /^function (\w+)/,
- jsDump = {
- // type is used mostly internally, you can fix a (custom)type in advance
- parse: function( obj, type, stack ) {
- stack = stack || [ ];
- var inStack, res,
- parser = this.parsers[ type || this.typeOf(obj) ];
-
- type = typeof parser;
- inStack = inArray( obj, stack );
-
- if ( inStack !== -1 ) {
- return "recursion(" + (inStack - stack.length) + ")";
- }
- if ( type === "function" ) {
- stack.push( obj );
- res = parser.call( this, obj, stack );
- stack.pop();
- return res;
- }
- return ( type === "string" ) ? parser : this.parsers.error;
- },
- typeOf: function( obj ) {
- var type;
- if ( obj === null ) {
- type = "null";
- } else if ( typeof obj === "undefined" ) {
- type = "undefined";
- } else if ( QUnit.is( "regexp", obj) ) {
- type = "regexp";
- } else if ( QUnit.is( "date", obj) ) {
- type = "date";
- } else if ( QUnit.is( "function", obj) ) {
- type = "function";
- } else if ( typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined" ) {
- type = "window";
- } else if ( obj.nodeType === 9 ) {
- type = "document";
- } else if ( obj.nodeType ) {
- type = "node";
- } else if (
- // native arrays
- toString.call( obj ) === "[object Array]" ||
- // NodeList objects
- ( typeof obj.length === "number" && typeof obj.item !== "undefined" && ( obj.length ? obj.item(0) === obj[0] : ( obj.item( 0 ) === null && typeof obj[0] === "undefined" ) ) )
- ) {
- type = "array";
- } else if ( obj.constructor === Error.prototype.constructor ) {
- type = "error";
- } else {
- type = typeof obj;
- }
- return type;
- },
- separator: function() {
- return this.multiline ? this.HTML ? "
" : "\n" : this.HTML ? " " : " ";
- },
- // extra can be a number, shortcut for increasing-calling-decreasing
- indent: function( extra ) {
- if ( !this.multiline ) {
- return "";
- }
- var chr = this.indentChar;
- if ( this.HTML ) {
- chr = chr.replace( /\t/g, " " ).replace( / /g, " " );
- }
- return new Array( this._depth_ + (extra||0) ).join(chr);
- },
- up: function( a ) {
- this._depth_ += a || 1;
- },
- down: function( a ) {
- this._depth_ -= a || 1;
- },
- setParser: function( name, parser ) {
- this.parsers[name] = parser;
- },
- // The next 3 are exposed so you can use them
- quote: quote,
- literal: literal,
- join: join,
- //
- _depth_: 1,
- // This is the list of parsers, to modify them, use jsDump.setParser
- parsers: {
- window: "[Window]",
- document: "[Document]",
- error: function(error) {
- return "Error(\"" + error.message + "\")";
- },
- unknown: "[Unknown]",
- "null": "null",
- "undefined": "undefined",
- "function": function( fn ) {
- var ret = "function",
- // functions never have name in IE
- name = "name" in fn ? fn.name : (reName.exec(fn) || [])[1];
-
- if ( name ) {
- ret += " " + name;
- }
- ret += "( ";
-
- ret = [ ret, QUnit.jsDump.parse( fn, "functionArgs" ), "){" ].join( "" );
- return join( ret, QUnit.jsDump.parse(fn,"functionCode" ), "}" );
- },
- array: array,
- nodelist: array,
- "arguments": array,
- object: function( map, stack ) {
- var ret = [ ], keys, key, val, i;
- QUnit.jsDump.up();
- keys = [];
- for ( key in map ) {
- keys.push( key );
- }
- keys.sort();
- for ( i = 0; i < keys.length; i++ ) {
- key = keys[ i ];
- val = map[ key ];
- ret.push( QUnit.jsDump.parse( key, "key" ) + ": " + QUnit.jsDump.parse( val, undefined, stack ) );
- }
- QUnit.jsDump.down();
- return join( "{", ret, "}" );
- },
- node: function( node ) {
- var len, i, val,
- open = QUnit.jsDump.HTML ? "<" : "<",
- close = QUnit.jsDump.HTML ? ">" : ">",
- tag = node.nodeName.toLowerCase(),
- ret = open + tag,
- attrs = node.attributes;
-
- if ( attrs ) {
- for ( i = 0, len = attrs.length; i < len; i++ ) {
- val = attrs[i].nodeValue;
- // IE6 includes all attributes in .attributes, even ones not explicitly set.
- // Those have values like undefined, null, 0, false, "" or "inherit".
- if ( val && val !== "inherit" ) {
- ret += " " + attrs[i].nodeName + "=" + QUnit.jsDump.parse( val, "attribute" );
- }
- }
- }
- ret += close;
-
- // Show content of TextNode or CDATASection
- if ( node.nodeType === 3 || node.nodeType === 4 ) {
- ret += node.nodeValue;
- }
-
- return ret + open + "/" + tag + close;
- },
- // function calls it internally, it's the arguments part of the function
- functionArgs: function( fn ) {
- var args,
- l = fn.length;
-
- if ( !l ) {
- return "";
- }
-
- args = new Array(l);
- while ( l-- ) {
- // 97 is 'a'
- args[l] = String.fromCharCode(97+l);
- }
- return " " + args.join( ", " ) + " ";
- },
- // object calls it internally, the key part of an item in a map
- key: quote,
- // function calls it internally, it's the content of the function
- functionCode: "[code]",
- // node calls it internally, it's an html attribute value
- attribute: quote,
- string: quote,
- date: quote,
- regexp: literal,
- number: literal,
- "boolean": literal
- },
- // if true, entities are escaped ( <, >, \t, space and \n )
- HTML: false,
- // indentation unit
- indentChar: " ",
- // if true, items in a collection, are separated by a \n, else just a space.
- multiline: true
- };
-
- return jsDump;
-}());
-
-// from jquery.js
-function inArray( elem, array ) {
- if ( array.indexOf ) {
- return array.indexOf( elem );
- }
-
- for ( var i = 0, length = array.length; i < length; i++ ) {
- if ( array[ i ] === elem ) {
- return i;
- }
- }
-
- return -1;
-}
-
-/*
- * Javascript Diff Algorithm
- * By John Resig (http://ejohn.org/)
- * Modified by Chu Alan "sprite"
- *
- * Released under the MIT license.
- *
- * More Info:
- * http://ejohn.org/projects/javascript-diff-algorithm/
- *
- * Usage: QUnit.diff(expected, actual)
- *
- * QUnit.diff( "the quick brown fox jumped over", "the quick fox jumps over" ) == "the quick brown fox jumped jumps over"
- */
-QUnit.diff = (function() {
- /*jshint eqeqeq:false, eqnull:true */
- function diff( o, n ) {
- var i,
- ns = {},
- os = {};
-
- for ( i = 0; i < n.length; i++ ) {
- if ( !hasOwn.call( ns, n[i] ) ) {
- ns[ n[i] ] = {
- rows: [],
- o: null
- };
- }
- ns[ n[i] ].rows.push( i );
- }
-
- for ( i = 0; i < o.length; i++ ) {
- if ( !hasOwn.call( os, o[i] ) ) {
- os[ o[i] ] = {
- rows: [],
- n: null
- };
- }
- os[ o[i] ].rows.push( i );
- }
-
- for ( i in ns ) {
- if ( !hasOwn.call( ns, i ) ) {
- continue;
- }
- if ( ns[i].rows.length === 1 && hasOwn.call( os, i ) && os[i].rows.length === 1 ) {
- n[ ns[i].rows[0] ] = {
- text: n[ ns[i].rows[0] ],
- row: os[i].rows[0]
- };
- o[ os[i].rows[0] ] = {
- text: o[ os[i].rows[0] ],
- row: ns[i].rows[0]
- };
- }
- }
-
- for ( i = 0; i < n.length - 1; i++ ) {
- if ( n[i].text != null && n[ i + 1 ].text == null && n[i].row + 1 < o.length && o[ n[i].row + 1 ].text == null &&
- n[ i + 1 ] == o[ n[i].row + 1 ] ) {
-
- n[ i + 1 ] = {
- text: n[ i + 1 ],
- row: n[i].row + 1
- };
- o[ n[i].row + 1 ] = {
- text: o[ n[i].row + 1 ],
- row: i + 1
- };
- }
- }
-
- for ( i = n.length - 1; i > 0; i-- ) {
- if ( n[i].text != null && n[ i - 1 ].text == null && n[i].row > 0 && o[ n[i].row - 1 ].text == null &&
- n[ i - 1 ] == o[ n[i].row - 1 ]) {
-
- n[ i - 1 ] = {
- text: n[ i - 1 ],
- row: n[i].row - 1
- };
- o[ n[i].row - 1 ] = {
- text: o[ n[i].row - 1 ],
- row: i - 1
- };
- }
- }
-
- return {
- o: o,
- n: n
- };
- }
-
- return function( o, n ) {
- o = o.replace( /\s+$/, "" );
- n = n.replace( /\s+$/, "" );
-
- var i, pre,
- str = "",
- out = diff( o === "" ? [] : o.split(/\s+/), n === "" ? [] : n.split(/\s+/) ),
- oSpace = o.match(/\s+/g),
- nSpace = n.match(/\s+/g);
-
- if ( oSpace == null ) {
- oSpace = [ " " ];
- }
- else {
- oSpace.push( " " );
- }
-
- if ( nSpace == null ) {
- nSpace = [ " " ];
- }
- else {
- nSpace.push( " " );
- }
-
- if ( out.n.length === 0 ) {
- for ( i = 0; i < out.o.length; i++ ) {
- str += "" + out.o[i] + oSpace[i] + "";
- }
- }
- else {
- if ( out.n[0].text == null ) {
- for ( n = 0; n < out.o.length && out.o[n].text == null; n++ ) {
- str += "" + out.o[n] + oSpace[n] + "";
- }
- }
-
- for ( i = 0; i < out.n.length; i++ ) {
- if (out.n[i].text == null) {
- str += "" + out.n[i] + nSpace[i] + "";
- }
- else {
- // `pre` initialized at top of scope
- pre = "";
-
- for ( n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++ ) {
- pre += "" + out.o[n] + oSpace[n] + "";
- }
- str += " " + out.n[i].text + nSpace[i] + pre;
- }
- }
- }
-
- return str;
- };
-}());
-
-// for CommonJS enviroments, export everything
-if ( typeof exports !== "undefined" ) {
- extend( exports, QUnit );
-}
-
-// get at whatever the global object is, like window in browsers
-}( (function() {return this;}.call()) ));
diff --git a/test/lib/require.js b/test/lib/require.js
deleted file mode 100644
index 987f865..0000000
--- a/test/lib/require.js
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- RequireJS 2.1.5 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.
- Available via the MIT or new BSD license.
- see: http://github.com/jrburke/requirejs for details
-*/
-var requirejs,require,define;
-(function(aa){function I(b){return"[object Function]"===L.call(b)}function J(b){return"[object Array]"===L.call(b)}function y(b,c){if(b){var d;for(d=0;dthis.depCount&&!this.defined){if(I(n)){if(this.events.error)try{e=i.execCb(c,n,b,e)}catch(d){a=d}else e=i.execCb(c,n,b,e);this.map.isDefine&&((b=this.module)&&void 0!==b.exports&&b.exports!==this.exports?e=b.exports:void 0===e&&this.usingExports&&(e=this.exports));if(a)return a.requireMap=this.map,a.requireModules=[this.map.id],a.requireType="define",v(this.error=
-a)}else e=n;this.exports=e;if(this.map.isDefine&&!this.ignore&&(q[c]=e,l.onResourceLoad))l.onResourceLoad(i,this.map,this.depMaps);x(c);this.defined=!0}this.defining=!1;this.defined&&!this.defineEmitted&&(this.defineEmitted=!0,this.emit("defined",this.exports),this.defineEmitComplete=!0)}}else this.fetch()}},callPlugin:function(){var a=this.map,b=a.id,d=j(a.prefix);this.depMaps.push(d);t(d,"defined",u(this,function(e){var n,d;d=this.map.name;var g=this.map.parentMap?this.map.parentMap.name:null,h=
-i.makeRequire(a.parentMap,{enableBuildCallback:!0});if(this.map.unnormalized){if(e.normalize&&(d=e.normalize(d,function(a){return c(a,g,!0)})||""),e=j(a.prefix+"!"+d,this.map.parentMap),t(e,"defined",u(this,function(a){this.init([],function(){return a},null,{enabled:!0,ignore:!0})})),d=m(p,e.id)){this.depMaps.push(e);if(this.events.error)d.on("error",u(this,function(a){this.emit("error",a)}));d.enable()}}else n=u(this,function(a){this.init([],function(){return a},null,{enabled:!0})}),n.error=u(this,
-function(a){this.inited=!0;this.error=a;a.requireModules=[b];G(p,function(a){0===a.map.id.indexOf(b+"_unnormalized")&&x(a.map.id)});v(a)}),n.fromText=u(this,function(e,c){var d=a.name,g=j(d),C=O;c&&(e=c);C&&(O=!1);r(g);s(k.config,b)&&(k.config[d]=k.config[b]);try{l.exec(e)}catch(ca){return v(B("fromtexteval","fromText eval for "+b+" failed: "+ca,ca,[b]))}C&&(O=!0);this.depMaps.push(g);i.completeLoad(d);h([d],n)}),e.load(a.name,h,n,k)}));i.enable(d,this);this.pluginMaps[d.id]=d},enable:function(){V[this.map.id]=
-this;this.enabling=this.enabled=!0;y(this.depMaps,u(this,function(a,b){var c,e;if("string"===typeof a){a=j(a,this.map.isDefine?this.map:this.map.parentMap,!1,!this.skipMap);this.depMaps[b]=a;if(c=m(N,a.id)){this.depExports[b]=c(this);return}this.depCount+=1;t(a,"defined",u(this,function(a){this.defineDep(b,a);this.check()}));this.errback&&t(a,"error",this.errback)}c=a.id;e=p[c];!s(N,c)&&(e&&!e.enabled)&&i.enable(a,this)}));G(this.pluginMaps,u(this,function(a){var b=m(p,a.id);b&&!b.enabled&&i.enable(a,
-this)}));this.enabling=!1;this.check()},on:function(a,b){var c=this.events[a];c||(c=this.events[a]=[]);c.push(b)},emit:function(a,b){y(this.events[a],function(a){a(b)});"error"===a&&delete this.events[a]}};i={config:k,contextName:b,registry:p,defined:q,urlFetched:U,defQueue:H,Module:Z,makeModuleMap:j,nextTick:l.nextTick,onError:v,configure:function(a){a.baseUrl&&"/"!==a.baseUrl.charAt(a.baseUrl.length-1)&&(a.baseUrl+="/");var b=k.pkgs,c=k.shim,e={paths:!0,config:!0,map:!0};G(a,function(a,b){e[b]?
-"map"===b?(k.map||(k.map={}),R(k[b],a,!0,!0)):R(k[b],a,!0):k[b]=a});a.shim&&(G(a.shim,function(a,b){J(a)&&(a={deps:a});if((a.exports||a.init)&&!a.exportsFn)a.exportsFn=i.makeShimExports(a);c[b]=a}),k.shim=c);a.packages&&(y(a.packages,function(a){a="string"===typeof a?{name:a}:a;b[a.name]={name:a.name,location:a.location||a.name,main:(a.main||"main").replace(ja,"").replace(ea,"")}}),k.pkgs=b);G(p,function(a,b){!a.inited&&!a.map.unnormalized&&(a.map=j(b))});if(a.deps||a.callback)i.require(a.deps||[],
-a.callback)},makeShimExports:function(a){return function(){var b;a.init&&(b=a.init.apply(aa,arguments));return b||a.exports&&ba(a.exports)}},makeRequire:function(a,f){function d(e,c,h){var g,k;f.enableBuildCallback&&(c&&I(c))&&(c.__requireJsBuild=!0);if("string"===typeof e){if(I(c))return v(B("requireargs","Invalid require call"),h);if(a&&s(N,e))return N[e](p[a.id]);if(l.get)return l.get(i,e,a,d);g=j(e,a,!1,!0);g=g.id;return!s(q,g)?v(B("notloaded",'Module name "'+g+'" has not been loaded yet for context: '+
-b+(a?"":". Use require([])"))):q[g]}L();i.nextTick(function(){L();k=r(j(null,a));k.skipMap=f.skipMap;k.init(e,c,h,{enabled:!0});D()});return d}f=f||{};R(d,{isBrowser:A,toUrl:function(b){var d,f=b.lastIndexOf("."),g=b.split("/")[0];if(-1!==f&&(!("."===g||".."===g)||1h.attachEvent.toString().indexOf("[native code"))&&!Y?(O=!0,h.attachEvent("onreadystatechange",b.onScriptLoad)):(h.addEventListener("load",b.onScriptLoad,!1),h.addEventListener("error",b.onScriptError,!1)),h.src=d,K=h,D?x.insertBefore(h,D):x.appendChild(h),K=null,h;if(da)try{importScripts(d),b.completeLoad(c)}catch(j){b.onError(B("importscripts","importScripts failed for "+c+" at "+d,j,[c]))}};A&&M(document.getElementsByTagName("script"),function(b){x||(x=
-b.parentNode);if(t=b.getAttribute("data-main"))return r.baseUrl||(E=t.split("/"),Q=E.pop(),fa=E.length?E.join("/")+"/":"./",r.baseUrl=fa,t=Q),t=t.replace(ea,""),r.deps=r.deps?r.deps.concat(t):[t],!0});define=function(b,c,d){var l,h;"string"!==typeof b&&(d=c,c=b,b=null);J(c)||(d=c,c=[]);!c.length&&I(d)&&d.length&&(d.toString().replace(la,"").replace(ma,function(b,d){c.push(d)}),c=(1===d.length?["require"]:["require","exports","module"]).concat(c));if(O){if(!(l=K))P&&"interactive"===P.readyState||M(document.getElementsByTagName("script"),
-function(b){if("interactive"===b.readyState)return P=b}),l=P;l&&(b||(b=l.getAttribute("data-requiremodule")),h=F[l.getAttribute("data-requirecontext")])}(h?h.defQueue:T).push([b,c,d])};define.amd={jQuery:!0};l.exec=function(b){return eval(b)};l(r)}})(this);
diff --git a/test/lib/resemble.js b/test/lib/resemble.js
new file mode 100644
index 0000000..1cb8c29
--- /dev/null
+++ b/test/lib/resemble.js
@@ -0,0 +1,535 @@
+/*
+Author: James Cryer
+Company: Huddle
+Last updated date: 21 Feb 2013
+URL: https://github.com/Huddle/Resemble.js
+*/
+
+(function(_this){
+ 'use strict';
+
+ _this['resemble'] = function( fileData ){
+
+ var data = {};
+ var images = [];
+ var updateCallbackArray = [];
+
+ var tolerance = { // between 0 and 255
+ red: 16,
+ green: 16,
+ blue: 16,
+ minBrightness: 16,
+ maxBrightness: 240
+ };
+
+ var ignoreAntialiasing = false;
+ var ignoreColors = false;
+
+ function triggerDataUpdate(){
+ var len = updateCallbackArray.length;
+ var i;
+ for(i=0;i tolerance.maxBrightness;
+ }
+
+ function getHue(r,g,b){
+
+ r = r / 255;
+ g = g / 255;
+ b = b / 255;
+ var max = Math.max(r, g, b), min = Math.min(r, g, b);
+ var h;
+ var d;
+
+ if (max == min){
+ h = 0; // achromatic
+ } else{
+ d = max - min;
+ switch(max){
+ case r: h = (g - b) / d + (g < b ? 6 : 0); break;
+ case g: h = (b - r) / d + 2; break;
+ case b: h = (r - g) / d + 4; break;
+ }
+ h /= 6;
+ }
+
+ return h;
+ }
+
+ function isAntialiased(sourcePix, data, cacheSet, verticalPos, horizontalPos, width){
+ var offset;
+ var targetPix;
+ var distance = 1;
+ var i;
+ var j;
+ var hasHighContrastSibling = 0;
+ var hasSiblingWithDifferentHue = 0;
+ var hasEquivilantSibling = 0;
+
+ addHueInfo(sourcePix);
+
+ for (i = distance*-1; i <= distance; i++){
+ for (j = distance*-1; j <= distance; j++){
+
+ if(i===0 && j===0){
+ // ignore source pixel
+ } else {
+
+ offset = ((verticalPos+j)*width + (horizontalPos+i)) * 4;
+ targetPix = getPixelInfo(data, offset, cacheSet);
+
+ if(targetPix === null){
+ continue;
+ }
+
+ addBrightnessInfo(targetPix);
+ addHueInfo(targetPix);
+
+ if( isContrasting(sourcePix, targetPix) ){
+ hasHighContrastSibling++;
+ }
+
+ if( isRGBSame(sourcePix,targetPix) ){
+ hasEquivilantSibling++;
+ }
+
+ if( Math.abs(targetPix.h - sourcePix.h) > 0.3 ){
+ hasSiblingWithDifferentHue++;
+ }
+
+ if( hasSiblingWithDifferentHue > 1 || hasHighContrastSibling > 1){
+ return true;
+ }
+ }
+ }
+ }
+
+ if(hasEquivilantSibling < 2){
+ return true;
+ }
+
+ return false;
+ }
+
+ function errorPixel(px, offset){
+ px[offset] = 255; //r
+ px[offset + 1] = 0; //g
+ px[offset + 2] = 255; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyPixel(px, offset, data){
+ px[offset] = data.r; //r
+ px[offset + 1] = data.g; //g
+ px[offset + 2] = data.b; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyGrayScalePixel(px, offset, data){
+ px[offset] = data.brightness; //r
+ px[offset + 1] = data.brightness; //g
+ px[offset + 2] = data.brightness; //b
+ px[offset + 3] = 255; //a
+ }
+
+
+ function getPixelInfo(data, offset, cacheSet){
+ var r;
+ var g;
+ var b;
+ var d;
+
+ if(typeof data[offset] !== 'undefined'){
+ r = data[offset];
+ g = data[offset+1];
+ b = data[offset+2];
+ d = {
+ r: r,
+ g: g,
+ b: b
+ };
+
+ return d;
+ } else {
+ return null;
+ }
+ }
+
+ function addBrightnessInfo(data){
+ data.brightness = getBrightness(data.r,data.g,data.b); // 'corrected' lightness
+ }
+
+ function addHueInfo(data){
+ data.h = getHue(data.r,data.g,data.b);
+ }
+
+ function analyseImages(img1, img2, width, height){
+
+ var hiddenCanvas = document.createElement('canvas');
+
+ var data1 = img1.data;
+ var data2 = img2.data;
+
+ hiddenCanvas.width = width;
+ hiddenCanvas.height = height;
+
+ var context = hiddenCanvas.getContext('2d');
+ var imgd = context.createImageData(width,height);
+ var targetPix = imgd.data;
+
+ var mismatchCount = 0;
+
+ var time = Date.now();
+
+ var skip;
+
+ if( (width > 1200 || height > 1200) && ignoreAntialiasing){
+ skip = 6;
+ }
+
+ loop(height, width, function(verticalPos, horizontalPos){
+
+ if(skip){ // only skip if the image isn't small
+ if(verticalPos % skip === 0 || horizontalPos % skip === 0){
+ return;
+ }
+ }
+
+ var offset = (verticalPos*width + horizontalPos) * 4;
+ var pixel1 = getPixelInfo(data1, offset, 1);
+ var pixel2 = getPixelInfo(data2, offset, 2);
+
+ if(pixel1 === null || pixel2 === null){
+ return;
+ }
+
+ if (ignoreColors){
+
+ addBrightnessInfo(pixel1);
+ addBrightnessInfo(pixel2);
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ return;
+ }
+
+ if( isRGBSimilar(pixel1, pixel2) ){
+ copyPixel(targetPix, offset, pixel2);
+
+ } else if( ignoreAntialiasing && (
+ addBrightnessInfo(pixel1), // jit pixel info augmentation looks a little weird, sorry.
+ addBrightnessInfo(pixel2),
+ isAntialiased(pixel1, data1, 1, verticalPos, horizontalPos, width) ||
+ isAntialiased(pixel2, data2, 2, verticalPos, horizontalPos, width)
+ )){
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+
+ });
+
+ data.misMatchPercentage = (mismatchCount / (height*width) * 100).toFixed(2);
+ data.analysisTime = Date.now() - time;
+
+ data.getImageDataUrl = function(text){
+ var barHeight = 0;
+
+ if(text){
+ barHeight = addLabel(text,context,hiddenCanvas);
+ }
+
+ context.putImageData(imgd, 0, barHeight);
+
+ return hiddenCanvas.toDataURL("image/png");
+ };
+ }
+
+ function addLabel(text, context, hiddenCanvas){
+ var textPadding = 2;
+
+ context.font = '12px sans-serif';
+
+ var textWidth = context.measureText(text).width + textPadding*2;
+ var barHeight = 22;
+
+ if(textWidth > hiddenCanvas.width){
+ hiddenCanvas.width = textWidth;
+ }
+
+ hiddenCanvas.height += barHeight;
+
+ context.fillStyle = "#666";
+ context.fillRect(0,0,hiddenCanvas.width,barHeight -4);
+ context.fillStyle = "#fff";
+ context.fillRect(0,barHeight -4,hiddenCanvas.width, 4);
+
+ context.fillStyle = "#fff";
+ context.textBaseline = "top";
+ context.font = '12px sans-serif';
+ context.fillText(text, textPadding, 1);
+
+ return barHeight;
+ }
+
+ function normalise(img, w, h){
+ var c;
+ var context;
+
+ if(img.height < h || img.width < w){
+ c = document.createElement('canvas');
+ c.width = w;
+ c.height = h;
+ context = c.getContext('2d');
+ context.putImageData(img, 0, 0);
+ return context.getImageData(0, 0, w, h);
+ }
+
+ return img;
+ }
+
+ function compare(one, two){
+
+ function onceWeHaveBoth(){
+ var width;
+ var height;
+ if(images.length === 2){
+ width = images[0].width > images[1].width ? images[0].width : images[1].width;
+ height = images[0].height > images[1].height ? images[0].height : images[1].height;
+
+ if( (images[0].width === images[1].width) && (images[0].height === images[1].height) ){
+ data.isSameDimensions = true;
+ } else {
+ data.isSameDimensions = false;
+ }
+
+ analyseImages( normalise(images[0],width, height), normalise(images[1],width, height), width, height);
+
+ triggerDataUpdate();
+ }
+ }
+
+ images = [];
+ loadImageData(one, onceWeHaveBoth);
+ loadImageData(two, onceWeHaveBoth);
+ }
+
+ function getCompareApi(param){
+
+ var secondFileData,
+ hasMethod = typeof param === 'function';
+
+ if( !hasMethod ){
+ // assume it's file data
+ secondFileData = param;
+ }
+
+ var self = {
+ ignoreNothing: function(){
+
+ tolerance.red = 16;
+ tolerance.green = 16;
+ tolerance.blue = 16;
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreAntialiasing: function(){
+
+ tolerance.red = 32;
+ tolerance.green = 32;
+ tolerance.blue = 32;
+ tolerance.minBrightness = 64;
+ tolerance.maxBrightness = 96;
+
+ ignoreAntialiasing = true;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreColors: function(){
+
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = true;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ onComplete: function( callback ){
+
+ updateCallbackArray.push(callback);
+
+ var wrapper = function(){
+ compare(fileData, secondFileData);
+ };
+
+ wrapper();
+
+ return getCompareApi(wrapper);
+ }
+ };
+
+ return self;
+ }
+
+ return {
+ onComplete: function( callback ){
+ updateCallbackArray.push(callback);
+ loadImageData(fileData, function(imageData, width, height){
+ parseImage(imageData.data, width, height);
+ });
+ },
+ compareTo: function(secondFileData){
+ return getCompareApi(secondFileData);
+ }
+ };
+
+ };
+}(this));
\ No newline at end of file
diff --git a/test/testsuite.js b/test/testsuite.js
deleted file mode 100644
index b486acb..0000000
--- a/test/testsuite.js
+++ /dev/null
@@ -1,36 +0,0 @@
-requirejs.config({
- baseUrl: '/test/unit/'
-});
-
-define(function(require) {
- var testModules = [
- 'Pixi',
- 'Point',
- 'Rectangle',
- 'DisplayObject',
- 'DisplayObjectContainer',
- 'Sprite',
- 'MovieClip',
- 'InteractionManager',
- 'Stage',
- 'utils/Utils',
- 'utils/EventTarget',
- 'utils/Matrix',
- 'utils/Detector',
- 'renderers/WebGLShaders',
- 'renderers/WebGLRenderer',
- 'renderers/WebGLBatch',
- 'renderers/CanvasRenderer',
- 'extras/Strip',
- 'extras/Rope',
- 'textures/BaseTexture',
- 'textures/Texture',
- 'loaders/SpriteSheetLoader',
- 'loaders/AssetLoader'
- ];
-
- // Resolve all testModules and then start the Test Runner.
- require(testModules, function() {
- QUnit.start();
- });
-});
\ No newline at end of file
diff --git a/test/textures/SpriteSheet-Aliens.png b/test/textures/SpriteSheet-Aliens.png
new file mode 100644
index 0000000..210acb1
--- /dev/null
+++ b/test/textures/SpriteSheet-Aliens.png
Binary files differ
diff --git a/test/textures/SpriteSheet-Explosion.png b/test/textures/SpriteSheet-Explosion.png
new file mode 100755
index 0000000..79e1a69
--- /dev/null
+++ b/test/textures/SpriteSheet-Explosion.png
Binary files differ
diff --git a/test/textures/bunny.png b/test/textures/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/textures/bunny.png
Binary files differ
diff --git a/test/unit/DisplayObject.js b/test/unit/DisplayObject.js
deleted file mode 100644
index 5e7e72f..0000000
--- a/test/unit/DisplayObject.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObject');
-});
diff --git a/test/unit/DisplayObjectContainer.js b/test/unit/DisplayObjectContainer.js
deleted file mode 100644
index b323959..0000000
--- a/test/unit/DisplayObjectContainer.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObjectContainer');
-});
diff --git a/test/unit/InteractionManager.js b/test/unit/InteractionManager.js
deleted file mode 100644
index e751f52..0000000
--- a/test/unit/InteractionManager.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('InteractionManager');
-});
diff --git a/test/unit/MovieClip.js b/test/unit/MovieClip.js
deleted file mode 100644
index 37d9446..0000000
--- a/test/unit/MovieClip.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('MovieClip');
-});
diff --git a/test/unit/Pixi.js b/test/unit/Pixi.js
deleted file mode 100644
index 36eee73..0000000
--- a/test/unit/Pixi.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Pixi');
-});
diff --git a/test/unit/Point.js b/test/unit/Point.js
deleted file mode 100644
index 983ff6e..0000000
--- a/test/unit/Point.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Point');
-});
diff --git a/test/unit/Rectangle.js b/test/unit/Rectangle.js
deleted file mode 100644
index 3b439ba..0000000
--- a/test/unit/Rectangle.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Rectangle');
-});
diff --git a/test/unit/Sprite.js b/test/unit/Sprite.js
deleted file mode 100644
index ed4f596..0000000
--- a/test/unit/Sprite.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Sprite');
-});
diff --git a/test/unit/Stage.js b/test/unit/Stage.js
deleted file mode 100644
index 2d70291..0000000
--- a/test/unit/Stage.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Stage');
-});
diff --git a/test/unit/extras/Rope.js b/test/unit/extras/Rope.js
deleted file mode 100644
index 5606f14..0000000
--- a/test/unit/extras/Rope.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Rope');
-});
diff --git a/test/unit/extras/Strip.js b/test/unit/extras/Strip.js
deleted file mode 100644
index 0134d3a..0000000
--- a/test/unit/extras/Strip.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Strip');
-});
diff --git a/test/unit/loaders/AssetLoader.js b/test/unit/loaders/AssetLoader.js
deleted file mode 100644
index 13b8443..0000000
--- a/test/unit/loaders/AssetLoader.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('AssetLoader');
-});
diff --git a/test/unit/loaders/SpriteSheetLoader.js b/test/unit/loaders/SpriteSheetLoader.js
deleted file mode 100644
index 8bf0cb2..0000000
--- a/test/unit/loaders/SpriteSheetLoader.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('SpriteSheetLoader');
-});
diff --git a/test/unit/pixi/InteractionManager.js b/test/unit/pixi/InteractionManager.js
new file mode 100644
index 0000000..ed3001f
--- /dev/null
+++ b/test/unit/pixi/InteractionManager.js
@@ -0,0 +1,10 @@
+describe('pixi/InteractionManager', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var InteractionManager = PIXI.InteractionManager;
+
+ it('Module exists', function () {
+ expect(InteractionManager).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/Pixi.js b/test/unit/pixi/Pixi.js
new file mode 100644
index 0000000..27debc1
--- /dev/null
+++ b/test/unit/pixi/Pixi.js
@@ -0,0 +1,9 @@
+describe('pixi/Pixi', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+
+ it('Module exists', function () {
+ expect(global).to.have.property('PIXI').and.to.be.an('object');
+ });
+});
diff --git a/test/unit/pixi/core/Circle.js b/test/unit/pixi/core/Circle.js
new file mode 100644
index 0000000..93a4456
--- /dev/null
+++ b/test/unit/pixi/core/Circle.js
@@ -0,0 +1,22 @@
+describe('pixi/core/Circle', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Circle = PIXI.Circle;
+
+ it('Module exists', function () {
+ expect(Circle).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Circle();
+
+ expect(obj).to.be.an.instanceof(Circle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', 0);
+ expect(obj).to.have.property('y', 0);
+ expect(obj).to.have.property('radius', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Ellipse.js b/test/unit/pixi/core/Ellipse.js
new file mode 100644
index 0000000..026b56f
--- /dev/null
+++ b/test/unit/pixi/core/Ellipse.js
@@ -0,0 +1,24 @@
+describe('pixi/core/Ellipse', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Ellipse = PIXI.Ellipse;
+
+ it('Module exists', function () {
+ expect(Ellipse).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Ellipse();
+
+ expect(obj).to.be.an.instanceof(Ellipse);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+ expect(obj).to.respondTo('getBounds');
+
+ expect(obj).to.have.property('x', 0);
+ expect(obj).to.have.property('y', 0);
+ expect(obj).to.have.property('width', 0);
+ expect(obj).to.have.property('height', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Matrix.js b/test/unit/pixi/core/Matrix.js
new file mode 100644
index 0000000..b48989e
--- /dev/null
+++ b/test/unit/pixi/core/Matrix.js
@@ -0,0 +1,30 @@
+describe('pixi/core/Matrix', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var mat3 = PIXI.mat3;
+ var mat4 = PIXI.mat4;
+ var Matrix = PIXI.Matrix;
+
+ it('Ensure determineMatrixArrayType works', function () {
+ expect(Matrix).to.be.a('function');
+ });
+
+ it('mat3 exists', function () {
+ expect(mat3).to.be.an('object');
+ });
+
+ it('Confirm new mat3 matrix', function () {
+ var matrix = new mat3.create();
+ pixi_core_Matrix_confirmNewMat3(matrix);
+ });
+
+ it('mat3 exists', function () {
+ expect(mat4).to.be.an('object');
+ });
+
+ it('Confirm new mat4 matrix', function () {
+ var matrix = new mat4.create();
+ pixi_core_Matrix_confirmNewMat4(matrix);
+ });
+});
diff --git a/test/unit/pixi/core/Point.js b/test/unit/pixi/core/Point.js
new file mode 100644
index 0000000..c4d5163
--- /dev/null
+++ b/test/unit/pixi/core/Point.js
@@ -0,0 +1,15 @@
+describe('pixi/core/Point', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Point = PIXI.Point;
+
+ it('Module exists', function () {
+ expect(Point).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Point();
+ pixi_core_Point_confirm(obj, 0, 0);
+ });
+});
diff --git a/test/unit/pixi/core/Polygon.js b/test/unit/pixi/core/Polygon.js
new file mode 100644
index 0000000..dc8c918
--- /dev/null
+++ b/test/unit/pixi/core/Polygon.js
@@ -0,0 +1,20 @@
+describe('pixi/core/Polygon', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Polygon = PIXI.Polygon;
+
+ it('Module exists', function () {
+ expect(Polygon).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Polygon();
+
+ expect(obj).to.be.an.instanceof(Polygon);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.deep.property('points.length', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Rectangle.js b/test/unit/pixi/core/Rectangle.js
new file mode 100644
index 0000000..d43316e
--- /dev/null
+++ b/test/unit/pixi/core/Rectangle.js
@@ -0,0 +1,15 @@
+describe('pixi/core/Rectangle', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Rectangle = PIXI.Rectangle;
+
+ it('Module exists', function () {
+ expect(Rectangle).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var rect = new Rectangle();
+ pixi_core_Rectangle_confirm(rect, 0, 0, 0, 0);
+ });
+});
diff --git a/test/unit/pixi/display/DisplayObject.js b/test/unit/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..40c6fbc
--- /dev/null
+++ b/test/unit/pixi/display/DisplayObject.js
@@ -0,0 +1,21 @@
+describe('pixi/display/DisplayObject', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var DisplayObject = PIXI.DisplayObject;
+
+ it('Module exists', function () {
+ expect(DisplayObject).to.be.a('function');
+ expect(PIXI).to.have.property('visibleCount', 0);
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new DisplayObject();
+
+ pixi_display_DisplayObject_confirmNew(obj);
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', false);
+ expect(obj).to.have.property('stage', null);
+ });
+});
diff --git a/test/unit/pixi/display/DisplayObjectContainer.js b/test/unit/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..ce7f02f
--- /dev/null
+++ b/test/unit/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,20 @@
+describe('pixi/display/DisplayObjectContainer', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var DisplayObjectContainer = PIXI.DisplayObjectContainer;
+
+ it('Module exists', function () {
+ expect(DisplayObjectContainer).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new DisplayObjectContainer();
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', false);
+ expect(obj).to.have.property('stage', null);
+ });
+});
diff --git a/test/unit/pixi/display/MovieClip.js b/test/unit/pixi/display/MovieClip.js
new file mode 100644
index 0000000..f3c6c6a
--- /dev/null
+++ b/test/unit/pixi/display/MovieClip.js
@@ -0,0 +1,33 @@
+describe('pixi/display/MovieClip', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var MovieClip = PIXI.MovieClip;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(MovieClip).to.be.a('function');
+ });
+
+ it('Confirm new instance', function (done) {
+ var texture = Texture.fromImage('/base/test/textures/SpriteSheet-Explosion.png');
+ var obj = new MovieClip([texture]);
+
+ pixi_display_Sprite_confirmNew(obj, done);
+
+ expect(obj).to.be.an.instanceof(MovieClip);
+ expect(obj).to.respondTo('stop');
+ expect(obj).to.respondTo('play');
+ expect(obj).to.respondTo('gotoAndStop');
+ expect(obj).to.respondTo('gotoAndPlay');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('textures.length', 1);
+ expect(obj).to.have.deep.property('textures[0]', texture);
+ expect(obj).to.have.property('animationSpeed', 1);
+ expect(obj).to.have.property('loop', true);
+ expect(obj).to.have.property('onComplete', null);
+ expect(obj).to.have.property('currentFrame', 0);
+ expect(obj).to.have.property('playing', false);
+ });
+});
diff --git a/test/unit/pixi/display/Sprite.js b/test/unit/pixi/display/Sprite.js
new file mode 100644
index 0000000..54e914f
--- /dev/null
+++ b/test/unit/pixi/display/Sprite.js
@@ -0,0 +1,25 @@
+describe('pixi/display/Sprite', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Sprite = PIXI.Sprite;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(Sprite).to.be.a('function');
+ expect(PIXI).to.have.deep.property('blendModes.NORMAL', 0);
+ expect(PIXI).to.have.deep.property('blendModes.SCREEN', 1);
+ });
+
+ it('Members exist', function () {
+ expect(Sprite).itself.to.respondTo('fromImage');
+ expect(Sprite).itself.to.respondTo('fromFrame');
+ });
+
+ it('Confirm new instance', function (done) {
+ var texture = Texture.fromImage('/base/test/textures/SpriteSheet-Aliens.png');
+ var obj = new Sprite(texture);
+
+ pixi_display_Sprite_confirmNew(obj, done);
+ });
+});
diff --git a/test/unit/pixi/display/Stage.js b/test/unit/pixi/display/Stage.js
new file mode 100644
index 0000000..3cc2a4d
--- /dev/null
+++ b/test/unit/pixi/display/Stage.js
@@ -0,0 +1,49 @@
+describe('pixi/display/Stage', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Stage = PIXI.Stage;
+ var InteractionManager = PIXI.InteractionManager;
+ var Rectangle = PIXI.Rectangle;
+
+ it('Module exists', function () {
+ expect(Stage).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Stage(null, true);
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(Stage);
+ expect(obj).to.respondTo('updateTransform');
+ expect(obj).to.respondTo('setBackgroundColor');
+ expect(obj).to.respondTo('getMousePosition');
+
+ // FIXME: duplicate member in DisplayObject
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ // FIXME: convert arg to bool in constructor
+ expect(obj).to.have.property('interactive', true);
+
+ expect(obj).to.have.property('interactionManager')
+ .and.to.be.an.instanceof(InteractionManager)
+ .and.to.have.property('stage', obj);
+
+ expect(obj).to.have.property('dirty', true);
+
+ expect(obj).to.have.property('stage', obj);
+
+ expect(obj).to.have.property('hitArea')
+ .and.to.be.an.instanceof(Rectangle);
+ pixi_core_Rectangle_confirm(obj.hitArea, 0, 0, 100000, 100000);
+
+ expect(obj).to.have.property('backgroundColor', 0x000000);
+ expect(obj).to.have.deep.property('backgroundColorSplit.length', 3);
+ expect(obj).to.have.deep.property('backgroundColorSplit[0]', 0);
+ expect(obj).to.have.deep.property('backgroundColorSplit[1]', 0);
+ expect(obj).to.have.deep.property('backgroundColorSplit[2]', 0);
+ expect(obj).to.have.property('backgroundColorString', '#000000');
+
+ expect(obj).to.have.property('worldVisible', true);
+ });
+});
diff --git a/.gitignore b/.gitignore
index 12e1b62..0b88317 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
node_modules
.DS_Store
-.project
\ No newline at end of file
+.project
+*.log
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..63e4d7c
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,8 @@
+language: node_js
+node_js:
+ - 0.10
+
+before_script:
+ - npm install -g grunt-cli
+ - export DISPLAY=:99.0
+ - sh -e /etc/init.d/xvfb start
diff --git a/Gruntfile.js b/Gruntfile.js
index b083b49..103938c 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -1,10 +1,12 @@
+'use strict';
+
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-connect');
- grunt.loadNpmTasks('grunt-contrib-qunit');
grunt.loadNpmTasks('grunt-contrib-yuidoc');
+ grunt.loadTasks('tasks');
var root = 'src/pixi/',
debug = 'bin/pixi.dev.js',
@@ -79,7 +81,7 @@
},
files: {
srcBlob: '<%= dirs.src %>/**/*.js',
- testBlob: '<%= dirs.test %>/unit/**/*.js',
+ testBlob: '<%= dirs.test %>/{functional,lib/pixi,unit}/**/*.js',
build: '<%= dirs.build %>/pixi.dev.js',
buildMin: '<%= dirs.build %>/pixi.js'
},
@@ -94,7 +96,12 @@
},
jshint: {
beforeconcat: srcFiles,
- test: ['<%= files.testBlob %>'],
+ test: {
+ src: ['<%= files.testBlob %>'],
+ options: {
+ expr: true
+ }
+ },
options: {
asi: true,
smarttabs: true
@@ -128,12 +135,6 @@
]
},
connect: {
- qunit: {
- options: {
- port: grunt.option('port-test') || 9002,
- base: './'
- }
- },
test: {
options: {
port: grunt.option('port-test') || 9002,
@@ -142,13 +143,6 @@
}
}
},
- qunit: {
- all: {
- options: {
- urls: ['http://localhost:' + (grunt.option('port-test') || 9002) + '/test/index.html']
- }
- }
- },
yuidoc: {
compile: {
name: '<%= pkg.name %>',
@@ -161,6 +155,13 @@
outdir: '<%= dirs.docs %>'
}
}
+ },
+ karma: {
+ unit: {
+ configFile: 'test/karma.conf.js',
+ // browsers: ['Chrome'],
+ singleRun: true
+ }
}
});
@@ -182,9 +183,10 @@
}
)
- grunt.registerTask('default', ['concat', 'uglify', 'distribute']);
grunt.registerTask('build', ['concat', 'uglify', 'distribute']);
- grunt.registerTask('test', ['build', 'connect:qunit', 'qunit']);
+ grunt.registerTask('test', ['concat', 'jshint:test', 'karma']);
grunt.registerTask('docs', ['yuidoc']);
-
-}
\ No newline at end of file
+ grunt.registerTask('default', ['test', 'uglify', 'distribute']);
+ // Travis CI task.
+ grunt.registerTask('travis', ['test']);
+}
diff --git a/README.md b/README.md
index c62ef86..690cfe4 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,8 @@

+[](http://travis-ci.org/drkibitz/pixi.js)
+
#### JavaScript 2D Renderer ####
The aim of this project is to provide a fast lightweight 2D library that works
diff --git a/package.json b/package.json
index b373240..1246a68 100644
--- a/package.json
+++ b/package.json
@@ -18,14 +18,21 @@
"main": "bin/pixi.js",
+ "scripts": {
+ "test": "grunt travis --verbose"
+ },
+
"dependencies": {},
"devDependencies": {
"grunt": "~0.4.x",
- "grunt-contrib-jshint": "0.3.x",
+ "grunt-contrib-jshint": "0.6.x",
"grunt-contrib-uglify": "0.2.x",
- "grunt-contrib-connect": "0.2.x",
- "grunt-contrib-qunit": "0.2.x",
+ "grunt-contrib-connect": "0.3.x",
"grunt-contrib-yuidoc": "0.4.x",
- "grunt-contrib-concat": "0.1.x"
+ "grunt-contrib-concat": "0.3.x",
+ "chai": "~1.7.0",
+ "karma": "0.11.0",
+ "karma-firefox-launcher": "0.1.0",
+ "karma-mocha": "0.1.0"
}
}
diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js
index a7c520e..ee82bbd 100644
--- a/src/pixi/InteractionManager.js
+++ b/src/pixi/InteractionManager.js
@@ -62,7 +62,6 @@
this.onTouchEnd = this.onTouchEnd.bind(this);
this.onTouchMove = this.onTouchMove.bind(this);
-
this.last = 0;
}
diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js
index 1a95d20..eef1059 100644
--- a/src/pixi/core/Ellipse.js
+++ b/src/pixi/core/Ellipse.js
@@ -78,7 +78,7 @@
return (normx + normy < 0.25);
}
-PIXI.Ellipse.getBounds = function()
+PIXI.Ellipse.prototype.getBounds = function()
{
return new PIXI.Rectangle(this.x, this.y, this.width, this.height);
}
diff --git a/tasks/karma.js b/tasks/karma.js
new file mode 100644
index 0000000..c340485
--- /dev/null
+++ b/tasks/karma.js
@@ -0,0 +1,27 @@
+'use strict';
+
+var path = require('path');
+var server = require('karma').server;
+
+module.exports = function (grunt) {
+ grunt.registerMultiTask('karma', 'run karma.', function() {
+ var done = this.async();
+ var options = this.options({
+ background: false
+ });
+ var data = this.data;
+
+ //merge options onto data, with data taking precedence
+ data = grunt.util._.merge(options, data);
+ data.configFile = path.resolve(data.configFile);
+ if (data.configFile) {
+ data.configFile = grunt.template.process(data.configFile);
+ }
+
+ server.start(
+ data,
+ function(code) {
+ done(!code);
+ });
+ });
+};
diff --git a/test/functional/example-1-basics/bunny.png b/test/functional/example-1-basics/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/functional/example-1-basics/bunny.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-30.png b/test/functional/example-1-basics/frame-30.png
new file mode 100644
index 0000000..96e3409
--- /dev/null
+++ b/test/functional/example-1-basics/frame-30.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-60.png b/test/functional/example-1-basics/frame-60.png
new file mode 100644
index 0000000..af3f4ce
--- /dev/null
+++ b/test/functional/example-1-basics/frame-60.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-90.png b/test/functional/example-1-basics/frame-90.png
new file mode 100644
index 0000000..099b823
--- /dev/null
+++ b/test/functional/example-1-basics/frame-90.png
Binary files differ
diff --git a/test/functional/example-1-basics/index.js b/test/functional/example-1-basics/index.js
new file mode 100644
index 0000000..7ae7a98
--- /dev/null
+++ b/test/functional/example-1-basics/index.js
@@ -0,0 +1,133 @@
+describe('Example 1 - Basics', function () {
+ 'use strict';
+
+ var baseUri = '/base/test/functional/example-1-basics';
+ var expect = chai.expect;
+ var currentFrame = 0;
+ var frameEvents = {};
+ var stage;
+ var renderer;
+ var bunny;
+
+ function onFrame(frame, callback) {
+ frameEvents[frame] = callback;
+ }
+
+ function animate() {
+ currentFrame += 1;
+
+ requestAnimFrame( animate );
+
+ // just for fun, lets rotate mr rabbit a little
+ bunny.rotation += 0.1;
+
+ // render the stage
+ renderer.render(stage);
+
+ if (frameEvents[currentFrame])
+ frameEvents[currentFrame](currentFrame);
+ }
+
+ function initScene() {
+ // create an new instance of a pixi stage
+ stage = new PIXI.Stage(0x66FF99);
+
+ // create a renderer instance
+ renderer = PIXI.autoDetectRenderer(400, 300);
+ console.log('Is PIXI.WebGLRenderer: ' + (renderer instanceof PIXI.WebGLRenderer));
+
+ // add the renderer view element to the DOM
+ document.body.appendChild(renderer.view);
+
+ requestAnimFrame( animate );
+
+ // create a texture from an image path
+ var texture = PIXI.Texture.fromImage(baseUri + "/bunny.png");
+ // create a new Sprite using the texture
+ bunny = new PIXI.Sprite(texture);
+
+ // center the sprites anchor point
+ bunny.anchor.x = 0.5;
+ bunny.anchor.y = 0.5;
+
+ // move the sprite t the center of the screen
+ bunny.position.x = 200;
+ bunny.position.y = 150;
+
+ stage.addChild(bunny);
+ }
+
+ it('assets loaded', function (done) {
+ var loader = new PIXI.AssetLoader([
+ baseUri + '/bunny.png',
+ baseUri + '/frame-30.png',
+ baseUri + '/frame-60.png',
+ baseUri + '/frame-90.png'
+ ]);
+ // loader.on('onProgress', function (event) {
+ // console.log(event.content);
+ // });
+ loader.on('onComplete', function (event) {
+ done();
+ initScene();
+ });
+ loader.load();
+ });
+
+ it('frame 30 should match', function (done) {
+ this.timeout(700);
+ onFrame(30, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-30.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 60 should match', function (done) {
+ this.timeout(1200);
+ onFrame(60, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-60.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 90 should match', function (done) {
+ this.timeout(1700);
+ onFrame(90, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-90.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ // it('capture something', function (done) {
+ // this.timeout(2000000);
+ // onFrame(30, function () {
+ // var img = new Image();
+ // img.src = renderer.view.toDataURL('image/png');
+ // document.body.appendChild(img);
+ // });
+ // });
+});
diff --git a/test/index.html b/test/index.html
deleted file mode 100644
index 9cbcac5..0000000
--- a/test/index.html
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
- Pixi.js Test Suite
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/test/karma.conf.js b/test/karma.conf.js
new file mode 100644
index 0000000..c66a696
--- /dev/null
+++ b/test/karma.conf.js
@@ -0,0 +1,82 @@
+module.exports = function(config) {
+ config.set({
+
+ // base path, that will be used to resolve files and exclude
+ basePath : '../',
+
+ frameworks : ['mocha'],
+
+ // list of files / patterns to load in the browser
+ files : [
+ 'node_modules/chai/chai.js',
+ 'bin/pixi.dev.js',
+ 'test/lib/**/*.js',
+ 'test/unit/**/*.js',
+ // 'test/functional/**/*.js',
+ {pattern: 'test/**/*.png', watched: false, included: false, served: true}
+ ],
+
+ // list of files to exclude
+ exclude : [],
+
+ // use dolts reporter, as travis terminal does not support escaping sequences
+ // possible values: 'dots', 'progress', 'junit', 'teamcity'
+ // CLI --reporters progress
+ reporters : ['progress'],
+
+ // web server port
+ // CLI --port 9876
+ port : 9876,
+
+ // cli runner port
+ // CLI --runner-port 9100
+ runnerPort : 9100,
+
+ // enable / disable colors in the output (reporters and logs)
+ // CLI --colors --no-colors
+ colors : true,
+
+ // level of logging
+ // possible values: karma.LOG_DISABLE || karma.LOG_ERROR || karma.LOG_WARN || karma.LOG_INFO || karma.LOG_DEBUG
+ // CLI --log-level debug
+ logLevel : config.LOG_DEBUG,
+
+ // enable / disable watching file and executing tests whenever any file changes
+ // CLI --auto-watch --no-auto-watch
+ autoWatch : false,
+
+ // Start these browsers, currently available:
+ // - Chrome
+ // - ChromeCanary
+ // - Firefox
+ // - Opera
+ // - Safari (only Mac)
+ // - PhantomJS
+ // - IE (only Windows)
+ // CLI --browsers Chrome,Firefox,Safari
+ browsers : ['Firefox'],
+
+ // If browser does not capture in given timeout [ms], kill it
+ // CLI --capture-timeout 5000
+ captureTimeout : 5000,
+
+ // Auto run tests on start (when browsers are captured) and exit
+ // CLI --single-run --no-single-run
+ singleRun : true,
+
+ // report which specs are slower than 500ms
+ // CLI --report-slower-than 500
+ reportSlowerThan : 1000,
+
+ preprocessors : {
+ // '**/client/js/*.js': 'coverage'
+ },
+
+ plugins : [
+ 'karma-mocha',
+ // 'karma-chrome-launcher',
+ 'karma-firefox-launcher',
+ // 'karma-phantomjs-launcher'
+ ]
+ });
+};
diff --git a/test/lib/pixi/core/Matrix.js b/test/lib/pixi/core/Matrix.js
new file mode 100644
index 0000000..d26386b
--- /dev/null
+++ b/test/lib/pixi/core/Matrix.js
@@ -0,0 +1,40 @@
+
+function pixi_core_Matrix_confirmNewMat3(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(1);
+ expect(matrix[5]).to.equal(0);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(1);
+}
+
+function pixi_core_Matrix_confirmNewMat4(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[0]).to.equal(1);
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(0);
+ expect(matrix[5]).to.equal(1);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(0);
+ expect(matrix[9]).to.equal(0);
+ expect(matrix[10]).to.equal(1);
+ expect(matrix[11]).to.equal(0);
+ expect(matrix[12]).to.equal(0);
+ expect(matrix[13]).to.equal(0);
+ expect(matrix[14]).to.equal(0);
+ expect(matrix[15]).to.equal(1);
+}
diff --git a/test/lib/pixi/core/Point.js b/test/lib/pixi/core/Point.js
new file mode 100644
index 0000000..e5df07b
--- /dev/null
+++ b/test/lib/pixi/core/Point.js
@@ -0,0 +1,10 @@
+
+function pixi_core_Point_confirm(obj, x, y) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Point);
+ expect(obj).to.respondTo('clone');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+}
diff --git a/test/lib/pixi/core/Rectangle.js b/test/lib/pixi/core/Rectangle.js
new file mode 100644
index 0000000..23f0d12
--- /dev/null
+++ b/test/lib/pixi/core/Rectangle.js
@@ -0,0 +1,13 @@
+
+function pixi_core_Rectangle_confirm(obj, x, y, width, height) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Rectangle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+ expect(obj).to.have.property('width', width);
+ expect(obj).to.have.property('height', height);
+}
diff --git a/test/lib/pixi/display/DisplayObject.js b/test/lib/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..1388a7f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObject.js
@@ -0,0 +1,43 @@
+
+function pixi_display_DisplayObject_confirmNew(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObject);
+ expect(obj).to.respondTo('setInteractive');
+ expect(obj).to.respondTo('addFilter');
+ expect(obj).to.respondTo('removeFilter');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.property('last', obj);
+ expect(obj).to.have.property('first', obj);
+
+ expect(obj).to.contain.property('position');
+ pixi_core_Point_confirm(obj.position, 0, 0);
+ expect(obj).to.contain.property('scale');
+ pixi_core_Point_confirm(obj.scale, 1, 1);
+ expect(obj).to.contain.property('pivot');
+ pixi_core_Point_confirm(obj.pivot, 0, 0);
+
+ expect(obj).to.have.property('rotation', 0);
+ expect(obj).to.have.property('alpha', 1);
+ expect(obj).to.have.property('visible', true);
+ expect(obj).to.have.property('buttonMode', false);
+ expect(obj).to.have.property('parent', null);
+ expect(obj).to.have.property('worldAlpha', 1);
+
+ expect(obj).to.have.property('hitArea');
+ expect(obj).to.have.property('interactive'); // TODO: Have a better default value
+ expect('mask' in obj).to.be.true; // TODO: Have a better default value
+ expect(obj.mask).to.be.undefined;
+
+ expect(obj).to.have.property('renderable');
+ expect(obj).to.have.property('stage');
+
+ expect(obj).to.have.deep.property('worldTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ expect(obj).to.have.deep.property('localTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.localTransform);
+
+ expect(obj).to.have.deep.property('color.length', 0);
+ expect(obj).to.have.property('dynamic', true);
+}
diff --git a/test/lib/pixi/display/DisplayObjectContainer.js b/test/lib/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..085c59f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,16 @@
+
+function pixi_display_DisplayObjectContainer_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObject_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObjectContainer);
+ expect(obj).to.respondTo('addChild');
+ expect(obj).to.respondTo('addChildAt');
+ expect(obj).to.respondTo('swapChildren');
+ expect(obj).to.respondTo('getChildAt');
+ expect(obj).to.respondTo('removeChild');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('children.length', 0);
+}
diff --git a/test/lib/pixi/display/Sprite.js b/test/lib/pixi/display/Sprite.js
new file mode 100644
index 0000000..cc7a2d6
--- /dev/null
+++ b/test/lib/pixi/display/Sprite.js
@@ -0,0 +1,28 @@
+
+function pixi_display_Sprite_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Sprite);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', true);
+ expect(obj).to.have.property('stage', null);
+
+ expect(obj).to.have.property('anchor');
+ pixi_core_Point_confirm(obj.anchor, 0, 0);
+
+ expect(obj).to.have.property('blendMode', PIXI.blendModes.NORMAL);
+ expect(obj).to.have.property('width', 1); // TODO: is 1 expected
+ expect(obj).to.have.property('height', 1); // TODO: is 1 expected
+
+ // FIXME: Just make this a boolean that is always there
+ expect(!!obj.updateFrame).to.equal(obj.texture.baseTexture.hasLoaded);
+
+ expect(obj).to.have.property('texture');
+ pixi_textures_Texture_confirmNew(obj.texture, done);
+}
diff --git a/test/lib/pixi/extras/Strip.js b/test/lib/pixi/extras/Strip.js
new file mode 100644
index 0000000..8927a8a
--- /dev/null
+++ b/test/lib/pixi/extras/Strip.js
@@ -0,0 +1,12 @@
+
+function pixi_extras_Strip_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Strip);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ // TODO: Test properties
+}
diff --git a/test/lib/pixi/textures/Texture.js b/test/lib/pixi/textures/Texture.js
new file mode 100644
index 0000000..d5867b6
--- /dev/null
+++ b/test/lib/pixi/textures/Texture.js
@@ -0,0 +1,31 @@
+
+function pixi_textures_Texture_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ function confirmFrameDone() {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, obj.baseTexture.width, obj.baseTexture.height);
+
+ expect(obj).to.have.property('width', obj.baseTexture.width);
+ expect(obj).to.have.property('height', obj.baseTexture.height);
+ done();
+ }
+
+ expect(obj).to.be.an.instanceof(PIXI.Texture);
+ pixi_utils_EventTarget_like(obj);
+
+ expect(obj).to.have.property('baseTexture')
+ .and.to.be.an.instanceof(PIXI.BaseTexture);
+
+ expect(obj).to.have.property('scope', obj);
+
+ expect(obj).to.have.property('trim');
+ pixi_core_Point_confirm(obj.trim, 0, 0);
+
+ expect(obj).to.have.property('frame');
+ if (obj.baseTexture.hasLoaded) {
+ confirmFrameDone();
+ } else {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, 1, 1);
+ obj.addEventListener('update', confirmFrameDone);
+ }
+}
diff --git a/test/lib/pixi/utils/EventTarget.js b/test/lib/pixi/utils/EventTarget.js
new file mode 100644
index 0000000..7b1dcfa
--- /dev/null
+++ b/test/lib/pixi/utils/EventTarget.js
@@ -0,0 +1,8 @@
+
+function pixi_utils_EventTarget_like(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.respondTo('addEventListener');
+ expect(obj).to.respondTo('dispatchEvent');
+ expect(obj).to.respondTo('removeEventListener');
+}
diff --git a/test/lib/qunit-1.11.0.css b/test/lib/qunit-1.11.0.css
deleted file mode 100644
index d7fc0c8..0000000
--- a/test/lib/qunit-1.11.0.css
+++ /dev/null
@@ -1,244 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-/** Font Family and Sizes */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
- font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
-}
-
-#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
-#qunit-tests { font-size: smaller; }
-
-
-/** Resets */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter {
- margin: 0;
- padding: 0;
-}
-
-
-/** Header */
-
-#qunit-header {
- padding: 0.5em 0 0.5em 1em;
-
- color: #8699a4;
- background-color: #0d3349;
-
- font-size: 1.5em;
- line-height: 1em;
- font-weight: normal;
-
- border-radius: 5px 5px 0 0;
- -moz-border-radius: 5px 5px 0 0;
- -webkit-border-top-right-radius: 5px;
- -webkit-border-top-left-radius: 5px;
-}
-
-#qunit-header a {
- text-decoration: none;
- color: #c2ccd1;
-}
-
-#qunit-header a:hover,
-#qunit-header a:focus {
- color: #fff;
-}
-
-#qunit-testrunner-toolbar label {
- display: inline-block;
- padding: 0 .5em 0 .1em;
-}
-
-#qunit-banner {
- height: 5px;
-}
-
-#qunit-testrunner-toolbar {
- padding: 0.5em 0 0.5em 2em;
- color: #5E740B;
- background-color: #eee;
- overflow: hidden;
-}
-
-#qunit-userAgent {
- padding: 0.5em 0 0.5em 2.5em;
- background-color: #2b81af;
- color: #fff;
- text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
-}
-
-#qunit-modulefilter-container {
- float: right;
-}
-
-/** Tests: Pass/Fail */
-
-#qunit-tests {
- list-style-position: inside;
-}
-
-#qunit-tests li {
- padding: 0.4em 0.5em 0.4em 2.5em;
- border-bottom: 1px solid #fff;
- list-style-position: inside;
-}
-
-#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running {
- display: none;
-}
-
-#qunit-tests li strong {
- cursor: pointer;
-}
-
-#qunit-tests li a {
- padding: 0.5em;
- color: #c2ccd1;
- text-decoration: none;
-}
-#qunit-tests li a:hover,
-#qunit-tests li a:focus {
- color: #000;
-}
-
-#qunit-tests li .runtime {
- float: right;
- font-size: smaller;
-}
-
-.qunit-assert-list {
- margin-top: 0.5em;
- padding: 0.5em;
-
- background-color: #fff;
-
- border-radius: 5px;
- -moz-border-radius: 5px;
- -webkit-border-radius: 5px;
-}
-
-.qunit-collapsed {
- display: none;
-}
-
-#qunit-tests table {
- border-collapse: collapse;
- margin-top: .2em;
-}
-
-#qunit-tests th {
- text-align: right;
- vertical-align: top;
- padding: 0 .5em 0 0;
-}
-
-#qunit-tests td {
- vertical-align: top;
-}
-
-#qunit-tests pre {
- margin: 0;
- white-space: pre-wrap;
- word-wrap: break-word;
-}
-
-#qunit-tests del {
- background-color: #e0f2be;
- color: #374e0c;
- text-decoration: none;
-}
-
-#qunit-tests ins {
- background-color: #ffcaca;
- color: #500;
- text-decoration: none;
-}
-
-/*** Test Counts */
-
-#qunit-tests b.counts { color: black; }
-#qunit-tests b.passed { color: #5E740B; }
-#qunit-tests b.failed { color: #710909; }
-
-#qunit-tests li li {
- padding: 5px;
- background-color: #fff;
- border-bottom: none;
- list-style-position: inside;
-}
-
-/*** Passing Styles */
-
-#qunit-tests li li.pass {
- color: #3c510c;
- background-color: #fff;
- border-left: 10px solid #C6E746;
-}
-
-#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
-#qunit-tests .pass .test-name { color: #366097; }
-
-#qunit-tests .pass .test-actual,
-#qunit-tests .pass .test-expected { color: #999999; }
-
-#qunit-banner.qunit-pass { background-color: #C6E746; }
-
-/*** Failing Styles */
-
-#qunit-tests li li.fail {
- color: #710909;
- background-color: #fff;
- border-left: 10px solid #EE5757;
- white-space: pre;
-}
-
-#qunit-tests > li:last-child {
- border-radius: 0 0 5px 5px;
- -moz-border-radius: 0 0 5px 5px;
- -webkit-border-bottom-right-radius: 5px;
- -webkit-border-bottom-left-radius: 5px;
-}
-
-#qunit-tests .fail { color: #000000; background-color: #EE5757; }
-#qunit-tests .fail .test-name,
-#qunit-tests .fail .module-name { color: #000000; }
-
-#qunit-tests .fail .test-actual { color: #EE5757; }
-#qunit-tests .fail .test-expected { color: green; }
-
-#qunit-banner.qunit-fail { background-color: #EE5757; }
-
-
-/** Result */
-
-#qunit-testresult {
- padding: 0.5em 0.5em 0.5em 2.5em;
-
- color: #2b81af;
- background-color: #D2E0E6;
-
- border-bottom: 1px solid white;
-}
-#qunit-testresult .module-name {
- font-weight: bold;
-}
-
-/** Fixture */
-
-#qunit-fixture {
- position: absolute;
- top: -10000px;
- left: -10000px;
- width: 1000px;
- height: 1000px;
-}
diff --git a/test/lib/qunit-1.11.0.js b/test/lib/qunit-1.11.0.js
deleted file mode 100644
index 302545f..0000000
--- a/test/lib/qunit-1.11.0.js
+++ /dev/null
@@ -1,2152 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-(function( window ) {
-
-var QUnit,
- assert,
- config,
- onErrorFnPrev,
- testId = 0,
- fileName = (sourceFromStacktrace( 0 ) || "" ).replace(/(:\d+)+\)?/, "").replace(/.+\//, ""),
- toString = Object.prototype.toString,
- hasOwn = Object.prototype.hasOwnProperty,
- // Keep a local reference to Date (GH-283)
- Date = window.Date,
- defined = {
- setTimeout: typeof window.setTimeout !== "undefined",
- sessionStorage: (function() {
- var x = "qunit-test-string";
- try {
- sessionStorage.setItem( x, x );
- sessionStorage.removeItem( x );
- return true;
- } catch( e ) {
- return false;
- }
- }())
- },
- /**
- * Provides a normalized error string, correcting an issue
- * with IE 7 (and prior) where Error.prototype.toString is
- * not properly implemented
- *
- * Based on http://es5.github.com/#x15.11.4.4
- *
- * @param {String|Error} error
- * @return {String} error message
- */
- errorString = function( error ) {
- var name, message,
- errorString = error.toString();
- if ( errorString.substring( 0, 7 ) === "[object" ) {
- name = error.name ? error.name.toString() : "Error";
- message = error.message ? error.message.toString() : "";
- if ( name && message ) {
- return name + ": " + message;
- } else if ( name ) {
- return name;
- } else if ( message ) {
- return message;
- } else {
- return "Error";
- }
- } else {
- return errorString;
- }
- },
- /**
- * Makes a clone of an object using only Array or Object as base,
- * and copies over the own enumerable properties.
- *
- * @param {Object} obj
- * @return {Object} New object with only the own properties (recursively).
- */
- objectValues = function( obj ) {
- // Grunt 0.3.x uses an older version of jshint that still has jshint/jshint#392.
- /*jshint newcap: false */
- var key, val,
- vals = QUnit.is( "array", obj ) ? [] : {};
- for ( key in obj ) {
- if ( hasOwn.call( obj, key ) ) {
- val = obj[key];
- vals[key] = val === Object(val) ? objectValues(val) : val;
- }
- }
- return vals;
- };
-
-function Test( settings ) {
- extend( this, settings );
- this.assertions = [];
- this.testNumber = ++Test.count;
-}
-
-Test.count = 0;
-
-Test.prototype = {
- init: function() {
- var a, b, li,
- tests = id( "qunit-tests" );
-
- if ( tests ) {
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml;
-
- // `a` initialized at top of scope
- a = document.createElement( "a" );
- a.innerHTML = "Rerun";
- a.href = QUnit.url({ testNumber: this.testNumber });
-
- li = document.createElement( "li" );
- li.appendChild( b );
- li.appendChild( a );
- li.className = "running";
- li.id = this.id = "qunit-test-output" + testId++;
-
- tests.appendChild( li );
- }
- },
- setup: function() {
- if ( this.module !== config.previousModule ) {
- if ( config.previousModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.previousModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
- config.previousModule = this.module;
- config.moduleStats = { all: 0, bad: 0 };
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- } else if ( config.autorun ) {
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- }
-
- config.current = this;
-
- this.testEnvironment = extend({
- setup: function() {},
- teardown: function() {}
- }, this.moduleTestEnvironment );
-
- this.started = +new Date();
- runLoggingCallbacks( "testStart", QUnit, {
- name: this.testName,
- module: this.module
- });
-
- // allow utility functions to access the current test environment
- // TODO why??
- QUnit.current_testEnvironment = this.testEnvironment;
-
- if ( !config.pollution ) {
- saveGlobal();
- }
- if ( config.notrycatch ) {
- this.testEnvironment.setup.call( this.testEnvironment );
- return;
- }
- try {
- this.testEnvironment.setup.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Setup failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- },
- run: function() {
- config.current = this;
-
- var running = id( "qunit-testresult" );
-
- if ( running ) {
- running.innerHTML = "Running:
" + this.nameHtml;
- }
-
- if ( this.async ) {
- QUnit.stop();
- }
-
- this.callbackStarted = +new Date();
-
- if ( config.notrycatch ) {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- return;
- }
-
- try {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- } catch( e ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
-
- QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + " " + this.stack + ": " + ( e.message || e ), extractStacktrace( e, 0 ) );
- // else next test will carry the responsibility
- saveGlobal();
-
- // Restart the tests if they're blocking
- if ( config.blocking ) {
- QUnit.start();
- }
- }
- },
- teardown: function() {
- config.current = this;
- if ( config.notrycatch ) {
- if ( typeof this.callbackRuntime === "undefined" ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
- }
- this.testEnvironment.teardown.call( this.testEnvironment );
- return;
- } else {
- try {
- this.testEnvironment.teardown.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Teardown failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- }
- checkPollution();
- },
- finish: function() {
- config.current = this;
- if ( config.requireExpects && this.expected === null ) {
- QUnit.pushFailure( "Expected number of assertions to be defined, but expect() was not called.", this.stack );
- } else if ( this.expected !== null && this.expected !== this.assertions.length ) {
- QUnit.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack );
- } else if ( this.expected === null && !this.assertions.length ) {
- QUnit.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions.", this.stack );
- }
-
- var i, assertion, a, b, time, li, ol,
- test = this,
- good = 0,
- bad = 0,
- tests = id( "qunit-tests" );
-
- this.runtime = +new Date() - this.started;
- config.stats.all += this.assertions.length;
- config.moduleStats.all += this.assertions.length;
-
- if ( tests ) {
- ol = document.createElement( "ol" );
- ol.className = "qunit-assert-list";
-
- for ( i = 0; i < this.assertions.length; i++ ) {
- assertion = this.assertions[i];
-
- li = document.createElement( "li" );
- li.className = assertion.result ? "pass" : "fail";
- li.innerHTML = assertion.message || ( assertion.result ? "okay" : "failed" );
- ol.appendChild( li );
-
- if ( assertion.result ) {
- good++;
- } else {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
-
- // store result when possible
- if ( QUnit.config.reorder && defined.sessionStorage ) {
- if ( bad ) {
- sessionStorage.setItem( "qunit-test-" + this.module + "-" + this.testName, bad );
- } else {
- sessionStorage.removeItem( "qunit-test-" + this.module + "-" + this.testName );
- }
- }
-
- if ( bad === 0 ) {
- addClass( ol, "qunit-collapsed" );
- }
-
- // `b` initialized at top of scope
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml + " (" + bad + ", " + good + ", " + this.assertions.length + ")";
-
- addEvent(b, "click", function() {
- var next = b.parentNode.lastChild,
- collapsed = hasClass( next, "qunit-collapsed" );
- ( collapsed ? removeClass : addClass )( next, "qunit-collapsed" );
- });
-
- addEvent(b, "dblclick", function( e ) {
- var target = e && e.target ? e.target : window.event.srcElement;
- if ( target.nodeName.toLowerCase() === "span" || target.nodeName.toLowerCase() === "b" ) {
- target = target.parentNode;
- }
- if ( window.location && target.nodeName.toLowerCase() === "strong" ) {
- window.location = QUnit.url({ testNumber: test.testNumber });
- }
- });
-
- // `time` initialized at top of scope
- time = document.createElement( "span" );
- time.className = "runtime";
- time.innerHTML = this.runtime + " ms";
-
- // `li` initialized at top of scope
- li = id( this.id );
- li.className = bad ? "fail" : "pass";
- li.removeChild( li.firstChild );
- a = li.firstChild;
- li.appendChild( b );
- li.appendChild( a );
- li.appendChild( time );
- li.appendChild( ol );
-
- } else {
- for ( i = 0; i < this.assertions.length; i++ ) {
- if ( !this.assertions[i].result ) {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
- }
-
- runLoggingCallbacks( "testDone", QUnit, {
- name: this.testName,
- module: this.module,
- failed: bad,
- passed: this.assertions.length - bad,
- total: this.assertions.length,
- duration: this.runtime
- });
-
- QUnit.reset();
-
- config.current = undefined;
- },
-
- queue: function() {
- var bad,
- test = this;
-
- synchronize(function() {
- test.init();
- });
- function run() {
- // each of these can by async
- synchronize(function() {
- test.setup();
- });
- synchronize(function() {
- test.run();
- });
- synchronize(function() {
- test.teardown();
- });
- synchronize(function() {
- test.finish();
- });
- }
-
- // `bad` initialized at top of scope
- // defer when previous test run passed, if storage is available
- bad = QUnit.config.reorder && defined.sessionStorage &&
- +sessionStorage.getItem( "qunit-test-" + this.module + "-" + this.testName );
-
- if ( bad ) {
- run();
- } else {
- synchronize( run, true );
- }
- }
-};
-
-// Root QUnit object.
-// `QUnit` initialized at top of scope
-QUnit = {
-
- // call on start of module test to prepend name to all tests
- module: function( name, testEnvironment ) {
- config.currentModule = name;
- config.currentModuleTestEnvironment = testEnvironment;
- config.modules[name] = true;
- },
-
- asyncTest: function( testName, expected, callback ) {
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- QUnit.test( testName, expected, callback, true );
- },
-
- test: function( testName, expected, callback, async ) {
- var test,
- nameHtml = "" + escapeText( testName ) + "";
-
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- if ( config.currentModule ) {
- nameHtml = "" + escapeText( config.currentModule ) + ": " + nameHtml;
- }
-
- test = new Test({
- nameHtml: nameHtml,
- testName: testName,
- expected: expected,
- async: async,
- callback: callback,
- module: config.currentModule,
- moduleTestEnvironment: config.currentModuleTestEnvironment,
- stack: sourceFromStacktrace( 2 )
- });
-
- if ( !validTest( test ) ) {
- return;
- }
-
- test.queue();
- },
-
- // Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through.
- expect: function( asserts ) {
- if (arguments.length === 1) {
- config.current.expected = asserts;
- } else {
- return config.current.expected;
- }
- },
-
- start: function( count ) {
- // QUnit hasn't been initialized yet.
- // Note: RequireJS (et al) may delay onLoad
- if ( config.semaphore === undefined ) {
- QUnit.begin(function() {
- // This is triggered at the top of QUnit.load, push start() to the event loop, to allow QUnit.load to finish first
- setTimeout(function() {
- QUnit.start( count );
- });
- });
- return;
- }
-
- config.semaphore -= count || 1;
- // don't start until equal number of stop-calls
- if ( config.semaphore > 0 ) {
- return;
- }
- // ignore if start is called more often then stop
- if ( config.semaphore < 0 ) {
- config.semaphore = 0;
- QUnit.pushFailure( "Called start() while already started (QUnit.config.semaphore was 0 already)", null, sourceFromStacktrace(2) );
- return;
- }
- // A slight delay, to avoid any current callbacks
- if ( defined.setTimeout ) {
- window.setTimeout(function() {
- if ( config.semaphore > 0 ) {
- return;
- }
- if ( config.timeout ) {
- clearTimeout( config.timeout );
- }
-
- config.blocking = false;
- process( true );
- }, 13);
- } else {
- config.blocking = false;
- process( true );
- }
- },
-
- stop: function( count ) {
- config.semaphore += count || 1;
- config.blocking = true;
-
- if ( config.testTimeout && defined.setTimeout ) {
- clearTimeout( config.timeout );
- config.timeout = window.setTimeout(function() {
- QUnit.ok( false, "Test timed out" );
- config.semaphore = 1;
- QUnit.start();
- }, config.testTimeout );
- }
- }
-};
-
-// `assert` initialized at top of scope
-// Asssert helpers
-// All of these must either call QUnit.push() or manually do:
-// - runLoggingCallbacks( "log", .. );
-// - config.current.assertions.push({ .. });
-// We attach it to the QUnit object *after* we expose the public API,
-// otherwise `assert` will become a global variable in browsers (#341).
-assert = {
- /**
- * Asserts rough true-ish result.
- * @name ok
- * @function
- * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" );
- */
- ok: function( result, msg ) {
- if ( !config.current ) {
- throw new Error( "ok() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
- result = !!result;
-
- var source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: msg
- };
-
- msg = escapeText( msg || (result ? "okay" : "failed" ) );
- msg = "" + msg + "";
-
- if ( !result ) {
- source = sourceFromStacktrace( 2 );
- if ( source ) {
- details.source = source;
- msg += "Source: | " + escapeText( source ) + " |
---|
";
- }
- }
- runLoggingCallbacks( "log", QUnit, details );
- config.current.assertions.push({
- result: result,
- message: msg
- });
- },
-
- /**
- * Assert that the first two arguments are equal, with an optional message.
- * Prints out both actual and expected values.
- * @name equal
- * @function
- * @example equal( format( "Received {0} bytes.", 2), "Received 2 bytes.", "format() replaces {0} with next argument" );
- */
- equal: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected == actual, actual, expected, message );
- },
-
- /**
- * @name notEqual
- * @function
- */
- notEqual: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected != actual, actual, expected, message );
- },
-
- /**
- * @name propEqual
- * @function
- */
- propEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notPropEqual
- * @function
- */
- notPropEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name deepEqual
- * @function
- */
- deepEqual: function( actual, expected, message ) {
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notDeepEqual
- * @function
- */
- notDeepEqual: function( actual, expected, message ) {
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name strictEqual
- * @function
- */
- strictEqual: function( actual, expected, message ) {
- QUnit.push( expected === actual, actual, expected, message );
- },
-
- /**
- * @name notStrictEqual
- * @function
- */
- notStrictEqual: function( actual, expected, message ) {
- QUnit.push( expected !== actual, actual, expected, message );
- },
-
- "throws": function( block, expected, message ) {
- var actual,
- expectedOutput = expected,
- ok = false;
-
- // 'expected' is optional
- if ( typeof expected === "string" ) {
- message = expected;
- expected = null;
- }
-
- config.current.ignoreGlobalErrors = true;
- try {
- block.call( config.current.testEnvironment );
- } catch (e) {
- actual = e;
- }
- config.current.ignoreGlobalErrors = false;
-
- if ( actual ) {
- // we don't want to validate thrown error
- if ( !expected ) {
- ok = true;
- expectedOutput = null;
- // expected is a regexp
- } else if ( QUnit.objectType( expected ) === "regexp" ) {
- ok = expected.test( errorString( actual ) );
- // expected is a constructor
- } else if ( actual instanceof expected ) {
- ok = true;
- // expected is a validation function which returns true is validation passed
- } else if ( expected.call( {}, actual ) === true ) {
- expectedOutput = null;
- ok = true;
- }
-
- QUnit.push( ok, actual, expectedOutput, message );
- } else {
- QUnit.pushFailure( message, null, 'No exception was thrown.' );
- }
- }
-};
-
-/**
- * @deprecate since 1.8.0
- * Kept assertion helpers in root for backwards compatibility.
- */
-extend( QUnit, assert );
-
-/**
- * @deprecated since 1.9.0
- * Kept root "raises()" for backwards compatibility.
- * (Note that we don't introduce assert.raises).
- */
-QUnit.raises = assert[ "throws" ];
-
-/**
- * @deprecated since 1.0.0, replaced with error pushes since 1.3.0
- * Kept to avoid TypeErrors for undefined methods.
- */
-QUnit.equals = function() {
- QUnit.push( false, false, false, "QUnit.equals has been deprecated since 2009 (e88049a0), use QUnit.equal instead" );
-};
-QUnit.same = function() {
- QUnit.push( false, false, false, "QUnit.same has been deprecated since 2009 (e88049a0), use QUnit.deepEqual instead" );
-};
-
-// We want access to the constructor's prototype
-(function() {
- function F() {}
- F.prototype = QUnit;
- QUnit = new F();
- // Make F QUnit's constructor so that we can add to the prototype later
- QUnit.constructor = F;
-}());
-
-/**
- * Config object: Maintain internal state
- * Later exposed as QUnit.config
- * `config` initialized at top of scope
- */
-config = {
- // The queue of tests to run
- queue: [],
-
- // block until document ready
- blocking: true,
-
- // when enabled, show only failing tests
- // gets persisted through sessionStorage and can be changed in UI via checkbox
- hidepassed: false,
-
- // by default, run previously failed tests first
- // very useful in combination with "Hide passed tests" checked
- reorder: true,
-
- // by default, modify document.title when suite is done
- altertitle: true,
-
- // when enabled, all tests must call expect()
- requireExpects: false,
-
- // add checkboxes that are persisted in the query-string
- // when enabled, the id is set to `true` as a `QUnit.config` property
- urlConfig: [
- {
- id: "noglobals",
- label: "Check for Globals",
- tooltip: "Enabling this will test if any test introduces new properties on the `window` object. Stored as query-strings."
- },
- {
- id: "notrycatch",
- label: "No try-catch",
- tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging exceptions in IE reasonable. Stored as query-strings."
- }
- ],
-
- // Set of all modules.
- modules: {},
-
- // logging callback queues
- begin: [],
- done: [],
- log: [],
- testStart: [],
- testDone: [],
- moduleStart: [],
- moduleDone: []
-};
-
-// Export global variables, unless an 'exports' object exists,
-// in that case we assume we're in CommonJS (dealt with on the bottom of the script)
-if ( typeof exports === "undefined" ) {
- extend( window, QUnit );
-
- // Expose QUnit object
- window.QUnit = QUnit;
-}
-
-// Initialize more QUnit.config and QUnit.urlParams
-(function() {
- var i,
- location = window.location || { search: "", protocol: "file:" },
- params = location.search.slice( 1 ).split( "&" ),
- length = params.length,
- urlParams = {},
- current;
-
- if ( params[ 0 ] ) {
- for ( i = 0; i < length; i++ ) {
- current = params[ i ].split( "=" );
- current[ 0 ] = decodeURIComponent( current[ 0 ] );
- // allow just a key to turn on a flag, e.g., test.html?noglobals
- current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true;
- urlParams[ current[ 0 ] ] = current[ 1 ];
- }
- }
-
- QUnit.urlParams = urlParams;
-
- // String search anywhere in moduleName+testName
- config.filter = urlParams.filter;
-
- // Exact match of the module name
- config.module = urlParams.module;
-
- config.testNumber = parseInt( urlParams.testNumber, 10 ) || null;
-
- // Figure out if we're running the tests from a server or not
- QUnit.isLocal = location.protocol === "file:";
-}());
-
-// Extend QUnit object,
-// these after set here because they should not be exposed as global functions
-extend( QUnit, {
- assert: assert,
-
- config: config,
-
- // Initialize the configuration options
- init: function() {
- extend( config, {
- stats: { all: 0, bad: 0 },
- moduleStats: { all: 0, bad: 0 },
- started: +new Date(),
- updateRate: 1000,
- blocking: false,
- autostart: true,
- autorun: false,
- filter: "",
- queue: [],
- semaphore: 1
- });
-
- var tests, banner, result,
- qunit = id( "qunit" );
-
- if ( qunit ) {
- qunit.innerHTML =
- "" +
- "" +
- "" +
- "" +
- "
";
- }
-
- tests = id( "qunit-tests" );
- banner = id( "qunit-banner" );
- result = id( "qunit-testresult" );
-
- if ( tests ) {
- tests.innerHTML = "";
- }
-
- if ( banner ) {
- banner.className = "";
- }
-
- if ( result ) {
- result.parentNode.removeChild( result );
- }
-
- if ( tests ) {
- result = document.createElement( "p" );
- result.id = "qunit-testresult";
- result.className = "result";
- tests.parentNode.insertBefore( result, tests );
- result.innerHTML = "Running...
";
- }
- },
-
- // Resets the test setup. Useful for tests that modify the DOM.
- reset: function() {
- var fixture = id( "qunit-fixture" );
- if ( fixture ) {
- fixture.innerHTML = config.fixture;
- }
- },
-
- // Trigger an event on an element.
- // @example triggerEvent( document.body, "click" );
- triggerEvent: function( elem, type, event ) {
- if ( document.createEvent ) {
- event = document.createEvent( "MouseEvents" );
- event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView,
- 0, 0, 0, 0, 0, false, false, false, false, 0, null);
-
- elem.dispatchEvent( event );
- } else if ( elem.fireEvent ) {
- elem.fireEvent( "on" + type );
- }
- },
-
- // Safe object type checking
- is: function( type, obj ) {
- return QUnit.objectType( obj ) === type;
- },
-
- objectType: function( obj ) {
- if ( typeof obj === "undefined" ) {
- return "undefined";
- // consider: typeof null === object
- }
- if ( obj === null ) {
- return "null";
- }
-
- var match = toString.call( obj ).match(/^\[object\s(.*)\]$/),
- type = match && match[1] || "";
-
- switch ( type ) {
- case "Number":
- if ( isNaN(obj) ) {
- return "nan";
- }
- return "number";
- case "String":
- case "Boolean":
- case "Array":
- case "Date":
- case "RegExp":
- case "Function":
- return type.toLowerCase();
- }
- if ( typeof obj === "object" ) {
- return "object";
- }
- return undefined;
- },
-
- push: function( result, actual, expected, message ) {
- if ( !config.current ) {
- throw new Error( "assertion outside test context, was " + sourceFromStacktrace() );
- }
-
- var output, source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: message,
- actual: actual,
- expected: expected
- };
-
- message = escapeText( message ) || ( result ? "okay" : "failed" );
- message = "" + message + "";
- output = message;
-
- if ( !result ) {
- expected = escapeText( QUnit.jsDump.parse(expected) );
- actual = escapeText( QUnit.jsDump.parse(actual) );
- output += "Expected: | " + expected + " |
";
-
- if ( actual !== expected ) {
- output += "Result: | " + actual + " |
";
- output += "Diff: | " + QUnit.diff( expected, actual ) + " |
";
- }
-
- source = sourceFromStacktrace();
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
- }
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: !!result,
- message: output
- });
- },
-
- pushFailure: function( message, source, actual ) {
- if ( !config.current ) {
- throw new Error( "pushFailure() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
-
- var output,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: false,
- message: message
- };
-
- message = escapeText( message ) || "error";
- message = "" + message + "";
- output = message;
-
- output += "";
-
- if ( actual ) {
- output += "Result: | " + escapeText( actual ) + " |
";
- }
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: false,
- message: output
- });
- },
-
- url: function( params ) {
- params = extend( extend( {}, QUnit.urlParams ), params );
- var key,
- querystring = "?";
-
- for ( key in params ) {
- if ( !hasOwn.call( params, key ) ) {
- continue;
- }
- querystring += encodeURIComponent( key ) + "=" +
- encodeURIComponent( params[ key ] ) + "&";
- }
- return window.location.protocol + "//" + window.location.host +
- window.location.pathname + querystring.slice( 0, -1 );
- },
-
- extend: extend,
- id: id,
- addEvent: addEvent
- // load, equiv, jsDump, diff: Attached later
-});
-
-/**
- * @deprecated: Created for backwards compatibility with test runner that set the hook function
- * into QUnit.{hook}, instead of invoking it and passing the hook function.
- * QUnit.constructor is set to the empty F() above so that we can add to it's prototype here.
- * Doing this allows us to tell if the following methods have been overwritten on the actual
- * QUnit object.
- */
-extend( QUnit.constructor.prototype, {
-
- // Logging callbacks; all receive a single argument with the listed properties
- // run test/logs.html for any related changes
- begin: registerLoggingCallback( "begin" ),
-
- // done: { failed, passed, total, runtime }
- done: registerLoggingCallback( "done" ),
-
- // log: { result, actual, expected, message }
- log: registerLoggingCallback( "log" ),
-
- // testStart: { name }
- testStart: registerLoggingCallback( "testStart" ),
-
- // testDone: { name, failed, passed, total, duration }
- testDone: registerLoggingCallback( "testDone" ),
-
- // moduleStart: { name }
- moduleStart: registerLoggingCallback( "moduleStart" ),
-
- // moduleDone: { name, failed, passed, total }
- moduleDone: registerLoggingCallback( "moduleDone" )
-});
-
-if ( typeof document === "undefined" || document.readyState === "complete" ) {
- config.autorun = true;
-}
-
-QUnit.load = function() {
- runLoggingCallbacks( "begin", QUnit, {} );
-
- // Initialize the config, saving the execution queue
- var banner, filter, i, label, len, main, ol, toolbar, userAgent, val,
- urlConfigCheckboxesContainer, urlConfigCheckboxes, moduleFilter,
- numModules = 0,
- moduleFilterHtml = "",
- urlConfigHtml = "",
- oldconfig = extend( {}, config );
-
- QUnit.init();
- extend(config, oldconfig);
-
- config.blocking = false;
-
- len = config.urlConfig.length;
-
- for ( i = 0; i < len; i++ ) {
- val = config.urlConfig[i];
- if ( typeof val === "string" ) {
- val = {
- id: val,
- label: val,
- tooltip: "[no tooltip available]"
- };
- }
- config[ val.id ] = QUnit.urlParams[ val.id ];
- urlConfigHtml += "";
- }
-
- moduleFilterHtml += "";
-
- // `userAgent` initialized at top of scope
- userAgent = id( "qunit-userAgent" );
- if ( userAgent ) {
- userAgent.innerHTML = navigator.userAgent;
- }
-
- // `banner` initialized at top of scope
- banner = id( "qunit-header" );
- if ( banner ) {
- banner.innerHTML = "" + banner.innerHTML + " ";
- }
-
- // `toolbar` initialized at top of scope
- toolbar = id( "qunit-testrunner-toolbar" );
- if ( toolbar ) {
- // `filter` initialized at top of scope
- filter = document.createElement( "input" );
- filter.type = "checkbox";
- filter.id = "qunit-filter-pass";
-
- addEvent( filter, "click", function() {
- var tmp,
- ol = document.getElementById( "qunit-tests" );
-
- if ( filter.checked ) {
- ol.className = ol.className + " hidepass";
- } else {
- tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " ";
- ol.className = tmp.replace( / hidepass /, " " );
- }
- if ( defined.sessionStorage ) {
- if (filter.checked) {
- sessionStorage.setItem( "qunit-filter-passed-tests", "true" );
- } else {
- sessionStorage.removeItem( "qunit-filter-passed-tests" );
- }
- }
- });
-
- if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem( "qunit-filter-passed-tests" ) ) {
- filter.checked = true;
- // `ol` initialized at top of scope
- ol = document.getElementById( "qunit-tests" );
- ol.className = ol.className + " hidepass";
- }
- toolbar.appendChild( filter );
-
- // `label` initialized at top of scope
- label = document.createElement( "label" );
- label.setAttribute( "for", "qunit-filter-pass" );
- label.setAttribute( "title", "Only show tests and assertons that fail. Stored in sessionStorage." );
- label.innerHTML = "Hide passed tests";
- toolbar.appendChild( label );
-
- urlConfigCheckboxesContainer = document.createElement("span");
- urlConfigCheckboxesContainer.innerHTML = urlConfigHtml;
- urlConfigCheckboxes = urlConfigCheckboxesContainer.getElementsByTagName("input");
- // For oldIE support:
- // * Add handlers to the individual elements instead of the container
- // * Use "click" instead of "change"
- // * Fallback from event.target to event.srcElement
- addEvents( urlConfigCheckboxes, "click", function( event ) {
- var params = {},
- target = event.target || event.srcElement;
- params[ target.name ] = target.checked ? true : undefined;
- window.location = QUnit.url( params );
- });
- toolbar.appendChild( urlConfigCheckboxesContainer );
-
- if (numModules > 1) {
- moduleFilter = document.createElement( 'span' );
- moduleFilter.setAttribute( 'id', 'qunit-modulefilter-container' );
- moduleFilter.innerHTML = moduleFilterHtml;
- addEvent( moduleFilter.lastChild, "change", function() {
- var selectBox = moduleFilter.getElementsByTagName("select")[0],
- selectedModule = decodeURIComponent(selectBox.options[selectBox.selectedIndex].value);
-
- window.location = QUnit.url( { module: ( selectedModule === "" ) ? undefined : selectedModule } );
- });
- toolbar.appendChild(moduleFilter);
- }
- }
-
- // `main` initialized at top of scope
- main = id( "qunit-fixture" );
- if ( main ) {
- config.fixture = main.innerHTML;
- }
-
- if ( config.autostart ) {
- QUnit.start();
- }
-};
-
-addEvent( window, "load", QUnit.load );
-
-// `onErrorFnPrev` initialized at top of scope
-// Preserve other handlers
-onErrorFnPrev = window.onerror;
-
-// Cover uncaught exceptions
-// Returning true will surpress the default browser handler,
-// returning false will let it run.
-window.onerror = function ( error, filePath, linerNr ) {
- var ret = false;
- if ( onErrorFnPrev ) {
- ret = onErrorFnPrev( error, filePath, linerNr );
- }
-
- // Treat return value as window.onerror itself does,
- // Only do our handling if not surpressed.
- if ( ret !== true ) {
- if ( QUnit.config.current ) {
- if ( QUnit.config.current.ignoreGlobalErrors ) {
- return true;
- }
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- } else {
- QUnit.test( "global failure", extend( function() {
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- }, { validTest: validTest } ) );
- }
- return false;
- }
-
- return ret;
-};
-
-function done() {
- config.autorun = true;
-
- // Log the last module results
- if ( config.currentModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.currentModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
-
- var i, key,
- banner = id( "qunit-banner" ),
- tests = id( "qunit-tests" ),
- runtime = +new Date() - config.started,
- passed = config.stats.all - config.stats.bad,
- html = [
- "Tests completed in ",
- runtime,
- " milliseconds.
",
- "",
- passed,
- " assertions of ",
- config.stats.all,
- " passed, ",
- config.stats.bad,
- " failed."
- ].join( "" );
-
- if ( banner ) {
- banner.className = ( config.stats.bad ? "qunit-fail" : "qunit-pass" );
- }
-
- if ( tests ) {
- id( "qunit-testresult" ).innerHTML = html;
- }
-
- if ( config.altertitle && typeof document !== "undefined" && document.title ) {
- // show ✖ for good, ✔ for bad suite result in title
- // use escape sequences in case file gets loaded with non-utf-8-charset
- document.title = [
- ( config.stats.bad ? "\u2716" : "\u2714" ),
- document.title.replace( /^[\u2714\u2716] /i, "" )
- ].join( " " );
- }
-
- // clear own sessionStorage items if all tests passed
- if ( config.reorder && defined.sessionStorage && config.stats.bad === 0 ) {
- // `key` & `i` initialized at top of scope
- for ( i = 0; i < sessionStorage.length; i++ ) {
- key = sessionStorage.key( i++ );
- if ( key.indexOf( "qunit-test-" ) === 0 ) {
- sessionStorage.removeItem( key );
- }
- }
- }
-
- // scroll back to top to show results
- if ( window.scrollTo ) {
- window.scrollTo(0, 0);
- }
-
- runLoggingCallbacks( "done", QUnit, {
- failed: config.stats.bad,
- passed: passed,
- total: config.stats.all,
- runtime: runtime
- });
-}
-
-/** @return Boolean: true if this test should be ran */
-function validTest( test ) {
- var include,
- filter = config.filter && config.filter.toLowerCase(),
- module = config.module && config.module.toLowerCase(),
- fullName = (test.module + ": " + test.testName).toLowerCase();
-
- // Internally-generated tests are always valid
- if ( test.callback && test.callback.validTest === validTest ) {
- delete test.callback.validTest;
- return true;
- }
-
- if ( config.testNumber ) {
- return test.testNumber === config.testNumber;
- }
-
- if ( module && ( !test.module || test.module.toLowerCase() !== module ) ) {
- return false;
- }
-
- if ( !filter ) {
- return true;
- }
-
- include = filter.charAt( 0 ) !== "!";
- if ( !include ) {
- filter = filter.slice( 1 );
- }
-
- // If the filter matches, we need to honour include
- if ( fullName.indexOf( filter ) !== -1 ) {
- return include;
- }
-
- // Otherwise, do the opposite
- return !include;
-}
-
-// so far supports only Firefox, Chrome and Opera (buggy), Safari (for real exceptions)
-// Later Safari and IE10 are supposed to support error.stack as well
-// See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack
-function extractStacktrace( e, offset ) {
- offset = offset === undefined ? 3 : offset;
-
- var stack, include, i;
-
- if ( e.stacktrace ) {
- // Opera
- return e.stacktrace.split( "\n" )[ offset + 3 ];
- } else if ( e.stack ) {
- // Firefox, Chrome
- stack = e.stack.split( "\n" );
- if (/^error$/i.test( stack[0] ) ) {
- stack.shift();
- }
- if ( fileName ) {
- include = [];
- for ( i = offset; i < stack.length; i++ ) {
- if ( stack[ i ].indexOf( fileName ) !== -1 ) {
- break;
- }
- include.push( stack[ i ] );
- }
- if ( include.length ) {
- return include.join( "\n" );
- }
- }
- return stack[ offset ];
- } else if ( e.sourceURL ) {
- // Safari, PhantomJS
- // hopefully one day Safari provides actual stacktraces
- // exclude useless self-reference for generated Error objects
- if ( /qunit.js$/.test( e.sourceURL ) ) {
- return;
- }
- // for actual exceptions, this is useful
- return e.sourceURL + ":" + e.line;
- }
-}
-function sourceFromStacktrace( offset ) {
- try {
- throw new Error();
- } catch ( e ) {
- return extractStacktrace( e, offset );
- }
-}
-
-/**
- * Escape text for attribute or text content.
- */
-function escapeText( s ) {
- if ( !s ) {
- return "";
- }
- s = s + "";
- // Both single quotes and double quotes (for attributes)
- return s.replace( /['"<>&]/g, function( s ) {
- switch( s ) {
- case '\'':
- return ''';
- case '"':
- return '"';
- case '<':
- return '<';
- case '>':
- return '>';
- case '&':
- return '&';
- }
- });
-}
-
-function synchronize( callback, last ) {
- config.queue.push( callback );
-
- if ( config.autorun && !config.blocking ) {
- process( last );
- }
-}
-
-function process( last ) {
- function next() {
- process( last );
- }
- var start = new Date().getTime();
- config.depth = config.depth ? config.depth + 1 : 1;
-
- while ( config.queue.length && !config.blocking ) {
- if ( !defined.setTimeout || config.updateRate <= 0 || ( ( new Date().getTime() - start ) < config.updateRate ) ) {
- config.queue.shift()();
- } else {
- window.setTimeout( next, 13 );
- break;
- }
- }
- config.depth--;
- if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) {
- done();
- }
-}
-
-function saveGlobal() {
- config.pollution = [];
-
- if ( config.noglobals ) {
- for ( var key in window ) {
- // in Opera sometimes DOM element ids show up here, ignore them
- if ( !hasOwn.call( window, key ) || /^qunit-test-output/.test( key ) ) {
- continue;
- }
- config.pollution.push( key );
- }
- }
-}
-
-function checkPollution() {
- var newGlobals,
- deletedGlobals,
- old = config.pollution;
-
- saveGlobal();
-
- newGlobals = diff( config.pollution, old );
- if ( newGlobals.length > 0 ) {
- QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join(", ") );
- }
-
- deletedGlobals = diff( old, config.pollution );
- if ( deletedGlobals.length > 0 ) {
- QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join(", ") );
- }
-}
-
-// returns a new Array with the elements that are in a but not in b
-function diff( a, b ) {
- var i, j,
- result = a.slice();
-
- for ( i = 0; i < result.length; i++ ) {
- for ( j = 0; j < b.length; j++ ) {
- if ( result[i] === b[j] ) {
- result.splice( i, 1 );
- i--;
- break;
- }
- }
- }
- return result;
-}
-
-function extend( a, b ) {
- for ( var prop in b ) {
- if ( b[ prop ] === undefined ) {
- delete a[ prop ];
-
- // Avoid "Member not found" error in IE8 caused by setting window.constructor
- } else if ( prop !== "constructor" || a !== window ) {
- a[ prop ] = b[ prop ];
- }
- }
-
- return a;
-}
-
-/**
- * @param {HTMLElement} elem
- * @param {string} type
- * @param {Function} fn
- */
-function addEvent( elem, type, fn ) {
- // Standards-based browsers
- if ( elem.addEventListener ) {
- elem.addEventListener( type, fn, false );
- // IE
- } else {
- elem.attachEvent( "on" + type, fn );
- }
-}
-
-/**
- * @param {Array|NodeList} elems
- * @param {string} type
- * @param {Function} fn
- */
-function addEvents( elems, type, fn ) {
- var i = elems.length;
- while ( i-- ) {
- addEvent( elems[i], type, fn );
- }
-}
-
-function hasClass( elem, name ) {
- return (" " + elem.className + " ").indexOf(" " + name + " ") > -1;
-}
-
-function addClass( elem, name ) {
- if ( !hasClass( elem, name ) ) {
- elem.className += (elem.className ? " " : "") + name;
- }
-}
-
-function removeClass( elem, name ) {
- var set = " " + elem.className + " ";
- // Class name may appear multiple times
- while ( set.indexOf(" " + name + " ") > -1 ) {
- set = set.replace(" " + name + " " , " ");
- }
- // If possible, trim it for prettiness, but not neccecarily
- elem.className = window.jQuery ? jQuery.trim( set ) : ( set.trim ? set.trim() : set );
-}
-
-function id( name ) {
- return !!( typeof document !== "undefined" && document && document.getElementById ) &&
- document.getElementById( name );
-}
-
-function registerLoggingCallback( key ) {
- return function( callback ) {
- config[key].push( callback );
- };
-}
-
-// Supports deprecated method of completely overwriting logging callbacks
-function runLoggingCallbacks( key, scope, args ) {
- var i, callbacks;
- if ( QUnit.hasOwnProperty( key ) ) {
- QUnit[ key ].call(scope, args );
- } else {
- callbacks = config[ key ];
- for ( i = 0; i < callbacks.length; i++ ) {
- callbacks[ i ].call( scope, args );
- }
- }
-}
-
-// Test for equality any JavaScript type.
-// Author: Philippe Rathé
-QUnit.equiv = (function() {
-
- // Call the o related callback with the given arguments.
- function bindCallbacks( o, callbacks, args ) {
- var prop = QUnit.objectType( o );
- if ( prop ) {
- if ( QUnit.objectType( callbacks[ prop ] ) === "function" ) {
- return callbacks[ prop ].apply( callbacks, args );
- } else {
- return callbacks[ prop ]; // or undefined
- }
- }
- }
-
- // the real equiv function
- var innerEquiv,
- // stack to decide between skip/abort functions
- callers = [],
- // stack to avoiding loops from circular referencing
- parents = [],
-
- getProto = Object.getPrototypeOf || function ( obj ) {
- return obj.__proto__;
- },
- callbacks = (function () {
-
- // for string, boolean, number and null
- function useStrictEquality( b, a ) {
- /*jshint eqeqeq:false */
- if ( b instanceof a.constructor || a instanceof b.constructor ) {
- // to catch short annotaion VS 'new' annotation of a
- // declaration
- // e.g. var i = 1;
- // var j = new Number(1);
- return a == b;
- } else {
- return a === b;
- }
- }
-
- return {
- "string": useStrictEquality,
- "boolean": useStrictEquality,
- "number": useStrictEquality,
- "null": useStrictEquality,
- "undefined": useStrictEquality,
-
- "nan": function( b ) {
- return isNaN( b );
- },
-
- "date": function( b, a ) {
- return QUnit.objectType( b ) === "date" && a.valueOf() === b.valueOf();
- },
-
- "regexp": function( b, a ) {
- return QUnit.objectType( b ) === "regexp" &&
- // the regex itself
- a.source === b.source &&
- // and its modifers
- a.global === b.global &&
- // (gmi) ...
- a.ignoreCase === b.ignoreCase &&
- a.multiline === b.multiline &&
- a.sticky === b.sticky;
- },
-
- // - skip when the property is a method of an instance (OOP)
- // - abort otherwise,
- // initial === would have catch identical references anyway
- "function": function() {
- var caller = callers[callers.length - 1];
- return caller !== Object && typeof caller !== "undefined";
- },
-
- "array": function( b, a ) {
- var i, j, len, loop;
-
- // b could be an object literal here
- if ( QUnit.objectType( b ) !== "array" ) {
- return false;
- }
-
- len = a.length;
- if ( len !== b.length ) {
- // safe and faster
- return false;
- }
-
- // track reference to avoid circular references
- parents.push( a );
- for ( i = 0; i < len; i++ ) {
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- loop = true;// dont rewalk array
- }
- }
- if ( !loop && !innerEquiv(a[i], b[i]) ) {
- parents.pop();
- return false;
- }
- }
- parents.pop();
- return true;
- },
-
- "object": function( b, a ) {
- var i, j, loop,
- // Default to true
- eq = true,
- aProperties = [],
- bProperties = [];
-
- // comparing constructors is more strict than using
- // instanceof
- if ( a.constructor !== b.constructor ) {
- // Allow objects with no prototype to be equivalent to
- // objects with Object as their constructor.
- if ( !(( getProto(a) === null && getProto(b) === Object.prototype ) ||
- ( getProto(b) === null && getProto(a) === Object.prototype ) ) ) {
- return false;
- }
- }
-
- // stack constructor before traversing properties
- callers.push( a.constructor );
- // track reference to avoid circular references
- parents.push( a );
-
- for ( i in a ) { // be strict: don't ensures hasOwnProperty
- // and go deep
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- // don't go down the same path twice
- loop = true;
- }
- }
- aProperties.push(i); // collect a's properties
-
- if (!loop && !innerEquiv( a[i], b[i] ) ) {
- eq = false;
- break;
- }
- }
-
- callers.pop(); // unstack, we are done
- parents.pop();
-
- for ( i in b ) {
- bProperties.push( i ); // collect b's properties
- }
-
- // Ensures identical properties name
- return eq && innerEquiv( aProperties.sort(), bProperties.sort() );
- }
- };
- }());
-
- innerEquiv = function() { // can take multiple arguments
- var args = [].slice.apply( arguments );
- if ( args.length < 2 ) {
- return true; // end transition
- }
-
- return (function( a, b ) {
- if ( a === b ) {
- return true; // catch the most you can
- } else if ( a === null || b === null || typeof a === "undefined" ||
- typeof b === "undefined" ||
- QUnit.objectType(a) !== QUnit.objectType(b) ) {
- return false; // don't lose time with error prone cases
- } else {
- return bindCallbacks(a, callbacks, [ b, a ]);
- }
-
- // apply transition with (1..n) arguments
- }( args[0], args[1] ) && arguments.callee.apply( this, args.splice(1, args.length - 1 )) );
- };
-
- return innerEquiv;
-}());
-
-/**
- * jsDump Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com |
- * http://flesler.blogspot.com Licensed under BSD
- * (http://www.opensource.org/licenses/bsd-license.php) Date: 5/15/2008
- *
- * @projectDescription Advanced and extensible data dumping for Javascript.
- * @version 1.0.0
- * @author Ariel Flesler
- * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html}
- */
-QUnit.jsDump = (function() {
- function quote( str ) {
- return '"' + str.toString().replace( /"/g, '\\"' ) + '"';
- }
- function literal( o ) {
- return o + "";
- }
- function join( pre, arr, post ) {
- var s = jsDump.separator(),
- base = jsDump.indent(),
- inner = jsDump.indent(1);
- if ( arr.join ) {
- arr = arr.join( "," + s + inner );
- }
- if ( !arr ) {
- return pre + post;
- }
- return [ pre, inner + arr, base + post ].join(s);
- }
- function array( arr, stack ) {
- var i = arr.length, ret = new Array(i);
- this.up();
- while ( i-- ) {
- ret[i] = this.parse( arr[i] , undefined , stack);
- }
- this.down();
- return join( "[", ret, "]" );
- }
-
- var reName = /^function (\w+)/,
- jsDump = {
- // type is used mostly internally, you can fix a (custom)type in advance
- parse: function( obj, type, stack ) {
- stack = stack || [ ];
- var inStack, res,
- parser = this.parsers[ type || this.typeOf(obj) ];
-
- type = typeof parser;
- inStack = inArray( obj, stack );
-
- if ( inStack !== -1 ) {
- return "recursion(" + (inStack - stack.length) + ")";
- }
- if ( type === "function" ) {
- stack.push( obj );
- res = parser.call( this, obj, stack );
- stack.pop();
- return res;
- }
- return ( type === "string" ) ? parser : this.parsers.error;
- },
- typeOf: function( obj ) {
- var type;
- if ( obj === null ) {
- type = "null";
- } else if ( typeof obj === "undefined" ) {
- type = "undefined";
- } else if ( QUnit.is( "regexp", obj) ) {
- type = "regexp";
- } else if ( QUnit.is( "date", obj) ) {
- type = "date";
- } else if ( QUnit.is( "function", obj) ) {
- type = "function";
- } else if ( typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined" ) {
- type = "window";
- } else if ( obj.nodeType === 9 ) {
- type = "document";
- } else if ( obj.nodeType ) {
- type = "node";
- } else if (
- // native arrays
- toString.call( obj ) === "[object Array]" ||
- // NodeList objects
- ( typeof obj.length === "number" && typeof obj.item !== "undefined" && ( obj.length ? obj.item(0) === obj[0] : ( obj.item( 0 ) === null && typeof obj[0] === "undefined" ) ) )
- ) {
- type = "array";
- } else if ( obj.constructor === Error.prototype.constructor ) {
- type = "error";
- } else {
- type = typeof obj;
- }
- return type;
- },
- separator: function() {
- return this.multiline ? this.HTML ? "
" : "\n" : this.HTML ? " " : " ";
- },
- // extra can be a number, shortcut for increasing-calling-decreasing
- indent: function( extra ) {
- if ( !this.multiline ) {
- return "";
- }
- var chr = this.indentChar;
- if ( this.HTML ) {
- chr = chr.replace( /\t/g, " " ).replace( / /g, " " );
- }
- return new Array( this._depth_ + (extra||0) ).join(chr);
- },
- up: function( a ) {
- this._depth_ += a || 1;
- },
- down: function( a ) {
- this._depth_ -= a || 1;
- },
- setParser: function( name, parser ) {
- this.parsers[name] = parser;
- },
- // The next 3 are exposed so you can use them
- quote: quote,
- literal: literal,
- join: join,
- //
- _depth_: 1,
- // This is the list of parsers, to modify them, use jsDump.setParser
- parsers: {
- window: "[Window]",
- document: "[Document]",
- error: function(error) {
- return "Error(\"" + error.message + "\")";
- },
- unknown: "[Unknown]",
- "null": "null",
- "undefined": "undefined",
- "function": function( fn ) {
- var ret = "function",
- // functions never have name in IE
- name = "name" in fn ? fn.name : (reName.exec(fn) || [])[1];
-
- if ( name ) {
- ret += " " + name;
- }
- ret += "( ";
-
- ret = [ ret, QUnit.jsDump.parse( fn, "functionArgs" ), "){" ].join( "" );
- return join( ret, QUnit.jsDump.parse(fn,"functionCode" ), "}" );
- },
- array: array,
- nodelist: array,
- "arguments": array,
- object: function( map, stack ) {
- var ret = [ ], keys, key, val, i;
- QUnit.jsDump.up();
- keys = [];
- for ( key in map ) {
- keys.push( key );
- }
- keys.sort();
- for ( i = 0; i < keys.length; i++ ) {
- key = keys[ i ];
- val = map[ key ];
- ret.push( QUnit.jsDump.parse( key, "key" ) + ": " + QUnit.jsDump.parse( val, undefined, stack ) );
- }
- QUnit.jsDump.down();
- return join( "{", ret, "}" );
- },
- node: function( node ) {
- var len, i, val,
- open = QUnit.jsDump.HTML ? "<" : "<",
- close = QUnit.jsDump.HTML ? ">" : ">",
- tag = node.nodeName.toLowerCase(),
- ret = open + tag,
- attrs = node.attributes;
-
- if ( attrs ) {
- for ( i = 0, len = attrs.length; i < len; i++ ) {
- val = attrs[i].nodeValue;
- // IE6 includes all attributes in .attributes, even ones not explicitly set.
- // Those have values like undefined, null, 0, false, "" or "inherit".
- if ( val && val !== "inherit" ) {
- ret += " " + attrs[i].nodeName + "=" + QUnit.jsDump.parse( val, "attribute" );
- }
- }
- }
- ret += close;
-
- // Show content of TextNode or CDATASection
- if ( node.nodeType === 3 || node.nodeType === 4 ) {
- ret += node.nodeValue;
- }
-
- return ret + open + "/" + tag + close;
- },
- // function calls it internally, it's the arguments part of the function
- functionArgs: function( fn ) {
- var args,
- l = fn.length;
-
- if ( !l ) {
- return "";
- }
-
- args = new Array(l);
- while ( l-- ) {
- // 97 is 'a'
- args[l] = String.fromCharCode(97+l);
- }
- return " " + args.join( ", " ) + " ";
- },
- // object calls it internally, the key part of an item in a map
- key: quote,
- // function calls it internally, it's the content of the function
- functionCode: "[code]",
- // node calls it internally, it's an html attribute value
- attribute: quote,
- string: quote,
- date: quote,
- regexp: literal,
- number: literal,
- "boolean": literal
- },
- // if true, entities are escaped ( <, >, \t, space and \n )
- HTML: false,
- // indentation unit
- indentChar: " ",
- // if true, items in a collection, are separated by a \n, else just a space.
- multiline: true
- };
-
- return jsDump;
-}());
-
-// from jquery.js
-function inArray( elem, array ) {
- if ( array.indexOf ) {
- return array.indexOf( elem );
- }
-
- for ( var i = 0, length = array.length; i < length; i++ ) {
- if ( array[ i ] === elem ) {
- return i;
- }
- }
-
- return -1;
-}
-
-/*
- * Javascript Diff Algorithm
- * By John Resig (http://ejohn.org/)
- * Modified by Chu Alan "sprite"
- *
- * Released under the MIT license.
- *
- * More Info:
- * http://ejohn.org/projects/javascript-diff-algorithm/
- *
- * Usage: QUnit.diff(expected, actual)
- *
- * QUnit.diff( "the quick brown fox jumped over", "the quick fox jumps over" ) == "the quick brown fox jumped jumps over"
- */
-QUnit.diff = (function() {
- /*jshint eqeqeq:false, eqnull:true */
- function diff( o, n ) {
- var i,
- ns = {},
- os = {};
-
- for ( i = 0; i < n.length; i++ ) {
- if ( !hasOwn.call( ns, n[i] ) ) {
- ns[ n[i] ] = {
- rows: [],
- o: null
- };
- }
- ns[ n[i] ].rows.push( i );
- }
-
- for ( i = 0; i < o.length; i++ ) {
- if ( !hasOwn.call( os, o[i] ) ) {
- os[ o[i] ] = {
- rows: [],
- n: null
- };
- }
- os[ o[i] ].rows.push( i );
- }
-
- for ( i in ns ) {
- if ( !hasOwn.call( ns, i ) ) {
- continue;
- }
- if ( ns[i].rows.length === 1 && hasOwn.call( os, i ) && os[i].rows.length === 1 ) {
- n[ ns[i].rows[0] ] = {
- text: n[ ns[i].rows[0] ],
- row: os[i].rows[0]
- };
- o[ os[i].rows[0] ] = {
- text: o[ os[i].rows[0] ],
- row: ns[i].rows[0]
- };
- }
- }
-
- for ( i = 0; i < n.length - 1; i++ ) {
- if ( n[i].text != null && n[ i + 1 ].text == null && n[i].row + 1 < o.length && o[ n[i].row + 1 ].text == null &&
- n[ i + 1 ] == o[ n[i].row + 1 ] ) {
-
- n[ i + 1 ] = {
- text: n[ i + 1 ],
- row: n[i].row + 1
- };
- o[ n[i].row + 1 ] = {
- text: o[ n[i].row + 1 ],
- row: i + 1
- };
- }
- }
-
- for ( i = n.length - 1; i > 0; i-- ) {
- if ( n[i].text != null && n[ i - 1 ].text == null && n[i].row > 0 && o[ n[i].row - 1 ].text == null &&
- n[ i - 1 ] == o[ n[i].row - 1 ]) {
-
- n[ i - 1 ] = {
- text: n[ i - 1 ],
- row: n[i].row - 1
- };
- o[ n[i].row - 1 ] = {
- text: o[ n[i].row - 1 ],
- row: i - 1
- };
- }
- }
-
- return {
- o: o,
- n: n
- };
- }
-
- return function( o, n ) {
- o = o.replace( /\s+$/, "" );
- n = n.replace( /\s+$/, "" );
-
- var i, pre,
- str = "",
- out = diff( o === "" ? [] : o.split(/\s+/), n === "" ? [] : n.split(/\s+/) ),
- oSpace = o.match(/\s+/g),
- nSpace = n.match(/\s+/g);
-
- if ( oSpace == null ) {
- oSpace = [ " " ];
- }
- else {
- oSpace.push( " " );
- }
-
- if ( nSpace == null ) {
- nSpace = [ " " ];
- }
- else {
- nSpace.push( " " );
- }
-
- if ( out.n.length === 0 ) {
- for ( i = 0; i < out.o.length; i++ ) {
- str += "" + out.o[i] + oSpace[i] + "";
- }
- }
- else {
- if ( out.n[0].text == null ) {
- for ( n = 0; n < out.o.length && out.o[n].text == null; n++ ) {
- str += "" + out.o[n] + oSpace[n] + "";
- }
- }
-
- for ( i = 0; i < out.n.length; i++ ) {
- if (out.n[i].text == null) {
- str += "" + out.n[i] + nSpace[i] + "";
- }
- else {
- // `pre` initialized at top of scope
- pre = "";
-
- for ( n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++ ) {
- pre += "" + out.o[n] + oSpace[n] + "";
- }
- str += " " + out.n[i].text + nSpace[i] + pre;
- }
- }
- }
-
- return str;
- };
-}());
-
-// for CommonJS enviroments, export everything
-if ( typeof exports !== "undefined" ) {
- extend( exports, QUnit );
-}
-
-// get at whatever the global object is, like window in browsers
-}( (function() {return this;}.call()) ));
diff --git a/test/lib/require.js b/test/lib/require.js
deleted file mode 100644
index 987f865..0000000
--- a/test/lib/require.js
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- RequireJS 2.1.5 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.
- Available via the MIT or new BSD license.
- see: http://github.com/jrburke/requirejs for details
-*/
-var requirejs,require,define;
-(function(aa){function I(b){return"[object Function]"===L.call(b)}function J(b){return"[object Array]"===L.call(b)}function y(b,c){if(b){var d;for(d=0;dthis.depCount&&!this.defined){if(I(n)){if(this.events.error)try{e=i.execCb(c,n,b,e)}catch(d){a=d}else e=i.execCb(c,n,b,e);this.map.isDefine&&((b=this.module)&&void 0!==b.exports&&b.exports!==this.exports?e=b.exports:void 0===e&&this.usingExports&&(e=this.exports));if(a)return a.requireMap=this.map,a.requireModules=[this.map.id],a.requireType="define",v(this.error=
-a)}else e=n;this.exports=e;if(this.map.isDefine&&!this.ignore&&(q[c]=e,l.onResourceLoad))l.onResourceLoad(i,this.map,this.depMaps);x(c);this.defined=!0}this.defining=!1;this.defined&&!this.defineEmitted&&(this.defineEmitted=!0,this.emit("defined",this.exports),this.defineEmitComplete=!0)}}else this.fetch()}},callPlugin:function(){var a=this.map,b=a.id,d=j(a.prefix);this.depMaps.push(d);t(d,"defined",u(this,function(e){var n,d;d=this.map.name;var g=this.map.parentMap?this.map.parentMap.name:null,h=
-i.makeRequire(a.parentMap,{enableBuildCallback:!0});if(this.map.unnormalized){if(e.normalize&&(d=e.normalize(d,function(a){return c(a,g,!0)})||""),e=j(a.prefix+"!"+d,this.map.parentMap),t(e,"defined",u(this,function(a){this.init([],function(){return a},null,{enabled:!0,ignore:!0})})),d=m(p,e.id)){this.depMaps.push(e);if(this.events.error)d.on("error",u(this,function(a){this.emit("error",a)}));d.enable()}}else n=u(this,function(a){this.init([],function(){return a},null,{enabled:!0})}),n.error=u(this,
-function(a){this.inited=!0;this.error=a;a.requireModules=[b];G(p,function(a){0===a.map.id.indexOf(b+"_unnormalized")&&x(a.map.id)});v(a)}),n.fromText=u(this,function(e,c){var d=a.name,g=j(d),C=O;c&&(e=c);C&&(O=!1);r(g);s(k.config,b)&&(k.config[d]=k.config[b]);try{l.exec(e)}catch(ca){return v(B("fromtexteval","fromText eval for "+b+" failed: "+ca,ca,[b]))}C&&(O=!0);this.depMaps.push(g);i.completeLoad(d);h([d],n)}),e.load(a.name,h,n,k)}));i.enable(d,this);this.pluginMaps[d.id]=d},enable:function(){V[this.map.id]=
-this;this.enabling=this.enabled=!0;y(this.depMaps,u(this,function(a,b){var c,e;if("string"===typeof a){a=j(a,this.map.isDefine?this.map:this.map.parentMap,!1,!this.skipMap);this.depMaps[b]=a;if(c=m(N,a.id)){this.depExports[b]=c(this);return}this.depCount+=1;t(a,"defined",u(this,function(a){this.defineDep(b,a);this.check()}));this.errback&&t(a,"error",this.errback)}c=a.id;e=p[c];!s(N,c)&&(e&&!e.enabled)&&i.enable(a,this)}));G(this.pluginMaps,u(this,function(a){var b=m(p,a.id);b&&!b.enabled&&i.enable(a,
-this)}));this.enabling=!1;this.check()},on:function(a,b){var c=this.events[a];c||(c=this.events[a]=[]);c.push(b)},emit:function(a,b){y(this.events[a],function(a){a(b)});"error"===a&&delete this.events[a]}};i={config:k,contextName:b,registry:p,defined:q,urlFetched:U,defQueue:H,Module:Z,makeModuleMap:j,nextTick:l.nextTick,onError:v,configure:function(a){a.baseUrl&&"/"!==a.baseUrl.charAt(a.baseUrl.length-1)&&(a.baseUrl+="/");var b=k.pkgs,c=k.shim,e={paths:!0,config:!0,map:!0};G(a,function(a,b){e[b]?
-"map"===b?(k.map||(k.map={}),R(k[b],a,!0,!0)):R(k[b],a,!0):k[b]=a});a.shim&&(G(a.shim,function(a,b){J(a)&&(a={deps:a});if((a.exports||a.init)&&!a.exportsFn)a.exportsFn=i.makeShimExports(a);c[b]=a}),k.shim=c);a.packages&&(y(a.packages,function(a){a="string"===typeof a?{name:a}:a;b[a.name]={name:a.name,location:a.location||a.name,main:(a.main||"main").replace(ja,"").replace(ea,"")}}),k.pkgs=b);G(p,function(a,b){!a.inited&&!a.map.unnormalized&&(a.map=j(b))});if(a.deps||a.callback)i.require(a.deps||[],
-a.callback)},makeShimExports:function(a){return function(){var b;a.init&&(b=a.init.apply(aa,arguments));return b||a.exports&&ba(a.exports)}},makeRequire:function(a,f){function d(e,c,h){var g,k;f.enableBuildCallback&&(c&&I(c))&&(c.__requireJsBuild=!0);if("string"===typeof e){if(I(c))return v(B("requireargs","Invalid require call"),h);if(a&&s(N,e))return N[e](p[a.id]);if(l.get)return l.get(i,e,a,d);g=j(e,a,!1,!0);g=g.id;return!s(q,g)?v(B("notloaded",'Module name "'+g+'" has not been loaded yet for context: '+
-b+(a?"":". Use require([])"))):q[g]}L();i.nextTick(function(){L();k=r(j(null,a));k.skipMap=f.skipMap;k.init(e,c,h,{enabled:!0});D()});return d}f=f||{};R(d,{isBrowser:A,toUrl:function(b){var d,f=b.lastIndexOf("."),g=b.split("/")[0];if(-1!==f&&(!("."===g||".."===g)||1h.attachEvent.toString().indexOf("[native code"))&&!Y?(O=!0,h.attachEvent("onreadystatechange",b.onScriptLoad)):(h.addEventListener("load",b.onScriptLoad,!1),h.addEventListener("error",b.onScriptError,!1)),h.src=d,K=h,D?x.insertBefore(h,D):x.appendChild(h),K=null,h;if(da)try{importScripts(d),b.completeLoad(c)}catch(j){b.onError(B("importscripts","importScripts failed for "+c+" at "+d,j,[c]))}};A&&M(document.getElementsByTagName("script"),function(b){x||(x=
-b.parentNode);if(t=b.getAttribute("data-main"))return r.baseUrl||(E=t.split("/"),Q=E.pop(),fa=E.length?E.join("/")+"/":"./",r.baseUrl=fa,t=Q),t=t.replace(ea,""),r.deps=r.deps?r.deps.concat(t):[t],!0});define=function(b,c,d){var l,h;"string"!==typeof b&&(d=c,c=b,b=null);J(c)||(d=c,c=[]);!c.length&&I(d)&&d.length&&(d.toString().replace(la,"").replace(ma,function(b,d){c.push(d)}),c=(1===d.length?["require"]:["require","exports","module"]).concat(c));if(O){if(!(l=K))P&&"interactive"===P.readyState||M(document.getElementsByTagName("script"),
-function(b){if("interactive"===b.readyState)return P=b}),l=P;l&&(b||(b=l.getAttribute("data-requiremodule")),h=F[l.getAttribute("data-requirecontext")])}(h?h.defQueue:T).push([b,c,d])};define.amd={jQuery:!0};l.exec=function(b){return eval(b)};l(r)}})(this);
diff --git a/test/lib/resemble.js b/test/lib/resemble.js
new file mode 100644
index 0000000..1cb8c29
--- /dev/null
+++ b/test/lib/resemble.js
@@ -0,0 +1,535 @@
+/*
+Author: James Cryer
+Company: Huddle
+Last updated date: 21 Feb 2013
+URL: https://github.com/Huddle/Resemble.js
+*/
+
+(function(_this){
+ 'use strict';
+
+ _this['resemble'] = function( fileData ){
+
+ var data = {};
+ var images = [];
+ var updateCallbackArray = [];
+
+ var tolerance = { // between 0 and 255
+ red: 16,
+ green: 16,
+ blue: 16,
+ minBrightness: 16,
+ maxBrightness: 240
+ };
+
+ var ignoreAntialiasing = false;
+ var ignoreColors = false;
+
+ function triggerDataUpdate(){
+ var len = updateCallbackArray.length;
+ var i;
+ for(i=0;i tolerance.maxBrightness;
+ }
+
+ function getHue(r,g,b){
+
+ r = r / 255;
+ g = g / 255;
+ b = b / 255;
+ var max = Math.max(r, g, b), min = Math.min(r, g, b);
+ var h;
+ var d;
+
+ if (max == min){
+ h = 0; // achromatic
+ } else{
+ d = max - min;
+ switch(max){
+ case r: h = (g - b) / d + (g < b ? 6 : 0); break;
+ case g: h = (b - r) / d + 2; break;
+ case b: h = (r - g) / d + 4; break;
+ }
+ h /= 6;
+ }
+
+ return h;
+ }
+
+ function isAntialiased(sourcePix, data, cacheSet, verticalPos, horizontalPos, width){
+ var offset;
+ var targetPix;
+ var distance = 1;
+ var i;
+ var j;
+ var hasHighContrastSibling = 0;
+ var hasSiblingWithDifferentHue = 0;
+ var hasEquivilantSibling = 0;
+
+ addHueInfo(sourcePix);
+
+ for (i = distance*-1; i <= distance; i++){
+ for (j = distance*-1; j <= distance; j++){
+
+ if(i===0 && j===0){
+ // ignore source pixel
+ } else {
+
+ offset = ((verticalPos+j)*width + (horizontalPos+i)) * 4;
+ targetPix = getPixelInfo(data, offset, cacheSet);
+
+ if(targetPix === null){
+ continue;
+ }
+
+ addBrightnessInfo(targetPix);
+ addHueInfo(targetPix);
+
+ if( isContrasting(sourcePix, targetPix) ){
+ hasHighContrastSibling++;
+ }
+
+ if( isRGBSame(sourcePix,targetPix) ){
+ hasEquivilantSibling++;
+ }
+
+ if( Math.abs(targetPix.h - sourcePix.h) > 0.3 ){
+ hasSiblingWithDifferentHue++;
+ }
+
+ if( hasSiblingWithDifferentHue > 1 || hasHighContrastSibling > 1){
+ return true;
+ }
+ }
+ }
+ }
+
+ if(hasEquivilantSibling < 2){
+ return true;
+ }
+
+ return false;
+ }
+
+ function errorPixel(px, offset){
+ px[offset] = 255; //r
+ px[offset + 1] = 0; //g
+ px[offset + 2] = 255; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyPixel(px, offset, data){
+ px[offset] = data.r; //r
+ px[offset + 1] = data.g; //g
+ px[offset + 2] = data.b; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyGrayScalePixel(px, offset, data){
+ px[offset] = data.brightness; //r
+ px[offset + 1] = data.brightness; //g
+ px[offset + 2] = data.brightness; //b
+ px[offset + 3] = 255; //a
+ }
+
+
+ function getPixelInfo(data, offset, cacheSet){
+ var r;
+ var g;
+ var b;
+ var d;
+
+ if(typeof data[offset] !== 'undefined'){
+ r = data[offset];
+ g = data[offset+1];
+ b = data[offset+2];
+ d = {
+ r: r,
+ g: g,
+ b: b
+ };
+
+ return d;
+ } else {
+ return null;
+ }
+ }
+
+ function addBrightnessInfo(data){
+ data.brightness = getBrightness(data.r,data.g,data.b); // 'corrected' lightness
+ }
+
+ function addHueInfo(data){
+ data.h = getHue(data.r,data.g,data.b);
+ }
+
+ function analyseImages(img1, img2, width, height){
+
+ var hiddenCanvas = document.createElement('canvas');
+
+ var data1 = img1.data;
+ var data2 = img2.data;
+
+ hiddenCanvas.width = width;
+ hiddenCanvas.height = height;
+
+ var context = hiddenCanvas.getContext('2d');
+ var imgd = context.createImageData(width,height);
+ var targetPix = imgd.data;
+
+ var mismatchCount = 0;
+
+ var time = Date.now();
+
+ var skip;
+
+ if( (width > 1200 || height > 1200) && ignoreAntialiasing){
+ skip = 6;
+ }
+
+ loop(height, width, function(verticalPos, horizontalPos){
+
+ if(skip){ // only skip if the image isn't small
+ if(verticalPos % skip === 0 || horizontalPos % skip === 0){
+ return;
+ }
+ }
+
+ var offset = (verticalPos*width + horizontalPos) * 4;
+ var pixel1 = getPixelInfo(data1, offset, 1);
+ var pixel2 = getPixelInfo(data2, offset, 2);
+
+ if(pixel1 === null || pixel2 === null){
+ return;
+ }
+
+ if (ignoreColors){
+
+ addBrightnessInfo(pixel1);
+ addBrightnessInfo(pixel2);
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ return;
+ }
+
+ if( isRGBSimilar(pixel1, pixel2) ){
+ copyPixel(targetPix, offset, pixel2);
+
+ } else if( ignoreAntialiasing && (
+ addBrightnessInfo(pixel1), // jit pixel info augmentation looks a little weird, sorry.
+ addBrightnessInfo(pixel2),
+ isAntialiased(pixel1, data1, 1, verticalPos, horizontalPos, width) ||
+ isAntialiased(pixel2, data2, 2, verticalPos, horizontalPos, width)
+ )){
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+
+ });
+
+ data.misMatchPercentage = (mismatchCount / (height*width) * 100).toFixed(2);
+ data.analysisTime = Date.now() - time;
+
+ data.getImageDataUrl = function(text){
+ var barHeight = 0;
+
+ if(text){
+ barHeight = addLabel(text,context,hiddenCanvas);
+ }
+
+ context.putImageData(imgd, 0, barHeight);
+
+ return hiddenCanvas.toDataURL("image/png");
+ };
+ }
+
+ function addLabel(text, context, hiddenCanvas){
+ var textPadding = 2;
+
+ context.font = '12px sans-serif';
+
+ var textWidth = context.measureText(text).width + textPadding*2;
+ var barHeight = 22;
+
+ if(textWidth > hiddenCanvas.width){
+ hiddenCanvas.width = textWidth;
+ }
+
+ hiddenCanvas.height += barHeight;
+
+ context.fillStyle = "#666";
+ context.fillRect(0,0,hiddenCanvas.width,barHeight -4);
+ context.fillStyle = "#fff";
+ context.fillRect(0,barHeight -4,hiddenCanvas.width, 4);
+
+ context.fillStyle = "#fff";
+ context.textBaseline = "top";
+ context.font = '12px sans-serif';
+ context.fillText(text, textPadding, 1);
+
+ return barHeight;
+ }
+
+ function normalise(img, w, h){
+ var c;
+ var context;
+
+ if(img.height < h || img.width < w){
+ c = document.createElement('canvas');
+ c.width = w;
+ c.height = h;
+ context = c.getContext('2d');
+ context.putImageData(img, 0, 0);
+ return context.getImageData(0, 0, w, h);
+ }
+
+ return img;
+ }
+
+ function compare(one, two){
+
+ function onceWeHaveBoth(){
+ var width;
+ var height;
+ if(images.length === 2){
+ width = images[0].width > images[1].width ? images[0].width : images[1].width;
+ height = images[0].height > images[1].height ? images[0].height : images[1].height;
+
+ if( (images[0].width === images[1].width) && (images[0].height === images[1].height) ){
+ data.isSameDimensions = true;
+ } else {
+ data.isSameDimensions = false;
+ }
+
+ analyseImages( normalise(images[0],width, height), normalise(images[1],width, height), width, height);
+
+ triggerDataUpdate();
+ }
+ }
+
+ images = [];
+ loadImageData(one, onceWeHaveBoth);
+ loadImageData(two, onceWeHaveBoth);
+ }
+
+ function getCompareApi(param){
+
+ var secondFileData,
+ hasMethod = typeof param === 'function';
+
+ if( !hasMethod ){
+ // assume it's file data
+ secondFileData = param;
+ }
+
+ var self = {
+ ignoreNothing: function(){
+
+ tolerance.red = 16;
+ tolerance.green = 16;
+ tolerance.blue = 16;
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreAntialiasing: function(){
+
+ tolerance.red = 32;
+ tolerance.green = 32;
+ tolerance.blue = 32;
+ tolerance.minBrightness = 64;
+ tolerance.maxBrightness = 96;
+
+ ignoreAntialiasing = true;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreColors: function(){
+
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = true;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ onComplete: function( callback ){
+
+ updateCallbackArray.push(callback);
+
+ var wrapper = function(){
+ compare(fileData, secondFileData);
+ };
+
+ wrapper();
+
+ return getCompareApi(wrapper);
+ }
+ };
+
+ return self;
+ }
+
+ return {
+ onComplete: function( callback ){
+ updateCallbackArray.push(callback);
+ loadImageData(fileData, function(imageData, width, height){
+ parseImage(imageData.data, width, height);
+ });
+ },
+ compareTo: function(secondFileData){
+ return getCompareApi(secondFileData);
+ }
+ };
+
+ };
+}(this));
\ No newline at end of file
diff --git a/test/testsuite.js b/test/testsuite.js
deleted file mode 100644
index b486acb..0000000
--- a/test/testsuite.js
+++ /dev/null
@@ -1,36 +0,0 @@
-requirejs.config({
- baseUrl: '/test/unit/'
-});
-
-define(function(require) {
- var testModules = [
- 'Pixi',
- 'Point',
- 'Rectangle',
- 'DisplayObject',
- 'DisplayObjectContainer',
- 'Sprite',
- 'MovieClip',
- 'InteractionManager',
- 'Stage',
- 'utils/Utils',
- 'utils/EventTarget',
- 'utils/Matrix',
- 'utils/Detector',
- 'renderers/WebGLShaders',
- 'renderers/WebGLRenderer',
- 'renderers/WebGLBatch',
- 'renderers/CanvasRenderer',
- 'extras/Strip',
- 'extras/Rope',
- 'textures/BaseTexture',
- 'textures/Texture',
- 'loaders/SpriteSheetLoader',
- 'loaders/AssetLoader'
- ];
-
- // Resolve all testModules and then start the Test Runner.
- require(testModules, function() {
- QUnit.start();
- });
-});
\ No newline at end of file
diff --git a/test/textures/SpriteSheet-Aliens.png b/test/textures/SpriteSheet-Aliens.png
new file mode 100644
index 0000000..210acb1
--- /dev/null
+++ b/test/textures/SpriteSheet-Aliens.png
Binary files differ
diff --git a/test/textures/SpriteSheet-Explosion.png b/test/textures/SpriteSheet-Explosion.png
new file mode 100755
index 0000000..79e1a69
--- /dev/null
+++ b/test/textures/SpriteSheet-Explosion.png
Binary files differ
diff --git a/test/textures/bunny.png b/test/textures/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/textures/bunny.png
Binary files differ
diff --git a/test/unit/DisplayObject.js b/test/unit/DisplayObject.js
deleted file mode 100644
index 5e7e72f..0000000
--- a/test/unit/DisplayObject.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObject');
-});
diff --git a/test/unit/DisplayObjectContainer.js b/test/unit/DisplayObjectContainer.js
deleted file mode 100644
index b323959..0000000
--- a/test/unit/DisplayObjectContainer.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObjectContainer');
-});
diff --git a/test/unit/InteractionManager.js b/test/unit/InteractionManager.js
deleted file mode 100644
index e751f52..0000000
--- a/test/unit/InteractionManager.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('InteractionManager');
-});
diff --git a/test/unit/MovieClip.js b/test/unit/MovieClip.js
deleted file mode 100644
index 37d9446..0000000
--- a/test/unit/MovieClip.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('MovieClip');
-});
diff --git a/test/unit/Pixi.js b/test/unit/Pixi.js
deleted file mode 100644
index 36eee73..0000000
--- a/test/unit/Pixi.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Pixi');
-});
diff --git a/test/unit/Point.js b/test/unit/Point.js
deleted file mode 100644
index 983ff6e..0000000
--- a/test/unit/Point.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Point');
-});
diff --git a/test/unit/Rectangle.js b/test/unit/Rectangle.js
deleted file mode 100644
index 3b439ba..0000000
--- a/test/unit/Rectangle.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Rectangle');
-});
diff --git a/test/unit/Sprite.js b/test/unit/Sprite.js
deleted file mode 100644
index ed4f596..0000000
--- a/test/unit/Sprite.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Sprite');
-});
diff --git a/test/unit/Stage.js b/test/unit/Stage.js
deleted file mode 100644
index 2d70291..0000000
--- a/test/unit/Stage.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Stage');
-});
diff --git a/test/unit/extras/Rope.js b/test/unit/extras/Rope.js
deleted file mode 100644
index 5606f14..0000000
--- a/test/unit/extras/Rope.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Rope');
-});
diff --git a/test/unit/extras/Strip.js b/test/unit/extras/Strip.js
deleted file mode 100644
index 0134d3a..0000000
--- a/test/unit/extras/Strip.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Strip');
-});
diff --git a/test/unit/loaders/AssetLoader.js b/test/unit/loaders/AssetLoader.js
deleted file mode 100644
index 13b8443..0000000
--- a/test/unit/loaders/AssetLoader.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('AssetLoader');
-});
diff --git a/test/unit/loaders/SpriteSheetLoader.js b/test/unit/loaders/SpriteSheetLoader.js
deleted file mode 100644
index 8bf0cb2..0000000
--- a/test/unit/loaders/SpriteSheetLoader.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('SpriteSheetLoader');
-});
diff --git a/test/unit/pixi/InteractionManager.js b/test/unit/pixi/InteractionManager.js
new file mode 100644
index 0000000..ed3001f
--- /dev/null
+++ b/test/unit/pixi/InteractionManager.js
@@ -0,0 +1,10 @@
+describe('pixi/InteractionManager', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var InteractionManager = PIXI.InteractionManager;
+
+ it('Module exists', function () {
+ expect(InteractionManager).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/Pixi.js b/test/unit/pixi/Pixi.js
new file mode 100644
index 0000000..27debc1
--- /dev/null
+++ b/test/unit/pixi/Pixi.js
@@ -0,0 +1,9 @@
+describe('pixi/Pixi', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+
+ it('Module exists', function () {
+ expect(global).to.have.property('PIXI').and.to.be.an('object');
+ });
+});
diff --git a/test/unit/pixi/core/Circle.js b/test/unit/pixi/core/Circle.js
new file mode 100644
index 0000000..93a4456
--- /dev/null
+++ b/test/unit/pixi/core/Circle.js
@@ -0,0 +1,22 @@
+describe('pixi/core/Circle', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Circle = PIXI.Circle;
+
+ it('Module exists', function () {
+ expect(Circle).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Circle();
+
+ expect(obj).to.be.an.instanceof(Circle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', 0);
+ expect(obj).to.have.property('y', 0);
+ expect(obj).to.have.property('radius', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Ellipse.js b/test/unit/pixi/core/Ellipse.js
new file mode 100644
index 0000000..026b56f
--- /dev/null
+++ b/test/unit/pixi/core/Ellipse.js
@@ -0,0 +1,24 @@
+describe('pixi/core/Ellipse', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Ellipse = PIXI.Ellipse;
+
+ it('Module exists', function () {
+ expect(Ellipse).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Ellipse();
+
+ expect(obj).to.be.an.instanceof(Ellipse);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+ expect(obj).to.respondTo('getBounds');
+
+ expect(obj).to.have.property('x', 0);
+ expect(obj).to.have.property('y', 0);
+ expect(obj).to.have.property('width', 0);
+ expect(obj).to.have.property('height', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Matrix.js b/test/unit/pixi/core/Matrix.js
new file mode 100644
index 0000000..b48989e
--- /dev/null
+++ b/test/unit/pixi/core/Matrix.js
@@ -0,0 +1,30 @@
+describe('pixi/core/Matrix', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var mat3 = PIXI.mat3;
+ var mat4 = PIXI.mat4;
+ var Matrix = PIXI.Matrix;
+
+ it('Ensure determineMatrixArrayType works', function () {
+ expect(Matrix).to.be.a('function');
+ });
+
+ it('mat3 exists', function () {
+ expect(mat3).to.be.an('object');
+ });
+
+ it('Confirm new mat3 matrix', function () {
+ var matrix = new mat3.create();
+ pixi_core_Matrix_confirmNewMat3(matrix);
+ });
+
+ it('mat3 exists', function () {
+ expect(mat4).to.be.an('object');
+ });
+
+ it('Confirm new mat4 matrix', function () {
+ var matrix = new mat4.create();
+ pixi_core_Matrix_confirmNewMat4(matrix);
+ });
+});
diff --git a/test/unit/pixi/core/Point.js b/test/unit/pixi/core/Point.js
new file mode 100644
index 0000000..c4d5163
--- /dev/null
+++ b/test/unit/pixi/core/Point.js
@@ -0,0 +1,15 @@
+describe('pixi/core/Point', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Point = PIXI.Point;
+
+ it('Module exists', function () {
+ expect(Point).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Point();
+ pixi_core_Point_confirm(obj, 0, 0);
+ });
+});
diff --git a/test/unit/pixi/core/Polygon.js b/test/unit/pixi/core/Polygon.js
new file mode 100644
index 0000000..dc8c918
--- /dev/null
+++ b/test/unit/pixi/core/Polygon.js
@@ -0,0 +1,20 @@
+describe('pixi/core/Polygon', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Polygon = PIXI.Polygon;
+
+ it('Module exists', function () {
+ expect(Polygon).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Polygon();
+
+ expect(obj).to.be.an.instanceof(Polygon);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.deep.property('points.length', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Rectangle.js b/test/unit/pixi/core/Rectangle.js
new file mode 100644
index 0000000..d43316e
--- /dev/null
+++ b/test/unit/pixi/core/Rectangle.js
@@ -0,0 +1,15 @@
+describe('pixi/core/Rectangle', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Rectangle = PIXI.Rectangle;
+
+ it('Module exists', function () {
+ expect(Rectangle).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var rect = new Rectangle();
+ pixi_core_Rectangle_confirm(rect, 0, 0, 0, 0);
+ });
+});
diff --git a/test/unit/pixi/display/DisplayObject.js b/test/unit/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..40c6fbc
--- /dev/null
+++ b/test/unit/pixi/display/DisplayObject.js
@@ -0,0 +1,21 @@
+describe('pixi/display/DisplayObject', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var DisplayObject = PIXI.DisplayObject;
+
+ it('Module exists', function () {
+ expect(DisplayObject).to.be.a('function');
+ expect(PIXI).to.have.property('visibleCount', 0);
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new DisplayObject();
+
+ pixi_display_DisplayObject_confirmNew(obj);
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', false);
+ expect(obj).to.have.property('stage', null);
+ });
+});
diff --git a/test/unit/pixi/display/DisplayObjectContainer.js b/test/unit/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..ce7f02f
--- /dev/null
+++ b/test/unit/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,20 @@
+describe('pixi/display/DisplayObjectContainer', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var DisplayObjectContainer = PIXI.DisplayObjectContainer;
+
+ it('Module exists', function () {
+ expect(DisplayObjectContainer).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new DisplayObjectContainer();
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', false);
+ expect(obj).to.have.property('stage', null);
+ });
+});
diff --git a/test/unit/pixi/display/MovieClip.js b/test/unit/pixi/display/MovieClip.js
new file mode 100644
index 0000000..f3c6c6a
--- /dev/null
+++ b/test/unit/pixi/display/MovieClip.js
@@ -0,0 +1,33 @@
+describe('pixi/display/MovieClip', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var MovieClip = PIXI.MovieClip;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(MovieClip).to.be.a('function');
+ });
+
+ it('Confirm new instance', function (done) {
+ var texture = Texture.fromImage('/base/test/textures/SpriteSheet-Explosion.png');
+ var obj = new MovieClip([texture]);
+
+ pixi_display_Sprite_confirmNew(obj, done);
+
+ expect(obj).to.be.an.instanceof(MovieClip);
+ expect(obj).to.respondTo('stop');
+ expect(obj).to.respondTo('play');
+ expect(obj).to.respondTo('gotoAndStop');
+ expect(obj).to.respondTo('gotoAndPlay');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('textures.length', 1);
+ expect(obj).to.have.deep.property('textures[0]', texture);
+ expect(obj).to.have.property('animationSpeed', 1);
+ expect(obj).to.have.property('loop', true);
+ expect(obj).to.have.property('onComplete', null);
+ expect(obj).to.have.property('currentFrame', 0);
+ expect(obj).to.have.property('playing', false);
+ });
+});
diff --git a/test/unit/pixi/display/Sprite.js b/test/unit/pixi/display/Sprite.js
new file mode 100644
index 0000000..54e914f
--- /dev/null
+++ b/test/unit/pixi/display/Sprite.js
@@ -0,0 +1,25 @@
+describe('pixi/display/Sprite', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Sprite = PIXI.Sprite;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(Sprite).to.be.a('function');
+ expect(PIXI).to.have.deep.property('blendModes.NORMAL', 0);
+ expect(PIXI).to.have.deep.property('blendModes.SCREEN', 1);
+ });
+
+ it('Members exist', function () {
+ expect(Sprite).itself.to.respondTo('fromImage');
+ expect(Sprite).itself.to.respondTo('fromFrame');
+ });
+
+ it('Confirm new instance', function (done) {
+ var texture = Texture.fromImage('/base/test/textures/SpriteSheet-Aliens.png');
+ var obj = new Sprite(texture);
+
+ pixi_display_Sprite_confirmNew(obj, done);
+ });
+});
diff --git a/test/unit/pixi/display/Stage.js b/test/unit/pixi/display/Stage.js
new file mode 100644
index 0000000..3cc2a4d
--- /dev/null
+++ b/test/unit/pixi/display/Stage.js
@@ -0,0 +1,49 @@
+describe('pixi/display/Stage', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Stage = PIXI.Stage;
+ var InteractionManager = PIXI.InteractionManager;
+ var Rectangle = PIXI.Rectangle;
+
+ it('Module exists', function () {
+ expect(Stage).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Stage(null, true);
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(Stage);
+ expect(obj).to.respondTo('updateTransform');
+ expect(obj).to.respondTo('setBackgroundColor');
+ expect(obj).to.respondTo('getMousePosition');
+
+ // FIXME: duplicate member in DisplayObject
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ // FIXME: convert arg to bool in constructor
+ expect(obj).to.have.property('interactive', true);
+
+ expect(obj).to.have.property('interactionManager')
+ .and.to.be.an.instanceof(InteractionManager)
+ .and.to.have.property('stage', obj);
+
+ expect(obj).to.have.property('dirty', true);
+
+ expect(obj).to.have.property('stage', obj);
+
+ expect(obj).to.have.property('hitArea')
+ .and.to.be.an.instanceof(Rectangle);
+ pixi_core_Rectangle_confirm(obj.hitArea, 0, 0, 100000, 100000);
+
+ expect(obj).to.have.property('backgroundColor', 0x000000);
+ expect(obj).to.have.deep.property('backgroundColorSplit.length', 3);
+ expect(obj).to.have.deep.property('backgroundColorSplit[0]', 0);
+ expect(obj).to.have.deep.property('backgroundColorSplit[1]', 0);
+ expect(obj).to.have.deep.property('backgroundColorSplit[2]', 0);
+ expect(obj).to.have.property('backgroundColorString', '#000000');
+
+ expect(obj).to.have.property('worldVisible', true);
+ });
+});
diff --git a/test/unit/pixi/extras/CustomRenderable.js b/test/unit/pixi/extras/CustomRenderable.js
new file mode 100644
index 0000000..8d83cf0
--- /dev/null
+++ b/test/unit/pixi/extras/CustomRenderable.js
@@ -0,0 +1,21 @@
+describe('pixi/extras/CustomRenderable', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var CustomRenderable = PIXI.CustomRenderable;
+
+ it('Module exists', function () {
+ expect(CustomRenderable).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new CustomRenderable();
+
+ pixi_display_DisplayObject_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(CustomRenderable);
+ expect(obj).to.respondTo('renderCanvas');
+ expect(obj).to.respondTo('initWebGL');
+ expect(obj).to.respondTo('renderWebGL');
+ });
+});
diff --git a/.gitignore b/.gitignore
index 12e1b62..0b88317 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
node_modules
.DS_Store
-.project
\ No newline at end of file
+.project
+*.log
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..63e4d7c
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,8 @@
+language: node_js
+node_js:
+ - 0.10
+
+before_script:
+ - npm install -g grunt-cli
+ - export DISPLAY=:99.0
+ - sh -e /etc/init.d/xvfb start
diff --git a/Gruntfile.js b/Gruntfile.js
index b083b49..103938c 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -1,10 +1,12 @@
+'use strict';
+
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-connect');
- grunt.loadNpmTasks('grunt-contrib-qunit');
grunt.loadNpmTasks('grunt-contrib-yuidoc');
+ grunt.loadTasks('tasks');
var root = 'src/pixi/',
debug = 'bin/pixi.dev.js',
@@ -79,7 +81,7 @@
},
files: {
srcBlob: '<%= dirs.src %>/**/*.js',
- testBlob: '<%= dirs.test %>/unit/**/*.js',
+ testBlob: '<%= dirs.test %>/{functional,lib/pixi,unit}/**/*.js',
build: '<%= dirs.build %>/pixi.dev.js',
buildMin: '<%= dirs.build %>/pixi.js'
},
@@ -94,7 +96,12 @@
},
jshint: {
beforeconcat: srcFiles,
- test: ['<%= files.testBlob %>'],
+ test: {
+ src: ['<%= files.testBlob %>'],
+ options: {
+ expr: true
+ }
+ },
options: {
asi: true,
smarttabs: true
@@ -128,12 +135,6 @@
]
},
connect: {
- qunit: {
- options: {
- port: grunt.option('port-test') || 9002,
- base: './'
- }
- },
test: {
options: {
port: grunt.option('port-test') || 9002,
@@ -142,13 +143,6 @@
}
}
},
- qunit: {
- all: {
- options: {
- urls: ['http://localhost:' + (grunt.option('port-test') || 9002) + '/test/index.html']
- }
- }
- },
yuidoc: {
compile: {
name: '<%= pkg.name %>',
@@ -161,6 +155,13 @@
outdir: '<%= dirs.docs %>'
}
}
+ },
+ karma: {
+ unit: {
+ configFile: 'test/karma.conf.js',
+ // browsers: ['Chrome'],
+ singleRun: true
+ }
}
});
@@ -182,9 +183,10 @@
}
)
- grunt.registerTask('default', ['concat', 'uglify', 'distribute']);
grunt.registerTask('build', ['concat', 'uglify', 'distribute']);
- grunt.registerTask('test', ['build', 'connect:qunit', 'qunit']);
+ grunt.registerTask('test', ['concat', 'jshint:test', 'karma']);
grunt.registerTask('docs', ['yuidoc']);
-
-}
\ No newline at end of file
+ grunt.registerTask('default', ['test', 'uglify', 'distribute']);
+ // Travis CI task.
+ grunt.registerTask('travis', ['test']);
+}
diff --git a/README.md b/README.md
index c62ef86..690cfe4 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,8 @@

+[](http://travis-ci.org/drkibitz/pixi.js)
+
#### JavaScript 2D Renderer ####
The aim of this project is to provide a fast lightweight 2D library that works
diff --git a/package.json b/package.json
index b373240..1246a68 100644
--- a/package.json
+++ b/package.json
@@ -18,14 +18,21 @@
"main": "bin/pixi.js",
+ "scripts": {
+ "test": "grunt travis --verbose"
+ },
+
"dependencies": {},
"devDependencies": {
"grunt": "~0.4.x",
- "grunt-contrib-jshint": "0.3.x",
+ "grunt-contrib-jshint": "0.6.x",
"grunt-contrib-uglify": "0.2.x",
- "grunt-contrib-connect": "0.2.x",
- "grunt-contrib-qunit": "0.2.x",
+ "grunt-contrib-connect": "0.3.x",
"grunt-contrib-yuidoc": "0.4.x",
- "grunt-contrib-concat": "0.1.x"
+ "grunt-contrib-concat": "0.3.x",
+ "chai": "~1.7.0",
+ "karma": "0.11.0",
+ "karma-firefox-launcher": "0.1.0",
+ "karma-mocha": "0.1.0"
}
}
diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js
index a7c520e..ee82bbd 100644
--- a/src/pixi/InteractionManager.js
+++ b/src/pixi/InteractionManager.js
@@ -62,7 +62,6 @@
this.onTouchEnd = this.onTouchEnd.bind(this);
this.onTouchMove = this.onTouchMove.bind(this);
-
this.last = 0;
}
diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js
index 1a95d20..eef1059 100644
--- a/src/pixi/core/Ellipse.js
+++ b/src/pixi/core/Ellipse.js
@@ -78,7 +78,7 @@
return (normx + normy < 0.25);
}
-PIXI.Ellipse.getBounds = function()
+PIXI.Ellipse.prototype.getBounds = function()
{
return new PIXI.Rectangle(this.x, this.y, this.width, this.height);
}
diff --git a/tasks/karma.js b/tasks/karma.js
new file mode 100644
index 0000000..c340485
--- /dev/null
+++ b/tasks/karma.js
@@ -0,0 +1,27 @@
+'use strict';
+
+var path = require('path');
+var server = require('karma').server;
+
+module.exports = function (grunt) {
+ grunt.registerMultiTask('karma', 'run karma.', function() {
+ var done = this.async();
+ var options = this.options({
+ background: false
+ });
+ var data = this.data;
+
+ //merge options onto data, with data taking precedence
+ data = grunt.util._.merge(options, data);
+ data.configFile = path.resolve(data.configFile);
+ if (data.configFile) {
+ data.configFile = grunt.template.process(data.configFile);
+ }
+
+ server.start(
+ data,
+ function(code) {
+ done(!code);
+ });
+ });
+};
diff --git a/test/functional/example-1-basics/bunny.png b/test/functional/example-1-basics/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/functional/example-1-basics/bunny.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-30.png b/test/functional/example-1-basics/frame-30.png
new file mode 100644
index 0000000..96e3409
--- /dev/null
+++ b/test/functional/example-1-basics/frame-30.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-60.png b/test/functional/example-1-basics/frame-60.png
new file mode 100644
index 0000000..af3f4ce
--- /dev/null
+++ b/test/functional/example-1-basics/frame-60.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-90.png b/test/functional/example-1-basics/frame-90.png
new file mode 100644
index 0000000..099b823
--- /dev/null
+++ b/test/functional/example-1-basics/frame-90.png
Binary files differ
diff --git a/test/functional/example-1-basics/index.js b/test/functional/example-1-basics/index.js
new file mode 100644
index 0000000..7ae7a98
--- /dev/null
+++ b/test/functional/example-1-basics/index.js
@@ -0,0 +1,133 @@
+describe('Example 1 - Basics', function () {
+ 'use strict';
+
+ var baseUri = '/base/test/functional/example-1-basics';
+ var expect = chai.expect;
+ var currentFrame = 0;
+ var frameEvents = {};
+ var stage;
+ var renderer;
+ var bunny;
+
+ function onFrame(frame, callback) {
+ frameEvents[frame] = callback;
+ }
+
+ function animate() {
+ currentFrame += 1;
+
+ requestAnimFrame( animate );
+
+ // just for fun, lets rotate mr rabbit a little
+ bunny.rotation += 0.1;
+
+ // render the stage
+ renderer.render(stage);
+
+ if (frameEvents[currentFrame])
+ frameEvents[currentFrame](currentFrame);
+ }
+
+ function initScene() {
+ // create an new instance of a pixi stage
+ stage = new PIXI.Stage(0x66FF99);
+
+ // create a renderer instance
+ renderer = PIXI.autoDetectRenderer(400, 300);
+ console.log('Is PIXI.WebGLRenderer: ' + (renderer instanceof PIXI.WebGLRenderer));
+
+ // add the renderer view element to the DOM
+ document.body.appendChild(renderer.view);
+
+ requestAnimFrame( animate );
+
+ // create a texture from an image path
+ var texture = PIXI.Texture.fromImage(baseUri + "/bunny.png");
+ // create a new Sprite using the texture
+ bunny = new PIXI.Sprite(texture);
+
+ // center the sprites anchor point
+ bunny.anchor.x = 0.5;
+ bunny.anchor.y = 0.5;
+
+ // move the sprite t the center of the screen
+ bunny.position.x = 200;
+ bunny.position.y = 150;
+
+ stage.addChild(bunny);
+ }
+
+ it('assets loaded', function (done) {
+ var loader = new PIXI.AssetLoader([
+ baseUri + '/bunny.png',
+ baseUri + '/frame-30.png',
+ baseUri + '/frame-60.png',
+ baseUri + '/frame-90.png'
+ ]);
+ // loader.on('onProgress', function (event) {
+ // console.log(event.content);
+ // });
+ loader.on('onComplete', function (event) {
+ done();
+ initScene();
+ });
+ loader.load();
+ });
+
+ it('frame 30 should match', function (done) {
+ this.timeout(700);
+ onFrame(30, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-30.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 60 should match', function (done) {
+ this.timeout(1200);
+ onFrame(60, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-60.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 90 should match', function (done) {
+ this.timeout(1700);
+ onFrame(90, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-90.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ // it('capture something', function (done) {
+ // this.timeout(2000000);
+ // onFrame(30, function () {
+ // var img = new Image();
+ // img.src = renderer.view.toDataURL('image/png');
+ // document.body.appendChild(img);
+ // });
+ // });
+});
diff --git a/test/index.html b/test/index.html
deleted file mode 100644
index 9cbcac5..0000000
--- a/test/index.html
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
- Pixi.js Test Suite
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/test/karma.conf.js b/test/karma.conf.js
new file mode 100644
index 0000000..c66a696
--- /dev/null
+++ b/test/karma.conf.js
@@ -0,0 +1,82 @@
+module.exports = function(config) {
+ config.set({
+
+ // base path, that will be used to resolve files and exclude
+ basePath : '../',
+
+ frameworks : ['mocha'],
+
+ // list of files / patterns to load in the browser
+ files : [
+ 'node_modules/chai/chai.js',
+ 'bin/pixi.dev.js',
+ 'test/lib/**/*.js',
+ 'test/unit/**/*.js',
+ // 'test/functional/**/*.js',
+ {pattern: 'test/**/*.png', watched: false, included: false, served: true}
+ ],
+
+ // list of files to exclude
+ exclude : [],
+
+ // use dolts reporter, as travis terminal does not support escaping sequences
+ // possible values: 'dots', 'progress', 'junit', 'teamcity'
+ // CLI --reporters progress
+ reporters : ['progress'],
+
+ // web server port
+ // CLI --port 9876
+ port : 9876,
+
+ // cli runner port
+ // CLI --runner-port 9100
+ runnerPort : 9100,
+
+ // enable / disable colors in the output (reporters and logs)
+ // CLI --colors --no-colors
+ colors : true,
+
+ // level of logging
+ // possible values: karma.LOG_DISABLE || karma.LOG_ERROR || karma.LOG_WARN || karma.LOG_INFO || karma.LOG_DEBUG
+ // CLI --log-level debug
+ logLevel : config.LOG_DEBUG,
+
+ // enable / disable watching file and executing tests whenever any file changes
+ // CLI --auto-watch --no-auto-watch
+ autoWatch : false,
+
+ // Start these browsers, currently available:
+ // - Chrome
+ // - ChromeCanary
+ // - Firefox
+ // - Opera
+ // - Safari (only Mac)
+ // - PhantomJS
+ // - IE (only Windows)
+ // CLI --browsers Chrome,Firefox,Safari
+ browsers : ['Firefox'],
+
+ // If browser does not capture in given timeout [ms], kill it
+ // CLI --capture-timeout 5000
+ captureTimeout : 5000,
+
+ // Auto run tests on start (when browsers are captured) and exit
+ // CLI --single-run --no-single-run
+ singleRun : true,
+
+ // report which specs are slower than 500ms
+ // CLI --report-slower-than 500
+ reportSlowerThan : 1000,
+
+ preprocessors : {
+ // '**/client/js/*.js': 'coverage'
+ },
+
+ plugins : [
+ 'karma-mocha',
+ // 'karma-chrome-launcher',
+ 'karma-firefox-launcher',
+ // 'karma-phantomjs-launcher'
+ ]
+ });
+};
diff --git a/test/lib/pixi/core/Matrix.js b/test/lib/pixi/core/Matrix.js
new file mode 100644
index 0000000..d26386b
--- /dev/null
+++ b/test/lib/pixi/core/Matrix.js
@@ -0,0 +1,40 @@
+
+function pixi_core_Matrix_confirmNewMat3(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(1);
+ expect(matrix[5]).to.equal(0);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(1);
+}
+
+function pixi_core_Matrix_confirmNewMat4(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[0]).to.equal(1);
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(0);
+ expect(matrix[5]).to.equal(1);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(0);
+ expect(matrix[9]).to.equal(0);
+ expect(matrix[10]).to.equal(1);
+ expect(matrix[11]).to.equal(0);
+ expect(matrix[12]).to.equal(0);
+ expect(matrix[13]).to.equal(0);
+ expect(matrix[14]).to.equal(0);
+ expect(matrix[15]).to.equal(1);
+}
diff --git a/test/lib/pixi/core/Point.js b/test/lib/pixi/core/Point.js
new file mode 100644
index 0000000..e5df07b
--- /dev/null
+++ b/test/lib/pixi/core/Point.js
@@ -0,0 +1,10 @@
+
+function pixi_core_Point_confirm(obj, x, y) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Point);
+ expect(obj).to.respondTo('clone');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+}
diff --git a/test/lib/pixi/core/Rectangle.js b/test/lib/pixi/core/Rectangle.js
new file mode 100644
index 0000000..23f0d12
--- /dev/null
+++ b/test/lib/pixi/core/Rectangle.js
@@ -0,0 +1,13 @@
+
+function pixi_core_Rectangle_confirm(obj, x, y, width, height) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Rectangle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+ expect(obj).to.have.property('width', width);
+ expect(obj).to.have.property('height', height);
+}
diff --git a/test/lib/pixi/display/DisplayObject.js b/test/lib/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..1388a7f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObject.js
@@ -0,0 +1,43 @@
+
+function pixi_display_DisplayObject_confirmNew(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObject);
+ expect(obj).to.respondTo('setInteractive');
+ expect(obj).to.respondTo('addFilter');
+ expect(obj).to.respondTo('removeFilter');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.property('last', obj);
+ expect(obj).to.have.property('first', obj);
+
+ expect(obj).to.contain.property('position');
+ pixi_core_Point_confirm(obj.position, 0, 0);
+ expect(obj).to.contain.property('scale');
+ pixi_core_Point_confirm(obj.scale, 1, 1);
+ expect(obj).to.contain.property('pivot');
+ pixi_core_Point_confirm(obj.pivot, 0, 0);
+
+ expect(obj).to.have.property('rotation', 0);
+ expect(obj).to.have.property('alpha', 1);
+ expect(obj).to.have.property('visible', true);
+ expect(obj).to.have.property('buttonMode', false);
+ expect(obj).to.have.property('parent', null);
+ expect(obj).to.have.property('worldAlpha', 1);
+
+ expect(obj).to.have.property('hitArea');
+ expect(obj).to.have.property('interactive'); // TODO: Have a better default value
+ expect('mask' in obj).to.be.true; // TODO: Have a better default value
+ expect(obj.mask).to.be.undefined;
+
+ expect(obj).to.have.property('renderable');
+ expect(obj).to.have.property('stage');
+
+ expect(obj).to.have.deep.property('worldTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ expect(obj).to.have.deep.property('localTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.localTransform);
+
+ expect(obj).to.have.deep.property('color.length', 0);
+ expect(obj).to.have.property('dynamic', true);
+}
diff --git a/test/lib/pixi/display/DisplayObjectContainer.js b/test/lib/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..085c59f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,16 @@
+
+function pixi_display_DisplayObjectContainer_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObject_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObjectContainer);
+ expect(obj).to.respondTo('addChild');
+ expect(obj).to.respondTo('addChildAt');
+ expect(obj).to.respondTo('swapChildren');
+ expect(obj).to.respondTo('getChildAt');
+ expect(obj).to.respondTo('removeChild');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('children.length', 0);
+}
diff --git a/test/lib/pixi/display/Sprite.js b/test/lib/pixi/display/Sprite.js
new file mode 100644
index 0000000..cc7a2d6
--- /dev/null
+++ b/test/lib/pixi/display/Sprite.js
@@ -0,0 +1,28 @@
+
+function pixi_display_Sprite_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Sprite);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', true);
+ expect(obj).to.have.property('stage', null);
+
+ expect(obj).to.have.property('anchor');
+ pixi_core_Point_confirm(obj.anchor, 0, 0);
+
+ expect(obj).to.have.property('blendMode', PIXI.blendModes.NORMAL);
+ expect(obj).to.have.property('width', 1); // TODO: is 1 expected
+ expect(obj).to.have.property('height', 1); // TODO: is 1 expected
+
+ // FIXME: Just make this a boolean that is always there
+ expect(!!obj.updateFrame).to.equal(obj.texture.baseTexture.hasLoaded);
+
+ expect(obj).to.have.property('texture');
+ pixi_textures_Texture_confirmNew(obj.texture, done);
+}
diff --git a/test/lib/pixi/extras/Strip.js b/test/lib/pixi/extras/Strip.js
new file mode 100644
index 0000000..8927a8a
--- /dev/null
+++ b/test/lib/pixi/extras/Strip.js
@@ -0,0 +1,12 @@
+
+function pixi_extras_Strip_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Strip);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ // TODO: Test properties
+}
diff --git a/test/lib/pixi/textures/Texture.js b/test/lib/pixi/textures/Texture.js
new file mode 100644
index 0000000..d5867b6
--- /dev/null
+++ b/test/lib/pixi/textures/Texture.js
@@ -0,0 +1,31 @@
+
+function pixi_textures_Texture_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ function confirmFrameDone() {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, obj.baseTexture.width, obj.baseTexture.height);
+
+ expect(obj).to.have.property('width', obj.baseTexture.width);
+ expect(obj).to.have.property('height', obj.baseTexture.height);
+ done();
+ }
+
+ expect(obj).to.be.an.instanceof(PIXI.Texture);
+ pixi_utils_EventTarget_like(obj);
+
+ expect(obj).to.have.property('baseTexture')
+ .and.to.be.an.instanceof(PIXI.BaseTexture);
+
+ expect(obj).to.have.property('scope', obj);
+
+ expect(obj).to.have.property('trim');
+ pixi_core_Point_confirm(obj.trim, 0, 0);
+
+ expect(obj).to.have.property('frame');
+ if (obj.baseTexture.hasLoaded) {
+ confirmFrameDone();
+ } else {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, 1, 1);
+ obj.addEventListener('update', confirmFrameDone);
+ }
+}
diff --git a/test/lib/pixi/utils/EventTarget.js b/test/lib/pixi/utils/EventTarget.js
new file mode 100644
index 0000000..7b1dcfa
--- /dev/null
+++ b/test/lib/pixi/utils/EventTarget.js
@@ -0,0 +1,8 @@
+
+function pixi_utils_EventTarget_like(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.respondTo('addEventListener');
+ expect(obj).to.respondTo('dispatchEvent');
+ expect(obj).to.respondTo('removeEventListener');
+}
diff --git a/test/lib/qunit-1.11.0.css b/test/lib/qunit-1.11.0.css
deleted file mode 100644
index d7fc0c8..0000000
--- a/test/lib/qunit-1.11.0.css
+++ /dev/null
@@ -1,244 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-/** Font Family and Sizes */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
- font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
-}
-
-#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
-#qunit-tests { font-size: smaller; }
-
-
-/** Resets */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter {
- margin: 0;
- padding: 0;
-}
-
-
-/** Header */
-
-#qunit-header {
- padding: 0.5em 0 0.5em 1em;
-
- color: #8699a4;
- background-color: #0d3349;
-
- font-size: 1.5em;
- line-height: 1em;
- font-weight: normal;
-
- border-radius: 5px 5px 0 0;
- -moz-border-radius: 5px 5px 0 0;
- -webkit-border-top-right-radius: 5px;
- -webkit-border-top-left-radius: 5px;
-}
-
-#qunit-header a {
- text-decoration: none;
- color: #c2ccd1;
-}
-
-#qunit-header a:hover,
-#qunit-header a:focus {
- color: #fff;
-}
-
-#qunit-testrunner-toolbar label {
- display: inline-block;
- padding: 0 .5em 0 .1em;
-}
-
-#qunit-banner {
- height: 5px;
-}
-
-#qunit-testrunner-toolbar {
- padding: 0.5em 0 0.5em 2em;
- color: #5E740B;
- background-color: #eee;
- overflow: hidden;
-}
-
-#qunit-userAgent {
- padding: 0.5em 0 0.5em 2.5em;
- background-color: #2b81af;
- color: #fff;
- text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
-}
-
-#qunit-modulefilter-container {
- float: right;
-}
-
-/** Tests: Pass/Fail */
-
-#qunit-tests {
- list-style-position: inside;
-}
-
-#qunit-tests li {
- padding: 0.4em 0.5em 0.4em 2.5em;
- border-bottom: 1px solid #fff;
- list-style-position: inside;
-}
-
-#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running {
- display: none;
-}
-
-#qunit-tests li strong {
- cursor: pointer;
-}
-
-#qunit-tests li a {
- padding: 0.5em;
- color: #c2ccd1;
- text-decoration: none;
-}
-#qunit-tests li a:hover,
-#qunit-tests li a:focus {
- color: #000;
-}
-
-#qunit-tests li .runtime {
- float: right;
- font-size: smaller;
-}
-
-.qunit-assert-list {
- margin-top: 0.5em;
- padding: 0.5em;
-
- background-color: #fff;
-
- border-radius: 5px;
- -moz-border-radius: 5px;
- -webkit-border-radius: 5px;
-}
-
-.qunit-collapsed {
- display: none;
-}
-
-#qunit-tests table {
- border-collapse: collapse;
- margin-top: .2em;
-}
-
-#qunit-tests th {
- text-align: right;
- vertical-align: top;
- padding: 0 .5em 0 0;
-}
-
-#qunit-tests td {
- vertical-align: top;
-}
-
-#qunit-tests pre {
- margin: 0;
- white-space: pre-wrap;
- word-wrap: break-word;
-}
-
-#qunit-tests del {
- background-color: #e0f2be;
- color: #374e0c;
- text-decoration: none;
-}
-
-#qunit-tests ins {
- background-color: #ffcaca;
- color: #500;
- text-decoration: none;
-}
-
-/*** Test Counts */
-
-#qunit-tests b.counts { color: black; }
-#qunit-tests b.passed { color: #5E740B; }
-#qunit-tests b.failed { color: #710909; }
-
-#qunit-tests li li {
- padding: 5px;
- background-color: #fff;
- border-bottom: none;
- list-style-position: inside;
-}
-
-/*** Passing Styles */
-
-#qunit-tests li li.pass {
- color: #3c510c;
- background-color: #fff;
- border-left: 10px solid #C6E746;
-}
-
-#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
-#qunit-tests .pass .test-name { color: #366097; }
-
-#qunit-tests .pass .test-actual,
-#qunit-tests .pass .test-expected { color: #999999; }
-
-#qunit-banner.qunit-pass { background-color: #C6E746; }
-
-/*** Failing Styles */
-
-#qunit-tests li li.fail {
- color: #710909;
- background-color: #fff;
- border-left: 10px solid #EE5757;
- white-space: pre;
-}
-
-#qunit-tests > li:last-child {
- border-radius: 0 0 5px 5px;
- -moz-border-radius: 0 0 5px 5px;
- -webkit-border-bottom-right-radius: 5px;
- -webkit-border-bottom-left-radius: 5px;
-}
-
-#qunit-tests .fail { color: #000000; background-color: #EE5757; }
-#qunit-tests .fail .test-name,
-#qunit-tests .fail .module-name { color: #000000; }
-
-#qunit-tests .fail .test-actual { color: #EE5757; }
-#qunit-tests .fail .test-expected { color: green; }
-
-#qunit-banner.qunit-fail { background-color: #EE5757; }
-
-
-/** Result */
-
-#qunit-testresult {
- padding: 0.5em 0.5em 0.5em 2.5em;
-
- color: #2b81af;
- background-color: #D2E0E6;
-
- border-bottom: 1px solid white;
-}
-#qunit-testresult .module-name {
- font-weight: bold;
-}
-
-/** Fixture */
-
-#qunit-fixture {
- position: absolute;
- top: -10000px;
- left: -10000px;
- width: 1000px;
- height: 1000px;
-}
diff --git a/test/lib/qunit-1.11.0.js b/test/lib/qunit-1.11.0.js
deleted file mode 100644
index 302545f..0000000
--- a/test/lib/qunit-1.11.0.js
+++ /dev/null
@@ -1,2152 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-(function( window ) {
-
-var QUnit,
- assert,
- config,
- onErrorFnPrev,
- testId = 0,
- fileName = (sourceFromStacktrace( 0 ) || "" ).replace(/(:\d+)+\)?/, "").replace(/.+\//, ""),
- toString = Object.prototype.toString,
- hasOwn = Object.prototype.hasOwnProperty,
- // Keep a local reference to Date (GH-283)
- Date = window.Date,
- defined = {
- setTimeout: typeof window.setTimeout !== "undefined",
- sessionStorage: (function() {
- var x = "qunit-test-string";
- try {
- sessionStorage.setItem( x, x );
- sessionStorage.removeItem( x );
- return true;
- } catch( e ) {
- return false;
- }
- }())
- },
- /**
- * Provides a normalized error string, correcting an issue
- * with IE 7 (and prior) where Error.prototype.toString is
- * not properly implemented
- *
- * Based on http://es5.github.com/#x15.11.4.4
- *
- * @param {String|Error} error
- * @return {String} error message
- */
- errorString = function( error ) {
- var name, message,
- errorString = error.toString();
- if ( errorString.substring( 0, 7 ) === "[object" ) {
- name = error.name ? error.name.toString() : "Error";
- message = error.message ? error.message.toString() : "";
- if ( name && message ) {
- return name + ": " + message;
- } else if ( name ) {
- return name;
- } else if ( message ) {
- return message;
- } else {
- return "Error";
- }
- } else {
- return errorString;
- }
- },
- /**
- * Makes a clone of an object using only Array or Object as base,
- * and copies over the own enumerable properties.
- *
- * @param {Object} obj
- * @return {Object} New object with only the own properties (recursively).
- */
- objectValues = function( obj ) {
- // Grunt 0.3.x uses an older version of jshint that still has jshint/jshint#392.
- /*jshint newcap: false */
- var key, val,
- vals = QUnit.is( "array", obj ) ? [] : {};
- for ( key in obj ) {
- if ( hasOwn.call( obj, key ) ) {
- val = obj[key];
- vals[key] = val === Object(val) ? objectValues(val) : val;
- }
- }
- return vals;
- };
-
-function Test( settings ) {
- extend( this, settings );
- this.assertions = [];
- this.testNumber = ++Test.count;
-}
-
-Test.count = 0;
-
-Test.prototype = {
- init: function() {
- var a, b, li,
- tests = id( "qunit-tests" );
-
- if ( tests ) {
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml;
-
- // `a` initialized at top of scope
- a = document.createElement( "a" );
- a.innerHTML = "Rerun";
- a.href = QUnit.url({ testNumber: this.testNumber });
-
- li = document.createElement( "li" );
- li.appendChild( b );
- li.appendChild( a );
- li.className = "running";
- li.id = this.id = "qunit-test-output" + testId++;
-
- tests.appendChild( li );
- }
- },
- setup: function() {
- if ( this.module !== config.previousModule ) {
- if ( config.previousModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.previousModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
- config.previousModule = this.module;
- config.moduleStats = { all: 0, bad: 0 };
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- } else if ( config.autorun ) {
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- }
-
- config.current = this;
-
- this.testEnvironment = extend({
- setup: function() {},
- teardown: function() {}
- }, this.moduleTestEnvironment );
-
- this.started = +new Date();
- runLoggingCallbacks( "testStart", QUnit, {
- name: this.testName,
- module: this.module
- });
-
- // allow utility functions to access the current test environment
- // TODO why??
- QUnit.current_testEnvironment = this.testEnvironment;
-
- if ( !config.pollution ) {
- saveGlobal();
- }
- if ( config.notrycatch ) {
- this.testEnvironment.setup.call( this.testEnvironment );
- return;
- }
- try {
- this.testEnvironment.setup.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Setup failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- },
- run: function() {
- config.current = this;
-
- var running = id( "qunit-testresult" );
-
- if ( running ) {
- running.innerHTML = "Running:
" + this.nameHtml;
- }
-
- if ( this.async ) {
- QUnit.stop();
- }
-
- this.callbackStarted = +new Date();
-
- if ( config.notrycatch ) {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- return;
- }
-
- try {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- } catch( e ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
-
- QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + " " + this.stack + ": " + ( e.message || e ), extractStacktrace( e, 0 ) );
- // else next test will carry the responsibility
- saveGlobal();
-
- // Restart the tests if they're blocking
- if ( config.blocking ) {
- QUnit.start();
- }
- }
- },
- teardown: function() {
- config.current = this;
- if ( config.notrycatch ) {
- if ( typeof this.callbackRuntime === "undefined" ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
- }
- this.testEnvironment.teardown.call( this.testEnvironment );
- return;
- } else {
- try {
- this.testEnvironment.teardown.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Teardown failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- }
- checkPollution();
- },
- finish: function() {
- config.current = this;
- if ( config.requireExpects && this.expected === null ) {
- QUnit.pushFailure( "Expected number of assertions to be defined, but expect() was not called.", this.stack );
- } else if ( this.expected !== null && this.expected !== this.assertions.length ) {
- QUnit.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack );
- } else if ( this.expected === null && !this.assertions.length ) {
- QUnit.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions.", this.stack );
- }
-
- var i, assertion, a, b, time, li, ol,
- test = this,
- good = 0,
- bad = 0,
- tests = id( "qunit-tests" );
-
- this.runtime = +new Date() - this.started;
- config.stats.all += this.assertions.length;
- config.moduleStats.all += this.assertions.length;
-
- if ( tests ) {
- ol = document.createElement( "ol" );
- ol.className = "qunit-assert-list";
-
- for ( i = 0; i < this.assertions.length; i++ ) {
- assertion = this.assertions[i];
-
- li = document.createElement( "li" );
- li.className = assertion.result ? "pass" : "fail";
- li.innerHTML = assertion.message || ( assertion.result ? "okay" : "failed" );
- ol.appendChild( li );
-
- if ( assertion.result ) {
- good++;
- } else {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
-
- // store result when possible
- if ( QUnit.config.reorder && defined.sessionStorage ) {
- if ( bad ) {
- sessionStorage.setItem( "qunit-test-" + this.module + "-" + this.testName, bad );
- } else {
- sessionStorage.removeItem( "qunit-test-" + this.module + "-" + this.testName );
- }
- }
-
- if ( bad === 0 ) {
- addClass( ol, "qunit-collapsed" );
- }
-
- // `b` initialized at top of scope
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml + " (" + bad + ", " + good + ", " + this.assertions.length + ")";
-
- addEvent(b, "click", function() {
- var next = b.parentNode.lastChild,
- collapsed = hasClass( next, "qunit-collapsed" );
- ( collapsed ? removeClass : addClass )( next, "qunit-collapsed" );
- });
-
- addEvent(b, "dblclick", function( e ) {
- var target = e && e.target ? e.target : window.event.srcElement;
- if ( target.nodeName.toLowerCase() === "span" || target.nodeName.toLowerCase() === "b" ) {
- target = target.parentNode;
- }
- if ( window.location && target.nodeName.toLowerCase() === "strong" ) {
- window.location = QUnit.url({ testNumber: test.testNumber });
- }
- });
-
- // `time` initialized at top of scope
- time = document.createElement( "span" );
- time.className = "runtime";
- time.innerHTML = this.runtime + " ms";
-
- // `li` initialized at top of scope
- li = id( this.id );
- li.className = bad ? "fail" : "pass";
- li.removeChild( li.firstChild );
- a = li.firstChild;
- li.appendChild( b );
- li.appendChild( a );
- li.appendChild( time );
- li.appendChild( ol );
-
- } else {
- for ( i = 0; i < this.assertions.length; i++ ) {
- if ( !this.assertions[i].result ) {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
- }
-
- runLoggingCallbacks( "testDone", QUnit, {
- name: this.testName,
- module: this.module,
- failed: bad,
- passed: this.assertions.length - bad,
- total: this.assertions.length,
- duration: this.runtime
- });
-
- QUnit.reset();
-
- config.current = undefined;
- },
-
- queue: function() {
- var bad,
- test = this;
-
- synchronize(function() {
- test.init();
- });
- function run() {
- // each of these can by async
- synchronize(function() {
- test.setup();
- });
- synchronize(function() {
- test.run();
- });
- synchronize(function() {
- test.teardown();
- });
- synchronize(function() {
- test.finish();
- });
- }
-
- // `bad` initialized at top of scope
- // defer when previous test run passed, if storage is available
- bad = QUnit.config.reorder && defined.sessionStorage &&
- +sessionStorage.getItem( "qunit-test-" + this.module + "-" + this.testName );
-
- if ( bad ) {
- run();
- } else {
- synchronize( run, true );
- }
- }
-};
-
-// Root QUnit object.
-// `QUnit` initialized at top of scope
-QUnit = {
-
- // call on start of module test to prepend name to all tests
- module: function( name, testEnvironment ) {
- config.currentModule = name;
- config.currentModuleTestEnvironment = testEnvironment;
- config.modules[name] = true;
- },
-
- asyncTest: function( testName, expected, callback ) {
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- QUnit.test( testName, expected, callback, true );
- },
-
- test: function( testName, expected, callback, async ) {
- var test,
- nameHtml = "" + escapeText( testName ) + "";
-
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- if ( config.currentModule ) {
- nameHtml = "" + escapeText( config.currentModule ) + ": " + nameHtml;
- }
-
- test = new Test({
- nameHtml: nameHtml,
- testName: testName,
- expected: expected,
- async: async,
- callback: callback,
- module: config.currentModule,
- moduleTestEnvironment: config.currentModuleTestEnvironment,
- stack: sourceFromStacktrace( 2 )
- });
-
- if ( !validTest( test ) ) {
- return;
- }
-
- test.queue();
- },
-
- // Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through.
- expect: function( asserts ) {
- if (arguments.length === 1) {
- config.current.expected = asserts;
- } else {
- return config.current.expected;
- }
- },
-
- start: function( count ) {
- // QUnit hasn't been initialized yet.
- // Note: RequireJS (et al) may delay onLoad
- if ( config.semaphore === undefined ) {
- QUnit.begin(function() {
- // This is triggered at the top of QUnit.load, push start() to the event loop, to allow QUnit.load to finish first
- setTimeout(function() {
- QUnit.start( count );
- });
- });
- return;
- }
-
- config.semaphore -= count || 1;
- // don't start until equal number of stop-calls
- if ( config.semaphore > 0 ) {
- return;
- }
- // ignore if start is called more often then stop
- if ( config.semaphore < 0 ) {
- config.semaphore = 0;
- QUnit.pushFailure( "Called start() while already started (QUnit.config.semaphore was 0 already)", null, sourceFromStacktrace(2) );
- return;
- }
- // A slight delay, to avoid any current callbacks
- if ( defined.setTimeout ) {
- window.setTimeout(function() {
- if ( config.semaphore > 0 ) {
- return;
- }
- if ( config.timeout ) {
- clearTimeout( config.timeout );
- }
-
- config.blocking = false;
- process( true );
- }, 13);
- } else {
- config.blocking = false;
- process( true );
- }
- },
-
- stop: function( count ) {
- config.semaphore += count || 1;
- config.blocking = true;
-
- if ( config.testTimeout && defined.setTimeout ) {
- clearTimeout( config.timeout );
- config.timeout = window.setTimeout(function() {
- QUnit.ok( false, "Test timed out" );
- config.semaphore = 1;
- QUnit.start();
- }, config.testTimeout );
- }
- }
-};
-
-// `assert` initialized at top of scope
-// Asssert helpers
-// All of these must either call QUnit.push() or manually do:
-// - runLoggingCallbacks( "log", .. );
-// - config.current.assertions.push({ .. });
-// We attach it to the QUnit object *after* we expose the public API,
-// otherwise `assert` will become a global variable in browsers (#341).
-assert = {
- /**
- * Asserts rough true-ish result.
- * @name ok
- * @function
- * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" );
- */
- ok: function( result, msg ) {
- if ( !config.current ) {
- throw new Error( "ok() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
- result = !!result;
-
- var source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: msg
- };
-
- msg = escapeText( msg || (result ? "okay" : "failed" ) );
- msg = "" + msg + "";
-
- if ( !result ) {
- source = sourceFromStacktrace( 2 );
- if ( source ) {
- details.source = source;
- msg += "Source: | " + escapeText( source ) + " |
---|
";
- }
- }
- runLoggingCallbacks( "log", QUnit, details );
- config.current.assertions.push({
- result: result,
- message: msg
- });
- },
-
- /**
- * Assert that the first two arguments are equal, with an optional message.
- * Prints out both actual and expected values.
- * @name equal
- * @function
- * @example equal( format( "Received {0} bytes.", 2), "Received 2 bytes.", "format() replaces {0} with next argument" );
- */
- equal: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected == actual, actual, expected, message );
- },
-
- /**
- * @name notEqual
- * @function
- */
- notEqual: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected != actual, actual, expected, message );
- },
-
- /**
- * @name propEqual
- * @function
- */
- propEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notPropEqual
- * @function
- */
- notPropEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name deepEqual
- * @function
- */
- deepEqual: function( actual, expected, message ) {
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notDeepEqual
- * @function
- */
- notDeepEqual: function( actual, expected, message ) {
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name strictEqual
- * @function
- */
- strictEqual: function( actual, expected, message ) {
- QUnit.push( expected === actual, actual, expected, message );
- },
-
- /**
- * @name notStrictEqual
- * @function
- */
- notStrictEqual: function( actual, expected, message ) {
- QUnit.push( expected !== actual, actual, expected, message );
- },
-
- "throws": function( block, expected, message ) {
- var actual,
- expectedOutput = expected,
- ok = false;
-
- // 'expected' is optional
- if ( typeof expected === "string" ) {
- message = expected;
- expected = null;
- }
-
- config.current.ignoreGlobalErrors = true;
- try {
- block.call( config.current.testEnvironment );
- } catch (e) {
- actual = e;
- }
- config.current.ignoreGlobalErrors = false;
-
- if ( actual ) {
- // we don't want to validate thrown error
- if ( !expected ) {
- ok = true;
- expectedOutput = null;
- // expected is a regexp
- } else if ( QUnit.objectType( expected ) === "regexp" ) {
- ok = expected.test( errorString( actual ) );
- // expected is a constructor
- } else if ( actual instanceof expected ) {
- ok = true;
- // expected is a validation function which returns true is validation passed
- } else if ( expected.call( {}, actual ) === true ) {
- expectedOutput = null;
- ok = true;
- }
-
- QUnit.push( ok, actual, expectedOutput, message );
- } else {
- QUnit.pushFailure( message, null, 'No exception was thrown.' );
- }
- }
-};
-
-/**
- * @deprecate since 1.8.0
- * Kept assertion helpers in root for backwards compatibility.
- */
-extend( QUnit, assert );
-
-/**
- * @deprecated since 1.9.0
- * Kept root "raises()" for backwards compatibility.
- * (Note that we don't introduce assert.raises).
- */
-QUnit.raises = assert[ "throws" ];
-
-/**
- * @deprecated since 1.0.0, replaced with error pushes since 1.3.0
- * Kept to avoid TypeErrors for undefined methods.
- */
-QUnit.equals = function() {
- QUnit.push( false, false, false, "QUnit.equals has been deprecated since 2009 (e88049a0), use QUnit.equal instead" );
-};
-QUnit.same = function() {
- QUnit.push( false, false, false, "QUnit.same has been deprecated since 2009 (e88049a0), use QUnit.deepEqual instead" );
-};
-
-// We want access to the constructor's prototype
-(function() {
- function F() {}
- F.prototype = QUnit;
- QUnit = new F();
- // Make F QUnit's constructor so that we can add to the prototype later
- QUnit.constructor = F;
-}());
-
-/**
- * Config object: Maintain internal state
- * Later exposed as QUnit.config
- * `config` initialized at top of scope
- */
-config = {
- // The queue of tests to run
- queue: [],
-
- // block until document ready
- blocking: true,
-
- // when enabled, show only failing tests
- // gets persisted through sessionStorage and can be changed in UI via checkbox
- hidepassed: false,
-
- // by default, run previously failed tests first
- // very useful in combination with "Hide passed tests" checked
- reorder: true,
-
- // by default, modify document.title when suite is done
- altertitle: true,
-
- // when enabled, all tests must call expect()
- requireExpects: false,
-
- // add checkboxes that are persisted in the query-string
- // when enabled, the id is set to `true` as a `QUnit.config` property
- urlConfig: [
- {
- id: "noglobals",
- label: "Check for Globals",
- tooltip: "Enabling this will test if any test introduces new properties on the `window` object. Stored as query-strings."
- },
- {
- id: "notrycatch",
- label: "No try-catch",
- tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging exceptions in IE reasonable. Stored as query-strings."
- }
- ],
-
- // Set of all modules.
- modules: {},
-
- // logging callback queues
- begin: [],
- done: [],
- log: [],
- testStart: [],
- testDone: [],
- moduleStart: [],
- moduleDone: []
-};
-
-// Export global variables, unless an 'exports' object exists,
-// in that case we assume we're in CommonJS (dealt with on the bottom of the script)
-if ( typeof exports === "undefined" ) {
- extend( window, QUnit );
-
- // Expose QUnit object
- window.QUnit = QUnit;
-}
-
-// Initialize more QUnit.config and QUnit.urlParams
-(function() {
- var i,
- location = window.location || { search: "", protocol: "file:" },
- params = location.search.slice( 1 ).split( "&" ),
- length = params.length,
- urlParams = {},
- current;
-
- if ( params[ 0 ] ) {
- for ( i = 0; i < length; i++ ) {
- current = params[ i ].split( "=" );
- current[ 0 ] = decodeURIComponent( current[ 0 ] );
- // allow just a key to turn on a flag, e.g., test.html?noglobals
- current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true;
- urlParams[ current[ 0 ] ] = current[ 1 ];
- }
- }
-
- QUnit.urlParams = urlParams;
-
- // String search anywhere in moduleName+testName
- config.filter = urlParams.filter;
-
- // Exact match of the module name
- config.module = urlParams.module;
-
- config.testNumber = parseInt( urlParams.testNumber, 10 ) || null;
-
- // Figure out if we're running the tests from a server or not
- QUnit.isLocal = location.protocol === "file:";
-}());
-
-// Extend QUnit object,
-// these after set here because they should not be exposed as global functions
-extend( QUnit, {
- assert: assert,
-
- config: config,
-
- // Initialize the configuration options
- init: function() {
- extend( config, {
- stats: { all: 0, bad: 0 },
- moduleStats: { all: 0, bad: 0 },
- started: +new Date(),
- updateRate: 1000,
- blocking: false,
- autostart: true,
- autorun: false,
- filter: "",
- queue: [],
- semaphore: 1
- });
-
- var tests, banner, result,
- qunit = id( "qunit" );
-
- if ( qunit ) {
- qunit.innerHTML =
- "" +
- "" +
- "" +
- "" +
- "
";
- }
-
- tests = id( "qunit-tests" );
- banner = id( "qunit-banner" );
- result = id( "qunit-testresult" );
-
- if ( tests ) {
- tests.innerHTML = "";
- }
-
- if ( banner ) {
- banner.className = "";
- }
-
- if ( result ) {
- result.parentNode.removeChild( result );
- }
-
- if ( tests ) {
- result = document.createElement( "p" );
- result.id = "qunit-testresult";
- result.className = "result";
- tests.parentNode.insertBefore( result, tests );
- result.innerHTML = "Running...
";
- }
- },
-
- // Resets the test setup. Useful for tests that modify the DOM.
- reset: function() {
- var fixture = id( "qunit-fixture" );
- if ( fixture ) {
- fixture.innerHTML = config.fixture;
- }
- },
-
- // Trigger an event on an element.
- // @example triggerEvent( document.body, "click" );
- triggerEvent: function( elem, type, event ) {
- if ( document.createEvent ) {
- event = document.createEvent( "MouseEvents" );
- event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView,
- 0, 0, 0, 0, 0, false, false, false, false, 0, null);
-
- elem.dispatchEvent( event );
- } else if ( elem.fireEvent ) {
- elem.fireEvent( "on" + type );
- }
- },
-
- // Safe object type checking
- is: function( type, obj ) {
- return QUnit.objectType( obj ) === type;
- },
-
- objectType: function( obj ) {
- if ( typeof obj === "undefined" ) {
- return "undefined";
- // consider: typeof null === object
- }
- if ( obj === null ) {
- return "null";
- }
-
- var match = toString.call( obj ).match(/^\[object\s(.*)\]$/),
- type = match && match[1] || "";
-
- switch ( type ) {
- case "Number":
- if ( isNaN(obj) ) {
- return "nan";
- }
- return "number";
- case "String":
- case "Boolean":
- case "Array":
- case "Date":
- case "RegExp":
- case "Function":
- return type.toLowerCase();
- }
- if ( typeof obj === "object" ) {
- return "object";
- }
- return undefined;
- },
-
- push: function( result, actual, expected, message ) {
- if ( !config.current ) {
- throw new Error( "assertion outside test context, was " + sourceFromStacktrace() );
- }
-
- var output, source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: message,
- actual: actual,
- expected: expected
- };
-
- message = escapeText( message ) || ( result ? "okay" : "failed" );
- message = "" + message + "";
- output = message;
-
- if ( !result ) {
- expected = escapeText( QUnit.jsDump.parse(expected) );
- actual = escapeText( QUnit.jsDump.parse(actual) );
- output += "Expected: | " + expected + " |
";
-
- if ( actual !== expected ) {
- output += "Result: | " + actual + " |
";
- output += "Diff: | " + QUnit.diff( expected, actual ) + " |
";
- }
-
- source = sourceFromStacktrace();
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
- }
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: !!result,
- message: output
- });
- },
-
- pushFailure: function( message, source, actual ) {
- if ( !config.current ) {
- throw new Error( "pushFailure() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
-
- var output,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: false,
- message: message
- };
-
- message = escapeText( message ) || "error";
- message = "" + message + "";
- output = message;
-
- output += "";
-
- if ( actual ) {
- output += "Result: | " + escapeText( actual ) + " |
";
- }
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: false,
- message: output
- });
- },
-
- url: function( params ) {
- params = extend( extend( {}, QUnit.urlParams ), params );
- var key,
- querystring = "?";
-
- for ( key in params ) {
- if ( !hasOwn.call( params, key ) ) {
- continue;
- }
- querystring += encodeURIComponent( key ) + "=" +
- encodeURIComponent( params[ key ] ) + "&";
- }
- return window.location.protocol + "//" + window.location.host +
- window.location.pathname + querystring.slice( 0, -1 );
- },
-
- extend: extend,
- id: id,
- addEvent: addEvent
- // load, equiv, jsDump, diff: Attached later
-});
-
-/**
- * @deprecated: Created for backwards compatibility with test runner that set the hook function
- * into QUnit.{hook}, instead of invoking it and passing the hook function.
- * QUnit.constructor is set to the empty F() above so that we can add to it's prototype here.
- * Doing this allows us to tell if the following methods have been overwritten on the actual
- * QUnit object.
- */
-extend( QUnit.constructor.prototype, {
-
- // Logging callbacks; all receive a single argument with the listed properties
- // run test/logs.html for any related changes
- begin: registerLoggingCallback( "begin" ),
-
- // done: { failed, passed, total, runtime }
- done: registerLoggingCallback( "done" ),
-
- // log: { result, actual, expected, message }
- log: registerLoggingCallback( "log" ),
-
- // testStart: { name }
- testStart: registerLoggingCallback( "testStart" ),
-
- // testDone: { name, failed, passed, total, duration }
- testDone: registerLoggingCallback( "testDone" ),
-
- // moduleStart: { name }
- moduleStart: registerLoggingCallback( "moduleStart" ),
-
- // moduleDone: { name, failed, passed, total }
- moduleDone: registerLoggingCallback( "moduleDone" )
-});
-
-if ( typeof document === "undefined" || document.readyState === "complete" ) {
- config.autorun = true;
-}
-
-QUnit.load = function() {
- runLoggingCallbacks( "begin", QUnit, {} );
-
- // Initialize the config, saving the execution queue
- var banner, filter, i, label, len, main, ol, toolbar, userAgent, val,
- urlConfigCheckboxesContainer, urlConfigCheckboxes, moduleFilter,
- numModules = 0,
- moduleFilterHtml = "",
- urlConfigHtml = "",
- oldconfig = extend( {}, config );
-
- QUnit.init();
- extend(config, oldconfig);
-
- config.blocking = false;
-
- len = config.urlConfig.length;
-
- for ( i = 0; i < len; i++ ) {
- val = config.urlConfig[i];
- if ( typeof val === "string" ) {
- val = {
- id: val,
- label: val,
- tooltip: "[no tooltip available]"
- };
- }
- config[ val.id ] = QUnit.urlParams[ val.id ];
- urlConfigHtml += "";
- }
-
- moduleFilterHtml += "";
-
- // `userAgent` initialized at top of scope
- userAgent = id( "qunit-userAgent" );
- if ( userAgent ) {
- userAgent.innerHTML = navigator.userAgent;
- }
-
- // `banner` initialized at top of scope
- banner = id( "qunit-header" );
- if ( banner ) {
- banner.innerHTML = "" + banner.innerHTML + " ";
- }
-
- // `toolbar` initialized at top of scope
- toolbar = id( "qunit-testrunner-toolbar" );
- if ( toolbar ) {
- // `filter` initialized at top of scope
- filter = document.createElement( "input" );
- filter.type = "checkbox";
- filter.id = "qunit-filter-pass";
-
- addEvent( filter, "click", function() {
- var tmp,
- ol = document.getElementById( "qunit-tests" );
-
- if ( filter.checked ) {
- ol.className = ol.className + " hidepass";
- } else {
- tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " ";
- ol.className = tmp.replace( / hidepass /, " " );
- }
- if ( defined.sessionStorage ) {
- if (filter.checked) {
- sessionStorage.setItem( "qunit-filter-passed-tests", "true" );
- } else {
- sessionStorage.removeItem( "qunit-filter-passed-tests" );
- }
- }
- });
-
- if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem( "qunit-filter-passed-tests" ) ) {
- filter.checked = true;
- // `ol` initialized at top of scope
- ol = document.getElementById( "qunit-tests" );
- ol.className = ol.className + " hidepass";
- }
- toolbar.appendChild( filter );
-
- // `label` initialized at top of scope
- label = document.createElement( "label" );
- label.setAttribute( "for", "qunit-filter-pass" );
- label.setAttribute( "title", "Only show tests and assertons that fail. Stored in sessionStorage." );
- label.innerHTML = "Hide passed tests";
- toolbar.appendChild( label );
-
- urlConfigCheckboxesContainer = document.createElement("span");
- urlConfigCheckboxesContainer.innerHTML = urlConfigHtml;
- urlConfigCheckboxes = urlConfigCheckboxesContainer.getElementsByTagName("input");
- // For oldIE support:
- // * Add handlers to the individual elements instead of the container
- // * Use "click" instead of "change"
- // * Fallback from event.target to event.srcElement
- addEvents( urlConfigCheckboxes, "click", function( event ) {
- var params = {},
- target = event.target || event.srcElement;
- params[ target.name ] = target.checked ? true : undefined;
- window.location = QUnit.url( params );
- });
- toolbar.appendChild( urlConfigCheckboxesContainer );
-
- if (numModules > 1) {
- moduleFilter = document.createElement( 'span' );
- moduleFilter.setAttribute( 'id', 'qunit-modulefilter-container' );
- moduleFilter.innerHTML = moduleFilterHtml;
- addEvent( moduleFilter.lastChild, "change", function() {
- var selectBox = moduleFilter.getElementsByTagName("select")[0],
- selectedModule = decodeURIComponent(selectBox.options[selectBox.selectedIndex].value);
-
- window.location = QUnit.url( { module: ( selectedModule === "" ) ? undefined : selectedModule } );
- });
- toolbar.appendChild(moduleFilter);
- }
- }
-
- // `main` initialized at top of scope
- main = id( "qunit-fixture" );
- if ( main ) {
- config.fixture = main.innerHTML;
- }
-
- if ( config.autostart ) {
- QUnit.start();
- }
-};
-
-addEvent( window, "load", QUnit.load );
-
-// `onErrorFnPrev` initialized at top of scope
-// Preserve other handlers
-onErrorFnPrev = window.onerror;
-
-// Cover uncaught exceptions
-// Returning true will surpress the default browser handler,
-// returning false will let it run.
-window.onerror = function ( error, filePath, linerNr ) {
- var ret = false;
- if ( onErrorFnPrev ) {
- ret = onErrorFnPrev( error, filePath, linerNr );
- }
-
- // Treat return value as window.onerror itself does,
- // Only do our handling if not surpressed.
- if ( ret !== true ) {
- if ( QUnit.config.current ) {
- if ( QUnit.config.current.ignoreGlobalErrors ) {
- return true;
- }
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- } else {
- QUnit.test( "global failure", extend( function() {
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- }, { validTest: validTest } ) );
- }
- return false;
- }
-
- return ret;
-};
-
-function done() {
- config.autorun = true;
-
- // Log the last module results
- if ( config.currentModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.currentModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
-
- var i, key,
- banner = id( "qunit-banner" ),
- tests = id( "qunit-tests" ),
- runtime = +new Date() - config.started,
- passed = config.stats.all - config.stats.bad,
- html = [
- "Tests completed in ",
- runtime,
- " milliseconds.
",
- "",
- passed,
- " assertions of ",
- config.stats.all,
- " passed, ",
- config.stats.bad,
- " failed."
- ].join( "" );
-
- if ( banner ) {
- banner.className = ( config.stats.bad ? "qunit-fail" : "qunit-pass" );
- }
-
- if ( tests ) {
- id( "qunit-testresult" ).innerHTML = html;
- }
-
- if ( config.altertitle && typeof document !== "undefined" && document.title ) {
- // show ✖ for good, ✔ for bad suite result in title
- // use escape sequences in case file gets loaded with non-utf-8-charset
- document.title = [
- ( config.stats.bad ? "\u2716" : "\u2714" ),
- document.title.replace( /^[\u2714\u2716] /i, "" )
- ].join( " " );
- }
-
- // clear own sessionStorage items if all tests passed
- if ( config.reorder && defined.sessionStorage && config.stats.bad === 0 ) {
- // `key` & `i` initialized at top of scope
- for ( i = 0; i < sessionStorage.length; i++ ) {
- key = sessionStorage.key( i++ );
- if ( key.indexOf( "qunit-test-" ) === 0 ) {
- sessionStorage.removeItem( key );
- }
- }
- }
-
- // scroll back to top to show results
- if ( window.scrollTo ) {
- window.scrollTo(0, 0);
- }
-
- runLoggingCallbacks( "done", QUnit, {
- failed: config.stats.bad,
- passed: passed,
- total: config.stats.all,
- runtime: runtime
- });
-}
-
-/** @return Boolean: true if this test should be ran */
-function validTest( test ) {
- var include,
- filter = config.filter && config.filter.toLowerCase(),
- module = config.module && config.module.toLowerCase(),
- fullName = (test.module + ": " + test.testName).toLowerCase();
-
- // Internally-generated tests are always valid
- if ( test.callback && test.callback.validTest === validTest ) {
- delete test.callback.validTest;
- return true;
- }
-
- if ( config.testNumber ) {
- return test.testNumber === config.testNumber;
- }
-
- if ( module && ( !test.module || test.module.toLowerCase() !== module ) ) {
- return false;
- }
-
- if ( !filter ) {
- return true;
- }
-
- include = filter.charAt( 0 ) !== "!";
- if ( !include ) {
- filter = filter.slice( 1 );
- }
-
- // If the filter matches, we need to honour include
- if ( fullName.indexOf( filter ) !== -1 ) {
- return include;
- }
-
- // Otherwise, do the opposite
- return !include;
-}
-
-// so far supports only Firefox, Chrome and Opera (buggy), Safari (for real exceptions)
-// Later Safari and IE10 are supposed to support error.stack as well
-// See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack
-function extractStacktrace( e, offset ) {
- offset = offset === undefined ? 3 : offset;
-
- var stack, include, i;
-
- if ( e.stacktrace ) {
- // Opera
- return e.stacktrace.split( "\n" )[ offset + 3 ];
- } else if ( e.stack ) {
- // Firefox, Chrome
- stack = e.stack.split( "\n" );
- if (/^error$/i.test( stack[0] ) ) {
- stack.shift();
- }
- if ( fileName ) {
- include = [];
- for ( i = offset; i < stack.length; i++ ) {
- if ( stack[ i ].indexOf( fileName ) !== -1 ) {
- break;
- }
- include.push( stack[ i ] );
- }
- if ( include.length ) {
- return include.join( "\n" );
- }
- }
- return stack[ offset ];
- } else if ( e.sourceURL ) {
- // Safari, PhantomJS
- // hopefully one day Safari provides actual stacktraces
- // exclude useless self-reference for generated Error objects
- if ( /qunit.js$/.test( e.sourceURL ) ) {
- return;
- }
- // for actual exceptions, this is useful
- return e.sourceURL + ":" + e.line;
- }
-}
-function sourceFromStacktrace( offset ) {
- try {
- throw new Error();
- } catch ( e ) {
- return extractStacktrace( e, offset );
- }
-}
-
-/**
- * Escape text for attribute or text content.
- */
-function escapeText( s ) {
- if ( !s ) {
- return "";
- }
- s = s + "";
- // Both single quotes and double quotes (for attributes)
- return s.replace( /['"<>&]/g, function( s ) {
- switch( s ) {
- case '\'':
- return ''';
- case '"':
- return '"';
- case '<':
- return '<';
- case '>':
- return '>';
- case '&':
- return '&';
- }
- });
-}
-
-function synchronize( callback, last ) {
- config.queue.push( callback );
-
- if ( config.autorun && !config.blocking ) {
- process( last );
- }
-}
-
-function process( last ) {
- function next() {
- process( last );
- }
- var start = new Date().getTime();
- config.depth = config.depth ? config.depth + 1 : 1;
-
- while ( config.queue.length && !config.blocking ) {
- if ( !defined.setTimeout || config.updateRate <= 0 || ( ( new Date().getTime() - start ) < config.updateRate ) ) {
- config.queue.shift()();
- } else {
- window.setTimeout( next, 13 );
- break;
- }
- }
- config.depth--;
- if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) {
- done();
- }
-}
-
-function saveGlobal() {
- config.pollution = [];
-
- if ( config.noglobals ) {
- for ( var key in window ) {
- // in Opera sometimes DOM element ids show up here, ignore them
- if ( !hasOwn.call( window, key ) || /^qunit-test-output/.test( key ) ) {
- continue;
- }
- config.pollution.push( key );
- }
- }
-}
-
-function checkPollution() {
- var newGlobals,
- deletedGlobals,
- old = config.pollution;
-
- saveGlobal();
-
- newGlobals = diff( config.pollution, old );
- if ( newGlobals.length > 0 ) {
- QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join(", ") );
- }
-
- deletedGlobals = diff( old, config.pollution );
- if ( deletedGlobals.length > 0 ) {
- QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join(", ") );
- }
-}
-
-// returns a new Array with the elements that are in a but not in b
-function diff( a, b ) {
- var i, j,
- result = a.slice();
-
- for ( i = 0; i < result.length; i++ ) {
- for ( j = 0; j < b.length; j++ ) {
- if ( result[i] === b[j] ) {
- result.splice( i, 1 );
- i--;
- break;
- }
- }
- }
- return result;
-}
-
-function extend( a, b ) {
- for ( var prop in b ) {
- if ( b[ prop ] === undefined ) {
- delete a[ prop ];
-
- // Avoid "Member not found" error in IE8 caused by setting window.constructor
- } else if ( prop !== "constructor" || a !== window ) {
- a[ prop ] = b[ prop ];
- }
- }
-
- return a;
-}
-
-/**
- * @param {HTMLElement} elem
- * @param {string} type
- * @param {Function} fn
- */
-function addEvent( elem, type, fn ) {
- // Standards-based browsers
- if ( elem.addEventListener ) {
- elem.addEventListener( type, fn, false );
- // IE
- } else {
- elem.attachEvent( "on" + type, fn );
- }
-}
-
-/**
- * @param {Array|NodeList} elems
- * @param {string} type
- * @param {Function} fn
- */
-function addEvents( elems, type, fn ) {
- var i = elems.length;
- while ( i-- ) {
- addEvent( elems[i], type, fn );
- }
-}
-
-function hasClass( elem, name ) {
- return (" " + elem.className + " ").indexOf(" " + name + " ") > -1;
-}
-
-function addClass( elem, name ) {
- if ( !hasClass( elem, name ) ) {
- elem.className += (elem.className ? " " : "") + name;
- }
-}
-
-function removeClass( elem, name ) {
- var set = " " + elem.className + " ";
- // Class name may appear multiple times
- while ( set.indexOf(" " + name + " ") > -1 ) {
- set = set.replace(" " + name + " " , " ");
- }
- // If possible, trim it for prettiness, but not neccecarily
- elem.className = window.jQuery ? jQuery.trim( set ) : ( set.trim ? set.trim() : set );
-}
-
-function id( name ) {
- return !!( typeof document !== "undefined" && document && document.getElementById ) &&
- document.getElementById( name );
-}
-
-function registerLoggingCallback( key ) {
- return function( callback ) {
- config[key].push( callback );
- };
-}
-
-// Supports deprecated method of completely overwriting logging callbacks
-function runLoggingCallbacks( key, scope, args ) {
- var i, callbacks;
- if ( QUnit.hasOwnProperty( key ) ) {
- QUnit[ key ].call(scope, args );
- } else {
- callbacks = config[ key ];
- for ( i = 0; i < callbacks.length; i++ ) {
- callbacks[ i ].call( scope, args );
- }
- }
-}
-
-// Test for equality any JavaScript type.
-// Author: Philippe Rathé
-QUnit.equiv = (function() {
-
- // Call the o related callback with the given arguments.
- function bindCallbacks( o, callbacks, args ) {
- var prop = QUnit.objectType( o );
- if ( prop ) {
- if ( QUnit.objectType( callbacks[ prop ] ) === "function" ) {
- return callbacks[ prop ].apply( callbacks, args );
- } else {
- return callbacks[ prop ]; // or undefined
- }
- }
- }
-
- // the real equiv function
- var innerEquiv,
- // stack to decide between skip/abort functions
- callers = [],
- // stack to avoiding loops from circular referencing
- parents = [],
-
- getProto = Object.getPrototypeOf || function ( obj ) {
- return obj.__proto__;
- },
- callbacks = (function () {
-
- // for string, boolean, number and null
- function useStrictEquality( b, a ) {
- /*jshint eqeqeq:false */
- if ( b instanceof a.constructor || a instanceof b.constructor ) {
- // to catch short annotaion VS 'new' annotation of a
- // declaration
- // e.g. var i = 1;
- // var j = new Number(1);
- return a == b;
- } else {
- return a === b;
- }
- }
-
- return {
- "string": useStrictEquality,
- "boolean": useStrictEquality,
- "number": useStrictEquality,
- "null": useStrictEquality,
- "undefined": useStrictEquality,
-
- "nan": function( b ) {
- return isNaN( b );
- },
-
- "date": function( b, a ) {
- return QUnit.objectType( b ) === "date" && a.valueOf() === b.valueOf();
- },
-
- "regexp": function( b, a ) {
- return QUnit.objectType( b ) === "regexp" &&
- // the regex itself
- a.source === b.source &&
- // and its modifers
- a.global === b.global &&
- // (gmi) ...
- a.ignoreCase === b.ignoreCase &&
- a.multiline === b.multiline &&
- a.sticky === b.sticky;
- },
-
- // - skip when the property is a method of an instance (OOP)
- // - abort otherwise,
- // initial === would have catch identical references anyway
- "function": function() {
- var caller = callers[callers.length - 1];
- return caller !== Object && typeof caller !== "undefined";
- },
-
- "array": function( b, a ) {
- var i, j, len, loop;
-
- // b could be an object literal here
- if ( QUnit.objectType( b ) !== "array" ) {
- return false;
- }
-
- len = a.length;
- if ( len !== b.length ) {
- // safe and faster
- return false;
- }
-
- // track reference to avoid circular references
- parents.push( a );
- for ( i = 0; i < len; i++ ) {
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- loop = true;// dont rewalk array
- }
- }
- if ( !loop && !innerEquiv(a[i], b[i]) ) {
- parents.pop();
- return false;
- }
- }
- parents.pop();
- return true;
- },
-
- "object": function( b, a ) {
- var i, j, loop,
- // Default to true
- eq = true,
- aProperties = [],
- bProperties = [];
-
- // comparing constructors is more strict than using
- // instanceof
- if ( a.constructor !== b.constructor ) {
- // Allow objects with no prototype to be equivalent to
- // objects with Object as their constructor.
- if ( !(( getProto(a) === null && getProto(b) === Object.prototype ) ||
- ( getProto(b) === null && getProto(a) === Object.prototype ) ) ) {
- return false;
- }
- }
-
- // stack constructor before traversing properties
- callers.push( a.constructor );
- // track reference to avoid circular references
- parents.push( a );
-
- for ( i in a ) { // be strict: don't ensures hasOwnProperty
- // and go deep
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- // don't go down the same path twice
- loop = true;
- }
- }
- aProperties.push(i); // collect a's properties
-
- if (!loop && !innerEquiv( a[i], b[i] ) ) {
- eq = false;
- break;
- }
- }
-
- callers.pop(); // unstack, we are done
- parents.pop();
-
- for ( i in b ) {
- bProperties.push( i ); // collect b's properties
- }
-
- // Ensures identical properties name
- return eq && innerEquiv( aProperties.sort(), bProperties.sort() );
- }
- };
- }());
-
- innerEquiv = function() { // can take multiple arguments
- var args = [].slice.apply( arguments );
- if ( args.length < 2 ) {
- return true; // end transition
- }
-
- return (function( a, b ) {
- if ( a === b ) {
- return true; // catch the most you can
- } else if ( a === null || b === null || typeof a === "undefined" ||
- typeof b === "undefined" ||
- QUnit.objectType(a) !== QUnit.objectType(b) ) {
- return false; // don't lose time with error prone cases
- } else {
- return bindCallbacks(a, callbacks, [ b, a ]);
- }
-
- // apply transition with (1..n) arguments
- }( args[0], args[1] ) && arguments.callee.apply( this, args.splice(1, args.length - 1 )) );
- };
-
- return innerEquiv;
-}());
-
-/**
- * jsDump Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com |
- * http://flesler.blogspot.com Licensed under BSD
- * (http://www.opensource.org/licenses/bsd-license.php) Date: 5/15/2008
- *
- * @projectDescription Advanced and extensible data dumping for Javascript.
- * @version 1.0.0
- * @author Ariel Flesler
- * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html}
- */
-QUnit.jsDump = (function() {
- function quote( str ) {
- return '"' + str.toString().replace( /"/g, '\\"' ) + '"';
- }
- function literal( o ) {
- return o + "";
- }
- function join( pre, arr, post ) {
- var s = jsDump.separator(),
- base = jsDump.indent(),
- inner = jsDump.indent(1);
- if ( arr.join ) {
- arr = arr.join( "," + s + inner );
- }
- if ( !arr ) {
- return pre + post;
- }
- return [ pre, inner + arr, base + post ].join(s);
- }
- function array( arr, stack ) {
- var i = arr.length, ret = new Array(i);
- this.up();
- while ( i-- ) {
- ret[i] = this.parse( arr[i] , undefined , stack);
- }
- this.down();
- return join( "[", ret, "]" );
- }
-
- var reName = /^function (\w+)/,
- jsDump = {
- // type is used mostly internally, you can fix a (custom)type in advance
- parse: function( obj, type, stack ) {
- stack = stack || [ ];
- var inStack, res,
- parser = this.parsers[ type || this.typeOf(obj) ];
-
- type = typeof parser;
- inStack = inArray( obj, stack );
-
- if ( inStack !== -1 ) {
- return "recursion(" + (inStack - stack.length) + ")";
- }
- if ( type === "function" ) {
- stack.push( obj );
- res = parser.call( this, obj, stack );
- stack.pop();
- return res;
- }
- return ( type === "string" ) ? parser : this.parsers.error;
- },
- typeOf: function( obj ) {
- var type;
- if ( obj === null ) {
- type = "null";
- } else if ( typeof obj === "undefined" ) {
- type = "undefined";
- } else if ( QUnit.is( "regexp", obj) ) {
- type = "regexp";
- } else if ( QUnit.is( "date", obj) ) {
- type = "date";
- } else if ( QUnit.is( "function", obj) ) {
- type = "function";
- } else if ( typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined" ) {
- type = "window";
- } else if ( obj.nodeType === 9 ) {
- type = "document";
- } else if ( obj.nodeType ) {
- type = "node";
- } else if (
- // native arrays
- toString.call( obj ) === "[object Array]" ||
- // NodeList objects
- ( typeof obj.length === "number" && typeof obj.item !== "undefined" && ( obj.length ? obj.item(0) === obj[0] : ( obj.item( 0 ) === null && typeof obj[0] === "undefined" ) ) )
- ) {
- type = "array";
- } else if ( obj.constructor === Error.prototype.constructor ) {
- type = "error";
- } else {
- type = typeof obj;
- }
- return type;
- },
- separator: function() {
- return this.multiline ? this.HTML ? "
" : "\n" : this.HTML ? " " : " ";
- },
- // extra can be a number, shortcut for increasing-calling-decreasing
- indent: function( extra ) {
- if ( !this.multiline ) {
- return "";
- }
- var chr = this.indentChar;
- if ( this.HTML ) {
- chr = chr.replace( /\t/g, " " ).replace( / /g, " " );
- }
- return new Array( this._depth_ + (extra||0) ).join(chr);
- },
- up: function( a ) {
- this._depth_ += a || 1;
- },
- down: function( a ) {
- this._depth_ -= a || 1;
- },
- setParser: function( name, parser ) {
- this.parsers[name] = parser;
- },
- // The next 3 are exposed so you can use them
- quote: quote,
- literal: literal,
- join: join,
- //
- _depth_: 1,
- // This is the list of parsers, to modify them, use jsDump.setParser
- parsers: {
- window: "[Window]",
- document: "[Document]",
- error: function(error) {
- return "Error(\"" + error.message + "\")";
- },
- unknown: "[Unknown]",
- "null": "null",
- "undefined": "undefined",
- "function": function( fn ) {
- var ret = "function",
- // functions never have name in IE
- name = "name" in fn ? fn.name : (reName.exec(fn) || [])[1];
-
- if ( name ) {
- ret += " " + name;
- }
- ret += "( ";
-
- ret = [ ret, QUnit.jsDump.parse( fn, "functionArgs" ), "){" ].join( "" );
- return join( ret, QUnit.jsDump.parse(fn,"functionCode" ), "}" );
- },
- array: array,
- nodelist: array,
- "arguments": array,
- object: function( map, stack ) {
- var ret = [ ], keys, key, val, i;
- QUnit.jsDump.up();
- keys = [];
- for ( key in map ) {
- keys.push( key );
- }
- keys.sort();
- for ( i = 0; i < keys.length; i++ ) {
- key = keys[ i ];
- val = map[ key ];
- ret.push( QUnit.jsDump.parse( key, "key" ) + ": " + QUnit.jsDump.parse( val, undefined, stack ) );
- }
- QUnit.jsDump.down();
- return join( "{", ret, "}" );
- },
- node: function( node ) {
- var len, i, val,
- open = QUnit.jsDump.HTML ? "<" : "<",
- close = QUnit.jsDump.HTML ? ">" : ">",
- tag = node.nodeName.toLowerCase(),
- ret = open + tag,
- attrs = node.attributes;
-
- if ( attrs ) {
- for ( i = 0, len = attrs.length; i < len; i++ ) {
- val = attrs[i].nodeValue;
- // IE6 includes all attributes in .attributes, even ones not explicitly set.
- // Those have values like undefined, null, 0, false, "" or "inherit".
- if ( val && val !== "inherit" ) {
- ret += " " + attrs[i].nodeName + "=" + QUnit.jsDump.parse( val, "attribute" );
- }
- }
- }
- ret += close;
-
- // Show content of TextNode or CDATASection
- if ( node.nodeType === 3 || node.nodeType === 4 ) {
- ret += node.nodeValue;
- }
-
- return ret + open + "/" + tag + close;
- },
- // function calls it internally, it's the arguments part of the function
- functionArgs: function( fn ) {
- var args,
- l = fn.length;
-
- if ( !l ) {
- return "";
- }
-
- args = new Array(l);
- while ( l-- ) {
- // 97 is 'a'
- args[l] = String.fromCharCode(97+l);
- }
- return " " + args.join( ", " ) + " ";
- },
- // object calls it internally, the key part of an item in a map
- key: quote,
- // function calls it internally, it's the content of the function
- functionCode: "[code]",
- // node calls it internally, it's an html attribute value
- attribute: quote,
- string: quote,
- date: quote,
- regexp: literal,
- number: literal,
- "boolean": literal
- },
- // if true, entities are escaped ( <, >, \t, space and \n )
- HTML: false,
- // indentation unit
- indentChar: " ",
- // if true, items in a collection, are separated by a \n, else just a space.
- multiline: true
- };
-
- return jsDump;
-}());
-
-// from jquery.js
-function inArray( elem, array ) {
- if ( array.indexOf ) {
- return array.indexOf( elem );
- }
-
- for ( var i = 0, length = array.length; i < length; i++ ) {
- if ( array[ i ] === elem ) {
- return i;
- }
- }
-
- return -1;
-}
-
-/*
- * Javascript Diff Algorithm
- * By John Resig (http://ejohn.org/)
- * Modified by Chu Alan "sprite"
- *
- * Released under the MIT license.
- *
- * More Info:
- * http://ejohn.org/projects/javascript-diff-algorithm/
- *
- * Usage: QUnit.diff(expected, actual)
- *
- * QUnit.diff( "the quick brown fox jumped over", "the quick fox jumps over" ) == "the quick brown fox jumped jumps over"
- */
-QUnit.diff = (function() {
- /*jshint eqeqeq:false, eqnull:true */
- function diff( o, n ) {
- var i,
- ns = {},
- os = {};
-
- for ( i = 0; i < n.length; i++ ) {
- if ( !hasOwn.call( ns, n[i] ) ) {
- ns[ n[i] ] = {
- rows: [],
- o: null
- };
- }
- ns[ n[i] ].rows.push( i );
- }
-
- for ( i = 0; i < o.length; i++ ) {
- if ( !hasOwn.call( os, o[i] ) ) {
- os[ o[i] ] = {
- rows: [],
- n: null
- };
- }
- os[ o[i] ].rows.push( i );
- }
-
- for ( i in ns ) {
- if ( !hasOwn.call( ns, i ) ) {
- continue;
- }
- if ( ns[i].rows.length === 1 && hasOwn.call( os, i ) && os[i].rows.length === 1 ) {
- n[ ns[i].rows[0] ] = {
- text: n[ ns[i].rows[0] ],
- row: os[i].rows[0]
- };
- o[ os[i].rows[0] ] = {
- text: o[ os[i].rows[0] ],
- row: ns[i].rows[0]
- };
- }
- }
-
- for ( i = 0; i < n.length - 1; i++ ) {
- if ( n[i].text != null && n[ i + 1 ].text == null && n[i].row + 1 < o.length && o[ n[i].row + 1 ].text == null &&
- n[ i + 1 ] == o[ n[i].row + 1 ] ) {
-
- n[ i + 1 ] = {
- text: n[ i + 1 ],
- row: n[i].row + 1
- };
- o[ n[i].row + 1 ] = {
- text: o[ n[i].row + 1 ],
- row: i + 1
- };
- }
- }
-
- for ( i = n.length - 1; i > 0; i-- ) {
- if ( n[i].text != null && n[ i - 1 ].text == null && n[i].row > 0 && o[ n[i].row - 1 ].text == null &&
- n[ i - 1 ] == o[ n[i].row - 1 ]) {
-
- n[ i - 1 ] = {
- text: n[ i - 1 ],
- row: n[i].row - 1
- };
- o[ n[i].row - 1 ] = {
- text: o[ n[i].row - 1 ],
- row: i - 1
- };
- }
- }
-
- return {
- o: o,
- n: n
- };
- }
-
- return function( o, n ) {
- o = o.replace( /\s+$/, "" );
- n = n.replace( /\s+$/, "" );
-
- var i, pre,
- str = "",
- out = diff( o === "" ? [] : o.split(/\s+/), n === "" ? [] : n.split(/\s+/) ),
- oSpace = o.match(/\s+/g),
- nSpace = n.match(/\s+/g);
-
- if ( oSpace == null ) {
- oSpace = [ " " ];
- }
- else {
- oSpace.push( " " );
- }
-
- if ( nSpace == null ) {
- nSpace = [ " " ];
- }
- else {
- nSpace.push( " " );
- }
-
- if ( out.n.length === 0 ) {
- for ( i = 0; i < out.o.length; i++ ) {
- str += "" + out.o[i] + oSpace[i] + "";
- }
- }
- else {
- if ( out.n[0].text == null ) {
- for ( n = 0; n < out.o.length && out.o[n].text == null; n++ ) {
- str += "" + out.o[n] + oSpace[n] + "";
- }
- }
-
- for ( i = 0; i < out.n.length; i++ ) {
- if (out.n[i].text == null) {
- str += "" + out.n[i] + nSpace[i] + "";
- }
- else {
- // `pre` initialized at top of scope
- pre = "";
-
- for ( n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++ ) {
- pre += "" + out.o[n] + oSpace[n] + "";
- }
- str += " " + out.n[i].text + nSpace[i] + pre;
- }
- }
- }
-
- return str;
- };
-}());
-
-// for CommonJS enviroments, export everything
-if ( typeof exports !== "undefined" ) {
- extend( exports, QUnit );
-}
-
-// get at whatever the global object is, like window in browsers
-}( (function() {return this;}.call()) ));
diff --git a/test/lib/require.js b/test/lib/require.js
deleted file mode 100644
index 987f865..0000000
--- a/test/lib/require.js
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- RequireJS 2.1.5 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.
- Available via the MIT or new BSD license.
- see: http://github.com/jrburke/requirejs for details
-*/
-var requirejs,require,define;
-(function(aa){function I(b){return"[object Function]"===L.call(b)}function J(b){return"[object Array]"===L.call(b)}function y(b,c){if(b){var d;for(d=0;dthis.depCount&&!this.defined){if(I(n)){if(this.events.error)try{e=i.execCb(c,n,b,e)}catch(d){a=d}else e=i.execCb(c,n,b,e);this.map.isDefine&&((b=this.module)&&void 0!==b.exports&&b.exports!==this.exports?e=b.exports:void 0===e&&this.usingExports&&(e=this.exports));if(a)return a.requireMap=this.map,a.requireModules=[this.map.id],a.requireType="define",v(this.error=
-a)}else e=n;this.exports=e;if(this.map.isDefine&&!this.ignore&&(q[c]=e,l.onResourceLoad))l.onResourceLoad(i,this.map,this.depMaps);x(c);this.defined=!0}this.defining=!1;this.defined&&!this.defineEmitted&&(this.defineEmitted=!0,this.emit("defined",this.exports),this.defineEmitComplete=!0)}}else this.fetch()}},callPlugin:function(){var a=this.map,b=a.id,d=j(a.prefix);this.depMaps.push(d);t(d,"defined",u(this,function(e){var n,d;d=this.map.name;var g=this.map.parentMap?this.map.parentMap.name:null,h=
-i.makeRequire(a.parentMap,{enableBuildCallback:!0});if(this.map.unnormalized){if(e.normalize&&(d=e.normalize(d,function(a){return c(a,g,!0)})||""),e=j(a.prefix+"!"+d,this.map.parentMap),t(e,"defined",u(this,function(a){this.init([],function(){return a},null,{enabled:!0,ignore:!0})})),d=m(p,e.id)){this.depMaps.push(e);if(this.events.error)d.on("error",u(this,function(a){this.emit("error",a)}));d.enable()}}else n=u(this,function(a){this.init([],function(){return a},null,{enabled:!0})}),n.error=u(this,
-function(a){this.inited=!0;this.error=a;a.requireModules=[b];G(p,function(a){0===a.map.id.indexOf(b+"_unnormalized")&&x(a.map.id)});v(a)}),n.fromText=u(this,function(e,c){var d=a.name,g=j(d),C=O;c&&(e=c);C&&(O=!1);r(g);s(k.config,b)&&(k.config[d]=k.config[b]);try{l.exec(e)}catch(ca){return v(B("fromtexteval","fromText eval for "+b+" failed: "+ca,ca,[b]))}C&&(O=!0);this.depMaps.push(g);i.completeLoad(d);h([d],n)}),e.load(a.name,h,n,k)}));i.enable(d,this);this.pluginMaps[d.id]=d},enable:function(){V[this.map.id]=
-this;this.enabling=this.enabled=!0;y(this.depMaps,u(this,function(a,b){var c,e;if("string"===typeof a){a=j(a,this.map.isDefine?this.map:this.map.parentMap,!1,!this.skipMap);this.depMaps[b]=a;if(c=m(N,a.id)){this.depExports[b]=c(this);return}this.depCount+=1;t(a,"defined",u(this,function(a){this.defineDep(b,a);this.check()}));this.errback&&t(a,"error",this.errback)}c=a.id;e=p[c];!s(N,c)&&(e&&!e.enabled)&&i.enable(a,this)}));G(this.pluginMaps,u(this,function(a){var b=m(p,a.id);b&&!b.enabled&&i.enable(a,
-this)}));this.enabling=!1;this.check()},on:function(a,b){var c=this.events[a];c||(c=this.events[a]=[]);c.push(b)},emit:function(a,b){y(this.events[a],function(a){a(b)});"error"===a&&delete this.events[a]}};i={config:k,contextName:b,registry:p,defined:q,urlFetched:U,defQueue:H,Module:Z,makeModuleMap:j,nextTick:l.nextTick,onError:v,configure:function(a){a.baseUrl&&"/"!==a.baseUrl.charAt(a.baseUrl.length-1)&&(a.baseUrl+="/");var b=k.pkgs,c=k.shim,e={paths:!0,config:!0,map:!0};G(a,function(a,b){e[b]?
-"map"===b?(k.map||(k.map={}),R(k[b],a,!0,!0)):R(k[b],a,!0):k[b]=a});a.shim&&(G(a.shim,function(a,b){J(a)&&(a={deps:a});if((a.exports||a.init)&&!a.exportsFn)a.exportsFn=i.makeShimExports(a);c[b]=a}),k.shim=c);a.packages&&(y(a.packages,function(a){a="string"===typeof a?{name:a}:a;b[a.name]={name:a.name,location:a.location||a.name,main:(a.main||"main").replace(ja,"").replace(ea,"")}}),k.pkgs=b);G(p,function(a,b){!a.inited&&!a.map.unnormalized&&(a.map=j(b))});if(a.deps||a.callback)i.require(a.deps||[],
-a.callback)},makeShimExports:function(a){return function(){var b;a.init&&(b=a.init.apply(aa,arguments));return b||a.exports&&ba(a.exports)}},makeRequire:function(a,f){function d(e,c,h){var g,k;f.enableBuildCallback&&(c&&I(c))&&(c.__requireJsBuild=!0);if("string"===typeof e){if(I(c))return v(B("requireargs","Invalid require call"),h);if(a&&s(N,e))return N[e](p[a.id]);if(l.get)return l.get(i,e,a,d);g=j(e,a,!1,!0);g=g.id;return!s(q,g)?v(B("notloaded",'Module name "'+g+'" has not been loaded yet for context: '+
-b+(a?"":". Use require([])"))):q[g]}L();i.nextTick(function(){L();k=r(j(null,a));k.skipMap=f.skipMap;k.init(e,c,h,{enabled:!0});D()});return d}f=f||{};R(d,{isBrowser:A,toUrl:function(b){var d,f=b.lastIndexOf("."),g=b.split("/")[0];if(-1!==f&&(!("."===g||".."===g)||1h.attachEvent.toString().indexOf("[native code"))&&!Y?(O=!0,h.attachEvent("onreadystatechange",b.onScriptLoad)):(h.addEventListener("load",b.onScriptLoad,!1),h.addEventListener("error",b.onScriptError,!1)),h.src=d,K=h,D?x.insertBefore(h,D):x.appendChild(h),K=null,h;if(da)try{importScripts(d),b.completeLoad(c)}catch(j){b.onError(B("importscripts","importScripts failed for "+c+" at "+d,j,[c]))}};A&&M(document.getElementsByTagName("script"),function(b){x||(x=
-b.parentNode);if(t=b.getAttribute("data-main"))return r.baseUrl||(E=t.split("/"),Q=E.pop(),fa=E.length?E.join("/")+"/":"./",r.baseUrl=fa,t=Q),t=t.replace(ea,""),r.deps=r.deps?r.deps.concat(t):[t],!0});define=function(b,c,d){var l,h;"string"!==typeof b&&(d=c,c=b,b=null);J(c)||(d=c,c=[]);!c.length&&I(d)&&d.length&&(d.toString().replace(la,"").replace(ma,function(b,d){c.push(d)}),c=(1===d.length?["require"]:["require","exports","module"]).concat(c));if(O){if(!(l=K))P&&"interactive"===P.readyState||M(document.getElementsByTagName("script"),
-function(b){if("interactive"===b.readyState)return P=b}),l=P;l&&(b||(b=l.getAttribute("data-requiremodule")),h=F[l.getAttribute("data-requirecontext")])}(h?h.defQueue:T).push([b,c,d])};define.amd={jQuery:!0};l.exec=function(b){return eval(b)};l(r)}})(this);
diff --git a/test/lib/resemble.js b/test/lib/resemble.js
new file mode 100644
index 0000000..1cb8c29
--- /dev/null
+++ b/test/lib/resemble.js
@@ -0,0 +1,535 @@
+/*
+Author: James Cryer
+Company: Huddle
+Last updated date: 21 Feb 2013
+URL: https://github.com/Huddle/Resemble.js
+*/
+
+(function(_this){
+ 'use strict';
+
+ _this['resemble'] = function( fileData ){
+
+ var data = {};
+ var images = [];
+ var updateCallbackArray = [];
+
+ var tolerance = { // between 0 and 255
+ red: 16,
+ green: 16,
+ blue: 16,
+ minBrightness: 16,
+ maxBrightness: 240
+ };
+
+ var ignoreAntialiasing = false;
+ var ignoreColors = false;
+
+ function triggerDataUpdate(){
+ var len = updateCallbackArray.length;
+ var i;
+ for(i=0;i tolerance.maxBrightness;
+ }
+
+ function getHue(r,g,b){
+
+ r = r / 255;
+ g = g / 255;
+ b = b / 255;
+ var max = Math.max(r, g, b), min = Math.min(r, g, b);
+ var h;
+ var d;
+
+ if (max == min){
+ h = 0; // achromatic
+ } else{
+ d = max - min;
+ switch(max){
+ case r: h = (g - b) / d + (g < b ? 6 : 0); break;
+ case g: h = (b - r) / d + 2; break;
+ case b: h = (r - g) / d + 4; break;
+ }
+ h /= 6;
+ }
+
+ return h;
+ }
+
+ function isAntialiased(sourcePix, data, cacheSet, verticalPos, horizontalPos, width){
+ var offset;
+ var targetPix;
+ var distance = 1;
+ var i;
+ var j;
+ var hasHighContrastSibling = 0;
+ var hasSiblingWithDifferentHue = 0;
+ var hasEquivilantSibling = 0;
+
+ addHueInfo(sourcePix);
+
+ for (i = distance*-1; i <= distance; i++){
+ for (j = distance*-1; j <= distance; j++){
+
+ if(i===0 && j===0){
+ // ignore source pixel
+ } else {
+
+ offset = ((verticalPos+j)*width + (horizontalPos+i)) * 4;
+ targetPix = getPixelInfo(data, offset, cacheSet);
+
+ if(targetPix === null){
+ continue;
+ }
+
+ addBrightnessInfo(targetPix);
+ addHueInfo(targetPix);
+
+ if( isContrasting(sourcePix, targetPix) ){
+ hasHighContrastSibling++;
+ }
+
+ if( isRGBSame(sourcePix,targetPix) ){
+ hasEquivilantSibling++;
+ }
+
+ if( Math.abs(targetPix.h - sourcePix.h) > 0.3 ){
+ hasSiblingWithDifferentHue++;
+ }
+
+ if( hasSiblingWithDifferentHue > 1 || hasHighContrastSibling > 1){
+ return true;
+ }
+ }
+ }
+ }
+
+ if(hasEquivilantSibling < 2){
+ return true;
+ }
+
+ return false;
+ }
+
+ function errorPixel(px, offset){
+ px[offset] = 255; //r
+ px[offset + 1] = 0; //g
+ px[offset + 2] = 255; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyPixel(px, offset, data){
+ px[offset] = data.r; //r
+ px[offset + 1] = data.g; //g
+ px[offset + 2] = data.b; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyGrayScalePixel(px, offset, data){
+ px[offset] = data.brightness; //r
+ px[offset + 1] = data.brightness; //g
+ px[offset + 2] = data.brightness; //b
+ px[offset + 3] = 255; //a
+ }
+
+
+ function getPixelInfo(data, offset, cacheSet){
+ var r;
+ var g;
+ var b;
+ var d;
+
+ if(typeof data[offset] !== 'undefined'){
+ r = data[offset];
+ g = data[offset+1];
+ b = data[offset+2];
+ d = {
+ r: r,
+ g: g,
+ b: b
+ };
+
+ return d;
+ } else {
+ return null;
+ }
+ }
+
+ function addBrightnessInfo(data){
+ data.brightness = getBrightness(data.r,data.g,data.b); // 'corrected' lightness
+ }
+
+ function addHueInfo(data){
+ data.h = getHue(data.r,data.g,data.b);
+ }
+
+ function analyseImages(img1, img2, width, height){
+
+ var hiddenCanvas = document.createElement('canvas');
+
+ var data1 = img1.data;
+ var data2 = img2.data;
+
+ hiddenCanvas.width = width;
+ hiddenCanvas.height = height;
+
+ var context = hiddenCanvas.getContext('2d');
+ var imgd = context.createImageData(width,height);
+ var targetPix = imgd.data;
+
+ var mismatchCount = 0;
+
+ var time = Date.now();
+
+ var skip;
+
+ if( (width > 1200 || height > 1200) && ignoreAntialiasing){
+ skip = 6;
+ }
+
+ loop(height, width, function(verticalPos, horizontalPos){
+
+ if(skip){ // only skip if the image isn't small
+ if(verticalPos % skip === 0 || horizontalPos % skip === 0){
+ return;
+ }
+ }
+
+ var offset = (verticalPos*width + horizontalPos) * 4;
+ var pixel1 = getPixelInfo(data1, offset, 1);
+ var pixel2 = getPixelInfo(data2, offset, 2);
+
+ if(pixel1 === null || pixel2 === null){
+ return;
+ }
+
+ if (ignoreColors){
+
+ addBrightnessInfo(pixel1);
+ addBrightnessInfo(pixel2);
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ return;
+ }
+
+ if( isRGBSimilar(pixel1, pixel2) ){
+ copyPixel(targetPix, offset, pixel2);
+
+ } else if( ignoreAntialiasing && (
+ addBrightnessInfo(pixel1), // jit pixel info augmentation looks a little weird, sorry.
+ addBrightnessInfo(pixel2),
+ isAntialiased(pixel1, data1, 1, verticalPos, horizontalPos, width) ||
+ isAntialiased(pixel2, data2, 2, verticalPos, horizontalPos, width)
+ )){
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+
+ });
+
+ data.misMatchPercentage = (mismatchCount / (height*width) * 100).toFixed(2);
+ data.analysisTime = Date.now() - time;
+
+ data.getImageDataUrl = function(text){
+ var barHeight = 0;
+
+ if(text){
+ barHeight = addLabel(text,context,hiddenCanvas);
+ }
+
+ context.putImageData(imgd, 0, barHeight);
+
+ return hiddenCanvas.toDataURL("image/png");
+ };
+ }
+
+ function addLabel(text, context, hiddenCanvas){
+ var textPadding = 2;
+
+ context.font = '12px sans-serif';
+
+ var textWidth = context.measureText(text).width + textPadding*2;
+ var barHeight = 22;
+
+ if(textWidth > hiddenCanvas.width){
+ hiddenCanvas.width = textWidth;
+ }
+
+ hiddenCanvas.height += barHeight;
+
+ context.fillStyle = "#666";
+ context.fillRect(0,0,hiddenCanvas.width,barHeight -4);
+ context.fillStyle = "#fff";
+ context.fillRect(0,barHeight -4,hiddenCanvas.width, 4);
+
+ context.fillStyle = "#fff";
+ context.textBaseline = "top";
+ context.font = '12px sans-serif';
+ context.fillText(text, textPadding, 1);
+
+ return barHeight;
+ }
+
+ function normalise(img, w, h){
+ var c;
+ var context;
+
+ if(img.height < h || img.width < w){
+ c = document.createElement('canvas');
+ c.width = w;
+ c.height = h;
+ context = c.getContext('2d');
+ context.putImageData(img, 0, 0);
+ return context.getImageData(0, 0, w, h);
+ }
+
+ return img;
+ }
+
+ function compare(one, two){
+
+ function onceWeHaveBoth(){
+ var width;
+ var height;
+ if(images.length === 2){
+ width = images[0].width > images[1].width ? images[0].width : images[1].width;
+ height = images[0].height > images[1].height ? images[0].height : images[1].height;
+
+ if( (images[0].width === images[1].width) && (images[0].height === images[1].height) ){
+ data.isSameDimensions = true;
+ } else {
+ data.isSameDimensions = false;
+ }
+
+ analyseImages( normalise(images[0],width, height), normalise(images[1],width, height), width, height);
+
+ triggerDataUpdate();
+ }
+ }
+
+ images = [];
+ loadImageData(one, onceWeHaveBoth);
+ loadImageData(two, onceWeHaveBoth);
+ }
+
+ function getCompareApi(param){
+
+ var secondFileData,
+ hasMethod = typeof param === 'function';
+
+ if( !hasMethod ){
+ // assume it's file data
+ secondFileData = param;
+ }
+
+ var self = {
+ ignoreNothing: function(){
+
+ tolerance.red = 16;
+ tolerance.green = 16;
+ tolerance.blue = 16;
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreAntialiasing: function(){
+
+ tolerance.red = 32;
+ tolerance.green = 32;
+ tolerance.blue = 32;
+ tolerance.minBrightness = 64;
+ tolerance.maxBrightness = 96;
+
+ ignoreAntialiasing = true;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreColors: function(){
+
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = true;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ onComplete: function( callback ){
+
+ updateCallbackArray.push(callback);
+
+ var wrapper = function(){
+ compare(fileData, secondFileData);
+ };
+
+ wrapper();
+
+ return getCompareApi(wrapper);
+ }
+ };
+
+ return self;
+ }
+
+ return {
+ onComplete: function( callback ){
+ updateCallbackArray.push(callback);
+ loadImageData(fileData, function(imageData, width, height){
+ parseImage(imageData.data, width, height);
+ });
+ },
+ compareTo: function(secondFileData){
+ return getCompareApi(secondFileData);
+ }
+ };
+
+ };
+}(this));
\ No newline at end of file
diff --git a/test/testsuite.js b/test/testsuite.js
deleted file mode 100644
index b486acb..0000000
--- a/test/testsuite.js
+++ /dev/null
@@ -1,36 +0,0 @@
-requirejs.config({
- baseUrl: '/test/unit/'
-});
-
-define(function(require) {
- var testModules = [
- 'Pixi',
- 'Point',
- 'Rectangle',
- 'DisplayObject',
- 'DisplayObjectContainer',
- 'Sprite',
- 'MovieClip',
- 'InteractionManager',
- 'Stage',
- 'utils/Utils',
- 'utils/EventTarget',
- 'utils/Matrix',
- 'utils/Detector',
- 'renderers/WebGLShaders',
- 'renderers/WebGLRenderer',
- 'renderers/WebGLBatch',
- 'renderers/CanvasRenderer',
- 'extras/Strip',
- 'extras/Rope',
- 'textures/BaseTexture',
- 'textures/Texture',
- 'loaders/SpriteSheetLoader',
- 'loaders/AssetLoader'
- ];
-
- // Resolve all testModules and then start the Test Runner.
- require(testModules, function() {
- QUnit.start();
- });
-});
\ No newline at end of file
diff --git a/test/textures/SpriteSheet-Aliens.png b/test/textures/SpriteSheet-Aliens.png
new file mode 100644
index 0000000..210acb1
--- /dev/null
+++ b/test/textures/SpriteSheet-Aliens.png
Binary files differ
diff --git a/test/textures/SpriteSheet-Explosion.png b/test/textures/SpriteSheet-Explosion.png
new file mode 100755
index 0000000..79e1a69
--- /dev/null
+++ b/test/textures/SpriteSheet-Explosion.png
Binary files differ
diff --git a/test/textures/bunny.png b/test/textures/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/textures/bunny.png
Binary files differ
diff --git a/test/unit/DisplayObject.js b/test/unit/DisplayObject.js
deleted file mode 100644
index 5e7e72f..0000000
--- a/test/unit/DisplayObject.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObject');
-});
diff --git a/test/unit/DisplayObjectContainer.js b/test/unit/DisplayObjectContainer.js
deleted file mode 100644
index b323959..0000000
--- a/test/unit/DisplayObjectContainer.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObjectContainer');
-});
diff --git a/test/unit/InteractionManager.js b/test/unit/InteractionManager.js
deleted file mode 100644
index e751f52..0000000
--- a/test/unit/InteractionManager.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('InteractionManager');
-});
diff --git a/test/unit/MovieClip.js b/test/unit/MovieClip.js
deleted file mode 100644
index 37d9446..0000000
--- a/test/unit/MovieClip.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('MovieClip');
-});
diff --git a/test/unit/Pixi.js b/test/unit/Pixi.js
deleted file mode 100644
index 36eee73..0000000
--- a/test/unit/Pixi.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Pixi');
-});
diff --git a/test/unit/Point.js b/test/unit/Point.js
deleted file mode 100644
index 983ff6e..0000000
--- a/test/unit/Point.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Point');
-});
diff --git a/test/unit/Rectangle.js b/test/unit/Rectangle.js
deleted file mode 100644
index 3b439ba..0000000
--- a/test/unit/Rectangle.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Rectangle');
-});
diff --git a/test/unit/Sprite.js b/test/unit/Sprite.js
deleted file mode 100644
index ed4f596..0000000
--- a/test/unit/Sprite.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Sprite');
-});
diff --git a/test/unit/Stage.js b/test/unit/Stage.js
deleted file mode 100644
index 2d70291..0000000
--- a/test/unit/Stage.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Stage');
-});
diff --git a/test/unit/extras/Rope.js b/test/unit/extras/Rope.js
deleted file mode 100644
index 5606f14..0000000
--- a/test/unit/extras/Rope.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Rope');
-});
diff --git a/test/unit/extras/Strip.js b/test/unit/extras/Strip.js
deleted file mode 100644
index 0134d3a..0000000
--- a/test/unit/extras/Strip.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Strip');
-});
diff --git a/test/unit/loaders/AssetLoader.js b/test/unit/loaders/AssetLoader.js
deleted file mode 100644
index 13b8443..0000000
--- a/test/unit/loaders/AssetLoader.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('AssetLoader');
-});
diff --git a/test/unit/loaders/SpriteSheetLoader.js b/test/unit/loaders/SpriteSheetLoader.js
deleted file mode 100644
index 8bf0cb2..0000000
--- a/test/unit/loaders/SpriteSheetLoader.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('SpriteSheetLoader');
-});
diff --git a/test/unit/pixi/InteractionManager.js b/test/unit/pixi/InteractionManager.js
new file mode 100644
index 0000000..ed3001f
--- /dev/null
+++ b/test/unit/pixi/InteractionManager.js
@@ -0,0 +1,10 @@
+describe('pixi/InteractionManager', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var InteractionManager = PIXI.InteractionManager;
+
+ it('Module exists', function () {
+ expect(InteractionManager).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/Pixi.js b/test/unit/pixi/Pixi.js
new file mode 100644
index 0000000..27debc1
--- /dev/null
+++ b/test/unit/pixi/Pixi.js
@@ -0,0 +1,9 @@
+describe('pixi/Pixi', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+
+ it('Module exists', function () {
+ expect(global).to.have.property('PIXI').and.to.be.an('object');
+ });
+});
diff --git a/test/unit/pixi/core/Circle.js b/test/unit/pixi/core/Circle.js
new file mode 100644
index 0000000..93a4456
--- /dev/null
+++ b/test/unit/pixi/core/Circle.js
@@ -0,0 +1,22 @@
+describe('pixi/core/Circle', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Circle = PIXI.Circle;
+
+ it('Module exists', function () {
+ expect(Circle).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Circle();
+
+ expect(obj).to.be.an.instanceof(Circle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', 0);
+ expect(obj).to.have.property('y', 0);
+ expect(obj).to.have.property('radius', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Ellipse.js b/test/unit/pixi/core/Ellipse.js
new file mode 100644
index 0000000..026b56f
--- /dev/null
+++ b/test/unit/pixi/core/Ellipse.js
@@ -0,0 +1,24 @@
+describe('pixi/core/Ellipse', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Ellipse = PIXI.Ellipse;
+
+ it('Module exists', function () {
+ expect(Ellipse).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Ellipse();
+
+ expect(obj).to.be.an.instanceof(Ellipse);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+ expect(obj).to.respondTo('getBounds');
+
+ expect(obj).to.have.property('x', 0);
+ expect(obj).to.have.property('y', 0);
+ expect(obj).to.have.property('width', 0);
+ expect(obj).to.have.property('height', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Matrix.js b/test/unit/pixi/core/Matrix.js
new file mode 100644
index 0000000..b48989e
--- /dev/null
+++ b/test/unit/pixi/core/Matrix.js
@@ -0,0 +1,30 @@
+describe('pixi/core/Matrix', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var mat3 = PIXI.mat3;
+ var mat4 = PIXI.mat4;
+ var Matrix = PIXI.Matrix;
+
+ it('Ensure determineMatrixArrayType works', function () {
+ expect(Matrix).to.be.a('function');
+ });
+
+ it('mat3 exists', function () {
+ expect(mat3).to.be.an('object');
+ });
+
+ it('Confirm new mat3 matrix', function () {
+ var matrix = new mat3.create();
+ pixi_core_Matrix_confirmNewMat3(matrix);
+ });
+
+ it('mat3 exists', function () {
+ expect(mat4).to.be.an('object');
+ });
+
+ it('Confirm new mat4 matrix', function () {
+ var matrix = new mat4.create();
+ pixi_core_Matrix_confirmNewMat4(matrix);
+ });
+});
diff --git a/test/unit/pixi/core/Point.js b/test/unit/pixi/core/Point.js
new file mode 100644
index 0000000..c4d5163
--- /dev/null
+++ b/test/unit/pixi/core/Point.js
@@ -0,0 +1,15 @@
+describe('pixi/core/Point', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Point = PIXI.Point;
+
+ it('Module exists', function () {
+ expect(Point).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Point();
+ pixi_core_Point_confirm(obj, 0, 0);
+ });
+});
diff --git a/test/unit/pixi/core/Polygon.js b/test/unit/pixi/core/Polygon.js
new file mode 100644
index 0000000..dc8c918
--- /dev/null
+++ b/test/unit/pixi/core/Polygon.js
@@ -0,0 +1,20 @@
+describe('pixi/core/Polygon', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Polygon = PIXI.Polygon;
+
+ it('Module exists', function () {
+ expect(Polygon).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Polygon();
+
+ expect(obj).to.be.an.instanceof(Polygon);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.deep.property('points.length', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Rectangle.js b/test/unit/pixi/core/Rectangle.js
new file mode 100644
index 0000000..d43316e
--- /dev/null
+++ b/test/unit/pixi/core/Rectangle.js
@@ -0,0 +1,15 @@
+describe('pixi/core/Rectangle', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Rectangle = PIXI.Rectangle;
+
+ it('Module exists', function () {
+ expect(Rectangle).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var rect = new Rectangle();
+ pixi_core_Rectangle_confirm(rect, 0, 0, 0, 0);
+ });
+});
diff --git a/test/unit/pixi/display/DisplayObject.js b/test/unit/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..40c6fbc
--- /dev/null
+++ b/test/unit/pixi/display/DisplayObject.js
@@ -0,0 +1,21 @@
+describe('pixi/display/DisplayObject', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var DisplayObject = PIXI.DisplayObject;
+
+ it('Module exists', function () {
+ expect(DisplayObject).to.be.a('function');
+ expect(PIXI).to.have.property('visibleCount', 0);
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new DisplayObject();
+
+ pixi_display_DisplayObject_confirmNew(obj);
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', false);
+ expect(obj).to.have.property('stage', null);
+ });
+});
diff --git a/test/unit/pixi/display/DisplayObjectContainer.js b/test/unit/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..ce7f02f
--- /dev/null
+++ b/test/unit/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,20 @@
+describe('pixi/display/DisplayObjectContainer', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var DisplayObjectContainer = PIXI.DisplayObjectContainer;
+
+ it('Module exists', function () {
+ expect(DisplayObjectContainer).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new DisplayObjectContainer();
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', false);
+ expect(obj).to.have.property('stage', null);
+ });
+});
diff --git a/test/unit/pixi/display/MovieClip.js b/test/unit/pixi/display/MovieClip.js
new file mode 100644
index 0000000..f3c6c6a
--- /dev/null
+++ b/test/unit/pixi/display/MovieClip.js
@@ -0,0 +1,33 @@
+describe('pixi/display/MovieClip', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var MovieClip = PIXI.MovieClip;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(MovieClip).to.be.a('function');
+ });
+
+ it('Confirm new instance', function (done) {
+ var texture = Texture.fromImage('/base/test/textures/SpriteSheet-Explosion.png');
+ var obj = new MovieClip([texture]);
+
+ pixi_display_Sprite_confirmNew(obj, done);
+
+ expect(obj).to.be.an.instanceof(MovieClip);
+ expect(obj).to.respondTo('stop');
+ expect(obj).to.respondTo('play');
+ expect(obj).to.respondTo('gotoAndStop');
+ expect(obj).to.respondTo('gotoAndPlay');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('textures.length', 1);
+ expect(obj).to.have.deep.property('textures[0]', texture);
+ expect(obj).to.have.property('animationSpeed', 1);
+ expect(obj).to.have.property('loop', true);
+ expect(obj).to.have.property('onComplete', null);
+ expect(obj).to.have.property('currentFrame', 0);
+ expect(obj).to.have.property('playing', false);
+ });
+});
diff --git a/test/unit/pixi/display/Sprite.js b/test/unit/pixi/display/Sprite.js
new file mode 100644
index 0000000..54e914f
--- /dev/null
+++ b/test/unit/pixi/display/Sprite.js
@@ -0,0 +1,25 @@
+describe('pixi/display/Sprite', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Sprite = PIXI.Sprite;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(Sprite).to.be.a('function');
+ expect(PIXI).to.have.deep.property('blendModes.NORMAL', 0);
+ expect(PIXI).to.have.deep.property('blendModes.SCREEN', 1);
+ });
+
+ it('Members exist', function () {
+ expect(Sprite).itself.to.respondTo('fromImage');
+ expect(Sprite).itself.to.respondTo('fromFrame');
+ });
+
+ it('Confirm new instance', function (done) {
+ var texture = Texture.fromImage('/base/test/textures/SpriteSheet-Aliens.png');
+ var obj = new Sprite(texture);
+
+ pixi_display_Sprite_confirmNew(obj, done);
+ });
+});
diff --git a/test/unit/pixi/display/Stage.js b/test/unit/pixi/display/Stage.js
new file mode 100644
index 0000000..3cc2a4d
--- /dev/null
+++ b/test/unit/pixi/display/Stage.js
@@ -0,0 +1,49 @@
+describe('pixi/display/Stage', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Stage = PIXI.Stage;
+ var InteractionManager = PIXI.InteractionManager;
+ var Rectangle = PIXI.Rectangle;
+
+ it('Module exists', function () {
+ expect(Stage).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Stage(null, true);
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(Stage);
+ expect(obj).to.respondTo('updateTransform');
+ expect(obj).to.respondTo('setBackgroundColor');
+ expect(obj).to.respondTo('getMousePosition');
+
+ // FIXME: duplicate member in DisplayObject
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ // FIXME: convert arg to bool in constructor
+ expect(obj).to.have.property('interactive', true);
+
+ expect(obj).to.have.property('interactionManager')
+ .and.to.be.an.instanceof(InteractionManager)
+ .and.to.have.property('stage', obj);
+
+ expect(obj).to.have.property('dirty', true);
+
+ expect(obj).to.have.property('stage', obj);
+
+ expect(obj).to.have.property('hitArea')
+ .and.to.be.an.instanceof(Rectangle);
+ pixi_core_Rectangle_confirm(obj.hitArea, 0, 0, 100000, 100000);
+
+ expect(obj).to.have.property('backgroundColor', 0x000000);
+ expect(obj).to.have.deep.property('backgroundColorSplit.length', 3);
+ expect(obj).to.have.deep.property('backgroundColorSplit[0]', 0);
+ expect(obj).to.have.deep.property('backgroundColorSplit[1]', 0);
+ expect(obj).to.have.deep.property('backgroundColorSplit[2]', 0);
+ expect(obj).to.have.property('backgroundColorString', '#000000');
+
+ expect(obj).to.have.property('worldVisible', true);
+ });
+});
diff --git a/test/unit/pixi/extras/CustomRenderable.js b/test/unit/pixi/extras/CustomRenderable.js
new file mode 100644
index 0000000..8d83cf0
--- /dev/null
+++ b/test/unit/pixi/extras/CustomRenderable.js
@@ -0,0 +1,21 @@
+describe('pixi/extras/CustomRenderable', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var CustomRenderable = PIXI.CustomRenderable;
+
+ it('Module exists', function () {
+ expect(CustomRenderable).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new CustomRenderable();
+
+ pixi_display_DisplayObject_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(CustomRenderable);
+ expect(obj).to.respondTo('renderCanvas');
+ expect(obj).to.respondTo('initWebGL');
+ expect(obj).to.respondTo('renderWebGL');
+ });
+});
diff --git a/test/unit/pixi/extras/Rope.js b/test/unit/pixi/extras/Rope.js
new file mode 100644
index 0000000..6ddaf83
--- /dev/null
+++ b/test/unit/pixi/extras/Rope.js
@@ -0,0 +1,26 @@
+describe('pixi/extras/Rope', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Rope = PIXI.Rope;
+ var Texture = PIXI.Texture;
+ var Point = PIXI.Point;
+
+ it('Module exists', function () {
+ expect(Rope).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var texture = Texture.fromImage('/base/test/textures/bunny.png');
+ var obj = new Rope(texture, [new Point(), new Point(5, 10), new Point(10, 20)]);
+
+ pixi_extras_Strip_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(Rope);
+ expect(obj).to.respondTo('refresh');
+ expect(obj).to.respondTo('updateTransform');
+ expect(obj).to.respondTo('setTexture');
+
+ // TODO: Test properties
+ });
+});
diff --git a/.gitignore b/.gitignore
index 12e1b62..0b88317 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
node_modules
.DS_Store
-.project
\ No newline at end of file
+.project
+*.log
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..63e4d7c
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,8 @@
+language: node_js
+node_js:
+ - 0.10
+
+before_script:
+ - npm install -g grunt-cli
+ - export DISPLAY=:99.0
+ - sh -e /etc/init.d/xvfb start
diff --git a/Gruntfile.js b/Gruntfile.js
index b083b49..103938c 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -1,10 +1,12 @@
+'use strict';
+
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-connect');
- grunt.loadNpmTasks('grunt-contrib-qunit');
grunt.loadNpmTasks('grunt-contrib-yuidoc');
+ grunt.loadTasks('tasks');
var root = 'src/pixi/',
debug = 'bin/pixi.dev.js',
@@ -79,7 +81,7 @@
},
files: {
srcBlob: '<%= dirs.src %>/**/*.js',
- testBlob: '<%= dirs.test %>/unit/**/*.js',
+ testBlob: '<%= dirs.test %>/{functional,lib/pixi,unit}/**/*.js',
build: '<%= dirs.build %>/pixi.dev.js',
buildMin: '<%= dirs.build %>/pixi.js'
},
@@ -94,7 +96,12 @@
},
jshint: {
beforeconcat: srcFiles,
- test: ['<%= files.testBlob %>'],
+ test: {
+ src: ['<%= files.testBlob %>'],
+ options: {
+ expr: true
+ }
+ },
options: {
asi: true,
smarttabs: true
@@ -128,12 +135,6 @@
]
},
connect: {
- qunit: {
- options: {
- port: grunt.option('port-test') || 9002,
- base: './'
- }
- },
test: {
options: {
port: grunt.option('port-test') || 9002,
@@ -142,13 +143,6 @@
}
}
},
- qunit: {
- all: {
- options: {
- urls: ['http://localhost:' + (grunt.option('port-test') || 9002) + '/test/index.html']
- }
- }
- },
yuidoc: {
compile: {
name: '<%= pkg.name %>',
@@ -161,6 +155,13 @@
outdir: '<%= dirs.docs %>'
}
}
+ },
+ karma: {
+ unit: {
+ configFile: 'test/karma.conf.js',
+ // browsers: ['Chrome'],
+ singleRun: true
+ }
}
});
@@ -182,9 +183,10 @@
}
)
- grunt.registerTask('default', ['concat', 'uglify', 'distribute']);
grunt.registerTask('build', ['concat', 'uglify', 'distribute']);
- grunt.registerTask('test', ['build', 'connect:qunit', 'qunit']);
+ grunt.registerTask('test', ['concat', 'jshint:test', 'karma']);
grunt.registerTask('docs', ['yuidoc']);
-
-}
\ No newline at end of file
+ grunt.registerTask('default', ['test', 'uglify', 'distribute']);
+ // Travis CI task.
+ grunt.registerTask('travis', ['test']);
+}
diff --git a/README.md b/README.md
index c62ef86..690cfe4 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,8 @@

+[](http://travis-ci.org/drkibitz/pixi.js)
+
#### JavaScript 2D Renderer ####
The aim of this project is to provide a fast lightweight 2D library that works
diff --git a/package.json b/package.json
index b373240..1246a68 100644
--- a/package.json
+++ b/package.json
@@ -18,14 +18,21 @@
"main": "bin/pixi.js",
+ "scripts": {
+ "test": "grunt travis --verbose"
+ },
+
"dependencies": {},
"devDependencies": {
"grunt": "~0.4.x",
- "grunt-contrib-jshint": "0.3.x",
+ "grunt-contrib-jshint": "0.6.x",
"grunt-contrib-uglify": "0.2.x",
- "grunt-contrib-connect": "0.2.x",
- "grunt-contrib-qunit": "0.2.x",
+ "grunt-contrib-connect": "0.3.x",
"grunt-contrib-yuidoc": "0.4.x",
- "grunt-contrib-concat": "0.1.x"
+ "grunt-contrib-concat": "0.3.x",
+ "chai": "~1.7.0",
+ "karma": "0.11.0",
+ "karma-firefox-launcher": "0.1.0",
+ "karma-mocha": "0.1.0"
}
}
diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js
index a7c520e..ee82bbd 100644
--- a/src/pixi/InteractionManager.js
+++ b/src/pixi/InteractionManager.js
@@ -62,7 +62,6 @@
this.onTouchEnd = this.onTouchEnd.bind(this);
this.onTouchMove = this.onTouchMove.bind(this);
-
this.last = 0;
}
diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js
index 1a95d20..eef1059 100644
--- a/src/pixi/core/Ellipse.js
+++ b/src/pixi/core/Ellipse.js
@@ -78,7 +78,7 @@
return (normx + normy < 0.25);
}
-PIXI.Ellipse.getBounds = function()
+PIXI.Ellipse.prototype.getBounds = function()
{
return new PIXI.Rectangle(this.x, this.y, this.width, this.height);
}
diff --git a/tasks/karma.js b/tasks/karma.js
new file mode 100644
index 0000000..c340485
--- /dev/null
+++ b/tasks/karma.js
@@ -0,0 +1,27 @@
+'use strict';
+
+var path = require('path');
+var server = require('karma').server;
+
+module.exports = function (grunt) {
+ grunt.registerMultiTask('karma', 'run karma.', function() {
+ var done = this.async();
+ var options = this.options({
+ background: false
+ });
+ var data = this.data;
+
+ //merge options onto data, with data taking precedence
+ data = grunt.util._.merge(options, data);
+ data.configFile = path.resolve(data.configFile);
+ if (data.configFile) {
+ data.configFile = grunt.template.process(data.configFile);
+ }
+
+ server.start(
+ data,
+ function(code) {
+ done(!code);
+ });
+ });
+};
diff --git a/test/functional/example-1-basics/bunny.png b/test/functional/example-1-basics/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/functional/example-1-basics/bunny.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-30.png b/test/functional/example-1-basics/frame-30.png
new file mode 100644
index 0000000..96e3409
--- /dev/null
+++ b/test/functional/example-1-basics/frame-30.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-60.png b/test/functional/example-1-basics/frame-60.png
new file mode 100644
index 0000000..af3f4ce
--- /dev/null
+++ b/test/functional/example-1-basics/frame-60.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-90.png b/test/functional/example-1-basics/frame-90.png
new file mode 100644
index 0000000..099b823
--- /dev/null
+++ b/test/functional/example-1-basics/frame-90.png
Binary files differ
diff --git a/test/functional/example-1-basics/index.js b/test/functional/example-1-basics/index.js
new file mode 100644
index 0000000..7ae7a98
--- /dev/null
+++ b/test/functional/example-1-basics/index.js
@@ -0,0 +1,133 @@
+describe('Example 1 - Basics', function () {
+ 'use strict';
+
+ var baseUri = '/base/test/functional/example-1-basics';
+ var expect = chai.expect;
+ var currentFrame = 0;
+ var frameEvents = {};
+ var stage;
+ var renderer;
+ var bunny;
+
+ function onFrame(frame, callback) {
+ frameEvents[frame] = callback;
+ }
+
+ function animate() {
+ currentFrame += 1;
+
+ requestAnimFrame( animate );
+
+ // just for fun, lets rotate mr rabbit a little
+ bunny.rotation += 0.1;
+
+ // render the stage
+ renderer.render(stage);
+
+ if (frameEvents[currentFrame])
+ frameEvents[currentFrame](currentFrame);
+ }
+
+ function initScene() {
+ // create an new instance of a pixi stage
+ stage = new PIXI.Stage(0x66FF99);
+
+ // create a renderer instance
+ renderer = PIXI.autoDetectRenderer(400, 300);
+ console.log('Is PIXI.WebGLRenderer: ' + (renderer instanceof PIXI.WebGLRenderer));
+
+ // add the renderer view element to the DOM
+ document.body.appendChild(renderer.view);
+
+ requestAnimFrame( animate );
+
+ // create a texture from an image path
+ var texture = PIXI.Texture.fromImage(baseUri + "/bunny.png");
+ // create a new Sprite using the texture
+ bunny = new PIXI.Sprite(texture);
+
+ // center the sprites anchor point
+ bunny.anchor.x = 0.5;
+ bunny.anchor.y = 0.5;
+
+ // move the sprite t the center of the screen
+ bunny.position.x = 200;
+ bunny.position.y = 150;
+
+ stage.addChild(bunny);
+ }
+
+ it('assets loaded', function (done) {
+ var loader = new PIXI.AssetLoader([
+ baseUri + '/bunny.png',
+ baseUri + '/frame-30.png',
+ baseUri + '/frame-60.png',
+ baseUri + '/frame-90.png'
+ ]);
+ // loader.on('onProgress', function (event) {
+ // console.log(event.content);
+ // });
+ loader.on('onComplete', function (event) {
+ done();
+ initScene();
+ });
+ loader.load();
+ });
+
+ it('frame 30 should match', function (done) {
+ this.timeout(700);
+ onFrame(30, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-30.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 60 should match', function (done) {
+ this.timeout(1200);
+ onFrame(60, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-60.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 90 should match', function (done) {
+ this.timeout(1700);
+ onFrame(90, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-90.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ // it('capture something', function (done) {
+ // this.timeout(2000000);
+ // onFrame(30, function () {
+ // var img = new Image();
+ // img.src = renderer.view.toDataURL('image/png');
+ // document.body.appendChild(img);
+ // });
+ // });
+});
diff --git a/test/index.html b/test/index.html
deleted file mode 100644
index 9cbcac5..0000000
--- a/test/index.html
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
- Pixi.js Test Suite
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/test/karma.conf.js b/test/karma.conf.js
new file mode 100644
index 0000000..c66a696
--- /dev/null
+++ b/test/karma.conf.js
@@ -0,0 +1,82 @@
+module.exports = function(config) {
+ config.set({
+
+ // base path, that will be used to resolve files and exclude
+ basePath : '../',
+
+ frameworks : ['mocha'],
+
+ // list of files / patterns to load in the browser
+ files : [
+ 'node_modules/chai/chai.js',
+ 'bin/pixi.dev.js',
+ 'test/lib/**/*.js',
+ 'test/unit/**/*.js',
+ // 'test/functional/**/*.js',
+ {pattern: 'test/**/*.png', watched: false, included: false, served: true}
+ ],
+
+ // list of files to exclude
+ exclude : [],
+
+ // use dolts reporter, as travis terminal does not support escaping sequences
+ // possible values: 'dots', 'progress', 'junit', 'teamcity'
+ // CLI --reporters progress
+ reporters : ['progress'],
+
+ // web server port
+ // CLI --port 9876
+ port : 9876,
+
+ // cli runner port
+ // CLI --runner-port 9100
+ runnerPort : 9100,
+
+ // enable / disable colors in the output (reporters and logs)
+ // CLI --colors --no-colors
+ colors : true,
+
+ // level of logging
+ // possible values: karma.LOG_DISABLE || karma.LOG_ERROR || karma.LOG_WARN || karma.LOG_INFO || karma.LOG_DEBUG
+ // CLI --log-level debug
+ logLevel : config.LOG_DEBUG,
+
+ // enable / disable watching file and executing tests whenever any file changes
+ // CLI --auto-watch --no-auto-watch
+ autoWatch : false,
+
+ // Start these browsers, currently available:
+ // - Chrome
+ // - ChromeCanary
+ // - Firefox
+ // - Opera
+ // - Safari (only Mac)
+ // - PhantomJS
+ // - IE (only Windows)
+ // CLI --browsers Chrome,Firefox,Safari
+ browsers : ['Firefox'],
+
+ // If browser does not capture in given timeout [ms], kill it
+ // CLI --capture-timeout 5000
+ captureTimeout : 5000,
+
+ // Auto run tests on start (when browsers are captured) and exit
+ // CLI --single-run --no-single-run
+ singleRun : true,
+
+ // report which specs are slower than 500ms
+ // CLI --report-slower-than 500
+ reportSlowerThan : 1000,
+
+ preprocessors : {
+ // '**/client/js/*.js': 'coverage'
+ },
+
+ plugins : [
+ 'karma-mocha',
+ // 'karma-chrome-launcher',
+ 'karma-firefox-launcher',
+ // 'karma-phantomjs-launcher'
+ ]
+ });
+};
diff --git a/test/lib/pixi/core/Matrix.js b/test/lib/pixi/core/Matrix.js
new file mode 100644
index 0000000..d26386b
--- /dev/null
+++ b/test/lib/pixi/core/Matrix.js
@@ -0,0 +1,40 @@
+
+function pixi_core_Matrix_confirmNewMat3(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(1);
+ expect(matrix[5]).to.equal(0);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(1);
+}
+
+function pixi_core_Matrix_confirmNewMat4(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[0]).to.equal(1);
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(0);
+ expect(matrix[5]).to.equal(1);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(0);
+ expect(matrix[9]).to.equal(0);
+ expect(matrix[10]).to.equal(1);
+ expect(matrix[11]).to.equal(0);
+ expect(matrix[12]).to.equal(0);
+ expect(matrix[13]).to.equal(0);
+ expect(matrix[14]).to.equal(0);
+ expect(matrix[15]).to.equal(1);
+}
diff --git a/test/lib/pixi/core/Point.js b/test/lib/pixi/core/Point.js
new file mode 100644
index 0000000..e5df07b
--- /dev/null
+++ b/test/lib/pixi/core/Point.js
@@ -0,0 +1,10 @@
+
+function pixi_core_Point_confirm(obj, x, y) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Point);
+ expect(obj).to.respondTo('clone');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+}
diff --git a/test/lib/pixi/core/Rectangle.js b/test/lib/pixi/core/Rectangle.js
new file mode 100644
index 0000000..23f0d12
--- /dev/null
+++ b/test/lib/pixi/core/Rectangle.js
@@ -0,0 +1,13 @@
+
+function pixi_core_Rectangle_confirm(obj, x, y, width, height) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Rectangle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+ expect(obj).to.have.property('width', width);
+ expect(obj).to.have.property('height', height);
+}
diff --git a/test/lib/pixi/display/DisplayObject.js b/test/lib/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..1388a7f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObject.js
@@ -0,0 +1,43 @@
+
+function pixi_display_DisplayObject_confirmNew(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObject);
+ expect(obj).to.respondTo('setInteractive');
+ expect(obj).to.respondTo('addFilter');
+ expect(obj).to.respondTo('removeFilter');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.property('last', obj);
+ expect(obj).to.have.property('first', obj);
+
+ expect(obj).to.contain.property('position');
+ pixi_core_Point_confirm(obj.position, 0, 0);
+ expect(obj).to.contain.property('scale');
+ pixi_core_Point_confirm(obj.scale, 1, 1);
+ expect(obj).to.contain.property('pivot');
+ pixi_core_Point_confirm(obj.pivot, 0, 0);
+
+ expect(obj).to.have.property('rotation', 0);
+ expect(obj).to.have.property('alpha', 1);
+ expect(obj).to.have.property('visible', true);
+ expect(obj).to.have.property('buttonMode', false);
+ expect(obj).to.have.property('parent', null);
+ expect(obj).to.have.property('worldAlpha', 1);
+
+ expect(obj).to.have.property('hitArea');
+ expect(obj).to.have.property('interactive'); // TODO: Have a better default value
+ expect('mask' in obj).to.be.true; // TODO: Have a better default value
+ expect(obj.mask).to.be.undefined;
+
+ expect(obj).to.have.property('renderable');
+ expect(obj).to.have.property('stage');
+
+ expect(obj).to.have.deep.property('worldTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ expect(obj).to.have.deep.property('localTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.localTransform);
+
+ expect(obj).to.have.deep.property('color.length', 0);
+ expect(obj).to.have.property('dynamic', true);
+}
diff --git a/test/lib/pixi/display/DisplayObjectContainer.js b/test/lib/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..085c59f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,16 @@
+
+function pixi_display_DisplayObjectContainer_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObject_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObjectContainer);
+ expect(obj).to.respondTo('addChild');
+ expect(obj).to.respondTo('addChildAt');
+ expect(obj).to.respondTo('swapChildren');
+ expect(obj).to.respondTo('getChildAt');
+ expect(obj).to.respondTo('removeChild');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('children.length', 0);
+}
diff --git a/test/lib/pixi/display/Sprite.js b/test/lib/pixi/display/Sprite.js
new file mode 100644
index 0000000..cc7a2d6
--- /dev/null
+++ b/test/lib/pixi/display/Sprite.js
@@ -0,0 +1,28 @@
+
+function pixi_display_Sprite_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Sprite);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', true);
+ expect(obj).to.have.property('stage', null);
+
+ expect(obj).to.have.property('anchor');
+ pixi_core_Point_confirm(obj.anchor, 0, 0);
+
+ expect(obj).to.have.property('blendMode', PIXI.blendModes.NORMAL);
+ expect(obj).to.have.property('width', 1); // TODO: is 1 expected
+ expect(obj).to.have.property('height', 1); // TODO: is 1 expected
+
+ // FIXME: Just make this a boolean that is always there
+ expect(!!obj.updateFrame).to.equal(obj.texture.baseTexture.hasLoaded);
+
+ expect(obj).to.have.property('texture');
+ pixi_textures_Texture_confirmNew(obj.texture, done);
+}
diff --git a/test/lib/pixi/extras/Strip.js b/test/lib/pixi/extras/Strip.js
new file mode 100644
index 0000000..8927a8a
--- /dev/null
+++ b/test/lib/pixi/extras/Strip.js
@@ -0,0 +1,12 @@
+
+function pixi_extras_Strip_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Strip);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ // TODO: Test properties
+}
diff --git a/test/lib/pixi/textures/Texture.js b/test/lib/pixi/textures/Texture.js
new file mode 100644
index 0000000..d5867b6
--- /dev/null
+++ b/test/lib/pixi/textures/Texture.js
@@ -0,0 +1,31 @@
+
+function pixi_textures_Texture_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ function confirmFrameDone() {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, obj.baseTexture.width, obj.baseTexture.height);
+
+ expect(obj).to.have.property('width', obj.baseTexture.width);
+ expect(obj).to.have.property('height', obj.baseTexture.height);
+ done();
+ }
+
+ expect(obj).to.be.an.instanceof(PIXI.Texture);
+ pixi_utils_EventTarget_like(obj);
+
+ expect(obj).to.have.property('baseTexture')
+ .and.to.be.an.instanceof(PIXI.BaseTexture);
+
+ expect(obj).to.have.property('scope', obj);
+
+ expect(obj).to.have.property('trim');
+ pixi_core_Point_confirm(obj.trim, 0, 0);
+
+ expect(obj).to.have.property('frame');
+ if (obj.baseTexture.hasLoaded) {
+ confirmFrameDone();
+ } else {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, 1, 1);
+ obj.addEventListener('update', confirmFrameDone);
+ }
+}
diff --git a/test/lib/pixi/utils/EventTarget.js b/test/lib/pixi/utils/EventTarget.js
new file mode 100644
index 0000000..7b1dcfa
--- /dev/null
+++ b/test/lib/pixi/utils/EventTarget.js
@@ -0,0 +1,8 @@
+
+function pixi_utils_EventTarget_like(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.respondTo('addEventListener');
+ expect(obj).to.respondTo('dispatchEvent');
+ expect(obj).to.respondTo('removeEventListener');
+}
diff --git a/test/lib/qunit-1.11.0.css b/test/lib/qunit-1.11.0.css
deleted file mode 100644
index d7fc0c8..0000000
--- a/test/lib/qunit-1.11.0.css
+++ /dev/null
@@ -1,244 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-/** Font Family and Sizes */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
- font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
-}
-
-#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
-#qunit-tests { font-size: smaller; }
-
-
-/** Resets */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter {
- margin: 0;
- padding: 0;
-}
-
-
-/** Header */
-
-#qunit-header {
- padding: 0.5em 0 0.5em 1em;
-
- color: #8699a4;
- background-color: #0d3349;
-
- font-size: 1.5em;
- line-height: 1em;
- font-weight: normal;
-
- border-radius: 5px 5px 0 0;
- -moz-border-radius: 5px 5px 0 0;
- -webkit-border-top-right-radius: 5px;
- -webkit-border-top-left-radius: 5px;
-}
-
-#qunit-header a {
- text-decoration: none;
- color: #c2ccd1;
-}
-
-#qunit-header a:hover,
-#qunit-header a:focus {
- color: #fff;
-}
-
-#qunit-testrunner-toolbar label {
- display: inline-block;
- padding: 0 .5em 0 .1em;
-}
-
-#qunit-banner {
- height: 5px;
-}
-
-#qunit-testrunner-toolbar {
- padding: 0.5em 0 0.5em 2em;
- color: #5E740B;
- background-color: #eee;
- overflow: hidden;
-}
-
-#qunit-userAgent {
- padding: 0.5em 0 0.5em 2.5em;
- background-color: #2b81af;
- color: #fff;
- text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
-}
-
-#qunit-modulefilter-container {
- float: right;
-}
-
-/** Tests: Pass/Fail */
-
-#qunit-tests {
- list-style-position: inside;
-}
-
-#qunit-tests li {
- padding: 0.4em 0.5em 0.4em 2.5em;
- border-bottom: 1px solid #fff;
- list-style-position: inside;
-}
-
-#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running {
- display: none;
-}
-
-#qunit-tests li strong {
- cursor: pointer;
-}
-
-#qunit-tests li a {
- padding: 0.5em;
- color: #c2ccd1;
- text-decoration: none;
-}
-#qunit-tests li a:hover,
-#qunit-tests li a:focus {
- color: #000;
-}
-
-#qunit-tests li .runtime {
- float: right;
- font-size: smaller;
-}
-
-.qunit-assert-list {
- margin-top: 0.5em;
- padding: 0.5em;
-
- background-color: #fff;
-
- border-radius: 5px;
- -moz-border-radius: 5px;
- -webkit-border-radius: 5px;
-}
-
-.qunit-collapsed {
- display: none;
-}
-
-#qunit-tests table {
- border-collapse: collapse;
- margin-top: .2em;
-}
-
-#qunit-tests th {
- text-align: right;
- vertical-align: top;
- padding: 0 .5em 0 0;
-}
-
-#qunit-tests td {
- vertical-align: top;
-}
-
-#qunit-tests pre {
- margin: 0;
- white-space: pre-wrap;
- word-wrap: break-word;
-}
-
-#qunit-tests del {
- background-color: #e0f2be;
- color: #374e0c;
- text-decoration: none;
-}
-
-#qunit-tests ins {
- background-color: #ffcaca;
- color: #500;
- text-decoration: none;
-}
-
-/*** Test Counts */
-
-#qunit-tests b.counts { color: black; }
-#qunit-tests b.passed { color: #5E740B; }
-#qunit-tests b.failed { color: #710909; }
-
-#qunit-tests li li {
- padding: 5px;
- background-color: #fff;
- border-bottom: none;
- list-style-position: inside;
-}
-
-/*** Passing Styles */
-
-#qunit-tests li li.pass {
- color: #3c510c;
- background-color: #fff;
- border-left: 10px solid #C6E746;
-}
-
-#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
-#qunit-tests .pass .test-name { color: #366097; }
-
-#qunit-tests .pass .test-actual,
-#qunit-tests .pass .test-expected { color: #999999; }
-
-#qunit-banner.qunit-pass { background-color: #C6E746; }
-
-/*** Failing Styles */
-
-#qunit-tests li li.fail {
- color: #710909;
- background-color: #fff;
- border-left: 10px solid #EE5757;
- white-space: pre;
-}
-
-#qunit-tests > li:last-child {
- border-radius: 0 0 5px 5px;
- -moz-border-radius: 0 0 5px 5px;
- -webkit-border-bottom-right-radius: 5px;
- -webkit-border-bottom-left-radius: 5px;
-}
-
-#qunit-tests .fail { color: #000000; background-color: #EE5757; }
-#qunit-tests .fail .test-name,
-#qunit-tests .fail .module-name { color: #000000; }
-
-#qunit-tests .fail .test-actual { color: #EE5757; }
-#qunit-tests .fail .test-expected { color: green; }
-
-#qunit-banner.qunit-fail { background-color: #EE5757; }
-
-
-/** Result */
-
-#qunit-testresult {
- padding: 0.5em 0.5em 0.5em 2.5em;
-
- color: #2b81af;
- background-color: #D2E0E6;
-
- border-bottom: 1px solid white;
-}
-#qunit-testresult .module-name {
- font-weight: bold;
-}
-
-/** Fixture */
-
-#qunit-fixture {
- position: absolute;
- top: -10000px;
- left: -10000px;
- width: 1000px;
- height: 1000px;
-}
diff --git a/test/lib/qunit-1.11.0.js b/test/lib/qunit-1.11.0.js
deleted file mode 100644
index 302545f..0000000
--- a/test/lib/qunit-1.11.0.js
+++ /dev/null
@@ -1,2152 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-(function( window ) {
-
-var QUnit,
- assert,
- config,
- onErrorFnPrev,
- testId = 0,
- fileName = (sourceFromStacktrace( 0 ) || "" ).replace(/(:\d+)+\)?/, "").replace(/.+\//, ""),
- toString = Object.prototype.toString,
- hasOwn = Object.prototype.hasOwnProperty,
- // Keep a local reference to Date (GH-283)
- Date = window.Date,
- defined = {
- setTimeout: typeof window.setTimeout !== "undefined",
- sessionStorage: (function() {
- var x = "qunit-test-string";
- try {
- sessionStorage.setItem( x, x );
- sessionStorage.removeItem( x );
- return true;
- } catch( e ) {
- return false;
- }
- }())
- },
- /**
- * Provides a normalized error string, correcting an issue
- * with IE 7 (and prior) where Error.prototype.toString is
- * not properly implemented
- *
- * Based on http://es5.github.com/#x15.11.4.4
- *
- * @param {String|Error} error
- * @return {String} error message
- */
- errorString = function( error ) {
- var name, message,
- errorString = error.toString();
- if ( errorString.substring( 0, 7 ) === "[object" ) {
- name = error.name ? error.name.toString() : "Error";
- message = error.message ? error.message.toString() : "";
- if ( name && message ) {
- return name + ": " + message;
- } else if ( name ) {
- return name;
- } else if ( message ) {
- return message;
- } else {
- return "Error";
- }
- } else {
- return errorString;
- }
- },
- /**
- * Makes a clone of an object using only Array or Object as base,
- * and copies over the own enumerable properties.
- *
- * @param {Object} obj
- * @return {Object} New object with only the own properties (recursively).
- */
- objectValues = function( obj ) {
- // Grunt 0.3.x uses an older version of jshint that still has jshint/jshint#392.
- /*jshint newcap: false */
- var key, val,
- vals = QUnit.is( "array", obj ) ? [] : {};
- for ( key in obj ) {
- if ( hasOwn.call( obj, key ) ) {
- val = obj[key];
- vals[key] = val === Object(val) ? objectValues(val) : val;
- }
- }
- return vals;
- };
-
-function Test( settings ) {
- extend( this, settings );
- this.assertions = [];
- this.testNumber = ++Test.count;
-}
-
-Test.count = 0;
-
-Test.prototype = {
- init: function() {
- var a, b, li,
- tests = id( "qunit-tests" );
-
- if ( tests ) {
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml;
-
- // `a` initialized at top of scope
- a = document.createElement( "a" );
- a.innerHTML = "Rerun";
- a.href = QUnit.url({ testNumber: this.testNumber });
-
- li = document.createElement( "li" );
- li.appendChild( b );
- li.appendChild( a );
- li.className = "running";
- li.id = this.id = "qunit-test-output" + testId++;
-
- tests.appendChild( li );
- }
- },
- setup: function() {
- if ( this.module !== config.previousModule ) {
- if ( config.previousModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.previousModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
- config.previousModule = this.module;
- config.moduleStats = { all: 0, bad: 0 };
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- } else if ( config.autorun ) {
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- }
-
- config.current = this;
-
- this.testEnvironment = extend({
- setup: function() {},
- teardown: function() {}
- }, this.moduleTestEnvironment );
-
- this.started = +new Date();
- runLoggingCallbacks( "testStart", QUnit, {
- name: this.testName,
- module: this.module
- });
-
- // allow utility functions to access the current test environment
- // TODO why??
- QUnit.current_testEnvironment = this.testEnvironment;
-
- if ( !config.pollution ) {
- saveGlobal();
- }
- if ( config.notrycatch ) {
- this.testEnvironment.setup.call( this.testEnvironment );
- return;
- }
- try {
- this.testEnvironment.setup.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Setup failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- },
- run: function() {
- config.current = this;
-
- var running = id( "qunit-testresult" );
-
- if ( running ) {
- running.innerHTML = "Running:
" + this.nameHtml;
- }
-
- if ( this.async ) {
- QUnit.stop();
- }
-
- this.callbackStarted = +new Date();
-
- if ( config.notrycatch ) {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- return;
- }
-
- try {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- } catch( e ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
-
- QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + " " + this.stack + ": " + ( e.message || e ), extractStacktrace( e, 0 ) );
- // else next test will carry the responsibility
- saveGlobal();
-
- // Restart the tests if they're blocking
- if ( config.blocking ) {
- QUnit.start();
- }
- }
- },
- teardown: function() {
- config.current = this;
- if ( config.notrycatch ) {
- if ( typeof this.callbackRuntime === "undefined" ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
- }
- this.testEnvironment.teardown.call( this.testEnvironment );
- return;
- } else {
- try {
- this.testEnvironment.teardown.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Teardown failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- }
- checkPollution();
- },
- finish: function() {
- config.current = this;
- if ( config.requireExpects && this.expected === null ) {
- QUnit.pushFailure( "Expected number of assertions to be defined, but expect() was not called.", this.stack );
- } else if ( this.expected !== null && this.expected !== this.assertions.length ) {
- QUnit.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack );
- } else if ( this.expected === null && !this.assertions.length ) {
- QUnit.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions.", this.stack );
- }
-
- var i, assertion, a, b, time, li, ol,
- test = this,
- good = 0,
- bad = 0,
- tests = id( "qunit-tests" );
-
- this.runtime = +new Date() - this.started;
- config.stats.all += this.assertions.length;
- config.moduleStats.all += this.assertions.length;
-
- if ( tests ) {
- ol = document.createElement( "ol" );
- ol.className = "qunit-assert-list";
-
- for ( i = 0; i < this.assertions.length; i++ ) {
- assertion = this.assertions[i];
-
- li = document.createElement( "li" );
- li.className = assertion.result ? "pass" : "fail";
- li.innerHTML = assertion.message || ( assertion.result ? "okay" : "failed" );
- ol.appendChild( li );
-
- if ( assertion.result ) {
- good++;
- } else {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
-
- // store result when possible
- if ( QUnit.config.reorder && defined.sessionStorage ) {
- if ( bad ) {
- sessionStorage.setItem( "qunit-test-" + this.module + "-" + this.testName, bad );
- } else {
- sessionStorage.removeItem( "qunit-test-" + this.module + "-" + this.testName );
- }
- }
-
- if ( bad === 0 ) {
- addClass( ol, "qunit-collapsed" );
- }
-
- // `b` initialized at top of scope
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml + " (" + bad + ", " + good + ", " + this.assertions.length + ")";
-
- addEvent(b, "click", function() {
- var next = b.parentNode.lastChild,
- collapsed = hasClass( next, "qunit-collapsed" );
- ( collapsed ? removeClass : addClass )( next, "qunit-collapsed" );
- });
-
- addEvent(b, "dblclick", function( e ) {
- var target = e && e.target ? e.target : window.event.srcElement;
- if ( target.nodeName.toLowerCase() === "span" || target.nodeName.toLowerCase() === "b" ) {
- target = target.parentNode;
- }
- if ( window.location && target.nodeName.toLowerCase() === "strong" ) {
- window.location = QUnit.url({ testNumber: test.testNumber });
- }
- });
-
- // `time` initialized at top of scope
- time = document.createElement( "span" );
- time.className = "runtime";
- time.innerHTML = this.runtime + " ms";
-
- // `li` initialized at top of scope
- li = id( this.id );
- li.className = bad ? "fail" : "pass";
- li.removeChild( li.firstChild );
- a = li.firstChild;
- li.appendChild( b );
- li.appendChild( a );
- li.appendChild( time );
- li.appendChild( ol );
-
- } else {
- for ( i = 0; i < this.assertions.length; i++ ) {
- if ( !this.assertions[i].result ) {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
- }
-
- runLoggingCallbacks( "testDone", QUnit, {
- name: this.testName,
- module: this.module,
- failed: bad,
- passed: this.assertions.length - bad,
- total: this.assertions.length,
- duration: this.runtime
- });
-
- QUnit.reset();
-
- config.current = undefined;
- },
-
- queue: function() {
- var bad,
- test = this;
-
- synchronize(function() {
- test.init();
- });
- function run() {
- // each of these can by async
- synchronize(function() {
- test.setup();
- });
- synchronize(function() {
- test.run();
- });
- synchronize(function() {
- test.teardown();
- });
- synchronize(function() {
- test.finish();
- });
- }
-
- // `bad` initialized at top of scope
- // defer when previous test run passed, if storage is available
- bad = QUnit.config.reorder && defined.sessionStorage &&
- +sessionStorage.getItem( "qunit-test-" + this.module + "-" + this.testName );
-
- if ( bad ) {
- run();
- } else {
- synchronize( run, true );
- }
- }
-};
-
-// Root QUnit object.
-// `QUnit` initialized at top of scope
-QUnit = {
-
- // call on start of module test to prepend name to all tests
- module: function( name, testEnvironment ) {
- config.currentModule = name;
- config.currentModuleTestEnvironment = testEnvironment;
- config.modules[name] = true;
- },
-
- asyncTest: function( testName, expected, callback ) {
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- QUnit.test( testName, expected, callback, true );
- },
-
- test: function( testName, expected, callback, async ) {
- var test,
- nameHtml = "" + escapeText( testName ) + "";
-
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- if ( config.currentModule ) {
- nameHtml = "" + escapeText( config.currentModule ) + ": " + nameHtml;
- }
-
- test = new Test({
- nameHtml: nameHtml,
- testName: testName,
- expected: expected,
- async: async,
- callback: callback,
- module: config.currentModule,
- moduleTestEnvironment: config.currentModuleTestEnvironment,
- stack: sourceFromStacktrace( 2 )
- });
-
- if ( !validTest( test ) ) {
- return;
- }
-
- test.queue();
- },
-
- // Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through.
- expect: function( asserts ) {
- if (arguments.length === 1) {
- config.current.expected = asserts;
- } else {
- return config.current.expected;
- }
- },
-
- start: function( count ) {
- // QUnit hasn't been initialized yet.
- // Note: RequireJS (et al) may delay onLoad
- if ( config.semaphore === undefined ) {
- QUnit.begin(function() {
- // This is triggered at the top of QUnit.load, push start() to the event loop, to allow QUnit.load to finish first
- setTimeout(function() {
- QUnit.start( count );
- });
- });
- return;
- }
-
- config.semaphore -= count || 1;
- // don't start until equal number of stop-calls
- if ( config.semaphore > 0 ) {
- return;
- }
- // ignore if start is called more often then stop
- if ( config.semaphore < 0 ) {
- config.semaphore = 0;
- QUnit.pushFailure( "Called start() while already started (QUnit.config.semaphore was 0 already)", null, sourceFromStacktrace(2) );
- return;
- }
- // A slight delay, to avoid any current callbacks
- if ( defined.setTimeout ) {
- window.setTimeout(function() {
- if ( config.semaphore > 0 ) {
- return;
- }
- if ( config.timeout ) {
- clearTimeout( config.timeout );
- }
-
- config.blocking = false;
- process( true );
- }, 13);
- } else {
- config.blocking = false;
- process( true );
- }
- },
-
- stop: function( count ) {
- config.semaphore += count || 1;
- config.blocking = true;
-
- if ( config.testTimeout && defined.setTimeout ) {
- clearTimeout( config.timeout );
- config.timeout = window.setTimeout(function() {
- QUnit.ok( false, "Test timed out" );
- config.semaphore = 1;
- QUnit.start();
- }, config.testTimeout );
- }
- }
-};
-
-// `assert` initialized at top of scope
-// Asssert helpers
-// All of these must either call QUnit.push() or manually do:
-// - runLoggingCallbacks( "log", .. );
-// - config.current.assertions.push({ .. });
-// We attach it to the QUnit object *after* we expose the public API,
-// otherwise `assert` will become a global variable in browsers (#341).
-assert = {
- /**
- * Asserts rough true-ish result.
- * @name ok
- * @function
- * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" );
- */
- ok: function( result, msg ) {
- if ( !config.current ) {
- throw new Error( "ok() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
- result = !!result;
-
- var source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: msg
- };
-
- msg = escapeText( msg || (result ? "okay" : "failed" ) );
- msg = "" + msg + "";
-
- if ( !result ) {
- source = sourceFromStacktrace( 2 );
- if ( source ) {
- details.source = source;
- msg += "Source: | " + escapeText( source ) + " |
---|
";
- }
- }
- runLoggingCallbacks( "log", QUnit, details );
- config.current.assertions.push({
- result: result,
- message: msg
- });
- },
-
- /**
- * Assert that the first two arguments are equal, with an optional message.
- * Prints out both actual and expected values.
- * @name equal
- * @function
- * @example equal( format( "Received {0} bytes.", 2), "Received 2 bytes.", "format() replaces {0} with next argument" );
- */
- equal: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected == actual, actual, expected, message );
- },
-
- /**
- * @name notEqual
- * @function
- */
- notEqual: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected != actual, actual, expected, message );
- },
-
- /**
- * @name propEqual
- * @function
- */
- propEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notPropEqual
- * @function
- */
- notPropEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name deepEqual
- * @function
- */
- deepEqual: function( actual, expected, message ) {
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notDeepEqual
- * @function
- */
- notDeepEqual: function( actual, expected, message ) {
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name strictEqual
- * @function
- */
- strictEqual: function( actual, expected, message ) {
- QUnit.push( expected === actual, actual, expected, message );
- },
-
- /**
- * @name notStrictEqual
- * @function
- */
- notStrictEqual: function( actual, expected, message ) {
- QUnit.push( expected !== actual, actual, expected, message );
- },
-
- "throws": function( block, expected, message ) {
- var actual,
- expectedOutput = expected,
- ok = false;
-
- // 'expected' is optional
- if ( typeof expected === "string" ) {
- message = expected;
- expected = null;
- }
-
- config.current.ignoreGlobalErrors = true;
- try {
- block.call( config.current.testEnvironment );
- } catch (e) {
- actual = e;
- }
- config.current.ignoreGlobalErrors = false;
-
- if ( actual ) {
- // we don't want to validate thrown error
- if ( !expected ) {
- ok = true;
- expectedOutput = null;
- // expected is a regexp
- } else if ( QUnit.objectType( expected ) === "regexp" ) {
- ok = expected.test( errorString( actual ) );
- // expected is a constructor
- } else if ( actual instanceof expected ) {
- ok = true;
- // expected is a validation function which returns true is validation passed
- } else if ( expected.call( {}, actual ) === true ) {
- expectedOutput = null;
- ok = true;
- }
-
- QUnit.push( ok, actual, expectedOutput, message );
- } else {
- QUnit.pushFailure( message, null, 'No exception was thrown.' );
- }
- }
-};
-
-/**
- * @deprecate since 1.8.0
- * Kept assertion helpers in root for backwards compatibility.
- */
-extend( QUnit, assert );
-
-/**
- * @deprecated since 1.9.0
- * Kept root "raises()" for backwards compatibility.
- * (Note that we don't introduce assert.raises).
- */
-QUnit.raises = assert[ "throws" ];
-
-/**
- * @deprecated since 1.0.0, replaced with error pushes since 1.3.0
- * Kept to avoid TypeErrors for undefined methods.
- */
-QUnit.equals = function() {
- QUnit.push( false, false, false, "QUnit.equals has been deprecated since 2009 (e88049a0), use QUnit.equal instead" );
-};
-QUnit.same = function() {
- QUnit.push( false, false, false, "QUnit.same has been deprecated since 2009 (e88049a0), use QUnit.deepEqual instead" );
-};
-
-// We want access to the constructor's prototype
-(function() {
- function F() {}
- F.prototype = QUnit;
- QUnit = new F();
- // Make F QUnit's constructor so that we can add to the prototype later
- QUnit.constructor = F;
-}());
-
-/**
- * Config object: Maintain internal state
- * Later exposed as QUnit.config
- * `config` initialized at top of scope
- */
-config = {
- // The queue of tests to run
- queue: [],
-
- // block until document ready
- blocking: true,
-
- // when enabled, show only failing tests
- // gets persisted through sessionStorage and can be changed in UI via checkbox
- hidepassed: false,
-
- // by default, run previously failed tests first
- // very useful in combination with "Hide passed tests" checked
- reorder: true,
-
- // by default, modify document.title when suite is done
- altertitle: true,
-
- // when enabled, all tests must call expect()
- requireExpects: false,
-
- // add checkboxes that are persisted in the query-string
- // when enabled, the id is set to `true` as a `QUnit.config` property
- urlConfig: [
- {
- id: "noglobals",
- label: "Check for Globals",
- tooltip: "Enabling this will test if any test introduces new properties on the `window` object. Stored as query-strings."
- },
- {
- id: "notrycatch",
- label: "No try-catch",
- tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging exceptions in IE reasonable. Stored as query-strings."
- }
- ],
-
- // Set of all modules.
- modules: {},
-
- // logging callback queues
- begin: [],
- done: [],
- log: [],
- testStart: [],
- testDone: [],
- moduleStart: [],
- moduleDone: []
-};
-
-// Export global variables, unless an 'exports' object exists,
-// in that case we assume we're in CommonJS (dealt with on the bottom of the script)
-if ( typeof exports === "undefined" ) {
- extend( window, QUnit );
-
- // Expose QUnit object
- window.QUnit = QUnit;
-}
-
-// Initialize more QUnit.config and QUnit.urlParams
-(function() {
- var i,
- location = window.location || { search: "", protocol: "file:" },
- params = location.search.slice( 1 ).split( "&" ),
- length = params.length,
- urlParams = {},
- current;
-
- if ( params[ 0 ] ) {
- for ( i = 0; i < length; i++ ) {
- current = params[ i ].split( "=" );
- current[ 0 ] = decodeURIComponent( current[ 0 ] );
- // allow just a key to turn on a flag, e.g., test.html?noglobals
- current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true;
- urlParams[ current[ 0 ] ] = current[ 1 ];
- }
- }
-
- QUnit.urlParams = urlParams;
-
- // String search anywhere in moduleName+testName
- config.filter = urlParams.filter;
-
- // Exact match of the module name
- config.module = urlParams.module;
-
- config.testNumber = parseInt( urlParams.testNumber, 10 ) || null;
-
- // Figure out if we're running the tests from a server or not
- QUnit.isLocal = location.protocol === "file:";
-}());
-
-// Extend QUnit object,
-// these after set here because they should not be exposed as global functions
-extend( QUnit, {
- assert: assert,
-
- config: config,
-
- // Initialize the configuration options
- init: function() {
- extend( config, {
- stats: { all: 0, bad: 0 },
- moduleStats: { all: 0, bad: 0 },
- started: +new Date(),
- updateRate: 1000,
- blocking: false,
- autostart: true,
- autorun: false,
- filter: "",
- queue: [],
- semaphore: 1
- });
-
- var tests, banner, result,
- qunit = id( "qunit" );
-
- if ( qunit ) {
- qunit.innerHTML =
- "" +
- "" +
- "" +
- "" +
- "
";
- }
-
- tests = id( "qunit-tests" );
- banner = id( "qunit-banner" );
- result = id( "qunit-testresult" );
-
- if ( tests ) {
- tests.innerHTML = "";
- }
-
- if ( banner ) {
- banner.className = "";
- }
-
- if ( result ) {
- result.parentNode.removeChild( result );
- }
-
- if ( tests ) {
- result = document.createElement( "p" );
- result.id = "qunit-testresult";
- result.className = "result";
- tests.parentNode.insertBefore( result, tests );
- result.innerHTML = "Running...
";
- }
- },
-
- // Resets the test setup. Useful for tests that modify the DOM.
- reset: function() {
- var fixture = id( "qunit-fixture" );
- if ( fixture ) {
- fixture.innerHTML = config.fixture;
- }
- },
-
- // Trigger an event on an element.
- // @example triggerEvent( document.body, "click" );
- triggerEvent: function( elem, type, event ) {
- if ( document.createEvent ) {
- event = document.createEvent( "MouseEvents" );
- event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView,
- 0, 0, 0, 0, 0, false, false, false, false, 0, null);
-
- elem.dispatchEvent( event );
- } else if ( elem.fireEvent ) {
- elem.fireEvent( "on" + type );
- }
- },
-
- // Safe object type checking
- is: function( type, obj ) {
- return QUnit.objectType( obj ) === type;
- },
-
- objectType: function( obj ) {
- if ( typeof obj === "undefined" ) {
- return "undefined";
- // consider: typeof null === object
- }
- if ( obj === null ) {
- return "null";
- }
-
- var match = toString.call( obj ).match(/^\[object\s(.*)\]$/),
- type = match && match[1] || "";
-
- switch ( type ) {
- case "Number":
- if ( isNaN(obj) ) {
- return "nan";
- }
- return "number";
- case "String":
- case "Boolean":
- case "Array":
- case "Date":
- case "RegExp":
- case "Function":
- return type.toLowerCase();
- }
- if ( typeof obj === "object" ) {
- return "object";
- }
- return undefined;
- },
-
- push: function( result, actual, expected, message ) {
- if ( !config.current ) {
- throw new Error( "assertion outside test context, was " + sourceFromStacktrace() );
- }
-
- var output, source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: message,
- actual: actual,
- expected: expected
- };
-
- message = escapeText( message ) || ( result ? "okay" : "failed" );
- message = "" + message + "";
- output = message;
-
- if ( !result ) {
- expected = escapeText( QUnit.jsDump.parse(expected) );
- actual = escapeText( QUnit.jsDump.parse(actual) );
- output += "Expected: | " + expected + " |
";
-
- if ( actual !== expected ) {
- output += "Result: | " + actual + " |
";
- output += "Diff: | " + QUnit.diff( expected, actual ) + " |
";
- }
-
- source = sourceFromStacktrace();
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
- }
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: !!result,
- message: output
- });
- },
-
- pushFailure: function( message, source, actual ) {
- if ( !config.current ) {
- throw new Error( "pushFailure() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
-
- var output,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: false,
- message: message
- };
-
- message = escapeText( message ) || "error";
- message = "" + message + "";
- output = message;
-
- output += "";
-
- if ( actual ) {
- output += "Result: | " + escapeText( actual ) + " |
";
- }
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: false,
- message: output
- });
- },
-
- url: function( params ) {
- params = extend( extend( {}, QUnit.urlParams ), params );
- var key,
- querystring = "?";
-
- for ( key in params ) {
- if ( !hasOwn.call( params, key ) ) {
- continue;
- }
- querystring += encodeURIComponent( key ) + "=" +
- encodeURIComponent( params[ key ] ) + "&";
- }
- return window.location.protocol + "//" + window.location.host +
- window.location.pathname + querystring.slice( 0, -1 );
- },
-
- extend: extend,
- id: id,
- addEvent: addEvent
- // load, equiv, jsDump, diff: Attached later
-});
-
-/**
- * @deprecated: Created for backwards compatibility with test runner that set the hook function
- * into QUnit.{hook}, instead of invoking it and passing the hook function.
- * QUnit.constructor is set to the empty F() above so that we can add to it's prototype here.
- * Doing this allows us to tell if the following methods have been overwritten on the actual
- * QUnit object.
- */
-extend( QUnit.constructor.prototype, {
-
- // Logging callbacks; all receive a single argument with the listed properties
- // run test/logs.html for any related changes
- begin: registerLoggingCallback( "begin" ),
-
- // done: { failed, passed, total, runtime }
- done: registerLoggingCallback( "done" ),
-
- // log: { result, actual, expected, message }
- log: registerLoggingCallback( "log" ),
-
- // testStart: { name }
- testStart: registerLoggingCallback( "testStart" ),
-
- // testDone: { name, failed, passed, total, duration }
- testDone: registerLoggingCallback( "testDone" ),
-
- // moduleStart: { name }
- moduleStart: registerLoggingCallback( "moduleStart" ),
-
- // moduleDone: { name, failed, passed, total }
- moduleDone: registerLoggingCallback( "moduleDone" )
-});
-
-if ( typeof document === "undefined" || document.readyState === "complete" ) {
- config.autorun = true;
-}
-
-QUnit.load = function() {
- runLoggingCallbacks( "begin", QUnit, {} );
-
- // Initialize the config, saving the execution queue
- var banner, filter, i, label, len, main, ol, toolbar, userAgent, val,
- urlConfigCheckboxesContainer, urlConfigCheckboxes, moduleFilter,
- numModules = 0,
- moduleFilterHtml = "",
- urlConfigHtml = "",
- oldconfig = extend( {}, config );
-
- QUnit.init();
- extend(config, oldconfig);
-
- config.blocking = false;
-
- len = config.urlConfig.length;
-
- for ( i = 0; i < len; i++ ) {
- val = config.urlConfig[i];
- if ( typeof val === "string" ) {
- val = {
- id: val,
- label: val,
- tooltip: "[no tooltip available]"
- };
- }
- config[ val.id ] = QUnit.urlParams[ val.id ];
- urlConfigHtml += "";
- }
-
- moduleFilterHtml += "";
-
- // `userAgent` initialized at top of scope
- userAgent = id( "qunit-userAgent" );
- if ( userAgent ) {
- userAgent.innerHTML = navigator.userAgent;
- }
-
- // `banner` initialized at top of scope
- banner = id( "qunit-header" );
- if ( banner ) {
- banner.innerHTML = "" + banner.innerHTML + " ";
- }
-
- // `toolbar` initialized at top of scope
- toolbar = id( "qunit-testrunner-toolbar" );
- if ( toolbar ) {
- // `filter` initialized at top of scope
- filter = document.createElement( "input" );
- filter.type = "checkbox";
- filter.id = "qunit-filter-pass";
-
- addEvent( filter, "click", function() {
- var tmp,
- ol = document.getElementById( "qunit-tests" );
-
- if ( filter.checked ) {
- ol.className = ol.className + " hidepass";
- } else {
- tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " ";
- ol.className = tmp.replace( / hidepass /, " " );
- }
- if ( defined.sessionStorage ) {
- if (filter.checked) {
- sessionStorage.setItem( "qunit-filter-passed-tests", "true" );
- } else {
- sessionStorage.removeItem( "qunit-filter-passed-tests" );
- }
- }
- });
-
- if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem( "qunit-filter-passed-tests" ) ) {
- filter.checked = true;
- // `ol` initialized at top of scope
- ol = document.getElementById( "qunit-tests" );
- ol.className = ol.className + " hidepass";
- }
- toolbar.appendChild( filter );
-
- // `label` initialized at top of scope
- label = document.createElement( "label" );
- label.setAttribute( "for", "qunit-filter-pass" );
- label.setAttribute( "title", "Only show tests and assertons that fail. Stored in sessionStorage." );
- label.innerHTML = "Hide passed tests";
- toolbar.appendChild( label );
-
- urlConfigCheckboxesContainer = document.createElement("span");
- urlConfigCheckboxesContainer.innerHTML = urlConfigHtml;
- urlConfigCheckboxes = urlConfigCheckboxesContainer.getElementsByTagName("input");
- // For oldIE support:
- // * Add handlers to the individual elements instead of the container
- // * Use "click" instead of "change"
- // * Fallback from event.target to event.srcElement
- addEvents( urlConfigCheckboxes, "click", function( event ) {
- var params = {},
- target = event.target || event.srcElement;
- params[ target.name ] = target.checked ? true : undefined;
- window.location = QUnit.url( params );
- });
- toolbar.appendChild( urlConfigCheckboxesContainer );
-
- if (numModules > 1) {
- moduleFilter = document.createElement( 'span' );
- moduleFilter.setAttribute( 'id', 'qunit-modulefilter-container' );
- moduleFilter.innerHTML = moduleFilterHtml;
- addEvent( moduleFilter.lastChild, "change", function() {
- var selectBox = moduleFilter.getElementsByTagName("select")[0],
- selectedModule = decodeURIComponent(selectBox.options[selectBox.selectedIndex].value);
-
- window.location = QUnit.url( { module: ( selectedModule === "" ) ? undefined : selectedModule } );
- });
- toolbar.appendChild(moduleFilter);
- }
- }
-
- // `main` initialized at top of scope
- main = id( "qunit-fixture" );
- if ( main ) {
- config.fixture = main.innerHTML;
- }
-
- if ( config.autostart ) {
- QUnit.start();
- }
-};
-
-addEvent( window, "load", QUnit.load );
-
-// `onErrorFnPrev` initialized at top of scope
-// Preserve other handlers
-onErrorFnPrev = window.onerror;
-
-// Cover uncaught exceptions
-// Returning true will surpress the default browser handler,
-// returning false will let it run.
-window.onerror = function ( error, filePath, linerNr ) {
- var ret = false;
- if ( onErrorFnPrev ) {
- ret = onErrorFnPrev( error, filePath, linerNr );
- }
-
- // Treat return value as window.onerror itself does,
- // Only do our handling if not surpressed.
- if ( ret !== true ) {
- if ( QUnit.config.current ) {
- if ( QUnit.config.current.ignoreGlobalErrors ) {
- return true;
- }
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- } else {
- QUnit.test( "global failure", extend( function() {
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- }, { validTest: validTest } ) );
- }
- return false;
- }
-
- return ret;
-};
-
-function done() {
- config.autorun = true;
-
- // Log the last module results
- if ( config.currentModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.currentModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
-
- var i, key,
- banner = id( "qunit-banner" ),
- tests = id( "qunit-tests" ),
- runtime = +new Date() - config.started,
- passed = config.stats.all - config.stats.bad,
- html = [
- "Tests completed in ",
- runtime,
- " milliseconds.
",
- "",
- passed,
- " assertions of ",
- config.stats.all,
- " passed, ",
- config.stats.bad,
- " failed."
- ].join( "" );
-
- if ( banner ) {
- banner.className = ( config.stats.bad ? "qunit-fail" : "qunit-pass" );
- }
-
- if ( tests ) {
- id( "qunit-testresult" ).innerHTML = html;
- }
-
- if ( config.altertitle && typeof document !== "undefined" && document.title ) {
- // show ✖ for good, ✔ for bad suite result in title
- // use escape sequences in case file gets loaded with non-utf-8-charset
- document.title = [
- ( config.stats.bad ? "\u2716" : "\u2714" ),
- document.title.replace( /^[\u2714\u2716] /i, "" )
- ].join( " " );
- }
-
- // clear own sessionStorage items if all tests passed
- if ( config.reorder && defined.sessionStorage && config.stats.bad === 0 ) {
- // `key` & `i` initialized at top of scope
- for ( i = 0; i < sessionStorage.length; i++ ) {
- key = sessionStorage.key( i++ );
- if ( key.indexOf( "qunit-test-" ) === 0 ) {
- sessionStorage.removeItem( key );
- }
- }
- }
-
- // scroll back to top to show results
- if ( window.scrollTo ) {
- window.scrollTo(0, 0);
- }
-
- runLoggingCallbacks( "done", QUnit, {
- failed: config.stats.bad,
- passed: passed,
- total: config.stats.all,
- runtime: runtime
- });
-}
-
-/** @return Boolean: true if this test should be ran */
-function validTest( test ) {
- var include,
- filter = config.filter && config.filter.toLowerCase(),
- module = config.module && config.module.toLowerCase(),
- fullName = (test.module + ": " + test.testName).toLowerCase();
-
- // Internally-generated tests are always valid
- if ( test.callback && test.callback.validTest === validTest ) {
- delete test.callback.validTest;
- return true;
- }
-
- if ( config.testNumber ) {
- return test.testNumber === config.testNumber;
- }
-
- if ( module && ( !test.module || test.module.toLowerCase() !== module ) ) {
- return false;
- }
-
- if ( !filter ) {
- return true;
- }
-
- include = filter.charAt( 0 ) !== "!";
- if ( !include ) {
- filter = filter.slice( 1 );
- }
-
- // If the filter matches, we need to honour include
- if ( fullName.indexOf( filter ) !== -1 ) {
- return include;
- }
-
- // Otherwise, do the opposite
- return !include;
-}
-
-// so far supports only Firefox, Chrome and Opera (buggy), Safari (for real exceptions)
-// Later Safari and IE10 are supposed to support error.stack as well
-// See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack
-function extractStacktrace( e, offset ) {
- offset = offset === undefined ? 3 : offset;
-
- var stack, include, i;
-
- if ( e.stacktrace ) {
- // Opera
- return e.stacktrace.split( "\n" )[ offset + 3 ];
- } else if ( e.stack ) {
- // Firefox, Chrome
- stack = e.stack.split( "\n" );
- if (/^error$/i.test( stack[0] ) ) {
- stack.shift();
- }
- if ( fileName ) {
- include = [];
- for ( i = offset; i < stack.length; i++ ) {
- if ( stack[ i ].indexOf( fileName ) !== -1 ) {
- break;
- }
- include.push( stack[ i ] );
- }
- if ( include.length ) {
- return include.join( "\n" );
- }
- }
- return stack[ offset ];
- } else if ( e.sourceURL ) {
- // Safari, PhantomJS
- // hopefully one day Safari provides actual stacktraces
- // exclude useless self-reference for generated Error objects
- if ( /qunit.js$/.test( e.sourceURL ) ) {
- return;
- }
- // for actual exceptions, this is useful
- return e.sourceURL + ":" + e.line;
- }
-}
-function sourceFromStacktrace( offset ) {
- try {
- throw new Error();
- } catch ( e ) {
- return extractStacktrace( e, offset );
- }
-}
-
-/**
- * Escape text for attribute or text content.
- */
-function escapeText( s ) {
- if ( !s ) {
- return "";
- }
- s = s + "";
- // Both single quotes and double quotes (for attributes)
- return s.replace( /['"<>&]/g, function( s ) {
- switch( s ) {
- case '\'':
- return ''';
- case '"':
- return '"';
- case '<':
- return '<';
- case '>':
- return '>';
- case '&':
- return '&';
- }
- });
-}
-
-function synchronize( callback, last ) {
- config.queue.push( callback );
-
- if ( config.autorun && !config.blocking ) {
- process( last );
- }
-}
-
-function process( last ) {
- function next() {
- process( last );
- }
- var start = new Date().getTime();
- config.depth = config.depth ? config.depth + 1 : 1;
-
- while ( config.queue.length && !config.blocking ) {
- if ( !defined.setTimeout || config.updateRate <= 0 || ( ( new Date().getTime() - start ) < config.updateRate ) ) {
- config.queue.shift()();
- } else {
- window.setTimeout( next, 13 );
- break;
- }
- }
- config.depth--;
- if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) {
- done();
- }
-}
-
-function saveGlobal() {
- config.pollution = [];
-
- if ( config.noglobals ) {
- for ( var key in window ) {
- // in Opera sometimes DOM element ids show up here, ignore them
- if ( !hasOwn.call( window, key ) || /^qunit-test-output/.test( key ) ) {
- continue;
- }
- config.pollution.push( key );
- }
- }
-}
-
-function checkPollution() {
- var newGlobals,
- deletedGlobals,
- old = config.pollution;
-
- saveGlobal();
-
- newGlobals = diff( config.pollution, old );
- if ( newGlobals.length > 0 ) {
- QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join(", ") );
- }
-
- deletedGlobals = diff( old, config.pollution );
- if ( deletedGlobals.length > 0 ) {
- QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join(", ") );
- }
-}
-
-// returns a new Array with the elements that are in a but not in b
-function diff( a, b ) {
- var i, j,
- result = a.slice();
-
- for ( i = 0; i < result.length; i++ ) {
- for ( j = 0; j < b.length; j++ ) {
- if ( result[i] === b[j] ) {
- result.splice( i, 1 );
- i--;
- break;
- }
- }
- }
- return result;
-}
-
-function extend( a, b ) {
- for ( var prop in b ) {
- if ( b[ prop ] === undefined ) {
- delete a[ prop ];
-
- // Avoid "Member not found" error in IE8 caused by setting window.constructor
- } else if ( prop !== "constructor" || a !== window ) {
- a[ prop ] = b[ prop ];
- }
- }
-
- return a;
-}
-
-/**
- * @param {HTMLElement} elem
- * @param {string} type
- * @param {Function} fn
- */
-function addEvent( elem, type, fn ) {
- // Standards-based browsers
- if ( elem.addEventListener ) {
- elem.addEventListener( type, fn, false );
- // IE
- } else {
- elem.attachEvent( "on" + type, fn );
- }
-}
-
-/**
- * @param {Array|NodeList} elems
- * @param {string} type
- * @param {Function} fn
- */
-function addEvents( elems, type, fn ) {
- var i = elems.length;
- while ( i-- ) {
- addEvent( elems[i], type, fn );
- }
-}
-
-function hasClass( elem, name ) {
- return (" " + elem.className + " ").indexOf(" " + name + " ") > -1;
-}
-
-function addClass( elem, name ) {
- if ( !hasClass( elem, name ) ) {
- elem.className += (elem.className ? " " : "") + name;
- }
-}
-
-function removeClass( elem, name ) {
- var set = " " + elem.className + " ";
- // Class name may appear multiple times
- while ( set.indexOf(" " + name + " ") > -1 ) {
- set = set.replace(" " + name + " " , " ");
- }
- // If possible, trim it for prettiness, but not neccecarily
- elem.className = window.jQuery ? jQuery.trim( set ) : ( set.trim ? set.trim() : set );
-}
-
-function id( name ) {
- return !!( typeof document !== "undefined" && document && document.getElementById ) &&
- document.getElementById( name );
-}
-
-function registerLoggingCallback( key ) {
- return function( callback ) {
- config[key].push( callback );
- };
-}
-
-// Supports deprecated method of completely overwriting logging callbacks
-function runLoggingCallbacks( key, scope, args ) {
- var i, callbacks;
- if ( QUnit.hasOwnProperty( key ) ) {
- QUnit[ key ].call(scope, args );
- } else {
- callbacks = config[ key ];
- for ( i = 0; i < callbacks.length; i++ ) {
- callbacks[ i ].call( scope, args );
- }
- }
-}
-
-// Test for equality any JavaScript type.
-// Author: Philippe Rathé
-QUnit.equiv = (function() {
-
- // Call the o related callback with the given arguments.
- function bindCallbacks( o, callbacks, args ) {
- var prop = QUnit.objectType( o );
- if ( prop ) {
- if ( QUnit.objectType( callbacks[ prop ] ) === "function" ) {
- return callbacks[ prop ].apply( callbacks, args );
- } else {
- return callbacks[ prop ]; // or undefined
- }
- }
- }
-
- // the real equiv function
- var innerEquiv,
- // stack to decide between skip/abort functions
- callers = [],
- // stack to avoiding loops from circular referencing
- parents = [],
-
- getProto = Object.getPrototypeOf || function ( obj ) {
- return obj.__proto__;
- },
- callbacks = (function () {
-
- // for string, boolean, number and null
- function useStrictEquality( b, a ) {
- /*jshint eqeqeq:false */
- if ( b instanceof a.constructor || a instanceof b.constructor ) {
- // to catch short annotaion VS 'new' annotation of a
- // declaration
- // e.g. var i = 1;
- // var j = new Number(1);
- return a == b;
- } else {
- return a === b;
- }
- }
-
- return {
- "string": useStrictEquality,
- "boolean": useStrictEquality,
- "number": useStrictEquality,
- "null": useStrictEquality,
- "undefined": useStrictEquality,
-
- "nan": function( b ) {
- return isNaN( b );
- },
-
- "date": function( b, a ) {
- return QUnit.objectType( b ) === "date" && a.valueOf() === b.valueOf();
- },
-
- "regexp": function( b, a ) {
- return QUnit.objectType( b ) === "regexp" &&
- // the regex itself
- a.source === b.source &&
- // and its modifers
- a.global === b.global &&
- // (gmi) ...
- a.ignoreCase === b.ignoreCase &&
- a.multiline === b.multiline &&
- a.sticky === b.sticky;
- },
-
- // - skip when the property is a method of an instance (OOP)
- // - abort otherwise,
- // initial === would have catch identical references anyway
- "function": function() {
- var caller = callers[callers.length - 1];
- return caller !== Object && typeof caller !== "undefined";
- },
-
- "array": function( b, a ) {
- var i, j, len, loop;
-
- // b could be an object literal here
- if ( QUnit.objectType( b ) !== "array" ) {
- return false;
- }
-
- len = a.length;
- if ( len !== b.length ) {
- // safe and faster
- return false;
- }
-
- // track reference to avoid circular references
- parents.push( a );
- for ( i = 0; i < len; i++ ) {
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- loop = true;// dont rewalk array
- }
- }
- if ( !loop && !innerEquiv(a[i], b[i]) ) {
- parents.pop();
- return false;
- }
- }
- parents.pop();
- return true;
- },
-
- "object": function( b, a ) {
- var i, j, loop,
- // Default to true
- eq = true,
- aProperties = [],
- bProperties = [];
-
- // comparing constructors is more strict than using
- // instanceof
- if ( a.constructor !== b.constructor ) {
- // Allow objects with no prototype to be equivalent to
- // objects with Object as their constructor.
- if ( !(( getProto(a) === null && getProto(b) === Object.prototype ) ||
- ( getProto(b) === null && getProto(a) === Object.prototype ) ) ) {
- return false;
- }
- }
-
- // stack constructor before traversing properties
- callers.push( a.constructor );
- // track reference to avoid circular references
- parents.push( a );
-
- for ( i in a ) { // be strict: don't ensures hasOwnProperty
- // and go deep
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- // don't go down the same path twice
- loop = true;
- }
- }
- aProperties.push(i); // collect a's properties
-
- if (!loop && !innerEquiv( a[i], b[i] ) ) {
- eq = false;
- break;
- }
- }
-
- callers.pop(); // unstack, we are done
- parents.pop();
-
- for ( i in b ) {
- bProperties.push( i ); // collect b's properties
- }
-
- // Ensures identical properties name
- return eq && innerEquiv( aProperties.sort(), bProperties.sort() );
- }
- };
- }());
-
- innerEquiv = function() { // can take multiple arguments
- var args = [].slice.apply( arguments );
- if ( args.length < 2 ) {
- return true; // end transition
- }
-
- return (function( a, b ) {
- if ( a === b ) {
- return true; // catch the most you can
- } else if ( a === null || b === null || typeof a === "undefined" ||
- typeof b === "undefined" ||
- QUnit.objectType(a) !== QUnit.objectType(b) ) {
- return false; // don't lose time with error prone cases
- } else {
- return bindCallbacks(a, callbacks, [ b, a ]);
- }
-
- // apply transition with (1..n) arguments
- }( args[0], args[1] ) && arguments.callee.apply( this, args.splice(1, args.length - 1 )) );
- };
-
- return innerEquiv;
-}());
-
-/**
- * jsDump Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com |
- * http://flesler.blogspot.com Licensed under BSD
- * (http://www.opensource.org/licenses/bsd-license.php) Date: 5/15/2008
- *
- * @projectDescription Advanced and extensible data dumping for Javascript.
- * @version 1.0.0
- * @author Ariel Flesler
- * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html}
- */
-QUnit.jsDump = (function() {
- function quote( str ) {
- return '"' + str.toString().replace( /"/g, '\\"' ) + '"';
- }
- function literal( o ) {
- return o + "";
- }
- function join( pre, arr, post ) {
- var s = jsDump.separator(),
- base = jsDump.indent(),
- inner = jsDump.indent(1);
- if ( arr.join ) {
- arr = arr.join( "," + s + inner );
- }
- if ( !arr ) {
- return pre + post;
- }
- return [ pre, inner + arr, base + post ].join(s);
- }
- function array( arr, stack ) {
- var i = arr.length, ret = new Array(i);
- this.up();
- while ( i-- ) {
- ret[i] = this.parse( arr[i] , undefined , stack);
- }
- this.down();
- return join( "[", ret, "]" );
- }
-
- var reName = /^function (\w+)/,
- jsDump = {
- // type is used mostly internally, you can fix a (custom)type in advance
- parse: function( obj, type, stack ) {
- stack = stack || [ ];
- var inStack, res,
- parser = this.parsers[ type || this.typeOf(obj) ];
-
- type = typeof parser;
- inStack = inArray( obj, stack );
-
- if ( inStack !== -1 ) {
- return "recursion(" + (inStack - stack.length) + ")";
- }
- if ( type === "function" ) {
- stack.push( obj );
- res = parser.call( this, obj, stack );
- stack.pop();
- return res;
- }
- return ( type === "string" ) ? parser : this.parsers.error;
- },
- typeOf: function( obj ) {
- var type;
- if ( obj === null ) {
- type = "null";
- } else if ( typeof obj === "undefined" ) {
- type = "undefined";
- } else if ( QUnit.is( "regexp", obj) ) {
- type = "regexp";
- } else if ( QUnit.is( "date", obj) ) {
- type = "date";
- } else if ( QUnit.is( "function", obj) ) {
- type = "function";
- } else if ( typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined" ) {
- type = "window";
- } else if ( obj.nodeType === 9 ) {
- type = "document";
- } else if ( obj.nodeType ) {
- type = "node";
- } else if (
- // native arrays
- toString.call( obj ) === "[object Array]" ||
- // NodeList objects
- ( typeof obj.length === "number" && typeof obj.item !== "undefined" && ( obj.length ? obj.item(0) === obj[0] : ( obj.item( 0 ) === null && typeof obj[0] === "undefined" ) ) )
- ) {
- type = "array";
- } else if ( obj.constructor === Error.prototype.constructor ) {
- type = "error";
- } else {
- type = typeof obj;
- }
- return type;
- },
- separator: function() {
- return this.multiline ? this.HTML ? "
" : "\n" : this.HTML ? " " : " ";
- },
- // extra can be a number, shortcut for increasing-calling-decreasing
- indent: function( extra ) {
- if ( !this.multiline ) {
- return "";
- }
- var chr = this.indentChar;
- if ( this.HTML ) {
- chr = chr.replace( /\t/g, " " ).replace( / /g, " " );
- }
- return new Array( this._depth_ + (extra||0) ).join(chr);
- },
- up: function( a ) {
- this._depth_ += a || 1;
- },
- down: function( a ) {
- this._depth_ -= a || 1;
- },
- setParser: function( name, parser ) {
- this.parsers[name] = parser;
- },
- // The next 3 are exposed so you can use them
- quote: quote,
- literal: literal,
- join: join,
- //
- _depth_: 1,
- // This is the list of parsers, to modify them, use jsDump.setParser
- parsers: {
- window: "[Window]",
- document: "[Document]",
- error: function(error) {
- return "Error(\"" + error.message + "\")";
- },
- unknown: "[Unknown]",
- "null": "null",
- "undefined": "undefined",
- "function": function( fn ) {
- var ret = "function",
- // functions never have name in IE
- name = "name" in fn ? fn.name : (reName.exec(fn) || [])[1];
-
- if ( name ) {
- ret += " " + name;
- }
- ret += "( ";
-
- ret = [ ret, QUnit.jsDump.parse( fn, "functionArgs" ), "){" ].join( "" );
- return join( ret, QUnit.jsDump.parse(fn,"functionCode" ), "}" );
- },
- array: array,
- nodelist: array,
- "arguments": array,
- object: function( map, stack ) {
- var ret = [ ], keys, key, val, i;
- QUnit.jsDump.up();
- keys = [];
- for ( key in map ) {
- keys.push( key );
- }
- keys.sort();
- for ( i = 0; i < keys.length; i++ ) {
- key = keys[ i ];
- val = map[ key ];
- ret.push( QUnit.jsDump.parse( key, "key" ) + ": " + QUnit.jsDump.parse( val, undefined, stack ) );
- }
- QUnit.jsDump.down();
- return join( "{", ret, "}" );
- },
- node: function( node ) {
- var len, i, val,
- open = QUnit.jsDump.HTML ? "<" : "<",
- close = QUnit.jsDump.HTML ? ">" : ">",
- tag = node.nodeName.toLowerCase(),
- ret = open + tag,
- attrs = node.attributes;
-
- if ( attrs ) {
- for ( i = 0, len = attrs.length; i < len; i++ ) {
- val = attrs[i].nodeValue;
- // IE6 includes all attributes in .attributes, even ones not explicitly set.
- // Those have values like undefined, null, 0, false, "" or "inherit".
- if ( val && val !== "inherit" ) {
- ret += " " + attrs[i].nodeName + "=" + QUnit.jsDump.parse( val, "attribute" );
- }
- }
- }
- ret += close;
-
- // Show content of TextNode or CDATASection
- if ( node.nodeType === 3 || node.nodeType === 4 ) {
- ret += node.nodeValue;
- }
-
- return ret + open + "/" + tag + close;
- },
- // function calls it internally, it's the arguments part of the function
- functionArgs: function( fn ) {
- var args,
- l = fn.length;
-
- if ( !l ) {
- return "";
- }
-
- args = new Array(l);
- while ( l-- ) {
- // 97 is 'a'
- args[l] = String.fromCharCode(97+l);
- }
- return " " + args.join( ", " ) + " ";
- },
- // object calls it internally, the key part of an item in a map
- key: quote,
- // function calls it internally, it's the content of the function
- functionCode: "[code]",
- // node calls it internally, it's an html attribute value
- attribute: quote,
- string: quote,
- date: quote,
- regexp: literal,
- number: literal,
- "boolean": literal
- },
- // if true, entities are escaped ( <, >, \t, space and \n )
- HTML: false,
- // indentation unit
- indentChar: " ",
- // if true, items in a collection, are separated by a \n, else just a space.
- multiline: true
- };
-
- return jsDump;
-}());
-
-// from jquery.js
-function inArray( elem, array ) {
- if ( array.indexOf ) {
- return array.indexOf( elem );
- }
-
- for ( var i = 0, length = array.length; i < length; i++ ) {
- if ( array[ i ] === elem ) {
- return i;
- }
- }
-
- return -1;
-}
-
-/*
- * Javascript Diff Algorithm
- * By John Resig (http://ejohn.org/)
- * Modified by Chu Alan "sprite"
- *
- * Released under the MIT license.
- *
- * More Info:
- * http://ejohn.org/projects/javascript-diff-algorithm/
- *
- * Usage: QUnit.diff(expected, actual)
- *
- * QUnit.diff( "the quick brown fox jumped over", "the quick fox jumps over" ) == "the quick brown fox jumped jumps over"
- */
-QUnit.diff = (function() {
- /*jshint eqeqeq:false, eqnull:true */
- function diff( o, n ) {
- var i,
- ns = {},
- os = {};
-
- for ( i = 0; i < n.length; i++ ) {
- if ( !hasOwn.call( ns, n[i] ) ) {
- ns[ n[i] ] = {
- rows: [],
- o: null
- };
- }
- ns[ n[i] ].rows.push( i );
- }
-
- for ( i = 0; i < o.length; i++ ) {
- if ( !hasOwn.call( os, o[i] ) ) {
- os[ o[i] ] = {
- rows: [],
- n: null
- };
- }
- os[ o[i] ].rows.push( i );
- }
-
- for ( i in ns ) {
- if ( !hasOwn.call( ns, i ) ) {
- continue;
- }
- if ( ns[i].rows.length === 1 && hasOwn.call( os, i ) && os[i].rows.length === 1 ) {
- n[ ns[i].rows[0] ] = {
- text: n[ ns[i].rows[0] ],
- row: os[i].rows[0]
- };
- o[ os[i].rows[0] ] = {
- text: o[ os[i].rows[0] ],
- row: ns[i].rows[0]
- };
- }
- }
-
- for ( i = 0; i < n.length - 1; i++ ) {
- if ( n[i].text != null && n[ i + 1 ].text == null && n[i].row + 1 < o.length && o[ n[i].row + 1 ].text == null &&
- n[ i + 1 ] == o[ n[i].row + 1 ] ) {
-
- n[ i + 1 ] = {
- text: n[ i + 1 ],
- row: n[i].row + 1
- };
- o[ n[i].row + 1 ] = {
- text: o[ n[i].row + 1 ],
- row: i + 1
- };
- }
- }
-
- for ( i = n.length - 1; i > 0; i-- ) {
- if ( n[i].text != null && n[ i - 1 ].text == null && n[i].row > 0 && o[ n[i].row - 1 ].text == null &&
- n[ i - 1 ] == o[ n[i].row - 1 ]) {
-
- n[ i - 1 ] = {
- text: n[ i - 1 ],
- row: n[i].row - 1
- };
- o[ n[i].row - 1 ] = {
- text: o[ n[i].row - 1 ],
- row: i - 1
- };
- }
- }
-
- return {
- o: o,
- n: n
- };
- }
-
- return function( o, n ) {
- o = o.replace( /\s+$/, "" );
- n = n.replace( /\s+$/, "" );
-
- var i, pre,
- str = "",
- out = diff( o === "" ? [] : o.split(/\s+/), n === "" ? [] : n.split(/\s+/) ),
- oSpace = o.match(/\s+/g),
- nSpace = n.match(/\s+/g);
-
- if ( oSpace == null ) {
- oSpace = [ " " ];
- }
- else {
- oSpace.push( " " );
- }
-
- if ( nSpace == null ) {
- nSpace = [ " " ];
- }
- else {
- nSpace.push( " " );
- }
-
- if ( out.n.length === 0 ) {
- for ( i = 0; i < out.o.length; i++ ) {
- str += "" + out.o[i] + oSpace[i] + "";
- }
- }
- else {
- if ( out.n[0].text == null ) {
- for ( n = 0; n < out.o.length && out.o[n].text == null; n++ ) {
- str += "" + out.o[n] + oSpace[n] + "";
- }
- }
-
- for ( i = 0; i < out.n.length; i++ ) {
- if (out.n[i].text == null) {
- str += "" + out.n[i] + nSpace[i] + "";
- }
- else {
- // `pre` initialized at top of scope
- pre = "";
-
- for ( n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++ ) {
- pre += "" + out.o[n] + oSpace[n] + "";
- }
- str += " " + out.n[i].text + nSpace[i] + pre;
- }
- }
- }
-
- return str;
- };
-}());
-
-// for CommonJS enviroments, export everything
-if ( typeof exports !== "undefined" ) {
- extend( exports, QUnit );
-}
-
-// get at whatever the global object is, like window in browsers
-}( (function() {return this;}.call()) ));
diff --git a/test/lib/require.js b/test/lib/require.js
deleted file mode 100644
index 987f865..0000000
--- a/test/lib/require.js
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- RequireJS 2.1.5 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.
- Available via the MIT or new BSD license.
- see: http://github.com/jrburke/requirejs for details
-*/
-var requirejs,require,define;
-(function(aa){function I(b){return"[object Function]"===L.call(b)}function J(b){return"[object Array]"===L.call(b)}function y(b,c){if(b){var d;for(d=0;dthis.depCount&&!this.defined){if(I(n)){if(this.events.error)try{e=i.execCb(c,n,b,e)}catch(d){a=d}else e=i.execCb(c,n,b,e);this.map.isDefine&&((b=this.module)&&void 0!==b.exports&&b.exports!==this.exports?e=b.exports:void 0===e&&this.usingExports&&(e=this.exports));if(a)return a.requireMap=this.map,a.requireModules=[this.map.id],a.requireType="define",v(this.error=
-a)}else e=n;this.exports=e;if(this.map.isDefine&&!this.ignore&&(q[c]=e,l.onResourceLoad))l.onResourceLoad(i,this.map,this.depMaps);x(c);this.defined=!0}this.defining=!1;this.defined&&!this.defineEmitted&&(this.defineEmitted=!0,this.emit("defined",this.exports),this.defineEmitComplete=!0)}}else this.fetch()}},callPlugin:function(){var a=this.map,b=a.id,d=j(a.prefix);this.depMaps.push(d);t(d,"defined",u(this,function(e){var n,d;d=this.map.name;var g=this.map.parentMap?this.map.parentMap.name:null,h=
-i.makeRequire(a.parentMap,{enableBuildCallback:!0});if(this.map.unnormalized){if(e.normalize&&(d=e.normalize(d,function(a){return c(a,g,!0)})||""),e=j(a.prefix+"!"+d,this.map.parentMap),t(e,"defined",u(this,function(a){this.init([],function(){return a},null,{enabled:!0,ignore:!0})})),d=m(p,e.id)){this.depMaps.push(e);if(this.events.error)d.on("error",u(this,function(a){this.emit("error",a)}));d.enable()}}else n=u(this,function(a){this.init([],function(){return a},null,{enabled:!0})}),n.error=u(this,
-function(a){this.inited=!0;this.error=a;a.requireModules=[b];G(p,function(a){0===a.map.id.indexOf(b+"_unnormalized")&&x(a.map.id)});v(a)}),n.fromText=u(this,function(e,c){var d=a.name,g=j(d),C=O;c&&(e=c);C&&(O=!1);r(g);s(k.config,b)&&(k.config[d]=k.config[b]);try{l.exec(e)}catch(ca){return v(B("fromtexteval","fromText eval for "+b+" failed: "+ca,ca,[b]))}C&&(O=!0);this.depMaps.push(g);i.completeLoad(d);h([d],n)}),e.load(a.name,h,n,k)}));i.enable(d,this);this.pluginMaps[d.id]=d},enable:function(){V[this.map.id]=
-this;this.enabling=this.enabled=!0;y(this.depMaps,u(this,function(a,b){var c,e;if("string"===typeof a){a=j(a,this.map.isDefine?this.map:this.map.parentMap,!1,!this.skipMap);this.depMaps[b]=a;if(c=m(N,a.id)){this.depExports[b]=c(this);return}this.depCount+=1;t(a,"defined",u(this,function(a){this.defineDep(b,a);this.check()}));this.errback&&t(a,"error",this.errback)}c=a.id;e=p[c];!s(N,c)&&(e&&!e.enabled)&&i.enable(a,this)}));G(this.pluginMaps,u(this,function(a){var b=m(p,a.id);b&&!b.enabled&&i.enable(a,
-this)}));this.enabling=!1;this.check()},on:function(a,b){var c=this.events[a];c||(c=this.events[a]=[]);c.push(b)},emit:function(a,b){y(this.events[a],function(a){a(b)});"error"===a&&delete this.events[a]}};i={config:k,contextName:b,registry:p,defined:q,urlFetched:U,defQueue:H,Module:Z,makeModuleMap:j,nextTick:l.nextTick,onError:v,configure:function(a){a.baseUrl&&"/"!==a.baseUrl.charAt(a.baseUrl.length-1)&&(a.baseUrl+="/");var b=k.pkgs,c=k.shim,e={paths:!0,config:!0,map:!0};G(a,function(a,b){e[b]?
-"map"===b?(k.map||(k.map={}),R(k[b],a,!0,!0)):R(k[b],a,!0):k[b]=a});a.shim&&(G(a.shim,function(a,b){J(a)&&(a={deps:a});if((a.exports||a.init)&&!a.exportsFn)a.exportsFn=i.makeShimExports(a);c[b]=a}),k.shim=c);a.packages&&(y(a.packages,function(a){a="string"===typeof a?{name:a}:a;b[a.name]={name:a.name,location:a.location||a.name,main:(a.main||"main").replace(ja,"").replace(ea,"")}}),k.pkgs=b);G(p,function(a,b){!a.inited&&!a.map.unnormalized&&(a.map=j(b))});if(a.deps||a.callback)i.require(a.deps||[],
-a.callback)},makeShimExports:function(a){return function(){var b;a.init&&(b=a.init.apply(aa,arguments));return b||a.exports&&ba(a.exports)}},makeRequire:function(a,f){function d(e,c,h){var g,k;f.enableBuildCallback&&(c&&I(c))&&(c.__requireJsBuild=!0);if("string"===typeof e){if(I(c))return v(B("requireargs","Invalid require call"),h);if(a&&s(N,e))return N[e](p[a.id]);if(l.get)return l.get(i,e,a,d);g=j(e,a,!1,!0);g=g.id;return!s(q,g)?v(B("notloaded",'Module name "'+g+'" has not been loaded yet for context: '+
-b+(a?"":". Use require([])"))):q[g]}L();i.nextTick(function(){L();k=r(j(null,a));k.skipMap=f.skipMap;k.init(e,c,h,{enabled:!0});D()});return d}f=f||{};R(d,{isBrowser:A,toUrl:function(b){var d,f=b.lastIndexOf("."),g=b.split("/")[0];if(-1!==f&&(!("."===g||".."===g)||1h.attachEvent.toString().indexOf("[native code"))&&!Y?(O=!0,h.attachEvent("onreadystatechange",b.onScriptLoad)):(h.addEventListener("load",b.onScriptLoad,!1),h.addEventListener("error",b.onScriptError,!1)),h.src=d,K=h,D?x.insertBefore(h,D):x.appendChild(h),K=null,h;if(da)try{importScripts(d),b.completeLoad(c)}catch(j){b.onError(B("importscripts","importScripts failed for "+c+" at "+d,j,[c]))}};A&&M(document.getElementsByTagName("script"),function(b){x||(x=
-b.parentNode);if(t=b.getAttribute("data-main"))return r.baseUrl||(E=t.split("/"),Q=E.pop(),fa=E.length?E.join("/")+"/":"./",r.baseUrl=fa,t=Q),t=t.replace(ea,""),r.deps=r.deps?r.deps.concat(t):[t],!0});define=function(b,c,d){var l,h;"string"!==typeof b&&(d=c,c=b,b=null);J(c)||(d=c,c=[]);!c.length&&I(d)&&d.length&&(d.toString().replace(la,"").replace(ma,function(b,d){c.push(d)}),c=(1===d.length?["require"]:["require","exports","module"]).concat(c));if(O){if(!(l=K))P&&"interactive"===P.readyState||M(document.getElementsByTagName("script"),
-function(b){if("interactive"===b.readyState)return P=b}),l=P;l&&(b||(b=l.getAttribute("data-requiremodule")),h=F[l.getAttribute("data-requirecontext")])}(h?h.defQueue:T).push([b,c,d])};define.amd={jQuery:!0};l.exec=function(b){return eval(b)};l(r)}})(this);
diff --git a/test/lib/resemble.js b/test/lib/resemble.js
new file mode 100644
index 0000000..1cb8c29
--- /dev/null
+++ b/test/lib/resemble.js
@@ -0,0 +1,535 @@
+/*
+Author: James Cryer
+Company: Huddle
+Last updated date: 21 Feb 2013
+URL: https://github.com/Huddle/Resemble.js
+*/
+
+(function(_this){
+ 'use strict';
+
+ _this['resemble'] = function( fileData ){
+
+ var data = {};
+ var images = [];
+ var updateCallbackArray = [];
+
+ var tolerance = { // between 0 and 255
+ red: 16,
+ green: 16,
+ blue: 16,
+ minBrightness: 16,
+ maxBrightness: 240
+ };
+
+ var ignoreAntialiasing = false;
+ var ignoreColors = false;
+
+ function triggerDataUpdate(){
+ var len = updateCallbackArray.length;
+ var i;
+ for(i=0;i tolerance.maxBrightness;
+ }
+
+ function getHue(r,g,b){
+
+ r = r / 255;
+ g = g / 255;
+ b = b / 255;
+ var max = Math.max(r, g, b), min = Math.min(r, g, b);
+ var h;
+ var d;
+
+ if (max == min){
+ h = 0; // achromatic
+ } else{
+ d = max - min;
+ switch(max){
+ case r: h = (g - b) / d + (g < b ? 6 : 0); break;
+ case g: h = (b - r) / d + 2; break;
+ case b: h = (r - g) / d + 4; break;
+ }
+ h /= 6;
+ }
+
+ return h;
+ }
+
+ function isAntialiased(sourcePix, data, cacheSet, verticalPos, horizontalPos, width){
+ var offset;
+ var targetPix;
+ var distance = 1;
+ var i;
+ var j;
+ var hasHighContrastSibling = 0;
+ var hasSiblingWithDifferentHue = 0;
+ var hasEquivilantSibling = 0;
+
+ addHueInfo(sourcePix);
+
+ for (i = distance*-1; i <= distance; i++){
+ for (j = distance*-1; j <= distance; j++){
+
+ if(i===0 && j===0){
+ // ignore source pixel
+ } else {
+
+ offset = ((verticalPos+j)*width + (horizontalPos+i)) * 4;
+ targetPix = getPixelInfo(data, offset, cacheSet);
+
+ if(targetPix === null){
+ continue;
+ }
+
+ addBrightnessInfo(targetPix);
+ addHueInfo(targetPix);
+
+ if( isContrasting(sourcePix, targetPix) ){
+ hasHighContrastSibling++;
+ }
+
+ if( isRGBSame(sourcePix,targetPix) ){
+ hasEquivilantSibling++;
+ }
+
+ if( Math.abs(targetPix.h - sourcePix.h) > 0.3 ){
+ hasSiblingWithDifferentHue++;
+ }
+
+ if( hasSiblingWithDifferentHue > 1 || hasHighContrastSibling > 1){
+ return true;
+ }
+ }
+ }
+ }
+
+ if(hasEquivilantSibling < 2){
+ return true;
+ }
+
+ return false;
+ }
+
+ function errorPixel(px, offset){
+ px[offset] = 255; //r
+ px[offset + 1] = 0; //g
+ px[offset + 2] = 255; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyPixel(px, offset, data){
+ px[offset] = data.r; //r
+ px[offset + 1] = data.g; //g
+ px[offset + 2] = data.b; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyGrayScalePixel(px, offset, data){
+ px[offset] = data.brightness; //r
+ px[offset + 1] = data.brightness; //g
+ px[offset + 2] = data.brightness; //b
+ px[offset + 3] = 255; //a
+ }
+
+
+ function getPixelInfo(data, offset, cacheSet){
+ var r;
+ var g;
+ var b;
+ var d;
+
+ if(typeof data[offset] !== 'undefined'){
+ r = data[offset];
+ g = data[offset+1];
+ b = data[offset+2];
+ d = {
+ r: r,
+ g: g,
+ b: b
+ };
+
+ return d;
+ } else {
+ return null;
+ }
+ }
+
+ function addBrightnessInfo(data){
+ data.brightness = getBrightness(data.r,data.g,data.b); // 'corrected' lightness
+ }
+
+ function addHueInfo(data){
+ data.h = getHue(data.r,data.g,data.b);
+ }
+
+ function analyseImages(img1, img2, width, height){
+
+ var hiddenCanvas = document.createElement('canvas');
+
+ var data1 = img1.data;
+ var data2 = img2.data;
+
+ hiddenCanvas.width = width;
+ hiddenCanvas.height = height;
+
+ var context = hiddenCanvas.getContext('2d');
+ var imgd = context.createImageData(width,height);
+ var targetPix = imgd.data;
+
+ var mismatchCount = 0;
+
+ var time = Date.now();
+
+ var skip;
+
+ if( (width > 1200 || height > 1200) && ignoreAntialiasing){
+ skip = 6;
+ }
+
+ loop(height, width, function(verticalPos, horizontalPos){
+
+ if(skip){ // only skip if the image isn't small
+ if(verticalPos % skip === 0 || horizontalPos % skip === 0){
+ return;
+ }
+ }
+
+ var offset = (verticalPos*width + horizontalPos) * 4;
+ var pixel1 = getPixelInfo(data1, offset, 1);
+ var pixel2 = getPixelInfo(data2, offset, 2);
+
+ if(pixel1 === null || pixel2 === null){
+ return;
+ }
+
+ if (ignoreColors){
+
+ addBrightnessInfo(pixel1);
+ addBrightnessInfo(pixel2);
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ return;
+ }
+
+ if( isRGBSimilar(pixel1, pixel2) ){
+ copyPixel(targetPix, offset, pixel2);
+
+ } else if( ignoreAntialiasing && (
+ addBrightnessInfo(pixel1), // jit pixel info augmentation looks a little weird, sorry.
+ addBrightnessInfo(pixel2),
+ isAntialiased(pixel1, data1, 1, verticalPos, horizontalPos, width) ||
+ isAntialiased(pixel2, data2, 2, verticalPos, horizontalPos, width)
+ )){
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+
+ });
+
+ data.misMatchPercentage = (mismatchCount / (height*width) * 100).toFixed(2);
+ data.analysisTime = Date.now() - time;
+
+ data.getImageDataUrl = function(text){
+ var barHeight = 0;
+
+ if(text){
+ barHeight = addLabel(text,context,hiddenCanvas);
+ }
+
+ context.putImageData(imgd, 0, barHeight);
+
+ return hiddenCanvas.toDataURL("image/png");
+ };
+ }
+
+ function addLabel(text, context, hiddenCanvas){
+ var textPadding = 2;
+
+ context.font = '12px sans-serif';
+
+ var textWidth = context.measureText(text).width + textPadding*2;
+ var barHeight = 22;
+
+ if(textWidth > hiddenCanvas.width){
+ hiddenCanvas.width = textWidth;
+ }
+
+ hiddenCanvas.height += barHeight;
+
+ context.fillStyle = "#666";
+ context.fillRect(0,0,hiddenCanvas.width,barHeight -4);
+ context.fillStyle = "#fff";
+ context.fillRect(0,barHeight -4,hiddenCanvas.width, 4);
+
+ context.fillStyle = "#fff";
+ context.textBaseline = "top";
+ context.font = '12px sans-serif';
+ context.fillText(text, textPadding, 1);
+
+ return barHeight;
+ }
+
+ function normalise(img, w, h){
+ var c;
+ var context;
+
+ if(img.height < h || img.width < w){
+ c = document.createElement('canvas');
+ c.width = w;
+ c.height = h;
+ context = c.getContext('2d');
+ context.putImageData(img, 0, 0);
+ return context.getImageData(0, 0, w, h);
+ }
+
+ return img;
+ }
+
+ function compare(one, two){
+
+ function onceWeHaveBoth(){
+ var width;
+ var height;
+ if(images.length === 2){
+ width = images[0].width > images[1].width ? images[0].width : images[1].width;
+ height = images[0].height > images[1].height ? images[0].height : images[1].height;
+
+ if( (images[0].width === images[1].width) && (images[0].height === images[1].height) ){
+ data.isSameDimensions = true;
+ } else {
+ data.isSameDimensions = false;
+ }
+
+ analyseImages( normalise(images[0],width, height), normalise(images[1],width, height), width, height);
+
+ triggerDataUpdate();
+ }
+ }
+
+ images = [];
+ loadImageData(one, onceWeHaveBoth);
+ loadImageData(two, onceWeHaveBoth);
+ }
+
+ function getCompareApi(param){
+
+ var secondFileData,
+ hasMethod = typeof param === 'function';
+
+ if( !hasMethod ){
+ // assume it's file data
+ secondFileData = param;
+ }
+
+ var self = {
+ ignoreNothing: function(){
+
+ tolerance.red = 16;
+ tolerance.green = 16;
+ tolerance.blue = 16;
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreAntialiasing: function(){
+
+ tolerance.red = 32;
+ tolerance.green = 32;
+ tolerance.blue = 32;
+ tolerance.minBrightness = 64;
+ tolerance.maxBrightness = 96;
+
+ ignoreAntialiasing = true;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreColors: function(){
+
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = true;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ onComplete: function( callback ){
+
+ updateCallbackArray.push(callback);
+
+ var wrapper = function(){
+ compare(fileData, secondFileData);
+ };
+
+ wrapper();
+
+ return getCompareApi(wrapper);
+ }
+ };
+
+ return self;
+ }
+
+ return {
+ onComplete: function( callback ){
+ updateCallbackArray.push(callback);
+ loadImageData(fileData, function(imageData, width, height){
+ parseImage(imageData.data, width, height);
+ });
+ },
+ compareTo: function(secondFileData){
+ return getCompareApi(secondFileData);
+ }
+ };
+
+ };
+}(this));
\ No newline at end of file
diff --git a/test/testsuite.js b/test/testsuite.js
deleted file mode 100644
index b486acb..0000000
--- a/test/testsuite.js
+++ /dev/null
@@ -1,36 +0,0 @@
-requirejs.config({
- baseUrl: '/test/unit/'
-});
-
-define(function(require) {
- var testModules = [
- 'Pixi',
- 'Point',
- 'Rectangle',
- 'DisplayObject',
- 'DisplayObjectContainer',
- 'Sprite',
- 'MovieClip',
- 'InteractionManager',
- 'Stage',
- 'utils/Utils',
- 'utils/EventTarget',
- 'utils/Matrix',
- 'utils/Detector',
- 'renderers/WebGLShaders',
- 'renderers/WebGLRenderer',
- 'renderers/WebGLBatch',
- 'renderers/CanvasRenderer',
- 'extras/Strip',
- 'extras/Rope',
- 'textures/BaseTexture',
- 'textures/Texture',
- 'loaders/SpriteSheetLoader',
- 'loaders/AssetLoader'
- ];
-
- // Resolve all testModules and then start the Test Runner.
- require(testModules, function() {
- QUnit.start();
- });
-});
\ No newline at end of file
diff --git a/test/textures/SpriteSheet-Aliens.png b/test/textures/SpriteSheet-Aliens.png
new file mode 100644
index 0000000..210acb1
--- /dev/null
+++ b/test/textures/SpriteSheet-Aliens.png
Binary files differ
diff --git a/test/textures/SpriteSheet-Explosion.png b/test/textures/SpriteSheet-Explosion.png
new file mode 100755
index 0000000..79e1a69
--- /dev/null
+++ b/test/textures/SpriteSheet-Explosion.png
Binary files differ
diff --git a/test/textures/bunny.png b/test/textures/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/textures/bunny.png
Binary files differ
diff --git a/test/unit/DisplayObject.js b/test/unit/DisplayObject.js
deleted file mode 100644
index 5e7e72f..0000000
--- a/test/unit/DisplayObject.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObject');
-});
diff --git a/test/unit/DisplayObjectContainer.js b/test/unit/DisplayObjectContainer.js
deleted file mode 100644
index b323959..0000000
--- a/test/unit/DisplayObjectContainer.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObjectContainer');
-});
diff --git a/test/unit/InteractionManager.js b/test/unit/InteractionManager.js
deleted file mode 100644
index e751f52..0000000
--- a/test/unit/InteractionManager.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('InteractionManager');
-});
diff --git a/test/unit/MovieClip.js b/test/unit/MovieClip.js
deleted file mode 100644
index 37d9446..0000000
--- a/test/unit/MovieClip.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('MovieClip');
-});
diff --git a/test/unit/Pixi.js b/test/unit/Pixi.js
deleted file mode 100644
index 36eee73..0000000
--- a/test/unit/Pixi.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Pixi');
-});
diff --git a/test/unit/Point.js b/test/unit/Point.js
deleted file mode 100644
index 983ff6e..0000000
--- a/test/unit/Point.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Point');
-});
diff --git a/test/unit/Rectangle.js b/test/unit/Rectangle.js
deleted file mode 100644
index 3b439ba..0000000
--- a/test/unit/Rectangle.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Rectangle');
-});
diff --git a/test/unit/Sprite.js b/test/unit/Sprite.js
deleted file mode 100644
index ed4f596..0000000
--- a/test/unit/Sprite.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Sprite');
-});
diff --git a/test/unit/Stage.js b/test/unit/Stage.js
deleted file mode 100644
index 2d70291..0000000
--- a/test/unit/Stage.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Stage');
-});
diff --git a/test/unit/extras/Rope.js b/test/unit/extras/Rope.js
deleted file mode 100644
index 5606f14..0000000
--- a/test/unit/extras/Rope.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Rope');
-});
diff --git a/test/unit/extras/Strip.js b/test/unit/extras/Strip.js
deleted file mode 100644
index 0134d3a..0000000
--- a/test/unit/extras/Strip.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Strip');
-});
diff --git a/test/unit/loaders/AssetLoader.js b/test/unit/loaders/AssetLoader.js
deleted file mode 100644
index 13b8443..0000000
--- a/test/unit/loaders/AssetLoader.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('AssetLoader');
-});
diff --git a/test/unit/loaders/SpriteSheetLoader.js b/test/unit/loaders/SpriteSheetLoader.js
deleted file mode 100644
index 8bf0cb2..0000000
--- a/test/unit/loaders/SpriteSheetLoader.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('SpriteSheetLoader');
-});
diff --git a/test/unit/pixi/InteractionManager.js b/test/unit/pixi/InteractionManager.js
new file mode 100644
index 0000000..ed3001f
--- /dev/null
+++ b/test/unit/pixi/InteractionManager.js
@@ -0,0 +1,10 @@
+describe('pixi/InteractionManager', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var InteractionManager = PIXI.InteractionManager;
+
+ it('Module exists', function () {
+ expect(InteractionManager).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/Pixi.js b/test/unit/pixi/Pixi.js
new file mode 100644
index 0000000..27debc1
--- /dev/null
+++ b/test/unit/pixi/Pixi.js
@@ -0,0 +1,9 @@
+describe('pixi/Pixi', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+
+ it('Module exists', function () {
+ expect(global).to.have.property('PIXI').and.to.be.an('object');
+ });
+});
diff --git a/test/unit/pixi/core/Circle.js b/test/unit/pixi/core/Circle.js
new file mode 100644
index 0000000..93a4456
--- /dev/null
+++ b/test/unit/pixi/core/Circle.js
@@ -0,0 +1,22 @@
+describe('pixi/core/Circle', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Circle = PIXI.Circle;
+
+ it('Module exists', function () {
+ expect(Circle).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Circle();
+
+ expect(obj).to.be.an.instanceof(Circle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', 0);
+ expect(obj).to.have.property('y', 0);
+ expect(obj).to.have.property('radius', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Ellipse.js b/test/unit/pixi/core/Ellipse.js
new file mode 100644
index 0000000..026b56f
--- /dev/null
+++ b/test/unit/pixi/core/Ellipse.js
@@ -0,0 +1,24 @@
+describe('pixi/core/Ellipse', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Ellipse = PIXI.Ellipse;
+
+ it('Module exists', function () {
+ expect(Ellipse).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Ellipse();
+
+ expect(obj).to.be.an.instanceof(Ellipse);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+ expect(obj).to.respondTo('getBounds');
+
+ expect(obj).to.have.property('x', 0);
+ expect(obj).to.have.property('y', 0);
+ expect(obj).to.have.property('width', 0);
+ expect(obj).to.have.property('height', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Matrix.js b/test/unit/pixi/core/Matrix.js
new file mode 100644
index 0000000..b48989e
--- /dev/null
+++ b/test/unit/pixi/core/Matrix.js
@@ -0,0 +1,30 @@
+describe('pixi/core/Matrix', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var mat3 = PIXI.mat3;
+ var mat4 = PIXI.mat4;
+ var Matrix = PIXI.Matrix;
+
+ it('Ensure determineMatrixArrayType works', function () {
+ expect(Matrix).to.be.a('function');
+ });
+
+ it('mat3 exists', function () {
+ expect(mat3).to.be.an('object');
+ });
+
+ it('Confirm new mat3 matrix', function () {
+ var matrix = new mat3.create();
+ pixi_core_Matrix_confirmNewMat3(matrix);
+ });
+
+ it('mat3 exists', function () {
+ expect(mat4).to.be.an('object');
+ });
+
+ it('Confirm new mat4 matrix', function () {
+ var matrix = new mat4.create();
+ pixi_core_Matrix_confirmNewMat4(matrix);
+ });
+});
diff --git a/test/unit/pixi/core/Point.js b/test/unit/pixi/core/Point.js
new file mode 100644
index 0000000..c4d5163
--- /dev/null
+++ b/test/unit/pixi/core/Point.js
@@ -0,0 +1,15 @@
+describe('pixi/core/Point', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Point = PIXI.Point;
+
+ it('Module exists', function () {
+ expect(Point).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Point();
+ pixi_core_Point_confirm(obj, 0, 0);
+ });
+});
diff --git a/test/unit/pixi/core/Polygon.js b/test/unit/pixi/core/Polygon.js
new file mode 100644
index 0000000..dc8c918
--- /dev/null
+++ b/test/unit/pixi/core/Polygon.js
@@ -0,0 +1,20 @@
+describe('pixi/core/Polygon', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Polygon = PIXI.Polygon;
+
+ it('Module exists', function () {
+ expect(Polygon).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Polygon();
+
+ expect(obj).to.be.an.instanceof(Polygon);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.deep.property('points.length', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Rectangle.js b/test/unit/pixi/core/Rectangle.js
new file mode 100644
index 0000000..d43316e
--- /dev/null
+++ b/test/unit/pixi/core/Rectangle.js
@@ -0,0 +1,15 @@
+describe('pixi/core/Rectangle', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Rectangle = PIXI.Rectangle;
+
+ it('Module exists', function () {
+ expect(Rectangle).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var rect = new Rectangle();
+ pixi_core_Rectangle_confirm(rect, 0, 0, 0, 0);
+ });
+});
diff --git a/test/unit/pixi/display/DisplayObject.js b/test/unit/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..40c6fbc
--- /dev/null
+++ b/test/unit/pixi/display/DisplayObject.js
@@ -0,0 +1,21 @@
+describe('pixi/display/DisplayObject', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var DisplayObject = PIXI.DisplayObject;
+
+ it('Module exists', function () {
+ expect(DisplayObject).to.be.a('function');
+ expect(PIXI).to.have.property('visibleCount', 0);
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new DisplayObject();
+
+ pixi_display_DisplayObject_confirmNew(obj);
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', false);
+ expect(obj).to.have.property('stage', null);
+ });
+});
diff --git a/test/unit/pixi/display/DisplayObjectContainer.js b/test/unit/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..ce7f02f
--- /dev/null
+++ b/test/unit/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,20 @@
+describe('pixi/display/DisplayObjectContainer', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var DisplayObjectContainer = PIXI.DisplayObjectContainer;
+
+ it('Module exists', function () {
+ expect(DisplayObjectContainer).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new DisplayObjectContainer();
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', false);
+ expect(obj).to.have.property('stage', null);
+ });
+});
diff --git a/test/unit/pixi/display/MovieClip.js b/test/unit/pixi/display/MovieClip.js
new file mode 100644
index 0000000..f3c6c6a
--- /dev/null
+++ b/test/unit/pixi/display/MovieClip.js
@@ -0,0 +1,33 @@
+describe('pixi/display/MovieClip', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var MovieClip = PIXI.MovieClip;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(MovieClip).to.be.a('function');
+ });
+
+ it('Confirm new instance', function (done) {
+ var texture = Texture.fromImage('/base/test/textures/SpriteSheet-Explosion.png');
+ var obj = new MovieClip([texture]);
+
+ pixi_display_Sprite_confirmNew(obj, done);
+
+ expect(obj).to.be.an.instanceof(MovieClip);
+ expect(obj).to.respondTo('stop');
+ expect(obj).to.respondTo('play');
+ expect(obj).to.respondTo('gotoAndStop');
+ expect(obj).to.respondTo('gotoAndPlay');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('textures.length', 1);
+ expect(obj).to.have.deep.property('textures[0]', texture);
+ expect(obj).to.have.property('animationSpeed', 1);
+ expect(obj).to.have.property('loop', true);
+ expect(obj).to.have.property('onComplete', null);
+ expect(obj).to.have.property('currentFrame', 0);
+ expect(obj).to.have.property('playing', false);
+ });
+});
diff --git a/test/unit/pixi/display/Sprite.js b/test/unit/pixi/display/Sprite.js
new file mode 100644
index 0000000..54e914f
--- /dev/null
+++ b/test/unit/pixi/display/Sprite.js
@@ -0,0 +1,25 @@
+describe('pixi/display/Sprite', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Sprite = PIXI.Sprite;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(Sprite).to.be.a('function');
+ expect(PIXI).to.have.deep.property('blendModes.NORMAL', 0);
+ expect(PIXI).to.have.deep.property('blendModes.SCREEN', 1);
+ });
+
+ it('Members exist', function () {
+ expect(Sprite).itself.to.respondTo('fromImage');
+ expect(Sprite).itself.to.respondTo('fromFrame');
+ });
+
+ it('Confirm new instance', function (done) {
+ var texture = Texture.fromImage('/base/test/textures/SpriteSheet-Aliens.png');
+ var obj = new Sprite(texture);
+
+ pixi_display_Sprite_confirmNew(obj, done);
+ });
+});
diff --git a/test/unit/pixi/display/Stage.js b/test/unit/pixi/display/Stage.js
new file mode 100644
index 0000000..3cc2a4d
--- /dev/null
+++ b/test/unit/pixi/display/Stage.js
@@ -0,0 +1,49 @@
+describe('pixi/display/Stage', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Stage = PIXI.Stage;
+ var InteractionManager = PIXI.InteractionManager;
+ var Rectangle = PIXI.Rectangle;
+
+ it('Module exists', function () {
+ expect(Stage).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Stage(null, true);
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(Stage);
+ expect(obj).to.respondTo('updateTransform');
+ expect(obj).to.respondTo('setBackgroundColor');
+ expect(obj).to.respondTo('getMousePosition');
+
+ // FIXME: duplicate member in DisplayObject
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ // FIXME: convert arg to bool in constructor
+ expect(obj).to.have.property('interactive', true);
+
+ expect(obj).to.have.property('interactionManager')
+ .and.to.be.an.instanceof(InteractionManager)
+ .and.to.have.property('stage', obj);
+
+ expect(obj).to.have.property('dirty', true);
+
+ expect(obj).to.have.property('stage', obj);
+
+ expect(obj).to.have.property('hitArea')
+ .and.to.be.an.instanceof(Rectangle);
+ pixi_core_Rectangle_confirm(obj.hitArea, 0, 0, 100000, 100000);
+
+ expect(obj).to.have.property('backgroundColor', 0x000000);
+ expect(obj).to.have.deep.property('backgroundColorSplit.length', 3);
+ expect(obj).to.have.deep.property('backgroundColorSplit[0]', 0);
+ expect(obj).to.have.deep.property('backgroundColorSplit[1]', 0);
+ expect(obj).to.have.deep.property('backgroundColorSplit[2]', 0);
+ expect(obj).to.have.property('backgroundColorString', '#000000');
+
+ expect(obj).to.have.property('worldVisible', true);
+ });
+});
diff --git a/test/unit/pixi/extras/CustomRenderable.js b/test/unit/pixi/extras/CustomRenderable.js
new file mode 100644
index 0000000..8d83cf0
--- /dev/null
+++ b/test/unit/pixi/extras/CustomRenderable.js
@@ -0,0 +1,21 @@
+describe('pixi/extras/CustomRenderable', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var CustomRenderable = PIXI.CustomRenderable;
+
+ it('Module exists', function () {
+ expect(CustomRenderable).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new CustomRenderable();
+
+ pixi_display_DisplayObject_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(CustomRenderable);
+ expect(obj).to.respondTo('renderCanvas');
+ expect(obj).to.respondTo('initWebGL');
+ expect(obj).to.respondTo('renderWebGL');
+ });
+});
diff --git a/test/unit/pixi/extras/Rope.js b/test/unit/pixi/extras/Rope.js
new file mode 100644
index 0000000..6ddaf83
--- /dev/null
+++ b/test/unit/pixi/extras/Rope.js
@@ -0,0 +1,26 @@
+describe('pixi/extras/Rope', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Rope = PIXI.Rope;
+ var Texture = PIXI.Texture;
+ var Point = PIXI.Point;
+
+ it('Module exists', function () {
+ expect(Rope).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var texture = Texture.fromImage('/base/test/textures/bunny.png');
+ var obj = new Rope(texture, [new Point(), new Point(5, 10), new Point(10, 20)]);
+
+ pixi_extras_Strip_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(Rope);
+ expect(obj).to.respondTo('refresh');
+ expect(obj).to.respondTo('updateTransform');
+ expect(obj).to.respondTo('setTexture');
+
+ // TODO: Test properties
+ });
+});
diff --git a/test/unit/pixi/extras/Spine.js b/test/unit/pixi/extras/Spine.js
new file mode 100644
index 0000000..0708bc0
--- /dev/null
+++ b/test/unit/pixi/extras/Spine.js
@@ -0,0 +1,10 @@
+describe('pixi/extras/Spine', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Spine = PIXI.Spine;
+
+ it('Module exists', function () {
+ expect(Spine).to.be.a('function');
+ });
+});
diff --git a/.gitignore b/.gitignore
index 12e1b62..0b88317 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
node_modules
.DS_Store
-.project
\ No newline at end of file
+.project
+*.log
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..63e4d7c
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,8 @@
+language: node_js
+node_js:
+ - 0.10
+
+before_script:
+ - npm install -g grunt-cli
+ - export DISPLAY=:99.0
+ - sh -e /etc/init.d/xvfb start
diff --git a/Gruntfile.js b/Gruntfile.js
index b083b49..103938c 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -1,10 +1,12 @@
+'use strict';
+
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-connect');
- grunt.loadNpmTasks('grunt-contrib-qunit');
grunt.loadNpmTasks('grunt-contrib-yuidoc');
+ grunt.loadTasks('tasks');
var root = 'src/pixi/',
debug = 'bin/pixi.dev.js',
@@ -79,7 +81,7 @@
},
files: {
srcBlob: '<%= dirs.src %>/**/*.js',
- testBlob: '<%= dirs.test %>/unit/**/*.js',
+ testBlob: '<%= dirs.test %>/{functional,lib/pixi,unit}/**/*.js',
build: '<%= dirs.build %>/pixi.dev.js',
buildMin: '<%= dirs.build %>/pixi.js'
},
@@ -94,7 +96,12 @@
},
jshint: {
beforeconcat: srcFiles,
- test: ['<%= files.testBlob %>'],
+ test: {
+ src: ['<%= files.testBlob %>'],
+ options: {
+ expr: true
+ }
+ },
options: {
asi: true,
smarttabs: true
@@ -128,12 +135,6 @@
]
},
connect: {
- qunit: {
- options: {
- port: grunt.option('port-test') || 9002,
- base: './'
- }
- },
test: {
options: {
port: grunt.option('port-test') || 9002,
@@ -142,13 +143,6 @@
}
}
},
- qunit: {
- all: {
- options: {
- urls: ['http://localhost:' + (grunt.option('port-test') || 9002) + '/test/index.html']
- }
- }
- },
yuidoc: {
compile: {
name: '<%= pkg.name %>',
@@ -161,6 +155,13 @@
outdir: '<%= dirs.docs %>'
}
}
+ },
+ karma: {
+ unit: {
+ configFile: 'test/karma.conf.js',
+ // browsers: ['Chrome'],
+ singleRun: true
+ }
}
});
@@ -182,9 +183,10 @@
}
)
- grunt.registerTask('default', ['concat', 'uglify', 'distribute']);
grunt.registerTask('build', ['concat', 'uglify', 'distribute']);
- grunt.registerTask('test', ['build', 'connect:qunit', 'qunit']);
+ grunt.registerTask('test', ['concat', 'jshint:test', 'karma']);
grunt.registerTask('docs', ['yuidoc']);
-
-}
\ No newline at end of file
+ grunt.registerTask('default', ['test', 'uglify', 'distribute']);
+ // Travis CI task.
+ grunt.registerTask('travis', ['test']);
+}
diff --git a/README.md b/README.md
index c62ef86..690cfe4 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,8 @@

+[](http://travis-ci.org/drkibitz/pixi.js)
+
#### JavaScript 2D Renderer ####
The aim of this project is to provide a fast lightweight 2D library that works
diff --git a/package.json b/package.json
index b373240..1246a68 100644
--- a/package.json
+++ b/package.json
@@ -18,14 +18,21 @@
"main": "bin/pixi.js",
+ "scripts": {
+ "test": "grunt travis --verbose"
+ },
+
"dependencies": {},
"devDependencies": {
"grunt": "~0.4.x",
- "grunt-contrib-jshint": "0.3.x",
+ "grunt-contrib-jshint": "0.6.x",
"grunt-contrib-uglify": "0.2.x",
- "grunt-contrib-connect": "0.2.x",
- "grunt-contrib-qunit": "0.2.x",
+ "grunt-contrib-connect": "0.3.x",
"grunt-contrib-yuidoc": "0.4.x",
- "grunt-contrib-concat": "0.1.x"
+ "grunt-contrib-concat": "0.3.x",
+ "chai": "~1.7.0",
+ "karma": "0.11.0",
+ "karma-firefox-launcher": "0.1.0",
+ "karma-mocha": "0.1.0"
}
}
diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js
index a7c520e..ee82bbd 100644
--- a/src/pixi/InteractionManager.js
+++ b/src/pixi/InteractionManager.js
@@ -62,7 +62,6 @@
this.onTouchEnd = this.onTouchEnd.bind(this);
this.onTouchMove = this.onTouchMove.bind(this);
-
this.last = 0;
}
diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js
index 1a95d20..eef1059 100644
--- a/src/pixi/core/Ellipse.js
+++ b/src/pixi/core/Ellipse.js
@@ -78,7 +78,7 @@
return (normx + normy < 0.25);
}
-PIXI.Ellipse.getBounds = function()
+PIXI.Ellipse.prototype.getBounds = function()
{
return new PIXI.Rectangle(this.x, this.y, this.width, this.height);
}
diff --git a/tasks/karma.js b/tasks/karma.js
new file mode 100644
index 0000000..c340485
--- /dev/null
+++ b/tasks/karma.js
@@ -0,0 +1,27 @@
+'use strict';
+
+var path = require('path');
+var server = require('karma').server;
+
+module.exports = function (grunt) {
+ grunt.registerMultiTask('karma', 'run karma.', function() {
+ var done = this.async();
+ var options = this.options({
+ background: false
+ });
+ var data = this.data;
+
+ //merge options onto data, with data taking precedence
+ data = grunt.util._.merge(options, data);
+ data.configFile = path.resolve(data.configFile);
+ if (data.configFile) {
+ data.configFile = grunt.template.process(data.configFile);
+ }
+
+ server.start(
+ data,
+ function(code) {
+ done(!code);
+ });
+ });
+};
diff --git a/test/functional/example-1-basics/bunny.png b/test/functional/example-1-basics/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/functional/example-1-basics/bunny.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-30.png b/test/functional/example-1-basics/frame-30.png
new file mode 100644
index 0000000..96e3409
--- /dev/null
+++ b/test/functional/example-1-basics/frame-30.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-60.png b/test/functional/example-1-basics/frame-60.png
new file mode 100644
index 0000000..af3f4ce
--- /dev/null
+++ b/test/functional/example-1-basics/frame-60.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-90.png b/test/functional/example-1-basics/frame-90.png
new file mode 100644
index 0000000..099b823
--- /dev/null
+++ b/test/functional/example-1-basics/frame-90.png
Binary files differ
diff --git a/test/functional/example-1-basics/index.js b/test/functional/example-1-basics/index.js
new file mode 100644
index 0000000..7ae7a98
--- /dev/null
+++ b/test/functional/example-1-basics/index.js
@@ -0,0 +1,133 @@
+describe('Example 1 - Basics', function () {
+ 'use strict';
+
+ var baseUri = '/base/test/functional/example-1-basics';
+ var expect = chai.expect;
+ var currentFrame = 0;
+ var frameEvents = {};
+ var stage;
+ var renderer;
+ var bunny;
+
+ function onFrame(frame, callback) {
+ frameEvents[frame] = callback;
+ }
+
+ function animate() {
+ currentFrame += 1;
+
+ requestAnimFrame( animate );
+
+ // just for fun, lets rotate mr rabbit a little
+ bunny.rotation += 0.1;
+
+ // render the stage
+ renderer.render(stage);
+
+ if (frameEvents[currentFrame])
+ frameEvents[currentFrame](currentFrame);
+ }
+
+ function initScene() {
+ // create an new instance of a pixi stage
+ stage = new PIXI.Stage(0x66FF99);
+
+ // create a renderer instance
+ renderer = PIXI.autoDetectRenderer(400, 300);
+ console.log('Is PIXI.WebGLRenderer: ' + (renderer instanceof PIXI.WebGLRenderer));
+
+ // add the renderer view element to the DOM
+ document.body.appendChild(renderer.view);
+
+ requestAnimFrame( animate );
+
+ // create a texture from an image path
+ var texture = PIXI.Texture.fromImage(baseUri + "/bunny.png");
+ // create a new Sprite using the texture
+ bunny = new PIXI.Sprite(texture);
+
+ // center the sprites anchor point
+ bunny.anchor.x = 0.5;
+ bunny.anchor.y = 0.5;
+
+ // move the sprite t the center of the screen
+ bunny.position.x = 200;
+ bunny.position.y = 150;
+
+ stage.addChild(bunny);
+ }
+
+ it('assets loaded', function (done) {
+ var loader = new PIXI.AssetLoader([
+ baseUri + '/bunny.png',
+ baseUri + '/frame-30.png',
+ baseUri + '/frame-60.png',
+ baseUri + '/frame-90.png'
+ ]);
+ // loader.on('onProgress', function (event) {
+ // console.log(event.content);
+ // });
+ loader.on('onComplete', function (event) {
+ done();
+ initScene();
+ });
+ loader.load();
+ });
+
+ it('frame 30 should match', function (done) {
+ this.timeout(700);
+ onFrame(30, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-30.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 60 should match', function (done) {
+ this.timeout(1200);
+ onFrame(60, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-60.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 90 should match', function (done) {
+ this.timeout(1700);
+ onFrame(90, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-90.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ // it('capture something', function (done) {
+ // this.timeout(2000000);
+ // onFrame(30, function () {
+ // var img = new Image();
+ // img.src = renderer.view.toDataURL('image/png');
+ // document.body.appendChild(img);
+ // });
+ // });
+});
diff --git a/test/index.html b/test/index.html
deleted file mode 100644
index 9cbcac5..0000000
--- a/test/index.html
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
- Pixi.js Test Suite
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/test/karma.conf.js b/test/karma.conf.js
new file mode 100644
index 0000000..c66a696
--- /dev/null
+++ b/test/karma.conf.js
@@ -0,0 +1,82 @@
+module.exports = function(config) {
+ config.set({
+
+ // base path, that will be used to resolve files and exclude
+ basePath : '../',
+
+ frameworks : ['mocha'],
+
+ // list of files / patterns to load in the browser
+ files : [
+ 'node_modules/chai/chai.js',
+ 'bin/pixi.dev.js',
+ 'test/lib/**/*.js',
+ 'test/unit/**/*.js',
+ // 'test/functional/**/*.js',
+ {pattern: 'test/**/*.png', watched: false, included: false, served: true}
+ ],
+
+ // list of files to exclude
+ exclude : [],
+
+ // use dolts reporter, as travis terminal does not support escaping sequences
+ // possible values: 'dots', 'progress', 'junit', 'teamcity'
+ // CLI --reporters progress
+ reporters : ['progress'],
+
+ // web server port
+ // CLI --port 9876
+ port : 9876,
+
+ // cli runner port
+ // CLI --runner-port 9100
+ runnerPort : 9100,
+
+ // enable / disable colors in the output (reporters and logs)
+ // CLI --colors --no-colors
+ colors : true,
+
+ // level of logging
+ // possible values: karma.LOG_DISABLE || karma.LOG_ERROR || karma.LOG_WARN || karma.LOG_INFO || karma.LOG_DEBUG
+ // CLI --log-level debug
+ logLevel : config.LOG_DEBUG,
+
+ // enable / disable watching file and executing tests whenever any file changes
+ // CLI --auto-watch --no-auto-watch
+ autoWatch : false,
+
+ // Start these browsers, currently available:
+ // - Chrome
+ // - ChromeCanary
+ // - Firefox
+ // - Opera
+ // - Safari (only Mac)
+ // - PhantomJS
+ // - IE (only Windows)
+ // CLI --browsers Chrome,Firefox,Safari
+ browsers : ['Firefox'],
+
+ // If browser does not capture in given timeout [ms], kill it
+ // CLI --capture-timeout 5000
+ captureTimeout : 5000,
+
+ // Auto run tests on start (when browsers are captured) and exit
+ // CLI --single-run --no-single-run
+ singleRun : true,
+
+ // report which specs are slower than 500ms
+ // CLI --report-slower-than 500
+ reportSlowerThan : 1000,
+
+ preprocessors : {
+ // '**/client/js/*.js': 'coverage'
+ },
+
+ plugins : [
+ 'karma-mocha',
+ // 'karma-chrome-launcher',
+ 'karma-firefox-launcher',
+ // 'karma-phantomjs-launcher'
+ ]
+ });
+};
diff --git a/test/lib/pixi/core/Matrix.js b/test/lib/pixi/core/Matrix.js
new file mode 100644
index 0000000..d26386b
--- /dev/null
+++ b/test/lib/pixi/core/Matrix.js
@@ -0,0 +1,40 @@
+
+function pixi_core_Matrix_confirmNewMat3(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(1);
+ expect(matrix[5]).to.equal(0);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(1);
+}
+
+function pixi_core_Matrix_confirmNewMat4(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[0]).to.equal(1);
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(0);
+ expect(matrix[5]).to.equal(1);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(0);
+ expect(matrix[9]).to.equal(0);
+ expect(matrix[10]).to.equal(1);
+ expect(matrix[11]).to.equal(0);
+ expect(matrix[12]).to.equal(0);
+ expect(matrix[13]).to.equal(0);
+ expect(matrix[14]).to.equal(0);
+ expect(matrix[15]).to.equal(1);
+}
diff --git a/test/lib/pixi/core/Point.js b/test/lib/pixi/core/Point.js
new file mode 100644
index 0000000..e5df07b
--- /dev/null
+++ b/test/lib/pixi/core/Point.js
@@ -0,0 +1,10 @@
+
+function pixi_core_Point_confirm(obj, x, y) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Point);
+ expect(obj).to.respondTo('clone');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+}
diff --git a/test/lib/pixi/core/Rectangle.js b/test/lib/pixi/core/Rectangle.js
new file mode 100644
index 0000000..23f0d12
--- /dev/null
+++ b/test/lib/pixi/core/Rectangle.js
@@ -0,0 +1,13 @@
+
+function pixi_core_Rectangle_confirm(obj, x, y, width, height) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Rectangle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+ expect(obj).to.have.property('width', width);
+ expect(obj).to.have.property('height', height);
+}
diff --git a/test/lib/pixi/display/DisplayObject.js b/test/lib/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..1388a7f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObject.js
@@ -0,0 +1,43 @@
+
+function pixi_display_DisplayObject_confirmNew(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObject);
+ expect(obj).to.respondTo('setInteractive');
+ expect(obj).to.respondTo('addFilter');
+ expect(obj).to.respondTo('removeFilter');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.property('last', obj);
+ expect(obj).to.have.property('first', obj);
+
+ expect(obj).to.contain.property('position');
+ pixi_core_Point_confirm(obj.position, 0, 0);
+ expect(obj).to.contain.property('scale');
+ pixi_core_Point_confirm(obj.scale, 1, 1);
+ expect(obj).to.contain.property('pivot');
+ pixi_core_Point_confirm(obj.pivot, 0, 0);
+
+ expect(obj).to.have.property('rotation', 0);
+ expect(obj).to.have.property('alpha', 1);
+ expect(obj).to.have.property('visible', true);
+ expect(obj).to.have.property('buttonMode', false);
+ expect(obj).to.have.property('parent', null);
+ expect(obj).to.have.property('worldAlpha', 1);
+
+ expect(obj).to.have.property('hitArea');
+ expect(obj).to.have.property('interactive'); // TODO: Have a better default value
+ expect('mask' in obj).to.be.true; // TODO: Have a better default value
+ expect(obj.mask).to.be.undefined;
+
+ expect(obj).to.have.property('renderable');
+ expect(obj).to.have.property('stage');
+
+ expect(obj).to.have.deep.property('worldTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ expect(obj).to.have.deep.property('localTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.localTransform);
+
+ expect(obj).to.have.deep.property('color.length', 0);
+ expect(obj).to.have.property('dynamic', true);
+}
diff --git a/test/lib/pixi/display/DisplayObjectContainer.js b/test/lib/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..085c59f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,16 @@
+
+function pixi_display_DisplayObjectContainer_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObject_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObjectContainer);
+ expect(obj).to.respondTo('addChild');
+ expect(obj).to.respondTo('addChildAt');
+ expect(obj).to.respondTo('swapChildren');
+ expect(obj).to.respondTo('getChildAt');
+ expect(obj).to.respondTo('removeChild');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('children.length', 0);
+}
diff --git a/test/lib/pixi/display/Sprite.js b/test/lib/pixi/display/Sprite.js
new file mode 100644
index 0000000..cc7a2d6
--- /dev/null
+++ b/test/lib/pixi/display/Sprite.js
@@ -0,0 +1,28 @@
+
+function pixi_display_Sprite_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Sprite);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', true);
+ expect(obj).to.have.property('stage', null);
+
+ expect(obj).to.have.property('anchor');
+ pixi_core_Point_confirm(obj.anchor, 0, 0);
+
+ expect(obj).to.have.property('blendMode', PIXI.blendModes.NORMAL);
+ expect(obj).to.have.property('width', 1); // TODO: is 1 expected
+ expect(obj).to.have.property('height', 1); // TODO: is 1 expected
+
+ // FIXME: Just make this a boolean that is always there
+ expect(!!obj.updateFrame).to.equal(obj.texture.baseTexture.hasLoaded);
+
+ expect(obj).to.have.property('texture');
+ pixi_textures_Texture_confirmNew(obj.texture, done);
+}
diff --git a/test/lib/pixi/extras/Strip.js b/test/lib/pixi/extras/Strip.js
new file mode 100644
index 0000000..8927a8a
--- /dev/null
+++ b/test/lib/pixi/extras/Strip.js
@@ -0,0 +1,12 @@
+
+function pixi_extras_Strip_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Strip);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ // TODO: Test properties
+}
diff --git a/test/lib/pixi/textures/Texture.js b/test/lib/pixi/textures/Texture.js
new file mode 100644
index 0000000..d5867b6
--- /dev/null
+++ b/test/lib/pixi/textures/Texture.js
@@ -0,0 +1,31 @@
+
+function pixi_textures_Texture_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ function confirmFrameDone() {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, obj.baseTexture.width, obj.baseTexture.height);
+
+ expect(obj).to.have.property('width', obj.baseTexture.width);
+ expect(obj).to.have.property('height', obj.baseTexture.height);
+ done();
+ }
+
+ expect(obj).to.be.an.instanceof(PIXI.Texture);
+ pixi_utils_EventTarget_like(obj);
+
+ expect(obj).to.have.property('baseTexture')
+ .and.to.be.an.instanceof(PIXI.BaseTexture);
+
+ expect(obj).to.have.property('scope', obj);
+
+ expect(obj).to.have.property('trim');
+ pixi_core_Point_confirm(obj.trim, 0, 0);
+
+ expect(obj).to.have.property('frame');
+ if (obj.baseTexture.hasLoaded) {
+ confirmFrameDone();
+ } else {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, 1, 1);
+ obj.addEventListener('update', confirmFrameDone);
+ }
+}
diff --git a/test/lib/pixi/utils/EventTarget.js b/test/lib/pixi/utils/EventTarget.js
new file mode 100644
index 0000000..7b1dcfa
--- /dev/null
+++ b/test/lib/pixi/utils/EventTarget.js
@@ -0,0 +1,8 @@
+
+function pixi_utils_EventTarget_like(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.respondTo('addEventListener');
+ expect(obj).to.respondTo('dispatchEvent');
+ expect(obj).to.respondTo('removeEventListener');
+}
diff --git a/test/lib/qunit-1.11.0.css b/test/lib/qunit-1.11.0.css
deleted file mode 100644
index d7fc0c8..0000000
--- a/test/lib/qunit-1.11.0.css
+++ /dev/null
@@ -1,244 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-/** Font Family and Sizes */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
- font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
-}
-
-#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
-#qunit-tests { font-size: smaller; }
-
-
-/** Resets */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter {
- margin: 0;
- padding: 0;
-}
-
-
-/** Header */
-
-#qunit-header {
- padding: 0.5em 0 0.5em 1em;
-
- color: #8699a4;
- background-color: #0d3349;
-
- font-size: 1.5em;
- line-height: 1em;
- font-weight: normal;
-
- border-radius: 5px 5px 0 0;
- -moz-border-radius: 5px 5px 0 0;
- -webkit-border-top-right-radius: 5px;
- -webkit-border-top-left-radius: 5px;
-}
-
-#qunit-header a {
- text-decoration: none;
- color: #c2ccd1;
-}
-
-#qunit-header a:hover,
-#qunit-header a:focus {
- color: #fff;
-}
-
-#qunit-testrunner-toolbar label {
- display: inline-block;
- padding: 0 .5em 0 .1em;
-}
-
-#qunit-banner {
- height: 5px;
-}
-
-#qunit-testrunner-toolbar {
- padding: 0.5em 0 0.5em 2em;
- color: #5E740B;
- background-color: #eee;
- overflow: hidden;
-}
-
-#qunit-userAgent {
- padding: 0.5em 0 0.5em 2.5em;
- background-color: #2b81af;
- color: #fff;
- text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
-}
-
-#qunit-modulefilter-container {
- float: right;
-}
-
-/** Tests: Pass/Fail */
-
-#qunit-tests {
- list-style-position: inside;
-}
-
-#qunit-tests li {
- padding: 0.4em 0.5em 0.4em 2.5em;
- border-bottom: 1px solid #fff;
- list-style-position: inside;
-}
-
-#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running {
- display: none;
-}
-
-#qunit-tests li strong {
- cursor: pointer;
-}
-
-#qunit-tests li a {
- padding: 0.5em;
- color: #c2ccd1;
- text-decoration: none;
-}
-#qunit-tests li a:hover,
-#qunit-tests li a:focus {
- color: #000;
-}
-
-#qunit-tests li .runtime {
- float: right;
- font-size: smaller;
-}
-
-.qunit-assert-list {
- margin-top: 0.5em;
- padding: 0.5em;
-
- background-color: #fff;
-
- border-radius: 5px;
- -moz-border-radius: 5px;
- -webkit-border-radius: 5px;
-}
-
-.qunit-collapsed {
- display: none;
-}
-
-#qunit-tests table {
- border-collapse: collapse;
- margin-top: .2em;
-}
-
-#qunit-tests th {
- text-align: right;
- vertical-align: top;
- padding: 0 .5em 0 0;
-}
-
-#qunit-tests td {
- vertical-align: top;
-}
-
-#qunit-tests pre {
- margin: 0;
- white-space: pre-wrap;
- word-wrap: break-word;
-}
-
-#qunit-tests del {
- background-color: #e0f2be;
- color: #374e0c;
- text-decoration: none;
-}
-
-#qunit-tests ins {
- background-color: #ffcaca;
- color: #500;
- text-decoration: none;
-}
-
-/*** Test Counts */
-
-#qunit-tests b.counts { color: black; }
-#qunit-tests b.passed { color: #5E740B; }
-#qunit-tests b.failed { color: #710909; }
-
-#qunit-tests li li {
- padding: 5px;
- background-color: #fff;
- border-bottom: none;
- list-style-position: inside;
-}
-
-/*** Passing Styles */
-
-#qunit-tests li li.pass {
- color: #3c510c;
- background-color: #fff;
- border-left: 10px solid #C6E746;
-}
-
-#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
-#qunit-tests .pass .test-name { color: #366097; }
-
-#qunit-tests .pass .test-actual,
-#qunit-tests .pass .test-expected { color: #999999; }
-
-#qunit-banner.qunit-pass { background-color: #C6E746; }
-
-/*** Failing Styles */
-
-#qunit-tests li li.fail {
- color: #710909;
- background-color: #fff;
- border-left: 10px solid #EE5757;
- white-space: pre;
-}
-
-#qunit-tests > li:last-child {
- border-radius: 0 0 5px 5px;
- -moz-border-radius: 0 0 5px 5px;
- -webkit-border-bottom-right-radius: 5px;
- -webkit-border-bottom-left-radius: 5px;
-}
-
-#qunit-tests .fail { color: #000000; background-color: #EE5757; }
-#qunit-tests .fail .test-name,
-#qunit-tests .fail .module-name { color: #000000; }
-
-#qunit-tests .fail .test-actual { color: #EE5757; }
-#qunit-tests .fail .test-expected { color: green; }
-
-#qunit-banner.qunit-fail { background-color: #EE5757; }
-
-
-/** Result */
-
-#qunit-testresult {
- padding: 0.5em 0.5em 0.5em 2.5em;
-
- color: #2b81af;
- background-color: #D2E0E6;
-
- border-bottom: 1px solid white;
-}
-#qunit-testresult .module-name {
- font-weight: bold;
-}
-
-/** Fixture */
-
-#qunit-fixture {
- position: absolute;
- top: -10000px;
- left: -10000px;
- width: 1000px;
- height: 1000px;
-}
diff --git a/test/lib/qunit-1.11.0.js b/test/lib/qunit-1.11.0.js
deleted file mode 100644
index 302545f..0000000
--- a/test/lib/qunit-1.11.0.js
+++ /dev/null
@@ -1,2152 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-(function( window ) {
-
-var QUnit,
- assert,
- config,
- onErrorFnPrev,
- testId = 0,
- fileName = (sourceFromStacktrace( 0 ) || "" ).replace(/(:\d+)+\)?/, "").replace(/.+\//, ""),
- toString = Object.prototype.toString,
- hasOwn = Object.prototype.hasOwnProperty,
- // Keep a local reference to Date (GH-283)
- Date = window.Date,
- defined = {
- setTimeout: typeof window.setTimeout !== "undefined",
- sessionStorage: (function() {
- var x = "qunit-test-string";
- try {
- sessionStorage.setItem( x, x );
- sessionStorage.removeItem( x );
- return true;
- } catch( e ) {
- return false;
- }
- }())
- },
- /**
- * Provides a normalized error string, correcting an issue
- * with IE 7 (and prior) where Error.prototype.toString is
- * not properly implemented
- *
- * Based on http://es5.github.com/#x15.11.4.4
- *
- * @param {String|Error} error
- * @return {String} error message
- */
- errorString = function( error ) {
- var name, message,
- errorString = error.toString();
- if ( errorString.substring( 0, 7 ) === "[object" ) {
- name = error.name ? error.name.toString() : "Error";
- message = error.message ? error.message.toString() : "";
- if ( name && message ) {
- return name + ": " + message;
- } else if ( name ) {
- return name;
- } else if ( message ) {
- return message;
- } else {
- return "Error";
- }
- } else {
- return errorString;
- }
- },
- /**
- * Makes a clone of an object using only Array or Object as base,
- * and copies over the own enumerable properties.
- *
- * @param {Object} obj
- * @return {Object} New object with only the own properties (recursively).
- */
- objectValues = function( obj ) {
- // Grunt 0.3.x uses an older version of jshint that still has jshint/jshint#392.
- /*jshint newcap: false */
- var key, val,
- vals = QUnit.is( "array", obj ) ? [] : {};
- for ( key in obj ) {
- if ( hasOwn.call( obj, key ) ) {
- val = obj[key];
- vals[key] = val === Object(val) ? objectValues(val) : val;
- }
- }
- return vals;
- };
-
-function Test( settings ) {
- extend( this, settings );
- this.assertions = [];
- this.testNumber = ++Test.count;
-}
-
-Test.count = 0;
-
-Test.prototype = {
- init: function() {
- var a, b, li,
- tests = id( "qunit-tests" );
-
- if ( tests ) {
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml;
-
- // `a` initialized at top of scope
- a = document.createElement( "a" );
- a.innerHTML = "Rerun";
- a.href = QUnit.url({ testNumber: this.testNumber });
-
- li = document.createElement( "li" );
- li.appendChild( b );
- li.appendChild( a );
- li.className = "running";
- li.id = this.id = "qunit-test-output" + testId++;
-
- tests.appendChild( li );
- }
- },
- setup: function() {
- if ( this.module !== config.previousModule ) {
- if ( config.previousModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.previousModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
- config.previousModule = this.module;
- config.moduleStats = { all: 0, bad: 0 };
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- } else if ( config.autorun ) {
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- }
-
- config.current = this;
-
- this.testEnvironment = extend({
- setup: function() {},
- teardown: function() {}
- }, this.moduleTestEnvironment );
-
- this.started = +new Date();
- runLoggingCallbacks( "testStart", QUnit, {
- name: this.testName,
- module: this.module
- });
-
- // allow utility functions to access the current test environment
- // TODO why??
- QUnit.current_testEnvironment = this.testEnvironment;
-
- if ( !config.pollution ) {
- saveGlobal();
- }
- if ( config.notrycatch ) {
- this.testEnvironment.setup.call( this.testEnvironment );
- return;
- }
- try {
- this.testEnvironment.setup.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Setup failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- },
- run: function() {
- config.current = this;
-
- var running = id( "qunit-testresult" );
-
- if ( running ) {
- running.innerHTML = "Running:
" + this.nameHtml;
- }
-
- if ( this.async ) {
- QUnit.stop();
- }
-
- this.callbackStarted = +new Date();
-
- if ( config.notrycatch ) {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- return;
- }
-
- try {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- } catch( e ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
-
- QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + " " + this.stack + ": " + ( e.message || e ), extractStacktrace( e, 0 ) );
- // else next test will carry the responsibility
- saveGlobal();
-
- // Restart the tests if they're blocking
- if ( config.blocking ) {
- QUnit.start();
- }
- }
- },
- teardown: function() {
- config.current = this;
- if ( config.notrycatch ) {
- if ( typeof this.callbackRuntime === "undefined" ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
- }
- this.testEnvironment.teardown.call( this.testEnvironment );
- return;
- } else {
- try {
- this.testEnvironment.teardown.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Teardown failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- }
- checkPollution();
- },
- finish: function() {
- config.current = this;
- if ( config.requireExpects && this.expected === null ) {
- QUnit.pushFailure( "Expected number of assertions to be defined, but expect() was not called.", this.stack );
- } else if ( this.expected !== null && this.expected !== this.assertions.length ) {
- QUnit.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack );
- } else if ( this.expected === null && !this.assertions.length ) {
- QUnit.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions.", this.stack );
- }
-
- var i, assertion, a, b, time, li, ol,
- test = this,
- good = 0,
- bad = 0,
- tests = id( "qunit-tests" );
-
- this.runtime = +new Date() - this.started;
- config.stats.all += this.assertions.length;
- config.moduleStats.all += this.assertions.length;
-
- if ( tests ) {
- ol = document.createElement( "ol" );
- ol.className = "qunit-assert-list";
-
- for ( i = 0; i < this.assertions.length; i++ ) {
- assertion = this.assertions[i];
-
- li = document.createElement( "li" );
- li.className = assertion.result ? "pass" : "fail";
- li.innerHTML = assertion.message || ( assertion.result ? "okay" : "failed" );
- ol.appendChild( li );
-
- if ( assertion.result ) {
- good++;
- } else {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
-
- // store result when possible
- if ( QUnit.config.reorder && defined.sessionStorage ) {
- if ( bad ) {
- sessionStorage.setItem( "qunit-test-" + this.module + "-" + this.testName, bad );
- } else {
- sessionStorage.removeItem( "qunit-test-" + this.module + "-" + this.testName );
- }
- }
-
- if ( bad === 0 ) {
- addClass( ol, "qunit-collapsed" );
- }
-
- // `b` initialized at top of scope
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml + " (" + bad + ", " + good + ", " + this.assertions.length + ")";
-
- addEvent(b, "click", function() {
- var next = b.parentNode.lastChild,
- collapsed = hasClass( next, "qunit-collapsed" );
- ( collapsed ? removeClass : addClass )( next, "qunit-collapsed" );
- });
-
- addEvent(b, "dblclick", function( e ) {
- var target = e && e.target ? e.target : window.event.srcElement;
- if ( target.nodeName.toLowerCase() === "span" || target.nodeName.toLowerCase() === "b" ) {
- target = target.parentNode;
- }
- if ( window.location && target.nodeName.toLowerCase() === "strong" ) {
- window.location = QUnit.url({ testNumber: test.testNumber });
- }
- });
-
- // `time` initialized at top of scope
- time = document.createElement( "span" );
- time.className = "runtime";
- time.innerHTML = this.runtime + " ms";
-
- // `li` initialized at top of scope
- li = id( this.id );
- li.className = bad ? "fail" : "pass";
- li.removeChild( li.firstChild );
- a = li.firstChild;
- li.appendChild( b );
- li.appendChild( a );
- li.appendChild( time );
- li.appendChild( ol );
-
- } else {
- for ( i = 0; i < this.assertions.length; i++ ) {
- if ( !this.assertions[i].result ) {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
- }
-
- runLoggingCallbacks( "testDone", QUnit, {
- name: this.testName,
- module: this.module,
- failed: bad,
- passed: this.assertions.length - bad,
- total: this.assertions.length,
- duration: this.runtime
- });
-
- QUnit.reset();
-
- config.current = undefined;
- },
-
- queue: function() {
- var bad,
- test = this;
-
- synchronize(function() {
- test.init();
- });
- function run() {
- // each of these can by async
- synchronize(function() {
- test.setup();
- });
- synchronize(function() {
- test.run();
- });
- synchronize(function() {
- test.teardown();
- });
- synchronize(function() {
- test.finish();
- });
- }
-
- // `bad` initialized at top of scope
- // defer when previous test run passed, if storage is available
- bad = QUnit.config.reorder && defined.sessionStorage &&
- +sessionStorage.getItem( "qunit-test-" + this.module + "-" + this.testName );
-
- if ( bad ) {
- run();
- } else {
- synchronize( run, true );
- }
- }
-};
-
-// Root QUnit object.
-// `QUnit` initialized at top of scope
-QUnit = {
-
- // call on start of module test to prepend name to all tests
- module: function( name, testEnvironment ) {
- config.currentModule = name;
- config.currentModuleTestEnvironment = testEnvironment;
- config.modules[name] = true;
- },
-
- asyncTest: function( testName, expected, callback ) {
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- QUnit.test( testName, expected, callback, true );
- },
-
- test: function( testName, expected, callback, async ) {
- var test,
- nameHtml = "" + escapeText( testName ) + "";
-
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- if ( config.currentModule ) {
- nameHtml = "" + escapeText( config.currentModule ) + ": " + nameHtml;
- }
-
- test = new Test({
- nameHtml: nameHtml,
- testName: testName,
- expected: expected,
- async: async,
- callback: callback,
- module: config.currentModule,
- moduleTestEnvironment: config.currentModuleTestEnvironment,
- stack: sourceFromStacktrace( 2 )
- });
-
- if ( !validTest( test ) ) {
- return;
- }
-
- test.queue();
- },
-
- // Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through.
- expect: function( asserts ) {
- if (arguments.length === 1) {
- config.current.expected = asserts;
- } else {
- return config.current.expected;
- }
- },
-
- start: function( count ) {
- // QUnit hasn't been initialized yet.
- // Note: RequireJS (et al) may delay onLoad
- if ( config.semaphore === undefined ) {
- QUnit.begin(function() {
- // This is triggered at the top of QUnit.load, push start() to the event loop, to allow QUnit.load to finish first
- setTimeout(function() {
- QUnit.start( count );
- });
- });
- return;
- }
-
- config.semaphore -= count || 1;
- // don't start until equal number of stop-calls
- if ( config.semaphore > 0 ) {
- return;
- }
- // ignore if start is called more often then stop
- if ( config.semaphore < 0 ) {
- config.semaphore = 0;
- QUnit.pushFailure( "Called start() while already started (QUnit.config.semaphore was 0 already)", null, sourceFromStacktrace(2) );
- return;
- }
- // A slight delay, to avoid any current callbacks
- if ( defined.setTimeout ) {
- window.setTimeout(function() {
- if ( config.semaphore > 0 ) {
- return;
- }
- if ( config.timeout ) {
- clearTimeout( config.timeout );
- }
-
- config.blocking = false;
- process( true );
- }, 13);
- } else {
- config.blocking = false;
- process( true );
- }
- },
-
- stop: function( count ) {
- config.semaphore += count || 1;
- config.blocking = true;
-
- if ( config.testTimeout && defined.setTimeout ) {
- clearTimeout( config.timeout );
- config.timeout = window.setTimeout(function() {
- QUnit.ok( false, "Test timed out" );
- config.semaphore = 1;
- QUnit.start();
- }, config.testTimeout );
- }
- }
-};
-
-// `assert` initialized at top of scope
-// Asssert helpers
-// All of these must either call QUnit.push() or manually do:
-// - runLoggingCallbacks( "log", .. );
-// - config.current.assertions.push({ .. });
-// We attach it to the QUnit object *after* we expose the public API,
-// otherwise `assert` will become a global variable in browsers (#341).
-assert = {
- /**
- * Asserts rough true-ish result.
- * @name ok
- * @function
- * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" );
- */
- ok: function( result, msg ) {
- if ( !config.current ) {
- throw new Error( "ok() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
- result = !!result;
-
- var source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: msg
- };
-
- msg = escapeText( msg || (result ? "okay" : "failed" ) );
- msg = "" + msg + "";
-
- if ( !result ) {
- source = sourceFromStacktrace( 2 );
- if ( source ) {
- details.source = source;
- msg += "Source: | " + escapeText( source ) + " |
---|
";
- }
- }
- runLoggingCallbacks( "log", QUnit, details );
- config.current.assertions.push({
- result: result,
- message: msg
- });
- },
-
- /**
- * Assert that the first two arguments are equal, with an optional message.
- * Prints out both actual and expected values.
- * @name equal
- * @function
- * @example equal( format( "Received {0} bytes.", 2), "Received 2 bytes.", "format() replaces {0} with next argument" );
- */
- equal: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected == actual, actual, expected, message );
- },
-
- /**
- * @name notEqual
- * @function
- */
- notEqual: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected != actual, actual, expected, message );
- },
-
- /**
- * @name propEqual
- * @function
- */
- propEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notPropEqual
- * @function
- */
- notPropEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name deepEqual
- * @function
- */
- deepEqual: function( actual, expected, message ) {
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notDeepEqual
- * @function
- */
- notDeepEqual: function( actual, expected, message ) {
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name strictEqual
- * @function
- */
- strictEqual: function( actual, expected, message ) {
- QUnit.push( expected === actual, actual, expected, message );
- },
-
- /**
- * @name notStrictEqual
- * @function
- */
- notStrictEqual: function( actual, expected, message ) {
- QUnit.push( expected !== actual, actual, expected, message );
- },
-
- "throws": function( block, expected, message ) {
- var actual,
- expectedOutput = expected,
- ok = false;
-
- // 'expected' is optional
- if ( typeof expected === "string" ) {
- message = expected;
- expected = null;
- }
-
- config.current.ignoreGlobalErrors = true;
- try {
- block.call( config.current.testEnvironment );
- } catch (e) {
- actual = e;
- }
- config.current.ignoreGlobalErrors = false;
-
- if ( actual ) {
- // we don't want to validate thrown error
- if ( !expected ) {
- ok = true;
- expectedOutput = null;
- // expected is a regexp
- } else if ( QUnit.objectType( expected ) === "regexp" ) {
- ok = expected.test( errorString( actual ) );
- // expected is a constructor
- } else if ( actual instanceof expected ) {
- ok = true;
- // expected is a validation function which returns true is validation passed
- } else if ( expected.call( {}, actual ) === true ) {
- expectedOutput = null;
- ok = true;
- }
-
- QUnit.push( ok, actual, expectedOutput, message );
- } else {
- QUnit.pushFailure( message, null, 'No exception was thrown.' );
- }
- }
-};
-
-/**
- * @deprecate since 1.8.0
- * Kept assertion helpers in root for backwards compatibility.
- */
-extend( QUnit, assert );
-
-/**
- * @deprecated since 1.9.0
- * Kept root "raises()" for backwards compatibility.
- * (Note that we don't introduce assert.raises).
- */
-QUnit.raises = assert[ "throws" ];
-
-/**
- * @deprecated since 1.0.0, replaced with error pushes since 1.3.0
- * Kept to avoid TypeErrors for undefined methods.
- */
-QUnit.equals = function() {
- QUnit.push( false, false, false, "QUnit.equals has been deprecated since 2009 (e88049a0), use QUnit.equal instead" );
-};
-QUnit.same = function() {
- QUnit.push( false, false, false, "QUnit.same has been deprecated since 2009 (e88049a0), use QUnit.deepEqual instead" );
-};
-
-// We want access to the constructor's prototype
-(function() {
- function F() {}
- F.prototype = QUnit;
- QUnit = new F();
- // Make F QUnit's constructor so that we can add to the prototype later
- QUnit.constructor = F;
-}());
-
-/**
- * Config object: Maintain internal state
- * Later exposed as QUnit.config
- * `config` initialized at top of scope
- */
-config = {
- // The queue of tests to run
- queue: [],
-
- // block until document ready
- blocking: true,
-
- // when enabled, show only failing tests
- // gets persisted through sessionStorage and can be changed in UI via checkbox
- hidepassed: false,
-
- // by default, run previously failed tests first
- // very useful in combination with "Hide passed tests" checked
- reorder: true,
-
- // by default, modify document.title when suite is done
- altertitle: true,
-
- // when enabled, all tests must call expect()
- requireExpects: false,
-
- // add checkboxes that are persisted in the query-string
- // when enabled, the id is set to `true` as a `QUnit.config` property
- urlConfig: [
- {
- id: "noglobals",
- label: "Check for Globals",
- tooltip: "Enabling this will test if any test introduces new properties on the `window` object. Stored as query-strings."
- },
- {
- id: "notrycatch",
- label: "No try-catch",
- tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging exceptions in IE reasonable. Stored as query-strings."
- }
- ],
-
- // Set of all modules.
- modules: {},
-
- // logging callback queues
- begin: [],
- done: [],
- log: [],
- testStart: [],
- testDone: [],
- moduleStart: [],
- moduleDone: []
-};
-
-// Export global variables, unless an 'exports' object exists,
-// in that case we assume we're in CommonJS (dealt with on the bottom of the script)
-if ( typeof exports === "undefined" ) {
- extend( window, QUnit );
-
- // Expose QUnit object
- window.QUnit = QUnit;
-}
-
-// Initialize more QUnit.config and QUnit.urlParams
-(function() {
- var i,
- location = window.location || { search: "", protocol: "file:" },
- params = location.search.slice( 1 ).split( "&" ),
- length = params.length,
- urlParams = {},
- current;
-
- if ( params[ 0 ] ) {
- for ( i = 0; i < length; i++ ) {
- current = params[ i ].split( "=" );
- current[ 0 ] = decodeURIComponent( current[ 0 ] );
- // allow just a key to turn on a flag, e.g., test.html?noglobals
- current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true;
- urlParams[ current[ 0 ] ] = current[ 1 ];
- }
- }
-
- QUnit.urlParams = urlParams;
-
- // String search anywhere in moduleName+testName
- config.filter = urlParams.filter;
-
- // Exact match of the module name
- config.module = urlParams.module;
-
- config.testNumber = parseInt( urlParams.testNumber, 10 ) || null;
-
- // Figure out if we're running the tests from a server or not
- QUnit.isLocal = location.protocol === "file:";
-}());
-
-// Extend QUnit object,
-// these after set here because they should not be exposed as global functions
-extend( QUnit, {
- assert: assert,
-
- config: config,
-
- // Initialize the configuration options
- init: function() {
- extend( config, {
- stats: { all: 0, bad: 0 },
- moduleStats: { all: 0, bad: 0 },
- started: +new Date(),
- updateRate: 1000,
- blocking: false,
- autostart: true,
- autorun: false,
- filter: "",
- queue: [],
- semaphore: 1
- });
-
- var tests, banner, result,
- qunit = id( "qunit" );
-
- if ( qunit ) {
- qunit.innerHTML =
- "" +
- "" +
- "" +
- "" +
- "
";
- }
-
- tests = id( "qunit-tests" );
- banner = id( "qunit-banner" );
- result = id( "qunit-testresult" );
-
- if ( tests ) {
- tests.innerHTML = "";
- }
-
- if ( banner ) {
- banner.className = "";
- }
-
- if ( result ) {
- result.parentNode.removeChild( result );
- }
-
- if ( tests ) {
- result = document.createElement( "p" );
- result.id = "qunit-testresult";
- result.className = "result";
- tests.parentNode.insertBefore( result, tests );
- result.innerHTML = "Running...
";
- }
- },
-
- // Resets the test setup. Useful for tests that modify the DOM.
- reset: function() {
- var fixture = id( "qunit-fixture" );
- if ( fixture ) {
- fixture.innerHTML = config.fixture;
- }
- },
-
- // Trigger an event on an element.
- // @example triggerEvent( document.body, "click" );
- triggerEvent: function( elem, type, event ) {
- if ( document.createEvent ) {
- event = document.createEvent( "MouseEvents" );
- event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView,
- 0, 0, 0, 0, 0, false, false, false, false, 0, null);
-
- elem.dispatchEvent( event );
- } else if ( elem.fireEvent ) {
- elem.fireEvent( "on" + type );
- }
- },
-
- // Safe object type checking
- is: function( type, obj ) {
- return QUnit.objectType( obj ) === type;
- },
-
- objectType: function( obj ) {
- if ( typeof obj === "undefined" ) {
- return "undefined";
- // consider: typeof null === object
- }
- if ( obj === null ) {
- return "null";
- }
-
- var match = toString.call( obj ).match(/^\[object\s(.*)\]$/),
- type = match && match[1] || "";
-
- switch ( type ) {
- case "Number":
- if ( isNaN(obj) ) {
- return "nan";
- }
- return "number";
- case "String":
- case "Boolean":
- case "Array":
- case "Date":
- case "RegExp":
- case "Function":
- return type.toLowerCase();
- }
- if ( typeof obj === "object" ) {
- return "object";
- }
- return undefined;
- },
-
- push: function( result, actual, expected, message ) {
- if ( !config.current ) {
- throw new Error( "assertion outside test context, was " + sourceFromStacktrace() );
- }
-
- var output, source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: message,
- actual: actual,
- expected: expected
- };
-
- message = escapeText( message ) || ( result ? "okay" : "failed" );
- message = "" + message + "";
- output = message;
-
- if ( !result ) {
- expected = escapeText( QUnit.jsDump.parse(expected) );
- actual = escapeText( QUnit.jsDump.parse(actual) );
- output += "Expected: | " + expected + " |
";
-
- if ( actual !== expected ) {
- output += "Result: | " + actual + " |
";
- output += "Diff: | " + QUnit.diff( expected, actual ) + " |
";
- }
-
- source = sourceFromStacktrace();
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
- }
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: !!result,
- message: output
- });
- },
-
- pushFailure: function( message, source, actual ) {
- if ( !config.current ) {
- throw new Error( "pushFailure() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
-
- var output,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: false,
- message: message
- };
-
- message = escapeText( message ) || "error";
- message = "" + message + "";
- output = message;
-
- output += "";
-
- if ( actual ) {
- output += "Result: | " + escapeText( actual ) + " |
";
- }
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: false,
- message: output
- });
- },
-
- url: function( params ) {
- params = extend( extend( {}, QUnit.urlParams ), params );
- var key,
- querystring = "?";
-
- for ( key in params ) {
- if ( !hasOwn.call( params, key ) ) {
- continue;
- }
- querystring += encodeURIComponent( key ) + "=" +
- encodeURIComponent( params[ key ] ) + "&";
- }
- return window.location.protocol + "//" + window.location.host +
- window.location.pathname + querystring.slice( 0, -1 );
- },
-
- extend: extend,
- id: id,
- addEvent: addEvent
- // load, equiv, jsDump, diff: Attached later
-});
-
-/**
- * @deprecated: Created for backwards compatibility with test runner that set the hook function
- * into QUnit.{hook}, instead of invoking it and passing the hook function.
- * QUnit.constructor is set to the empty F() above so that we can add to it's prototype here.
- * Doing this allows us to tell if the following methods have been overwritten on the actual
- * QUnit object.
- */
-extend( QUnit.constructor.prototype, {
-
- // Logging callbacks; all receive a single argument with the listed properties
- // run test/logs.html for any related changes
- begin: registerLoggingCallback( "begin" ),
-
- // done: { failed, passed, total, runtime }
- done: registerLoggingCallback( "done" ),
-
- // log: { result, actual, expected, message }
- log: registerLoggingCallback( "log" ),
-
- // testStart: { name }
- testStart: registerLoggingCallback( "testStart" ),
-
- // testDone: { name, failed, passed, total, duration }
- testDone: registerLoggingCallback( "testDone" ),
-
- // moduleStart: { name }
- moduleStart: registerLoggingCallback( "moduleStart" ),
-
- // moduleDone: { name, failed, passed, total }
- moduleDone: registerLoggingCallback( "moduleDone" )
-});
-
-if ( typeof document === "undefined" || document.readyState === "complete" ) {
- config.autorun = true;
-}
-
-QUnit.load = function() {
- runLoggingCallbacks( "begin", QUnit, {} );
-
- // Initialize the config, saving the execution queue
- var banner, filter, i, label, len, main, ol, toolbar, userAgent, val,
- urlConfigCheckboxesContainer, urlConfigCheckboxes, moduleFilter,
- numModules = 0,
- moduleFilterHtml = "",
- urlConfigHtml = "",
- oldconfig = extend( {}, config );
-
- QUnit.init();
- extend(config, oldconfig);
-
- config.blocking = false;
-
- len = config.urlConfig.length;
-
- for ( i = 0; i < len; i++ ) {
- val = config.urlConfig[i];
- if ( typeof val === "string" ) {
- val = {
- id: val,
- label: val,
- tooltip: "[no tooltip available]"
- };
- }
- config[ val.id ] = QUnit.urlParams[ val.id ];
- urlConfigHtml += "";
- }
-
- moduleFilterHtml += "";
-
- // `userAgent` initialized at top of scope
- userAgent = id( "qunit-userAgent" );
- if ( userAgent ) {
- userAgent.innerHTML = navigator.userAgent;
- }
-
- // `banner` initialized at top of scope
- banner = id( "qunit-header" );
- if ( banner ) {
- banner.innerHTML = "" + banner.innerHTML + " ";
- }
-
- // `toolbar` initialized at top of scope
- toolbar = id( "qunit-testrunner-toolbar" );
- if ( toolbar ) {
- // `filter` initialized at top of scope
- filter = document.createElement( "input" );
- filter.type = "checkbox";
- filter.id = "qunit-filter-pass";
-
- addEvent( filter, "click", function() {
- var tmp,
- ol = document.getElementById( "qunit-tests" );
-
- if ( filter.checked ) {
- ol.className = ol.className + " hidepass";
- } else {
- tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " ";
- ol.className = tmp.replace( / hidepass /, " " );
- }
- if ( defined.sessionStorage ) {
- if (filter.checked) {
- sessionStorage.setItem( "qunit-filter-passed-tests", "true" );
- } else {
- sessionStorage.removeItem( "qunit-filter-passed-tests" );
- }
- }
- });
-
- if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem( "qunit-filter-passed-tests" ) ) {
- filter.checked = true;
- // `ol` initialized at top of scope
- ol = document.getElementById( "qunit-tests" );
- ol.className = ol.className + " hidepass";
- }
- toolbar.appendChild( filter );
-
- // `label` initialized at top of scope
- label = document.createElement( "label" );
- label.setAttribute( "for", "qunit-filter-pass" );
- label.setAttribute( "title", "Only show tests and assertons that fail. Stored in sessionStorage." );
- label.innerHTML = "Hide passed tests";
- toolbar.appendChild( label );
-
- urlConfigCheckboxesContainer = document.createElement("span");
- urlConfigCheckboxesContainer.innerHTML = urlConfigHtml;
- urlConfigCheckboxes = urlConfigCheckboxesContainer.getElementsByTagName("input");
- // For oldIE support:
- // * Add handlers to the individual elements instead of the container
- // * Use "click" instead of "change"
- // * Fallback from event.target to event.srcElement
- addEvents( urlConfigCheckboxes, "click", function( event ) {
- var params = {},
- target = event.target || event.srcElement;
- params[ target.name ] = target.checked ? true : undefined;
- window.location = QUnit.url( params );
- });
- toolbar.appendChild( urlConfigCheckboxesContainer );
-
- if (numModules > 1) {
- moduleFilter = document.createElement( 'span' );
- moduleFilter.setAttribute( 'id', 'qunit-modulefilter-container' );
- moduleFilter.innerHTML = moduleFilterHtml;
- addEvent( moduleFilter.lastChild, "change", function() {
- var selectBox = moduleFilter.getElementsByTagName("select")[0],
- selectedModule = decodeURIComponent(selectBox.options[selectBox.selectedIndex].value);
-
- window.location = QUnit.url( { module: ( selectedModule === "" ) ? undefined : selectedModule } );
- });
- toolbar.appendChild(moduleFilter);
- }
- }
-
- // `main` initialized at top of scope
- main = id( "qunit-fixture" );
- if ( main ) {
- config.fixture = main.innerHTML;
- }
-
- if ( config.autostart ) {
- QUnit.start();
- }
-};
-
-addEvent( window, "load", QUnit.load );
-
-// `onErrorFnPrev` initialized at top of scope
-// Preserve other handlers
-onErrorFnPrev = window.onerror;
-
-// Cover uncaught exceptions
-// Returning true will surpress the default browser handler,
-// returning false will let it run.
-window.onerror = function ( error, filePath, linerNr ) {
- var ret = false;
- if ( onErrorFnPrev ) {
- ret = onErrorFnPrev( error, filePath, linerNr );
- }
-
- // Treat return value as window.onerror itself does,
- // Only do our handling if not surpressed.
- if ( ret !== true ) {
- if ( QUnit.config.current ) {
- if ( QUnit.config.current.ignoreGlobalErrors ) {
- return true;
- }
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- } else {
- QUnit.test( "global failure", extend( function() {
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- }, { validTest: validTest } ) );
- }
- return false;
- }
-
- return ret;
-};
-
-function done() {
- config.autorun = true;
-
- // Log the last module results
- if ( config.currentModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.currentModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
-
- var i, key,
- banner = id( "qunit-banner" ),
- tests = id( "qunit-tests" ),
- runtime = +new Date() - config.started,
- passed = config.stats.all - config.stats.bad,
- html = [
- "Tests completed in ",
- runtime,
- " milliseconds.
",
- "",
- passed,
- " assertions of ",
- config.stats.all,
- " passed, ",
- config.stats.bad,
- " failed."
- ].join( "" );
-
- if ( banner ) {
- banner.className = ( config.stats.bad ? "qunit-fail" : "qunit-pass" );
- }
-
- if ( tests ) {
- id( "qunit-testresult" ).innerHTML = html;
- }
-
- if ( config.altertitle && typeof document !== "undefined" && document.title ) {
- // show ✖ for good, ✔ for bad suite result in title
- // use escape sequences in case file gets loaded with non-utf-8-charset
- document.title = [
- ( config.stats.bad ? "\u2716" : "\u2714" ),
- document.title.replace( /^[\u2714\u2716] /i, "" )
- ].join( " " );
- }
-
- // clear own sessionStorage items if all tests passed
- if ( config.reorder && defined.sessionStorage && config.stats.bad === 0 ) {
- // `key` & `i` initialized at top of scope
- for ( i = 0; i < sessionStorage.length; i++ ) {
- key = sessionStorage.key( i++ );
- if ( key.indexOf( "qunit-test-" ) === 0 ) {
- sessionStorage.removeItem( key );
- }
- }
- }
-
- // scroll back to top to show results
- if ( window.scrollTo ) {
- window.scrollTo(0, 0);
- }
-
- runLoggingCallbacks( "done", QUnit, {
- failed: config.stats.bad,
- passed: passed,
- total: config.stats.all,
- runtime: runtime
- });
-}
-
-/** @return Boolean: true if this test should be ran */
-function validTest( test ) {
- var include,
- filter = config.filter && config.filter.toLowerCase(),
- module = config.module && config.module.toLowerCase(),
- fullName = (test.module + ": " + test.testName).toLowerCase();
-
- // Internally-generated tests are always valid
- if ( test.callback && test.callback.validTest === validTest ) {
- delete test.callback.validTest;
- return true;
- }
-
- if ( config.testNumber ) {
- return test.testNumber === config.testNumber;
- }
-
- if ( module && ( !test.module || test.module.toLowerCase() !== module ) ) {
- return false;
- }
-
- if ( !filter ) {
- return true;
- }
-
- include = filter.charAt( 0 ) !== "!";
- if ( !include ) {
- filter = filter.slice( 1 );
- }
-
- // If the filter matches, we need to honour include
- if ( fullName.indexOf( filter ) !== -1 ) {
- return include;
- }
-
- // Otherwise, do the opposite
- return !include;
-}
-
-// so far supports only Firefox, Chrome and Opera (buggy), Safari (for real exceptions)
-// Later Safari and IE10 are supposed to support error.stack as well
-// See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack
-function extractStacktrace( e, offset ) {
- offset = offset === undefined ? 3 : offset;
-
- var stack, include, i;
-
- if ( e.stacktrace ) {
- // Opera
- return e.stacktrace.split( "\n" )[ offset + 3 ];
- } else if ( e.stack ) {
- // Firefox, Chrome
- stack = e.stack.split( "\n" );
- if (/^error$/i.test( stack[0] ) ) {
- stack.shift();
- }
- if ( fileName ) {
- include = [];
- for ( i = offset; i < stack.length; i++ ) {
- if ( stack[ i ].indexOf( fileName ) !== -1 ) {
- break;
- }
- include.push( stack[ i ] );
- }
- if ( include.length ) {
- return include.join( "\n" );
- }
- }
- return stack[ offset ];
- } else if ( e.sourceURL ) {
- // Safari, PhantomJS
- // hopefully one day Safari provides actual stacktraces
- // exclude useless self-reference for generated Error objects
- if ( /qunit.js$/.test( e.sourceURL ) ) {
- return;
- }
- // for actual exceptions, this is useful
- return e.sourceURL + ":" + e.line;
- }
-}
-function sourceFromStacktrace( offset ) {
- try {
- throw new Error();
- } catch ( e ) {
- return extractStacktrace( e, offset );
- }
-}
-
-/**
- * Escape text for attribute or text content.
- */
-function escapeText( s ) {
- if ( !s ) {
- return "";
- }
- s = s + "";
- // Both single quotes and double quotes (for attributes)
- return s.replace( /['"<>&]/g, function( s ) {
- switch( s ) {
- case '\'':
- return ''';
- case '"':
- return '"';
- case '<':
- return '<';
- case '>':
- return '>';
- case '&':
- return '&';
- }
- });
-}
-
-function synchronize( callback, last ) {
- config.queue.push( callback );
-
- if ( config.autorun && !config.blocking ) {
- process( last );
- }
-}
-
-function process( last ) {
- function next() {
- process( last );
- }
- var start = new Date().getTime();
- config.depth = config.depth ? config.depth + 1 : 1;
-
- while ( config.queue.length && !config.blocking ) {
- if ( !defined.setTimeout || config.updateRate <= 0 || ( ( new Date().getTime() - start ) < config.updateRate ) ) {
- config.queue.shift()();
- } else {
- window.setTimeout( next, 13 );
- break;
- }
- }
- config.depth--;
- if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) {
- done();
- }
-}
-
-function saveGlobal() {
- config.pollution = [];
-
- if ( config.noglobals ) {
- for ( var key in window ) {
- // in Opera sometimes DOM element ids show up here, ignore them
- if ( !hasOwn.call( window, key ) || /^qunit-test-output/.test( key ) ) {
- continue;
- }
- config.pollution.push( key );
- }
- }
-}
-
-function checkPollution() {
- var newGlobals,
- deletedGlobals,
- old = config.pollution;
-
- saveGlobal();
-
- newGlobals = diff( config.pollution, old );
- if ( newGlobals.length > 0 ) {
- QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join(", ") );
- }
-
- deletedGlobals = diff( old, config.pollution );
- if ( deletedGlobals.length > 0 ) {
- QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join(", ") );
- }
-}
-
-// returns a new Array with the elements that are in a but not in b
-function diff( a, b ) {
- var i, j,
- result = a.slice();
-
- for ( i = 0; i < result.length; i++ ) {
- for ( j = 0; j < b.length; j++ ) {
- if ( result[i] === b[j] ) {
- result.splice( i, 1 );
- i--;
- break;
- }
- }
- }
- return result;
-}
-
-function extend( a, b ) {
- for ( var prop in b ) {
- if ( b[ prop ] === undefined ) {
- delete a[ prop ];
-
- // Avoid "Member not found" error in IE8 caused by setting window.constructor
- } else if ( prop !== "constructor" || a !== window ) {
- a[ prop ] = b[ prop ];
- }
- }
-
- return a;
-}
-
-/**
- * @param {HTMLElement} elem
- * @param {string} type
- * @param {Function} fn
- */
-function addEvent( elem, type, fn ) {
- // Standards-based browsers
- if ( elem.addEventListener ) {
- elem.addEventListener( type, fn, false );
- // IE
- } else {
- elem.attachEvent( "on" + type, fn );
- }
-}
-
-/**
- * @param {Array|NodeList} elems
- * @param {string} type
- * @param {Function} fn
- */
-function addEvents( elems, type, fn ) {
- var i = elems.length;
- while ( i-- ) {
- addEvent( elems[i], type, fn );
- }
-}
-
-function hasClass( elem, name ) {
- return (" " + elem.className + " ").indexOf(" " + name + " ") > -1;
-}
-
-function addClass( elem, name ) {
- if ( !hasClass( elem, name ) ) {
- elem.className += (elem.className ? " " : "") + name;
- }
-}
-
-function removeClass( elem, name ) {
- var set = " " + elem.className + " ";
- // Class name may appear multiple times
- while ( set.indexOf(" " + name + " ") > -1 ) {
- set = set.replace(" " + name + " " , " ");
- }
- // If possible, trim it for prettiness, but not neccecarily
- elem.className = window.jQuery ? jQuery.trim( set ) : ( set.trim ? set.trim() : set );
-}
-
-function id( name ) {
- return !!( typeof document !== "undefined" && document && document.getElementById ) &&
- document.getElementById( name );
-}
-
-function registerLoggingCallback( key ) {
- return function( callback ) {
- config[key].push( callback );
- };
-}
-
-// Supports deprecated method of completely overwriting logging callbacks
-function runLoggingCallbacks( key, scope, args ) {
- var i, callbacks;
- if ( QUnit.hasOwnProperty( key ) ) {
- QUnit[ key ].call(scope, args );
- } else {
- callbacks = config[ key ];
- for ( i = 0; i < callbacks.length; i++ ) {
- callbacks[ i ].call( scope, args );
- }
- }
-}
-
-// Test for equality any JavaScript type.
-// Author: Philippe Rathé
-QUnit.equiv = (function() {
-
- // Call the o related callback with the given arguments.
- function bindCallbacks( o, callbacks, args ) {
- var prop = QUnit.objectType( o );
- if ( prop ) {
- if ( QUnit.objectType( callbacks[ prop ] ) === "function" ) {
- return callbacks[ prop ].apply( callbacks, args );
- } else {
- return callbacks[ prop ]; // or undefined
- }
- }
- }
-
- // the real equiv function
- var innerEquiv,
- // stack to decide between skip/abort functions
- callers = [],
- // stack to avoiding loops from circular referencing
- parents = [],
-
- getProto = Object.getPrototypeOf || function ( obj ) {
- return obj.__proto__;
- },
- callbacks = (function () {
-
- // for string, boolean, number and null
- function useStrictEquality( b, a ) {
- /*jshint eqeqeq:false */
- if ( b instanceof a.constructor || a instanceof b.constructor ) {
- // to catch short annotaion VS 'new' annotation of a
- // declaration
- // e.g. var i = 1;
- // var j = new Number(1);
- return a == b;
- } else {
- return a === b;
- }
- }
-
- return {
- "string": useStrictEquality,
- "boolean": useStrictEquality,
- "number": useStrictEquality,
- "null": useStrictEquality,
- "undefined": useStrictEquality,
-
- "nan": function( b ) {
- return isNaN( b );
- },
-
- "date": function( b, a ) {
- return QUnit.objectType( b ) === "date" && a.valueOf() === b.valueOf();
- },
-
- "regexp": function( b, a ) {
- return QUnit.objectType( b ) === "regexp" &&
- // the regex itself
- a.source === b.source &&
- // and its modifers
- a.global === b.global &&
- // (gmi) ...
- a.ignoreCase === b.ignoreCase &&
- a.multiline === b.multiline &&
- a.sticky === b.sticky;
- },
-
- // - skip when the property is a method of an instance (OOP)
- // - abort otherwise,
- // initial === would have catch identical references anyway
- "function": function() {
- var caller = callers[callers.length - 1];
- return caller !== Object && typeof caller !== "undefined";
- },
-
- "array": function( b, a ) {
- var i, j, len, loop;
-
- // b could be an object literal here
- if ( QUnit.objectType( b ) !== "array" ) {
- return false;
- }
-
- len = a.length;
- if ( len !== b.length ) {
- // safe and faster
- return false;
- }
-
- // track reference to avoid circular references
- parents.push( a );
- for ( i = 0; i < len; i++ ) {
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- loop = true;// dont rewalk array
- }
- }
- if ( !loop && !innerEquiv(a[i], b[i]) ) {
- parents.pop();
- return false;
- }
- }
- parents.pop();
- return true;
- },
-
- "object": function( b, a ) {
- var i, j, loop,
- // Default to true
- eq = true,
- aProperties = [],
- bProperties = [];
-
- // comparing constructors is more strict than using
- // instanceof
- if ( a.constructor !== b.constructor ) {
- // Allow objects with no prototype to be equivalent to
- // objects with Object as their constructor.
- if ( !(( getProto(a) === null && getProto(b) === Object.prototype ) ||
- ( getProto(b) === null && getProto(a) === Object.prototype ) ) ) {
- return false;
- }
- }
-
- // stack constructor before traversing properties
- callers.push( a.constructor );
- // track reference to avoid circular references
- parents.push( a );
-
- for ( i in a ) { // be strict: don't ensures hasOwnProperty
- // and go deep
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- // don't go down the same path twice
- loop = true;
- }
- }
- aProperties.push(i); // collect a's properties
-
- if (!loop && !innerEquiv( a[i], b[i] ) ) {
- eq = false;
- break;
- }
- }
-
- callers.pop(); // unstack, we are done
- parents.pop();
-
- for ( i in b ) {
- bProperties.push( i ); // collect b's properties
- }
-
- // Ensures identical properties name
- return eq && innerEquiv( aProperties.sort(), bProperties.sort() );
- }
- };
- }());
-
- innerEquiv = function() { // can take multiple arguments
- var args = [].slice.apply( arguments );
- if ( args.length < 2 ) {
- return true; // end transition
- }
-
- return (function( a, b ) {
- if ( a === b ) {
- return true; // catch the most you can
- } else if ( a === null || b === null || typeof a === "undefined" ||
- typeof b === "undefined" ||
- QUnit.objectType(a) !== QUnit.objectType(b) ) {
- return false; // don't lose time with error prone cases
- } else {
- return bindCallbacks(a, callbacks, [ b, a ]);
- }
-
- // apply transition with (1..n) arguments
- }( args[0], args[1] ) && arguments.callee.apply( this, args.splice(1, args.length - 1 )) );
- };
-
- return innerEquiv;
-}());
-
-/**
- * jsDump Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com |
- * http://flesler.blogspot.com Licensed under BSD
- * (http://www.opensource.org/licenses/bsd-license.php) Date: 5/15/2008
- *
- * @projectDescription Advanced and extensible data dumping for Javascript.
- * @version 1.0.0
- * @author Ariel Flesler
- * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html}
- */
-QUnit.jsDump = (function() {
- function quote( str ) {
- return '"' + str.toString().replace( /"/g, '\\"' ) + '"';
- }
- function literal( o ) {
- return o + "";
- }
- function join( pre, arr, post ) {
- var s = jsDump.separator(),
- base = jsDump.indent(),
- inner = jsDump.indent(1);
- if ( arr.join ) {
- arr = arr.join( "," + s + inner );
- }
- if ( !arr ) {
- return pre + post;
- }
- return [ pre, inner + arr, base + post ].join(s);
- }
- function array( arr, stack ) {
- var i = arr.length, ret = new Array(i);
- this.up();
- while ( i-- ) {
- ret[i] = this.parse( arr[i] , undefined , stack);
- }
- this.down();
- return join( "[", ret, "]" );
- }
-
- var reName = /^function (\w+)/,
- jsDump = {
- // type is used mostly internally, you can fix a (custom)type in advance
- parse: function( obj, type, stack ) {
- stack = stack || [ ];
- var inStack, res,
- parser = this.parsers[ type || this.typeOf(obj) ];
-
- type = typeof parser;
- inStack = inArray( obj, stack );
-
- if ( inStack !== -1 ) {
- return "recursion(" + (inStack - stack.length) + ")";
- }
- if ( type === "function" ) {
- stack.push( obj );
- res = parser.call( this, obj, stack );
- stack.pop();
- return res;
- }
- return ( type === "string" ) ? parser : this.parsers.error;
- },
- typeOf: function( obj ) {
- var type;
- if ( obj === null ) {
- type = "null";
- } else if ( typeof obj === "undefined" ) {
- type = "undefined";
- } else if ( QUnit.is( "regexp", obj) ) {
- type = "regexp";
- } else if ( QUnit.is( "date", obj) ) {
- type = "date";
- } else if ( QUnit.is( "function", obj) ) {
- type = "function";
- } else if ( typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined" ) {
- type = "window";
- } else if ( obj.nodeType === 9 ) {
- type = "document";
- } else if ( obj.nodeType ) {
- type = "node";
- } else if (
- // native arrays
- toString.call( obj ) === "[object Array]" ||
- // NodeList objects
- ( typeof obj.length === "number" && typeof obj.item !== "undefined" && ( obj.length ? obj.item(0) === obj[0] : ( obj.item( 0 ) === null && typeof obj[0] === "undefined" ) ) )
- ) {
- type = "array";
- } else if ( obj.constructor === Error.prototype.constructor ) {
- type = "error";
- } else {
- type = typeof obj;
- }
- return type;
- },
- separator: function() {
- return this.multiline ? this.HTML ? "
" : "\n" : this.HTML ? " " : " ";
- },
- // extra can be a number, shortcut for increasing-calling-decreasing
- indent: function( extra ) {
- if ( !this.multiline ) {
- return "";
- }
- var chr = this.indentChar;
- if ( this.HTML ) {
- chr = chr.replace( /\t/g, " " ).replace( / /g, " " );
- }
- return new Array( this._depth_ + (extra||0) ).join(chr);
- },
- up: function( a ) {
- this._depth_ += a || 1;
- },
- down: function( a ) {
- this._depth_ -= a || 1;
- },
- setParser: function( name, parser ) {
- this.parsers[name] = parser;
- },
- // The next 3 are exposed so you can use them
- quote: quote,
- literal: literal,
- join: join,
- //
- _depth_: 1,
- // This is the list of parsers, to modify them, use jsDump.setParser
- parsers: {
- window: "[Window]",
- document: "[Document]",
- error: function(error) {
- return "Error(\"" + error.message + "\")";
- },
- unknown: "[Unknown]",
- "null": "null",
- "undefined": "undefined",
- "function": function( fn ) {
- var ret = "function",
- // functions never have name in IE
- name = "name" in fn ? fn.name : (reName.exec(fn) || [])[1];
-
- if ( name ) {
- ret += " " + name;
- }
- ret += "( ";
-
- ret = [ ret, QUnit.jsDump.parse( fn, "functionArgs" ), "){" ].join( "" );
- return join( ret, QUnit.jsDump.parse(fn,"functionCode" ), "}" );
- },
- array: array,
- nodelist: array,
- "arguments": array,
- object: function( map, stack ) {
- var ret = [ ], keys, key, val, i;
- QUnit.jsDump.up();
- keys = [];
- for ( key in map ) {
- keys.push( key );
- }
- keys.sort();
- for ( i = 0; i < keys.length; i++ ) {
- key = keys[ i ];
- val = map[ key ];
- ret.push( QUnit.jsDump.parse( key, "key" ) + ": " + QUnit.jsDump.parse( val, undefined, stack ) );
- }
- QUnit.jsDump.down();
- return join( "{", ret, "}" );
- },
- node: function( node ) {
- var len, i, val,
- open = QUnit.jsDump.HTML ? "<" : "<",
- close = QUnit.jsDump.HTML ? ">" : ">",
- tag = node.nodeName.toLowerCase(),
- ret = open + tag,
- attrs = node.attributes;
-
- if ( attrs ) {
- for ( i = 0, len = attrs.length; i < len; i++ ) {
- val = attrs[i].nodeValue;
- // IE6 includes all attributes in .attributes, even ones not explicitly set.
- // Those have values like undefined, null, 0, false, "" or "inherit".
- if ( val && val !== "inherit" ) {
- ret += " " + attrs[i].nodeName + "=" + QUnit.jsDump.parse( val, "attribute" );
- }
- }
- }
- ret += close;
-
- // Show content of TextNode or CDATASection
- if ( node.nodeType === 3 || node.nodeType === 4 ) {
- ret += node.nodeValue;
- }
-
- return ret + open + "/" + tag + close;
- },
- // function calls it internally, it's the arguments part of the function
- functionArgs: function( fn ) {
- var args,
- l = fn.length;
-
- if ( !l ) {
- return "";
- }
-
- args = new Array(l);
- while ( l-- ) {
- // 97 is 'a'
- args[l] = String.fromCharCode(97+l);
- }
- return " " + args.join( ", " ) + " ";
- },
- // object calls it internally, the key part of an item in a map
- key: quote,
- // function calls it internally, it's the content of the function
- functionCode: "[code]",
- // node calls it internally, it's an html attribute value
- attribute: quote,
- string: quote,
- date: quote,
- regexp: literal,
- number: literal,
- "boolean": literal
- },
- // if true, entities are escaped ( <, >, \t, space and \n )
- HTML: false,
- // indentation unit
- indentChar: " ",
- // if true, items in a collection, are separated by a \n, else just a space.
- multiline: true
- };
-
- return jsDump;
-}());
-
-// from jquery.js
-function inArray( elem, array ) {
- if ( array.indexOf ) {
- return array.indexOf( elem );
- }
-
- for ( var i = 0, length = array.length; i < length; i++ ) {
- if ( array[ i ] === elem ) {
- return i;
- }
- }
-
- return -1;
-}
-
-/*
- * Javascript Diff Algorithm
- * By John Resig (http://ejohn.org/)
- * Modified by Chu Alan "sprite"
- *
- * Released under the MIT license.
- *
- * More Info:
- * http://ejohn.org/projects/javascript-diff-algorithm/
- *
- * Usage: QUnit.diff(expected, actual)
- *
- * QUnit.diff( "the quick brown fox jumped over", "the quick fox jumps over" ) == "the quick brown fox jumped jumps over"
- */
-QUnit.diff = (function() {
- /*jshint eqeqeq:false, eqnull:true */
- function diff( o, n ) {
- var i,
- ns = {},
- os = {};
-
- for ( i = 0; i < n.length; i++ ) {
- if ( !hasOwn.call( ns, n[i] ) ) {
- ns[ n[i] ] = {
- rows: [],
- o: null
- };
- }
- ns[ n[i] ].rows.push( i );
- }
-
- for ( i = 0; i < o.length; i++ ) {
- if ( !hasOwn.call( os, o[i] ) ) {
- os[ o[i] ] = {
- rows: [],
- n: null
- };
- }
- os[ o[i] ].rows.push( i );
- }
-
- for ( i in ns ) {
- if ( !hasOwn.call( ns, i ) ) {
- continue;
- }
- if ( ns[i].rows.length === 1 && hasOwn.call( os, i ) && os[i].rows.length === 1 ) {
- n[ ns[i].rows[0] ] = {
- text: n[ ns[i].rows[0] ],
- row: os[i].rows[0]
- };
- o[ os[i].rows[0] ] = {
- text: o[ os[i].rows[0] ],
- row: ns[i].rows[0]
- };
- }
- }
-
- for ( i = 0; i < n.length - 1; i++ ) {
- if ( n[i].text != null && n[ i + 1 ].text == null && n[i].row + 1 < o.length && o[ n[i].row + 1 ].text == null &&
- n[ i + 1 ] == o[ n[i].row + 1 ] ) {
-
- n[ i + 1 ] = {
- text: n[ i + 1 ],
- row: n[i].row + 1
- };
- o[ n[i].row + 1 ] = {
- text: o[ n[i].row + 1 ],
- row: i + 1
- };
- }
- }
-
- for ( i = n.length - 1; i > 0; i-- ) {
- if ( n[i].text != null && n[ i - 1 ].text == null && n[i].row > 0 && o[ n[i].row - 1 ].text == null &&
- n[ i - 1 ] == o[ n[i].row - 1 ]) {
-
- n[ i - 1 ] = {
- text: n[ i - 1 ],
- row: n[i].row - 1
- };
- o[ n[i].row - 1 ] = {
- text: o[ n[i].row - 1 ],
- row: i - 1
- };
- }
- }
-
- return {
- o: o,
- n: n
- };
- }
-
- return function( o, n ) {
- o = o.replace( /\s+$/, "" );
- n = n.replace( /\s+$/, "" );
-
- var i, pre,
- str = "",
- out = diff( o === "" ? [] : o.split(/\s+/), n === "" ? [] : n.split(/\s+/) ),
- oSpace = o.match(/\s+/g),
- nSpace = n.match(/\s+/g);
-
- if ( oSpace == null ) {
- oSpace = [ " " ];
- }
- else {
- oSpace.push( " " );
- }
-
- if ( nSpace == null ) {
- nSpace = [ " " ];
- }
- else {
- nSpace.push( " " );
- }
-
- if ( out.n.length === 0 ) {
- for ( i = 0; i < out.o.length; i++ ) {
- str += "" + out.o[i] + oSpace[i] + "";
- }
- }
- else {
- if ( out.n[0].text == null ) {
- for ( n = 0; n < out.o.length && out.o[n].text == null; n++ ) {
- str += "" + out.o[n] + oSpace[n] + "";
- }
- }
-
- for ( i = 0; i < out.n.length; i++ ) {
- if (out.n[i].text == null) {
- str += "" + out.n[i] + nSpace[i] + "";
- }
- else {
- // `pre` initialized at top of scope
- pre = "";
-
- for ( n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++ ) {
- pre += "" + out.o[n] + oSpace[n] + "";
- }
- str += " " + out.n[i].text + nSpace[i] + pre;
- }
- }
- }
-
- return str;
- };
-}());
-
-// for CommonJS enviroments, export everything
-if ( typeof exports !== "undefined" ) {
- extend( exports, QUnit );
-}
-
-// get at whatever the global object is, like window in browsers
-}( (function() {return this;}.call()) ));
diff --git a/test/lib/require.js b/test/lib/require.js
deleted file mode 100644
index 987f865..0000000
--- a/test/lib/require.js
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- RequireJS 2.1.5 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.
- Available via the MIT or new BSD license.
- see: http://github.com/jrburke/requirejs for details
-*/
-var requirejs,require,define;
-(function(aa){function I(b){return"[object Function]"===L.call(b)}function J(b){return"[object Array]"===L.call(b)}function y(b,c){if(b){var d;for(d=0;dthis.depCount&&!this.defined){if(I(n)){if(this.events.error)try{e=i.execCb(c,n,b,e)}catch(d){a=d}else e=i.execCb(c,n,b,e);this.map.isDefine&&((b=this.module)&&void 0!==b.exports&&b.exports!==this.exports?e=b.exports:void 0===e&&this.usingExports&&(e=this.exports));if(a)return a.requireMap=this.map,a.requireModules=[this.map.id],a.requireType="define",v(this.error=
-a)}else e=n;this.exports=e;if(this.map.isDefine&&!this.ignore&&(q[c]=e,l.onResourceLoad))l.onResourceLoad(i,this.map,this.depMaps);x(c);this.defined=!0}this.defining=!1;this.defined&&!this.defineEmitted&&(this.defineEmitted=!0,this.emit("defined",this.exports),this.defineEmitComplete=!0)}}else this.fetch()}},callPlugin:function(){var a=this.map,b=a.id,d=j(a.prefix);this.depMaps.push(d);t(d,"defined",u(this,function(e){var n,d;d=this.map.name;var g=this.map.parentMap?this.map.parentMap.name:null,h=
-i.makeRequire(a.parentMap,{enableBuildCallback:!0});if(this.map.unnormalized){if(e.normalize&&(d=e.normalize(d,function(a){return c(a,g,!0)})||""),e=j(a.prefix+"!"+d,this.map.parentMap),t(e,"defined",u(this,function(a){this.init([],function(){return a},null,{enabled:!0,ignore:!0})})),d=m(p,e.id)){this.depMaps.push(e);if(this.events.error)d.on("error",u(this,function(a){this.emit("error",a)}));d.enable()}}else n=u(this,function(a){this.init([],function(){return a},null,{enabled:!0})}),n.error=u(this,
-function(a){this.inited=!0;this.error=a;a.requireModules=[b];G(p,function(a){0===a.map.id.indexOf(b+"_unnormalized")&&x(a.map.id)});v(a)}),n.fromText=u(this,function(e,c){var d=a.name,g=j(d),C=O;c&&(e=c);C&&(O=!1);r(g);s(k.config,b)&&(k.config[d]=k.config[b]);try{l.exec(e)}catch(ca){return v(B("fromtexteval","fromText eval for "+b+" failed: "+ca,ca,[b]))}C&&(O=!0);this.depMaps.push(g);i.completeLoad(d);h([d],n)}),e.load(a.name,h,n,k)}));i.enable(d,this);this.pluginMaps[d.id]=d},enable:function(){V[this.map.id]=
-this;this.enabling=this.enabled=!0;y(this.depMaps,u(this,function(a,b){var c,e;if("string"===typeof a){a=j(a,this.map.isDefine?this.map:this.map.parentMap,!1,!this.skipMap);this.depMaps[b]=a;if(c=m(N,a.id)){this.depExports[b]=c(this);return}this.depCount+=1;t(a,"defined",u(this,function(a){this.defineDep(b,a);this.check()}));this.errback&&t(a,"error",this.errback)}c=a.id;e=p[c];!s(N,c)&&(e&&!e.enabled)&&i.enable(a,this)}));G(this.pluginMaps,u(this,function(a){var b=m(p,a.id);b&&!b.enabled&&i.enable(a,
-this)}));this.enabling=!1;this.check()},on:function(a,b){var c=this.events[a];c||(c=this.events[a]=[]);c.push(b)},emit:function(a,b){y(this.events[a],function(a){a(b)});"error"===a&&delete this.events[a]}};i={config:k,contextName:b,registry:p,defined:q,urlFetched:U,defQueue:H,Module:Z,makeModuleMap:j,nextTick:l.nextTick,onError:v,configure:function(a){a.baseUrl&&"/"!==a.baseUrl.charAt(a.baseUrl.length-1)&&(a.baseUrl+="/");var b=k.pkgs,c=k.shim,e={paths:!0,config:!0,map:!0};G(a,function(a,b){e[b]?
-"map"===b?(k.map||(k.map={}),R(k[b],a,!0,!0)):R(k[b],a,!0):k[b]=a});a.shim&&(G(a.shim,function(a,b){J(a)&&(a={deps:a});if((a.exports||a.init)&&!a.exportsFn)a.exportsFn=i.makeShimExports(a);c[b]=a}),k.shim=c);a.packages&&(y(a.packages,function(a){a="string"===typeof a?{name:a}:a;b[a.name]={name:a.name,location:a.location||a.name,main:(a.main||"main").replace(ja,"").replace(ea,"")}}),k.pkgs=b);G(p,function(a,b){!a.inited&&!a.map.unnormalized&&(a.map=j(b))});if(a.deps||a.callback)i.require(a.deps||[],
-a.callback)},makeShimExports:function(a){return function(){var b;a.init&&(b=a.init.apply(aa,arguments));return b||a.exports&&ba(a.exports)}},makeRequire:function(a,f){function d(e,c,h){var g,k;f.enableBuildCallback&&(c&&I(c))&&(c.__requireJsBuild=!0);if("string"===typeof e){if(I(c))return v(B("requireargs","Invalid require call"),h);if(a&&s(N,e))return N[e](p[a.id]);if(l.get)return l.get(i,e,a,d);g=j(e,a,!1,!0);g=g.id;return!s(q,g)?v(B("notloaded",'Module name "'+g+'" has not been loaded yet for context: '+
-b+(a?"":". Use require([])"))):q[g]}L();i.nextTick(function(){L();k=r(j(null,a));k.skipMap=f.skipMap;k.init(e,c,h,{enabled:!0});D()});return d}f=f||{};R(d,{isBrowser:A,toUrl:function(b){var d,f=b.lastIndexOf("."),g=b.split("/")[0];if(-1!==f&&(!("."===g||".."===g)||1h.attachEvent.toString().indexOf("[native code"))&&!Y?(O=!0,h.attachEvent("onreadystatechange",b.onScriptLoad)):(h.addEventListener("load",b.onScriptLoad,!1),h.addEventListener("error",b.onScriptError,!1)),h.src=d,K=h,D?x.insertBefore(h,D):x.appendChild(h),K=null,h;if(da)try{importScripts(d),b.completeLoad(c)}catch(j){b.onError(B("importscripts","importScripts failed for "+c+" at "+d,j,[c]))}};A&&M(document.getElementsByTagName("script"),function(b){x||(x=
-b.parentNode);if(t=b.getAttribute("data-main"))return r.baseUrl||(E=t.split("/"),Q=E.pop(),fa=E.length?E.join("/")+"/":"./",r.baseUrl=fa,t=Q),t=t.replace(ea,""),r.deps=r.deps?r.deps.concat(t):[t],!0});define=function(b,c,d){var l,h;"string"!==typeof b&&(d=c,c=b,b=null);J(c)||(d=c,c=[]);!c.length&&I(d)&&d.length&&(d.toString().replace(la,"").replace(ma,function(b,d){c.push(d)}),c=(1===d.length?["require"]:["require","exports","module"]).concat(c));if(O){if(!(l=K))P&&"interactive"===P.readyState||M(document.getElementsByTagName("script"),
-function(b){if("interactive"===b.readyState)return P=b}),l=P;l&&(b||(b=l.getAttribute("data-requiremodule")),h=F[l.getAttribute("data-requirecontext")])}(h?h.defQueue:T).push([b,c,d])};define.amd={jQuery:!0};l.exec=function(b){return eval(b)};l(r)}})(this);
diff --git a/test/lib/resemble.js b/test/lib/resemble.js
new file mode 100644
index 0000000..1cb8c29
--- /dev/null
+++ b/test/lib/resemble.js
@@ -0,0 +1,535 @@
+/*
+Author: James Cryer
+Company: Huddle
+Last updated date: 21 Feb 2013
+URL: https://github.com/Huddle/Resemble.js
+*/
+
+(function(_this){
+ 'use strict';
+
+ _this['resemble'] = function( fileData ){
+
+ var data = {};
+ var images = [];
+ var updateCallbackArray = [];
+
+ var tolerance = { // between 0 and 255
+ red: 16,
+ green: 16,
+ blue: 16,
+ minBrightness: 16,
+ maxBrightness: 240
+ };
+
+ var ignoreAntialiasing = false;
+ var ignoreColors = false;
+
+ function triggerDataUpdate(){
+ var len = updateCallbackArray.length;
+ var i;
+ for(i=0;i tolerance.maxBrightness;
+ }
+
+ function getHue(r,g,b){
+
+ r = r / 255;
+ g = g / 255;
+ b = b / 255;
+ var max = Math.max(r, g, b), min = Math.min(r, g, b);
+ var h;
+ var d;
+
+ if (max == min){
+ h = 0; // achromatic
+ } else{
+ d = max - min;
+ switch(max){
+ case r: h = (g - b) / d + (g < b ? 6 : 0); break;
+ case g: h = (b - r) / d + 2; break;
+ case b: h = (r - g) / d + 4; break;
+ }
+ h /= 6;
+ }
+
+ return h;
+ }
+
+ function isAntialiased(sourcePix, data, cacheSet, verticalPos, horizontalPos, width){
+ var offset;
+ var targetPix;
+ var distance = 1;
+ var i;
+ var j;
+ var hasHighContrastSibling = 0;
+ var hasSiblingWithDifferentHue = 0;
+ var hasEquivilantSibling = 0;
+
+ addHueInfo(sourcePix);
+
+ for (i = distance*-1; i <= distance; i++){
+ for (j = distance*-1; j <= distance; j++){
+
+ if(i===0 && j===0){
+ // ignore source pixel
+ } else {
+
+ offset = ((verticalPos+j)*width + (horizontalPos+i)) * 4;
+ targetPix = getPixelInfo(data, offset, cacheSet);
+
+ if(targetPix === null){
+ continue;
+ }
+
+ addBrightnessInfo(targetPix);
+ addHueInfo(targetPix);
+
+ if( isContrasting(sourcePix, targetPix) ){
+ hasHighContrastSibling++;
+ }
+
+ if( isRGBSame(sourcePix,targetPix) ){
+ hasEquivilantSibling++;
+ }
+
+ if( Math.abs(targetPix.h - sourcePix.h) > 0.3 ){
+ hasSiblingWithDifferentHue++;
+ }
+
+ if( hasSiblingWithDifferentHue > 1 || hasHighContrastSibling > 1){
+ return true;
+ }
+ }
+ }
+ }
+
+ if(hasEquivilantSibling < 2){
+ return true;
+ }
+
+ return false;
+ }
+
+ function errorPixel(px, offset){
+ px[offset] = 255; //r
+ px[offset + 1] = 0; //g
+ px[offset + 2] = 255; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyPixel(px, offset, data){
+ px[offset] = data.r; //r
+ px[offset + 1] = data.g; //g
+ px[offset + 2] = data.b; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyGrayScalePixel(px, offset, data){
+ px[offset] = data.brightness; //r
+ px[offset + 1] = data.brightness; //g
+ px[offset + 2] = data.brightness; //b
+ px[offset + 3] = 255; //a
+ }
+
+
+ function getPixelInfo(data, offset, cacheSet){
+ var r;
+ var g;
+ var b;
+ var d;
+
+ if(typeof data[offset] !== 'undefined'){
+ r = data[offset];
+ g = data[offset+1];
+ b = data[offset+2];
+ d = {
+ r: r,
+ g: g,
+ b: b
+ };
+
+ return d;
+ } else {
+ return null;
+ }
+ }
+
+ function addBrightnessInfo(data){
+ data.brightness = getBrightness(data.r,data.g,data.b); // 'corrected' lightness
+ }
+
+ function addHueInfo(data){
+ data.h = getHue(data.r,data.g,data.b);
+ }
+
+ function analyseImages(img1, img2, width, height){
+
+ var hiddenCanvas = document.createElement('canvas');
+
+ var data1 = img1.data;
+ var data2 = img2.data;
+
+ hiddenCanvas.width = width;
+ hiddenCanvas.height = height;
+
+ var context = hiddenCanvas.getContext('2d');
+ var imgd = context.createImageData(width,height);
+ var targetPix = imgd.data;
+
+ var mismatchCount = 0;
+
+ var time = Date.now();
+
+ var skip;
+
+ if( (width > 1200 || height > 1200) && ignoreAntialiasing){
+ skip = 6;
+ }
+
+ loop(height, width, function(verticalPos, horizontalPos){
+
+ if(skip){ // only skip if the image isn't small
+ if(verticalPos % skip === 0 || horizontalPos % skip === 0){
+ return;
+ }
+ }
+
+ var offset = (verticalPos*width + horizontalPos) * 4;
+ var pixel1 = getPixelInfo(data1, offset, 1);
+ var pixel2 = getPixelInfo(data2, offset, 2);
+
+ if(pixel1 === null || pixel2 === null){
+ return;
+ }
+
+ if (ignoreColors){
+
+ addBrightnessInfo(pixel1);
+ addBrightnessInfo(pixel2);
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ return;
+ }
+
+ if( isRGBSimilar(pixel1, pixel2) ){
+ copyPixel(targetPix, offset, pixel2);
+
+ } else if( ignoreAntialiasing && (
+ addBrightnessInfo(pixel1), // jit pixel info augmentation looks a little weird, sorry.
+ addBrightnessInfo(pixel2),
+ isAntialiased(pixel1, data1, 1, verticalPos, horizontalPos, width) ||
+ isAntialiased(pixel2, data2, 2, verticalPos, horizontalPos, width)
+ )){
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+
+ });
+
+ data.misMatchPercentage = (mismatchCount / (height*width) * 100).toFixed(2);
+ data.analysisTime = Date.now() - time;
+
+ data.getImageDataUrl = function(text){
+ var barHeight = 0;
+
+ if(text){
+ barHeight = addLabel(text,context,hiddenCanvas);
+ }
+
+ context.putImageData(imgd, 0, barHeight);
+
+ return hiddenCanvas.toDataURL("image/png");
+ };
+ }
+
+ function addLabel(text, context, hiddenCanvas){
+ var textPadding = 2;
+
+ context.font = '12px sans-serif';
+
+ var textWidth = context.measureText(text).width + textPadding*2;
+ var barHeight = 22;
+
+ if(textWidth > hiddenCanvas.width){
+ hiddenCanvas.width = textWidth;
+ }
+
+ hiddenCanvas.height += barHeight;
+
+ context.fillStyle = "#666";
+ context.fillRect(0,0,hiddenCanvas.width,barHeight -4);
+ context.fillStyle = "#fff";
+ context.fillRect(0,barHeight -4,hiddenCanvas.width, 4);
+
+ context.fillStyle = "#fff";
+ context.textBaseline = "top";
+ context.font = '12px sans-serif';
+ context.fillText(text, textPadding, 1);
+
+ return barHeight;
+ }
+
+ function normalise(img, w, h){
+ var c;
+ var context;
+
+ if(img.height < h || img.width < w){
+ c = document.createElement('canvas');
+ c.width = w;
+ c.height = h;
+ context = c.getContext('2d');
+ context.putImageData(img, 0, 0);
+ return context.getImageData(0, 0, w, h);
+ }
+
+ return img;
+ }
+
+ function compare(one, two){
+
+ function onceWeHaveBoth(){
+ var width;
+ var height;
+ if(images.length === 2){
+ width = images[0].width > images[1].width ? images[0].width : images[1].width;
+ height = images[0].height > images[1].height ? images[0].height : images[1].height;
+
+ if( (images[0].width === images[1].width) && (images[0].height === images[1].height) ){
+ data.isSameDimensions = true;
+ } else {
+ data.isSameDimensions = false;
+ }
+
+ analyseImages( normalise(images[0],width, height), normalise(images[1],width, height), width, height);
+
+ triggerDataUpdate();
+ }
+ }
+
+ images = [];
+ loadImageData(one, onceWeHaveBoth);
+ loadImageData(two, onceWeHaveBoth);
+ }
+
+ function getCompareApi(param){
+
+ var secondFileData,
+ hasMethod = typeof param === 'function';
+
+ if( !hasMethod ){
+ // assume it's file data
+ secondFileData = param;
+ }
+
+ var self = {
+ ignoreNothing: function(){
+
+ tolerance.red = 16;
+ tolerance.green = 16;
+ tolerance.blue = 16;
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreAntialiasing: function(){
+
+ tolerance.red = 32;
+ tolerance.green = 32;
+ tolerance.blue = 32;
+ tolerance.minBrightness = 64;
+ tolerance.maxBrightness = 96;
+
+ ignoreAntialiasing = true;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreColors: function(){
+
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = true;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ onComplete: function( callback ){
+
+ updateCallbackArray.push(callback);
+
+ var wrapper = function(){
+ compare(fileData, secondFileData);
+ };
+
+ wrapper();
+
+ return getCompareApi(wrapper);
+ }
+ };
+
+ return self;
+ }
+
+ return {
+ onComplete: function( callback ){
+ updateCallbackArray.push(callback);
+ loadImageData(fileData, function(imageData, width, height){
+ parseImage(imageData.data, width, height);
+ });
+ },
+ compareTo: function(secondFileData){
+ return getCompareApi(secondFileData);
+ }
+ };
+
+ };
+}(this));
\ No newline at end of file
diff --git a/test/testsuite.js b/test/testsuite.js
deleted file mode 100644
index b486acb..0000000
--- a/test/testsuite.js
+++ /dev/null
@@ -1,36 +0,0 @@
-requirejs.config({
- baseUrl: '/test/unit/'
-});
-
-define(function(require) {
- var testModules = [
- 'Pixi',
- 'Point',
- 'Rectangle',
- 'DisplayObject',
- 'DisplayObjectContainer',
- 'Sprite',
- 'MovieClip',
- 'InteractionManager',
- 'Stage',
- 'utils/Utils',
- 'utils/EventTarget',
- 'utils/Matrix',
- 'utils/Detector',
- 'renderers/WebGLShaders',
- 'renderers/WebGLRenderer',
- 'renderers/WebGLBatch',
- 'renderers/CanvasRenderer',
- 'extras/Strip',
- 'extras/Rope',
- 'textures/BaseTexture',
- 'textures/Texture',
- 'loaders/SpriteSheetLoader',
- 'loaders/AssetLoader'
- ];
-
- // Resolve all testModules and then start the Test Runner.
- require(testModules, function() {
- QUnit.start();
- });
-});
\ No newline at end of file
diff --git a/test/textures/SpriteSheet-Aliens.png b/test/textures/SpriteSheet-Aliens.png
new file mode 100644
index 0000000..210acb1
--- /dev/null
+++ b/test/textures/SpriteSheet-Aliens.png
Binary files differ
diff --git a/test/textures/SpriteSheet-Explosion.png b/test/textures/SpriteSheet-Explosion.png
new file mode 100755
index 0000000..79e1a69
--- /dev/null
+++ b/test/textures/SpriteSheet-Explosion.png
Binary files differ
diff --git a/test/textures/bunny.png b/test/textures/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/textures/bunny.png
Binary files differ
diff --git a/test/unit/DisplayObject.js b/test/unit/DisplayObject.js
deleted file mode 100644
index 5e7e72f..0000000
--- a/test/unit/DisplayObject.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObject');
-});
diff --git a/test/unit/DisplayObjectContainer.js b/test/unit/DisplayObjectContainer.js
deleted file mode 100644
index b323959..0000000
--- a/test/unit/DisplayObjectContainer.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObjectContainer');
-});
diff --git a/test/unit/InteractionManager.js b/test/unit/InteractionManager.js
deleted file mode 100644
index e751f52..0000000
--- a/test/unit/InteractionManager.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('InteractionManager');
-});
diff --git a/test/unit/MovieClip.js b/test/unit/MovieClip.js
deleted file mode 100644
index 37d9446..0000000
--- a/test/unit/MovieClip.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('MovieClip');
-});
diff --git a/test/unit/Pixi.js b/test/unit/Pixi.js
deleted file mode 100644
index 36eee73..0000000
--- a/test/unit/Pixi.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Pixi');
-});
diff --git a/test/unit/Point.js b/test/unit/Point.js
deleted file mode 100644
index 983ff6e..0000000
--- a/test/unit/Point.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Point');
-});
diff --git a/test/unit/Rectangle.js b/test/unit/Rectangle.js
deleted file mode 100644
index 3b439ba..0000000
--- a/test/unit/Rectangle.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Rectangle');
-});
diff --git a/test/unit/Sprite.js b/test/unit/Sprite.js
deleted file mode 100644
index ed4f596..0000000
--- a/test/unit/Sprite.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Sprite');
-});
diff --git a/test/unit/Stage.js b/test/unit/Stage.js
deleted file mode 100644
index 2d70291..0000000
--- a/test/unit/Stage.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Stage');
-});
diff --git a/test/unit/extras/Rope.js b/test/unit/extras/Rope.js
deleted file mode 100644
index 5606f14..0000000
--- a/test/unit/extras/Rope.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Rope');
-});
diff --git a/test/unit/extras/Strip.js b/test/unit/extras/Strip.js
deleted file mode 100644
index 0134d3a..0000000
--- a/test/unit/extras/Strip.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Strip');
-});
diff --git a/test/unit/loaders/AssetLoader.js b/test/unit/loaders/AssetLoader.js
deleted file mode 100644
index 13b8443..0000000
--- a/test/unit/loaders/AssetLoader.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('AssetLoader');
-});
diff --git a/test/unit/loaders/SpriteSheetLoader.js b/test/unit/loaders/SpriteSheetLoader.js
deleted file mode 100644
index 8bf0cb2..0000000
--- a/test/unit/loaders/SpriteSheetLoader.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('SpriteSheetLoader');
-});
diff --git a/test/unit/pixi/InteractionManager.js b/test/unit/pixi/InteractionManager.js
new file mode 100644
index 0000000..ed3001f
--- /dev/null
+++ b/test/unit/pixi/InteractionManager.js
@@ -0,0 +1,10 @@
+describe('pixi/InteractionManager', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var InteractionManager = PIXI.InteractionManager;
+
+ it('Module exists', function () {
+ expect(InteractionManager).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/Pixi.js b/test/unit/pixi/Pixi.js
new file mode 100644
index 0000000..27debc1
--- /dev/null
+++ b/test/unit/pixi/Pixi.js
@@ -0,0 +1,9 @@
+describe('pixi/Pixi', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+
+ it('Module exists', function () {
+ expect(global).to.have.property('PIXI').and.to.be.an('object');
+ });
+});
diff --git a/test/unit/pixi/core/Circle.js b/test/unit/pixi/core/Circle.js
new file mode 100644
index 0000000..93a4456
--- /dev/null
+++ b/test/unit/pixi/core/Circle.js
@@ -0,0 +1,22 @@
+describe('pixi/core/Circle', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Circle = PIXI.Circle;
+
+ it('Module exists', function () {
+ expect(Circle).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Circle();
+
+ expect(obj).to.be.an.instanceof(Circle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', 0);
+ expect(obj).to.have.property('y', 0);
+ expect(obj).to.have.property('radius', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Ellipse.js b/test/unit/pixi/core/Ellipse.js
new file mode 100644
index 0000000..026b56f
--- /dev/null
+++ b/test/unit/pixi/core/Ellipse.js
@@ -0,0 +1,24 @@
+describe('pixi/core/Ellipse', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Ellipse = PIXI.Ellipse;
+
+ it('Module exists', function () {
+ expect(Ellipse).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Ellipse();
+
+ expect(obj).to.be.an.instanceof(Ellipse);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+ expect(obj).to.respondTo('getBounds');
+
+ expect(obj).to.have.property('x', 0);
+ expect(obj).to.have.property('y', 0);
+ expect(obj).to.have.property('width', 0);
+ expect(obj).to.have.property('height', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Matrix.js b/test/unit/pixi/core/Matrix.js
new file mode 100644
index 0000000..b48989e
--- /dev/null
+++ b/test/unit/pixi/core/Matrix.js
@@ -0,0 +1,30 @@
+describe('pixi/core/Matrix', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var mat3 = PIXI.mat3;
+ var mat4 = PIXI.mat4;
+ var Matrix = PIXI.Matrix;
+
+ it('Ensure determineMatrixArrayType works', function () {
+ expect(Matrix).to.be.a('function');
+ });
+
+ it('mat3 exists', function () {
+ expect(mat3).to.be.an('object');
+ });
+
+ it('Confirm new mat3 matrix', function () {
+ var matrix = new mat3.create();
+ pixi_core_Matrix_confirmNewMat3(matrix);
+ });
+
+ it('mat3 exists', function () {
+ expect(mat4).to.be.an('object');
+ });
+
+ it('Confirm new mat4 matrix', function () {
+ var matrix = new mat4.create();
+ pixi_core_Matrix_confirmNewMat4(matrix);
+ });
+});
diff --git a/test/unit/pixi/core/Point.js b/test/unit/pixi/core/Point.js
new file mode 100644
index 0000000..c4d5163
--- /dev/null
+++ b/test/unit/pixi/core/Point.js
@@ -0,0 +1,15 @@
+describe('pixi/core/Point', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Point = PIXI.Point;
+
+ it('Module exists', function () {
+ expect(Point).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Point();
+ pixi_core_Point_confirm(obj, 0, 0);
+ });
+});
diff --git a/test/unit/pixi/core/Polygon.js b/test/unit/pixi/core/Polygon.js
new file mode 100644
index 0000000..dc8c918
--- /dev/null
+++ b/test/unit/pixi/core/Polygon.js
@@ -0,0 +1,20 @@
+describe('pixi/core/Polygon', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Polygon = PIXI.Polygon;
+
+ it('Module exists', function () {
+ expect(Polygon).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Polygon();
+
+ expect(obj).to.be.an.instanceof(Polygon);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.deep.property('points.length', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Rectangle.js b/test/unit/pixi/core/Rectangle.js
new file mode 100644
index 0000000..d43316e
--- /dev/null
+++ b/test/unit/pixi/core/Rectangle.js
@@ -0,0 +1,15 @@
+describe('pixi/core/Rectangle', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Rectangle = PIXI.Rectangle;
+
+ it('Module exists', function () {
+ expect(Rectangle).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var rect = new Rectangle();
+ pixi_core_Rectangle_confirm(rect, 0, 0, 0, 0);
+ });
+});
diff --git a/test/unit/pixi/display/DisplayObject.js b/test/unit/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..40c6fbc
--- /dev/null
+++ b/test/unit/pixi/display/DisplayObject.js
@@ -0,0 +1,21 @@
+describe('pixi/display/DisplayObject', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var DisplayObject = PIXI.DisplayObject;
+
+ it('Module exists', function () {
+ expect(DisplayObject).to.be.a('function');
+ expect(PIXI).to.have.property('visibleCount', 0);
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new DisplayObject();
+
+ pixi_display_DisplayObject_confirmNew(obj);
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', false);
+ expect(obj).to.have.property('stage', null);
+ });
+});
diff --git a/test/unit/pixi/display/DisplayObjectContainer.js b/test/unit/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..ce7f02f
--- /dev/null
+++ b/test/unit/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,20 @@
+describe('pixi/display/DisplayObjectContainer', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var DisplayObjectContainer = PIXI.DisplayObjectContainer;
+
+ it('Module exists', function () {
+ expect(DisplayObjectContainer).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new DisplayObjectContainer();
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', false);
+ expect(obj).to.have.property('stage', null);
+ });
+});
diff --git a/test/unit/pixi/display/MovieClip.js b/test/unit/pixi/display/MovieClip.js
new file mode 100644
index 0000000..f3c6c6a
--- /dev/null
+++ b/test/unit/pixi/display/MovieClip.js
@@ -0,0 +1,33 @@
+describe('pixi/display/MovieClip', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var MovieClip = PIXI.MovieClip;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(MovieClip).to.be.a('function');
+ });
+
+ it('Confirm new instance', function (done) {
+ var texture = Texture.fromImage('/base/test/textures/SpriteSheet-Explosion.png');
+ var obj = new MovieClip([texture]);
+
+ pixi_display_Sprite_confirmNew(obj, done);
+
+ expect(obj).to.be.an.instanceof(MovieClip);
+ expect(obj).to.respondTo('stop');
+ expect(obj).to.respondTo('play');
+ expect(obj).to.respondTo('gotoAndStop');
+ expect(obj).to.respondTo('gotoAndPlay');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('textures.length', 1);
+ expect(obj).to.have.deep.property('textures[0]', texture);
+ expect(obj).to.have.property('animationSpeed', 1);
+ expect(obj).to.have.property('loop', true);
+ expect(obj).to.have.property('onComplete', null);
+ expect(obj).to.have.property('currentFrame', 0);
+ expect(obj).to.have.property('playing', false);
+ });
+});
diff --git a/test/unit/pixi/display/Sprite.js b/test/unit/pixi/display/Sprite.js
new file mode 100644
index 0000000..54e914f
--- /dev/null
+++ b/test/unit/pixi/display/Sprite.js
@@ -0,0 +1,25 @@
+describe('pixi/display/Sprite', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Sprite = PIXI.Sprite;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(Sprite).to.be.a('function');
+ expect(PIXI).to.have.deep.property('blendModes.NORMAL', 0);
+ expect(PIXI).to.have.deep.property('blendModes.SCREEN', 1);
+ });
+
+ it('Members exist', function () {
+ expect(Sprite).itself.to.respondTo('fromImage');
+ expect(Sprite).itself.to.respondTo('fromFrame');
+ });
+
+ it('Confirm new instance', function (done) {
+ var texture = Texture.fromImage('/base/test/textures/SpriteSheet-Aliens.png');
+ var obj = new Sprite(texture);
+
+ pixi_display_Sprite_confirmNew(obj, done);
+ });
+});
diff --git a/test/unit/pixi/display/Stage.js b/test/unit/pixi/display/Stage.js
new file mode 100644
index 0000000..3cc2a4d
--- /dev/null
+++ b/test/unit/pixi/display/Stage.js
@@ -0,0 +1,49 @@
+describe('pixi/display/Stage', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Stage = PIXI.Stage;
+ var InteractionManager = PIXI.InteractionManager;
+ var Rectangle = PIXI.Rectangle;
+
+ it('Module exists', function () {
+ expect(Stage).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Stage(null, true);
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(Stage);
+ expect(obj).to.respondTo('updateTransform');
+ expect(obj).to.respondTo('setBackgroundColor');
+ expect(obj).to.respondTo('getMousePosition');
+
+ // FIXME: duplicate member in DisplayObject
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ // FIXME: convert arg to bool in constructor
+ expect(obj).to.have.property('interactive', true);
+
+ expect(obj).to.have.property('interactionManager')
+ .and.to.be.an.instanceof(InteractionManager)
+ .and.to.have.property('stage', obj);
+
+ expect(obj).to.have.property('dirty', true);
+
+ expect(obj).to.have.property('stage', obj);
+
+ expect(obj).to.have.property('hitArea')
+ .and.to.be.an.instanceof(Rectangle);
+ pixi_core_Rectangle_confirm(obj.hitArea, 0, 0, 100000, 100000);
+
+ expect(obj).to.have.property('backgroundColor', 0x000000);
+ expect(obj).to.have.deep.property('backgroundColorSplit.length', 3);
+ expect(obj).to.have.deep.property('backgroundColorSplit[0]', 0);
+ expect(obj).to.have.deep.property('backgroundColorSplit[1]', 0);
+ expect(obj).to.have.deep.property('backgroundColorSplit[2]', 0);
+ expect(obj).to.have.property('backgroundColorString', '#000000');
+
+ expect(obj).to.have.property('worldVisible', true);
+ });
+});
diff --git a/test/unit/pixi/extras/CustomRenderable.js b/test/unit/pixi/extras/CustomRenderable.js
new file mode 100644
index 0000000..8d83cf0
--- /dev/null
+++ b/test/unit/pixi/extras/CustomRenderable.js
@@ -0,0 +1,21 @@
+describe('pixi/extras/CustomRenderable', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var CustomRenderable = PIXI.CustomRenderable;
+
+ it('Module exists', function () {
+ expect(CustomRenderable).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new CustomRenderable();
+
+ pixi_display_DisplayObject_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(CustomRenderable);
+ expect(obj).to.respondTo('renderCanvas');
+ expect(obj).to.respondTo('initWebGL');
+ expect(obj).to.respondTo('renderWebGL');
+ });
+});
diff --git a/test/unit/pixi/extras/Rope.js b/test/unit/pixi/extras/Rope.js
new file mode 100644
index 0000000..6ddaf83
--- /dev/null
+++ b/test/unit/pixi/extras/Rope.js
@@ -0,0 +1,26 @@
+describe('pixi/extras/Rope', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Rope = PIXI.Rope;
+ var Texture = PIXI.Texture;
+ var Point = PIXI.Point;
+
+ it('Module exists', function () {
+ expect(Rope).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var texture = Texture.fromImage('/base/test/textures/bunny.png');
+ var obj = new Rope(texture, [new Point(), new Point(5, 10), new Point(10, 20)]);
+
+ pixi_extras_Strip_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(Rope);
+ expect(obj).to.respondTo('refresh');
+ expect(obj).to.respondTo('updateTransform');
+ expect(obj).to.respondTo('setTexture');
+
+ // TODO: Test properties
+ });
+});
diff --git a/test/unit/pixi/extras/Spine.js b/test/unit/pixi/extras/Spine.js
new file mode 100644
index 0000000..0708bc0
--- /dev/null
+++ b/test/unit/pixi/extras/Spine.js
@@ -0,0 +1,10 @@
+describe('pixi/extras/Spine', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Spine = PIXI.Spine;
+
+ it('Module exists', function () {
+ expect(Spine).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/extras/Strip.js b/test/unit/pixi/extras/Strip.js
new file mode 100644
index 0000000..8e564e1
--- /dev/null
+++ b/test/unit/pixi/extras/Strip.js
@@ -0,0 +1,18 @@
+describe('pixi/extras/Strip', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Strip = PIXI.Strip;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(Strip).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var texture = Texture.fromImage('/base/test/textures/bunny.png');
+ var obj = new Strip(texture, 20, 10000);
+
+ pixi_extras_Strip_confirmNew(obj);
+ });
+});
diff --git a/.gitignore b/.gitignore
index 12e1b62..0b88317 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
node_modules
.DS_Store
-.project
\ No newline at end of file
+.project
+*.log
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..63e4d7c
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,8 @@
+language: node_js
+node_js:
+ - 0.10
+
+before_script:
+ - npm install -g grunt-cli
+ - export DISPLAY=:99.0
+ - sh -e /etc/init.d/xvfb start
diff --git a/Gruntfile.js b/Gruntfile.js
index b083b49..103938c 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -1,10 +1,12 @@
+'use strict';
+
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-connect');
- grunt.loadNpmTasks('grunt-contrib-qunit');
grunt.loadNpmTasks('grunt-contrib-yuidoc');
+ grunt.loadTasks('tasks');
var root = 'src/pixi/',
debug = 'bin/pixi.dev.js',
@@ -79,7 +81,7 @@
},
files: {
srcBlob: '<%= dirs.src %>/**/*.js',
- testBlob: '<%= dirs.test %>/unit/**/*.js',
+ testBlob: '<%= dirs.test %>/{functional,lib/pixi,unit}/**/*.js',
build: '<%= dirs.build %>/pixi.dev.js',
buildMin: '<%= dirs.build %>/pixi.js'
},
@@ -94,7 +96,12 @@
},
jshint: {
beforeconcat: srcFiles,
- test: ['<%= files.testBlob %>'],
+ test: {
+ src: ['<%= files.testBlob %>'],
+ options: {
+ expr: true
+ }
+ },
options: {
asi: true,
smarttabs: true
@@ -128,12 +135,6 @@
]
},
connect: {
- qunit: {
- options: {
- port: grunt.option('port-test') || 9002,
- base: './'
- }
- },
test: {
options: {
port: grunt.option('port-test') || 9002,
@@ -142,13 +143,6 @@
}
}
},
- qunit: {
- all: {
- options: {
- urls: ['http://localhost:' + (grunt.option('port-test') || 9002) + '/test/index.html']
- }
- }
- },
yuidoc: {
compile: {
name: '<%= pkg.name %>',
@@ -161,6 +155,13 @@
outdir: '<%= dirs.docs %>'
}
}
+ },
+ karma: {
+ unit: {
+ configFile: 'test/karma.conf.js',
+ // browsers: ['Chrome'],
+ singleRun: true
+ }
}
});
@@ -182,9 +183,10 @@
}
)
- grunt.registerTask('default', ['concat', 'uglify', 'distribute']);
grunt.registerTask('build', ['concat', 'uglify', 'distribute']);
- grunt.registerTask('test', ['build', 'connect:qunit', 'qunit']);
+ grunt.registerTask('test', ['concat', 'jshint:test', 'karma']);
grunt.registerTask('docs', ['yuidoc']);
-
-}
\ No newline at end of file
+ grunt.registerTask('default', ['test', 'uglify', 'distribute']);
+ // Travis CI task.
+ grunt.registerTask('travis', ['test']);
+}
diff --git a/README.md b/README.md
index c62ef86..690cfe4 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,8 @@

+[](http://travis-ci.org/drkibitz/pixi.js)
+
#### JavaScript 2D Renderer ####
The aim of this project is to provide a fast lightweight 2D library that works
diff --git a/package.json b/package.json
index b373240..1246a68 100644
--- a/package.json
+++ b/package.json
@@ -18,14 +18,21 @@
"main": "bin/pixi.js",
+ "scripts": {
+ "test": "grunt travis --verbose"
+ },
+
"dependencies": {},
"devDependencies": {
"grunt": "~0.4.x",
- "grunt-contrib-jshint": "0.3.x",
+ "grunt-contrib-jshint": "0.6.x",
"grunt-contrib-uglify": "0.2.x",
- "grunt-contrib-connect": "0.2.x",
- "grunt-contrib-qunit": "0.2.x",
+ "grunt-contrib-connect": "0.3.x",
"grunt-contrib-yuidoc": "0.4.x",
- "grunt-contrib-concat": "0.1.x"
+ "grunt-contrib-concat": "0.3.x",
+ "chai": "~1.7.0",
+ "karma": "0.11.0",
+ "karma-firefox-launcher": "0.1.0",
+ "karma-mocha": "0.1.0"
}
}
diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js
index a7c520e..ee82bbd 100644
--- a/src/pixi/InteractionManager.js
+++ b/src/pixi/InteractionManager.js
@@ -62,7 +62,6 @@
this.onTouchEnd = this.onTouchEnd.bind(this);
this.onTouchMove = this.onTouchMove.bind(this);
-
this.last = 0;
}
diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js
index 1a95d20..eef1059 100644
--- a/src/pixi/core/Ellipse.js
+++ b/src/pixi/core/Ellipse.js
@@ -78,7 +78,7 @@
return (normx + normy < 0.25);
}
-PIXI.Ellipse.getBounds = function()
+PIXI.Ellipse.prototype.getBounds = function()
{
return new PIXI.Rectangle(this.x, this.y, this.width, this.height);
}
diff --git a/tasks/karma.js b/tasks/karma.js
new file mode 100644
index 0000000..c340485
--- /dev/null
+++ b/tasks/karma.js
@@ -0,0 +1,27 @@
+'use strict';
+
+var path = require('path');
+var server = require('karma').server;
+
+module.exports = function (grunt) {
+ grunt.registerMultiTask('karma', 'run karma.', function() {
+ var done = this.async();
+ var options = this.options({
+ background: false
+ });
+ var data = this.data;
+
+ //merge options onto data, with data taking precedence
+ data = grunt.util._.merge(options, data);
+ data.configFile = path.resolve(data.configFile);
+ if (data.configFile) {
+ data.configFile = grunt.template.process(data.configFile);
+ }
+
+ server.start(
+ data,
+ function(code) {
+ done(!code);
+ });
+ });
+};
diff --git a/test/functional/example-1-basics/bunny.png b/test/functional/example-1-basics/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/functional/example-1-basics/bunny.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-30.png b/test/functional/example-1-basics/frame-30.png
new file mode 100644
index 0000000..96e3409
--- /dev/null
+++ b/test/functional/example-1-basics/frame-30.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-60.png b/test/functional/example-1-basics/frame-60.png
new file mode 100644
index 0000000..af3f4ce
--- /dev/null
+++ b/test/functional/example-1-basics/frame-60.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-90.png b/test/functional/example-1-basics/frame-90.png
new file mode 100644
index 0000000..099b823
--- /dev/null
+++ b/test/functional/example-1-basics/frame-90.png
Binary files differ
diff --git a/test/functional/example-1-basics/index.js b/test/functional/example-1-basics/index.js
new file mode 100644
index 0000000..7ae7a98
--- /dev/null
+++ b/test/functional/example-1-basics/index.js
@@ -0,0 +1,133 @@
+describe('Example 1 - Basics', function () {
+ 'use strict';
+
+ var baseUri = '/base/test/functional/example-1-basics';
+ var expect = chai.expect;
+ var currentFrame = 0;
+ var frameEvents = {};
+ var stage;
+ var renderer;
+ var bunny;
+
+ function onFrame(frame, callback) {
+ frameEvents[frame] = callback;
+ }
+
+ function animate() {
+ currentFrame += 1;
+
+ requestAnimFrame( animate );
+
+ // just for fun, lets rotate mr rabbit a little
+ bunny.rotation += 0.1;
+
+ // render the stage
+ renderer.render(stage);
+
+ if (frameEvents[currentFrame])
+ frameEvents[currentFrame](currentFrame);
+ }
+
+ function initScene() {
+ // create an new instance of a pixi stage
+ stage = new PIXI.Stage(0x66FF99);
+
+ // create a renderer instance
+ renderer = PIXI.autoDetectRenderer(400, 300);
+ console.log('Is PIXI.WebGLRenderer: ' + (renderer instanceof PIXI.WebGLRenderer));
+
+ // add the renderer view element to the DOM
+ document.body.appendChild(renderer.view);
+
+ requestAnimFrame( animate );
+
+ // create a texture from an image path
+ var texture = PIXI.Texture.fromImage(baseUri + "/bunny.png");
+ // create a new Sprite using the texture
+ bunny = new PIXI.Sprite(texture);
+
+ // center the sprites anchor point
+ bunny.anchor.x = 0.5;
+ bunny.anchor.y = 0.5;
+
+ // move the sprite t the center of the screen
+ bunny.position.x = 200;
+ bunny.position.y = 150;
+
+ stage.addChild(bunny);
+ }
+
+ it('assets loaded', function (done) {
+ var loader = new PIXI.AssetLoader([
+ baseUri + '/bunny.png',
+ baseUri + '/frame-30.png',
+ baseUri + '/frame-60.png',
+ baseUri + '/frame-90.png'
+ ]);
+ // loader.on('onProgress', function (event) {
+ // console.log(event.content);
+ // });
+ loader.on('onComplete', function (event) {
+ done();
+ initScene();
+ });
+ loader.load();
+ });
+
+ it('frame 30 should match', function (done) {
+ this.timeout(700);
+ onFrame(30, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-30.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 60 should match', function (done) {
+ this.timeout(1200);
+ onFrame(60, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-60.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 90 should match', function (done) {
+ this.timeout(1700);
+ onFrame(90, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-90.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ // it('capture something', function (done) {
+ // this.timeout(2000000);
+ // onFrame(30, function () {
+ // var img = new Image();
+ // img.src = renderer.view.toDataURL('image/png');
+ // document.body.appendChild(img);
+ // });
+ // });
+});
diff --git a/test/index.html b/test/index.html
deleted file mode 100644
index 9cbcac5..0000000
--- a/test/index.html
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
- Pixi.js Test Suite
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/test/karma.conf.js b/test/karma.conf.js
new file mode 100644
index 0000000..c66a696
--- /dev/null
+++ b/test/karma.conf.js
@@ -0,0 +1,82 @@
+module.exports = function(config) {
+ config.set({
+
+ // base path, that will be used to resolve files and exclude
+ basePath : '../',
+
+ frameworks : ['mocha'],
+
+ // list of files / patterns to load in the browser
+ files : [
+ 'node_modules/chai/chai.js',
+ 'bin/pixi.dev.js',
+ 'test/lib/**/*.js',
+ 'test/unit/**/*.js',
+ // 'test/functional/**/*.js',
+ {pattern: 'test/**/*.png', watched: false, included: false, served: true}
+ ],
+
+ // list of files to exclude
+ exclude : [],
+
+ // use dolts reporter, as travis terminal does not support escaping sequences
+ // possible values: 'dots', 'progress', 'junit', 'teamcity'
+ // CLI --reporters progress
+ reporters : ['progress'],
+
+ // web server port
+ // CLI --port 9876
+ port : 9876,
+
+ // cli runner port
+ // CLI --runner-port 9100
+ runnerPort : 9100,
+
+ // enable / disable colors in the output (reporters and logs)
+ // CLI --colors --no-colors
+ colors : true,
+
+ // level of logging
+ // possible values: karma.LOG_DISABLE || karma.LOG_ERROR || karma.LOG_WARN || karma.LOG_INFO || karma.LOG_DEBUG
+ // CLI --log-level debug
+ logLevel : config.LOG_DEBUG,
+
+ // enable / disable watching file and executing tests whenever any file changes
+ // CLI --auto-watch --no-auto-watch
+ autoWatch : false,
+
+ // Start these browsers, currently available:
+ // - Chrome
+ // - ChromeCanary
+ // - Firefox
+ // - Opera
+ // - Safari (only Mac)
+ // - PhantomJS
+ // - IE (only Windows)
+ // CLI --browsers Chrome,Firefox,Safari
+ browsers : ['Firefox'],
+
+ // If browser does not capture in given timeout [ms], kill it
+ // CLI --capture-timeout 5000
+ captureTimeout : 5000,
+
+ // Auto run tests on start (when browsers are captured) and exit
+ // CLI --single-run --no-single-run
+ singleRun : true,
+
+ // report which specs are slower than 500ms
+ // CLI --report-slower-than 500
+ reportSlowerThan : 1000,
+
+ preprocessors : {
+ // '**/client/js/*.js': 'coverage'
+ },
+
+ plugins : [
+ 'karma-mocha',
+ // 'karma-chrome-launcher',
+ 'karma-firefox-launcher',
+ // 'karma-phantomjs-launcher'
+ ]
+ });
+};
diff --git a/test/lib/pixi/core/Matrix.js b/test/lib/pixi/core/Matrix.js
new file mode 100644
index 0000000..d26386b
--- /dev/null
+++ b/test/lib/pixi/core/Matrix.js
@@ -0,0 +1,40 @@
+
+function pixi_core_Matrix_confirmNewMat3(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(1);
+ expect(matrix[5]).to.equal(0);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(1);
+}
+
+function pixi_core_Matrix_confirmNewMat4(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[0]).to.equal(1);
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(0);
+ expect(matrix[5]).to.equal(1);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(0);
+ expect(matrix[9]).to.equal(0);
+ expect(matrix[10]).to.equal(1);
+ expect(matrix[11]).to.equal(0);
+ expect(matrix[12]).to.equal(0);
+ expect(matrix[13]).to.equal(0);
+ expect(matrix[14]).to.equal(0);
+ expect(matrix[15]).to.equal(1);
+}
diff --git a/test/lib/pixi/core/Point.js b/test/lib/pixi/core/Point.js
new file mode 100644
index 0000000..e5df07b
--- /dev/null
+++ b/test/lib/pixi/core/Point.js
@@ -0,0 +1,10 @@
+
+function pixi_core_Point_confirm(obj, x, y) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Point);
+ expect(obj).to.respondTo('clone');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+}
diff --git a/test/lib/pixi/core/Rectangle.js b/test/lib/pixi/core/Rectangle.js
new file mode 100644
index 0000000..23f0d12
--- /dev/null
+++ b/test/lib/pixi/core/Rectangle.js
@@ -0,0 +1,13 @@
+
+function pixi_core_Rectangle_confirm(obj, x, y, width, height) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Rectangle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+ expect(obj).to.have.property('width', width);
+ expect(obj).to.have.property('height', height);
+}
diff --git a/test/lib/pixi/display/DisplayObject.js b/test/lib/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..1388a7f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObject.js
@@ -0,0 +1,43 @@
+
+function pixi_display_DisplayObject_confirmNew(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObject);
+ expect(obj).to.respondTo('setInteractive');
+ expect(obj).to.respondTo('addFilter');
+ expect(obj).to.respondTo('removeFilter');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.property('last', obj);
+ expect(obj).to.have.property('first', obj);
+
+ expect(obj).to.contain.property('position');
+ pixi_core_Point_confirm(obj.position, 0, 0);
+ expect(obj).to.contain.property('scale');
+ pixi_core_Point_confirm(obj.scale, 1, 1);
+ expect(obj).to.contain.property('pivot');
+ pixi_core_Point_confirm(obj.pivot, 0, 0);
+
+ expect(obj).to.have.property('rotation', 0);
+ expect(obj).to.have.property('alpha', 1);
+ expect(obj).to.have.property('visible', true);
+ expect(obj).to.have.property('buttonMode', false);
+ expect(obj).to.have.property('parent', null);
+ expect(obj).to.have.property('worldAlpha', 1);
+
+ expect(obj).to.have.property('hitArea');
+ expect(obj).to.have.property('interactive'); // TODO: Have a better default value
+ expect('mask' in obj).to.be.true; // TODO: Have a better default value
+ expect(obj.mask).to.be.undefined;
+
+ expect(obj).to.have.property('renderable');
+ expect(obj).to.have.property('stage');
+
+ expect(obj).to.have.deep.property('worldTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ expect(obj).to.have.deep.property('localTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.localTransform);
+
+ expect(obj).to.have.deep.property('color.length', 0);
+ expect(obj).to.have.property('dynamic', true);
+}
diff --git a/test/lib/pixi/display/DisplayObjectContainer.js b/test/lib/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..085c59f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,16 @@
+
+function pixi_display_DisplayObjectContainer_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObject_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObjectContainer);
+ expect(obj).to.respondTo('addChild');
+ expect(obj).to.respondTo('addChildAt');
+ expect(obj).to.respondTo('swapChildren');
+ expect(obj).to.respondTo('getChildAt');
+ expect(obj).to.respondTo('removeChild');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('children.length', 0);
+}
diff --git a/test/lib/pixi/display/Sprite.js b/test/lib/pixi/display/Sprite.js
new file mode 100644
index 0000000..cc7a2d6
--- /dev/null
+++ b/test/lib/pixi/display/Sprite.js
@@ -0,0 +1,28 @@
+
+function pixi_display_Sprite_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Sprite);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', true);
+ expect(obj).to.have.property('stage', null);
+
+ expect(obj).to.have.property('anchor');
+ pixi_core_Point_confirm(obj.anchor, 0, 0);
+
+ expect(obj).to.have.property('blendMode', PIXI.blendModes.NORMAL);
+ expect(obj).to.have.property('width', 1); // TODO: is 1 expected
+ expect(obj).to.have.property('height', 1); // TODO: is 1 expected
+
+ // FIXME: Just make this a boolean that is always there
+ expect(!!obj.updateFrame).to.equal(obj.texture.baseTexture.hasLoaded);
+
+ expect(obj).to.have.property('texture');
+ pixi_textures_Texture_confirmNew(obj.texture, done);
+}
diff --git a/test/lib/pixi/extras/Strip.js b/test/lib/pixi/extras/Strip.js
new file mode 100644
index 0000000..8927a8a
--- /dev/null
+++ b/test/lib/pixi/extras/Strip.js
@@ -0,0 +1,12 @@
+
+function pixi_extras_Strip_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Strip);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ // TODO: Test properties
+}
diff --git a/test/lib/pixi/textures/Texture.js b/test/lib/pixi/textures/Texture.js
new file mode 100644
index 0000000..d5867b6
--- /dev/null
+++ b/test/lib/pixi/textures/Texture.js
@@ -0,0 +1,31 @@
+
+function pixi_textures_Texture_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ function confirmFrameDone() {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, obj.baseTexture.width, obj.baseTexture.height);
+
+ expect(obj).to.have.property('width', obj.baseTexture.width);
+ expect(obj).to.have.property('height', obj.baseTexture.height);
+ done();
+ }
+
+ expect(obj).to.be.an.instanceof(PIXI.Texture);
+ pixi_utils_EventTarget_like(obj);
+
+ expect(obj).to.have.property('baseTexture')
+ .and.to.be.an.instanceof(PIXI.BaseTexture);
+
+ expect(obj).to.have.property('scope', obj);
+
+ expect(obj).to.have.property('trim');
+ pixi_core_Point_confirm(obj.trim, 0, 0);
+
+ expect(obj).to.have.property('frame');
+ if (obj.baseTexture.hasLoaded) {
+ confirmFrameDone();
+ } else {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, 1, 1);
+ obj.addEventListener('update', confirmFrameDone);
+ }
+}
diff --git a/test/lib/pixi/utils/EventTarget.js b/test/lib/pixi/utils/EventTarget.js
new file mode 100644
index 0000000..7b1dcfa
--- /dev/null
+++ b/test/lib/pixi/utils/EventTarget.js
@@ -0,0 +1,8 @@
+
+function pixi_utils_EventTarget_like(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.respondTo('addEventListener');
+ expect(obj).to.respondTo('dispatchEvent');
+ expect(obj).to.respondTo('removeEventListener');
+}
diff --git a/test/lib/qunit-1.11.0.css b/test/lib/qunit-1.11.0.css
deleted file mode 100644
index d7fc0c8..0000000
--- a/test/lib/qunit-1.11.0.css
+++ /dev/null
@@ -1,244 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-/** Font Family and Sizes */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
- font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
-}
-
-#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
-#qunit-tests { font-size: smaller; }
-
-
-/** Resets */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter {
- margin: 0;
- padding: 0;
-}
-
-
-/** Header */
-
-#qunit-header {
- padding: 0.5em 0 0.5em 1em;
-
- color: #8699a4;
- background-color: #0d3349;
-
- font-size: 1.5em;
- line-height: 1em;
- font-weight: normal;
-
- border-radius: 5px 5px 0 0;
- -moz-border-radius: 5px 5px 0 0;
- -webkit-border-top-right-radius: 5px;
- -webkit-border-top-left-radius: 5px;
-}
-
-#qunit-header a {
- text-decoration: none;
- color: #c2ccd1;
-}
-
-#qunit-header a:hover,
-#qunit-header a:focus {
- color: #fff;
-}
-
-#qunit-testrunner-toolbar label {
- display: inline-block;
- padding: 0 .5em 0 .1em;
-}
-
-#qunit-banner {
- height: 5px;
-}
-
-#qunit-testrunner-toolbar {
- padding: 0.5em 0 0.5em 2em;
- color: #5E740B;
- background-color: #eee;
- overflow: hidden;
-}
-
-#qunit-userAgent {
- padding: 0.5em 0 0.5em 2.5em;
- background-color: #2b81af;
- color: #fff;
- text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
-}
-
-#qunit-modulefilter-container {
- float: right;
-}
-
-/** Tests: Pass/Fail */
-
-#qunit-tests {
- list-style-position: inside;
-}
-
-#qunit-tests li {
- padding: 0.4em 0.5em 0.4em 2.5em;
- border-bottom: 1px solid #fff;
- list-style-position: inside;
-}
-
-#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running {
- display: none;
-}
-
-#qunit-tests li strong {
- cursor: pointer;
-}
-
-#qunit-tests li a {
- padding: 0.5em;
- color: #c2ccd1;
- text-decoration: none;
-}
-#qunit-tests li a:hover,
-#qunit-tests li a:focus {
- color: #000;
-}
-
-#qunit-tests li .runtime {
- float: right;
- font-size: smaller;
-}
-
-.qunit-assert-list {
- margin-top: 0.5em;
- padding: 0.5em;
-
- background-color: #fff;
-
- border-radius: 5px;
- -moz-border-radius: 5px;
- -webkit-border-radius: 5px;
-}
-
-.qunit-collapsed {
- display: none;
-}
-
-#qunit-tests table {
- border-collapse: collapse;
- margin-top: .2em;
-}
-
-#qunit-tests th {
- text-align: right;
- vertical-align: top;
- padding: 0 .5em 0 0;
-}
-
-#qunit-tests td {
- vertical-align: top;
-}
-
-#qunit-tests pre {
- margin: 0;
- white-space: pre-wrap;
- word-wrap: break-word;
-}
-
-#qunit-tests del {
- background-color: #e0f2be;
- color: #374e0c;
- text-decoration: none;
-}
-
-#qunit-tests ins {
- background-color: #ffcaca;
- color: #500;
- text-decoration: none;
-}
-
-/*** Test Counts */
-
-#qunit-tests b.counts { color: black; }
-#qunit-tests b.passed { color: #5E740B; }
-#qunit-tests b.failed { color: #710909; }
-
-#qunit-tests li li {
- padding: 5px;
- background-color: #fff;
- border-bottom: none;
- list-style-position: inside;
-}
-
-/*** Passing Styles */
-
-#qunit-tests li li.pass {
- color: #3c510c;
- background-color: #fff;
- border-left: 10px solid #C6E746;
-}
-
-#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
-#qunit-tests .pass .test-name { color: #366097; }
-
-#qunit-tests .pass .test-actual,
-#qunit-tests .pass .test-expected { color: #999999; }
-
-#qunit-banner.qunit-pass { background-color: #C6E746; }
-
-/*** Failing Styles */
-
-#qunit-tests li li.fail {
- color: #710909;
- background-color: #fff;
- border-left: 10px solid #EE5757;
- white-space: pre;
-}
-
-#qunit-tests > li:last-child {
- border-radius: 0 0 5px 5px;
- -moz-border-radius: 0 0 5px 5px;
- -webkit-border-bottom-right-radius: 5px;
- -webkit-border-bottom-left-radius: 5px;
-}
-
-#qunit-tests .fail { color: #000000; background-color: #EE5757; }
-#qunit-tests .fail .test-name,
-#qunit-tests .fail .module-name { color: #000000; }
-
-#qunit-tests .fail .test-actual { color: #EE5757; }
-#qunit-tests .fail .test-expected { color: green; }
-
-#qunit-banner.qunit-fail { background-color: #EE5757; }
-
-
-/** Result */
-
-#qunit-testresult {
- padding: 0.5em 0.5em 0.5em 2.5em;
-
- color: #2b81af;
- background-color: #D2E0E6;
-
- border-bottom: 1px solid white;
-}
-#qunit-testresult .module-name {
- font-weight: bold;
-}
-
-/** Fixture */
-
-#qunit-fixture {
- position: absolute;
- top: -10000px;
- left: -10000px;
- width: 1000px;
- height: 1000px;
-}
diff --git a/test/lib/qunit-1.11.0.js b/test/lib/qunit-1.11.0.js
deleted file mode 100644
index 302545f..0000000
--- a/test/lib/qunit-1.11.0.js
+++ /dev/null
@@ -1,2152 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-(function( window ) {
-
-var QUnit,
- assert,
- config,
- onErrorFnPrev,
- testId = 0,
- fileName = (sourceFromStacktrace( 0 ) || "" ).replace(/(:\d+)+\)?/, "").replace(/.+\//, ""),
- toString = Object.prototype.toString,
- hasOwn = Object.prototype.hasOwnProperty,
- // Keep a local reference to Date (GH-283)
- Date = window.Date,
- defined = {
- setTimeout: typeof window.setTimeout !== "undefined",
- sessionStorage: (function() {
- var x = "qunit-test-string";
- try {
- sessionStorage.setItem( x, x );
- sessionStorage.removeItem( x );
- return true;
- } catch( e ) {
- return false;
- }
- }())
- },
- /**
- * Provides a normalized error string, correcting an issue
- * with IE 7 (and prior) where Error.prototype.toString is
- * not properly implemented
- *
- * Based on http://es5.github.com/#x15.11.4.4
- *
- * @param {String|Error} error
- * @return {String} error message
- */
- errorString = function( error ) {
- var name, message,
- errorString = error.toString();
- if ( errorString.substring( 0, 7 ) === "[object" ) {
- name = error.name ? error.name.toString() : "Error";
- message = error.message ? error.message.toString() : "";
- if ( name && message ) {
- return name + ": " + message;
- } else if ( name ) {
- return name;
- } else if ( message ) {
- return message;
- } else {
- return "Error";
- }
- } else {
- return errorString;
- }
- },
- /**
- * Makes a clone of an object using only Array or Object as base,
- * and copies over the own enumerable properties.
- *
- * @param {Object} obj
- * @return {Object} New object with only the own properties (recursively).
- */
- objectValues = function( obj ) {
- // Grunt 0.3.x uses an older version of jshint that still has jshint/jshint#392.
- /*jshint newcap: false */
- var key, val,
- vals = QUnit.is( "array", obj ) ? [] : {};
- for ( key in obj ) {
- if ( hasOwn.call( obj, key ) ) {
- val = obj[key];
- vals[key] = val === Object(val) ? objectValues(val) : val;
- }
- }
- return vals;
- };
-
-function Test( settings ) {
- extend( this, settings );
- this.assertions = [];
- this.testNumber = ++Test.count;
-}
-
-Test.count = 0;
-
-Test.prototype = {
- init: function() {
- var a, b, li,
- tests = id( "qunit-tests" );
-
- if ( tests ) {
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml;
-
- // `a` initialized at top of scope
- a = document.createElement( "a" );
- a.innerHTML = "Rerun";
- a.href = QUnit.url({ testNumber: this.testNumber });
-
- li = document.createElement( "li" );
- li.appendChild( b );
- li.appendChild( a );
- li.className = "running";
- li.id = this.id = "qunit-test-output" + testId++;
-
- tests.appendChild( li );
- }
- },
- setup: function() {
- if ( this.module !== config.previousModule ) {
- if ( config.previousModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.previousModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
- config.previousModule = this.module;
- config.moduleStats = { all: 0, bad: 0 };
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- } else if ( config.autorun ) {
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- }
-
- config.current = this;
-
- this.testEnvironment = extend({
- setup: function() {},
- teardown: function() {}
- }, this.moduleTestEnvironment );
-
- this.started = +new Date();
- runLoggingCallbacks( "testStart", QUnit, {
- name: this.testName,
- module: this.module
- });
-
- // allow utility functions to access the current test environment
- // TODO why??
- QUnit.current_testEnvironment = this.testEnvironment;
-
- if ( !config.pollution ) {
- saveGlobal();
- }
- if ( config.notrycatch ) {
- this.testEnvironment.setup.call( this.testEnvironment );
- return;
- }
- try {
- this.testEnvironment.setup.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Setup failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- },
- run: function() {
- config.current = this;
-
- var running = id( "qunit-testresult" );
-
- if ( running ) {
- running.innerHTML = "Running:
" + this.nameHtml;
- }
-
- if ( this.async ) {
- QUnit.stop();
- }
-
- this.callbackStarted = +new Date();
-
- if ( config.notrycatch ) {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- return;
- }
-
- try {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- } catch( e ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
-
- QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + " " + this.stack + ": " + ( e.message || e ), extractStacktrace( e, 0 ) );
- // else next test will carry the responsibility
- saveGlobal();
-
- // Restart the tests if they're blocking
- if ( config.blocking ) {
- QUnit.start();
- }
- }
- },
- teardown: function() {
- config.current = this;
- if ( config.notrycatch ) {
- if ( typeof this.callbackRuntime === "undefined" ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
- }
- this.testEnvironment.teardown.call( this.testEnvironment );
- return;
- } else {
- try {
- this.testEnvironment.teardown.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Teardown failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- }
- checkPollution();
- },
- finish: function() {
- config.current = this;
- if ( config.requireExpects && this.expected === null ) {
- QUnit.pushFailure( "Expected number of assertions to be defined, but expect() was not called.", this.stack );
- } else if ( this.expected !== null && this.expected !== this.assertions.length ) {
- QUnit.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack );
- } else if ( this.expected === null && !this.assertions.length ) {
- QUnit.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions.", this.stack );
- }
-
- var i, assertion, a, b, time, li, ol,
- test = this,
- good = 0,
- bad = 0,
- tests = id( "qunit-tests" );
-
- this.runtime = +new Date() - this.started;
- config.stats.all += this.assertions.length;
- config.moduleStats.all += this.assertions.length;
-
- if ( tests ) {
- ol = document.createElement( "ol" );
- ol.className = "qunit-assert-list";
-
- for ( i = 0; i < this.assertions.length; i++ ) {
- assertion = this.assertions[i];
-
- li = document.createElement( "li" );
- li.className = assertion.result ? "pass" : "fail";
- li.innerHTML = assertion.message || ( assertion.result ? "okay" : "failed" );
- ol.appendChild( li );
-
- if ( assertion.result ) {
- good++;
- } else {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
-
- // store result when possible
- if ( QUnit.config.reorder && defined.sessionStorage ) {
- if ( bad ) {
- sessionStorage.setItem( "qunit-test-" + this.module + "-" + this.testName, bad );
- } else {
- sessionStorage.removeItem( "qunit-test-" + this.module + "-" + this.testName );
- }
- }
-
- if ( bad === 0 ) {
- addClass( ol, "qunit-collapsed" );
- }
-
- // `b` initialized at top of scope
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml + " (" + bad + ", " + good + ", " + this.assertions.length + ")";
-
- addEvent(b, "click", function() {
- var next = b.parentNode.lastChild,
- collapsed = hasClass( next, "qunit-collapsed" );
- ( collapsed ? removeClass : addClass )( next, "qunit-collapsed" );
- });
-
- addEvent(b, "dblclick", function( e ) {
- var target = e && e.target ? e.target : window.event.srcElement;
- if ( target.nodeName.toLowerCase() === "span" || target.nodeName.toLowerCase() === "b" ) {
- target = target.parentNode;
- }
- if ( window.location && target.nodeName.toLowerCase() === "strong" ) {
- window.location = QUnit.url({ testNumber: test.testNumber });
- }
- });
-
- // `time` initialized at top of scope
- time = document.createElement( "span" );
- time.className = "runtime";
- time.innerHTML = this.runtime + " ms";
-
- // `li` initialized at top of scope
- li = id( this.id );
- li.className = bad ? "fail" : "pass";
- li.removeChild( li.firstChild );
- a = li.firstChild;
- li.appendChild( b );
- li.appendChild( a );
- li.appendChild( time );
- li.appendChild( ol );
-
- } else {
- for ( i = 0; i < this.assertions.length; i++ ) {
- if ( !this.assertions[i].result ) {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
- }
-
- runLoggingCallbacks( "testDone", QUnit, {
- name: this.testName,
- module: this.module,
- failed: bad,
- passed: this.assertions.length - bad,
- total: this.assertions.length,
- duration: this.runtime
- });
-
- QUnit.reset();
-
- config.current = undefined;
- },
-
- queue: function() {
- var bad,
- test = this;
-
- synchronize(function() {
- test.init();
- });
- function run() {
- // each of these can by async
- synchronize(function() {
- test.setup();
- });
- synchronize(function() {
- test.run();
- });
- synchronize(function() {
- test.teardown();
- });
- synchronize(function() {
- test.finish();
- });
- }
-
- // `bad` initialized at top of scope
- // defer when previous test run passed, if storage is available
- bad = QUnit.config.reorder && defined.sessionStorage &&
- +sessionStorage.getItem( "qunit-test-" + this.module + "-" + this.testName );
-
- if ( bad ) {
- run();
- } else {
- synchronize( run, true );
- }
- }
-};
-
-// Root QUnit object.
-// `QUnit` initialized at top of scope
-QUnit = {
-
- // call on start of module test to prepend name to all tests
- module: function( name, testEnvironment ) {
- config.currentModule = name;
- config.currentModuleTestEnvironment = testEnvironment;
- config.modules[name] = true;
- },
-
- asyncTest: function( testName, expected, callback ) {
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- QUnit.test( testName, expected, callback, true );
- },
-
- test: function( testName, expected, callback, async ) {
- var test,
- nameHtml = "" + escapeText( testName ) + "";
-
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- if ( config.currentModule ) {
- nameHtml = "" + escapeText( config.currentModule ) + ": " + nameHtml;
- }
-
- test = new Test({
- nameHtml: nameHtml,
- testName: testName,
- expected: expected,
- async: async,
- callback: callback,
- module: config.currentModule,
- moduleTestEnvironment: config.currentModuleTestEnvironment,
- stack: sourceFromStacktrace( 2 )
- });
-
- if ( !validTest( test ) ) {
- return;
- }
-
- test.queue();
- },
-
- // Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through.
- expect: function( asserts ) {
- if (arguments.length === 1) {
- config.current.expected = asserts;
- } else {
- return config.current.expected;
- }
- },
-
- start: function( count ) {
- // QUnit hasn't been initialized yet.
- // Note: RequireJS (et al) may delay onLoad
- if ( config.semaphore === undefined ) {
- QUnit.begin(function() {
- // This is triggered at the top of QUnit.load, push start() to the event loop, to allow QUnit.load to finish first
- setTimeout(function() {
- QUnit.start( count );
- });
- });
- return;
- }
-
- config.semaphore -= count || 1;
- // don't start until equal number of stop-calls
- if ( config.semaphore > 0 ) {
- return;
- }
- // ignore if start is called more often then stop
- if ( config.semaphore < 0 ) {
- config.semaphore = 0;
- QUnit.pushFailure( "Called start() while already started (QUnit.config.semaphore was 0 already)", null, sourceFromStacktrace(2) );
- return;
- }
- // A slight delay, to avoid any current callbacks
- if ( defined.setTimeout ) {
- window.setTimeout(function() {
- if ( config.semaphore > 0 ) {
- return;
- }
- if ( config.timeout ) {
- clearTimeout( config.timeout );
- }
-
- config.blocking = false;
- process( true );
- }, 13);
- } else {
- config.blocking = false;
- process( true );
- }
- },
-
- stop: function( count ) {
- config.semaphore += count || 1;
- config.blocking = true;
-
- if ( config.testTimeout && defined.setTimeout ) {
- clearTimeout( config.timeout );
- config.timeout = window.setTimeout(function() {
- QUnit.ok( false, "Test timed out" );
- config.semaphore = 1;
- QUnit.start();
- }, config.testTimeout );
- }
- }
-};
-
-// `assert` initialized at top of scope
-// Asssert helpers
-// All of these must either call QUnit.push() or manually do:
-// - runLoggingCallbacks( "log", .. );
-// - config.current.assertions.push({ .. });
-// We attach it to the QUnit object *after* we expose the public API,
-// otherwise `assert` will become a global variable in browsers (#341).
-assert = {
- /**
- * Asserts rough true-ish result.
- * @name ok
- * @function
- * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" );
- */
- ok: function( result, msg ) {
- if ( !config.current ) {
- throw new Error( "ok() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
- result = !!result;
-
- var source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: msg
- };
-
- msg = escapeText( msg || (result ? "okay" : "failed" ) );
- msg = "" + msg + "";
-
- if ( !result ) {
- source = sourceFromStacktrace( 2 );
- if ( source ) {
- details.source = source;
- msg += "Source: | " + escapeText( source ) + " |
---|
";
- }
- }
- runLoggingCallbacks( "log", QUnit, details );
- config.current.assertions.push({
- result: result,
- message: msg
- });
- },
-
- /**
- * Assert that the first two arguments are equal, with an optional message.
- * Prints out both actual and expected values.
- * @name equal
- * @function
- * @example equal( format( "Received {0} bytes.", 2), "Received 2 bytes.", "format() replaces {0} with next argument" );
- */
- equal: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected == actual, actual, expected, message );
- },
-
- /**
- * @name notEqual
- * @function
- */
- notEqual: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected != actual, actual, expected, message );
- },
-
- /**
- * @name propEqual
- * @function
- */
- propEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notPropEqual
- * @function
- */
- notPropEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name deepEqual
- * @function
- */
- deepEqual: function( actual, expected, message ) {
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notDeepEqual
- * @function
- */
- notDeepEqual: function( actual, expected, message ) {
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name strictEqual
- * @function
- */
- strictEqual: function( actual, expected, message ) {
- QUnit.push( expected === actual, actual, expected, message );
- },
-
- /**
- * @name notStrictEqual
- * @function
- */
- notStrictEqual: function( actual, expected, message ) {
- QUnit.push( expected !== actual, actual, expected, message );
- },
-
- "throws": function( block, expected, message ) {
- var actual,
- expectedOutput = expected,
- ok = false;
-
- // 'expected' is optional
- if ( typeof expected === "string" ) {
- message = expected;
- expected = null;
- }
-
- config.current.ignoreGlobalErrors = true;
- try {
- block.call( config.current.testEnvironment );
- } catch (e) {
- actual = e;
- }
- config.current.ignoreGlobalErrors = false;
-
- if ( actual ) {
- // we don't want to validate thrown error
- if ( !expected ) {
- ok = true;
- expectedOutput = null;
- // expected is a regexp
- } else if ( QUnit.objectType( expected ) === "regexp" ) {
- ok = expected.test( errorString( actual ) );
- // expected is a constructor
- } else if ( actual instanceof expected ) {
- ok = true;
- // expected is a validation function which returns true is validation passed
- } else if ( expected.call( {}, actual ) === true ) {
- expectedOutput = null;
- ok = true;
- }
-
- QUnit.push( ok, actual, expectedOutput, message );
- } else {
- QUnit.pushFailure( message, null, 'No exception was thrown.' );
- }
- }
-};
-
-/**
- * @deprecate since 1.8.0
- * Kept assertion helpers in root for backwards compatibility.
- */
-extend( QUnit, assert );
-
-/**
- * @deprecated since 1.9.0
- * Kept root "raises()" for backwards compatibility.
- * (Note that we don't introduce assert.raises).
- */
-QUnit.raises = assert[ "throws" ];
-
-/**
- * @deprecated since 1.0.0, replaced with error pushes since 1.3.0
- * Kept to avoid TypeErrors for undefined methods.
- */
-QUnit.equals = function() {
- QUnit.push( false, false, false, "QUnit.equals has been deprecated since 2009 (e88049a0), use QUnit.equal instead" );
-};
-QUnit.same = function() {
- QUnit.push( false, false, false, "QUnit.same has been deprecated since 2009 (e88049a0), use QUnit.deepEqual instead" );
-};
-
-// We want access to the constructor's prototype
-(function() {
- function F() {}
- F.prototype = QUnit;
- QUnit = new F();
- // Make F QUnit's constructor so that we can add to the prototype later
- QUnit.constructor = F;
-}());
-
-/**
- * Config object: Maintain internal state
- * Later exposed as QUnit.config
- * `config` initialized at top of scope
- */
-config = {
- // The queue of tests to run
- queue: [],
-
- // block until document ready
- blocking: true,
-
- // when enabled, show only failing tests
- // gets persisted through sessionStorage and can be changed in UI via checkbox
- hidepassed: false,
-
- // by default, run previously failed tests first
- // very useful in combination with "Hide passed tests" checked
- reorder: true,
-
- // by default, modify document.title when suite is done
- altertitle: true,
-
- // when enabled, all tests must call expect()
- requireExpects: false,
-
- // add checkboxes that are persisted in the query-string
- // when enabled, the id is set to `true` as a `QUnit.config` property
- urlConfig: [
- {
- id: "noglobals",
- label: "Check for Globals",
- tooltip: "Enabling this will test if any test introduces new properties on the `window` object. Stored as query-strings."
- },
- {
- id: "notrycatch",
- label: "No try-catch",
- tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging exceptions in IE reasonable. Stored as query-strings."
- }
- ],
-
- // Set of all modules.
- modules: {},
-
- // logging callback queues
- begin: [],
- done: [],
- log: [],
- testStart: [],
- testDone: [],
- moduleStart: [],
- moduleDone: []
-};
-
-// Export global variables, unless an 'exports' object exists,
-// in that case we assume we're in CommonJS (dealt with on the bottom of the script)
-if ( typeof exports === "undefined" ) {
- extend( window, QUnit );
-
- // Expose QUnit object
- window.QUnit = QUnit;
-}
-
-// Initialize more QUnit.config and QUnit.urlParams
-(function() {
- var i,
- location = window.location || { search: "", protocol: "file:" },
- params = location.search.slice( 1 ).split( "&" ),
- length = params.length,
- urlParams = {},
- current;
-
- if ( params[ 0 ] ) {
- for ( i = 0; i < length; i++ ) {
- current = params[ i ].split( "=" );
- current[ 0 ] = decodeURIComponent( current[ 0 ] );
- // allow just a key to turn on a flag, e.g., test.html?noglobals
- current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true;
- urlParams[ current[ 0 ] ] = current[ 1 ];
- }
- }
-
- QUnit.urlParams = urlParams;
-
- // String search anywhere in moduleName+testName
- config.filter = urlParams.filter;
-
- // Exact match of the module name
- config.module = urlParams.module;
-
- config.testNumber = parseInt( urlParams.testNumber, 10 ) || null;
-
- // Figure out if we're running the tests from a server or not
- QUnit.isLocal = location.protocol === "file:";
-}());
-
-// Extend QUnit object,
-// these after set here because they should not be exposed as global functions
-extend( QUnit, {
- assert: assert,
-
- config: config,
-
- // Initialize the configuration options
- init: function() {
- extend( config, {
- stats: { all: 0, bad: 0 },
- moduleStats: { all: 0, bad: 0 },
- started: +new Date(),
- updateRate: 1000,
- blocking: false,
- autostart: true,
- autorun: false,
- filter: "",
- queue: [],
- semaphore: 1
- });
-
- var tests, banner, result,
- qunit = id( "qunit" );
-
- if ( qunit ) {
- qunit.innerHTML =
- "" +
- "" +
- "" +
- "" +
- "
";
- }
-
- tests = id( "qunit-tests" );
- banner = id( "qunit-banner" );
- result = id( "qunit-testresult" );
-
- if ( tests ) {
- tests.innerHTML = "";
- }
-
- if ( banner ) {
- banner.className = "";
- }
-
- if ( result ) {
- result.parentNode.removeChild( result );
- }
-
- if ( tests ) {
- result = document.createElement( "p" );
- result.id = "qunit-testresult";
- result.className = "result";
- tests.parentNode.insertBefore( result, tests );
- result.innerHTML = "Running...
";
- }
- },
-
- // Resets the test setup. Useful for tests that modify the DOM.
- reset: function() {
- var fixture = id( "qunit-fixture" );
- if ( fixture ) {
- fixture.innerHTML = config.fixture;
- }
- },
-
- // Trigger an event on an element.
- // @example triggerEvent( document.body, "click" );
- triggerEvent: function( elem, type, event ) {
- if ( document.createEvent ) {
- event = document.createEvent( "MouseEvents" );
- event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView,
- 0, 0, 0, 0, 0, false, false, false, false, 0, null);
-
- elem.dispatchEvent( event );
- } else if ( elem.fireEvent ) {
- elem.fireEvent( "on" + type );
- }
- },
-
- // Safe object type checking
- is: function( type, obj ) {
- return QUnit.objectType( obj ) === type;
- },
-
- objectType: function( obj ) {
- if ( typeof obj === "undefined" ) {
- return "undefined";
- // consider: typeof null === object
- }
- if ( obj === null ) {
- return "null";
- }
-
- var match = toString.call( obj ).match(/^\[object\s(.*)\]$/),
- type = match && match[1] || "";
-
- switch ( type ) {
- case "Number":
- if ( isNaN(obj) ) {
- return "nan";
- }
- return "number";
- case "String":
- case "Boolean":
- case "Array":
- case "Date":
- case "RegExp":
- case "Function":
- return type.toLowerCase();
- }
- if ( typeof obj === "object" ) {
- return "object";
- }
- return undefined;
- },
-
- push: function( result, actual, expected, message ) {
- if ( !config.current ) {
- throw new Error( "assertion outside test context, was " + sourceFromStacktrace() );
- }
-
- var output, source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: message,
- actual: actual,
- expected: expected
- };
-
- message = escapeText( message ) || ( result ? "okay" : "failed" );
- message = "" + message + "";
- output = message;
-
- if ( !result ) {
- expected = escapeText( QUnit.jsDump.parse(expected) );
- actual = escapeText( QUnit.jsDump.parse(actual) );
- output += "Expected: | " + expected + " |
";
-
- if ( actual !== expected ) {
- output += "Result: | " + actual + " |
";
- output += "Diff: | " + QUnit.diff( expected, actual ) + " |
";
- }
-
- source = sourceFromStacktrace();
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
- }
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: !!result,
- message: output
- });
- },
-
- pushFailure: function( message, source, actual ) {
- if ( !config.current ) {
- throw new Error( "pushFailure() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
-
- var output,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: false,
- message: message
- };
-
- message = escapeText( message ) || "error";
- message = "" + message + "";
- output = message;
-
- output += "";
-
- if ( actual ) {
- output += "Result: | " + escapeText( actual ) + " |
";
- }
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: false,
- message: output
- });
- },
-
- url: function( params ) {
- params = extend( extend( {}, QUnit.urlParams ), params );
- var key,
- querystring = "?";
-
- for ( key in params ) {
- if ( !hasOwn.call( params, key ) ) {
- continue;
- }
- querystring += encodeURIComponent( key ) + "=" +
- encodeURIComponent( params[ key ] ) + "&";
- }
- return window.location.protocol + "//" + window.location.host +
- window.location.pathname + querystring.slice( 0, -1 );
- },
-
- extend: extend,
- id: id,
- addEvent: addEvent
- // load, equiv, jsDump, diff: Attached later
-});
-
-/**
- * @deprecated: Created for backwards compatibility with test runner that set the hook function
- * into QUnit.{hook}, instead of invoking it and passing the hook function.
- * QUnit.constructor is set to the empty F() above so that we can add to it's prototype here.
- * Doing this allows us to tell if the following methods have been overwritten on the actual
- * QUnit object.
- */
-extend( QUnit.constructor.prototype, {
-
- // Logging callbacks; all receive a single argument with the listed properties
- // run test/logs.html for any related changes
- begin: registerLoggingCallback( "begin" ),
-
- // done: { failed, passed, total, runtime }
- done: registerLoggingCallback( "done" ),
-
- // log: { result, actual, expected, message }
- log: registerLoggingCallback( "log" ),
-
- // testStart: { name }
- testStart: registerLoggingCallback( "testStart" ),
-
- // testDone: { name, failed, passed, total, duration }
- testDone: registerLoggingCallback( "testDone" ),
-
- // moduleStart: { name }
- moduleStart: registerLoggingCallback( "moduleStart" ),
-
- // moduleDone: { name, failed, passed, total }
- moduleDone: registerLoggingCallback( "moduleDone" )
-});
-
-if ( typeof document === "undefined" || document.readyState === "complete" ) {
- config.autorun = true;
-}
-
-QUnit.load = function() {
- runLoggingCallbacks( "begin", QUnit, {} );
-
- // Initialize the config, saving the execution queue
- var banner, filter, i, label, len, main, ol, toolbar, userAgent, val,
- urlConfigCheckboxesContainer, urlConfigCheckboxes, moduleFilter,
- numModules = 0,
- moduleFilterHtml = "",
- urlConfigHtml = "",
- oldconfig = extend( {}, config );
-
- QUnit.init();
- extend(config, oldconfig);
-
- config.blocking = false;
-
- len = config.urlConfig.length;
-
- for ( i = 0; i < len; i++ ) {
- val = config.urlConfig[i];
- if ( typeof val === "string" ) {
- val = {
- id: val,
- label: val,
- tooltip: "[no tooltip available]"
- };
- }
- config[ val.id ] = QUnit.urlParams[ val.id ];
- urlConfigHtml += "";
- }
-
- moduleFilterHtml += "";
-
- // `userAgent` initialized at top of scope
- userAgent = id( "qunit-userAgent" );
- if ( userAgent ) {
- userAgent.innerHTML = navigator.userAgent;
- }
-
- // `banner` initialized at top of scope
- banner = id( "qunit-header" );
- if ( banner ) {
- banner.innerHTML = "" + banner.innerHTML + " ";
- }
-
- // `toolbar` initialized at top of scope
- toolbar = id( "qunit-testrunner-toolbar" );
- if ( toolbar ) {
- // `filter` initialized at top of scope
- filter = document.createElement( "input" );
- filter.type = "checkbox";
- filter.id = "qunit-filter-pass";
-
- addEvent( filter, "click", function() {
- var tmp,
- ol = document.getElementById( "qunit-tests" );
-
- if ( filter.checked ) {
- ol.className = ol.className + " hidepass";
- } else {
- tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " ";
- ol.className = tmp.replace( / hidepass /, " " );
- }
- if ( defined.sessionStorage ) {
- if (filter.checked) {
- sessionStorage.setItem( "qunit-filter-passed-tests", "true" );
- } else {
- sessionStorage.removeItem( "qunit-filter-passed-tests" );
- }
- }
- });
-
- if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem( "qunit-filter-passed-tests" ) ) {
- filter.checked = true;
- // `ol` initialized at top of scope
- ol = document.getElementById( "qunit-tests" );
- ol.className = ol.className + " hidepass";
- }
- toolbar.appendChild( filter );
-
- // `label` initialized at top of scope
- label = document.createElement( "label" );
- label.setAttribute( "for", "qunit-filter-pass" );
- label.setAttribute( "title", "Only show tests and assertons that fail. Stored in sessionStorage." );
- label.innerHTML = "Hide passed tests";
- toolbar.appendChild( label );
-
- urlConfigCheckboxesContainer = document.createElement("span");
- urlConfigCheckboxesContainer.innerHTML = urlConfigHtml;
- urlConfigCheckboxes = urlConfigCheckboxesContainer.getElementsByTagName("input");
- // For oldIE support:
- // * Add handlers to the individual elements instead of the container
- // * Use "click" instead of "change"
- // * Fallback from event.target to event.srcElement
- addEvents( urlConfigCheckboxes, "click", function( event ) {
- var params = {},
- target = event.target || event.srcElement;
- params[ target.name ] = target.checked ? true : undefined;
- window.location = QUnit.url( params );
- });
- toolbar.appendChild( urlConfigCheckboxesContainer );
-
- if (numModules > 1) {
- moduleFilter = document.createElement( 'span' );
- moduleFilter.setAttribute( 'id', 'qunit-modulefilter-container' );
- moduleFilter.innerHTML = moduleFilterHtml;
- addEvent( moduleFilter.lastChild, "change", function() {
- var selectBox = moduleFilter.getElementsByTagName("select")[0],
- selectedModule = decodeURIComponent(selectBox.options[selectBox.selectedIndex].value);
-
- window.location = QUnit.url( { module: ( selectedModule === "" ) ? undefined : selectedModule } );
- });
- toolbar.appendChild(moduleFilter);
- }
- }
-
- // `main` initialized at top of scope
- main = id( "qunit-fixture" );
- if ( main ) {
- config.fixture = main.innerHTML;
- }
-
- if ( config.autostart ) {
- QUnit.start();
- }
-};
-
-addEvent( window, "load", QUnit.load );
-
-// `onErrorFnPrev` initialized at top of scope
-// Preserve other handlers
-onErrorFnPrev = window.onerror;
-
-// Cover uncaught exceptions
-// Returning true will surpress the default browser handler,
-// returning false will let it run.
-window.onerror = function ( error, filePath, linerNr ) {
- var ret = false;
- if ( onErrorFnPrev ) {
- ret = onErrorFnPrev( error, filePath, linerNr );
- }
-
- // Treat return value as window.onerror itself does,
- // Only do our handling if not surpressed.
- if ( ret !== true ) {
- if ( QUnit.config.current ) {
- if ( QUnit.config.current.ignoreGlobalErrors ) {
- return true;
- }
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- } else {
- QUnit.test( "global failure", extend( function() {
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- }, { validTest: validTest } ) );
- }
- return false;
- }
-
- return ret;
-};
-
-function done() {
- config.autorun = true;
-
- // Log the last module results
- if ( config.currentModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.currentModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
-
- var i, key,
- banner = id( "qunit-banner" ),
- tests = id( "qunit-tests" ),
- runtime = +new Date() - config.started,
- passed = config.stats.all - config.stats.bad,
- html = [
- "Tests completed in ",
- runtime,
- " milliseconds.
",
- "",
- passed,
- " assertions of ",
- config.stats.all,
- " passed, ",
- config.stats.bad,
- " failed."
- ].join( "" );
-
- if ( banner ) {
- banner.className = ( config.stats.bad ? "qunit-fail" : "qunit-pass" );
- }
-
- if ( tests ) {
- id( "qunit-testresult" ).innerHTML = html;
- }
-
- if ( config.altertitle && typeof document !== "undefined" && document.title ) {
- // show ✖ for good, ✔ for bad suite result in title
- // use escape sequences in case file gets loaded with non-utf-8-charset
- document.title = [
- ( config.stats.bad ? "\u2716" : "\u2714" ),
- document.title.replace( /^[\u2714\u2716] /i, "" )
- ].join( " " );
- }
-
- // clear own sessionStorage items if all tests passed
- if ( config.reorder && defined.sessionStorage && config.stats.bad === 0 ) {
- // `key` & `i` initialized at top of scope
- for ( i = 0; i < sessionStorage.length; i++ ) {
- key = sessionStorage.key( i++ );
- if ( key.indexOf( "qunit-test-" ) === 0 ) {
- sessionStorage.removeItem( key );
- }
- }
- }
-
- // scroll back to top to show results
- if ( window.scrollTo ) {
- window.scrollTo(0, 0);
- }
-
- runLoggingCallbacks( "done", QUnit, {
- failed: config.stats.bad,
- passed: passed,
- total: config.stats.all,
- runtime: runtime
- });
-}
-
-/** @return Boolean: true if this test should be ran */
-function validTest( test ) {
- var include,
- filter = config.filter && config.filter.toLowerCase(),
- module = config.module && config.module.toLowerCase(),
- fullName = (test.module + ": " + test.testName).toLowerCase();
-
- // Internally-generated tests are always valid
- if ( test.callback && test.callback.validTest === validTest ) {
- delete test.callback.validTest;
- return true;
- }
-
- if ( config.testNumber ) {
- return test.testNumber === config.testNumber;
- }
-
- if ( module && ( !test.module || test.module.toLowerCase() !== module ) ) {
- return false;
- }
-
- if ( !filter ) {
- return true;
- }
-
- include = filter.charAt( 0 ) !== "!";
- if ( !include ) {
- filter = filter.slice( 1 );
- }
-
- // If the filter matches, we need to honour include
- if ( fullName.indexOf( filter ) !== -1 ) {
- return include;
- }
-
- // Otherwise, do the opposite
- return !include;
-}
-
-// so far supports only Firefox, Chrome and Opera (buggy), Safari (for real exceptions)
-// Later Safari and IE10 are supposed to support error.stack as well
-// See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack
-function extractStacktrace( e, offset ) {
- offset = offset === undefined ? 3 : offset;
-
- var stack, include, i;
-
- if ( e.stacktrace ) {
- // Opera
- return e.stacktrace.split( "\n" )[ offset + 3 ];
- } else if ( e.stack ) {
- // Firefox, Chrome
- stack = e.stack.split( "\n" );
- if (/^error$/i.test( stack[0] ) ) {
- stack.shift();
- }
- if ( fileName ) {
- include = [];
- for ( i = offset; i < stack.length; i++ ) {
- if ( stack[ i ].indexOf( fileName ) !== -1 ) {
- break;
- }
- include.push( stack[ i ] );
- }
- if ( include.length ) {
- return include.join( "\n" );
- }
- }
- return stack[ offset ];
- } else if ( e.sourceURL ) {
- // Safari, PhantomJS
- // hopefully one day Safari provides actual stacktraces
- // exclude useless self-reference for generated Error objects
- if ( /qunit.js$/.test( e.sourceURL ) ) {
- return;
- }
- // for actual exceptions, this is useful
- return e.sourceURL + ":" + e.line;
- }
-}
-function sourceFromStacktrace( offset ) {
- try {
- throw new Error();
- } catch ( e ) {
- return extractStacktrace( e, offset );
- }
-}
-
-/**
- * Escape text for attribute or text content.
- */
-function escapeText( s ) {
- if ( !s ) {
- return "";
- }
- s = s + "";
- // Both single quotes and double quotes (for attributes)
- return s.replace( /['"<>&]/g, function( s ) {
- switch( s ) {
- case '\'':
- return ''';
- case '"':
- return '"';
- case '<':
- return '<';
- case '>':
- return '>';
- case '&':
- return '&';
- }
- });
-}
-
-function synchronize( callback, last ) {
- config.queue.push( callback );
-
- if ( config.autorun && !config.blocking ) {
- process( last );
- }
-}
-
-function process( last ) {
- function next() {
- process( last );
- }
- var start = new Date().getTime();
- config.depth = config.depth ? config.depth + 1 : 1;
-
- while ( config.queue.length && !config.blocking ) {
- if ( !defined.setTimeout || config.updateRate <= 0 || ( ( new Date().getTime() - start ) < config.updateRate ) ) {
- config.queue.shift()();
- } else {
- window.setTimeout( next, 13 );
- break;
- }
- }
- config.depth--;
- if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) {
- done();
- }
-}
-
-function saveGlobal() {
- config.pollution = [];
-
- if ( config.noglobals ) {
- for ( var key in window ) {
- // in Opera sometimes DOM element ids show up here, ignore them
- if ( !hasOwn.call( window, key ) || /^qunit-test-output/.test( key ) ) {
- continue;
- }
- config.pollution.push( key );
- }
- }
-}
-
-function checkPollution() {
- var newGlobals,
- deletedGlobals,
- old = config.pollution;
-
- saveGlobal();
-
- newGlobals = diff( config.pollution, old );
- if ( newGlobals.length > 0 ) {
- QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join(", ") );
- }
-
- deletedGlobals = diff( old, config.pollution );
- if ( deletedGlobals.length > 0 ) {
- QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join(", ") );
- }
-}
-
-// returns a new Array with the elements that are in a but not in b
-function diff( a, b ) {
- var i, j,
- result = a.slice();
-
- for ( i = 0; i < result.length; i++ ) {
- for ( j = 0; j < b.length; j++ ) {
- if ( result[i] === b[j] ) {
- result.splice( i, 1 );
- i--;
- break;
- }
- }
- }
- return result;
-}
-
-function extend( a, b ) {
- for ( var prop in b ) {
- if ( b[ prop ] === undefined ) {
- delete a[ prop ];
-
- // Avoid "Member not found" error in IE8 caused by setting window.constructor
- } else if ( prop !== "constructor" || a !== window ) {
- a[ prop ] = b[ prop ];
- }
- }
-
- return a;
-}
-
-/**
- * @param {HTMLElement} elem
- * @param {string} type
- * @param {Function} fn
- */
-function addEvent( elem, type, fn ) {
- // Standards-based browsers
- if ( elem.addEventListener ) {
- elem.addEventListener( type, fn, false );
- // IE
- } else {
- elem.attachEvent( "on" + type, fn );
- }
-}
-
-/**
- * @param {Array|NodeList} elems
- * @param {string} type
- * @param {Function} fn
- */
-function addEvents( elems, type, fn ) {
- var i = elems.length;
- while ( i-- ) {
- addEvent( elems[i], type, fn );
- }
-}
-
-function hasClass( elem, name ) {
- return (" " + elem.className + " ").indexOf(" " + name + " ") > -1;
-}
-
-function addClass( elem, name ) {
- if ( !hasClass( elem, name ) ) {
- elem.className += (elem.className ? " " : "") + name;
- }
-}
-
-function removeClass( elem, name ) {
- var set = " " + elem.className + " ";
- // Class name may appear multiple times
- while ( set.indexOf(" " + name + " ") > -1 ) {
- set = set.replace(" " + name + " " , " ");
- }
- // If possible, trim it for prettiness, but not neccecarily
- elem.className = window.jQuery ? jQuery.trim( set ) : ( set.trim ? set.trim() : set );
-}
-
-function id( name ) {
- return !!( typeof document !== "undefined" && document && document.getElementById ) &&
- document.getElementById( name );
-}
-
-function registerLoggingCallback( key ) {
- return function( callback ) {
- config[key].push( callback );
- };
-}
-
-// Supports deprecated method of completely overwriting logging callbacks
-function runLoggingCallbacks( key, scope, args ) {
- var i, callbacks;
- if ( QUnit.hasOwnProperty( key ) ) {
- QUnit[ key ].call(scope, args );
- } else {
- callbacks = config[ key ];
- for ( i = 0; i < callbacks.length; i++ ) {
- callbacks[ i ].call( scope, args );
- }
- }
-}
-
-// Test for equality any JavaScript type.
-// Author: Philippe Rathé
-QUnit.equiv = (function() {
-
- // Call the o related callback with the given arguments.
- function bindCallbacks( o, callbacks, args ) {
- var prop = QUnit.objectType( o );
- if ( prop ) {
- if ( QUnit.objectType( callbacks[ prop ] ) === "function" ) {
- return callbacks[ prop ].apply( callbacks, args );
- } else {
- return callbacks[ prop ]; // or undefined
- }
- }
- }
-
- // the real equiv function
- var innerEquiv,
- // stack to decide between skip/abort functions
- callers = [],
- // stack to avoiding loops from circular referencing
- parents = [],
-
- getProto = Object.getPrototypeOf || function ( obj ) {
- return obj.__proto__;
- },
- callbacks = (function () {
-
- // for string, boolean, number and null
- function useStrictEquality( b, a ) {
- /*jshint eqeqeq:false */
- if ( b instanceof a.constructor || a instanceof b.constructor ) {
- // to catch short annotaion VS 'new' annotation of a
- // declaration
- // e.g. var i = 1;
- // var j = new Number(1);
- return a == b;
- } else {
- return a === b;
- }
- }
-
- return {
- "string": useStrictEquality,
- "boolean": useStrictEquality,
- "number": useStrictEquality,
- "null": useStrictEquality,
- "undefined": useStrictEquality,
-
- "nan": function( b ) {
- return isNaN( b );
- },
-
- "date": function( b, a ) {
- return QUnit.objectType( b ) === "date" && a.valueOf() === b.valueOf();
- },
-
- "regexp": function( b, a ) {
- return QUnit.objectType( b ) === "regexp" &&
- // the regex itself
- a.source === b.source &&
- // and its modifers
- a.global === b.global &&
- // (gmi) ...
- a.ignoreCase === b.ignoreCase &&
- a.multiline === b.multiline &&
- a.sticky === b.sticky;
- },
-
- // - skip when the property is a method of an instance (OOP)
- // - abort otherwise,
- // initial === would have catch identical references anyway
- "function": function() {
- var caller = callers[callers.length - 1];
- return caller !== Object && typeof caller !== "undefined";
- },
-
- "array": function( b, a ) {
- var i, j, len, loop;
-
- // b could be an object literal here
- if ( QUnit.objectType( b ) !== "array" ) {
- return false;
- }
-
- len = a.length;
- if ( len !== b.length ) {
- // safe and faster
- return false;
- }
-
- // track reference to avoid circular references
- parents.push( a );
- for ( i = 0; i < len; i++ ) {
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- loop = true;// dont rewalk array
- }
- }
- if ( !loop && !innerEquiv(a[i], b[i]) ) {
- parents.pop();
- return false;
- }
- }
- parents.pop();
- return true;
- },
-
- "object": function( b, a ) {
- var i, j, loop,
- // Default to true
- eq = true,
- aProperties = [],
- bProperties = [];
-
- // comparing constructors is more strict than using
- // instanceof
- if ( a.constructor !== b.constructor ) {
- // Allow objects with no prototype to be equivalent to
- // objects with Object as their constructor.
- if ( !(( getProto(a) === null && getProto(b) === Object.prototype ) ||
- ( getProto(b) === null && getProto(a) === Object.prototype ) ) ) {
- return false;
- }
- }
-
- // stack constructor before traversing properties
- callers.push( a.constructor );
- // track reference to avoid circular references
- parents.push( a );
-
- for ( i in a ) { // be strict: don't ensures hasOwnProperty
- // and go deep
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- // don't go down the same path twice
- loop = true;
- }
- }
- aProperties.push(i); // collect a's properties
-
- if (!loop && !innerEquiv( a[i], b[i] ) ) {
- eq = false;
- break;
- }
- }
-
- callers.pop(); // unstack, we are done
- parents.pop();
-
- for ( i in b ) {
- bProperties.push( i ); // collect b's properties
- }
-
- // Ensures identical properties name
- return eq && innerEquiv( aProperties.sort(), bProperties.sort() );
- }
- };
- }());
-
- innerEquiv = function() { // can take multiple arguments
- var args = [].slice.apply( arguments );
- if ( args.length < 2 ) {
- return true; // end transition
- }
-
- return (function( a, b ) {
- if ( a === b ) {
- return true; // catch the most you can
- } else if ( a === null || b === null || typeof a === "undefined" ||
- typeof b === "undefined" ||
- QUnit.objectType(a) !== QUnit.objectType(b) ) {
- return false; // don't lose time with error prone cases
- } else {
- return bindCallbacks(a, callbacks, [ b, a ]);
- }
-
- // apply transition with (1..n) arguments
- }( args[0], args[1] ) && arguments.callee.apply( this, args.splice(1, args.length - 1 )) );
- };
-
- return innerEquiv;
-}());
-
-/**
- * jsDump Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com |
- * http://flesler.blogspot.com Licensed under BSD
- * (http://www.opensource.org/licenses/bsd-license.php) Date: 5/15/2008
- *
- * @projectDescription Advanced and extensible data dumping for Javascript.
- * @version 1.0.0
- * @author Ariel Flesler
- * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html}
- */
-QUnit.jsDump = (function() {
- function quote( str ) {
- return '"' + str.toString().replace( /"/g, '\\"' ) + '"';
- }
- function literal( o ) {
- return o + "";
- }
- function join( pre, arr, post ) {
- var s = jsDump.separator(),
- base = jsDump.indent(),
- inner = jsDump.indent(1);
- if ( arr.join ) {
- arr = arr.join( "," + s + inner );
- }
- if ( !arr ) {
- return pre + post;
- }
- return [ pre, inner + arr, base + post ].join(s);
- }
- function array( arr, stack ) {
- var i = arr.length, ret = new Array(i);
- this.up();
- while ( i-- ) {
- ret[i] = this.parse( arr[i] , undefined , stack);
- }
- this.down();
- return join( "[", ret, "]" );
- }
-
- var reName = /^function (\w+)/,
- jsDump = {
- // type is used mostly internally, you can fix a (custom)type in advance
- parse: function( obj, type, stack ) {
- stack = stack || [ ];
- var inStack, res,
- parser = this.parsers[ type || this.typeOf(obj) ];
-
- type = typeof parser;
- inStack = inArray( obj, stack );
-
- if ( inStack !== -1 ) {
- return "recursion(" + (inStack - stack.length) + ")";
- }
- if ( type === "function" ) {
- stack.push( obj );
- res = parser.call( this, obj, stack );
- stack.pop();
- return res;
- }
- return ( type === "string" ) ? parser : this.parsers.error;
- },
- typeOf: function( obj ) {
- var type;
- if ( obj === null ) {
- type = "null";
- } else if ( typeof obj === "undefined" ) {
- type = "undefined";
- } else if ( QUnit.is( "regexp", obj) ) {
- type = "regexp";
- } else if ( QUnit.is( "date", obj) ) {
- type = "date";
- } else if ( QUnit.is( "function", obj) ) {
- type = "function";
- } else if ( typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined" ) {
- type = "window";
- } else if ( obj.nodeType === 9 ) {
- type = "document";
- } else if ( obj.nodeType ) {
- type = "node";
- } else if (
- // native arrays
- toString.call( obj ) === "[object Array]" ||
- // NodeList objects
- ( typeof obj.length === "number" && typeof obj.item !== "undefined" && ( obj.length ? obj.item(0) === obj[0] : ( obj.item( 0 ) === null && typeof obj[0] === "undefined" ) ) )
- ) {
- type = "array";
- } else if ( obj.constructor === Error.prototype.constructor ) {
- type = "error";
- } else {
- type = typeof obj;
- }
- return type;
- },
- separator: function() {
- return this.multiline ? this.HTML ? "
" : "\n" : this.HTML ? " " : " ";
- },
- // extra can be a number, shortcut for increasing-calling-decreasing
- indent: function( extra ) {
- if ( !this.multiline ) {
- return "";
- }
- var chr = this.indentChar;
- if ( this.HTML ) {
- chr = chr.replace( /\t/g, " " ).replace( / /g, " " );
- }
- return new Array( this._depth_ + (extra||0) ).join(chr);
- },
- up: function( a ) {
- this._depth_ += a || 1;
- },
- down: function( a ) {
- this._depth_ -= a || 1;
- },
- setParser: function( name, parser ) {
- this.parsers[name] = parser;
- },
- // The next 3 are exposed so you can use them
- quote: quote,
- literal: literal,
- join: join,
- //
- _depth_: 1,
- // This is the list of parsers, to modify them, use jsDump.setParser
- parsers: {
- window: "[Window]",
- document: "[Document]",
- error: function(error) {
- return "Error(\"" + error.message + "\")";
- },
- unknown: "[Unknown]",
- "null": "null",
- "undefined": "undefined",
- "function": function( fn ) {
- var ret = "function",
- // functions never have name in IE
- name = "name" in fn ? fn.name : (reName.exec(fn) || [])[1];
-
- if ( name ) {
- ret += " " + name;
- }
- ret += "( ";
-
- ret = [ ret, QUnit.jsDump.parse( fn, "functionArgs" ), "){" ].join( "" );
- return join( ret, QUnit.jsDump.parse(fn,"functionCode" ), "}" );
- },
- array: array,
- nodelist: array,
- "arguments": array,
- object: function( map, stack ) {
- var ret = [ ], keys, key, val, i;
- QUnit.jsDump.up();
- keys = [];
- for ( key in map ) {
- keys.push( key );
- }
- keys.sort();
- for ( i = 0; i < keys.length; i++ ) {
- key = keys[ i ];
- val = map[ key ];
- ret.push( QUnit.jsDump.parse( key, "key" ) + ": " + QUnit.jsDump.parse( val, undefined, stack ) );
- }
- QUnit.jsDump.down();
- return join( "{", ret, "}" );
- },
- node: function( node ) {
- var len, i, val,
- open = QUnit.jsDump.HTML ? "<" : "<",
- close = QUnit.jsDump.HTML ? ">" : ">",
- tag = node.nodeName.toLowerCase(),
- ret = open + tag,
- attrs = node.attributes;
-
- if ( attrs ) {
- for ( i = 0, len = attrs.length; i < len; i++ ) {
- val = attrs[i].nodeValue;
- // IE6 includes all attributes in .attributes, even ones not explicitly set.
- // Those have values like undefined, null, 0, false, "" or "inherit".
- if ( val && val !== "inherit" ) {
- ret += " " + attrs[i].nodeName + "=" + QUnit.jsDump.parse( val, "attribute" );
- }
- }
- }
- ret += close;
-
- // Show content of TextNode or CDATASection
- if ( node.nodeType === 3 || node.nodeType === 4 ) {
- ret += node.nodeValue;
- }
-
- return ret + open + "/" + tag + close;
- },
- // function calls it internally, it's the arguments part of the function
- functionArgs: function( fn ) {
- var args,
- l = fn.length;
-
- if ( !l ) {
- return "";
- }
-
- args = new Array(l);
- while ( l-- ) {
- // 97 is 'a'
- args[l] = String.fromCharCode(97+l);
- }
- return " " + args.join( ", " ) + " ";
- },
- // object calls it internally, the key part of an item in a map
- key: quote,
- // function calls it internally, it's the content of the function
- functionCode: "[code]",
- // node calls it internally, it's an html attribute value
- attribute: quote,
- string: quote,
- date: quote,
- regexp: literal,
- number: literal,
- "boolean": literal
- },
- // if true, entities are escaped ( <, >, \t, space and \n )
- HTML: false,
- // indentation unit
- indentChar: " ",
- // if true, items in a collection, are separated by a \n, else just a space.
- multiline: true
- };
-
- return jsDump;
-}());
-
-// from jquery.js
-function inArray( elem, array ) {
- if ( array.indexOf ) {
- return array.indexOf( elem );
- }
-
- for ( var i = 0, length = array.length; i < length; i++ ) {
- if ( array[ i ] === elem ) {
- return i;
- }
- }
-
- return -1;
-}
-
-/*
- * Javascript Diff Algorithm
- * By John Resig (http://ejohn.org/)
- * Modified by Chu Alan "sprite"
- *
- * Released under the MIT license.
- *
- * More Info:
- * http://ejohn.org/projects/javascript-diff-algorithm/
- *
- * Usage: QUnit.diff(expected, actual)
- *
- * QUnit.diff( "the quick brown fox jumped over", "the quick fox jumps over" ) == "the quick brown fox jumped jumps over"
- */
-QUnit.diff = (function() {
- /*jshint eqeqeq:false, eqnull:true */
- function diff( o, n ) {
- var i,
- ns = {},
- os = {};
-
- for ( i = 0; i < n.length; i++ ) {
- if ( !hasOwn.call( ns, n[i] ) ) {
- ns[ n[i] ] = {
- rows: [],
- o: null
- };
- }
- ns[ n[i] ].rows.push( i );
- }
-
- for ( i = 0; i < o.length; i++ ) {
- if ( !hasOwn.call( os, o[i] ) ) {
- os[ o[i] ] = {
- rows: [],
- n: null
- };
- }
- os[ o[i] ].rows.push( i );
- }
-
- for ( i in ns ) {
- if ( !hasOwn.call( ns, i ) ) {
- continue;
- }
- if ( ns[i].rows.length === 1 && hasOwn.call( os, i ) && os[i].rows.length === 1 ) {
- n[ ns[i].rows[0] ] = {
- text: n[ ns[i].rows[0] ],
- row: os[i].rows[0]
- };
- o[ os[i].rows[0] ] = {
- text: o[ os[i].rows[0] ],
- row: ns[i].rows[0]
- };
- }
- }
-
- for ( i = 0; i < n.length - 1; i++ ) {
- if ( n[i].text != null && n[ i + 1 ].text == null && n[i].row + 1 < o.length && o[ n[i].row + 1 ].text == null &&
- n[ i + 1 ] == o[ n[i].row + 1 ] ) {
-
- n[ i + 1 ] = {
- text: n[ i + 1 ],
- row: n[i].row + 1
- };
- o[ n[i].row + 1 ] = {
- text: o[ n[i].row + 1 ],
- row: i + 1
- };
- }
- }
-
- for ( i = n.length - 1; i > 0; i-- ) {
- if ( n[i].text != null && n[ i - 1 ].text == null && n[i].row > 0 && o[ n[i].row - 1 ].text == null &&
- n[ i - 1 ] == o[ n[i].row - 1 ]) {
-
- n[ i - 1 ] = {
- text: n[ i - 1 ],
- row: n[i].row - 1
- };
- o[ n[i].row - 1 ] = {
- text: o[ n[i].row - 1 ],
- row: i - 1
- };
- }
- }
-
- return {
- o: o,
- n: n
- };
- }
-
- return function( o, n ) {
- o = o.replace( /\s+$/, "" );
- n = n.replace( /\s+$/, "" );
-
- var i, pre,
- str = "",
- out = diff( o === "" ? [] : o.split(/\s+/), n === "" ? [] : n.split(/\s+/) ),
- oSpace = o.match(/\s+/g),
- nSpace = n.match(/\s+/g);
-
- if ( oSpace == null ) {
- oSpace = [ " " ];
- }
- else {
- oSpace.push( " " );
- }
-
- if ( nSpace == null ) {
- nSpace = [ " " ];
- }
- else {
- nSpace.push( " " );
- }
-
- if ( out.n.length === 0 ) {
- for ( i = 0; i < out.o.length; i++ ) {
- str += "" + out.o[i] + oSpace[i] + "";
- }
- }
- else {
- if ( out.n[0].text == null ) {
- for ( n = 0; n < out.o.length && out.o[n].text == null; n++ ) {
- str += "" + out.o[n] + oSpace[n] + "";
- }
- }
-
- for ( i = 0; i < out.n.length; i++ ) {
- if (out.n[i].text == null) {
- str += "" + out.n[i] + nSpace[i] + "";
- }
- else {
- // `pre` initialized at top of scope
- pre = "";
-
- for ( n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++ ) {
- pre += "" + out.o[n] + oSpace[n] + "";
- }
- str += " " + out.n[i].text + nSpace[i] + pre;
- }
- }
- }
-
- return str;
- };
-}());
-
-// for CommonJS enviroments, export everything
-if ( typeof exports !== "undefined" ) {
- extend( exports, QUnit );
-}
-
-// get at whatever the global object is, like window in browsers
-}( (function() {return this;}.call()) ));
diff --git a/test/lib/require.js b/test/lib/require.js
deleted file mode 100644
index 987f865..0000000
--- a/test/lib/require.js
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- RequireJS 2.1.5 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.
- Available via the MIT or new BSD license.
- see: http://github.com/jrburke/requirejs for details
-*/
-var requirejs,require,define;
-(function(aa){function I(b){return"[object Function]"===L.call(b)}function J(b){return"[object Array]"===L.call(b)}function y(b,c){if(b){var d;for(d=0;dthis.depCount&&!this.defined){if(I(n)){if(this.events.error)try{e=i.execCb(c,n,b,e)}catch(d){a=d}else e=i.execCb(c,n,b,e);this.map.isDefine&&((b=this.module)&&void 0!==b.exports&&b.exports!==this.exports?e=b.exports:void 0===e&&this.usingExports&&(e=this.exports));if(a)return a.requireMap=this.map,a.requireModules=[this.map.id],a.requireType="define",v(this.error=
-a)}else e=n;this.exports=e;if(this.map.isDefine&&!this.ignore&&(q[c]=e,l.onResourceLoad))l.onResourceLoad(i,this.map,this.depMaps);x(c);this.defined=!0}this.defining=!1;this.defined&&!this.defineEmitted&&(this.defineEmitted=!0,this.emit("defined",this.exports),this.defineEmitComplete=!0)}}else this.fetch()}},callPlugin:function(){var a=this.map,b=a.id,d=j(a.prefix);this.depMaps.push(d);t(d,"defined",u(this,function(e){var n,d;d=this.map.name;var g=this.map.parentMap?this.map.parentMap.name:null,h=
-i.makeRequire(a.parentMap,{enableBuildCallback:!0});if(this.map.unnormalized){if(e.normalize&&(d=e.normalize(d,function(a){return c(a,g,!0)})||""),e=j(a.prefix+"!"+d,this.map.parentMap),t(e,"defined",u(this,function(a){this.init([],function(){return a},null,{enabled:!0,ignore:!0})})),d=m(p,e.id)){this.depMaps.push(e);if(this.events.error)d.on("error",u(this,function(a){this.emit("error",a)}));d.enable()}}else n=u(this,function(a){this.init([],function(){return a},null,{enabled:!0})}),n.error=u(this,
-function(a){this.inited=!0;this.error=a;a.requireModules=[b];G(p,function(a){0===a.map.id.indexOf(b+"_unnormalized")&&x(a.map.id)});v(a)}),n.fromText=u(this,function(e,c){var d=a.name,g=j(d),C=O;c&&(e=c);C&&(O=!1);r(g);s(k.config,b)&&(k.config[d]=k.config[b]);try{l.exec(e)}catch(ca){return v(B("fromtexteval","fromText eval for "+b+" failed: "+ca,ca,[b]))}C&&(O=!0);this.depMaps.push(g);i.completeLoad(d);h([d],n)}),e.load(a.name,h,n,k)}));i.enable(d,this);this.pluginMaps[d.id]=d},enable:function(){V[this.map.id]=
-this;this.enabling=this.enabled=!0;y(this.depMaps,u(this,function(a,b){var c,e;if("string"===typeof a){a=j(a,this.map.isDefine?this.map:this.map.parentMap,!1,!this.skipMap);this.depMaps[b]=a;if(c=m(N,a.id)){this.depExports[b]=c(this);return}this.depCount+=1;t(a,"defined",u(this,function(a){this.defineDep(b,a);this.check()}));this.errback&&t(a,"error",this.errback)}c=a.id;e=p[c];!s(N,c)&&(e&&!e.enabled)&&i.enable(a,this)}));G(this.pluginMaps,u(this,function(a){var b=m(p,a.id);b&&!b.enabled&&i.enable(a,
-this)}));this.enabling=!1;this.check()},on:function(a,b){var c=this.events[a];c||(c=this.events[a]=[]);c.push(b)},emit:function(a,b){y(this.events[a],function(a){a(b)});"error"===a&&delete this.events[a]}};i={config:k,contextName:b,registry:p,defined:q,urlFetched:U,defQueue:H,Module:Z,makeModuleMap:j,nextTick:l.nextTick,onError:v,configure:function(a){a.baseUrl&&"/"!==a.baseUrl.charAt(a.baseUrl.length-1)&&(a.baseUrl+="/");var b=k.pkgs,c=k.shim,e={paths:!0,config:!0,map:!0};G(a,function(a,b){e[b]?
-"map"===b?(k.map||(k.map={}),R(k[b],a,!0,!0)):R(k[b],a,!0):k[b]=a});a.shim&&(G(a.shim,function(a,b){J(a)&&(a={deps:a});if((a.exports||a.init)&&!a.exportsFn)a.exportsFn=i.makeShimExports(a);c[b]=a}),k.shim=c);a.packages&&(y(a.packages,function(a){a="string"===typeof a?{name:a}:a;b[a.name]={name:a.name,location:a.location||a.name,main:(a.main||"main").replace(ja,"").replace(ea,"")}}),k.pkgs=b);G(p,function(a,b){!a.inited&&!a.map.unnormalized&&(a.map=j(b))});if(a.deps||a.callback)i.require(a.deps||[],
-a.callback)},makeShimExports:function(a){return function(){var b;a.init&&(b=a.init.apply(aa,arguments));return b||a.exports&&ba(a.exports)}},makeRequire:function(a,f){function d(e,c,h){var g,k;f.enableBuildCallback&&(c&&I(c))&&(c.__requireJsBuild=!0);if("string"===typeof e){if(I(c))return v(B("requireargs","Invalid require call"),h);if(a&&s(N,e))return N[e](p[a.id]);if(l.get)return l.get(i,e,a,d);g=j(e,a,!1,!0);g=g.id;return!s(q,g)?v(B("notloaded",'Module name "'+g+'" has not been loaded yet for context: '+
-b+(a?"":". Use require([])"))):q[g]}L();i.nextTick(function(){L();k=r(j(null,a));k.skipMap=f.skipMap;k.init(e,c,h,{enabled:!0});D()});return d}f=f||{};R(d,{isBrowser:A,toUrl:function(b){var d,f=b.lastIndexOf("."),g=b.split("/")[0];if(-1!==f&&(!("."===g||".."===g)||1h.attachEvent.toString().indexOf("[native code"))&&!Y?(O=!0,h.attachEvent("onreadystatechange",b.onScriptLoad)):(h.addEventListener("load",b.onScriptLoad,!1),h.addEventListener("error",b.onScriptError,!1)),h.src=d,K=h,D?x.insertBefore(h,D):x.appendChild(h),K=null,h;if(da)try{importScripts(d),b.completeLoad(c)}catch(j){b.onError(B("importscripts","importScripts failed for "+c+" at "+d,j,[c]))}};A&&M(document.getElementsByTagName("script"),function(b){x||(x=
-b.parentNode);if(t=b.getAttribute("data-main"))return r.baseUrl||(E=t.split("/"),Q=E.pop(),fa=E.length?E.join("/")+"/":"./",r.baseUrl=fa,t=Q),t=t.replace(ea,""),r.deps=r.deps?r.deps.concat(t):[t],!0});define=function(b,c,d){var l,h;"string"!==typeof b&&(d=c,c=b,b=null);J(c)||(d=c,c=[]);!c.length&&I(d)&&d.length&&(d.toString().replace(la,"").replace(ma,function(b,d){c.push(d)}),c=(1===d.length?["require"]:["require","exports","module"]).concat(c));if(O){if(!(l=K))P&&"interactive"===P.readyState||M(document.getElementsByTagName("script"),
-function(b){if("interactive"===b.readyState)return P=b}),l=P;l&&(b||(b=l.getAttribute("data-requiremodule")),h=F[l.getAttribute("data-requirecontext")])}(h?h.defQueue:T).push([b,c,d])};define.amd={jQuery:!0};l.exec=function(b){return eval(b)};l(r)}})(this);
diff --git a/test/lib/resemble.js b/test/lib/resemble.js
new file mode 100644
index 0000000..1cb8c29
--- /dev/null
+++ b/test/lib/resemble.js
@@ -0,0 +1,535 @@
+/*
+Author: James Cryer
+Company: Huddle
+Last updated date: 21 Feb 2013
+URL: https://github.com/Huddle/Resemble.js
+*/
+
+(function(_this){
+ 'use strict';
+
+ _this['resemble'] = function( fileData ){
+
+ var data = {};
+ var images = [];
+ var updateCallbackArray = [];
+
+ var tolerance = { // between 0 and 255
+ red: 16,
+ green: 16,
+ blue: 16,
+ minBrightness: 16,
+ maxBrightness: 240
+ };
+
+ var ignoreAntialiasing = false;
+ var ignoreColors = false;
+
+ function triggerDataUpdate(){
+ var len = updateCallbackArray.length;
+ var i;
+ for(i=0;i tolerance.maxBrightness;
+ }
+
+ function getHue(r,g,b){
+
+ r = r / 255;
+ g = g / 255;
+ b = b / 255;
+ var max = Math.max(r, g, b), min = Math.min(r, g, b);
+ var h;
+ var d;
+
+ if (max == min){
+ h = 0; // achromatic
+ } else{
+ d = max - min;
+ switch(max){
+ case r: h = (g - b) / d + (g < b ? 6 : 0); break;
+ case g: h = (b - r) / d + 2; break;
+ case b: h = (r - g) / d + 4; break;
+ }
+ h /= 6;
+ }
+
+ return h;
+ }
+
+ function isAntialiased(sourcePix, data, cacheSet, verticalPos, horizontalPos, width){
+ var offset;
+ var targetPix;
+ var distance = 1;
+ var i;
+ var j;
+ var hasHighContrastSibling = 0;
+ var hasSiblingWithDifferentHue = 0;
+ var hasEquivilantSibling = 0;
+
+ addHueInfo(sourcePix);
+
+ for (i = distance*-1; i <= distance; i++){
+ for (j = distance*-1; j <= distance; j++){
+
+ if(i===0 && j===0){
+ // ignore source pixel
+ } else {
+
+ offset = ((verticalPos+j)*width + (horizontalPos+i)) * 4;
+ targetPix = getPixelInfo(data, offset, cacheSet);
+
+ if(targetPix === null){
+ continue;
+ }
+
+ addBrightnessInfo(targetPix);
+ addHueInfo(targetPix);
+
+ if( isContrasting(sourcePix, targetPix) ){
+ hasHighContrastSibling++;
+ }
+
+ if( isRGBSame(sourcePix,targetPix) ){
+ hasEquivilantSibling++;
+ }
+
+ if( Math.abs(targetPix.h - sourcePix.h) > 0.3 ){
+ hasSiblingWithDifferentHue++;
+ }
+
+ if( hasSiblingWithDifferentHue > 1 || hasHighContrastSibling > 1){
+ return true;
+ }
+ }
+ }
+ }
+
+ if(hasEquivilantSibling < 2){
+ return true;
+ }
+
+ return false;
+ }
+
+ function errorPixel(px, offset){
+ px[offset] = 255; //r
+ px[offset + 1] = 0; //g
+ px[offset + 2] = 255; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyPixel(px, offset, data){
+ px[offset] = data.r; //r
+ px[offset + 1] = data.g; //g
+ px[offset + 2] = data.b; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyGrayScalePixel(px, offset, data){
+ px[offset] = data.brightness; //r
+ px[offset + 1] = data.brightness; //g
+ px[offset + 2] = data.brightness; //b
+ px[offset + 3] = 255; //a
+ }
+
+
+ function getPixelInfo(data, offset, cacheSet){
+ var r;
+ var g;
+ var b;
+ var d;
+
+ if(typeof data[offset] !== 'undefined'){
+ r = data[offset];
+ g = data[offset+1];
+ b = data[offset+2];
+ d = {
+ r: r,
+ g: g,
+ b: b
+ };
+
+ return d;
+ } else {
+ return null;
+ }
+ }
+
+ function addBrightnessInfo(data){
+ data.brightness = getBrightness(data.r,data.g,data.b); // 'corrected' lightness
+ }
+
+ function addHueInfo(data){
+ data.h = getHue(data.r,data.g,data.b);
+ }
+
+ function analyseImages(img1, img2, width, height){
+
+ var hiddenCanvas = document.createElement('canvas');
+
+ var data1 = img1.data;
+ var data2 = img2.data;
+
+ hiddenCanvas.width = width;
+ hiddenCanvas.height = height;
+
+ var context = hiddenCanvas.getContext('2d');
+ var imgd = context.createImageData(width,height);
+ var targetPix = imgd.data;
+
+ var mismatchCount = 0;
+
+ var time = Date.now();
+
+ var skip;
+
+ if( (width > 1200 || height > 1200) && ignoreAntialiasing){
+ skip = 6;
+ }
+
+ loop(height, width, function(verticalPos, horizontalPos){
+
+ if(skip){ // only skip if the image isn't small
+ if(verticalPos % skip === 0 || horizontalPos % skip === 0){
+ return;
+ }
+ }
+
+ var offset = (verticalPos*width + horizontalPos) * 4;
+ var pixel1 = getPixelInfo(data1, offset, 1);
+ var pixel2 = getPixelInfo(data2, offset, 2);
+
+ if(pixel1 === null || pixel2 === null){
+ return;
+ }
+
+ if (ignoreColors){
+
+ addBrightnessInfo(pixel1);
+ addBrightnessInfo(pixel2);
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ return;
+ }
+
+ if( isRGBSimilar(pixel1, pixel2) ){
+ copyPixel(targetPix, offset, pixel2);
+
+ } else if( ignoreAntialiasing && (
+ addBrightnessInfo(pixel1), // jit pixel info augmentation looks a little weird, sorry.
+ addBrightnessInfo(pixel2),
+ isAntialiased(pixel1, data1, 1, verticalPos, horizontalPos, width) ||
+ isAntialiased(pixel2, data2, 2, verticalPos, horizontalPos, width)
+ )){
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+
+ });
+
+ data.misMatchPercentage = (mismatchCount / (height*width) * 100).toFixed(2);
+ data.analysisTime = Date.now() - time;
+
+ data.getImageDataUrl = function(text){
+ var barHeight = 0;
+
+ if(text){
+ barHeight = addLabel(text,context,hiddenCanvas);
+ }
+
+ context.putImageData(imgd, 0, barHeight);
+
+ return hiddenCanvas.toDataURL("image/png");
+ };
+ }
+
+ function addLabel(text, context, hiddenCanvas){
+ var textPadding = 2;
+
+ context.font = '12px sans-serif';
+
+ var textWidth = context.measureText(text).width + textPadding*2;
+ var barHeight = 22;
+
+ if(textWidth > hiddenCanvas.width){
+ hiddenCanvas.width = textWidth;
+ }
+
+ hiddenCanvas.height += barHeight;
+
+ context.fillStyle = "#666";
+ context.fillRect(0,0,hiddenCanvas.width,barHeight -4);
+ context.fillStyle = "#fff";
+ context.fillRect(0,barHeight -4,hiddenCanvas.width, 4);
+
+ context.fillStyle = "#fff";
+ context.textBaseline = "top";
+ context.font = '12px sans-serif';
+ context.fillText(text, textPadding, 1);
+
+ return barHeight;
+ }
+
+ function normalise(img, w, h){
+ var c;
+ var context;
+
+ if(img.height < h || img.width < w){
+ c = document.createElement('canvas');
+ c.width = w;
+ c.height = h;
+ context = c.getContext('2d');
+ context.putImageData(img, 0, 0);
+ return context.getImageData(0, 0, w, h);
+ }
+
+ return img;
+ }
+
+ function compare(one, two){
+
+ function onceWeHaveBoth(){
+ var width;
+ var height;
+ if(images.length === 2){
+ width = images[0].width > images[1].width ? images[0].width : images[1].width;
+ height = images[0].height > images[1].height ? images[0].height : images[1].height;
+
+ if( (images[0].width === images[1].width) && (images[0].height === images[1].height) ){
+ data.isSameDimensions = true;
+ } else {
+ data.isSameDimensions = false;
+ }
+
+ analyseImages( normalise(images[0],width, height), normalise(images[1],width, height), width, height);
+
+ triggerDataUpdate();
+ }
+ }
+
+ images = [];
+ loadImageData(one, onceWeHaveBoth);
+ loadImageData(two, onceWeHaveBoth);
+ }
+
+ function getCompareApi(param){
+
+ var secondFileData,
+ hasMethod = typeof param === 'function';
+
+ if( !hasMethod ){
+ // assume it's file data
+ secondFileData = param;
+ }
+
+ var self = {
+ ignoreNothing: function(){
+
+ tolerance.red = 16;
+ tolerance.green = 16;
+ tolerance.blue = 16;
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreAntialiasing: function(){
+
+ tolerance.red = 32;
+ tolerance.green = 32;
+ tolerance.blue = 32;
+ tolerance.minBrightness = 64;
+ tolerance.maxBrightness = 96;
+
+ ignoreAntialiasing = true;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreColors: function(){
+
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = true;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ onComplete: function( callback ){
+
+ updateCallbackArray.push(callback);
+
+ var wrapper = function(){
+ compare(fileData, secondFileData);
+ };
+
+ wrapper();
+
+ return getCompareApi(wrapper);
+ }
+ };
+
+ return self;
+ }
+
+ return {
+ onComplete: function( callback ){
+ updateCallbackArray.push(callback);
+ loadImageData(fileData, function(imageData, width, height){
+ parseImage(imageData.data, width, height);
+ });
+ },
+ compareTo: function(secondFileData){
+ return getCompareApi(secondFileData);
+ }
+ };
+
+ };
+}(this));
\ No newline at end of file
diff --git a/test/testsuite.js b/test/testsuite.js
deleted file mode 100644
index b486acb..0000000
--- a/test/testsuite.js
+++ /dev/null
@@ -1,36 +0,0 @@
-requirejs.config({
- baseUrl: '/test/unit/'
-});
-
-define(function(require) {
- var testModules = [
- 'Pixi',
- 'Point',
- 'Rectangle',
- 'DisplayObject',
- 'DisplayObjectContainer',
- 'Sprite',
- 'MovieClip',
- 'InteractionManager',
- 'Stage',
- 'utils/Utils',
- 'utils/EventTarget',
- 'utils/Matrix',
- 'utils/Detector',
- 'renderers/WebGLShaders',
- 'renderers/WebGLRenderer',
- 'renderers/WebGLBatch',
- 'renderers/CanvasRenderer',
- 'extras/Strip',
- 'extras/Rope',
- 'textures/BaseTexture',
- 'textures/Texture',
- 'loaders/SpriteSheetLoader',
- 'loaders/AssetLoader'
- ];
-
- // Resolve all testModules and then start the Test Runner.
- require(testModules, function() {
- QUnit.start();
- });
-});
\ No newline at end of file
diff --git a/test/textures/SpriteSheet-Aliens.png b/test/textures/SpriteSheet-Aliens.png
new file mode 100644
index 0000000..210acb1
--- /dev/null
+++ b/test/textures/SpriteSheet-Aliens.png
Binary files differ
diff --git a/test/textures/SpriteSheet-Explosion.png b/test/textures/SpriteSheet-Explosion.png
new file mode 100755
index 0000000..79e1a69
--- /dev/null
+++ b/test/textures/SpriteSheet-Explosion.png
Binary files differ
diff --git a/test/textures/bunny.png b/test/textures/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/textures/bunny.png
Binary files differ
diff --git a/test/unit/DisplayObject.js b/test/unit/DisplayObject.js
deleted file mode 100644
index 5e7e72f..0000000
--- a/test/unit/DisplayObject.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObject');
-});
diff --git a/test/unit/DisplayObjectContainer.js b/test/unit/DisplayObjectContainer.js
deleted file mode 100644
index b323959..0000000
--- a/test/unit/DisplayObjectContainer.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObjectContainer');
-});
diff --git a/test/unit/InteractionManager.js b/test/unit/InteractionManager.js
deleted file mode 100644
index e751f52..0000000
--- a/test/unit/InteractionManager.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('InteractionManager');
-});
diff --git a/test/unit/MovieClip.js b/test/unit/MovieClip.js
deleted file mode 100644
index 37d9446..0000000
--- a/test/unit/MovieClip.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('MovieClip');
-});
diff --git a/test/unit/Pixi.js b/test/unit/Pixi.js
deleted file mode 100644
index 36eee73..0000000
--- a/test/unit/Pixi.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Pixi');
-});
diff --git a/test/unit/Point.js b/test/unit/Point.js
deleted file mode 100644
index 983ff6e..0000000
--- a/test/unit/Point.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Point');
-});
diff --git a/test/unit/Rectangle.js b/test/unit/Rectangle.js
deleted file mode 100644
index 3b439ba..0000000
--- a/test/unit/Rectangle.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Rectangle');
-});
diff --git a/test/unit/Sprite.js b/test/unit/Sprite.js
deleted file mode 100644
index ed4f596..0000000
--- a/test/unit/Sprite.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Sprite');
-});
diff --git a/test/unit/Stage.js b/test/unit/Stage.js
deleted file mode 100644
index 2d70291..0000000
--- a/test/unit/Stage.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Stage');
-});
diff --git a/test/unit/extras/Rope.js b/test/unit/extras/Rope.js
deleted file mode 100644
index 5606f14..0000000
--- a/test/unit/extras/Rope.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Rope');
-});
diff --git a/test/unit/extras/Strip.js b/test/unit/extras/Strip.js
deleted file mode 100644
index 0134d3a..0000000
--- a/test/unit/extras/Strip.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Strip');
-});
diff --git a/test/unit/loaders/AssetLoader.js b/test/unit/loaders/AssetLoader.js
deleted file mode 100644
index 13b8443..0000000
--- a/test/unit/loaders/AssetLoader.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('AssetLoader');
-});
diff --git a/test/unit/loaders/SpriteSheetLoader.js b/test/unit/loaders/SpriteSheetLoader.js
deleted file mode 100644
index 8bf0cb2..0000000
--- a/test/unit/loaders/SpriteSheetLoader.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('SpriteSheetLoader');
-});
diff --git a/test/unit/pixi/InteractionManager.js b/test/unit/pixi/InteractionManager.js
new file mode 100644
index 0000000..ed3001f
--- /dev/null
+++ b/test/unit/pixi/InteractionManager.js
@@ -0,0 +1,10 @@
+describe('pixi/InteractionManager', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var InteractionManager = PIXI.InteractionManager;
+
+ it('Module exists', function () {
+ expect(InteractionManager).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/Pixi.js b/test/unit/pixi/Pixi.js
new file mode 100644
index 0000000..27debc1
--- /dev/null
+++ b/test/unit/pixi/Pixi.js
@@ -0,0 +1,9 @@
+describe('pixi/Pixi', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+
+ it('Module exists', function () {
+ expect(global).to.have.property('PIXI').and.to.be.an('object');
+ });
+});
diff --git a/test/unit/pixi/core/Circle.js b/test/unit/pixi/core/Circle.js
new file mode 100644
index 0000000..93a4456
--- /dev/null
+++ b/test/unit/pixi/core/Circle.js
@@ -0,0 +1,22 @@
+describe('pixi/core/Circle', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Circle = PIXI.Circle;
+
+ it('Module exists', function () {
+ expect(Circle).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Circle();
+
+ expect(obj).to.be.an.instanceof(Circle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', 0);
+ expect(obj).to.have.property('y', 0);
+ expect(obj).to.have.property('radius', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Ellipse.js b/test/unit/pixi/core/Ellipse.js
new file mode 100644
index 0000000..026b56f
--- /dev/null
+++ b/test/unit/pixi/core/Ellipse.js
@@ -0,0 +1,24 @@
+describe('pixi/core/Ellipse', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Ellipse = PIXI.Ellipse;
+
+ it('Module exists', function () {
+ expect(Ellipse).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Ellipse();
+
+ expect(obj).to.be.an.instanceof(Ellipse);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+ expect(obj).to.respondTo('getBounds');
+
+ expect(obj).to.have.property('x', 0);
+ expect(obj).to.have.property('y', 0);
+ expect(obj).to.have.property('width', 0);
+ expect(obj).to.have.property('height', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Matrix.js b/test/unit/pixi/core/Matrix.js
new file mode 100644
index 0000000..b48989e
--- /dev/null
+++ b/test/unit/pixi/core/Matrix.js
@@ -0,0 +1,30 @@
+describe('pixi/core/Matrix', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var mat3 = PIXI.mat3;
+ var mat4 = PIXI.mat4;
+ var Matrix = PIXI.Matrix;
+
+ it('Ensure determineMatrixArrayType works', function () {
+ expect(Matrix).to.be.a('function');
+ });
+
+ it('mat3 exists', function () {
+ expect(mat3).to.be.an('object');
+ });
+
+ it('Confirm new mat3 matrix', function () {
+ var matrix = new mat3.create();
+ pixi_core_Matrix_confirmNewMat3(matrix);
+ });
+
+ it('mat3 exists', function () {
+ expect(mat4).to.be.an('object');
+ });
+
+ it('Confirm new mat4 matrix', function () {
+ var matrix = new mat4.create();
+ pixi_core_Matrix_confirmNewMat4(matrix);
+ });
+});
diff --git a/test/unit/pixi/core/Point.js b/test/unit/pixi/core/Point.js
new file mode 100644
index 0000000..c4d5163
--- /dev/null
+++ b/test/unit/pixi/core/Point.js
@@ -0,0 +1,15 @@
+describe('pixi/core/Point', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Point = PIXI.Point;
+
+ it('Module exists', function () {
+ expect(Point).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Point();
+ pixi_core_Point_confirm(obj, 0, 0);
+ });
+});
diff --git a/test/unit/pixi/core/Polygon.js b/test/unit/pixi/core/Polygon.js
new file mode 100644
index 0000000..dc8c918
--- /dev/null
+++ b/test/unit/pixi/core/Polygon.js
@@ -0,0 +1,20 @@
+describe('pixi/core/Polygon', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Polygon = PIXI.Polygon;
+
+ it('Module exists', function () {
+ expect(Polygon).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Polygon();
+
+ expect(obj).to.be.an.instanceof(Polygon);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.deep.property('points.length', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Rectangle.js b/test/unit/pixi/core/Rectangle.js
new file mode 100644
index 0000000..d43316e
--- /dev/null
+++ b/test/unit/pixi/core/Rectangle.js
@@ -0,0 +1,15 @@
+describe('pixi/core/Rectangle', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Rectangle = PIXI.Rectangle;
+
+ it('Module exists', function () {
+ expect(Rectangle).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var rect = new Rectangle();
+ pixi_core_Rectangle_confirm(rect, 0, 0, 0, 0);
+ });
+});
diff --git a/test/unit/pixi/display/DisplayObject.js b/test/unit/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..40c6fbc
--- /dev/null
+++ b/test/unit/pixi/display/DisplayObject.js
@@ -0,0 +1,21 @@
+describe('pixi/display/DisplayObject', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var DisplayObject = PIXI.DisplayObject;
+
+ it('Module exists', function () {
+ expect(DisplayObject).to.be.a('function');
+ expect(PIXI).to.have.property('visibleCount', 0);
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new DisplayObject();
+
+ pixi_display_DisplayObject_confirmNew(obj);
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', false);
+ expect(obj).to.have.property('stage', null);
+ });
+});
diff --git a/test/unit/pixi/display/DisplayObjectContainer.js b/test/unit/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..ce7f02f
--- /dev/null
+++ b/test/unit/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,20 @@
+describe('pixi/display/DisplayObjectContainer', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var DisplayObjectContainer = PIXI.DisplayObjectContainer;
+
+ it('Module exists', function () {
+ expect(DisplayObjectContainer).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new DisplayObjectContainer();
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', false);
+ expect(obj).to.have.property('stage', null);
+ });
+});
diff --git a/test/unit/pixi/display/MovieClip.js b/test/unit/pixi/display/MovieClip.js
new file mode 100644
index 0000000..f3c6c6a
--- /dev/null
+++ b/test/unit/pixi/display/MovieClip.js
@@ -0,0 +1,33 @@
+describe('pixi/display/MovieClip', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var MovieClip = PIXI.MovieClip;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(MovieClip).to.be.a('function');
+ });
+
+ it('Confirm new instance', function (done) {
+ var texture = Texture.fromImage('/base/test/textures/SpriteSheet-Explosion.png');
+ var obj = new MovieClip([texture]);
+
+ pixi_display_Sprite_confirmNew(obj, done);
+
+ expect(obj).to.be.an.instanceof(MovieClip);
+ expect(obj).to.respondTo('stop');
+ expect(obj).to.respondTo('play');
+ expect(obj).to.respondTo('gotoAndStop');
+ expect(obj).to.respondTo('gotoAndPlay');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('textures.length', 1);
+ expect(obj).to.have.deep.property('textures[0]', texture);
+ expect(obj).to.have.property('animationSpeed', 1);
+ expect(obj).to.have.property('loop', true);
+ expect(obj).to.have.property('onComplete', null);
+ expect(obj).to.have.property('currentFrame', 0);
+ expect(obj).to.have.property('playing', false);
+ });
+});
diff --git a/test/unit/pixi/display/Sprite.js b/test/unit/pixi/display/Sprite.js
new file mode 100644
index 0000000..54e914f
--- /dev/null
+++ b/test/unit/pixi/display/Sprite.js
@@ -0,0 +1,25 @@
+describe('pixi/display/Sprite', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Sprite = PIXI.Sprite;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(Sprite).to.be.a('function');
+ expect(PIXI).to.have.deep.property('blendModes.NORMAL', 0);
+ expect(PIXI).to.have.deep.property('blendModes.SCREEN', 1);
+ });
+
+ it('Members exist', function () {
+ expect(Sprite).itself.to.respondTo('fromImage');
+ expect(Sprite).itself.to.respondTo('fromFrame');
+ });
+
+ it('Confirm new instance', function (done) {
+ var texture = Texture.fromImage('/base/test/textures/SpriteSheet-Aliens.png');
+ var obj = new Sprite(texture);
+
+ pixi_display_Sprite_confirmNew(obj, done);
+ });
+});
diff --git a/test/unit/pixi/display/Stage.js b/test/unit/pixi/display/Stage.js
new file mode 100644
index 0000000..3cc2a4d
--- /dev/null
+++ b/test/unit/pixi/display/Stage.js
@@ -0,0 +1,49 @@
+describe('pixi/display/Stage', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Stage = PIXI.Stage;
+ var InteractionManager = PIXI.InteractionManager;
+ var Rectangle = PIXI.Rectangle;
+
+ it('Module exists', function () {
+ expect(Stage).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Stage(null, true);
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(Stage);
+ expect(obj).to.respondTo('updateTransform');
+ expect(obj).to.respondTo('setBackgroundColor');
+ expect(obj).to.respondTo('getMousePosition');
+
+ // FIXME: duplicate member in DisplayObject
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ // FIXME: convert arg to bool in constructor
+ expect(obj).to.have.property('interactive', true);
+
+ expect(obj).to.have.property('interactionManager')
+ .and.to.be.an.instanceof(InteractionManager)
+ .and.to.have.property('stage', obj);
+
+ expect(obj).to.have.property('dirty', true);
+
+ expect(obj).to.have.property('stage', obj);
+
+ expect(obj).to.have.property('hitArea')
+ .and.to.be.an.instanceof(Rectangle);
+ pixi_core_Rectangle_confirm(obj.hitArea, 0, 0, 100000, 100000);
+
+ expect(obj).to.have.property('backgroundColor', 0x000000);
+ expect(obj).to.have.deep.property('backgroundColorSplit.length', 3);
+ expect(obj).to.have.deep.property('backgroundColorSplit[0]', 0);
+ expect(obj).to.have.deep.property('backgroundColorSplit[1]', 0);
+ expect(obj).to.have.deep.property('backgroundColorSplit[2]', 0);
+ expect(obj).to.have.property('backgroundColorString', '#000000');
+
+ expect(obj).to.have.property('worldVisible', true);
+ });
+});
diff --git a/test/unit/pixi/extras/CustomRenderable.js b/test/unit/pixi/extras/CustomRenderable.js
new file mode 100644
index 0000000..8d83cf0
--- /dev/null
+++ b/test/unit/pixi/extras/CustomRenderable.js
@@ -0,0 +1,21 @@
+describe('pixi/extras/CustomRenderable', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var CustomRenderable = PIXI.CustomRenderable;
+
+ it('Module exists', function () {
+ expect(CustomRenderable).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new CustomRenderable();
+
+ pixi_display_DisplayObject_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(CustomRenderable);
+ expect(obj).to.respondTo('renderCanvas');
+ expect(obj).to.respondTo('initWebGL');
+ expect(obj).to.respondTo('renderWebGL');
+ });
+});
diff --git a/test/unit/pixi/extras/Rope.js b/test/unit/pixi/extras/Rope.js
new file mode 100644
index 0000000..6ddaf83
--- /dev/null
+++ b/test/unit/pixi/extras/Rope.js
@@ -0,0 +1,26 @@
+describe('pixi/extras/Rope', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Rope = PIXI.Rope;
+ var Texture = PIXI.Texture;
+ var Point = PIXI.Point;
+
+ it('Module exists', function () {
+ expect(Rope).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var texture = Texture.fromImage('/base/test/textures/bunny.png');
+ var obj = new Rope(texture, [new Point(), new Point(5, 10), new Point(10, 20)]);
+
+ pixi_extras_Strip_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(Rope);
+ expect(obj).to.respondTo('refresh');
+ expect(obj).to.respondTo('updateTransform');
+ expect(obj).to.respondTo('setTexture');
+
+ // TODO: Test properties
+ });
+});
diff --git a/test/unit/pixi/extras/Spine.js b/test/unit/pixi/extras/Spine.js
new file mode 100644
index 0000000..0708bc0
--- /dev/null
+++ b/test/unit/pixi/extras/Spine.js
@@ -0,0 +1,10 @@
+describe('pixi/extras/Spine', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Spine = PIXI.Spine;
+
+ it('Module exists', function () {
+ expect(Spine).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/extras/Strip.js b/test/unit/pixi/extras/Strip.js
new file mode 100644
index 0000000..8e564e1
--- /dev/null
+++ b/test/unit/pixi/extras/Strip.js
@@ -0,0 +1,18 @@
+describe('pixi/extras/Strip', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Strip = PIXI.Strip;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(Strip).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var texture = Texture.fromImage('/base/test/textures/bunny.png');
+ var obj = new Strip(texture, 20, 10000);
+
+ pixi_extras_Strip_confirmNew(obj);
+ });
+});
diff --git a/test/unit/pixi/extras/TilingSprite.js b/test/unit/pixi/extras/TilingSprite.js
new file mode 100644
index 0000000..56aea14
--- /dev/null
+++ b/test/unit/pixi/extras/TilingSprite.js
@@ -0,0 +1,24 @@
+describe('pixi/extras/TilingSprite', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var TilingSprite = PIXI.TilingSprite;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(TilingSprite).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var texture = Texture.fromImage('/base/test/textures/bunny.png');
+ var obj = new TilingSprite(texture, 6000, 12000);
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(TilingSprite);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ // TODO: Test properties
+ });
+});
diff --git a/.gitignore b/.gitignore
index 12e1b62..0b88317 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
node_modules
.DS_Store
-.project
\ No newline at end of file
+.project
+*.log
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..63e4d7c
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,8 @@
+language: node_js
+node_js:
+ - 0.10
+
+before_script:
+ - npm install -g grunt-cli
+ - export DISPLAY=:99.0
+ - sh -e /etc/init.d/xvfb start
diff --git a/Gruntfile.js b/Gruntfile.js
index b083b49..103938c 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -1,10 +1,12 @@
+'use strict';
+
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-connect');
- grunt.loadNpmTasks('grunt-contrib-qunit');
grunt.loadNpmTasks('grunt-contrib-yuidoc');
+ grunt.loadTasks('tasks');
var root = 'src/pixi/',
debug = 'bin/pixi.dev.js',
@@ -79,7 +81,7 @@
},
files: {
srcBlob: '<%= dirs.src %>/**/*.js',
- testBlob: '<%= dirs.test %>/unit/**/*.js',
+ testBlob: '<%= dirs.test %>/{functional,lib/pixi,unit}/**/*.js',
build: '<%= dirs.build %>/pixi.dev.js',
buildMin: '<%= dirs.build %>/pixi.js'
},
@@ -94,7 +96,12 @@
},
jshint: {
beforeconcat: srcFiles,
- test: ['<%= files.testBlob %>'],
+ test: {
+ src: ['<%= files.testBlob %>'],
+ options: {
+ expr: true
+ }
+ },
options: {
asi: true,
smarttabs: true
@@ -128,12 +135,6 @@
]
},
connect: {
- qunit: {
- options: {
- port: grunt.option('port-test') || 9002,
- base: './'
- }
- },
test: {
options: {
port: grunt.option('port-test') || 9002,
@@ -142,13 +143,6 @@
}
}
},
- qunit: {
- all: {
- options: {
- urls: ['http://localhost:' + (grunt.option('port-test') || 9002) + '/test/index.html']
- }
- }
- },
yuidoc: {
compile: {
name: '<%= pkg.name %>',
@@ -161,6 +155,13 @@
outdir: '<%= dirs.docs %>'
}
}
+ },
+ karma: {
+ unit: {
+ configFile: 'test/karma.conf.js',
+ // browsers: ['Chrome'],
+ singleRun: true
+ }
}
});
@@ -182,9 +183,10 @@
}
)
- grunt.registerTask('default', ['concat', 'uglify', 'distribute']);
grunt.registerTask('build', ['concat', 'uglify', 'distribute']);
- grunt.registerTask('test', ['build', 'connect:qunit', 'qunit']);
+ grunt.registerTask('test', ['concat', 'jshint:test', 'karma']);
grunt.registerTask('docs', ['yuidoc']);
-
-}
\ No newline at end of file
+ grunt.registerTask('default', ['test', 'uglify', 'distribute']);
+ // Travis CI task.
+ grunt.registerTask('travis', ['test']);
+}
diff --git a/README.md b/README.md
index c62ef86..690cfe4 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,8 @@

+[](http://travis-ci.org/drkibitz/pixi.js)
+
#### JavaScript 2D Renderer ####
The aim of this project is to provide a fast lightweight 2D library that works
diff --git a/package.json b/package.json
index b373240..1246a68 100644
--- a/package.json
+++ b/package.json
@@ -18,14 +18,21 @@
"main": "bin/pixi.js",
+ "scripts": {
+ "test": "grunt travis --verbose"
+ },
+
"dependencies": {},
"devDependencies": {
"grunt": "~0.4.x",
- "grunt-contrib-jshint": "0.3.x",
+ "grunt-contrib-jshint": "0.6.x",
"grunt-contrib-uglify": "0.2.x",
- "grunt-contrib-connect": "0.2.x",
- "grunt-contrib-qunit": "0.2.x",
+ "grunt-contrib-connect": "0.3.x",
"grunt-contrib-yuidoc": "0.4.x",
- "grunt-contrib-concat": "0.1.x"
+ "grunt-contrib-concat": "0.3.x",
+ "chai": "~1.7.0",
+ "karma": "0.11.0",
+ "karma-firefox-launcher": "0.1.0",
+ "karma-mocha": "0.1.0"
}
}
diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js
index a7c520e..ee82bbd 100644
--- a/src/pixi/InteractionManager.js
+++ b/src/pixi/InteractionManager.js
@@ -62,7 +62,6 @@
this.onTouchEnd = this.onTouchEnd.bind(this);
this.onTouchMove = this.onTouchMove.bind(this);
-
this.last = 0;
}
diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js
index 1a95d20..eef1059 100644
--- a/src/pixi/core/Ellipse.js
+++ b/src/pixi/core/Ellipse.js
@@ -78,7 +78,7 @@
return (normx + normy < 0.25);
}
-PIXI.Ellipse.getBounds = function()
+PIXI.Ellipse.prototype.getBounds = function()
{
return new PIXI.Rectangle(this.x, this.y, this.width, this.height);
}
diff --git a/tasks/karma.js b/tasks/karma.js
new file mode 100644
index 0000000..c340485
--- /dev/null
+++ b/tasks/karma.js
@@ -0,0 +1,27 @@
+'use strict';
+
+var path = require('path');
+var server = require('karma').server;
+
+module.exports = function (grunt) {
+ grunt.registerMultiTask('karma', 'run karma.', function() {
+ var done = this.async();
+ var options = this.options({
+ background: false
+ });
+ var data = this.data;
+
+ //merge options onto data, with data taking precedence
+ data = grunt.util._.merge(options, data);
+ data.configFile = path.resolve(data.configFile);
+ if (data.configFile) {
+ data.configFile = grunt.template.process(data.configFile);
+ }
+
+ server.start(
+ data,
+ function(code) {
+ done(!code);
+ });
+ });
+};
diff --git a/test/functional/example-1-basics/bunny.png b/test/functional/example-1-basics/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/functional/example-1-basics/bunny.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-30.png b/test/functional/example-1-basics/frame-30.png
new file mode 100644
index 0000000..96e3409
--- /dev/null
+++ b/test/functional/example-1-basics/frame-30.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-60.png b/test/functional/example-1-basics/frame-60.png
new file mode 100644
index 0000000..af3f4ce
--- /dev/null
+++ b/test/functional/example-1-basics/frame-60.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-90.png b/test/functional/example-1-basics/frame-90.png
new file mode 100644
index 0000000..099b823
--- /dev/null
+++ b/test/functional/example-1-basics/frame-90.png
Binary files differ
diff --git a/test/functional/example-1-basics/index.js b/test/functional/example-1-basics/index.js
new file mode 100644
index 0000000..7ae7a98
--- /dev/null
+++ b/test/functional/example-1-basics/index.js
@@ -0,0 +1,133 @@
+describe('Example 1 - Basics', function () {
+ 'use strict';
+
+ var baseUri = '/base/test/functional/example-1-basics';
+ var expect = chai.expect;
+ var currentFrame = 0;
+ var frameEvents = {};
+ var stage;
+ var renderer;
+ var bunny;
+
+ function onFrame(frame, callback) {
+ frameEvents[frame] = callback;
+ }
+
+ function animate() {
+ currentFrame += 1;
+
+ requestAnimFrame( animate );
+
+ // just for fun, lets rotate mr rabbit a little
+ bunny.rotation += 0.1;
+
+ // render the stage
+ renderer.render(stage);
+
+ if (frameEvents[currentFrame])
+ frameEvents[currentFrame](currentFrame);
+ }
+
+ function initScene() {
+ // create an new instance of a pixi stage
+ stage = new PIXI.Stage(0x66FF99);
+
+ // create a renderer instance
+ renderer = PIXI.autoDetectRenderer(400, 300);
+ console.log('Is PIXI.WebGLRenderer: ' + (renderer instanceof PIXI.WebGLRenderer));
+
+ // add the renderer view element to the DOM
+ document.body.appendChild(renderer.view);
+
+ requestAnimFrame( animate );
+
+ // create a texture from an image path
+ var texture = PIXI.Texture.fromImage(baseUri + "/bunny.png");
+ // create a new Sprite using the texture
+ bunny = new PIXI.Sprite(texture);
+
+ // center the sprites anchor point
+ bunny.anchor.x = 0.5;
+ bunny.anchor.y = 0.5;
+
+ // move the sprite t the center of the screen
+ bunny.position.x = 200;
+ bunny.position.y = 150;
+
+ stage.addChild(bunny);
+ }
+
+ it('assets loaded', function (done) {
+ var loader = new PIXI.AssetLoader([
+ baseUri + '/bunny.png',
+ baseUri + '/frame-30.png',
+ baseUri + '/frame-60.png',
+ baseUri + '/frame-90.png'
+ ]);
+ // loader.on('onProgress', function (event) {
+ // console.log(event.content);
+ // });
+ loader.on('onComplete', function (event) {
+ done();
+ initScene();
+ });
+ loader.load();
+ });
+
+ it('frame 30 should match', function (done) {
+ this.timeout(700);
+ onFrame(30, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-30.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 60 should match', function (done) {
+ this.timeout(1200);
+ onFrame(60, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-60.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 90 should match', function (done) {
+ this.timeout(1700);
+ onFrame(90, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-90.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ // it('capture something', function (done) {
+ // this.timeout(2000000);
+ // onFrame(30, function () {
+ // var img = new Image();
+ // img.src = renderer.view.toDataURL('image/png');
+ // document.body.appendChild(img);
+ // });
+ // });
+});
diff --git a/test/index.html b/test/index.html
deleted file mode 100644
index 9cbcac5..0000000
--- a/test/index.html
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
- Pixi.js Test Suite
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/test/karma.conf.js b/test/karma.conf.js
new file mode 100644
index 0000000..c66a696
--- /dev/null
+++ b/test/karma.conf.js
@@ -0,0 +1,82 @@
+module.exports = function(config) {
+ config.set({
+
+ // base path, that will be used to resolve files and exclude
+ basePath : '../',
+
+ frameworks : ['mocha'],
+
+ // list of files / patterns to load in the browser
+ files : [
+ 'node_modules/chai/chai.js',
+ 'bin/pixi.dev.js',
+ 'test/lib/**/*.js',
+ 'test/unit/**/*.js',
+ // 'test/functional/**/*.js',
+ {pattern: 'test/**/*.png', watched: false, included: false, served: true}
+ ],
+
+ // list of files to exclude
+ exclude : [],
+
+ // use dolts reporter, as travis terminal does not support escaping sequences
+ // possible values: 'dots', 'progress', 'junit', 'teamcity'
+ // CLI --reporters progress
+ reporters : ['progress'],
+
+ // web server port
+ // CLI --port 9876
+ port : 9876,
+
+ // cli runner port
+ // CLI --runner-port 9100
+ runnerPort : 9100,
+
+ // enable / disable colors in the output (reporters and logs)
+ // CLI --colors --no-colors
+ colors : true,
+
+ // level of logging
+ // possible values: karma.LOG_DISABLE || karma.LOG_ERROR || karma.LOG_WARN || karma.LOG_INFO || karma.LOG_DEBUG
+ // CLI --log-level debug
+ logLevel : config.LOG_DEBUG,
+
+ // enable / disable watching file and executing tests whenever any file changes
+ // CLI --auto-watch --no-auto-watch
+ autoWatch : false,
+
+ // Start these browsers, currently available:
+ // - Chrome
+ // - ChromeCanary
+ // - Firefox
+ // - Opera
+ // - Safari (only Mac)
+ // - PhantomJS
+ // - IE (only Windows)
+ // CLI --browsers Chrome,Firefox,Safari
+ browsers : ['Firefox'],
+
+ // If browser does not capture in given timeout [ms], kill it
+ // CLI --capture-timeout 5000
+ captureTimeout : 5000,
+
+ // Auto run tests on start (when browsers are captured) and exit
+ // CLI --single-run --no-single-run
+ singleRun : true,
+
+ // report which specs are slower than 500ms
+ // CLI --report-slower-than 500
+ reportSlowerThan : 1000,
+
+ preprocessors : {
+ // '**/client/js/*.js': 'coverage'
+ },
+
+ plugins : [
+ 'karma-mocha',
+ // 'karma-chrome-launcher',
+ 'karma-firefox-launcher',
+ // 'karma-phantomjs-launcher'
+ ]
+ });
+};
diff --git a/test/lib/pixi/core/Matrix.js b/test/lib/pixi/core/Matrix.js
new file mode 100644
index 0000000..d26386b
--- /dev/null
+++ b/test/lib/pixi/core/Matrix.js
@@ -0,0 +1,40 @@
+
+function pixi_core_Matrix_confirmNewMat3(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(1);
+ expect(matrix[5]).to.equal(0);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(1);
+}
+
+function pixi_core_Matrix_confirmNewMat4(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[0]).to.equal(1);
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(0);
+ expect(matrix[5]).to.equal(1);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(0);
+ expect(matrix[9]).to.equal(0);
+ expect(matrix[10]).to.equal(1);
+ expect(matrix[11]).to.equal(0);
+ expect(matrix[12]).to.equal(0);
+ expect(matrix[13]).to.equal(0);
+ expect(matrix[14]).to.equal(0);
+ expect(matrix[15]).to.equal(1);
+}
diff --git a/test/lib/pixi/core/Point.js b/test/lib/pixi/core/Point.js
new file mode 100644
index 0000000..e5df07b
--- /dev/null
+++ b/test/lib/pixi/core/Point.js
@@ -0,0 +1,10 @@
+
+function pixi_core_Point_confirm(obj, x, y) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Point);
+ expect(obj).to.respondTo('clone');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+}
diff --git a/test/lib/pixi/core/Rectangle.js b/test/lib/pixi/core/Rectangle.js
new file mode 100644
index 0000000..23f0d12
--- /dev/null
+++ b/test/lib/pixi/core/Rectangle.js
@@ -0,0 +1,13 @@
+
+function pixi_core_Rectangle_confirm(obj, x, y, width, height) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Rectangle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+ expect(obj).to.have.property('width', width);
+ expect(obj).to.have.property('height', height);
+}
diff --git a/test/lib/pixi/display/DisplayObject.js b/test/lib/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..1388a7f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObject.js
@@ -0,0 +1,43 @@
+
+function pixi_display_DisplayObject_confirmNew(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObject);
+ expect(obj).to.respondTo('setInteractive');
+ expect(obj).to.respondTo('addFilter');
+ expect(obj).to.respondTo('removeFilter');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.property('last', obj);
+ expect(obj).to.have.property('first', obj);
+
+ expect(obj).to.contain.property('position');
+ pixi_core_Point_confirm(obj.position, 0, 0);
+ expect(obj).to.contain.property('scale');
+ pixi_core_Point_confirm(obj.scale, 1, 1);
+ expect(obj).to.contain.property('pivot');
+ pixi_core_Point_confirm(obj.pivot, 0, 0);
+
+ expect(obj).to.have.property('rotation', 0);
+ expect(obj).to.have.property('alpha', 1);
+ expect(obj).to.have.property('visible', true);
+ expect(obj).to.have.property('buttonMode', false);
+ expect(obj).to.have.property('parent', null);
+ expect(obj).to.have.property('worldAlpha', 1);
+
+ expect(obj).to.have.property('hitArea');
+ expect(obj).to.have.property('interactive'); // TODO: Have a better default value
+ expect('mask' in obj).to.be.true; // TODO: Have a better default value
+ expect(obj.mask).to.be.undefined;
+
+ expect(obj).to.have.property('renderable');
+ expect(obj).to.have.property('stage');
+
+ expect(obj).to.have.deep.property('worldTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ expect(obj).to.have.deep.property('localTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.localTransform);
+
+ expect(obj).to.have.deep.property('color.length', 0);
+ expect(obj).to.have.property('dynamic', true);
+}
diff --git a/test/lib/pixi/display/DisplayObjectContainer.js b/test/lib/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..085c59f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,16 @@
+
+function pixi_display_DisplayObjectContainer_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObject_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObjectContainer);
+ expect(obj).to.respondTo('addChild');
+ expect(obj).to.respondTo('addChildAt');
+ expect(obj).to.respondTo('swapChildren');
+ expect(obj).to.respondTo('getChildAt');
+ expect(obj).to.respondTo('removeChild');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('children.length', 0);
+}
diff --git a/test/lib/pixi/display/Sprite.js b/test/lib/pixi/display/Sprite.js
new file mode 100644
index 0000000..cc7a2d6
--- /dev/null
+++ b/test/lib/pixi/display/Sprite.js
@@ -0,0 +1,28 @@
+
+function pixi_display_Sprite_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Sprite);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', true);
+ expect(obj).to.have.property('stage', null);
+
+ expect(obj).to.have.property('anchor');
+ pixi_core_Point_confirm(obj.anchor, 0, 0);
+
+ expect(obj).to.have.property('blendMode', PIXI.blendModes.NORMAL);
+ expect(obj).to.have.property('width', 1); // TODO: is 1 expected
+ expect(obj).to.have.property('height', 1); // TODO: is 1 expected
+
+ // FIXME: Just make this a boolean that is always there
+ expect(!!obj.updateFrame).to.equal(obj.texture.baseTexture.hasLoaded);
+
+ expect(obj).to.have.property('texture');
+ pixi_textures_Texture_confirmNew(obj.texture, done);
+}
diff --git a/test/lib/pixi/extras/Strip.js b/test/lib/pixi/extras/Strip.js
new file mode 100644
index 0000000..8927a8a
--- /dev/null
+++ b/test/lib/pixi/extras/Strip.js
@@ -0,0 +1,12 @@
+
+function pixi_extras_Strip_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Strip);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ // TODO: Test properties
+}
diff --git a/test/lib/pixi/textures/Texture.js b/test/lib/pixi/textures/Texture.js
new file mode 100644
index 0000000..d5867b6
--- /dev/null
+++ b/test/lib/pixi/textures/Texture.js
@@ -0,0 +1,31 @@
+
+function pixi_textures_Texture_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ function confirmFrameDone() {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, obj.baseTexture.width, obj.baseTexture.height);
+
+ expect(obj).to.have.property('width', obj.baseTexture.width);
+ expect(obj).to.have.property('height', obj.baseTexture.height);
+ done();
+ }
+
+ expect(obj).to.be.an.instanceof(PIXI.Texture);
+ pixi_utils_EventTarget_like(obj);
+
+ expect(obj).to.have.property('baseTexture')
+ .and.to.be.an.instanceof(PIXI.BaseTexture);
+
+ expect(obj).to.have.property('scope', obj);
+
+ expect(obj).to.have.property('trim');
+ pixi_core_Point_confirm(obj.trim, 0, 0);
+
+ expect(obj).to.have.property('frame');
+ if (obj.baseTexture.hasLoaded) {
+ confirmFrameDone();
+ } else {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, 1, 1);
+ obj.addEventListener('update', confirmFrameDone);
+ }
+}
diff --git a/test/lib/pixi/utils/EventTarget.js b/test/lib/pixi/utils/EventTarget.js
new file mode 100644
index 0000000..7b1dcfa
--- /dev/null
+++ b/test/lib/pixi/utils/EventTarget.js
@@ -0,0 +1,8 @@
+
+function pixi_utils_EventTarget_like(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.respondTo('addEventListener');
+ expect(obj).to.respondTo('dispatchEvent');
+ expect(obj).to.respondTo('removeEventListener');
+}
diff --git a/test/lib/qunit-1.11.0.css b/test/lib/qunit-1.11.0.css
deleted file mode 100644
index d7fc0c8..0000000
--- a/test/lib/qunit-1.11.0.css
+++ /dev/null
@@ -1,244 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-/** Font Family and Sizes */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
- font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
-}
-
-#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
-#qunit-tests { font-size: smaller; }
-
-
-/** Resets */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter {
- margin: 0;
- padding: 0;
-}
-
-
-/** Header */
-
-#qunit-header {
- padding: 0.5em 0 0.5em 1em;
-
- color: #8699a4;
- background-color: #0d3349;
-
- font-size: 1.5em;
- line-height: 1em;
- font-weight: normal;
-
- border-radius: 5px 5px 0 0;
- -moz-border-radius: 5px 5px 0 0;
- -webkit-border-top-right-radius: 5px;
- -webkit-border-top-left-radius: 5px;
-}
-
-#qunit-header a {
- text-decoration: none;
- color: #c2ccd1;
-}
-
-#qunit-header a:hover,
-#qunit-header a:focus {
- color: #fff;
-}
-
-#qunit-testrunner-toolbar label {
- display: inline-block;
- padding: 0 .5em 0 .1em;
-}
-
-#qunit-banner {
- height: 5px;
-}
-
-#qunit-testrunner-toolbar {
- padding: 0.5em 0 0.5em 2em;
- color: #5E740B;
- background-color: #eee;
- overflow: hidden;
-}
-
-#qunit-userAgent {
- padding: 0.5em 0 0.5em 2.5em;
- background-color: #2b81af;
- color: #fff;
- text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
-}
-
-#qunit-modulefilter-container {
- float: right;
-}
-
-/** Tests: Pass/Fail */
-
-#qunit-tests {
- list-style-position: inside;
-}
-
-#qunit-tests li {
- padding: 0.4em 0.5em 0.4em 2.5em;
- border-bottom: 1px solid #fff;
- list-style-position: inside;
-}
-
-#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running {
- display: none;
-}
-
-#qunit-tests li strong {
- cursor: pointer;
-}
-
-#qunit-tests li a {
- padding: 0.5em;
- color: #c2ccd1;
- text-decoration: none;
-}
-#qunit-tests li a:hover,
-#qunit-tests li a:focus {
- color: #000;
-}
-
-#qunit-tests li .runtime {
- float: right;
- font-size: smaller;
-}
-
-.qunit-assert-list {
- margin-top: 0.5em;
- padding: 0.5em;
-
- background-color: #fff;
-
- border-radius: 5px;
- -moz-border-radius: 5px;
- -webkit-border-radius: 5px;
-}
-
-.qunit-collapsed {
- display: none;
-}
-
-#qunit-tests table {
- border-collapse: collapse;
- margin-top: .2em;
-}
-
-#qunit-tests th {
- text-align: right;
- vertical-align: top;
- padding: 0 .5em 0 0;
-}
-
-#qunit-tests td {
- vertical-align: top;
-}
-
-#qunit-tests pre {
- margin: 0;
- white-space: pre-wrap;
- word-wrap: break-word;
-}
-
-#qunit-tests del {
- background-color: #e0f2be;
- color: #374e0c;
- text-decoration: none;
-}
-
-#qunit-tests ins {
- background-color: #ffcaca;
- color: #500;
- text-decoration: none;
-}
-
-/*** Test Counts */
-
-#qunit-tests b.counts { color: black; }
-#qunit-tests b.passed { color: #5E740B; }
-#qunit-tests b.failed { color: #710909; }
-
-#qunit-tests li li {
- padding: 5px;
- background-color: #fff;
- border-bottom: none;
- list-style-position: inside;
-}
-
-/*** Passing Styles */
-
-#qunit-tests li li.pass {
- color: #3c510c;
- background-color: #fff;
- border-left: 10px solid #C6E746;
-}
-
-#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
-#qunit-tests .pass .test-name { color: #366097; }
-
-#qunit-tests .pass .test-actual,
-#qunit-tests .pass .test-expected { color: #999999; }
-
-#qunit-banner.qunit-pass { background-color: #C6E746; }
-
-/*** Failing Styles */
-
-#qunit-tests li li.fail {
- color: #710909;
- background-color: #fff;
- border-left: 10px solid #EE5757;
- white-space: pre;
-}
-
-#qunit-tests > li:last-child {
- border-radius: 0 0 5px 5px;
- -moz-border-radius: 0 0 5px 5px;
- -webkit-border-bottom-right-radius: 5px;
- -webkit-border-bottom-left-radius: 5px;
-}
-
-#qunit-tests .fail { color: #000000; background-color: #EE5757; }
-#qunit-tests .fail .test-name,
-#qunit-tests .fail .module-name { color: #000000; }
-
-#qunit-tests .fail .test-actual { color: #EE5757; }
-#qunit-tests .fail .test-expected { color: green; }
-
-#qunit-banner.qunit-fail { background-color: #EE5757; }
-
-
-/** Result */
-
-#qunit-testresult {
- padding: 0.5em 0.5em 0.5em 2.5em;
-
- color: #2b81af;
- background-color: #D2E0E6;
-
- border-bottom: 1px solid white;
-}
-#qunit-testresult .module-name {
- font-weight: bold;
-}
-
-/** Fixture */
-
-#qunit-fixture {
- position: absolute;
- top: -10000px;
- left: -10000px;
- width: 1000px;
- height: 1000px;
-}
diff --git a/test/lib/qunit-1.11.0.js b/test/lib/qunit-1.11.0.js
deleted file mode 100644
index 302545f..0000000
--- a/test/lib/qunit-1.11.0.js
+++ /dev/null
@@ -1,2152 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-(function( window ) {
-
-var QUnit,
- assert,
- config,
- onErrorFnPrev,
- testId = 0,
- fileName = (sourceFromStacktrace( 0 ) || "" ).replace(/(:\d+)+\)?/, "").replace(/.+\//, ""),
- toString = Object.prototype.toString,
- hasOwn = Object.prototype.hasOwnProperty,
- // Keep a local reference to Date (GH-283)
- Date = window.Date,
- defined = {
- setTimeout: typeof window.setTimeout !== "undefined",
- sessionStorage: (function() {
- var x = "qunit-test-string";
- try {
- sessionStorage.setItem( x, x );
- sessionStorage.removeItem( x );
- return true;
- } catch( e ) {
- return false;
- }
- }())
- },
- /**
- * Provides a normalized error string, correcting an issue
- * with IE 7 (and prior) where Error.prototype.toString is
- * not properly implemented
- *
- * Based on http://es5.github.com/#x15.11.4.4
- *
- * @param {String|Error} error
- * @return {String} error message
- */
- errorString = function( error ) {
- var name, message,
- errorString = error.toString();
- if ( errorString.substring( 0, 7 ) === "[object" ) {
- name = error.name ? error.name.toString() : "Error";
- message = error.message ? error.message.toString() : "";
- if ( name && message ) {
- return name + ": " + message;
- } else if ( name ) {
- return name;
- } else if ( message ) {
- return message;
- } else {
- return "Error";
- }
- } else {
- return errorString;
- }
- },
- /**
- * Makes a clone of an object using only Array or Object as base,
- * and copies over the own enumerable properties.
- *
- * @param {Object} obj
- * @return {Object} New object with only the own properties (recursively).
- */
- objectValues = function( obj ) {
- // Grunt 0.3.x uses an older version of jshint that still has jshint/jshint#392.
- /*jshint newcap: false */
- var key, val,
- vals = QUnit.is( "array", obj ) ? [] : {};
- for ( key in obj ) {
- if ( hasOwn.call( obj, key ) ) {
- val = obj[key];
- vals[key] = val === Object(val) ? objectValues(val) : val;
- }
- }
- return vals;
- };
-
-function Test( settings ) {
- extend( this, settings );
- this.assertions = [];
- this.testNumber = ++Test.count;
-}
-
-Test.count = 0;
-
-Test.prototype = {
- init: function() {
- var a, b, li,
- tests = id( "qunit-tests" );
-
- if ( tests ) {
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml;
-
- // `a` initialized at top of scope
- a = document.createElement( "a" );
- a.innerHTML = "Rerun";
- a.href = QUnit.url({ testNumber: this.testNumber });
-
- li = document.createElement( "li" );
- li.appendChild( b );
- li.appendChild( a );
- li.className = "running";
- li.id = this.id = "qunit-test-output" + testId++;
-
- tests.appendChild( li );
- }
- },
- setup: function() {
- if ( this.module !== config.previousModule ) {
- if ( config.previousModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.previousModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
- config.previousModule = this.module;
- config.moduleStats = { all: 0, bad: 0 };
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- } else if ( config.autorun ) {
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- }
-
- config.current = this;
-
- this.testEnvironment = extend({
- setup: function() {},
- teardown: function() {}
- }, this.moduleTestEnvironment );
-
- this.started = +new Date();
- runLoggingCallbacks( "testStart", QUnit, {
- name: this.testName,
- module: this.module
- });
-
- // allow utility functions to access the current test environment
- // TODO why??
- QUnit.current_testEnvironment = this.testEnvironment;
-
- if ( !config.pollution ) {
- saveGlobal();
- }
- if ( config.notrycatch ) {
- this.testEnvironment.setup.call( this.testEnvironment );
- return;
- }
- try {
- this.testEnvironment.setup.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Setup failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- },
- run: function() {
- config.current = this;
-
- var running = id( "qunit-testresult" );
-
- if ( running ) {
- running.innerHTML = "Running:
" + this.nameHtml;
- }
-
- if ( this.async ) {
- QUnit.stop();
- }
-
- this.callbackStarted = +new Date();
-
- if ( config.notrycatch ) {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- return;
- }
-
- try {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- } catch( e ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
-
- QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + " " + this.stack + ": " + ( e.message || e ), extractStacktrace( e, 0 ) );
- // else next test will carry the responsibility
- saveGlobal();
-
- // Restart the tests if they're blocking
- if ( config.blocking ) {
- QUnit.start();
- }
- }
- },
- teardown: function() {
- config.current = this;
- if ( config.notrycatch ) {
- if ( typeof this.callbackRuntime === "undefined" ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
- }
- this.testEnvironment.teardown.call( this.testEnvironment );
- return;
- } else {
- try {
- this.testEnvironment.teardown.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Teardown failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- }
- checkPollution();
- },
- finish: function() {
- config.current = this;
- if ( config.requireExpects && this.expected === null ) {
- QUnit.pushFailure( "Expected number of assertions to be defined, but expect() was not called.", this.stack );
- } else if ( this.expected !== null && this.expected !== this.assertions.length ) {
- QUnit.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack );
- } else if ( this.expected === null && !this.assertions.length ) {
- QUnit.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions.", this.stack );
- }
-
- var i, assertion, a, b, time, li, ol,
- test = this,
- good = 0,
- bad = 0,
- tests = id( "qunit-tests" );
-
- this.runtime = +new Date() - this.started;
- config.stats.all += this.assertions.length;
- config.moduleStats.all += this.assertions.length;
-
- if ( tests ) {
- ol = document.createElement( "ol" );
- ol.className = "qunit-assert-list";
-
- for ( i = 0; i < this.assertions.length; i++ ) {
- assertion = this.assertions[i];
-
- li = document.createElement( "li" );
- li.className = assertion.result ? "pass" : "fail";
- li.innerHTML = assertion.message || ( assertion.result ? "okay" : "failed" );
- ol.appendChild( li );
-
- if ( assertion.result ) {
- good++;
- } else {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
-
- // store result when possible
- if ( QUnit.config.reorder && defined.sessionStorage ) {
- if ( bad ) {
- sessionStorage.setItem( "qunit-test-" + this.module + "-" + this.testName, bad );
- } else {
- sessionStorage.removeItem( "qunit-test-" + this.module + "-" + this.testName );
- }
- }
-
- if ( bad === 0 ) {
- addClass( ol, "qunit-collapsed" );
- }
-
- // `b` initialized at top of scope
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml + " (" + bad + ", " + good + ", " + this.assertions.length + ")";
-
- addEvent(b, "click", function() {
- var next = b.parentNode.lastChild,
- collapsed = hasClass( next, "qunit-collapsed" );
- ( collapsed ? removeClass : addClass )( next, "qunit-collapsed" );
- });
-
- addEvent(b, "dblclick", function( e ) {
- var target = e && e.target ? e.target : window.event.srcElement;
- if ( target.nodeName.toLowerCase() === "span" || target.nodeName.toLowerCase() === "b" ) {
- target = target.parentNode;
- }
- if ( window.location && target.nodeName.toLowerCase() === "strong" ) {
- window.location = QUnit.url({ testNumber: test.testNumber });
- }
- });
-
- // `time` initialized at top of scope
- time = document.createElement( "span" );
- time.className = "runtime";
- time.innerHTML = this.runtime + " ms";
-
- // `li` initialized at top of scope
- li = id( this.id );
- li.className = bad ? "fail" : "pass";
- li.removeChild( li.firstChild );
- a = li.firstChild;
- li.appendChild( b );
- li.appendChild( a );
- li.appendChild( time );
- li.appendChild( ol );
-
- } else {
- for ( i = 0; i < this.assertions.length; i++ ) {
- if ( !this.assertions[i].result ) {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
- }
-
- runLoggingCallbacks( "testDone", QUnit, {
- name: this.testName,
- module: this.module,
- failed: bad,
- passed: this.assertions.length - bad,
- total: this.assertions.length,
- duration: this.runtime
- });
-
- QUnit.reset();
-
- config.current = undefined;
- },
-
- queue: function() {
- var bad,
- test = this;
-
- synchronize(function() {
- test.init();
- });
- function run() {
- // each of these can by async
- synchronize(function() {
- test.setup();
- });
- synchronize(function() {
- test.run();
- });
- synchronize(function() {
- test.teardown();
- });
- synchronize(function() {
- test.finish();
- });
- }
-
- // `bad` initialized at top of scope
- // defer when previous test run passed, if storage is available
- bad = QUnit.config.reorder && defined.sessionStorage &&
- +sessionStorage.getItem( "qunit-test-" + this.module + "-" + this.testName );
-
- if ( bad ) {
- run();
- } else {
- synchronize( run, true );
- }
- }
-};
-
-// Root QUnit object.
-// `QUnit` initialized at top of scope
-QUnit = {
-
- // call on start of module test to prepend name to all tests
- module: function( name, testEnvironment ) {
- config.currentModule = name;
- config.currentModuleTestEnvironment = testEnvironment;
- config.modules[name] = true;
- },
-
- asyncTest: function( testName, expected, callback ) {
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- QUnit.test( testName, expected, callback, true );
- },
-
- test: function( testName, expected, callback, async ) {
- var test,
- nameHtml = "" + escapeText( testName ) + "";
-
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- if ( config.currentModule ) {
- nameHtml = "" + escapeText( config.currentModule ) + ": " + nameHtml;
- }
-
- test = new Test({
- nameHtml: nameHtml,
- testName: testName,
- expected: expected,
- async: async,
- callback: callback,
- module: config.currentModule,
- moduleTestEnvironment: config.currentModuleTestEnvironment,
- stack: sourceFromStacktrace( 2 )
- });
-
- if ( !validTest( test ) ) {
- return;
- }
-
- test.queue();
- },
-
- // Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through.
- expect: function( asserts ) {
- if (arguments.length === 1) {
- config.current.expected = asserts;
- } else {
- return config.current.expected;
- }
- },
-
- start: function( count ) {
- // QUnit hasn't been initialized yet.
- // Note: RequireJS (et al) may delay onLoad
- if ( config.semaphore === undefined ) {
- QUnit.begin(function() {
- // This is triggered at the top of QUnit.load, push start() to the event loop, to allow QUnit.load to finish first
- setTimeout(function() {
- QUnit.start( count );
- });
- });
- return;
- }
-
- config.semaphore -= count || 1;
- // don't start until equal number of stop-calls
- if ( config.semaphore > 0 ) {
- return;
- }
- // ignore if start is called more often then stop
- if ( config.semaphore < 0 ) {
- config.semaphore = 0;
- QUnit.pushFailure( "Called start() while already started (QUnit.config.semaphore was 0 already)", null, sourceFromStacktrace(2) );
- return;
- }
- // A slight delay, to avoid any current callbacks
- if ( defined.setTimeout ) {
- window.setTimeout(function() {
- if ( config.semaphore > 0 ) {
- return;
- }
- if ( config.timeout ) {
- clearTimeout( config.timeout );
- }
-
- config.blocking = false;
- process( true );
- }, 13);
- } else {
- config.blocking = false;
- process( true );
- }
- },
-
- stop: function( count ) {
- config.semaphore += count || 1;
- config.blocking = true;
-
- if ( config.testTimeout && defined.setTimeout ) {
- clearTimeout( config.timeout );
- config.timeout = window.setTimeout(function() {
- QUnit.ok( false, "Test timed out" );
- config.semaphore = 1;
- QUnit.start();
- }, config.testTimeout );
- }
- }
-};
-
-// `assert` initialized at top of scope
-// Asssert helpers
-// All of these must either call QUnit.push() or manually do:
-// - runLoggingCallbacks( "log", .. );
-// - config.current.assertions.push({ .. });
-// We attach it to the QUnit object *after* we expose the public API,
-// otherwise `assert` will become a global variable in browsers (#341).
-assert = {
- /**
- * Asserts rough true-ish result.
- * @name ok
- * @function
- * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" );
- */
- ok: function( result, msg ) {
- if ( !config.current ) {
- throw new Error( "ok() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
- result = !!result;
-
- var source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: msg
- };
-
- msg = escapeText( msg || (result ? "okay" : "failed" ) );
- msg = "" + msg + "";
-
- if ( !result ) {
- source = sourceFromStacktrace( 2 );
- if ( source ) {
- details.source = source;
- msg += "Source: | " + escapeText( source ) + " |
---|
";
- }
- }
- runLoggingCallbacks( "log", QUnit, details );
- config.current.assertions.push({
- result: result,
- message: msg
- });
- },
-
- /**
- * Assert that the first two arguments are equal, with an optional message.
- * Prints out both actual and expected values.
- * @name equal
- * @function
- * @example equal( format( "Received {0} bytes.", 2), "Received 2 bytes.", "format() replaces {0} with next argument" );
- */
- equal: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected == actual, actual, expected, message );
- },
-
- /**
- * @name notEqual
- * @function
- */
- notEqual: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected != actual, actual, expected, message );
- },
-
- /**
- * @name propEqual
- * @function
- */
- propEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notPropEqual
- * @function
- */
- notPropEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name deepEqual
- * @function
- */
- deepEqual: function( actual, expected, message ) {
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notDeepEqual
- * @function
- */
- notDeepEqual: function( actual, expected, message ) {
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name strictEqual
- * @function
- */
- strictEqual: function( actual, expected, message ) {
- QUnit.push( expected === actual, actual, expected, message );
- },
-
- /**
- * @name notStrictEqual
- * @function
- */
- notStrictEqual: function( actual, expected, message ) {
- QUnit.push( expected !== actual, actual, expected, message );
- },
-
- "throws": function( block, expected, message ) {
- var actual,
- expectedOutput = expected,
- ok = false;
-
- // 'expected' is optional
- if ( typeof expected === "string" ) {
- message = expected;
- expected = null;
- }
-
- config.current.ignoreGlobalErrors = true;
- try {
- block.call( config.current.testEnvironment );
- } catch (e) {
- actual = e;
- }
- config.current.ignoreGlobalErrors = false;
-
- if ( actual ) {
- // we don't want to validate thrown error
- if ( !expected ) {
- ok = true;
- expectedOutput = null;
- // expected is a regexp
- } else if ( QUnit.objectType( expected ) === "regexp" ) {
- ok = expected.test( errorString( actual ) );
- // expected is a constructor
- } else if ( actual instanceof expected ) {
- ok = true;
- // expected is a validation function which returns true is validation passed
- } else if ( expected.call( {}, actual ) === true ) {
- expectedOutput = null;
- ok = true;
- }
-
- QUnit.push( ok, actual, expectedOutput, message );
- } else {
- QUnit.pushFailure( message, null, 'No exception was thrown.' );
- }
- }
-};
-
-/**
- * @deprecate since 1.8.0
- * Kept assertion helpers in root for backwards compatibility.
- */
-extend( QUnit, assert );
-
-/**
- * @deprecated since 1.9.0
- * Kept root "raises()" for backwards compatibility.
- * (Note that we don't introduce assert.raises).
- */
-QUnit.raises = assert[ "throws" ];
-
-/**
- * @deprecated since 1.0.0, replaced with error pushes since 1.3.0
- * Kept to avoid TypeErrors for undefined methods.
- */
-QUnit.equals = function() {
- QUnit.push( false, false, false, "QUnit.equals has been deprecated since 2009 (e88049a0), use QUnit.equal instead" );
-};
-QUnit.same = function() {
- QUnit.push( false, false, false, "QUnit.same has been deprecated since 2009 (e88049a0), use QUnit.deepEqual instead" );
-};
-
-// We want access to the constructor's prototype
-(function() {
- function F() {}
- F.prototype = QUnit;
- QUnit = new F();
- // Make F QUnit's constructor so that we can add to the prototype later
- QUnit.constructor = F;
-}());
-
-/**
- * Config object: Maintain internal state
- * Later exposed as QUnit.config
- * `config` initialized at top of scope
- */
-config = {
- // The queue of tests to run
- queue: [],
-
- // block until document ready
- blocking: true,
-
- // when enabled, show only failing tests
- // gets persisted through sessionStorage and can be changed in UI via checkbox
- hidepassed: false,
-
- // by default, run previously failed tests first
- // very useful in combination with "Hide passed tests" checked
- reorder: true,
-
- // by default, modify document.title when suite is done
- altertitle: true,
-
- // when enabled, all tests must call expect()
- requireExpects: false,
-
- // add checkboxes that are persisted in the query-string
- // when enabled, the id is set to `true` as a `QUnit.config` property
- urlConfig: [
- {
- id: "noglobals",
- label: "Check for Globals",
- tooltip: "Enabling this will test if any test introduces new properties on the `window` object. Stored as query-strings."
- },
- {
- id: "notrycatch",
- label: "No try-catch",
- tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging exceptions in IE reasonable. Stored as query-strings."
- }
- ],
-
- // Set of all modules.
- modules: {},
-
- // logging callback queues
- begin: [],
- done: [],
- log: [],
- testStart: [],
- testDone: [],
- moduleStart: [],
- moduleDone: []
-};
-
-// Export global variables, unless an 'exports' object exists,
-// in that case we assume we're in CommonJS (dealt with on the bottom of the script)
-if ( typeof exports === "undefined" ) {
- extend( window, QUnit );
-
- // Expose QUnit object
- window.QUnit = QUnit;
-}
-
-// Initialize more QUnit.config and QUnit.urlParams
-(function() {
- var i,
- location = window.location || { search: "", protocol: "file:" },
- params = location.search.slice( 1 ).split( "&" ),
- length = params.length,
- urlParams = {},
- current;
-
- if ( params[ 0 ] ) {
- for ( i = 0; i < length; i++ ) {
- current = params[ i ].split( "=" );
- current[ 0 ] = decodeURIComponent( current[ 0 ] );
- // allow just a key to turn on a flag, e.g., test.html?noglobals
- current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true;
- urlParams[ current[ 0 ] ] = current[ 1 ];
- }
- }
-
- QUnit.urlParams = urlParams;
-
- // String search anywhere in moduleName+testName
- config.filter = urlParams.filter;
-
- // Exact match of the module name
- config.module = urlParams.module;
-
- config.testNumber = parseInt( urlParams.testNumber, 10 ) || null;
-
- // Figure out if we're running the tests from a server or not
- QUnit.isLocal = location.protocol === "file:";
-}());
-
-// Extend QUnit object,
-// these after set here because they should not be exposed as global functions
-extend( QUnit, {
- assert: assert,
-
- config: config,
-
- // Initialize the configuration options
- init: function() {
- extend( config, {
- stats: { all: 0, bad: 0 },
- moduleStats: { all: 0, bad: 0 },
- started: +new Date(),
- updateRate: 1000,
- blocking: false,
- autostart: true,
- autorun: false,
- filter: "",
- queue: [],
- semaphore: 1
- });
-
- var tests, banner, result,
- qunit = id( "qunit" );
-
- if ( qunit ) {
- qunit.innerHTML =
- "" +
- "" +
- "" +
- "" +
- "
";
- }
-
- tests = id( "qunit-tests" );
- banner = id( "qunit-banner" );
- result = id( "qunit-testresult" );
-
- if ( tests ) {
- tests.innerHTML = "";
- }
-
- if ( banner ) {
- banner.className = "";
- }
-
- if ( result ) {
- result.parentNode.removeChild( result );
- }
-
- if ( tests ) {
- result = document.createElement( "p" );
- result.id = "qunit-testresult";
- result.className = "result";
- tests.parentNode.insertBefore( result, tests );
- result.innerHTML = "Running...
";
- }
- },
-
- // Resets the test setup. Useful for tests that modify the DOM.
- reset: function() {
- var fixture = id( "qunit-fixture" );
- if ( fixture ) {
- fixture.innerHTML = config.fixture;
- }
- },
-
- // Trigger an event on an element.
- // @example triggerEvent( document.body, "click" );
- triggerEvent: function( elem, type, event ) {
- if ( document.createEvent ) {
- event = document.createEvent( "MouseEvents" );
- event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView,
- 0, 0, 0, 0, 0, false, false, false, false, 0, null);
-
- elem.dispatchEvent( event );
- } else if ( elem.fireEvent ) {
- elem.fireEvent( "on" + type );
- }
- },
-
- // Safe object type checking
- is: function( type, obj ) {
- return QUnit.objectType( obj ) === type;
- },
-
- objectType: function( obj ) {
- if ( typeof obj === "undefined" ) {
- return "undefined";
- // consider: typeof null === object
- }
- if ( obj === null ) {
- return "null";
- }
-
- var match = toString.call( obj ).match(/^\[object\s(.*)\]$/),
- type = match && match[1] || "";
-
- switch ( type ) {
- case "Number":
- if ( isNaN(obj) ) {
- return "nan";
- }
- return "number";
- case "String":
- case "Boolean":
- case "Array":
- case "Date":
- case "RegExp":
- case "Function":
- return type.toLowerCase();
- }
- if ( typeof obj === "object" ) {
- return "object";
- }
- return undefined;
- },
-
- push: function( result, actual, expected, message ) {
- if ( !config.current ) {
- throw new Error( "assertion outside test context, was " + sourceFromStacktrace() );
- }
-
- var output, source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: message,
- actual: actual,
- expected: expected
- };
-
- message = escapeText( message ) || ( result ? "okay" : "failed" );
- message = "" + message + "";
- output = message;
-
- if ( !result ) {
- expected = escapeText( QUnit.jsDump.parse(expected) );
- actual = escapeText( QUnit.jsDump.parse(actual) );
- output += "Expected: | " + expected + " |
";
-
- if ( actual !== expected ) {
- output += "Result: | " + actual + " |
";
- output += "Diff: | " + QUnit.diff( expected, actual ) + " |
";
- }
-
- source = sourceFromStacktrace();
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
- }
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: !!result,
- message: output
- });
- },
-
- pushFailure: function( message, source, actual ) {
- if ( !config.current ) {
- throw new Error( "pushFailure() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
-
- var output,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: false,
- message: message
- };
-
- message = escapeText( message ) || "error";
- message = "" + message + "";
- output = message;
-
- output += "";
-
- if ( actual ) {
- output += "Result: | " + escapeText( actual ) + " |
";
- }
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: false,
- message: output
- });
- },
-
- url: function( params ) {
- params = extend( extend( {}, QUnit.urlParams ), params );
- var key,
- querystring = "?";
-
- for ( key in params ) {
- if ( !hasOwn.call( params, key ) ) {
- continue;
- }
- querystring += encodeURIComponent( key ) + "=" +
- encodeURIComponent( params[ key ] ) + "&";
- }
- return window.location.protocol + "//" + window.location.host +
- window.location.pathname + querystring.slice( 0, -1 );
- },
-
- extend: extend,
- id: id,
- addEvent: addEvent
- // load, equiv, jsDump, diff: Attached later
-});
-
-/**
- * @deprecated: Created for backwards compatibility with test runner that set the hook function
- * into QUnit.{hook}, instead of invoking it and passing the hook function.
- * QUnit.constructor is set to the empty F() above so that we can add to it's prototype here.
- * Doing this allows us to tell if the following methods have been overwritten on the actual
- * QUnit object.
- */
-extend( QUnit.constructor.prototype, {
-
- // Logging callbacks; all receive a single argument with the listed properties
- // run test/logs.html for any related changes
- begin: registerLoggingCallback( "begin" ),
-
- // done: { failed, passed, total, runtime }
- done: registerLoggingCallback( "done" ),
-
- // log: { result, actual, expected, message }
- log: registerLoggingCallback( "log" ),
-
- // testStart: { name }
- testStart: registerLoggingCallback( "testStart" ),
-
- // testDone: { name, failed, passed, total, duration }
- testDone: registerLoggingCallback( "testDone" ),
-
- // moduleStart: { name }
- moduleStart: registerLoggingCallback( "moduleStart" ),
-
- // moduleDone: { name, failed, passed, total }
- moduleDone: registerLoggingCallback( "moduleDone" )
-});
-
-if ( typeof document === "undefined" || document.readyState === "complete" ) {
- config.autorun = true;
-}
-
-QUnit.load = function() {
- runLoggingCallbacks( "begin", QUnit, {} );
-
- // Initialize the config, saving the execution queue
- var banner, filter, i, label, len, main, ol, toolbar, userAgent, val,
- urlConfigCheckboxesContainer, urlConfigCheckboxes, moduleFilter,
- numModules = 0,
- moduleFilterHtml = "",
- urlConfigHtml = "",
- oldconfig = extend( {}, config );
-
- QUnit.init();
- extend(config, oldconfig);
-
- config.blocking = false;
-
- len = config.urlConfig.length;
-
- for ( i = 0; i < len; i++ ) {
- val = config.urlConfig[i];
- if ( typeof val === "string" ) {
- val = {
- id: val,
- label: val,
- tooltip: "[no tooltip available]"
- };
- }
- config[ val.id ] = QUnit.urlParams[ val.id ];
- urlConfigHtml += "";
- }
-
- moduleFilterHtml += "";
-
- // `userAgent` initialized at top of scope
- userAgent = id( "qunit-userAgent" );
- if ( userAgent ) {
- userAgent.innerHTML = navigator.userAgent;
- }
-
- // `banner` initialized at top of scope
- banner = id( "qunit-header" );
- if ( banner ) {
- banner.innerHTML = "" + banner.innerHTML + " ";
- }
-
- // `toolbar` initialized at top of scope
- toolbar = id( "qunit-testrunner-toolbar" );
- if ( toolbar ) {
- // `filter` initialized at top of scope
- filter = document.createElement( "input" );
- filter.type = "checkbox";
- filter.id = "qunit-filter-pass";
-
- addEvent( filter, "click", function() {
- var tmp,
- ol = document.getElementById( "qunit-tests" );
-
- if ( filter.checked ) {
- ol.className = ol.className + " hidepass";
- } else {
- tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " ";
- ol.className = tmp.replace( / hidepass /, " " );
- }
- if ( defined.sessionStorage ) {
- if (filter.checked) {
- sessionStorage.setItem( "qunit-filter-passed-tests", "true" );
- } else {
- sessionStorage.removeItem( "qunit-filter-passed-tests" );
- }
- }
- });
-
- if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem( "qunit-filter-passed-tests" ) ) {
- filter.checked = true;
- // `ol` initialized at top of scope
- ol = document.getElementById( "qunit-tests" );
- ol.className = ol.className + " hidepass";
- }
- toolbar.appendChild( filter );
-
- // `label` initialized at top of scope
- label = document.createElement( "label" );
- label.setAttribute( "for", "qunit-filter-pass" );
- label.setAttribute( "title", "Only show tests and assertons that fail. Stored in sessionStorage." );
- label.innerHTML = "Hide passed tests";
- toolbar.appendChild( label );
-
- urlConfigCheckboxesContainer = document.createElement("span");
- urlConfigCheckboxesContainer.innerHTML = urlConfigHtml;
- urlConfigCheckboxes = urlConfigCheckboxesContainer.getElementsByTagName("input");
- // For oldIE support:
- // * Add handlers to the individual elements instead of the container
- // * Use "click" instead of "change"
- // * Fallback from event.target to event.srcElement
- addEvents( urlConfigCheckboxes, "click", function( event ) {
- var params = {},
- target = event.target || event.srcElement;
- params[ target.name ] = target.checked ? true : undefined;
- window.location = QUnit.url( params );
- });
- toolbar.appendChild( urlConfigCheckboxesContainer );
-
- if (numModules > 1) {
- moduleFilter = document.createElement( 'span' );
- moduleFilter.setAttribute( 'id', 'qunit-modulefilter-container' );
- moduleFilter.innerHTML = moduleFilterHtml;
- addEvent( moduleFilter.lastChild, "change", function() {
- var selectBox = moduleFilter.getElementsByTagName("select")[0],
- selectedModule = decodeURIComponent(selectBox.options[selectBox.selectedIndex].value);
-
- window.location = QUnit.url( { module: ( selectedModule === "" ) ? undefined : selectedModule } );
- });
- toolbar.appendChild(moduleFilter);
- }
- }
-
- // `main` initialized at top of scope
- main = id( "qunit-fixture" );
- if ( main ) {
- config.fixture = main.innerHTML;
- }
-
- if ( config.autostart ) {
- QUnit.start();
- }
-};
-
-addEvent( window, "load", QUnit.load );
-
-// `onErrorFnPrev` initialized at top of scope
-// Preserve other handlers
-onErrorFnPrev = window.onerror;
-
-// Cover uncaught exceptions
-// Returning true will surpress the default browser handler,
-// returning false will let it run.
-window.onerror = function ( error, filePath, linerNr ) {
- var ret = false;
- if ( onErrorFnPrev ) {
- ret = onErrorFnPrev( error, filePath, linerNr );
- }
-
- // Treat return value as window.onerror itself does,
- // Only do our handling if not surpressed.
- if ( ret !== true ) {
- if ( QUnit.config.current ) {
- if ( QUnit.config.current.ignoreGlobalErrors ) {
- return true;
- }
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- } else {
- QUnit.test( "global failure", extend( function() {
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- }, { validTest: validTest } ) );
- }
- return false;
- }
-
- return ret;
-};
-
-function done() {
- config.autorun = true;
-
- // Log the last module results
- if ( config.currentModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.currentModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
-
- var i, key,
- banner = id( "qunit-banner" ),
- tests = id( "qunit-tests" ),
- runtime = +new Date() - config.started,
- passed = config.stats.all - config.stats.bad,
- html = [
- "Tests completed in ",
- runtime,
- " milliseconds.
",
- "",
- passed,
- " assertions of ",
- config.stats.all,
- " passed, ",
- config.stats.bad,
- " failed."
- ].join( "" );
-
- if ( banner ) {
- banner.className = ( config.stats.bad ? "qunit-fail" : "qunit-pass" );
- }
-
- if ( tests ) {
- id( "qunit-testresult" ).innerHTML = html;
- }
-
- if ( config.altertitle && typeof document !== "undefined" && document.title ) {
- // show ✖ for good, ✔ for bad suite result in title
- // use escape sequences in case file gets loaded with non-utf-8-charset
- document.title = [
- ( config.stats.bad ? "\u2716" : "\u2714" ),
- document.title.replace( /^[\u2714\u2716] /i, "" )
- ].join( " " );
- }
-
- // clear own sessionStorage items if all tests passed
- if ( config.reorder && defined.sessionStorage && config.stats.bad === 0 ) {
- // `key` & `i` initialized at top of scope
- for ( i = 0; i < sessionStorage.length; i++ ) {
- key = sessionStorage.key( i++ );
- if ( key.indexOf( "qunit-test-" ) === 0 ) {
- sessionStorage.removeItem( key );
- }
- }
- }
-
- // scroll back to top to show results
- if ( window.scrollTo ) {
- window.scrollTo(0, 0);
- }
-
- runLoggingCallbacks( "done", QUnit, {
- failed: config.stats.bad,
- passed: passed,
- total: config.stats.all,
- runtime: runtime
- });
-}
-
-/** @return Boolean: true if this test should be ran */
-function validTest( test ) {
- var include,
- filter = config.filter && config.filter.toLowerCase(),
- module = config.module && config.module.toLowerCase(),
- fullName = (test.module + ": " + test.testName).toLowerCase();
-
- // Internally-generated tests are always valid
- if ( test.callback && test.callback.validTest === validTest ) {
- delete test.callback.validTest;
- return true;
- }
-
- if ( config.testNumber ) {
- return test.testNumber === config.testNumber;
- }
-
- if ( module && ( !test.module || test.module.toLowerCase() !== module ) ) {
- return false;
- }
-
- if ( !filter ) {
- return true;
- }
-
- include = filter.charAt( 0 ) !== "!";
- if ( !include ) {
- filter = filter.slice( 1 );
- }
-
- // If the filter matches, we need to honour include
- if ( fullName.indexOf( filter ) !== -1 ) {
- return include;
- }
-
- // Otherwise, do the opposite
- return !include;
-}
-
-// so far supports only Firefox, Chrome and Opera (buggy), Safari (for real exceptions)
-// Later Safari and IE10 are supposed to support error.stack as well
-// See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack
-function extractStacktrace( e, offset ) {
- offset = offset === undefined ? 3 : offset;
-
- var stack, include, i;
-
- if ( e.stacktrace ) {
- // Opera
- return e.stacktrace.split( "\n" )[ offset + 3 ];
- } else if ( e.stack ) {
- // Firefox, Chrome
- stack = e.stack.split( "\n" );
- if (/^error$/i.test( stack[0] ) ) {
- stack.shift();
- }
- if ( fileName ) {
- include = [];
- for ( i = offset; i < stack.length; i++ ) {
- if ( stack[ i ].indexOf( fileName ) !== -1 ) {
- break;
- }
- include.push( stack[ i ] );
- }
- if ( include.length ) {
- return include.join( "\n" );
- }
- }
- return stack[ offset ];
- } else if ( e.sourceURL ) {
- // Safari, PhantomJS
- // hopefully one day Safari provides actual stacktraces
- // exclude useless self-reference for generated Error objects
- if ( /qunit.js$/.test( e.sourceURL ) ) {
- return;
- }
- // for actual exceptions, this is useful
- return e.sourceURL + ":" + e.line;
- }
-}
-function sourceFromStacktrace( offset ) {
- try {
- throw new Error();
- } catch ( e ) {
- return extractStacktrace( e, offset );
- }
-}
-
-/**
- * Escape text for attribute or text content.
- */
-function escapeText( s ) {
- if ( !s ) {
- return "";
- }
- s = s + "";
- // Both single quotes and double quotes (for attributes)
- return s.replace( /['"<>&]/g, function( s ) {
- switch( s ) {
- case '\'':
- return ''';
- case '"':
- return '"';
- case '<':
- return '<';
- case '>':
- return '>';
- case '&':
- return '&';
- }
- });
-}
-
-function synchronize( callback, last ) {
- config.queue.push( callback );
-
- if ( config.autorun && !config.blocking ) {
- process( last );
- }
-}
-
-function process( last ) {
- function next() {
- process( last );
- }
- var start = new Date().getTime();
- config.depth = config.depth ? config.depth + 1 : 1;
-
- while ( config.queue.length && !config.blocking ) {
- if ( !defined.setTimeout || config.updateRate <= 0 || ( ( new Date().getTime() - start ) < config.updateRate ) ) {
- config.queue.shift()();
- } else {
- window.setTimeout( next, 13 );
- break;
- }
- }
- config.depth--;
- if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) {
- done();
- }
-}
-
-function saveGlobal() {
- config.pollution = [];
-
- if ( config.noglobals ) {
- for ( var key in window ) {
- // in Opera sometimes DOM element ids show up here, ignore them
- if ( !hasOwn.call( window, key ) || /^qunit-test-output/.test( key ) ) {
- continue;
- }
- config.pollution.push( key );
- }
- }
-}
-
-function checkPollution() {
- var newGlobals,
- deletedGlobals,
- old = config.pollution;
-
- saveGlobal();
-
- newGlobals = diff( config.pollution, old );
- if ( newGlobals.length > 0 ) {
- QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join(", ") );
- }
-
- deletedGlobals = diff( old, config.pollution );
- if ( deletedGlobals.length > 0 ) {
- QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join(", ") );
- }
-}
-
-// returns a new Array with the elements that are in a but not in b
-function diff( a, b ) {
- var i, j,
- result = a.slice();
-
- for ( i = 0; i < result.length; i++ ) {
- for ( j = 0; j < b.length; j++ ) {
- if ( result[i] === b[j] ) {
- result.splice( i, 1 );
- i--;
- break;
- }
- }
- }
- return result;
-}
-
-function extend( a, b ) {
- for ( var prop in b ) {
- if ( b[ prop ] === undefined ) {
- delete a[ prop ];
-
- // Avoid "Member not found" error in IE8 caused by setting window.constructor
- } else if ( prop !== "constructor" || a !== window ) {
- a[ prop ] = b[ prop ];
- }
- }
-
- return a;
-}
-
-/**
- * @param {HTMLElement} elem
- * @param {string} type
- * @param {Function} fn
- */
-function addEvent( elem, type, fn ) {
- // Standards-based browsers
- if ( elem.addEventListener ) {
- elem.addEventListener( type, fn, false );
- // IE
- } else {
- elem.attachEvent( "on" + type, fn );
- }
-}
-
-/**
- * @param {Array|NodeList} elems
- * @param {string} type
- * @param {Function} fn
- */
-function addEvents( elems, type, fn ) {
- var i = elems.length;
- while ( i-- ) {
- addEvent( elems[i], type, fn );
- }
-}
-
-function hasClass( elem, name ) {
- return (" " + elem.className + " ").indexOf(" " + name + " ") > -1;
-}
-
-function addClass( elem, name ) {
- if ( !hasClass( elem, name ) ) {
- elem.className += (elem.className ? " " : "") + name;
- }
-}
-
-function removeClass( elem, name ) {
- var set = " " + elem.className + " ";
- // Class name may appear multiple times
- while ( set.indexOf(" " + name + " ") > -1 ) {
- set = set.replace(" " + name + " " , " ");
- }
- // If possible, trim it for prettiness, but not neccecarily
- elem.className = window.jQuery ? jQuery.trim( set ) : ( set.trim ? set.trim() : set );
-}
-
-function id( name ) {
- return !!( typeof document !== "undefined" && document && document.getElementById ) &&
- document.getElementById( name );
-}
-
-function registerLoggingCallback( key ) {
- return function( callback ) {
- config[key].push( callback );
- };
-}
-
-// Supports deprecated method of completely overwriting logging callbacks
-function runLoggingCallbacks( key, scope, args ) {
- var i, callbacks;
- if ( QUnit.hasOwnProperty( key ) ) {
- QUnit[ key ].call(scope, args );
- } else {
- callbacks = config[ key ];
- for ( i = 0; i < callbacks.length; i++ ) {
- callbacks[ i ].call( scope, args );
- }
- }
-}
-
-// Test for equality any JavaScript type.
-// Author: Philippe Rathé
-QUnit.equiv = (function() {
-
- // Call the o related callback with the given arguments.
- function bindCallbacks( o, callbacks, args ) {
- var prop = QUnit.objectType( o );
- if ( prop ) {
- if ( QUnit.objectType( callbacks[ prop ] ) === "function" ) {
- return callbacks[ prop ].apply( callbacks, args );
- } else {
- return callbacks[ prop ]; // or undefined
- }
- }
- }
-
- // the real equiv function
- var innerEquiv,
- // stack to decide between skip/abort functions
- callers = [],
- // stack to avoiding loops from circular referencing
- parents = [],
-
- getProto = Object.getPrototypeOf || function ( obj ) {
- return obj.__proto__;
- },
- callbacks = (function () {
-
- // for string, boolean, number and null
- function useStrictEquality( b, a ) {
- /*jshint eqeqeq:false */
- if ( b instanceof a.constructor || a instanceof b.constructor ) {
- // to catch short annotaion VS 'new' annotation of a
- // declaration
- // e.g. var i = 1;
- // var j = new Number(1);
- return a == b;
- } else {
- return a === b;
- }
- }
-
- return {
- "string": useStrictEquality,
- "boolean": useStrictEquality,
- "number": useStrictEquality,
- "null": useStrictEquality,
- "undefined": useStrictEquality,
-
- "nan": function( b ) {
- return isNaN( b );
- },
-
- "date": function( b, a ) {
- return QUnit.objectType( b ) === "date" && a.valueOf() === b.valueOf();
- },
-
- "regexp": function( b, a ) {
- return QUnit.objectType( b ) === "regexp" &&
- // the regex itself
- a.source === b.source &&
- // and its modifers
- a.global === b.global &&
- // (gmi) ...
- a.ignoreCase === b.ignoreCase &&
- a.multiline === b.multiline &&
- a.sticky === b.sticky;
- },
-
- // - skip when the property is a method of an instance (OOP)
- // - abort otherwise,
- // initial === would have catch identical references anyway
- "function": function() {
- var caller = callers[callers.length - 1];
- return caller !== Object && typeof caller !== "undefined";
- },
-
- "array": function( b, a ) {
- var i, j, len, loop;
-
- // b could be an object literal here
- if ( QUnit.objectType( b ) !== "array" ) {
- return false;
- }
-
- len = a.length;
- if ( len !== b.length ) {
- // safe and faster
- return false;
- }
-
- // track reference to avoid circular references
- parents.push( a );
- for ( i = 0; i < len; i++ ) {
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- loop = true;// dont rewalk array
- }
- }
- if ( !loop && !innerEquiv(a[i], b[i]) ) {
- parents.pop();
- return false;
- }
- }
- parents.pop();
- return true;
- },
-
- "object": function( b, a ) {
- var i, j, loop,
- // Default to true
- eq = true,
- aProperties = [],
- bProperties = [];
-
- // comparing constructors is more strict than using
- // instanceof
- if ( a.constructor !== b.constructor ) {
- // Allow objects with no prototype to be equivalent to
- // objects with Object as their constructor.
- if ( !(( getProto(a) === null && getProto(b) === Object.prototype ) ||
- ( getProto(b) === null && getProto(a) === Object.prototype ) ) ) {
- return false;
- }
- }
-
- // stack constructor before traversing properties
- callers.push( a.constructor );
- // track reference to avoid circular references
- parents.push( a );
-
- for ( i in a ) { // be strict: don't ensures hasOwnProperty
- // and go deep
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- // don't go down the same path twice
- loop = true;
- }
- }
- aProperties.push(i); // collect a's properties
-
- if (!loop && !innerEquiv( a[i], b[i] ) ) {
- eq = false;
- break;
- }
- }
-
- callers.pop(); // unstack, we are done
- parents.pop();
-
- for ( i in b ) {
- bProperties.push( i ); // collect b's properties
- }
-
- // Ensures identical properties name
- return eq && innerEquiv( aProperties.sort(), bProperties.sort() );
- }
- };
- }());
-
- innerEquiv = function() { // can take multiple arguments
- var args = [].slice.apply( arguments );
- if ( args.length < 2 ) {
- return true; // end transition
- }
-
- return (function( a, b ) {
- if ( a === b ) {
- return true; // catch the most you can
- } else if ( a === null || b === null || typeof a === "undefined" ||
- typeof b === "undefined" ||
- QUnit.objectType(a) !== QUnit.objectType(b) ) {
- return false; // don't lose time with error prone cases
- } else {
- return bindCallbacks(a, callbacks, [ b, a ]);
- }
-
- // apply transition with (1..n) arguments
- }( args[0], args[1] ) && arguments.callee.apply( this, args.splice(1, args.length - 1 )) );
- };
-
- return innerEquiv;
-}());
-
-/**
- * jsDump Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com |
- * http://flesler.blogspot.com Licensed under BSD
- * (http://www.opensource.org/licenses/bsd-license.php) Date: 5/15/2008
- *
- * @projectDescription Advanced and extensible data dumping for Javascript.
- * @version 1.0.0
- * @author Ariel Flesler
- * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html}
- */
-QUnit.jsDump = (function() {
- function quote( str ) {
- return '"' + str.toString().replace( /"/g, '\\"' ) + '"';
- }
- function literal( o ) {
- return o + "";
- }
- function join( pre, arr, post ) {
- var s = jsDump.separator(),
- base = jsDump.indent(),
- inner = jsDump.indent(1);
- if ( arr.join ) {
- arr = arr.join( "," + s + inner );
- }
- if ( !arr ) {
- return pre + post;
- }
- return [ pre, inner + arr, base + post ].join(s);
- }
- function array( arr, stack ) {
- var i = arr.length, ret = new Array(i);
- this.up();
- while ( i-- ) {
- ret[i] = this.parse( arr[i] , undefined , stack);
- }
- this.down();
- return join( "[", ret, "]" );
- }
-
- var reName = /^function (\w+)/,
- jsDump = {
- // type is used mostly internally, you can fix a (custom)type in advance
- parse: function( obj, type, stack ) {
- stack = stack || [ ];
- var inStack, res,
- parser = this.parsers[ type || this.typeOf(obj) ];
-
- type = typeof parser;
- inStack = inArray( obj, stack );
-
- if ( inStack !== -1 ) {
- return "recursion(" + (inStack - stack.length) + ")";
- }
- if ( type === "function" ) {
- stack.push( obj );
- res = parser.call( this, obj, stack );
- stack.pop();
- return res;
- }
- return ( type === "string" ) ? parser : this.parsers.error;
- },
- typeOf: function( obj ) {
- var type;
- if ( obj === null ) {
- type = "null";
- } else if ( typeof obj === "undefined" ) {
- type = "undefined";
- } else if ( QUnit.is( "regexp", obj) ) {
- type = "regexp";
- } else if ( QUnit.is( "date", obj) ) {
- type = "date";
- } else if ( QUnit.is( "function", obj) ) {
- type = "function";
- } else if ( typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined" ) {
- type = "window";
- } else if ( obj.nodeType === 9 ) {
- type = "document";
- } else if ( obj.nodeType ) {
- type = "node";
- } else if (
- // native arrays
- toString.call( obj ) === "[object Array]" ||
- // NodeList objects
- ( typeof obj.length === "number" && typeof obj.item !== "undefined" && ( obj.length ? obj.item(0) === obj[0] : ( obj.item( 0 ) === null && typeof obj[0] === "undefined" ) ) )
- ) {
- type = "array";
- } else if ( obj.constructor === Error.prototype.constructor ) {
- type = "error";
- } else {
- type = typeof obj;
- }
- return type;
- },
- separator: function() {
- return this.multiline ? this.HTML ? "
" : "\n" : this.HTML ? " " : " ";
- },
- // extra can be a number, shortcut for increasing-calling-decreasing
- indent: function( extra ) {
- if ( !this.multiline ) {
- return "";
- }
- var chr = this.indentChar;
- if ( this.HTML ) {
- chr = chr.replace( /\t/g, " " ).replace( / /g, " " );
- }
- return new Array( this._depth_ + (extra||0) ).join(chr);
- },
- up: function( a ) {
- this._depth_ += a || 1;
- },
- down: function( a ) {
- this._depth_ -= a || 1;
- },
- setParser: function( name, parser ) {
- this.parsers[name] = parser;
- },
- // The next 3 are exposed so you can use them
- quote: quote,
- literal: literal,
- join: join,
- //
- _depth_: 1,
- // This is the list of parsers, to modify them, use jsDump.setParser
- parsers: {
- window: "[Window]",
- document: "[Document]",
- error: function(error) {
- return "Error(\"" + error.message + "\")";
- },
- unknown: "[Unknown]",
- "null": "null",
- "undefined": "undefined",
- "function": function( fn ) {
- var ret = "function",
- // functions never have name in IE
- name = "name" in fn ? fn.name : (reName.exec(fn) || [])[1];
-
- if ( name ) {
- ret += " " + name;
- }
- ret += "( ";
-
- ret = [ ret, QUnit.jsDump.parse( fn, "functionArgs" ), "){" ].join( "" );
- return join( ret, QUnit.jsDump.parse(fn,"functionCode" ), "}" );
- },
- array: array,
- nodelist: array,
- "arguments": array,
- object: function( map, stack ) {
- var ret = [ ], keys, key, val, i;
- QUnit.jsDump.up();
- keys = [];
- for ( key in map ) {
- keys.push( key );
- }
- keys.sort();
- for ( i = 0; i < keys.length; i++ ) {
- key = keys[ i ];
- val = map[ key ];
- ret.push( QUnit.jsDump.parse( key, "key" ) + ": " + QUnit.jsDump.parse( val, undefined, stack ) );
- }
- QUnit.jsDump.down();
- return join( "{", ret, "}" );
- },
- node: function( node ) {
- var len, i, val,
- open = QUnit.jsDump.HTML ? "<" : "<",
- close = QUnit.jsDump.HTML ? ">" : ">",
- tag = node.nodeName.toLowerCase(),
- ret = open + tag,
- attrs = node.attributes;
-
- if ( attrs ) {
- for ( i = 0, len = attrs.length; i < len; i++ ) {
- val = attrs[i].nodeValue;
- // IE6 includes all attributes in .attributes, even ones not explicitly set.
- // Those have values like undefined, null, 0, false, "" or "inherit".
- if ( val && val !== "inherit" ) {
- ret += " " + attrs[i].nodeName + "=" + QUnit.jsDump.parse( val, "attribute" );
- }
- }
- }
- ret += close;
-
- // Show content of TextNode or CDATASection
- if ( node.nodeType === 3 || node.nodeType === 4 ) {
- ret += node.nodeValue;
- }
-
- return ret + open + "/" + tag + close;
- },
- // function calls it internally, it's the arguments part of the function
- functionArgs: function( fn ) {
- var args,
- l = fn.length;
-
- if ( !l ) {
- return "";
- }
-
- args = new Array(l);
- while ( l-- ) {
- // 97 is 'a'
- args[l] = String.fromCharCode(97+l);
- }
- return " " + args.join( ", " ) + " ";
- },
- // object calls it internally, the key part of an item in a map
- key: quote,
- // function calls it internally, it's the content of the function
- functionCode: "[code]",
- // node calls it internally, it's an html attribute value
- attribute: quote,
- string: quote,
- date: quote,
- regexp: literal,
- number: literal,
- "boolean": literal
- },
- // if true, entities are escaped ( <, >, \t, space and \n )
- HTML: false,
- // indentation unit
- indentChar: " ",
- // if true, items in a collection, are separated by a \n, else just a space.
- multiline: true
- };
-
- return jsDump;
-}());
-
-// from jquery.js
-function inArray( elem, array ) {
- if ( array.indexOf ) {
- return array.indexOf( elem );
- }
-
- for ( var i = 0, length = array.length; i < length; i++ ) {
- if ( array[ i ] === elem ) {
- return i;
- }
- }
-
- return -1;
-}
-
-/*
- * Javascript Diff Algorithm
- * By John Resig (http://ejohn.org/)
- * Modified by Chu Alan "sprite"
- *
- * Released under the MIT license.
- *
- * More Info:
- * http://ejohn.org/projects/javascript-diff-algorithm/
- *
- * Usage: QUnit.diff(expected, actual)
- *
- * QUnit.diff( "the quick brown fox jumped over", "the quick fox jumps over" ) == "the quick brown fox jumped jumps over"
- */
-QUnit.diff = (function() {
- /*jshint eqeqeq:false, eqnull:true */
- function diff( o, n ) {
- var i,
- ns = {},
- os = {};
-
- for ( i = 0; i < n.length; i++ ) {
- if ( !hasOwn.call( ns, n[i] ) ) {
- ns[ n[i] ] = {
- rows: [],
- o: null
- };
- }
- ns[ n[i] ].rows.push( i );
- }
-
- for ( i = 0; i < o.length; i++ ) {
- if ( !hasOwn.call( os, o[i] ) ) {
- os[ o[i] ] = {
- rows: [],
- n: null
- };
- }
- os[ o[i] ].rows.push( i );
- }
-
- for ( i in ns ) {
- if ( !hasOwn.call( ns, i ) ) {
- continue;
- }
- if ( ns[i].rows.length === 1 && hasOwn.call( os, i ) && os[i].rows.length === 1 ) {
- n[ ns[i].rows[0] ] = {
- text: n[ ns[i].rows[0] ],
- row: os[i].rows[0]
- };
- o[ os[i].rows[0] ] = {
- text: o[ os[i].rows[0] ],
- row: ns[i].rows[0]
- };
- }
- }
-
- for ( i = 0; i < n.length - 1; i++ ) {
- if ( n[i].text != null && n[ i + 1 ].text == null && n[i].row + 1 < o.length && o[ n[i].row + 1 ].text == null &&
- n[ i + 1 ] == o[ n[i].row + 1 ] ) {
-
- n[ i + 1 ] = {
- text: n[ i + 1 ],
- row: n[i].row + 1
- };
- o[ n[i].row + 1 ] = {
- text: o[ n[i].row + 1 ],
- row: i + 1
- };
- }
- }
-
- for ( i = n.length - 1; i > 0; i-- ) {
- if ( n[i].text != null && n[ i - 1 ].text == null && n[i].row > 0 && o[ n[i].row - 1 ].text == null &&
- n[ i - 1 ] == o[ n[i].row - 1 ]) {
-
- n[ i - 1 ] = {
- text: n[ i - 1 ],
- row: n[i].row - 1
- };
- o[ n[i].row - 1 ] = {
- text: o[ n[i].row - 1 ],
- row: i - 1
- };
- }
- }
-
- return {
- o: o,
- n: n
- };
- }
-
- return function( o, n ) {
- o = o.replace( /\s+$/, "" );
- n = n.replace( /\s+$/, "" );
-
- var i, pre,
- str = "",
- out = diff( o === "" ? [] : o.split(/\s+/), n === "" ? [] : n.split(/\s+/) ),
- oSpace = o.match(/\s+/g),
- nSpace = n.match(/\s+/g);
-
- if ( oSpace == null ) {
- oSpace = [ " " ];
- }
- else {
- oSpace.push( " " );
- }
-
- if ( nSpace == null ) {
- nSpace = [ " " ];
- }
- else {
- nSpace.push( " " );
- }
-
- if ( out.n.length === 0 ) {
- for ( i = 0; i < out.o.length; i++ ) {
- str += "" + out.o[i] + oSpace[i] + "";
- }
- }
- else {
- if ( out.n[0].text == null ) {
- for ( n = 0; n < out.o.length && out.o[n].text == null; n++ ) {
- str += "" + out.o[n] + oSpace[n] + "";
- }
- }
-
- for ( i = 0; i < out.n.length; i++ ) {
- if (out.n[i].text == null) {
- str += "" + out.n[i] + nSpace[i] + "";
- }
- else {
- // `pre` initialized at top of scope
- pre = "";
-
- for ( n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++ ) {
- pre += "" + out.o[n] + oSpace[n] + "";
- }
- str += " " + out.n[i].text + nSpace[i] + pre;
- }
- }
- }
-
- return str;
- };
-}());
-
-// for CommonJS enviroments, export everything
-if ( typeof exports !== "undefined" ) {
- extend( exports, QUnit );
-}
-
-// get at whatever the global object is, like window in browsers
-}( (function() {return this;}.call()) ));
diff --git a/test/lib/require.js b/test/lib/require.js
deleted file mode 100644
index 987f865..0000000
--- a/test/lib/require.js
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- RequireJS 2.1.5 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.
- Available via the MIT or new BSD license.
- see: http://github.com/jrburke/requirejs for details
-*/
-var requirejs,require,define;
-(function(aa){function I(b){return"[object Function]"===L.call(b)}function J(b){return"[object Array]"===L.call(b)}function y(b,c){if(b){var d;for(d=0;dthis.depCount&&!this.defined){if(I(n)){if(this.events.error)try{e=i.execCb(c,n,b,e)}catch(d){a=d}else e=i.execCb(c,n,b,e);this.map.isDefine&&((b=this.module)&&void 0!==b.exports&&b.exports!==this.exports?e=b.exports:void 0===e&&this.usingExports&&(e=this.exports));if(a)return a.requireMap=this.map,a.requireModules=[this.map.id],a.requireType="define",v(this.error=
-a)}else e=n;this.exports=e;if(this.map.isDefine&&!this.ignore&&(q[c]=e,l.onResourceLoad))l.onResourceLoad(i,this.map,this.depMaps);x(c);this.defined=!0}this.defining=!1;this.defined&&!this.defineEmitted&&(this.defineEmitted=!0,this.emit("defined",this.exports),this.defineEmitComplete=!0)}}else this.fetch()}},callPlugin:function(){var a=this.map,b=a.id,d=j(a.prefix);this.depMaps.push(d);t(d,"defined",u(this,function(e){var n,d;d=this.map.name;var g=this.map.parentMap?this.map.parentMap.name:null,h=
-i.makeRequire(a.parentMap,{enableBuildCallback:!0});if(this.map.unnormalized){if(e.normalize&&(d=e.normalize(d,function(a){return c(a,g,!0)})||""),e=j(a.prefix+"!"+d,this.map.parentMap),t(e,"defined",u(this,function(a){this.init([],function(){return a},null,{enabled:!0,ignore:!0})})),d=m(p,e.id)){this.depMaps.push(e);if(this.events.error)d.on("error",u(this,function(a){this.emit("error",a)}));d.enable()}}else n=u(this,function(a){this.init([],function(){return a},null,{enabled:!0})}),n.error=u(this,
-function(a){this.inited=!0;this.error=a;a.requireModules=[b];G(p,function(a){0===a.map.id.indexOf(b+"_unnormalized")&&x(a.map.id)});v(a)}),n.fromText=u(this,function(e,c){var d=a.name,g=j(d),C=O;c&&(e=c);C&&(O=!1);r(g);s(k.config,b)&&(k.config[d]=k.config[b]);try{l.exec(e)}catch(ca){return v(B("fromtexteval","fromText eval for "+b+" failed: "+ca,ca,[b]))}C&&(O=!0);this.depMaps.push(g);i.completeLoad(d);h([d],n)}),e.load(a.name,h,n,k)}));i.enable(d,this);this.pluginMaps[d.id]=d},enable:function(){V[this.map.id]=
-this;this.enabling=this.enabled=!0;y(this.depMaps,u(this,function(a,b){var c,e;if("string"===typeof a){a=j(a,this.map.isDefine?this.map:this.map.parentMap,!1,!this.skipMap);this.depMaps[b]=a;if(c=m(N,a.id)){this.depExports[b]=c(this);return}this.depCount+=1;t(a,"defined",u(this,function(a){this.defineDep(b,a);this.check()}));this.errback&&t(a,"error",this.errback)}c=a.id;e=p[c];!s(N,c)&&(e&&!e.enabled)&&i.enable(a,this)}));G(this.pluginMaps,u(this,function(a){var b=m(p,a.id);b&&!b.enabled&&i.enable(a,
-this)}));this.enabling=!1;this.check()},on:function(a,b){var c=this.events[a];c||(c=this.events[a]=[]);c.push(b)},emit:function(a,b){y(this.events[a],function(a){a(b)});"error"===a&&delete this.events[a]}};i={config:k,contextName:b,registry:p,defined:q,urlFetched:U,defQueue:H,Module:Z,makeModuleMap:j,nextTick:l.nextTick,onError:v,configure:function(a){a.baseUrl&&"/"!==a.baseUrl.charAt(a.baseUrl.length-1)&&(a.baseUrl+="/");var b=k.pkgs,c=k.shim,e={paths:!0,config:!0,map:!0};G(a,function(a,b){e[b]?
-"map"===b?(k.map||(k.map={}),R(k[b],a,!0,!0)):R(k[b],a,!0):k[b]=a});a.shim&&(G(a.shim,function(a,b){J(a)&&(a={deps:a});if((a.exports||a.init)&&!a.exportsFn)a.exportsFn=i.makeShimExports(a);c[b]=a}),k.shim=c);a.packages&&(y(a.packages,function(a){a="string"===typeof a?{name:a}:a;b[a.name]={name:a.name,location:a.location||a.name,main:(a.main||"main").replace(ja,"").replace(ea,"")}}),k.pkgs=b);G(p,function(a,b){!a.inited&&!a.map.unnormalized&&(a.map=j(b))});if(a.deps||a.callback)i.require(a.deps||[],
-a.callback)},makeShimExports:function(a){return function(){var b;a.init&&(b=a.init.apply(aa,arguments));return b||a.exports&&ba(a.exports)}},makeRequire:function(a,f){function d(e,c,h){var g,k;f.enableBuildCallback&&(c&&I(c))&&(c.__requireJsBuild=!0);if("string"===typeof e){if(I(c))return v(B("requireargs","Invalid require call"),h);if(a&&s(N,e))return N[e](p[a.id]);if(l.get)return l.get(i,e,a,d);g=j(e,a,!1,!0);g=g.id;return!s(q,g)?v(B("notloaded",'Module name "'+g+'" has not been loaded yet for context: '+
-b+(a?"":". Use require([])"))):q[g]}L();i.nextTick(function(){L();k=r(j(null,a));k.skipMap=f.skipMap;k.init(e,c,h,{enabled:!0});D()});return d}f=f||{};R(d,{isBrowser:A,toUrl:function(b){var d,f=b.lastIndexOf("."),g=b.split("/")[0];if(-1!==f&&(!("."===g||".."===g)||1h.attachEvent.toString().indexOf("[native code"))&&!Y?(O=!0,h.attachEvent("onreadystatechange",b.onScriptLoad)):(h.addEventListener("load",b.onScriptLoad,!1),h.addEventListener("error",b.onScriptError,!1)),h.src=d,K=h,D?x.insertBefore(h,D):x.appendChild(h),K=null,h;if(da)try{importScripts(d),b.completeLoad(c)}catch(j){b.onError(B("importscripts","importScripts failed for "+c+" at "+d,j,[c]))}};A&&M(document.getElementsByTagName("script"),function(b){x||(x=
-b.parentNode);if(t=b.getAttribute("data-main"))return r.baseUrl||(E=t.split("/"),Q=E.pop(),fa=E.length?E.join("/")+"/":"./",r.baseUrl=fa,t=Q),t=t.replace(ea,""),r.deps=r.deps?r.deps.concat(t):[t],!0});define=function(b,c,d){var l,h;"string"!==typeof b&&(d=c,c=b,b=null);J(c)||(d=c,c=[]);!c.length&&I(d)&&d.length&&(d.toString().replace(la,"").replace(ma,function(b,d){c.push(d)}),c=(1===d.length?["require"]:["require","exports","module"]).concat(c));if(O){if(!(l=K))P&&"interactive"===P.readyState||M(document.getElementsByTagName("script"),
-function(b){if("interactive"===b.readyState)return P=b}),l=P;l&&(b||(b=l.getAttribute("data-requiremodule")),h=F[l.getAttribute("data-requirecontext")])}(h?h.defQueue:T).push([b,c,d])};define.amd={jQuery:!0};l.exec=function(b){return eval(b)};l(r)}})(this);
diff --git a/test/lib/resemble.js b/test/lib/resemble.js
new file mode 100644
index 0000000..1cb8c29
--- /dev/null
+++ b/test/lib/resemble.js
@@ -0,0 +1,535 @@
+/*
+Author: James Cryer
+Company: Huddle
+Last updated date: 21 Feb 2013
+URL: https://github.com/Huddle/Resemble.js
+*/
+
+(function(_this){
+ 'use strict';
+
+ _this['resemble'] = function( fileData ){
+
+ var data = {};
+ var images = [];
+ var updateCallbackArray = [];
+
+ var tolerance = { // between 0 and 255
+ red: 16,
+ green: 16,
+ blue: 16,
+ minBrightness: 16,
+ maxBrightness: 240
+ };
+
+ var ignoreAntialiasing = false;
+ var ignoreColors = false;
+
+ function triggerDataUpdate(){
+ var len = updateCallbackArray.length;
+ var i;
+ for(i=0;i tolerance.maxBrightness;
+ }
+
+ function getHue(r,g,b){
+
+ r = r / 255;
+ g = g / 255;
+ b = b / 255;
+ var max = Math.max(r, g, b), min = Math.min(r, g, b);
+ var h;
+ var d;
+
+ if (max == min){
+ h = 0; // achromatic
+ } else{
+ d = max - min;
+ switch(max){
+ case r: h = (g - b) / d + (g < b ? 6 : 0); break;
+ case g: h = (b - r) / d + 2; break;
+ case b: h = (r - g) / d + 4; break;
+ }
+ h /= 6;
+ }
+
+ return h;
+ }
+
+ function isAntialiased(sourcePix, data, cacheSet, verticalPos, horizontalPos, width){
+ var offset;
+ var targetPix;
+ var distance = 1;
+ var i;
+ var j;
+ var hasHighContrastSibling = 0;
+ var hasSiblingWithDifferentHue = 0;
+ var hasEquivilantSibling = 0;
+
+ addHueInfo(sourcePix);
+
+ for (i = distance*-1; i <= distance; i++){
+ for (j = distance*-1; j <= distance; j++){
+
+ if(i===0 && j===0){
+ // ignore source pixel
+ } else {
+
+ offset = ((verticalPos+j)*width + (horizontalPos+i)) * 4;
+ targetPix = getPixelInfo(data, offset, cacheSet);
+
+ if(targetPix === null){
+ continue;
+ }
+
+ addBrightnessInfo(targetPix);
+ addHueInfo(targetPix);
+
+ if( isContrasting(sourcePix, targetPix) ){
+ hasHighContrastSibling++;
+ }
+
+ if( isRGBSame(sourcePix,targetPix) ){
+ hasEquivilantSibling++;
+ }
+
+ if( Math.abs(targetPix.h - sourcePix.h) > 0.3 ){
+ hasSiblingWithDifferentHue++;
+ }
+
+ if( hasSiblingWithDifferentHue > 1 || hasHighContrastSibling > 1){
+ return true;
+ }
+ }
+ }
+ }
+
+ if(hasEquivilantSibling < 2){
+ return true;
+ }
+
+ return false;
+ }
+
+ function errorPixel(px, offset){
+ px[offset] = 255; //r
+ px[offset + 1] = 0; //g
+ px[offset + 2] = 255; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyPixel(px, offset, data){
+ px[offset] = data.r; //r
+ px[offset + 1] = data.g; //g
+ px[offset + 2] = data.b; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyGrayScalePixel(px, offset, data){
+ px[offset] = data.brightness; //r
+ px[offset + 1] = data.brightness; //g
+ px[offset + 2] = data.brightness; //b
+ px[offset + 3] = 255; //a
+ }
+
+
+ function getPixelInfo(data, offset, cacheSet){
+ var r;
+ var g;
+ var b;
+ var d;
+
+ if(typeof data[offset] !== 'undefined'){
+ r = data[offset];
+ g = data[offset+1];
+ b = data[offset+2];
+ d = {
+ r: r,
+ g: g,
+ b: b
+ };
+
+ return d;
+ } else {
+ return null;
+ }
+ }
+
+ function addBrightnessInfo(data){
+ data.brightness = getBrightness(data.r,data.g,data.b); // 'corrected' lightness
+ }
+
+ function addHueInfo(data){
+ data.h = getHue(data.r,data.g,data.b);
+ }
+
+ function analyseImages(img1, img2, width, height){
+
+ var hiddenCanvas = document.createElement('canvas');
+
+ var data1 = img1.data;
+ var data2 = img2.data;
+
+ hiddenCanvas.width = width;
+ hiddenCanvas.height = height;
+
+ var context = hiddenCanvas.getContext('2d');
+ var imgd = context.createImageData(width,height);
+ var targetPix = imgd.data;
+
+ var mismatchCount = 0;
+
+ var time = Date.now();
+
+ var skip;
+
+ if( (width > 1200 || height > 1200) && ignoreAntialiasing){
+ skip = 6;
+ }
+
+ loop(height, width, function(verticalPos, horizontalPos){
+
+ if(skip){ // only skip if the image isn't small
+ if(verticalPos % skip === 0 || horizontalPos % skip === 0){
+ return;
+ }
+ }
+
+ var offset = (verticalPos*width + horizontalPos) * 4;
+ var pixel1 = getPixelInfo(data1, offset, 1);
+ var pixel2 = getPixelInfo(data2, offset, 2);
+
+ if(pixel1 === null || pixel2 === null){
+ return;
+ }
+
+ if (ignoreColors){
+
+ addBrightnessInfo(pixel1);
+ addBrightnessInfo(pixel2);
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ return;
+ }
+
+ if( isRGBSimilar(pixel1, pixel2) ){
+ copyPixel(targetPix, offset, pixel2);
+
+ } else if( ignoreAntialiasing && (
+ addBrightnessInfo(pixel1), // jit pixel info augmentation looks a little weird, sorry.
+ addBrightnessInfo(pixel2),
+ isAntialiased(pixel1, data1, 1, verticalPos, horizontalPos, width) ||
+ isAntialiased(pixel2, data2, 2, verticalPos, horizontalPos, width)
+ )){
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+
+ });
+
+ data.misMatchPercentage = (mismatchCount / (height*width) * 100).toFixed(2);
+ data.analysisTime = Date.now() - time;
+
+ data.getImageDataUrl = function(text){
+ var barHeight = 0;
+
+ if(text){
+ barHeight = addLabel(text,context,hiddenCanvas);
+ }
+
+ context.putImageData(imgd, 0, barHeight);
+
+ return hiddenCanvas.toDataURL("image/png");
+ };
+ }
+
+ function addLabel(text, context, hiddenCanvas){
+ var textPadding = 2;
+
+ context.font = '12px sans-serif';
+
+ var textWidth = context.measureText(text).width + textPadding*2;
+ var barHeight = 22;
+
+ if(textWidth > hiddenCanvas.width){
+ hiddenCanvas.width = textWidth;
+ }
+
+ hiddenCanvas.height += barHeight;
+
+ context.fillStyle = "#666";
+ context.fillRect(0,0,hiddenCanvas.width,barHeight -4);
+ context.fillStyle = "#fff";
+ context.fillRect(0,barHeight -4,hiddenCanvas.width, 4);
+
+ context.fillStyle = "#fff";
+ context.textBaseline = "top";
+ context.font = '12px sans-serif';
+ context.fillText(text, textPadding, 1);
+
+ return barHeight;
+ }
+
+ function normalise(img, w, h){
+ var c;
+ var context;
+
+ if(img.height < h || img.width < w){
+ c = document.createElement('canvas');
+ c.width = w;
+ c.height = h;
+ context = c.getContext('2d');
+ context.putImageData(img, 0, 0);
+ return context.getImageData(0, 0, w, h);
+ }
+
+ return img;
+ }
+
+ function compare(one, two){
+
+ function onceWeHaveBoth(){
+ var width;
+ var height;
+ if(images.length === 2){
+ width = images[0].width > images[1].width ? images[0].width : images[1].width;
+ height = images[0].height > images[1].height ? images[0].height : images[1].height;
+
+ if( (images[0].width === images[1].width) && (images[0].height === images[1].height) ){
+ data.isSameDimensions = true;
+ } else {
+ data.isSameDimensions = false;
+ }
+
+ analyseImages( normalise(images[0],width, height), normalise(images[1],width, height), width, height);
+
+ triggerDataUpdate();
+ }
+ }
+
+ images = [];
+ loadImageData(one, onceWeHaveBoth);
+ loadImageData(two, onceWeHaveBoth);
+ }
+
+ function getCompareApi(param){
+
+ var secondFileData,
+ hasMethod = typeof param === 'function';
+
+ if( !hasMethod ){
+ // assume it's file data
+ secondFileData = param;
+ }
+
+ var self = {
+ ignoreNothing: function(){
+
+ tolerance.red = 16;
+ tolerance.green = 16;
+ tolerance.blue = 16;
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreAntialiasing: function(){
+
+ tolerance.red = 32;
+ tolerance.green = 32;
+ tolerance.blue = 32;
+ tolerance.minBrightness = 64;
+ tolerance.maxBrightness = 96;
+
+ ignoreAntialiasing = true;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreColors: function(){
+
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = true;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ onComplete: function( callback ){
+
+ updateCallbackArray.push(callback);
+
+ var wrapper = function(){
+ compare(fileData, secondFileData);
+ };
+
+ wrapper();
+
+ return getCompareApi(wrapper);
+ }
+ };
+
+ return self;
+ }
+
+ return {
+ onComplete: function( callback ){
+ updateCallbackArray.push(callback);
+ loadImageData(fileData, function(imageData, width, height){
+ parseImage(imageData.data, width, height);
+ });
+ },
+ compareTo: function(secondFileData){
+ return getCompareApi(secondFileData);
+ }
+ };
+
+ };
+}(this));
\ No newline at end of file
diff --git a/test/testsuite.js b/test/testsuite.js
deleted file mode 100644
index b486acb..0000000
--- a/test/testsuite.js
+++ /dev/null
@@ -1,36 +0,0 @@
-requirejs.config({
- baseUrl: '/test/unit/'
-});
-
-define(function(require) {
- var testModules = [
- 'Pixi',
- 'Point',
- 'Rectangle',
- 'DisplayObject',
- 'DisplayObjectContainer',
- 'Sprite',
- 'MovieClip',
- 'InteractionManager',
- 'Stage',
- 'utils/Utils',
- 'utils/EventTarget',
- 'utils/Matrix',
- 'utils/Detector',
- 'renderers/WebGLShaders',
- 'renderers/WebGLRenderer',
- 'renderers/WebGLBatch',
- 'renderers/CanvasRenderer',
- 'extras/Strip',
- 'extras/Rope',
- 'textures/BaseTexture',
- 'textures/Texture',
- 'loaders/SpriteSheetLoader',
- 'loaders/AssetLoader'
- ];
-
- // Resolve all testModules and then start the Test Runner.
- require(testModules, function() {
- QUnit.start();
- });
-});
\ No newline at end of file
diff --git a/test/textures/SpriteSheet-Aliens.png b/test/textures/SpriteSheet-Aliens.png
new file mode 100644
index 0000000..210acb1
--- /dev/null
+++ b/test/textures/SpriteSheet-Aliens.png
Binary files differ
diff --git a/test/textures/SpriteSheet-Explosion.png b/test/textures/SpriteSheet-Explosion.png
new file mode 100755
index 0000000..79e1a69
--- /dev/null
+++ b/test/textures/SpriteSheet-Explosion.png
Binary files differ
diff --git a/test/textures/bunny.png b/test/textures/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/textures/bunny.png
Binary files differ
diff --git a/test/unit/DisplayObject.js b/test/unit/DisplayObject.js
deleted file mode 100644
index 5e7e72f..0000000
--- a/test/unit/DisplayObject.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObject');
-});
diff --git a/test/unit/DisplayObjectContainer.js b/test/unit/DisplayObjectContainer.js
deleted file mode 100644
index b323959..0000000
--- a/test/unit/DisplayObjectContainer.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObjectContainer');
-});
diff --git a/test/unit/InteractionManager.js b/test/unit/InteractionManager.js
deleted file mode 100644
index e751f52..0000000
--- a/test/unit/InteractionManager.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('InteractionManager');
-});
diff --git a/test/unit/MovieClip.js b/test/unit/MovieClip.js
deleted file mode 100644
index 37d9446..0000000
--- a/test/unit/MovieClip.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('MovieClip');
-});
diff --git a/test/unit/Pixi.js b/test/unit/Pixi.js
deleted file mode 100644
index 36eee73..0000000
--- a/test/unit/Pixi.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Pixi');
-});
diff --git a/test/unit/Point.js b/test/unit/Point.js
deleted file mode 100644
index 983ff6e..0000000
--- a/test/unit/Point.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Point');
-});
diff --git a/test/unit/Rectangle.js b/test/unit/Rectangle.js
deleted file mode 100644
index 3b439ba..0000000
--- a/test/unit/Rectangle.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Rectangle');
-});
diff --git a/test/unit/Sprite.js b/test/unit/Sprite.js
deleted file mode 100644
index ed4f596..0000000
--- a/test/unit/Sprite.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Sprite');
-});
diff --git a/test/unit/Stage.js b/test/unit/Stage.js
deleted file mode 100644
index 2d70291..0000000
--- a/test/unit/Stage.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Stage');
-});
diff --git a/test/unit/extras/Rope.js b/test/unit/extras/Rope.js
deleted file mode 100644
index 5606f14..0000000
--- a/test/unit/extras/Rope.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Rope');
-});
diff --git a/test/unit/extras/Strip.js b/test/unit/extras/Strip.js
deleted file mode 100644
index 0134d3a..0000000
--- a/test/unit/extras/Strip.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Strip');
-});
diff --git a/test/unit/loaders/AssetLoader.js b/test/unit/loaders/AssetLoader.js
deleted file mode 100644
index 13b8443..0000000
--- a/test/unit/loaders/AssetLoader.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('AssetLoader');
-});
diff --git a/test/unit/loaders/SpriteSheetLoader.js b/test/unit/loaders/SpriteSheetLoader.js
deleted file mode 100644
index 8bf0cb2..0000000
--- a/test/unit/loaders/SpriteSheetLoader.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('SpriteSheetLoader');
-});
diff --git a/test/unit/pixi/InteractionManager.js b/test/unit/pixi/InteractionManager.js
new file mode 100644
index 0000000..ed3001f
--- /dev/null
+++ b/test/unit/pixi/InteractionManager.js
@@ -0,0 +1,10 @@
+describe('pixi/InteractionManager', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var InteractionManager = PIXI.InteractionManager;
+
+ it('Module exists', function () {
+ expect(InteractionManager).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/Pixi.js b/test/unit/pixi/Pixi.js
new file mode 100644
index 0000000..27debc1
--- /dev/null
+++ b/test/unit/pixi/Pixi.js
@@ -0,0 +1,9 @@
+describe('pixi/Pixi', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+
+ it('Module exists', function () {
+ expect(global).to.have.property('PIXI').and.to.be.an('object');
+ });
+});
diff --git a/test/unit/pixi/core/Circle.js b/test/unit/pixi/core/Circle.js
new file mode 100644
index 0000000..93a4456
--- /dev/null
+++ b/test/unit/pixi/core/Circle.js
@@ -0,0 +1,22 @@
+describe('pixi/core/Circle', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Circle = PIXI.Circle;
+
+ it('Module exists', function () {
+ expect(Circle).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Circle();
+
+ expect(obj).to.be.an.instanceof(Circle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', 0);
+ expect(obj).to.have.property('y', 0);
+ expect(obj).to.have.property('radius', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Ellipse.js b/test/unit/pixi/core/Ellipse.js
new file mode 100644
index 0000000..026b56f
--- /dev/null
+++ b/test/unit/pixi/core/Ellipse.js
@@ -0,0 +1,24 @@
+describe('pixi/core/Ellipse', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Ellipse = PIXI.Ellipse;
+
+ it('Module exists', function () {
+ expect(Ellipse).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Ellipse();
+
+ expect(obj).to.be.an.instanceof(Ellipse);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+ expect(obj).to.respondTo('getBounds');
+
+ expect(obj).to.have.property('x', 0);
+ expect(obj).to.have.property('y', 0);
+ expect(obj).to.have.property('width', 0);
+ expect(obj).to.have.property('height', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Matrix.js b/test/unit/pixi/core/Matrix.js
new file mode 100644
index 0000000..b48989e
--- /dev/null
+++ b/test/unit/pixi/core/Matrix.js
@@ -0,0 +1,30 @@
+describe('pixi/core/Matrix', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var mat3 = PIXI.mat3;
+ var mat4 = PIXI.mat4;
+ var Matrix = PIXI.Matrix;
+
+ it('Ensure determineMatrixArrayType works', function () {
+ expect(Matrix).to.be.a('function');
+ });
+
+ it('mat3 exists', function () {
+ expect(mat3).to.be.an('object');
+ });
+
+ it('Confirm new mat3 matrix', function () {
+ var matrix = new mat3.create();
+ pixi_core_Matrix_confirmNewMat3(matrix);
+ });
+
+ it('mat3 exists', function () {
+ expect(mat4).to.be.an('object');
+ });
+
+ it('Confirm new mat4 matrix', function () {
+ var matrix = new mat4.create();
+ pixi_core_Matrix_confirmNewMat4(matrix);
+ });
+});
diff --git a/test/unit/pixi/core/Point.js b/test/unit/pixi/core/Point.js
new file mode 100644
index 0000000..c4d5163
--- /dev/null
+++ b/test/unit/pixi/core/Point.js
@@ -0,0 +1,15 @@
+describe('pixi/core/Point', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Point = PIXI.Point;
+
+ it('Module exists', function () {
+ expect(Point).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Point();
+ pixi_core_Point_confirm(obj, 0, 0);
+ });
+});
diff --git a/test/unit/pixi/core/Polygon.js b/test/unit/pixi/core/Polygon.js
new file mode 100644
index 0000000..dc8c918
--- /dev/null
+++ b/test/unit/pixi/core/Polygon.js
@@ -0,0 +1,20 @@
+describe('pixi/core/Polygon', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Polygon = PIXI.Polygon;
+
+ it('Module exists', function () {
+ expect(Polygon).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Polygon();
+
+ expect(obj).to.be.an.instanceof(Polygon);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.deep.property('points.length', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Rectangle.js b/test/unit/pixi/core/Rectangle.js
new file mode 100644
index 0000000..d43316e
--- /dev/null
+++ b/test/unit/pixi/core/Rectangle.js
@@ -0,0 +1,15 @@
+describe('pixi/core/Rectangle', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Rectangle = PIXI.Rectangle;
+
+ it('Module exists', function () {
+ expect(Rectangle).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var rect = new Rectangle();
+ pixi_core_Rectangle_confirm(rect, 0, 0, 0, 0);
+ });
+});
diff --git a/test/unit/pixi/display/DisplayObject.js b/test/unit/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..40c6fbc
--- /dev/null
+++ b/test/unit/pixi/display/DisplayObject.js
@@ -0,0 +1,21 @@
+describe('pixi/display/DisplayObject', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var DisplayObject = PIXI.DisplayObject;
+
+ it('Module exists', function () {
+ expect(DisplayObject).to.be.a('function');
+ expect(PIXI).to.have.property('visibleCount', 0);
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new DisplayObject();
+
+ pixi_display_DisplayObject_confirmNew(obj);
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', false);
+ expect(obj).to.have.property('stage', null);
+ });
+});
diff --git a/test/unit/pixi/display/DisplayObjectContainer.js b/test/unit/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..ce7f02f
--- /dev/null
+++ b/test/unit/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,20 @@
+describe('pixi/display/DisplayObjectContainer', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var DisplayObjectContainer = PIXI.DisplayObjectContainer;
+
+ it('Module exists', function () {
+ expect(DisplayObjectContainer).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new DisplayObjectContainer();
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', false);
+ expect(obj).to.have.property('stage', null);
+ });
+});
diff --git a/test/unit/pixi/display/MovieClip.js b/test/unit/pixi/display/MovieClip.js
new file mode 100644
index 0000000..f3c6c6a
--- /dev/null
+++ b/test/unit/pixi/display/MovieClip.js
@@ -0,0 +1,33 @@
+describe('pixi/display/MovieClip', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var MovieClip = PIXI.MovieClip;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(MovieClip).to.be.a('function');
+ });
+
+ it('Confirm new instance', function (done) {
+ var texture = Texture.fromImage('/base/test/textures/SpriteSheet-Explosion.png');
+ var obj = new MovieClip([texture]);
+
+ pixi_display_Sprite_confirmNew(obj, done);
+
+ expect(obj).to.be.an.instanceof(MovieClip);
+ expect(obj).to.respondTo('stop');
+ expect(obj).to.respondTo('play');
+ expect(obj).to.respondTo('gotoAndStop');
+ expect(obj).to.respondTo('gotoAndPlay');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('textures.length', 1);
+ expect(obj).to.have.deep.property('textures[0]', texture);
+ expect(obj).to.have.property('animationSpeed', 1);
+ expect(obj).to.have.property('loop', true);
+ expect(obj).to.have.property('onComplete', null);
+ expect(obj).to.have.property('currentFrame', 0);
+ expect(obj).to.have.property('playing', false);
+ });
+});
diff --git a/test/unit/pixi/display/Sprite.js b/test/unit/pixi/display/Sprite.js
new file mode 100644
index 0000000..54e914f
--- /dev/null
+++ b/test/unit/pixi/display/Sprite.js
@@ -0,0 +1,25 @@
+describe('pixi/display/Sprite', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Sprite = PIXI.Sprite;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(Sprite).to.be.a('function');
+ expect(PIXI).to.have.deep.property('blendModes.NORMAL', 0);
+ expect(PIXI).to.have.deep.property('blendModes.SCREEN', 1);
+ });
+
+ it('Members exist', function () {
+ expect(Sprite).itself.to.respondTo('fromImage');
+ expect(Sprite).itself.to.respondTo('fromFrame');
+ });
+
+ it('Confirm new instance', function (done) {
+ var texture = Texture.fromImage('/base/test/textures/SpriteSheet-Aliens.png');
+ var obj = new Sprite(texture);
+
+ pixi_display_Sprite_confirmNew(obj, done);
+ });
+});
diff --git a/test/unit/pixi/display/Stage.js b/test/unit/pixi/display/Stage.js
new file mode 100644
index 0000000..3cc2a4d
--- /dev/null
+++ b/test/unit/pixi/display/Stage.js
@@ -0,0 +1,49 @@
+describe('pixi/display/Stage', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Stage = PIXI.Stage;
+ var InteractionManager = PIXI.InteractionManager;
+ var Rectangle = PIXI.Rectangle;
+
+ it('Module exists', function () {
+ expect(Stage).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Stage(null, true);
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(Stage);
+ expect(obj).to.respondTo('updateTransform');
+ expect(obj).to.respondTo('setBackgroundColor');
+ expect(obj).to.respondTo('getMousePosition');
+
+ // FIXME: duplicate member in DisplayObject
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ // FIXME: convert arg to bool in constructor
+ expect(obj).to.have.property('interactive', true);
+
+ expect(obj).to.have.property('interactionManager')
+ .and.to.be.an.instanceof(InteractionManager)
+ .and.to.have.property('stage', obj);
+
+ expect(obj).to.have.property('dirty', true);
+
+ expect(obj).to.have.property('stage', obj);
+
+ expect(obj).to.have.property('hitArea')
+ .and.to.be.an.instanceof(Rectangle);
+ pixi_core_Rectangle_confirm(obj.hitArea, 0, 0, 100000, 100000);
+
+ expect(obj).to.have.property('backgroundColor', 0x000000);
+ expect(obj).to.have.deep.property('backgroundColorSplit.length', 3);
+ expect(obj).to.have.deep.property('backgroundColorSplit[0]', 0);
+ expect(obj).to.have.deep.property('backgroundColorSplit[1]', 0);
+ expect(obj).to.have.deep.property('backgroundColorSplit[2]', 0);
+ expect(obj).to.have.property('backgroundColorString', '#000000');
+
+ expect(obj).to.have.property('worldVisible', true);
+ });
+});
diff --git a/test/unit/pixi/extras/CustomRenderable.js b/test/unit/pixi/extras/CustomRenderable.js
new file mode 100644
index 0000000..8d83cf0
--- /dev/null
+++ b/test/unit/pixi/extras/CustomRenderable.js
@@ -0,0 +1,21 @@
+describe('pixi/extras/CustomRenderable', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var CustomRenderable = PIXI.CustomRenderable;
+
+ it('Module exists', function () {
+ expect(CustomRenderable).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new CustomRenderable();
+
+ pixi_display_DisplayObject_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(CustomRenderable);
+ expect(obj).to.respondTo('renderCanvas');
+ expect(obj).to.respondTo('initWebGL');
+ expect(obj).to.respondTo('renderWebGL');
+ });
+});
diff --git a/test/unit/pixi/extras/Rope.js b/test/unit/pixi/extras/Rope.js
new file mode 100644
index 0000000..6ddaf83
--- /dev/null
+++ b/test/unit/pixi/extras/Rope.js
@@ -0,0 +1,26 @@
+describe('pixi/extras/Rope', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Rope = PIXI.Rope;
+ var Texture = PIXI.Texture;
+ var Point = PIXI.Point;
+
+ it('Module exists', function () {
+ expect(Rope).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var texture = Texture.fromImage('/base/test/textures/bunny.png');
+ var obj = new Rope(texture, [new Point(), new Point(5, 10), new Point(10, 20)]);
+
+ pixi_extras_Strip_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(Rope);
+ expect(obj).to.respondTo('refresh');
+ expect(obj).to.respondTo('updateTransform');
+ expect(obj).to.respondTo('setTexture');
+
+ // TODO: Test properties
+ });
+});
diff --git a/test/unit/pixi/extras/Spine.js b/test/unit/pixi/extras/Spine.js
new file mode 100644
index 0000000..0708bc0
--- /dev/null
+++ b/test/unit/pixi/extras/Spine.js
@@ -0,0 +1,10 @@
+describe('pixi/extras/Spine', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Spine = PIXI.Spine;
+
+ it('Module exists', function () {
+ expect(Spine).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/extras/Strip.js b/test/unit/pixi/extras/Strip.js
new file mode 100644
index 0000000..8e564e1
--- /dev/null
+++ b/test/unit/pixi/extras/Strip.js
@@ -0,0 +1,18 @@
+describe('pixi/extras/Strip', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Strip = PIXI.Strip;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(Strip).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var texture = Texture.fromImage('/base/test/textures/bunny.png');
+ var obj = new Strip(texture, 20, 10000);
+
+ pixi_extras_Strip_confirmNew(obj);
+ });
+});
diff --git a/test/unit/pixi/extras/TilingSprite.js b/test/unit/pixi/extras/TilingSprite.js
new file mode 100644
index 0000000..56aea14
--- /dev/null
+++ b/test/unit/pixi/extras/TilingSprite.js
@@ -0,0 +1,24 @@
+describe('pixi/extras/TilingSprite', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var TilingSprite = PIXI.TilingSprite;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(TilingSprite).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var texture = Texture.fromImage('/base/test/textures/bunny.png');
+ var obj = new TilingSprite(texture, 6000, 12000);
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(TilingSprite);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ // TODO: Test properties
+ });
+});
diff --git a/test/unit/pixi/filters/FilterBlock.js b/test/unit/pixi/filters/FilterBlock.js
new file mode 100644
index 0000000..870cec0
--- /dev/null
+++ b/test/unit/pixi/filters/FilterBlock.js
@@ -0,0 +1,10 @@
+describe('pixi/filters/FilterBlock', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var FilterBlock = PIXI.FilterBlock;
+
+ it('Module exists', function () {
+ expect(FilterBlock).to.be.a('function');
+ });
+});
diff --git a/.gitignore b/.gitignore
index 12e1b62..0b88317 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
node_modules
.DS_Store
-.project
\ No newline at end of file
+.project
+*.log
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..63e4d7c
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,8 @@
+language: node_js
+node_js:
+ - 0.10
+
+before_script:
+ - npm install -g grunt-cli
+ - export DISPLAY=:99.0
+ - sh -e /etc/init.d/xvfb start
diff --git a/Gruntfile.js b/Gruntfile.js
index b083b49..103938c 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -1,10 +1,12 @@
+'use strict';
+
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-connect');
- grunt.loadNpmTasks('grunt-contrib-qunit');
grunt.loadNpmTasks('grunt-contrib-yuidoc');
+ grunt.loadTasks('tasks');
var root = 'src/pixi/',
debug = 'bin/pixi.dev.js',
@@ -79,7 +81,7 @@
},
files: {
srcBlob: '<%= dirs.src %>/**/*.js',
- testBlob: '<%= dirs.test %>/unit/**/*.js',
+ testBlob: '<%= dirs.test %>/{functional,lib/pixi,unit}/**/*.js',
build: '<%= dirs.build %>/pixi.dev.js',
buildMin: '<%= dirs.build %>/pixi.js'
},
@@ -94,7 +96,12 @@
},
jshint: {
beforeconcat: srcFiles,
- test: ['<%= files.testBlob %>'],
+ test: {
+ src: ['<%= files.testBlob %>'],
+ options: {
+ expr: true
+ }
+ },
options: {
asi: true,
smarttabs: true
@@ -128,12 +135,6 @@
]
},
connect: {
- qunit: {
- options: {
- port: grunt.option('port-test') || 9002,
- base: './'
- }
- },
test: {
options: {
port: grunt.option('port-test') || 9002,
@@ -142,13 +143,6 @@
}
}
},
- qunit: {
- all: {
- options: {
- urls: ['http://localhost:' + (grunt.option('port-test') || 9002) + '/test/index.html']
- }
- }
- },
yuidoc: {
compile: {
name: '<%= pkg.name %>',
@@ -161,6 +155,13 @@
outdir: '<%= dirs.docs %>'
}
}
+ },
+ karma: {
+ unit: {
+ configFile: 'test/karma.conf.js',
+ // browsers: ['Chrome'],
+ singleRun: true
+ }
}
});
@@ -182,9 +183,10 @@
}
)
- grunt.registerTask('default', ['concat', 'uglify', 'distribute']);
grunt.registerTask('build', ['concat', 'uglify', 'distribute']);
- grunt.registerTask('test', ['build', 'connect:qunit', 'qunit']);
+ grunt.registerTask('test', ['concat', 'jshint:test', 'karma']);
grunt.registerTask('docs', ['yuidoc']);
-
-}
\ No newline at end of file
+ grunt.registerTask('default', ['test', 'uglify', 'distribute']);
+ // Travis CI task.
+ grunt.registerTask('travis', ['test']);
+}
diff --git a/README.md b/README.md
index c62ef86..690cfe4 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,8 @@

+[](http://travis-ci.org/drkibitz/pixi.js)
+
#### JavaScript 2D Renderer ####
The aim of this project is to provide a fast lightweight 2D library that works
diff --git a/package.json b/package.json
index b373240..1246a68 100644
--- a/package.json
+++ b/package.json
@@ -18,14 +18,21 @@
"main": "bin/pixi.js",
+ "scripts": {
+ "test": "grunt travis --verbose"
+ },
+
"dependencies": {},
"devDependencies": {
"grunt": "~0.4.x",
- "grunt-contrib-jshint": "0.3.x",
+ "grunt-contrib-jshint": "0.6.x",
"grunt-contrib-uglify": "0.2.x",
- "grunt-contrib-connect": "0.2.x",
- "grunt-contrib-qunit": "0.2.x",
+ "grunt-contrib-connect": "0.3.x",
"grunt-contrib-yuidoc": "0.4.x",
- "grunt-contrib-concat": "0.1.x"
+ "grunt-contrib-concat": "0.3.x",
+ "chai": "~1.7.0",
+ "karma": "0.11.0",
+ "karma-firefox-launcher": "0.1.0",
+ "karma-mocha": "0.1.0"
}
}
diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js
index a7c520e..ee82bbd 100644
--- a/src/pixi/InteractionManager.js
+++ b/src/pixi/InteractionManager.js
@@ -62,7 +62,6 @@
this.onTouchEnd = this.onTouchEnd.bind(this);
this.onTouchMove = this.onTouchMove.bind(this);
-
this.last = 0;
}
diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js
index 1a95d20..eef1059 100644
--- a/src/pixi/core/Ellipse.js
+++ b/src/pixi/core/Ellipse.js
@@ -78,7 +78,7 @@
return (normx + normy < 0.25);
}
-PIXI.Ellipse.getBounds = function()
+PIXI.Ellipse.prototype.getBounds = function()
{
return new PIXI.Rectangle(this.x, this.y, this.width, this.height);
}
diff --git a/tasks/karma.js b/tasks/karma.js
new file mode 100644
index 0000000..c340485
--- /dev/null
+++ b/tasks/karma.js
@@ -0,0 +1,27 @@
+'use strict';
+
+var path = require('path');
+var server = require('karma').server;
+
+module.exports = function (grunt) {
+ grunt.registerMultiTask('karma', 'run karma.', function() {
+ var done = this.async();
+ var options = this.options({
+ background: false
+ });
+ var data = this.data;
+
+ //merge options onto data, with data taking precedence
+ data = grunt.util._.merge(options, data);
+ data.configFile = path.resolve(data.configFile);
+ if (data.configFile) {
+ data.configFile = grunt.template.process(data.configFile);
+ }
+
+ server.start(
+ data,
+ function(code) {
+ done(!code);
+ });
+ });
+};
diff --git a/test/functional/example-1-basics/bunny.png b/test/functional/example-1-basics/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/functional/example-1-basics/bunny.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-30.png b/test/functional/example-1-basics/frame-30.png
new file mode 100644
index 0000000..96e3409
--- /dev/null
+++ b/test/functional/example-1-basics/frame-30.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-60.png b/test/functional/example-1-basics/frame-60.png
new file mode 100644
index 0000000..af3f4ce
--- /dev/null
+++ b/test/functional/example-1-basics/frame-60.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-90.png b/test/functional/example-1-basics/frame-90.png
new file mode 100644
index 0000000..099b823
--- /dev/null
+++ b/test/functional/example-1-basics/frame-90.png
Binary files differ
diff --git a/test/functional/example-1-basics/index.js b/test/functional/example-1-basics/index.js
new file mode 100644
index 0000000..7ae7a98
--- /dev/null
+++ b/test/functional/example-1-basics/index.js
@@ -0,0 +1,133 @@
+describe('Example 1 - Basics', function () {
+ 'use strict';
+
+ var baseUri = '/base/test/functional/example-1-basics';
+ var expect = chai.expect;
+ var currentFrame = 0;
+ var frameEvents = {};
+ var stage;
+ var renderer;
+ var bunny;
+
+ function onFrame(frame, callback) {
+ frameEvents[frame] = callback;
+ }
+
+ function animate() {
+ currentFrame += 1;
+
+ requestAnimFrame( animate );
+
+ // just for fun, lets rotate mr rabbit a little
+ bunny.rotation += 0.1;
+
+ // render the stage
+ renderer.render(stage);
+
+ if (frameEvents[currentFrame])
+ frameEvents[currentFrame](currentFrame);
+ }
+
+ function initScene() {
+ // create an new instance of a pixi stage
+ stage = new PIXI.Stage(0x66FF99);
+
+ // create a renderer instance
+ renderer = PIXI.autoDetectRenderer(400, 300);
+ console.log('Is PIXI.WebGLRenderer: ' + (renderer instanceof PIXI.WebGLRenderer));
+
+ // add the renderer view element to the DOM
+ document.body.appendChild(renderer.view);
+
+ requestAnimFrame( animate );
+
+ // create a texture from an image path
+ var texture = PIXI.Texture.fromImage(baseUri + "/bunny.png");
+ // create a new Sprite using the texture
+ bunny = new PIXI.Sprite(texture);
+
+ // center the sprites anchor point
+ bunny.anchor.x = 0.5;
+ bunny.anchor.y = 0.5;
+
+ // move the sprite t the center of the screen
+ bunny.position.x = 200;
+ bunny.position.y = 150;
+
+ stage.addChild(bunny);
+ }
+
+ it('assets loaded', function (done) {
+ var loader = new PIXI.AssetLoader([
+ baseUri + '/bunny.png',
+ baseUri + '/frame-30.png',
+ baseUri + '/frame-60.png',
+ baseUri + '/frame-90.png'
+ ]);
+ // loader.on('onProgress', function (event) {
+ // console.log(event.content);
+ // });
+ loader.on('onComplete', function (event) {
+ done();
+ initScene();
+ });
+ loader.load();
+ });
+
+ it('frame 30 should match', function (done) {
+ this.timeout(700);
+ onFrame(30, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-30.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 60 should match', function (done) {
+ this.timeout(1200);
+ onFrame(60, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-60.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 90 should match', function (done) {
+ this.timeout(1700);
+ onFrame(90, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-90.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ // it('capture something', function (done) {
+ // this.timeout(2000000);
+ // onFrame(30, function () {
+ // var img = new Image();
+ // img.src = renderer.view.toDataURL('image/png');
+ // document.body.appendChild(img);
+ // });
+ // });
+});
diff --git a/test/index.html b/test/index.html
deleted file mode 100644
index 9cbcac5..0000000
--- a/test/index.html
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
- Pixi.js Test Suite
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/test/karma.conf.js b/test/karma.conf.js
new file mode 100644
index 0000000..c66a696
--- /dev/null
+++ b/test/karma.conf.js
@@ -0,0 +1,82 @@
+module.exports = function(config) {
+ config.set({
+
+ // base path, that will be used to resolve files and exclude
+ basePath : '../',
+
+ frameworks : ['mocha'],
+
+ // list of files / patterns to load in the browser
+ files : [
+ 'node_modules/chai/chai.js',
+ 'bin/pixi.dev.js',
+ 'test/lib/**/*.js',
+ 'test/unit/**/*.js',
+ // 'test/functional/**/*.js',
+ {pattern: 'test/**/*.png', watched: false, included: false, served: true}
+ ],
+
+ // list of files to exclude
+ exclude : [],
+
+ // use dolts reporter, as travis terminal does not support escaping sequences
+ // possible values: 'dots', 'progress', 'junit', 'teamcity'
+ // CLI --reporters progress
+ reporters : ['progress'],
+
+ // web server port
+ // CLI --port 9876
+ port : 9876,
+
+ // cli runner port
+ // CLI --runner-port 9100
+ runnerPort : 9100,
+
+ // enable / disable colors in the output (reporters and logs)
+ // CLI --colors --no-colors
+ colors : true,
+
+ // level of logging
+ // possible values: karma.LOG_DISABLE || karma.LOG_ERROR || karma.LOG_WARN || karma.LOG_INFO || karma.LOG_DEBUG
+ // CLI --log-level debug
+ logLevel : config.LOG_DEBUG,
+
+ // enable / disable watching file and executing tests whenever any file changes
+ // CLI --auto-watch --no-auto-watch
+ autoWatch : false,
+
+ // Start these browsers, currently available:
+ // - Chrome
+ // - ChromeCanary
+ // - Firefox
+ // - Opera
+ // - Safari (only Mac)
+ // - PhantomJS
+ // - IE (only Windows)
+ // CLI --browsers Chrome,Firefox,Safari
+ browsers : ['Firefox'],
+
+ // If browser does not capture in given timeout [ms], kill it
+ // CLI --capture-timeout 5000
+ captureTimeout : 5000,
+
+ // Auto run tests on start (when browsers are captured) and exit
+ // CLI --single-run --no-single-run
+ singleRun : true,
+
+ // report which specs are slower than 500ms
+ // CLI --report-slower-than 500
+ reportSlowerThan : 1000,
+
+ preprocessors : {
+ // '**/client/js/*.js': 'coverage'
+ },
+
+ plugins : [
+ 'karma-mocha',
+ // 'karma-chrome-launcher',
+ 'karma-firefox-launcher',
+ // 'karma-phantomjs-launcher'
+ ]
+ });
+};
diff --git a/test/lib/pixi/core/Matrix.js b/test/lib/pixi/core/Matrix.js
new file mode 100644
index 0000000..d26386b
--- /dev/null
+++ b/test/lib/pixi/core/Matrix.js
@@ -0,0 +1,40 @@
+
+function pixi_core_Matrix_confirmNewMat3(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(1);
+ expect(matrix[5]).to.equal(0);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(1);
+}
+
+function pixi_core_Matrix_confirmNewMat4(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[0]).to.equal(1);
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(0);
+ expect(matrix[5]).to.equal(1);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(0);
+ expect(matrix[9]).to.equal(0);
+ expect(matrix[10]).to.equal(1);
+ expect(matrix[11]).to.equal(0);
+ expect(matrix[12]).to.equal(0);
+ expect(matrix[13]).to.equal(0);
+ expect(matrix[14]).to.equal(0);
+ expect(matrix[15]).to.equal(1);
+}
diff --git a/test/lib/pixi/core/Point.js b/test/lib/pixi/core/Point.js
new file mode 100644
index 0000000..e5df07b
--- /dev/null
+++ b/test/lib/pixi/core/Point.js
@@ -0,0 +1,10 @@
+
+function pixi_core_Point_confirm(obj, x, y) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Point);
+ expect(obj).to.respondTo('clone');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+}
diff --git a/test/lib/pixi/core/Rectangle.js b/test/lib/pixi/core/Rectangle.js
new file mode 100644
index 0000000..23f0d12
--- /dev/null
+++ b/test/lib/pixi/core/Rectangle.js
@@ -0,0 +1,13 @@
+
+function pixi_core_Rectangle_confirm(obj, x, y, width, height) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Rectangle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+ expect(obj).to.have.property('width', width);
+ expect(obj).to.have.property('height', height);
+}
diff --git a/test/lib/pixi/display/DisplayObject.js b/test/lib/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..1388a7f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObject.js
@@ -0,0 +1,43 @@
+
+function pixi_display_DisplayObject_confirmNew(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObject);
+ expect(obj).to.respondTo('setInteractive');
+ expect(obj).to.respondTo('addFilter');
+ expect(obj).to.respondTo('removeFilter');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.property('last', obj);
+ expect(obj).to.have.property('first', obj);
+
+ expect(obj).to.contain.property('position');
+ pixi_core_Point_confirm(obj.position, 0, 0);
+ expect(obj).to.contain.property('scale');
+ pixi_core_Point_confirm(obj.scale, 1, 1);
+ expect(obj).to.contain.property('pivot');
+ pixi_core_Point_confirm(obj.pivot, 0, 0);
+
+ expect(obj).to.have.property('rotation', 0);
+ expect(obj).to.have.property('alpha', 1);
+ expect(obj).to.have.property('visible', true);
+ expect(obj).to.have.property('buttonMode', false);
+ expect(obj).to.have.property('parent', null);
+ expect(obj).to.have.property('worldAlpha', 1);
+
+ expect(obj).to.have.property('hitArea');
+ expect(obj).to.have.property('interactive'); // TODO: Have a better default value
+ expect('mask' in obj).to.be.true; // TODO: Have a better default value
+ expect(obj.mask).to.be.undefined;
+
+ expect(obj).to.have.property('renderable');
+ expect(obj).to.have.property('stage');
+
+ expect(obj).to.have.deep.property('worldTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ expect(obj).to.have.deep.property('localTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.localTransform);
+
+ expect(obj).to.have.deep.property('color.length', 0);
+ expect(obj).to.have.property('dynamic', true);
+}
diff --git a/test/lib/pixi/display/DisplayObjectContainer.js b/test/lib/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..085c59f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,16 @@
+
+function pixi_display_DisplayObjectContainer_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObject_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObjectContainer);
+ expect(obj).to.respondTo('addChild');
+ expect(obj).to.respondTo('addChildAt');
+ expect(obj).to.respondTo('swapChildren');
+ expect(obj).to.respondTo('getChildAt');
+ expect(obj).to.respondTo('removeChild');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('children.length', 0);
+}
diff --git a/test/lib/pixi/display/Sprite.js b/test/lib/pixi/display/Sprite.js
new file mode 100644
index 0000000..cc7a2d6
--- /dev/null
+++ b/test/lib/pixi/display/Sprite.js
@@ -0,0 +1,28 @@
+
+function pixi_display_Sprite_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Sprite);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', true);
+ expect(obj).to.have.property('stage', null);
+
+ expect(obj).to.have.property('anchor');
+ pixi_core_Point_confirm(obj.anchor, 0, 0);
+
+ expect(obj).to.have.property('blendMode', PIXI.blendModes.NORMAL);
+ expect(obj).to.have.property('width', 1); // TODO: is 1 expected
+ expect(obj).to.have.property('height', 1); // TODO: is 1 expected
+
+ // FIXME: Just make this a boolean that is always there
+ expect(!!obj.updateFrame).to.equal(obj.texture.baseTexture.hasLoaded);
+
+ expect(obj).to.have.property('texture');
+ pixi_textures_Texture_confirmNew(obj.texture, done);
+}
diff --git a/test/lib/pixi/extras/Strip.js b/test/lib/pixi/extras/Strip.js
new file mode 100644
index 0000000..8927a8a
--- /dev/null
+++ b/test/lib/pixi/extras/Strip.js
@@ -0,0 +1,12 @@
+
+function pixi_extras_Strip_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Strip);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ // TODO: Test properties
+}
diff --git a/test/lib/pixi/textures/Texture.js b/test/lib/pixi/textures/Texture.js
new file mode 100644
index 0000000..d5867b6
--- /dev/null
+++ b/test/lib/pixi/textures/Texture.js
@@ -0,0 +1,31 @@
+
+function pixi_textures_Texture_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ function confirmFrameDone() {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, obj.baseTexture.width, obj.baseTexture.height);
+
+ expect(obj).to.have.property('width', obj.baseTexture.width);
+ expect(obj).to.have.property('height', obj.baseTexture.height);
+ done();
+ }
+
+ expect(obj).to.be.an.instanceof(PIXI.Texture);
+ pixi_utils_EventTarget_like(obj);
+
+ expect(obj).to.have.property('baseTexture')
+ .and.to.be.an.instanceof(PIXI.BaseTexture);
+
+ expect(obj).to.have.property('scope', obj);
+
+ expect(obj).to.have.property('trim');
+ pixi_core_Point_confirm(obj.trim, 0, 0);
+
+ expect(obj).to.have.property('frame');
+ if (obj.baseTexture.hasLoaded) {
+ confirmFrameDone();
+ } else {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, 1, 1);
+ obj.addEventListener('update', confirmFrameDone);
+ }
+}
diff --git a/test/lib/pixi/utils/EventTarget.js b/test/lib/pixi/utils/EventTarget.js
new file mode 100644
index 0000000..7b1dcfa
--- /dev/null
+++ b/test/lib/pixi/utils/EventTarget.js
@@ -0,0 +1,8 @@
+
+function pixi_utils_EventTarget_like(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.respondTo('addEventListener');
+ expect(obj).to.respondTo('dispatchEvent');
+ expect(obj).to.respondTo('removeEventListener');
+}
diff --git a/test/lib/qunit-1.11.0.css b/test/lib/qunit-1.11.0.css
deleted file mode 100644
index d7fc0c8..0000000
--- a/test/lib/qunit-1.11.0.css
+++ /dev/null
@@ -1,244 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-/** Font Family and Sizes */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
- font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
-}
-
-#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
-#qunit-tests { font-size: smaller; }
-
-
-/** Resets */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter {
- margin: 0;
- padding: 0;
-}
-
-
-/** Header */
-
-#qunit-header {
- padding: 0.5em 0 0.5em 1em;
-
- color: #8699a4;
- background-color: #0d3349;
-
- font-size: 1.5em;
- line-height: 1em;
- font-weight: normal;
-
- border-radius: 5px 5px 0 0;
- -moz-border-radius: 5px 5px 0 0;
- -webkit-border-top-right-radius: 5px;
- -webkit-border-top-left-radius: 5px;
-}
-
-#qunit-header a {
- text-decoration: none;
- color: #c2ccd1;
-}
-
-#qunit-header a:hover,
-#qunit-header a:focus {
- color: #fff;
-}
-
-#qunit-testrunner-toolbar label {
- display: inline-block;
- padding: 0 .5em 0 .1em;
-}
-
-#qunit-banner {
- height: 5px;
-}
-
-#qunit-testrunner-toolbar {
- padding: 0.5em 0 0.5em 2em;
- color: #5E740B;
- background-color: #eee;
- overflow: hidden;
-}
-
-#qunit-userAgent {
- padding: 0.5em 0 0.5em 2.5em;
- background-color: #2b81af;
- color: #fff;
- text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
-}
-
-#qunit-modulefilter-container {
- float: right;
-}
-
-/** Tests: Pass/Fail */
-
-#qunit-tests {
- list-style-position: inside;
-}
-
-#qunit-tests li {
- padding: 0.4em 0.5em 0.4em 2.5em;
- border-bottom: 1px solid #fff;
- list-style-position: inside;
-}
-
-#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running {
- display: none;
-}
-
-#qunit-tests li strong {
- cursor: pointer;
-}
-
-#qunit-tests li a {
- padding: 0.5em;
- color: #c2ccd1;
- text-decoration: none;
-}
-#qunit-tests li a:hover,
-#qunit-tests li a:focus {
- color: #000;
-}
-
-#qunit-tests li .runtime {
- float: right;
- font-size: smaller;
-}
-
-.qunit-assert-list {
- margin-top: 0.5em;
- padding: 0.5em;
-
- background-color: #fff;
-
- border-radius: 5px;
- -moz-border-radius: 5px;
- -webkit-border-radius: 5px;
-}
-
-.qunit-collapsed {
- display: none;
-}
-
-#qunit-tests table {
- border-collapse: collapse;
- margin-top: .2em;
-}
-
-#qunit-tests th {
- text-align: right;
- vertical-align: top;
- padding: 0 .5em 0 0;
-}
-
-#qunit-tests td {
- vertical-align: top;
-}
-
-#qunit-tests pre {
- margin: 0;
- white-space: pre-wrap;
- word-wrap: break-word;
-}
-
-#qunit-tests del {
- background-color: #e0f2be;
- color: #374e0c;
- text-decoration: none;
-}
-
-#qunit-tests ins {
- background-color: #ffcaca;
- color: #500;
- text-decoration: none;
-}
-
-/*** Test Counts */
-
-#qunit-tests b.counts { color: black; }
-#qunit-tests b.passed { color: #5E740B; }
-#qunit-tests b.failed { color: #710909; }
-
-#qunit-tests li li {
- padding: 5px;
- background-color: #fff;
- border-bottom: none;
- list-style-position: inside;
-}
-
-/*** Passing Styles */
-
-#qunit-tests li li.pass {
- color: #3c510c;
- background-color: #fff;
- border-left: 10px solid #C6E746;
-}
-
-#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
-#qunit-tests .pass .test-name { color: #366097; }
-
-#qunit-tests .pass .test-actual,
-#qunit-tests .pass .test-expected { color: #999999; }
-
-#qunit-banner.qunit-pass { background-color: #C6E746; }
-
-/*** Failing Styles */
-
-#qunit-tests li li.fail {
- color: #710909;
- background-color: #fff;
- border-left: 10px solid #EE5757;
- white-space: pre;
-}
-
-#qunit-tests > li:last-child {
- border-radius: 0 0 5px 5px;
- -moz-border-radius: 0 0 5px 5px;
- -webkit-border-bottom-right-radius: 5px;
- -webkit-border-bottom-left-radius: 5px;
-}
-
-#qunit-tests .fail { color: #000000; background-color: #EE5757; }
-#qunit-tests .fail .test-name,
-#qunit-tests .fail .module-name { color: #000000; }
-
-#qunit-tests .fail .test-actual { color: #EE5757; }
-#qunit-tests .fail .test-expected { color: green; }
-
-#qunit-banner.qunit-fail { background-color: #EE5757; }
-
-
-/** Result */
-
-#qunit-testresult {
- padding: 0.5em 0.5em 0.5em 2.5em;
-
- color: #2b81af;
- background-color: #D2E0E6;
-
- border-bottom: 1px solid white;
-}
-#qunit-testresult .module-name {
- font-weight: bold;
-}
-
-/** Fixture */
-
-#qunit-fixture {
- position: absolute;
- top: -10000px;
- left: -10000px;
- width: 1000px;
- height: 1000px;
-}
diff --git a/test/lib/qunit-1.11.0.js b/test/lib/qunit-1.11.0.js
deleted file mode 100644
index 302545f..0000000
--- a/test/lib/qunit-1.11.0.js
+++ /dev/null
@@ -1,2152 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-(function( window ) {
-
-var QUnit,
- assert,
- config,
- onErrorFnPrev,
- testId = 0,
- fileName = (sourceFromStacktrace( 0 ) || "" ).replace(/(:\d+)+\)?/, "").replace(/.+\//, ""),
- toString = Object.prototype.toString,
- hasOwn = Object.prototype.hasOwnProperty,
- // Keep a local reference to Date (GH-283)
- Date = window.Date,
- defined = {
- setTimeout: typeof window.setTimeout !== "undefined",
- sessionStorage: (function() {
- var x = "qunit-test-string";
- try {
- sessionStorage.setItem( x, x );
- sessionStorage.removeItem( x );
- return true;
- } catch( e ) {
- return false;
- }
- }())
- },
- /**
- * Provides a normalized error string, correcting an issue
- * with IE 7 (and prior) where Error.prototype.toString is
- * not properly implemented
- *
- * Based on http://es5.github.com/#x15.11.4.4
- *
- * @param {String|Error} error
- * @return {String} error message
- */
- errorString = function( error ) {
- var name, message,
- errorString = error.toString();
- if ( errorString.substring( 0, 7 ) === "[object" ) {
- name = error.name ? error.name.toString() : "Error";
- message = error.message ? error.message.toString() : "";
- if ( name && message ) {
- return name + ": " + message;
- } else if ( name ) {
- return name;
- } else if ( message ) {
- return message;
- } else {
- return "Error";
- }
- } else {
- return errorString;
- }
- },
- /**
- * Makes a clone of an object using only Array or Object as base,
- * and copies over the own enumerable properties.
- *
- * @param {Object} obj
- * @return {Object} New object with only the own properties (recursively).
- */
- objectValues = function( obj ) {
- // Grunt 0.3.x uses an older version of jshint that still has jshint/jshint#392.
- /*jshint newcap: false */
- var key, val,
- vals = QUnit.is( "array", obj ) ? [] : {};
- for ( key in obj ) {
- if ( hasOwn.call( obj, key ) ) {
- val = obj[key];
- vals[key] = val === Object(val) ? objectValues(val) : val;
- }
- }
- return vals;
- };
-
-function Test( settings ) {
- extend( this, settings );
- this.assertions = [];
- this.testNumber = ++Test.count;
-}
-
-Test.count = 0;
-
-Test.prototype = {
- init: function() {
- var a, b, li,
- tests = id( "qunit-tests" );
-
- if ( tests ) {
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml;
-
- // `a` initialized at top of scope
- a = document.createElement( "a" );
- a.innerHTML = "Rerun";
- a.href = QUnit.url({ testNumber: this.testNumber });
-
- li = document.createElement( "li" );
- li.appendChild( b );
- li.appendChild( a );
- li.className = "running";
- li.id = this.id = "qunit-test-output" + testId++;
-
- tests.appendChild( li );
- }
- },
- setup: function() {
- if ( this.module !== config.previousModule ) {
- if ( config.previousModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.previousModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
- config.previousModule = this.module;
- config.moduleStats = { all: 0, bad: 0 };
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- } else if ( config.autorun ) {
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- }
-
- config.current = this;
-
- this.testEnvironment = extend({
- setup: function() {},
- teardown: function() {}
- }, this.moduleTestEnvironment );
-
- this.started = +new Date();
- runLoggingCallbacks( "testStart", QUnit, {
- name: this.testName,
- module: this.module
- });
-
- // allow utility functions to access the current test environment
- // TODO why??
- QUnit.current_testEnvironment = this.testEnvironment;
-
- if ( !config.pollution ) {
- saveGlobal();
- }
- if ( config.notrycatch ) {
- this.testEnvironment.setup.call( this.testEnvironment );
- return;
- }
- try {
- this.testEnvironment.setup.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Setup failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- },
- run: function() {
- config.current = this;
-
- var running = id( "qunit-testresult" );
-
- if ( running ) {
- running.innerHTML = "Running:
" + this.nameHtml;
- }
-
- if ( this.async ) {
- QUnit.stop();
- }
-
- this.callbackStarted = +new Date();
-
- if ( config.notrycatch ) {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- return;
- }
-
- try {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- } catch( e ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
-
- QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + " " + this.stack + ": " + ( e.message || e ), extractStacktrace( e, 0 ) );
- // else next test will carry the responsibility
- saveGlobal();
-
- // Restart the tests if they're blocking
- if ( config.blocking ) {
- QUnit.start();
- }
- }
- },
- teardown: function() {
- config.current = this;
- if ( config.notrycatch ) {
- if ( typeof this.callbackRuntime === "undefined" ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
- }
- this.testEnvironment.teardown.call( this.testEnvironment );
- return;
- } else {
- try {
- this.testEnvironment.teardown.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Teardown failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- }
- checkPollution();
- },
- finish: function() {
- config.current = this;
- if ( config.requireExpects && this.expected === null ) {
- QUnit.pushFailure( "Expected number of assertions to be defined, but expect() was not called.", this.stack );
- } else if ( this.expected !== null && this.expected !== this.assertions.length ) {
- QUnit.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack );
- } else if ( this.expected === null && !this.assertions.length ) {
- QUnit.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions.", this.stack );
- }
-
- var i, assertion, a, b, time, li, ol,
- test = this,
- good = 0,
- bad = 0,
- tests = id( "qunit-tests" );
-
- this.runtime = +new Date() - this.started;
- config.stats.all += this.assertions.length;
- config.moduleStats.all += this.assertions.length;
-
- if ( tests ) {
- ol = document.createElement( "ol" );
- ol.className = "qunit-assert-list";
-
- for ( i = 0; i < this.assertions.length; i++ ) {
- assertion = this.assertions[i];
-
- li = document.createElement( "li" );
- li.className = assertion.result ? "pass" : "fail";
- li.innerHTML = assertion.message || ( assertion.result ? "okay" : "failed" );
- ol.appendChild( li );
-
- if ( assertion.result ) {
- good++;
- } else {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
-
- // store result when possible
- if ( QUnit.config.reorder && defined.sessionStorage ) {
- if ( bad ) {
- sessionStorage.setItem( "qunit-test-" + this.module + "-" + this.testName, bad );
- } else {
- sessionStorage.removeItem( "qunit-test-" + this.module + "-" + this.testName );
- }
- }
-
- if ( bad === 0 ) {
- addClass( ol, "qunit-collapsed" );
- }
-
- // `b` initialized at top of scope
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml + " (" + bad + ", " + good + ", " + this.assertions.length + ")";
-
- addEvent(b, "click", function() {
- var next = b.parentNode.lastChild,
- collapsed = hasClass( next, "qunit-collapsed" );
- ( collapsed ? removeClass : addClass )( next, "qunit-collapsed" );
- });
-
- addEvent(b, "dblclick", function( e ) {
- var target = e && e.target ? e.target : window.event.srcElement;
- if ( target.nodeName.toLowerCase() === "span" || target.nodeName.toLowerCase() === "b" ) {
- target = target.parentNode;
- }
- if ( window.location && target.nodeName.toLowerCase() === "strong" ) {
- window.location = QUnit.url({ testNumber: test.testNumber });
- }
- });
-
- // `time` initialized at top of scope
- time = document.createElement( "span" );
- time.className = "runtime";
- time.innerHTML = this.runtime + " ms";
-
- // `li` initialized at top of scope
- li = id( this.id );
- li.className = bad ? "fail" : "pass";
- li.removeChild( li.firstChild );
- a = li.firstChild;
- li.appendChild( b );
- li.appendChild( a );
- li.appendChild( time );
- li.appendChild( ol );
-
- } else {
- for ( i = 0; i < this.assertions.length; i++ ) {
- if ( !this.assertions[i].result ) {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
- }
-
- runLoggingCallbacks( "testDone", QUnit, {
- name: this.testName,
- module: this.module,
- failed: bad,
- passed: this.assertions.length - bad,
- total: this.assertions.length,
- duration: this.runtime
- });
-
- QUnit.reset();
-
- config.current = undefined;
- },
-
- queue: function() {
- var bad,
- test = this;
-
- synchronize(function() {
- test.init();
- });
- function run() {
- // each of these can by async
- synchronize(function() {
- test.setup();
- });
- synchronize(function() {
- test.run();
- });
- synchronize(function() {
- test.teardown();
- });
- synchronize(function() {
- test.finish();
- });
- }
-
- // `bad` initialized at top of scope
- // defer when previous test run passed, if storage is available
- bad = QUnit.config.reorder && defined.sessionStorage &&
- +sessionStorage.getItem( "qunit-test-" + this.module + "-" + this.testName );
-
- if ( bad ) {
- run();
- } else {
- synchronize( run, true );
- }
- }
-};
-
-// Root QUnit object.
-// `QUnit` initialized at top of scope
-QUnit = {
-
- // call on start of module test to prepend name to all tests
- module: function( name, testEnvironment ) {
- config.currentModule = name;
- config.currentModuleTestEnvironment = testEnvironment;
- config.modules[name] = true;
- },
-
- asyncTest: function( testName, expected, callback ) {
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- QUnit.test( testName, expected, callback, true );
- },
-
- test: function( testName, expected, callback, async ) {
- var test,
- nameHtml = "" + escapeText( testName ) + "";
-
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- if ( config.currentModule ) {
- nameHtml = "" + escapeText( config.currentModule ) + ": " + nameHtml;
- }
-
- test = new Test({
- nameHtml: nameHtml,
- testName: testName,
- expected: expected,
- async: async,
- callback: callback,
- module: config.currentModule,
- moduleTestEnvironment: config.currentModuleTestEnvironment,
- stack: sourceFromStacktrace( 2 )
- });
-
- if ( !validTest( test ) ) {
- return;
- }
-
- test.queue();
- },
-
- // Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through.
- expect: function( asserts ) {
- if (arguments.length === 1) {
- config.current.expected = asserts;
- } else {
- return config.current.expected;
- }
- },
-
- start: function( count ) {
- // QUnit hasn't been initialized yet.
- // Note: RequireJS (et al) may delay onLoad
- if ( config.semaphore === undefined ) {
- QUnit.begin(function() {
- // This is triggered at the top of QUnit.load, push start() to the event loop, to allow QUnit.load to finish first
- setTimeout(function() {
- QUnit.start( count );
- });
- });
- return;
- }
-
- config.semaphore -= count || 1;
- // don't start until equal number of stop-calls
- if ( config.semaphore > 0 ) {
- return;
- }
- // ignore if start is called more often then stop
- if ( config.semaphore < 0 ) {
- config.semaphore = 0;
- QUnit.pushFailure( "Called start() while already started (QUnit.config.semaphore was 0 already)", null, sourceFromStacktrace(2) );
- return;
- }
- // A slight delay, to avoid any current callbacks
- if ( defined.setTimeout ) {
- window.setTimeout(function() {
- if ( config.semaphore > 0 ) {
- return;
- }
- if ( config.timeout ) {
- clearTimeout( config.timeout );
- }
-
- config.blocking = false;
- process( true );
- }, 13);
- } else {
- config.blocking = false;
- process( true );
- }
- },
-
- stop: function( count ) {
- config.semaphore += count || 1;
- config.blocking = true;
-
- if ( config.testTimeout && defined.setTimeout ) {
- clearTimeout( config.timeout );
- config.timeout = window.setTimeout(function() {
- QUnit.ok( false, "Test timed out" );
- config.semaphore = 1;
- QUnit.start();
- }, config.testTimeout );
- }
- }
-};
-
-// `assert` initialized at top of scope
-// Asssert helpers
-// All of these must either call QUnit.push() or manually do:
-// - runLoggingCallbacks( "log", .. );
-// - config.current.assertions.push({ .. });
-// We attach it to the QUnit object *after* we expose the public API,
-// otherwise `assert` will become a global variable in browsers (#341).
-assert = {
- /**
- * Asserts rough true-ish result.
- * @name ok
- * @function
- * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" );
- */
- ok: function( result, msg ) {
- if ( !config.current ) {
- throw new Error( "ok() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
- result = !!result;
-
- var source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: msg
- };
-
- msg = escapeText( msg || (result ? "okay" : "failed" ) );
- msg = "" + msg + "";
-
- if ( !result ) {
- source = sourceFromStacktrace( 2 );
- if ( source ) {
- details.source = source;
- msg += "Source: | " + escapeText( source ) + " |
---|
";
- }
- }
- runLoggingCallbacks( "log", QUnit, details );
- config.current.assertions.push({
- result: result,
- message: msg
- });
- },
-
- /**
- * Assert that the first two arguments are equal, with an optional message.
- * Prints out both actual and expected values.
- * @name equal
- * @function
- * @example equal( format( "Received {0} bytes.", 2), "Received 2 bytes.", "format() replaces {0} with next argument" );
- */
- equal: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected == actual, actual, expected, message );
- },
-
- /**
- * @name notEqual
- * @function
- */
- notEqual: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected != actual, actual, expected, message );
- },
-
- /**
- * @name propEqual
- * @function
- */
- propEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notPropEqual
- * @function
- */
- notPropEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name deepEqual
- * @function
- */
- deepEqual: function( actual, expected, message ) {
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notDeepEqual
- * @function
- */
- notDeepEqual: function( actual, expected, message ) {
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name strictEqual
- * @function
- */
- strictEqual: function( actual, expected, message ) {
- QUnit.push( expected === actual, actual, expected, message );
- },
-
- /**
- * @name notStrictEqual
- * @function
- */
- notStrictEqual: function( actual, expected, message ) {
- QUnit.push( expected !== actual, actual, expected, message );
- },
-
- "throws": function( block, expected, message ) {
- var actual,
- expectedOutput = expected,
- ok = false;
-
- // 'expected' is optional
- if ( typeof expected === "string" ) {
- message = expected;
- expected = null;
- }
-
- config.current.ignoreGlobalErrors = true;
- try {
- block.call( config.current.testEnvironment );
- } catch (e) {
- actual = e;
- }
- config.current.ignoreGlobalErrors = false;
-
- if ( actual ) {
- // we don't want to validate thrown error
- if ( !expected ) {
- ok = true;
- expectedOutput = null;
- // expected is a regexp
- } else if ( QUnit.objectType( expected ) === "regexp" ) {
- ok = expected.test( errorString( actual ) );
- // expected is a constructor
- } else if ( actual instanceof expected ) {
- ok = true;
- // expected is a validation function which returns true is validation passed
- } else if ( expected.call( {}, actual ) === true ) {
- expectedOutput = null;
- ok = true;
- }
-
- QUnit.push( ok, actual, expectedOutput, message );
- } else {
- QUnit.pushFailure( message, null, 'No exception was thrown.' );
- }
- }
-};
-
-/**
- * @deprecate since 1.8.0
- * Kept assertion helpers in root for backwards compatibility.
- */
-extend( QUnit, assert );
-
-/**
- * @deprecated since 1.9.0
- * Kept root "raises()" for backwards compatibility.
- * (Note that we don't introduce assert.raises).
- */
-QUnit.raises = assert[ "throws" ];
-
-/**
- * @deprecated since 1.0.0, replaced with error pushes since 1.3.0
- * Kept to avoid TypeErrors for undefined methods.
- */
-QUnit.equals = function() {
- QUnit.push( false, false, false, "QUnit.equals has been deprecated since 2009 (e88049a0), use QUnit.equal instead" );
-};
-QUnit.same = function() {
- QUnit.push( false, false, false, "QUnit.same has been deprecated since 2009 (e88049a0), use QUnit.deepEqual instead" );
-};
-
-// We want access to the constructor's prototype
-(function() {
- function F() {}
- F.prototype = QUnit;
- QUnit = new F();
- // Make F QUnit's constructor so that we can add to the prototype later
- QUnit.constructor = F;
-}());
-
-/**
- * Config object: Maintain internal state
- * Later exposed as QUnit.config
- * `config` initialized at top of scope
- */
-config = {
- // The queue of tests to run
- queue: [],
-
- // block until document ready
- blocking: true,
-
- // when enabled, show only failing tests
- // gets persisted through sessionStorage and can be changed in UI via checkbox
- hidepassed: false,
-
- // by default, run previously failed tests first
- // very useful in combination with "Hide passed tests" checked
- reorder: true,
-
- // by default, modify document.title when suite is done
- altertitle: true,
-
- // when enabled, all tests must call expect()
- requireExpects: false,
-
- // add checkboxes that are persisted in the query-string
- // when enabled, the id is set to `true` as a `QUnit.config` property
- urlConfig: [
- {
- id: "noglobals",
- label: "Check for Globals",
- tooltip: "Enabling this will test if any test introduces new properties on the `window` object. Stored as query-strings."
- },
- {
- id: "notrycatch",
- label: "No try-catch",
- tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging exceptions in IE reasonable. Stored as query-strings."
- }
- ],
-
- // Set of all modules.
- modules: {},
-
- // logging callback queues
- begin: [],
- done: [],
- log: [],
- testStart: [],
- testDone: [],
- moduleStart: [],
- moduleDone: []
-};
-
-// Export global variables, unless an 'exports' object exists,
-// in that case we assume we're in CommonJS (dealt with on the bottom of the script)
-if ( typeof exports === "undefined" ) {
- extend( window, QUnit );
-
- // Expose QUnit object
- window.QUnit = QUnit;
-}
-
-// Initialize more QUnit.config and QUnit.urlParams
-(function() {
- var i,
- location = window.location || { search: "", protocol: "file:" },
- params = location.search.slice( 1 ).split( "&" ),
- length = params.length,
- urlParams = {},
- current;
-
- if ( params[ 0 ] ) {
- for ( i = 0; i < length; i++ ) {
- current = params[ i ].split( "=" );
- current[ 0 ] = decodeURIComponent( current[ 0 ] );
- // allow just a key to turn on a flag, e.g., test.html?noglobals
- current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true;
- urlParams[ current[ 0 ] ] = current[ 1 ];
- }
- }
-
- QUnit.urlParams = urlParams;
-
- // String search anywhere in moduleName+testName
- config.filter = urlParams.filter;
-
- // Exact match of the module name
- config.module = urlParams.module;
-
- config.testNumber = parseInt( urlParams.testNumber, 10 ) || null;
-
- // Figure out if we're running the tests from a server or not
- QUnit.isLocal = location.protocol === "file:";
-}());
-
-// Extend QUnit object,
-// these after set here because they should not be exposed as global functions
-extend( QUnit, {
- assert: assert,
-
- config: config,
-
- // Initialize the configuration options
- init: function() {
- extend( config, {
- stats: { all: 0, bad: 0 },
- moduleStats: { all: 0, bad: 0 },
- started: +new Date(),
- updateRate: 1000,
- blocking: false,
- autostart: true,
- autorun: false,
- filter: "",
- queue: [],
- semaphore: 1
- });
-
- var tests, banner, result,
- qunit = id( "qunit" );
-
- if ( qunit ) {
- qunit.innerHTML =
- "" +
- "" +
- "" +
- "" +
- "
";
- }
-
- tests = id( "qunit-tests" );
- banner = id( "qunit-banner" );
- result = id( "qunit-testresult" );
-
- if ( tests ) {
- tests.innerHTML = "";
- }
-
- if ( banner ) {
- banner.className = "";
- }
-
- if ( result ) {
- result.parentNode.removeChild( result );
- }
-
- if ( tests ) {
- result = document.createElement( "p" );
- result.id = "qunit-testresult";
- result.className = "result";
- tests.parentNode.insertBefore( result, tests );
- result.innerHTML = "Running...
";
- }
- },
-
- // Resets the test setup. Useful for tests that modify the DOM.
- reset: function() {
- var fixture = id( "qunit-fixture" );
- if ( fixture ) {
- fixture.innerHTML = config.fixture;
- }
- },
-
- // Trigger an event on an element.
- // @example triggerEvent( document.body, "click" );
- triggerEvent: function( elem, type, event ) {
- if ( document.createEvent ) {
- event = document.createEvent( "MouseEvents" );
- event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView,
- 0, 0, 0, 0, 0, false, false, false, false, 0, null);
-
- elem.dispatchEvent( event );
- } else if ( elem.fireEvent ) {
- elem.fireEvent( "on" + type );
- }
- },
-
- // Safe object type checking
- is: function( type, obj ) {
- return QUnit.objectType( obj ) === type;
- },
-
- objectType: function( obj ) {
- if ( typeof obj === "undefined" ) {
- return "undefined";
- // consider: typeof null === object
- }
- if ( obj === null ) {
- return "null";
- }
-
- var match = toString.call( obj ).match(/^\[object\s(.*)\]$/),
- type = match && match[1] || "";
-
- switch ( type ) {
- case "Number":
- if ( isNaN(obj) ) {
- return "nan";
- }
- return "number";
- case "String":
- case "Boolean":
- case "Array":
- case "Date":
- case "RegExp":
- case "Function":
- return type.toLowerCase();
- }
- if ( typeof obj === "object" ) {
- return "object";
- }
- return undefined;
- },
-
- push: function( result, actual, expected, message ) {
- if ( !config.current ) {
- throw new Error( "assertion outside test context, was " + sourceFromStacktrace() );
- }
-
- var output, source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: message,
- actual: actual,
- expected: expected
- };
-
- message = escapeText( message ) || ( result ? "okay" : "failed" );
- message = "" + message + "";
- output = message;
-
- if ( !result ) {
- expected = escapeText( QUnit.jsDump.parse(expected) );
- actual = escapeText( QUnit.jsDump.parse(actual) );
- output += "Expected: | " + expected + " |
";
-
- if ( actual !== expected ) {
- output += "Result: | " + actual + " |
";
- output += "Diff: | " + QUnit.diff( expected, actual ) + " |
";
- }
-
- source = sourceFromStacktrace();
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
- }
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: !!result,
- message: output
- });
- },
-
- pushFailure: function( message, source, actual ) {
- if ( !config.current ) {
- throw new Error( "pushFailure() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
-
- var output,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: false,
- message: message
- };
-
- message = escapeText( message ) || "error";
- message = "" + message + "";
- output = message;
-
- output += "";
-
- if ( actual ) {
- output += "Result: | " + escapeText( actual ) + " |
";
- }
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: false,
- message: output
- });
- },
-
- url: function( params ) {
- params = extend( extend( {}, QUnit.urlParams ), params );
- var key,
- querystring = "?";
-
- for ( key in params ) {
- if ( !hasOwn.call( params, key ) ) {
- continue;
- }
- querystring += encodeURIComponent( key ) + "=" +
- encodeURIComponent( params[ key ] ) + "&";
- }
- return window.location.protocol + "//" + window.location.host +
- window.location.pathname + querystring.slice( 0, -1 );
- },
-
- extend: extend,
- id: id,
- addEvent: addEvent
- // load, equiv, jsDump, diff: Attached later
-});
-
-/**
- * @deprecated: Created for backwards compatibility with test runner that set the hook function
- * into QUnit.{hook}, instead of invoking it and passing the hook function.
- * QUnit.constructor is set to the empty F() above so that we can add to it's prototype here.
- * Doing this allows us to tell if the following methods have been overwritten on the actual
- * QUnit object.
- */
-extend( QUnit.constructor.prototype, {
-
- // Logging callbacks; all receive a single argument with the listed properties
- // run test/logs.html for any related changes
- begin: registerLoggingCallback( "begin" ),
-
- // done: { failed, passed, total, runtime }
- done: registerLoggingCallback( "done" ),
-
- // log: { result, actual, expected, message }
- log: registerLoggingCallback( "log" ),
-
- // testStart: { name }
- testStart: registerLoggingCallback( "testStart" ),
-
- // testDone: { name, failed, passed, total, duration }
- testDone: registerLoggingCallback( "testDone" ),
-
- // moduleStart: { name }
- moduleStart: registerLoggingCallback( "moduleStart" ),
-
- // moduleDone: { name, failed, passed, total }
- moduleDone: registerLoggingCallback( "moduleDone" )
-});
-
-if ( typeof document === "undefined" || document.readyState === "complete" ) {
- config.autorun = true;
-}
-
-QUnit.load = function() {
- runLoggingCallbacks( "begin", QUnit, {} );
-
- // Initialize the config, saving the execution queue
- var banner, filter, i, label, len, main, ol, toolbar, userAgent, val,
- urlConfigCheckboxesContainer, urlConfigCheckboxes, moduleFilter,
- numModules = 0,
- moduleFilterHtml = "",
- urlConfigHtml = "",
- oldconfig = extend( {}, config );
-
- QUnit.init();
- extend(config, oldconfig);
-
- config.blocking = false;
-
- len = config.urlConfig.length;
-
- for ( i = 0; i < len; i++ ) {
- val = config.urlConfig[i];
- if ( typeof val === "string" ) {
- val = {
- id: val,
- label: val,
- tooltip: "[no tooltip available]"
- };
- }
- config[ val.id ] = QUnit.urlParams[ val.id ];
- urlConfigHtml += "";
- }
-
- moduleFilterHtml += "";
-
- // `userAgent` initialized at top of scope
- userAgent = id( "qunit-userAgent" );
- if ( userAgent ) {
- userAgent.innerHTML = navigator.userAgent;
- }
-
- // `banner` initialized at top of scope
- banner = id( "qunit-header" );
- if ( banner ) {
- banner.innerHTML = "" + banner.innerHTML + " ";
- }
-
- // `toolbar` initialized at top of scope
- toolbar = id( "qunit-testrunner-toolbar" );
- if ( toolbar ) {
- // `filter` initialized at top of scope
- filter = document.createElement( "input" );
- filter.type = "checkbox";
- filter.id = "qunit-filter-pass";
-
- addEvent( filter, "click", function() {
- var tmp,
- ol = document.getElementById( "qunit-tests" );
-
- if ( filter.checked ) {
- ol.className = ol.className + " hidepass";
- } else {
- tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " ";
- ol.className = tmp.replace( / hidepass /, " " );
- }
- if ( defined.sessionStorage ) {
- if (filter.checked) {
- sessionStorage.setItem( "qunit-filter-passed-tests", "true" );
- } else {
- sessionStorage.removeItem( "qunit-filter-passed-tests" );
- }
- }
- });
-
- if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem( "qunit-filter-passed-tests" ) ) {
- filter.checked = true;
- // `ol` initialized at top of scope
- ol = document.getElementById( "qunit-tests" );
- ol.className = ol.className + " hidepass";
- }
- toolbar.appendChild( filter );
-
- // `label` initialized at top of scope
- label = document.createElement( "label" );
- label.setAttribute( "for", "qunit-filter-pass" );
- label.setAttribute( "title", "Only show tests and assertons that fail. Stored in sessionStorage." );
- label.innerHTML = "Hide passed tests";
- toolbar.appendChild( label );
-
- urlConfigCheckboxesContainer = document.createElement("span");
- urlConfigCheckboxesContainer.innerHTML = urlConfigHtml;
- urlConfigCheckboxes = urlConfigCheckboxesContainer.getElementsByTagName("input");
- // For oldIE support:
- // * Add handlers to the individual elements instead of the container
- // * Use "click" instead of "change"
- // * Fallback from event.target to event.srcElement
- addEvents( urlConfigCheckboxes, "click", function( event ) {
- var params = {},
- target = event.target || event.srcElement;
- params[ target.name ] = target.checked ? true : undefined;
- window.location = QUnit.url( params );
- });
- toolbar.appendChild( urlConfigCheckboxesContainer );
-
- if (numModules > 1) {
- moduleFilter = document.createElement( 'span' );
- moduleFilter.setAttribute( 'id', 'qunit-modulefilter-container' );
- moduleFilter.innerHTML = moduleFilterHtml;
- addEvent( moduleFilter.lastChild, "change", function() {
- var selectBox = moduleFilter.getElementsByTagName("select")[0],
- selectedModule = decodeURIComponent(selectBox.options[selectBox.selectedIndex].value);
-
- window.location = QUnit.url( { module: ( selectedModule === "" ) ? undefined : selectedModule } );
- });
- toolbar.appendChild(moduleFilter);
- }
- }
-
- // `main` initialized at top of scope
- main = id( "qunit-fixture" );
- if ( main ) {
- config.fixture = main.innerHTML;
- }
-
- if ( config.autostart ) {
- QUnit.start();
- }
-};
-
-addEvent( window, "load", QUnit.load );
-
-// `onErrorFnPrev` initialized at top of scope
-// Preserve other handlers
-onErrorFnPrev = window.onerror;
-
-// Cover uncaught exceptions
-// Returning true will surpress the default browser handler,
-// returning false will let it run.
-window.onerror = function ( error, filePath, linerNr ) {
- var ret = false;
- if ( onErrorFnPrev ) {
- ret = onErrorFnPrev( error, filePath, linerNr );
- }
-
- // Treat return value as window.onerror itself does,
- // Only do our handling if not surpressed.
- if ( ret !== true ) {
- if ( QUnit.config.current ) {
- if ( QUnit.config.current.ignoreGlobalErrors ) {
- return true;
- }
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- } else {
- QUnit.test( "global failure", extend( function() {
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- }, { validTest: validTest } ) );
- }
- return false;
- }
-
- return ret;
-};
-
-function done() {
- config.autorun = true;
-
- // Log the last module results
- if ( config.currentModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.currentModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
-
- var i, key,
- banner = id( "qunit-banner" ),
- tests = id( "qunit-tests" ),
- runtime = +new Date() - config.started,
- passed = config.stats.all - config.stats.bad,
- html = [
- "Tests completed in ",
- runtime,
- " milliseconds.
",
- "",
- passed,
- " assertions of ",
- config.stats.all,
- " passed, ",
- config.stats.bad,
- " failed."
- ].join( "" );
-
- if ( banner ) {
- banner.className = ( config.stats.bad ? "qunit-fail" : "qunit-pass" );
- }
-
- if ( tests ) {
- id( "qunit-testresult" ).innerHTML = html;
- }
-
- if ( config.altertitle && typeof document !== "undefined" && document.title ) {
- // show ✖ for good, ✔ for bad suite result in title
- // use escape sequences in case file gets loaded with non-utf-8-charset
- document.title = [
- ( config.stats.bad ? "\u2716" : "\u2714" ),
- document.title.replace( /^[\u2714\u2716] /i, "" )
- ].join( " " );
- }
-
- // clear own sessionStorage items if all tests passed
- if ( config.reorder && defined.sessionStorage && config.stats.bad === 0 ) {
- // `key` & `i` initialized at top of scope
- for ( i = 0; i < sessionStorage.length; i++ ) {
- key = sessionStorage.key( i++ );
- if ( key.indexOf( "qunit-test-" ) === 0 ) {
- sessionStorage.removeItem( key );
- }
- }
- }
-
- // scroll back to top to show results
- if ( window.scrollTo ) {
- window.scrollTo(0, 0);
- }
-
- runLoggingCallbacks( "done", QUnit, {
- failed: config.stats.bad,
- passed: passed,
- total: config.stats.all,
- runtime: runtime
- });
-}
-
-/** @return Boolean: true if this test should be ran */
-function validTest( test ) {
- var include,
- filter = config.filter && config.filter.toLowerCase(),
- module = config.module && config.module.toLowerCase(),
- fullName = (test.module + ": " + test.testName).toLowerCase();
-
- // Internally-generated tests are always valid
- if ( test.callback && test.callback.validTest === validTest ) {
- delete test.callback.validTest;
- return true;
- }
-
- if ( config.testNumber ) {
- return test.testNumber === config.testNumber;
- }
-
- if ( module && ( !test.module || test.module.toLowerCase() !== module ) ) {
- return false;
- }
-
- if ( !filter ) {
- return true;
- }
-
- include = filter.charAt( 0 ) !== "!";
- if ( !include ) {
- filter = filter.slice( 1 );
- }
-
- // If the filter matches, we need to honour include
- if ( fullName.indexOf( filter ) !== -1 ) {
- return include;
- }
-
- // Otherwise, do the opposite
- return !include;
-}
-
-// so far supports only Firefox, Chrome and Opera (buggy), Safari (for real exceptions)
-// Later Safari and IE10 are supposed to support error.stack as well
-// See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack
-function extractStacktrace( e, offset ) {
- offset = offset === undefined ? 3 : offset;
-
- var stack, include, i;
-
- if ( e.stacktrace ) {
- // Opera
- return e.stacktrace.split( "\n" )[ offset + 3 ];
- } else if ( e.stack ) {
- // Firefox, Chrome
- stack = e.stack.split( "\n" );
- if (/^error$/i.test( stack[0] ) ) {
- stack.shift();
- }
- if ( fileName ) {
- include = [];
- for ( i = offset; i < stack.length; i++ ) {
- if ( stack[ i ].indexOf( fileName ) !== -1 ) {
- break;
- }
- include.push( stack[ i ] );
- }
- if ( include.length ) {
- return include.join( "\n" );
- }
- }
- return stack[ offset ];
- } else if ( e.sourceURL ) {
- // Safari, PhantomJS
- // hopefully one day Safari provides actual stacktraces
- // exclude useless self-reference for generated Error objects
- if ( /qunit.js$/.test( e.sourceURL ) ) {
- return;
- }
- // for actual exceptions, this is useful
- return e.sourceURL + ":" + e.line;
- }
-}
-function sourceFromStacktrace( offset ) {
- try {
- throw new Error();
- } catch ( e ) {
- return extractStacktrace( e, offset );
- }
-}
-
-/**
- * Escape text for attribute or text content.
- */
-function escapeText( s ) {
- if ( !s ) {
- return "";
- }
- s = s + "";
- // Both single quotes and double quotes (for attributes)
- return s.replace( /['"<>&]/g, function( s ) {
- switch( s ) {
- case '\'':
- return ''';
- case '"':
- return '"';
- case '<':
- return '<';
- case '>':
- return '>';
- case '&':
- return '&';
- }
- });
-}
-
-function synchronize( callback, last ) {
- config.queue.push( callback );
-
- if ( config.autorun && !config.blocking ) {
- process( last );
- }
-}
-
-function process( last ) {
- function next() {
- process( last );
- }
- var start = new Date().getTime();
- config.depth = config.depth ? config.depth + 1 : 1;
-
- while ( config.queue.length && !config.blocking ) {
- if ( !defined.setTimeout || config.updateRate <= 0 || ( ( new Date().getTime() - start ) < config.updateRate ) ) {
- config.queue.shift()();
- } else {
- window.setTimeout( next, 13 );
- break;
- }
- }
- config.depth--;
- if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) {
- done();
- }
-}
-
-function saveGlobal() {
- config.pollution = [];
-
- if ( config.noglobals ) {
- for ( var key in window ) {
- // in Opera sometimes DOM element ids show up here, ignore them
- if ( !hasOwn.call( window, key ) || /^qunit-test-output/.test( key ) ) {
- continue;
- }
- config.pollution.push( key );
- }
- }
-}
-
-function checkPollution() {
- var newGlobals,
- deletedGlobals,
- old = config.pollution;
-
- saveGlobal();
-
- newGlobals = diff( config.pollution, old );
- if ( newGlobals.length > 0 ) {
- QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join(", ") );
- }
-
- deletedGlobals = diff( old, config.pollution );
- if ( deletedGlobals.length > 0 ) {
- QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join(", ") );
- }
-}
-
-// returns a new Array with the elements that are in a but not in b
-function diff( a, b ) {
- var i, j,
- result = a.slice();
-
- for ( i = 0; i < result.length; i++ ) {
- for ( j = 0; j < b.length; j++ ) {
- if ( result[i] === b[j] ) {
- result.splice( i, 1 );
- i--;
- break;
- }
- }
- }
- return result;
-}
-
-function extend( a, b ) {
- for ( var prop in b ) {
- if ( b[ prop ] === undefined ) {
- delete a[ prop ];
-
- // Avoid "Member not found" error in IE8 caused by setting window.constructor
- } else if ( prop !== "constructor" || a !== window ) {
- a[ prop ] = b[ prop ];
- }
- }
-
- return a;
-}
-
-/**
- * @param {HTMLElement} elem
- * @param {string} type
- * @param {Function} fn
- */
-function addEvent( elem, type, fn ) {
- // Standards-based browsers
- if ( elem.addEventListener ) {
- elem.addEventListener( type, fn, false );
- // IE
- } else {
- elem.attachEvent( "on" + type, fn );
- }
-}
-
-/**
- * @param {Array|NodeList} elems
- * @param {string} type
- * @param {Function} fn
- */
-function addEvents( elems, type, fn ) {
- var i = elems.length;
- while ( i-- ) {
- addEvent( elems[i], type, fn );
- }
-}
-
-function hasClass( elem, name ) {
- return (" " + elem.className + " ").indexOf(" " + name + " ") > -1;
-}
-
-function addClass( elem, name ) {
- if ( !hasClass( elem, name ) ) {
- elem.className += (elem.className ? " " : "") + name;
- }
-}
-
-function removeClass( elem, name ) {
- var set = " " + elem.className + " ";
- // Class name may appear multiple times
- while ( set.indexOf(" " + name + " ") > -1 ) {
- set = set.replace(" " + name + " " , " ");
- }
- // If possible, trim it for prettiness, but not neccecarily
- elem.className = window.jQuery ? jQuery.trim( set ) : ( set.trim ? set.trim() : set );
-}
-
-function id( name ) {
- return !!( typeof document !== "undefined" && document && document.getElementById ) &&
- document.getElementById( name );
-}
-
-function registerLoggingCallback( key ) {
- return function( callback ) {
- config[key].push( callback );
- };
-}
-
-// Supports deprecated method of completely overwriting logging callbacks
-function runLoggingCallbacks( key, scope, args ) {
- var i, callbacks;
- if ( QUnit.hasOwnProperty( key ) ) {
- QUnit[ key ].call(scope, args );
- } else {
- callbacks = config[ key ];
- for ( i = 0; i < callbacks.length; i++ ) {
- callbacks[ i ].call( scope, args );
- }
- }
-}
-
-// Test for equality any JavaScript type.
-// Author: Philippe Rathé
-QUnit.equiv = (function() {
-
- // Call the o related callback with the given arguments.
- function bindCallbacks( o, callbacks, args ) {
- var prop = QUnit.objectType( o );
- if ( prop ) {
- if ( QUnit.objectType( callbacks[ prop ] ) === "function" ) {
- return callbacks[ prop ].apply( callbacks, args );
- } else {
- return callbacks[ prop ]; // or undefined
- }
- }
- }
-
- // the real equiv function
- var innerEquiv,
- // stack to decide between skip/abort functions
- callers = [],
- // stack to avoiding loops from circular referencing
- parents = [],
-
- getProto = Object.getPrototypeOf || function ( obj ) {
- return obj.__proto__;
- },
- callbacks = (function () {
-
- // for string, boolean, number and null
- function useStrictEquality( b, a ) {
- /*jshint eqeqeq:false */
- if ( b instanceof a.constructor || a instanceof b.constructor ) {
- // to catch short annotaion VS 'new' annotation of a
- // declaration
- // e.g. var i = 1;
- // var j = new Number(1);
- return a == b;
- } else {
- return a === b;
- }
- }
-
- return {
- "string": useStrictEquality,
- "boolean": useStrictEquality,
- "number": useStrictEquality,
- "null": useStrictEquality,
- "undefined": useStrictEquality,
-
- "nan": function( b ) {
- return isNaN( b );
- },
-
- "date": function( b, a ) {
- return QUnit.objectType( b ) === "date" && a.valueOf() === b.valueOf();
- },
-
- "regexp": function( b, a ) {
- return QUnit.objectType( b ) === "regexp" &&
- // the regex itself
- a.source === b.source &&
- // and its modifers
- a.global === b.global &&
- // (gmi) ...
- a.ignoreCase === b.ignoreCase &&
- a.multiline === b.multiline &&
- a.sticky === b.sticky;
- },
-
- // - skip when the property is a method of an instance (OOP)
- // - abort otherwise,
- // initial === would have catch identical references anyway
- "function": function() {
- var caller = callers[callers.length - 1];
- return caller !== Object && typeof caller !== "undefined";
- },
-
- "array": function( b, a ) {
- var i, j, len, loop;
-
- // b could be an object literal here
- if ( QUnit.objectType( b ) !== "array" ) {
- return false;
- }
-
- len = a.length;
- if ( len !== b.length ) {
- // safe and faster
- return false;
- }
-
- // track reference to avoid circular references
- parents.push( a );
- for ( i = 0; i < len; i++ ) {
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- loop = true;// dont rewalk array
- }
- }
- if ( !loop && !innerEquiv(a[i], b[i]) ) {
- parents.pop();
- return false;
- }
- }
- parents.pop();
- return true;
- },
-
- "object": function( b, a ) {
- var i, j, loop,
- // Default to true
- eq = true,
- aProperties = [],
- bProperties = [];
-
- // comparing constructors is more strict than using
- // instanceof
- if ( a.constructor !== b.constructor ) {
- // Allow objects with no prototype to be equivalent to
- // objects with Object as their constructor.
- if ( !(( getProto(a) === null && getProto(b) === Object.prototype ) ||
- ( getProto(b) === null && getProto(a) === Object.prototype ) ) ) {
- return false;
- }
- }
-
- // stack constructor before traversing properties
- callers.push( a.constructor );
- // track reference to avoid circular references
- parents.push( a );
-
- for ( i in a ) { // be strict: don't ensures hasOwnProperty
- // and go deep
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- // don't go down the same path twice
- loop = true;
- }
- }
- aProperties.push(i); // collect a's properties
-
- if (!loop && !innerEquiv( a[i], b[i] ) ) {
- eq = false;
- break;
- }
- }
-
- callers.pop(); // unstack, we are done
- parents.pop();
-
- for ( i in b ) {
- bProperties.push( i ); // collect b's properties
- }
-
- // Ensures identical properties name
- return eq && innerEquiv( aProperties.sort(), bProperties.sort() );
- }
- };
- }());
-
- innerEquiv = function() { // can take multiple arguments
- var args = [].slice.apply( arguments );
- if ( args.length < 2 ) {
- return true; // end transition
- }
-
- return (function( a, b ) {
- if ( a === b ) {
- return true; // catch the most you can
- } else if ( a === null || b === null || typeof a === "undefined" ||
- typeof b === "undefined" ||
- QUnit.objectType(a) !== QUnit.objectType(b) ) {
- return false; // don't lose time with error prone cases
- } else {
- return bindCallbacks(a, callbacks, [ b, a ]);
- }
-
- // apply transition with (1..n) arguments
- }( args[0], args[1] ) && arguments.callee.apply( this, args.splice(1, args.length - 1 )) );
- };
-
- return innerEquiv;
-}());
-
-/**
- * jsDump Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com |
- * http://flesler.blogspot.com Licensed under BSD
- * (http://www.opensource.org/licenses/bsd-license.php) Date: 5/15/2008
- *
- * @projectDescription Advanced and extensible data dumping for Javascript.
- * @version 1.0.0
- * @author Ariel Flesler
- * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html}
- */
-QUnit.jsDump = (function() {
- function quote( str ) {
- return '"' + str.toString().replace( /"/g, '\\"' ) + '"';
- }
- function literal( o ) {
- return o + "";
- }
- function join( pre, arr, post ) {
- var s = jsDump.separator(),
- base = jsDump.indent(),
- inner = jsDump.indent(1);
- if ( arr.join ) {
- arr = arr.join( "," + s + inner );
- }
- if ( !arr ) {
- return pre + post;
- }
- return [ pre, inner + arr, base + post ].join(s);
- }
- function array( arr, stack ) {
- var i = arr.length, ret = new Array(i);
- this.up();
- while ( i-- ) {
- ret[i] = this.parse( arr[i] , undefined , stack);
- }
- this.down();
- return join( "[", ret, "]" );
- }
-
- var reName = /^function (\w+)/,
- jsDump = {
- // type is used mostly internally, you can fix a (custom)type in advance
- parse: function( obj, type, stack ) {
- stack = stack || [ ];
- var inStack, res,
- parser = this.parsers[ type || this.typeOf(obj) ];
-
- type = typeof parser;
- inStack = inArray( obj, stack );
-
- if ( inStack !== -1 ) {
- return "recursion(" + (inStack - stack.length) + ")";
- }
- if ( type === "function" ) {
- stack.push( obj );
- res = parser.call( this, obj, stack );
- stack.pop();
- return res;
- }
- return ( type === "string" ) ? parser : this.parsers.error;
- },
- typeOf: function( obj ) {
- var type;
- if ( obj === null ) {
- type = "null";
- } else if ( typeof obj === "undefined" ) {
- type = "undefined";
- } else if ( QUnit.is( "regexp", obj) ) {
- type = "regexp";
- } else if ( QUnit.is( "date", obj) ) {
- type = "date";
- } else if ( QUnit.is( "function", obj) ) {
- type = "function";
- } else if ( typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined" ) {
- type = "window";
- } else if ( obj.nodeType === 9 ) {
- type = "document";
- } else if ( obj.nodeType ) {
- type = "node";
- } else if (
- // native arrays
- toString.call( obj ) === "[object Array]" ||
- // NodeList objects
- ( typeof obj.length === "number" && typeof obj.item !== "undefined" && ( obj.length ? obj.item(0) === obj[0] : ( obj.item( 0 ) === null && typeof obj[0] === "undefined" ) ) )
- ) {
- type = "array";
- } else if ( obj.constructor === Error.prototype.constructor ) {
- type = "error";
- } else {
- type = typeof obj;
- }
- return type;
- },
- separator: function() {
- return this.multiline ? this.HTML ? "
" : "\n" : this.HTML ? " " : " ";
- },
- // extra can be a number, shortcut for increasing-calling-decreasing
- indent: function( extra ) {
- if ( !this.multiline ) {
- return "";
- }
- var chr = this.indentChar;
- if ( this.HTML ) {
- chr = chr.replace( /\t/g, " " ).replace( / /g, " " );
- }
- return new Array( this._depth_ + (extra||0) ).join(chr);
- },
- up: function( a ) {
- this._depth_ += a || 1;
- },
- down: function( a ) {
- this._depth_ -= a || 1;
- },
- setParser: function( name, parser ) {
- this.parsers[name] = parser;
- },
- // The next 3 are exposed so you can use them
- quote: quote,
- literal: literal,
- join: join,
- //
- _depth_: 1,
- // This is the list of parsers, to modify them, use jsDump.setParser
- parsers: {
- window: "[Window]",
- document: "[Document]",
- error: function(error) {
- return "Error(\"" + error.message + "\")";
- },
- unknown: "[Unknown]",
- "null": "null",
- "undefined": "undefined",
- "function": function( fn ) {
- var ret = "function",
- // functions never have name in IE
- name = "name" in fn ? fn.name : (reName.exec(fn) || [])[1];
-
- if ( name ) {
- ret += " " + name;
- }
- ret += "( ";
-
- ret = [ ret, QUnit.jsDump.parse( fn, "functionArgs" ), "){" ].join( "" );
- return join( ret, QUnit.jsDump.parse(fn,"functionCode" ), "}" );
- },
- array: array,
- nodelist: array,
- "arguments": array,
- object: function( map, stack ) {
- var ret = [ ], keys, key, val, i;
- QUnit.jsDump.up();
- keys = [];
- for ( key in map ) {
- keys.push( key );
- }
- keys.sort();
- for ( i = 0; i < keys.length; i++ ) {
- key = keys[ i ];
- val = map[ key ];
- ret.push( QUnit.jsDump.parse( key, "key" ) + ": " + QUnit.jsDump.parse( val, undefined, stack ) );
- }
- QUnit.jsDump.down();
- return join( "{", ret, "}" );
- },
- node: function( node ) {
- var len, i, val,
- open = QUnit.jsDump.HTML ? "<" : "<",
- close = QUnit.jsDump.HTML ? ">" : ">",
- tag = node.nodeName.toLowerCase(),
- ret = open + tag,
- attrs = node.attributes;
-
- if ( attrs ) {
- for ( i = 0, len = attrs.length; i < len; i++ ) {
- val = attrs[i].nodeValue;
- // IE6 includes all attributes in .attributes, even ones not explicitly set.
- // Those have values like undefined, null, 0, false, "" or "inherit".
- if ( val && val !== "inherit" ) {
- ret += " " + attrs[i].nodeName + "=" + QUnit.jsDump.parse( val, "attribute" );
- }
- }
- }
- ret += close;
-
- // Show content of TextNode or CDATASection
- if ( node.nodeType === 3 || node.nodeType === 4 ) {
- ret += node.nodeValue;
- }
-
- return ret + open + "/" + tag + close;
- },
- // function calls it internally, it's the arguments part of the function
- functionArgs: function( fn ) {
- var args,
- l = fn.length;
-
- if ( !l ) {
- return "";
- }
-
- args = new Array(l);
- while ( l-- ) {
- // 97 is 'a'
- args[l] = String.fromCharCode(97+l);
- }
- return " " + args.join( ", " ) + " ";
- },
- // object calls it internally, the key part of an item in a map
- key: quote,
- // function calls it internally, it's the content of the function
- functionCode: "[code]",
- // node calls it internally, it's an html attribute value
- attribute: quote,
- string: quote,
- date: quote,
- regexp: literal,
- number: literal,
- "boolean": literal
- },
- // if true, entities are escaped ( <, >, \t, space and \n )
- HTML: false,
- // indentation unit
- indentChar: " ",
- // if true, items in a collection, are separated by a \n, else just a space.
- multiline: true
- };
-
- return jsDump;
-}());
-
-// from jquery.js
-function inArray( elem, array ) {
- if ( array.indexOf ) {
- return array.indexOf( elem );
- }
-
- for ( var i = 0, length = array.length; i < length; i++ ) {
- if ( array[ i ] === elem ) {
- return i;
- }
- }
-
- return -1;
-}
-
-/*
- * Javascript Diff Algorithm
- * By John Resig (http://ejohn.org/)
- * Modified by Chu Alan "sprite"
- *
- * Released under the MIT license.
- *
- * More Info:
- * http://ejohn.org/projects/javascript-diff-algorithm/
- *
- * Usage: QUnit.diff(expected, actual)
- *
- * QUnit.diff( "the quick brown fox jumped over", "the quick fox jumps over" ) == "the quick brown fox jumped jumps over"
- */
-QUnit.diff = (function() {
- /*jshint eqeqeq:false, eqnull:true */
- function diff( o, n ) {
- var i,
- ns = {},
- os = {};
-
- for ( i = 0; i < n.length; i++ ) {
- if ( !hasOwn.call( ns, n[i] ) ) {
- ns[ n[i] ] = {
- rows: [],
- o: null
- };
- }
- ns[ n[i] ].rows.push( i );
- }
-
- for ( i = 0; i < o.length; i++ ) {
- if ( !hasOwn.call( os, o[i] ) ) {
- os[ o[i] ] = {
- rows: [],
- n: null
- };
- }
- os[ o[i] ].rows.push( i );
- }
-
- for ( i in ns ) {
- if ( !hasOwn.call( ns, i ) ) {
- continue;
- }
- if ( ns[i].rows.length === 1 && hasOwn.call( os, i ) && os[i].rows.length === 1 ) {
- n[ ns[i].rows[0] ] = {
- text: n[ ns[i].rows[0] ],
- row: os[i].rows[0]
- };
- o[ os[i].rows[0] ] = {
- text: o[ os[i].rows[0] ],
- row: ns[i].rows[0]
- };
- }
- }
-
- for ( i = 0; i < n.length - 1; i++ ) {
- if ( n[i].text != null && n[ i + 1 ].text == null && n[i].row + 1 < o.length && o[ n[i].row + 1 ].text == null &&
- n[ i + 1 ] == o[ n[i].row + 1 ] ) {
-
- n[ i + 1 ] = {
- text: n[ i + 1 ],
- row: n[i].row + 1
- };
- o[ n[i].row + 1 ] = {
- text: o[ n[i].row + 1 ],
- row: i + 1
- };
- }
- }
-
- for ( i = n.length - 1; i > 0; i-- ) {
- if ( n[i].text != null && n[ i - 1 ].text == null && n[i].row > 0 && o[ n[i].row - 1 ].text == null &&
- n[ i - 1 ] == o[ n[i].row - 1 ]) {
-
- n[ i - 1 ] = {
- text: n[ i - 1 ],
- row: n[i].row - 1
- };
- o[ n[i].row - 1 ] = {
- text: o[ n[i].row - 1 ],
- row: i - 1
- };
- }
- }
-
- return {
- o: o,
- n: n
- };
- }
-
- return function( o, n ) {
- o = o.replace( /\s+$/, "" );
- n = n.replace( /\s+$/, "" );
-
- var i, pre,
- str = "",
- out = diff( o === "" ? [] : o.split(/\s+/), n === "" ? [] : n.split(/\s+/) ),
- oSpace = o.match(/\s+/g),
- nSpace = n.match(/\s+/g);
-
- if ( oSpace == null ) {
- oSpace = [ " " ];
- }
- else {
- oSpace.push( " " );
- }
-
- if ( nSpace == null ) {
- nSpace = [ " " ];
- }
- else {
- nSpace.push( " " );
- }
-
- if ( out.n.length === 0 ) {
- for ( i = 0; i < out.o.length; i++ ) {
- str += "" + out.o[i] + oSpace[i] + "";
- }
- }
- else {
- if ( out.n[0].text == null ) {
- for ( n = 0; n < out.o.length && out.o[n].text == null; n++ ) {
- str += "" + out.o[n] + oSpace[n] + "";
- }
- }
-
- for ( i = 0; i < out.n.length; i++ ) {
- if (out.n[i].text == null) {
- str += "" + out.n[i] + nSpace[i] + "";
- }
- else {
- // `pre` initialized at top of scope
- pre = "";
-
- for ( n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++ ) {
- pre += "" + out.o[n] + oSpace[n] + "";
- }
- str += " " + out.n[i].text + nSpace[i] + pre;
- }
- }
- }
-
- return str;
- };
-}());
-
-// for CommonJS enviroments, export everything
-if ( typeof exports !== "undefined" ) {
- extend( exports, QUnit );
-}
-
-// get at whatever the global object is, like window in browsers
-}( (function() {return this;}.call()) ));
diff --git a/test/lib/require.js b/test/lib/require.js
deleted file mode 100644
index 987f865..0000000
--- a/test/lib/require.js
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- RequireJS 2.1.5 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.
- Available via the MIT or new BSD license.
- see: http://github.com/jrburke/requirejs for details
-*/
-var requirejs,require,define;
-(function(aa){function I(b){return"[object Function]"===L.call(b)}function J(b){return"[object Array]"===L.call(b)}function y(b,c){if(b){var d;for(d=0;dthis.depCount&&!this.defined){if(I(n)){if(this.events.error)try{e=i.execCb(c,n,b,e)}catch(d){a=d}else e=i.execCb(c,n,b,e);this.map.isDefine&&((b=this.module)&&void 0!==b.exports&&b.exports!==this.exports?e=b.exports:void 0===e&&this.usingExports&&(e=this.exports));if(a)return a.requireMap=this.map,a.requireModules=[this.map.id],a.requireType="define",v(this.error=
-a)}else e=n;this.exports=e;if(this.map.isDefine&&!this.ignore&&(q[c]=e,l.onResourceLoad))l.onResourceLoad(i,this.map,this.depMaps);x(c);this.defined=!0}this.defining=!1;this.defined&&!this.defineEmitted&&(this.defineEmitted=!0,this.emit("defined",this.exports),this.defineEmitComplete=!0)}}else this.fetch()}},callPlugin:function(){var a=this.map,b=a.id,d=j(a.prefix);this.depMaps.push(d);t(d,"defined",u(this,function(e){var n,d;d=this.map.name;var g=this.map.parentMap?this.map.parentMap.name:null,h=
-i.makeRequire(a.parentMap,{enableBuildCallback:!0});if(this.map.unnormalized){if(e.normalize&&(d=e.normalize(d,function(a){return c(a,g,!0)})||""),e=j(a.prefix+"!"+d,this.map.parentMap),t(e,"defined",u(this,function(a){this.init([],function(){return a},null,{enabled:!0,ignore:!0})})),d=m(p,e.id)){this.depMaps.push(e);if(this.events.error)d.on("error",u(this,function(a){this.emit("error",a)}));d.enable()}}else n=u(this,function(a){this.init([],function(){return a},null,{enabled:!0})}),n.error=u(this,
-function(a){this.inited=!0;this.error=a;a.requireModules=[b];G(p,function(a){0===a.map.id.indexOf(b+"_unnormalized")&&x(a.map.id)});v(a)}),n.fromText=u(this,function(e,c){var d=a.name,g=j(d),C=O;c&&(e=c);C&&(O=!1);r(g);s(k.config,b)&&(k.config[d]=k.config[b]);try{l.exec(e)}catch(ca){return v(B("fromtexteval","fromText eval for "+b+" failed: "+ca,ca,[b]))}C&&(O=!0);this.depMaps.push(g);i.completeLoad(d);h([d],n)}),e.load(a.name,h,n,k)}));i.enable(d,this);this.pluginMaps[d.id]=d},enable:function(){V[this.map.id]=
-this;this.enabling=this.enabled=!0;y(this.depMaps,u(this,function(a,b){var c,e;if("string"===typeof a){a=j(a,this.map.isDefine?this.map:this.map.parentMap,!1,!this.skipMap);this.depMaps[b]=a;if(c=m(N,a.id)){this.depExports[b]=c(this);return}this.depCount+=1;t(a,"defined",u(this,function(a){this.defineDep(b,a);this.check()}));this.errback&&t(a,"error",this.errback)}c=a.id;e=p[c];!s(N,c)&&(e&&!e.enabled)&&i.enable(a,this)}));G(this.pluginMaps,u(this,function(a){var b=m(p,a.id);b&&!b.enabled&&i.enable(a,
-this)}));this.enabling=!1;this.check()},on:function(a,b){var c=this.events[a];c||(c=this.events[a]=[]);c.push(b)},emit:function(a,b){y(this.events[a],function(a){a(b)});"error"===a&&delete this.events[a]}};i={config:k,contextName:b,registry:p,defined:q,urlFetched:U,defQueue:H,Module:Z,makeModuleMap:j,nextTick:l.nextTick,onError:v,configure:function(a){a.baseUrl&&"/"!==a.baseUrl.charAt(a.baseUrl.length-1)&&(a.baseUrl+="/");var b=k.pkgs,c=k.shim,e={paths:!0,config:!0,map:!0};G(a,function(a,b){e[b]?
-"map"===b?(k.map||(k.map={}),R(k[b],a,!0,!0)):R(k[b],a,!0):k[b]=a});a.shim&&(G(a.shim,function(a,b){J(a)&&(a={deps:a});if((a.exports||a.init)&&!a.exportsFn)a.exportsFn=i.makeShimExports(a);c[b]=a}),k.shim=c);a.packages&&(y(a.packages,function(a){a="string"===typeof a?{name:a}:a;b[a.name]={name:a.name,location:a.location||a.name,main:(a.main||"main").replace(ja,"").replace(ea,"")}}),k.pkgs=b);G(p,function(a,b){!a.inited&&!a.map.unnormalized&&(a.map=j(b))});if(a.deps||a.callback)i.require(a.deps||[],
-a.callback)},makeShimExports:function(a){return function(){var b;a.init&&(b=a.init.apply(aa,arguments));return b||a.exports&&ba(a.exports)}},makeRequire:function(a,f){function d(e,c,h){var g,k;f.enableBuildCallback&&(c&&I(c))&&(c.__requireJsBuild=!0);if("string"===typeof e){if(I(c))return v(B("requireargs","Invalid require call"),h);if(a&&s(N,e))return N[e](p[a.id]);if(l.get)return l.get(i,e,a,d);g=j(e,a,!1,!0);g=g.id;return!s(q,g)?v(B("notloaded",'Module name "'+g+'" has not been loaded yet for context: '+
-b+(a?"":". Use require([])"))):q[g]}L();i.nextTick(function(){L();k=r(j(null,a));k.skipMap=f.skipMap;k.init(e,c,h,{enabled:!0});D()});return d}f=f||{};R(d,{isBrowser:A,toUrl:function(b){var d,f=b.lastIndexOf("."),g=b.split("/")[0];if(-1!==f&&(!("."===g||".."===g)||1h.attachEvent.toString().indexOf("[native code"))&&!Y?(O=!0,h.attachEvent("onreadystatechange",b.onScriptLoad)):(h.addEventListener("load",b.onScriptLoad,!1),h.addEventListener("error",b.onScriptError,!1)),h.src=d,K=h,D?x.insertBefore(h,D):x.appendChild(h),K=null,h;if(da)try{importScripts(d),b.completeLoad(c)}catch(j){b.onError(B("importscripts","importScripts failed for "+c+" at "+d,j,[c]))}};A&&M(document.getElementsByTagName("script"),function(b){x||(x=
-b.parentNode);if(t=b.getAttribute("data-main"))return r.baseUrl||(E=t.split("/"),Q=E.pop(),fa=E.length?E.join("/")+"/":"./",r.baseUrl=fa,t=Q),t=t.replace(ea,""),r.deps=r.deps?r.deps.concat(t):[t],!0});define=function(b,c,d){var l,h;"string"!==typeof b&&(d=c,c=b,b=null);J(c)||(d=c,c=[]);!c.length&&I(d)&&d.length&&(d.toString().replace(la,"").replace(ma,function(b,d){c.push(d)}),c=(1===d.length?["require"]:["require","exports","module"]).concat(c));if(O){if(!(l=K))P&&"interactive"===P.readyState||M(document.getElementsByTagName("script"),
-function(b){if("interactive"===b.readyState)return P=b}),l=P;l&&(b||(b=l.getAttribute("data-requiremodule")),h=F[l.getAttribute("data-requirecontext")])}(h?h.defQueue:T).push([b,c,d])};define.amd={jQuery:!0};l.exec=function(b){return eval(b)};l(r)}})(this);
diff --git a/test/lib/resemble.js b/test/lib/resemble.js
new file mode 100644
index 0000000..1cb8c29
--- /dev/null
+++ b/test/lib/resemble.js
@@ -0,0 +1,535 @@
+/*
+Author: James Cryer
+Company: Huddle
+Last updated date: 21 Feb 2013
+URL: https://github.com/Huddle/Resemble.js
+*/
+
+(function(_this){
+ 'use strict';
+
+ _this['resemble'] = function( fileData ){
+
+ var data = {};
+ var images = [];
+ var updateCallbackArray = [];
+
+ var tolerance = { // between 0 and 255
+ red: 16,
+ green: 16,
+ blue: 16,
+ minBrightness: 16,
+ maxBrightness: 240
+ };
+
+ var ignoreAntialiasing = false;
+ var ignoreColors = false;
+
+ function triggerDataUpdate(){
+ var len = updateCallbackArray.length;
+ var i;
+ for(i=0;i tolerance.maxBrightness;
+ }
+
+ function getHue(r,g,b){
+
+ r = r / 255;
+ g = g / 255;
+ b = b / 255;
+ var max = Math.max(r, g, b), min = Math.min(r, g, b);
+ var h;
+ var d;
+
+ if (max == min){
+ h = 0; // achromatic
+ } else{
+ d = max - min;
+ switch(max){
+ case r: h = (g - b) / d + (g < b ? 6 : 0); break;
+ case g: h = (b - r) / d + 2; break;
+ case b: h = (r - g) / d + 4; break;
+ }
+ h /= 6;
+ }
+
+ return h;
+ }
+
+ function isAntialiased(sourcePix, data, cacheSet, verticalPos, horizontalPos, width){
+ var offset;
+ var targetPix;
+ var distance = 1;
+ var i;
+ var j;
+ var hasHighContrastSibling = 0;
+ var hasSiblingWithDifferentHue = 0;
+ var hasEquivilantSibling = 0;
+
+ addHueInfo(sourcePix);
+
+ for (i = distance*-1; i <= distance; i++){
+ for (j = distance*-1; j <= distance; j++){
+
+ if(i===0 && j===0){
+ // ignore source pixel
+ } else {
+
+ offset = ((verticalPos+j)*width + (horizontalPos+i)) * 4;
+ targetPix = getPixelInfo(data, offset, cacheSet);
+
+ if(targetPix === null){
+ continue;
+ }
+
+ addBrightnessInfo(targetPix);
+ addHueInfo(targetPix);
+
+ if( isContrasting(sourcePix, targetPix) ){
+ hasHighContrastSibling++;
+ }
+
+ if( isRGBSame(sourcePix,targetPix) ){
+ hasEquivilantSibling++;
+ }
+
+ if( Math.abs(targetPix.h - sourcePix.h) > 0.3 ){
+ hasSiblingWithDifferentHue++;
+ }
+
+ if( hasSiblingWithDifferentHue > 1 || hasHighContrastSibling > 1){
+ return true;
+ }
+ }
+ }
+ }
+
+ if(hasEquivilantSibling < 2){
+ return true;
+ }
+
+ return false;
+ }
+
+ function errorPixel(px, offset){
+ px[offset] = 255; //r
+ px[offset + 1] = 0; //g
+ px[offset + 2] = 255; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyPixel(px, offset, data){
+ px[offset] = data.r; //r
+ px[offset + 1] = data.g; //g
+ px[offset + 2] = data.b; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyGrayScalePixel(px, offset, data){
+ px[offset] = data.brightness; //r
+ px[offset + 1] = data.brightness; //g
+ px[offset + 2] = data.brightness; //b
+ px[offset + 3] = 255; //a
+ }
+
+
+ function getPixelInfo(data, offset, cacheSet){
+ var r;
+ var g;
+ var b;
+ var d;
+
+ if(typeof data[offset] !== 'undefined'){
+ r = data[offset];
+ g = data[offset+1];
+ b = data[offset+2];
+ d = {
+ r: r,
+ g: g,
+ b: b
+ };
+
+ return d;
+ } else {
+ return null;
+ }
+ }
+
+ function addBrightnessInfo(data){
+ data.brightness = getBrightness(data.r,data.g,data.b); // 'corrected' lightness
+ }
+
+ function addHueInfo(data){
+ data.h = getHue(data.r,data.g,data.b);
+ }
+
+ function analyseImages(img1, img2, width, height){
+
+ var hiddenCanvas = document.createElement('canvas');
+
+ var data1 = img1.data;
+ var data2 = img2.data;
+
+ hiddenCanvas.width = width;
+ hiddenCanvas.height = height;
+
+ var context = hiddenCanvas.getContext('2d');
+ var imgd = context.createImageData(width,height);
+ var targetPix = imgd.data;
+
+ var mismatchCount = 0;
+
+ var time = Date.now();
+
+ var skip;
+
+ if( (width > 1200 || height > 1200) && ignoreAntialiasing){
+ skip = 6;
+ }
+
+ loop(height, width, function(verticalPos, horizontalPos){
+
+ if(skip){ // only skip if the image isn't small
+ if(verticalPos % skip === 0 || horizontalPos % skip === 0){
+ return;
+ }
+ }
+
+ var offset = (verticalPos*width + horizontalPos) * 4;
+ var pixel1 = getPixelInfo(data1, offset, 1);
+ var pixel2 = getPixelInfo(data2, offset, 2);
+
+ if(pixel1 === null || pixel2 === null){
+ return;
+ }
+
+ if (ignoreColors){
+
+ addBrightnessInfo(pixel1);
+ addBrightnessInfo(pixel2);
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ return;
+ }
+
+ if( isRGBSimilar(pixel1, pixel2) ){
+ copyPixel(targetPix, offset, pixel2);
+
+ } else if( ignoreAntialiasing && (
+ addBrightnessInfo(pixel1), // jit pixel info augmentation looks a little weird, sorry.
+ addBrightnessInfo(pixel2),
+ isAntialiased(pixel1, data1, 1, verticalPos, horizontalPos, width) ||
+ isAntialiased(pixel2, data2, 2, verticalPos, horizontalPos, width)
+ )){
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+
+ });
+
+ data.misMatchPercentage = (mismatchCount / (height*width) * 100).toFixed(2);
+ data.analysisTime = Date.now() - time;
+
+ data.getImageDataUrl = function(text){
+ var barHeight = 0;
+
+ if(text){
+ barHeight = addLabel(text,context,hiddenCanvas);
+ }
+
+ context.putImageData(imgd, 0, barHeight);
+
+ return hiddenCanvas.toDataURL("image/png");
+ };
+ }
+
+ function addLabel(text, context, hiddenCanvas){
+ var textPadding = 2;
+
+ context.font = '12px sans-serif';
+
+ var textWidth = context.measureText(text).width + textPadding*2;
+ var barHeight = 22;
+
+ if(textWidth > hiddenCanvas.width){
+ hiddenCanvas.width = textWidth;
+ }
+
+ hiddenCanvas.height += barHeight;
+
+ context.fillStyle = "#666";
+ context.fillRect(0,0,hiddenCanvas.width,barHeight -4);
+ context.fillStyle = "#fff";
+ context.fillRect(0,barHeight -4,hiddenCanvas.width, 4);
+
+ context.fillStyle = "#fff";
+ context.textBaseline = "top";
+ context.font = '12px sans-serif';
+ context.fillText(text, textPadding, 1);
+
+ return barHeight;
+ }
+
+ function normalise(img, w, h){
+ var c;
+ var context;
+
+ if(img.height < h || img.width < w){
+ c = document.createElement('canvas');
+ c.width = w;
+ c.height = h;
+ context = c.getContext('2d');
+ context.putImageData(img, 0, 0);
+ return context.getImageData(0, 0, w, h);
+ }
+
+ return img;
+ }
+
+ function compare(one, two){
+
+ function onceWeHaveBoth(){
+ var width;
+ var height;
+ if(images.length === 2){
+ width = images[0].width > images[1].width ? images[0].width : images[1].width;
+ height = images[0].height > images[1].height ? images[0].height : images[1].height;
+
+ if( (images[0].width === images[1].width) && (images[0].height === images[1].height) ){
+ data.isSameDimensions = true;
+ } else {
+ data.isSameDimensions = false;
+ }
+
+ analyseImages( normalise(images[0],width, height), normalise(images[1],width, height), width, height);
+
+ triggerDataUpdate();
+ }
+ }
+
+ images = [];
+ loadImageData(one, onceWeHaveBoth);
+ loadImageData(two, onceWeHaveBoth);
+ }
+
+ function getCompareApi(param){
+
+ var secondFileData,
+ hasMethod = typeof param === 'function';
+
+ if( !hasMethod ){
+ // assume it's file data
+ secondFileData = param;
+ }
+
+ var self = {
+ ignoreNothing: function(){
+
+ tolerance.red = 16;
+ tolerance.green = 16;
+ tolerance.blue = 16;
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreAntialiasing: function(){
+
+ tolerance.red = 32;
+ tolerance.green = 32;
+ tolerance.blue = 32;
+ tolerance.minBrightness = 64;
+ tolerance.maxBrightness = 96;
+
+ ignoreAntialiasing = true;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreColors: function(){
+
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = true;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ onComplete: function( callback ){
+
+ updateCallbackArray.push(callback);
+
+ var wrapper = function(){
+ compare(fileData, secondFileData);
+ };
+
+ wrapper();
+
+ return getCompareApi(wrapper);
+ }
+ };
+
+ return self;
+ }
+
+ return {
+ onComplete: function( callback ){
+ updateCallbackArray.push(callback);
+ loadImageData(fileData, function(imageData, width, height){
+ parseImage(imageData.data, width, height);
+ });
+ },
+ compareTo: function(secondFileData){
+ return getCompareApi(secondFileData);
+ }
+ };
+
+ };
+}(this));
\ No newline at end of file
diff --git a/test/testsuite.js b/test/testsuite.js
deleted file mode 100644
index b486acb..0000000
--- a/test/testsuite.js
+++ /dev/null
@@ -1,36 +0,0 @@
-requirejs.config({
- baseUrl: '/test/unit/'
-});
-
-define(function(require) {
- var testModules = [
- 'Pixi',
- 'Point',
- 'Rectangle',
- 'DisplayObject',
- 'DisplayObjectContainer',
- 'Sprite',
- 'MovieClip',
- 'InteractionManager',
- 'Stage',
- 'utils/Utils',
- 'utils/EventTarget',
- 'utils/Matrix',
- 'utils/Detector',
- 'renderers/WebGLShaders',
- 'renderers/WebGLRenderer',
- 'renderers/WebGLBatch',
- 'renderers/CanvasRenderer',
- 'extras/Strip',
- 'extras/Rope',
- 'textures/BaseTexture',
- 'textures/Texture',
- 'loaders/SpriteSheetLoader',
- 'loaders/AssetLoader'
- ];
-
- // Resolve all testModules and then start the Test Runner.
- require(testModules, function() {
- QUnit.start();
- });
-});
\ No newline at end of file
diff --git a/test/textures/SpriteSheet-Aliens.png b/test/textures/SpriteSheet-Aliens.png
new file mode 100644
index 0000000..210acb1
--- /dev/null
+++ b/test/textures/SpriteSheet-Aliens.png
Binary files differ
diff --git a/test/textures/SpriteSheet-Explosion.png b/test/textures/SpriteSheet-Explosion.png
new file mode 100755
index 0000000..79e1a69
--- /dev/null
+++ b/test/textures/SpriteSheet-Explosion.png
Binary files differ
diff --git a/test/textures/bunny.png b/test/textures/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/textures/bunny.png
Binary files differ
diff --git a/test/unit/DisplayObject.js b/test/unit/DisplayObject.js
deleted file mode 100644
index 5e7e72f..0000000
--- a/test/unit/DisplayObject.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObject');
-});
diff --git a/test/unit/DisplayObjectContainer.js b/test/unit/DisplayObjectContainer.js
deleted file mode 100644
index b323959..0000000
--- a/test/unit/DisplayObjectContainer.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObjectContainer');
-});
diff --git a/test/unit/InteractionManager.js b/test/unit/InteractionManager.js
deleted file mode 100644
index e751f52..0000000
--- a/test/unit/InteractionManager.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('InteractionManager');
-});
diff --git a/test/unit/MovieClip.js b/test/unit/MovieClip.js
deleted file mode 100644
index 37d9446..0000000
--- a/test/unit/MovieClip.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('MovieClip');
-});
diff --git a/test/unit/Pixi.js b/test/unit/Pixi.js
deleted file mode 100644
index 36eee73..0000000
--- a/test/unit/Pixi.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Pixi');
-});
diff --git a/test/unit/Point.js b/test/unit/Point.js
deleted file mode 100644
index 983ff6e..0000000
--- a/test/unit/Point.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Point');
-});
diff --git a/test/unit/Rectangle.js b/test/unit/Rectangle.js
deleted file mode 100644
index 3b439ba..0000000
--- a/test/unit/Rectangle.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Rectangle');
-});
diff --git a/test/unit/Sprite.js b/test/unit/Sprite.js
deleted file mode 100644
index ed4f596..0000000
--- a/test/unit/Sprite.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Sprite');
-});
diff --git a/test/unit/Stage.js b/test/unit/Stage.js
deleted file mode 100644
index 2d70291..0000000
--- a/test/unit/Stage.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Stage');
-});
diff --git a/test/unit/extras/Rope.js b/test/unit/extras/Rope.js
deleted file mode 100644
index 5606f14..0000000
--- a/test/unit/extras/Rope.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Rope');
-});
diff --git a/test/unit/extras/Strip.js b/test/unit/extras/Strip.js
deleted file mode 100644
index 0134d3a..0000000
--- a/test/unit/extras/Strip.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Strip');
-});
diff --git a/test/unit/loaders/AssetLoader.js b/test/unit/loaders/AssetLoader.js
deleted file mode 100644
index 13b8443..0000000
--- a/test/unit/loaders/AssetLoader.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('AssetLoader');
-});
diff --git a/test/unit/loaders/SpriteSheetLoader.js b/test/unit/loaders/SpriteSheetLoader.js
deleted file mode 100644
index 8bf0cb2..0000000
--- a/test/unit/loaders/SpriteSheetLoader.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('SpriteSheetLoader');
-});
diff --git a/test/unit/pixi/InteractionManager.js b/test/unit/pixi/InteractionManager.js
new file mode 100644
index 0000000..ed3001f
--- /dev/null
+++ b/test/unit/pixi/InteractionManager.js
@@ -0,0 +1,10 @@
+describe('pixi/InteractionManager', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var InteractionManager = PIXI.InteractionManager;
+
+ it('Module exists', function () {
+ expect(InteractionManager).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/Pixi.js b/test/unit/pixi/Pixi.js
new file mode 100644
index 0000000..27debc1
--- /dev/null
+++ b/test/unit/pixi/Pixi.js
@@ -0,0 +1,9 @@
+describe('pixi/Pixi', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+
+ it('Module exists', function () {
+ expect(global).to.have.property('PIXI').and.to.be.an('object');
+ });
+});
diff --git a/test/unit/pixi/core/Circle.js b/test/unit/pixi/core/Circle.js
new file mode 100644
index 0000000..93a4456
--- /dev/null
+++ b/test/unit/pixi/core/Circle.js
@@ -0,0 +1,22 @@
+describe('pixi/core/Circle', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Circle = PIXI.Circle;
+
+ it('Module exists', function () {
+ expect(Circle).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Circle();
+
+ expect(obj).to.be.an.instanceof(Circle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', 0);
+ expect(obj).to.have.property('y', 0);
+ expect(obj).to.have.property('radius', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Ellipse.js b/test/unit/pixi/core/Ellipse.js
new file mode 100644
index 0000000..026b56f
--- /dev/null
+++ b/test/unit/pixi/core/Ellipse.js
@@ -0,0 +1,24 @@
+describe('pixi/core/Ellipse', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Ellipse = PIXI.Ellipse;
+
+ it('Module exists', function () {
+ expect(Ellipse).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Ellipse();
+
+ expect(obj).to.be.an.instanceof(Ellipse);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+ expect(obj).to.respondTo('getBounds');
+
+ expect(obj).to.have.property('x', 0);
+ expect(obj).to.have.property('y', 0);
+ expect(obj).to.have.property('width', 0);
+ expect(obj).to.have.property('height', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Matrix.js b/test/unit/pixi/core/Matrix.js
new file mode 100644
index 0000000..b48989e
--- /dev/null
+++ b/test/unit/pixi/core/Matrix.js
@@ -0,0 +1,30 @@
+describe('pixi/core/Matrix', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var mat3 = PIXI.mat3;
+ var mat4 = PIXI.mat4;
+ var Matrix = PIXI.Matrix;
+
+ it('Ensure determineMatrixArrayType works', function () {
+ expect(Matrix).to.be.a('function');
+ });
+
+ it('mat3 exists', function () {
+ expect(mat3).to.be.an('object');
+ });
+
+ it('Confirm new mat3 matrix', function () {
+ var matrix = new mat3.create();
+ pixi_core_Matrix_confirmNewMat3(matrix);
+ });
+
+ it('mat3 exists', function () {
+ expect(mat4).to.be.an('object');
+ });
+
+ it('Confirm new mat4 matrix', function () {
+ var matrix = new mat4.create();
+ pixi_core_Matrix_confirmNewMat4(matrix);
+ });
+});
diff --git a/test/unit/pixi/core/Point.js b/test/unit/pixi/core/Point.js
new file mode 100644
index 0000000..c4d5163
--- /dev/null
+++ b/test/unit/pixi/core/Point.js
@@ -0,0 +1,15 @@
+describe('pixi/core/Point', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Point = PIXI.Point;
+
+ it('Module exists', function () {
+ expect(Point).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Point();
+ pixi_core_Point_confirm(obj, 0, 0);
+ });
+});
diff --git a/test/unit/pixi/core/Polygon.js b/test/unit/pixi/core/Polygon.js
new file mode 100644
index 0000000..dc8c918
--- /dev/null
+++ b/test/unit/pixi/core/Polygon.js
@@ -0,0 +1,20 @@
+describe('pixi/core/Polygon', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Polygon = PIXI.Polygon;
+
+ it('Module exists', function () {
+ expect(Polygon).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Polygon();
+
+ expect(obj).to.be.an.instanceof(Polygon);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.deep.property('points.length', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Rectangle.js b/test/unit/pixi/core/Rectangle.js
new file mode 100644
index 0000000..d43316e
--- /dev/null
+++ b/test/unit/pixi/core/Rectangle.js
@@ -0,0 +1,15 @@
+describe('pixi/core/Rectangle', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Rectangle = PIXI.Rectangle;
+
+ it('Module exists', function () {
+ expect(Rectangle).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var rect = new Rectangle();
+ pixi_core_Rectangle_confirm(rect, 0, 0, 0, 0);
+ });
+});
diff --git a/test/unit/pixi/display/DisplayObject.js b/test/unit/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..40c6fbc
--- /dev/null
+++ b/test/unit/pixi/display/DisplayObject.js
@@ -0,0 +1,21 @@
+describe('pixi/display/DisplayObject', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var DisplayObject = PIXI.DisplayObject;
+
+ it('Module exists', function () {
+ expect(DisplayObject).to.be.a('function');
+ expect(PIXI).to.have.property('visibleCount', 0);
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new DisplayObject();
+
+ pixi_display_DisplayObject_confirmNew(obj);
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', false);
+ expect(obj).to.have.property('stage', null);
+ });
+});
diff --git a/test/unit/pixi/display/DisplayObjectContainer.js b/test/unit/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..ce7f02f
--- /dev/null
+++ b/test/unit/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,20 @@
+describe('pixi/display/DisplayObjectContainer', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var DisplayObjectContainer = PIXI.DisplayObjectContainer;
+
+ it('Module exists', function () {
+ expect(DisplayObjectContainer).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new DisplayObjectContainer();
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', false);
+ expect(obj).to.have.property('stage', null);
+ });
+});
diff --git a/test/unit/pixi/display/MovieClip.js b/test/unit/pixi/display/MovieClip.js
new file mode 100644
index 0000000..f3c6c6a
--- /dev/null
+++ b/test/unit/pixi/display/MovieClip.js
@@ -0,0 +1,33 @@
+describe('pixi/display/MovieClip', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var MovieClip = PIXI.MovieClip;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(MovieClip).to.be.a('function');
+ });
+
+ it('Confirm new instance', function (done) {
+ var texture = Texture.fromImage('/base/test/textures/SpriteSheet-Explosion.png');
+ var obj = new MovieClip([texture]);
+
+ pixi_display_Sprite_confirmNew(obj, done);
+
+ expect(obj).to.be.an.instanceof(MovieClip);
+ expect(obj).to.respondTo('stop');
+ expect(obj).to.respondTo('play');
+ expect(obj).to.respondTo('gotoAndStop');
+ expect(obj).to.respondTo('gotoAndPlay');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('textures.length', 1);
+ expect(obj).to.have.deep.property('textures[0]', texture);
+ expect(obj).to.have.property('animationSpeed', 1);
+ expect(obj).to.have.property('loop', true);
+ expect(obj).to.have.property('onComplete', null);
+ expect(obj).to.have.property('currentFrame', 0);
+ expect(obj).to.have.property('playing', false);
+ });
+});
diff --git a/test/unit/pixi/display/Sprite.js b/test/unit/pixi/display/Sprite.js
new file mode 100644
index 0000000..54e914f
--- /dev/null
+++ b/test/unit/pixi/display/Sprite.js
@@ -0,0 +1,25 @@
+describe('pixi/display/Sprite', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Sprite = PIXI.Sprite;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(Sprite).to.be.a('function');
+ expect(PIXI).to.have.deep.property('blendModes.NORMAL', 0);
+ expect(PIXI).to.have.deep.property('blendModes.SCREEN', 1);
+ });
+
+ it('Members exist', function () {
+ expect(Sprite).itself.to.respondTo('fromImage');
+ expect(Sprite).itself.to.respondTo('fromFrame');
+ });
+
+ it('Confirm new instance', function (done) {
+ var texture = Texture.fromImage('/base/test/textures/SpriteSheet-Aliens.png');
+ var obj = new Sprite(texture);
+
+ pixi_display_Sprite_confirmNew(obj, done);
+ });
+});
diff --git a/test/unit/pixi/display/Stage.js b/test/unit/pixi/display/Stage.js
new file mode 100644
index 0000000..3cc2a4d
--- /dev/null
+++ b/test/unit/pixi/display/Stage.js
@@ -0,0 +1,49 @@
+describe('pixi/display/Stage', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Stage = PIXI.Stage;
+ var InteractionManager = PIXI.InteractionManager;
+ var Rectangle = PIXI.Rectangle;
+
+ it('Module exists', function () {
+ expect(Stage).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Stage(null, true);
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(Stage);
+ expect(obj).to.respondTo('updateTransform');
+ expect(obj).to.respondTo('setBackgroundColor');
+ expect(obj).to.respondTo('getMousePosition');
+
+ // FIXME: duplicate member in DisplayObject
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ // FIXME: convert arg to bool in constructor
+ expect(obj).to.have.property('interactive', true);
+
+ expect(obj).to.have.property('interactionManager')
+ .and.to.be.an.instanceof(InteractionManager)
+ .and.to.have.property('stage', obj);
+
+ expect(obj).to.have.property('dirty', true);
+
+ expect(obj).to.have.property('stage', obj);
+
+ expect(obj).to.have.property('hitArea')
+ .and.to.be.an.instanceof(Rectangle);
+ pixi_core_Rectangle_confirm(obj.hitArea, 0, 0, 100000, 100000);
+
+ expect(obj).to.have.property('backgroundColor', 0x000000);
+ expect(obj).to.have.deep.property('backgroundColorSplit.length', 3);
+ expect(obj).to.have.deep.property('backgroundColorSplit[0]', 0);
+ expect(obj).to.have.deep.property('backgroundColorSplit[1]', 0);
+ expect(obj).to.have.deep.property('backgroundColorSplit[2]', 0);
+ expect(obj).to.have.property('backgroundColorString', '#000000');
+
+ expect(obj).to.have.property('worldVisible', true);
+ });
+});
diff --git a/test/unit/pixi/extras/CustomRenderable.js b/test/unit/pixi/extras/CustomRenderable.js
new file mode 100644
index 0000000..8d83cf0
--- /dev/null
+++ b/test/unit/pixi/extras/CustomRenderable.js
@@ -0,0 +1,21 @@
+describe('pixi/extras/CustomRenderable', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var CustomRenderable = PIXI.CustomRenderable;
+
+ it('Module exists', function () {
+ expect(CustomRenderable).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new CustomRenderable();
+
+ pixi_display_DisplayObject_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(CustomRenderable);
+ expect(obj).to.respondTo('renderCanvas');
+ expect(obj).to.respondTo('initWebGL');
+ expect(obj).to.respondTo('renderWebGL');
+ });
+});
diff --git a/test/unit/pixi/extras/Rope.js b/test/unit/pixi/extras/Rope.js
new file mode 100644
index 0000000..6ddaf83
--- /dev/null
+++ b/test/unit/pixi/extras/Rope.js
@@ -0,0 +1,26 @@
+describe('pixi/extras/Rope', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Rope = PIXI.Rope;
+ var Texture = PIXI.Texture;
+ var Point = PIXI.Point;
+
+ it('Module exists', function () {
+ expect(Rope).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var texture = Texture.fromImage('/base/test/textures/bunny.png');
+ var obj = new Rope(texture, [new Point(), new Point(5, 10), new Point(10, 20)]);
+
+ pixi_extras_Strip_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(Rope);
+ expect(obj).to.respondTo('refresh');
+ expect(obj).to.respondTo('updateTransform');
+ expect(obj).to.respondTo('setTexture');
+
+ // TODO: Test properties
+ });
+});
diff --git a/test/unit/pixi/extras/Spine.js b/test/unit/pixi/extras/Spine.js
new file mode 100644
index 0000000..0708bc0
--- /dev/null
+++ b/test/unit/pixi/extras/Spine.js
@@ -0,0 +1,10 @@
+describe('pixi/extras/Spine', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Spine = PIXI.Spine;
+
+ it('Module exists', function () {
+ expect(Spine).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/extras/Strip.js b/test/unit/pixi/extras/Strip.js
new file mode 100644
index 0000000..8e564e1
--- /dev/null
+++ b/test/unit/pixi/extras/Strip.js
@@ -0,0 +1,18 @@
+describe('pixi/extras/Strip', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Strip = PIXI.Strip;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(Strip).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var texture = Texture.fromImage('/base/test/textures/bunny.png');
+ var obj = new Strip(texture, 20, 10000);
+
+ pixi_extras_Strip_confirmNew(obj);
+ });
+});
diff --git a/test/unit/pixi/extras/TilingSprite.js b/test/unit/pixi/extras/TilingSprite.js
new file mode 100644
index 0000000..56aea14
--- /dev/null
+++ b/test/unit/pixi/extras/TilingSprite.js
@@ -0,0 +1,24 @@
+describe('pixi/extras/TilingSprite', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var TilingSprite = PIXI.TilingSprite;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(TilingSprite).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var texture = Texture.fromImage('/base/test/textures/bunny.png');
+ var obj = new TilingSprite(texture, 6000, 12000);
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(TilingSprite);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ // TODO: Test properties
+ });
+});
diff --git a/test/unit/pixi/filters/FilterBlock.js b/test/unit/pixi/filters/FilterBlock.js
new file mode 100644
index 0000000..870cec0
--- /dev/null
+++ b/test/unit/pixi/filters/FilterBlock.js
@@ -0,0 +1,10 @@
+describe('pixi/filters/FilterBlock', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var FilterBlock = PIXI.FilterBlock;
+
+ it('Module exists', function () {
+ expect(FilterBlock).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/filters/MaskFilter.js b/test/unit/pixi/filters/MaskFilter.js
new file mode 100644
index 0000000..32d6a45
--- /dev/null
+++ b/test/unit/pixi/filters/MaskFilter.js
@@ -0,0 +1,10 @@
+describe('pixi/filters/MaskFilter', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ // var MaskFilter = PIXI.MaskFilter;
+
+ // it('Module exists', function () {
+ // expect(MaskFilter).to.be.a('function');
+ // });
+});
diff --git a/.gitignore b/.gitignore
index 12e1b62..0b88317 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
node_modules
.DS_Store
-.project
\ No newline at end of file
+.project
+*.log
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..63e4d7c
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,8 @@
+language: node_js
+node_js:
+ - 0.10
+
+before_script:
+ - npm install -g grunt-cli
+ - export DISPLAY=:99.0
+ - sh -e /etc/init.d/xvfb start
diff --git a/Gruntfile.js b/Gruntfile.js
index b083b49..103938c 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -1,10 +1,12 @@
+'use strict';
+
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-connect');
- grunt.loadNpmTasks('grunt-contrib-qunit');
grunt.loadNpmTasks('grunt-contrib-yuidoc');
+ grunt.loadTasks('tasks');
var root = 'src/pixi/',
debug = 'bin/pixi.dev.js',
@@ -79,7 +81,7 @@
},
files: {
srcBlob: '<%= dirs.src %>/**/*.js',
- testBlob: '<%= dirs.test %>/unit/**/*.js',
+ testBlob: '<%= dirs.test %>/{functional,lib/pixi,unit}/**/*.js',
build: '<%= dirs.build %>/pixi.dev.js',
buildMin: '<%= dirs.build %>/pixi.js'
},
@@ -94,7 +96,12 @@
},
jshint: {
beforeconcat: srcFiles,
- test: ['<%= files.testBlob %>'],
+ test: {
+ src: ['<%= files.testBlob %>'],
+ options: {
+ expr: true
+ }
+ },
options: {
asi: true,
smarttabs: true
@@ -128,12 +135,6 @@
]
},
connect: {
- qunit: {
- options: {
- port: grunt.option('port-test') || 9002,
- base: './'
- }
- },
test: {
options: {
port: grunt.option('port-test') || 9002,
@@ -142,13 +143,6 @@
}
}
},
- qunit: {
- all: {
- options: {
- urls: ['http://localhost:' + (grunt.option('port-test') || 9002) + '/test/index.html']
- }
- }
- },
yuidoc: {
compile: {
name: '<%= pkg.name %>',
@@ -161,6 +155,13 @@
outdir: '<%= dirs.docs %>'
}
}
+ },
+ karma: {
+ unit: {
+ configFile: 'test/karma.conf.js',
+ // browsers: ['Chrome'],
+ singleRun: true
+ }
}
});
@@ -182,9 +183,10 @@
}
)
- grunt.registerTask('default', ['concat', 'uglify', 'distribute']);
grunt.registerTask('build', ['concat', 'uglify', 'distribute']);
- grunt.registerTask('test', ['build', 'connect:qunit', 'qunit']);
+ grunt.registerTask('test', ['concat', 'jshint:test', 'karma']);
grunt.registerTask('docs', ['yuidoc']);
-
-}
\ No newline at end of file
+ grunt.registerTask('default', ['test', 'uglify', 'distribute']);
+ // Travis CI task.
+ grunt.registerTask('travis', ['test']);
+}
diff --git a/README.md b/README.md
index c62ef86..690cfe4 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,8 @@

+[](http://travis-ci.org/drkibitz/pixi.js)
+
#### JavaScript 2D Renderer ####
The aim of this project is to provide a fast lightweight 2D library that works
diff --git a/package.json b/package.json
index b373240..1246a68 100644
--- a/package.json
+++ b/package.json
@@ -18,14 +18,21 @@
"main": "bin/pixi.js",
+ "scripts": {
+ "test": "grunt travis --verbose"
+ },
+
"dependencies": {},
"devDependencies": {
"grunt": "~0.4.x",
- "grunt-contrib-jshint": "0.3.x",
+ "grunt-contrib-jshint": "0.6.x",
"grunt-contrib-uglify": "0.2.x",
- "grunt-contrib-connect": "0.2.x",
- "grunt-contrib-qunit": "0.2.x",
+ "grunt-contrib-connect": "0.3.x",
"grunt-contrib-yuidoc": "0.4.x",
- "grunt-contrib-concat": "0.1.x"
+ "grunt-contrib-concat": "0.3.x",
+ "chai": "~1.7.0",
+ "karma": "0.11.0",
+ "karma-firefox-launcher": "0.1.0",
+ "karma-mocha": "0.1.0"
}
}
diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js
index a7c520e..ee82bbd 100644
--- a/src/pixi/InteractionManager.js
+++ b/src/pixi/InteractionManager.js
@@ -62,7 +62,6 @@
this.onTouchEnd = this.onTouchEnd.bind(this);
this.onTouchMove = this.onTouchMove.bind(this);
-
this.last = 0;
}
diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js
index 1a95d20..eef1059 100644
--- a/src/pixi/core/Ellipse.js
+++ b/src/pixi/core/Ellipse.js
@@ -78,7 +78,7 @@
return (normx + normy < 0.25);
}
-PIXI.Ellipse.getBounds = function()
+PIXI.Ellipse.prototype.getBounds = function()
{
return new PIXI.Rectangle(this.x, this.y, this.width, this.height);
}
diff --git a/tasks/karma.js b/tasks/karma.js
new file mode 100644
index 0000000..c340485
--- /dev/null
+++ b/tasks/karma.js
@@ -0,0 +1,27 @@
+'use strict';
+
+var path = require('path');
+var server = require('karma').server;
+
+module.exports = function (grunt) {
+ grunt.registerMultiTask('karma', 'run karma.', function() {
+ var done = this.async();
+ var options = this.options({
+ background: false
+ });
+ var data = this.data;
+
+ //merge options onto data, with data taking precedence
+ data = grunt.util._.merge(options, data);
+ data.configFile = path.resolve(data.configFile);
+ if (data.configFile) {
+ data.configFile = grunt.template.process(data.configFile);
+ }
+
+ server.start(
+ data,
+ function(code) {
+ done(!code);
+ });
+ });
+};
diff --git a/test/functional/example-1-basics/bunny.png b/test/functional/example-1-basics/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/functional/example-1-basics/bunny.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-30.png b/test/functional/example-1-basics/frame-30.png
new file mode 100644
index 0000000..96e3409
--- /dev/null
+++ b/test/functional/example-1-basics/frame-30.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-60.png b/test/functional/example-1-basics/frame-60.png
new file mode 100644
index 0000000..af3f4ce
--- /dev/null
+++ b/test/functional/example-1-basics/frame-60.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-90.png b/test/functional/example-1-basics/frame-90.png
new file mode 100644
index 0000000..099b823
--- /dev/null
+++ b/test/functional/example-1-basics/frame-90.png
Binary files differ
diff --git a/test/functional/example-1-basics/index.js b/test/functional/example-1-basics/index.js
new file mode 100644
index 0000000..7ae7a98
--- /dev/null
+++ b/test/functional/example-1-basics/index.js
@@ -0,0 +1,133 @@
+describe('Example 1 - Basics', function () {
+ 'use strict';
+
+ var baseUri = '/base/test/functional/example-1-basics';
+ var expect = chai.expect;
+ var currentFrame = 0;
+ var frameEvents = {};
+ var stage;
+ var renderer;
+ var bunny;
+
+ function onFrame(frame, callback) {
+ frameEvents[frame] = callback;
+ }
+
+ function animate() {
+ currentFrame += 1;
+
+ requestAnimFrame( animate );
+
+ // just for fun, lets rotate mr rabbit a little
+ bunny.rotation += 0.1;
+
+ // render the stage
+ renderer.render(stage);
+
+ if (frameEvents[currentFrame])
+ frameEvents[currentFrame](currentFrame);
+ }
+
+ function initScene() {
+ // create an new instance of a pixi stage
+ stage = new PIXI.Stage(0x66FF99);
+
+ // create a renderer instance
+ renderer = PIXI.autoDetectRenderer(400, 300);
+ console.log('Is PIXI.WebGLRenderer: ' + (renderer instanceof PIXI.WebGLRenderer));
+
+ // add the renderer view element to the DOM
+ document.body.appendChild(renderer.view);
+
+ requestAnimFrame( animate );
+
+ // create a texture from an image path
+ var texture = PIXI.Texture.fromImage(baseUri + "/bunny.png");
+ // create a new Sprite using the texture
+ bunny = new PIXI.Sprite(texture);
+
+ // center the sprites anchor point
+ bunny.anchor.x = 0.5;
+ bunny.anchor.y = 0.5;
+
+ // move the sprite t the center of the screen
+ bunny.position.x = 200;
+ bunny.position.y = 150;
+
+ stage.addChild(bunny);
+ }
+
+ it('assets loaded', function (done) {
+ var loader = new PIXI.AssetLoader([
+ baseUri + '/bunny.png',
+ baseUri + '/frame-30.png',
+ baseUri + '/frame-60.png',
+ baseUri + '/frame-90.png'
+ ]);
+ // loader.on('onProgress', function (event) {
+ // console.log(event.content);
+ // });
+ loader.on('onComplete', function (event) {
+ done();
+ initScene();
+ });
+ loader.load();
+ });
+
+ it('frame 30 should match', function (done) {
+ this.timeout(700);
+ onFrame(30, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-30.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 60 should match', function (done) {
+ this.timeout(1200);
+ onFrame(60, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-60.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 90 should match', function (done) {
+ this.timeout(1700);
+ onFrame(90, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-90.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ // it('capture something', function (done) {
+ // this.timeout(2000000);
+ // onFrame(30, function () {
+ // var img = new Image();
+ // img.src = renderer.view.toDataURL('image/png');
+ // document.body.appendChild(img);
+ // });
+ // });
+});
diff --git a/test/index.html b/test/index.html
deleted file mode 100644
index 9cbcac5..0000000
--- a/test/index.html
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
- Pixi.js Test Suite
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/test/karma.conf.js b/test/karma.conf.js
new file mode 100644
index 0000000..c66a696
--- /dev/null
+++ b/test/karma.conf.js
@@ -0,0 +1,82 @@
+module.exports = function(config) {
+ config.set({
+
+ // base path, that will be used to resolve files and exclude
+ basePath : '../',
+
+ frameworks : ['mocha'],
+
+ // list of files / patterns to load in the browser
+ files : [
+ 'node_modules/chai/chai.js',
+ 'bin/pixi.dev.js',
+ 'test/lib/**/*.js',
+ 'test/unit/**/*.js',
+ // 'test/functional/**/*.js',
+ {pattern: 'test/**/*.png', watched: false, included: false, served: true}
+ ],
+
+ // list of files to exclude
+ exclude : [],
+
+ // use dolts reporter, as travis terminal does not support escaping sequences
+ // possible values: 'dots', 'progress', 'junit', 'teamcity'
+ // CLI --reporters progress
+ reporters : ['progress'],
+
+ // web server port
+ // CLI --port 9876
+ port : 9876,
+
+ // cli runner port
+ // CLI --runner-port 9100
+ runnerPort : 9100,
+
+ // enable / disable colors in the output (reporters and logs)
+ // CLI --colors --no-colors
+ colors : true,
+
+ // level of logging
+ // possible values: karma.LOG_DISABLE || karma.LOG_ERROR || karma.LOG_WARN || karma.LOG_INFO || karma.LOG_DEBUG
+ // CLI --log-level debug
+ logLevel : config.LOG_DEBUG,
+
+ // enable / disable watching file and executing tests whenever any file changes
+ // CLI --auto-watch --no-auto-watch
+ autoWatch : false,
+
+ // Start these browsers, currently available:
+ // - Chrome
+ // - ChromeCanary
+ // - Firefox
+ // - Opera
+ // - Safari (only Mac)
+ // - PhantomJS
+ // - IE (only Windows)
+ // CLI --browsers Chrome,Firefox,Safari
+ browsers : ['Firefox'],
+
+ // If browser does not capture in given timeout [ms], kill it
+ // CLI --capture-timeout 5000
+ captureTimeout : 5000,
+
+ // Auto run tests on start (when browsers are captured) and exit
+ // CLI --single-run --no-single-run
+ singleRun : true,
+
+ // report which specs are slower than 500ms
+ // CLI --report-slower-than 500
+ reportSlowerThan : 1000,
+
+ preprocessors : {
+ // '**/client/js/*.js': 'coverage'
+ },
+
+ plugins : [
+ 'karma-mocha',
+ // 'karma-chrome-launcher',
+ 'karma-firefox-launcher',
+ // 'karma-phantomjs-launcher'
+ ]
+ });
+};
diff --git a/test/lib/pixi/core/Matrix.js b/test/lib/pixi/core/Matrix.js
new file mode 100644
index 0000000..d26386b
--- /dev/null
+++ b/test/lib/pixi/core/Matrix.js
@@ -0,0 +1,40 @@
+
+function pixi_core_Matrix_confirmNewMat3(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(1);
+ expect(matrix[5]).to.equal(0);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(1);
+}
+
+function pixi_core_Matrix_confirmNewMat4(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[0]).to.equal(1);
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(0);
+ expect(matrix[5]).to.equal(1);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(0);
+ expect(matrix[9]).to.equal(0);
+ expect(matrix[10]).to.equal(1);
+ expect(matrix[11]).to.equal(0);
+ expect(matrix[12]).to.equal(0);
+ expect(matrix[13]).to.equal(0);
+ expect(matrix[14]).to.equal(0);
+ expect(matrix[15]).to.equal(1);
+}
diff --git a/test/lib/pixi/core/Point.js b/test/lib/pixi/core/Point.js
new file mode 100644
index 0000000..e5df07b
--- /dev/null
+++ b/test/lib/pixi/core/Point.js
@@ -0,0 +1,10 @@
+
+function pixi_core_Point_confirm(obj, x, y) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Point);
+ expect(obj).to.respondTo('clone');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+}
diff --git a/test/lib/pixi/core/Rectangle.js b/test/lib/pixi/core/Rectangle.js
new file mode 100644
index 0000000..23f0d12
--- /dev/null
+++ b/test/lib/pixi/core/Rectangle.js
@@ -0,0 +1,13 @@
+
+function pixi_core_Rectangle_confirm(obj, x, y, width, height) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Rectangle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+ expect(obj).to.have.property('width', width);
+ expect(obj).to.have.property('height', height);
+}
diff --git a/test/lib/pixi/display/DisplayObject.js b/test/lib/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..1388a7f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObject.js
@@ -0,0 +1,43 @@
+
+function pixi_display_DisplayObject_confirmNew(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObject);
+ expect(obj).to.respondTo('setInteractive');
+ expect(obj).to.respondTo('addFilter');
+ expect(obj).to.respondTo('removeFilter');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.property('last', obj);
+ expect(obj).to.have.property('first', obj);
+
+ expect(obj).to.contain.property('position');
+ pixi_core_Point_confirm(obj.position, 0, 0);
+ expect(obj).to.contain.property('scale');
+ pixi_core_Point_confirm(obj.scale, 1, 1);
+ expect(obj).to.contain.property('pivot');
+ pixi_core_Point_confirm(obj.pivot, 0, 0);
+
+ expect(obj).to.have.property('rotation', 0);
+ expect(obj).to.have.property('alpha', 1);
+ expect(obj).to.have.property('visible', true);
+ expect(obj).to.have.property('buttonMode', false);
+ expect(obj).to.have.property('parent', null);
+ expect(obj).to.have.property('worldAlpha', 1);
+
+ expect(obj).to.have.property('hitArea');
+ expect(obj).to.have.property('interactive'); // TODO: Have a better default value
+ expect('mask' in obj).to.be.true; // TODO: Have a better default value
+ expect(obj.mask).to.be.undefined;
+
+ expect(obj).to.have.property('renderable');
+ expect(obj).to.have.property('stage');
+
+ expect(obj).to.have.deep.property('worldTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ expect(obj).to.have.deep.property('localTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.localTransform);
+
+ expect(obj).to.have.deep.property('color.length', 0);
+ expect(obj).to.have.property('dynamic', true);
+}
diff --git a/test/lib/pixi/display/DisplayObjectContainer.js b/test/lib/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..085c59f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,16 @@
+
+function pixi_display_DisplayObjectContainer_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObject_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObjectContainer);
+ expect(obj).to.respondTo('addChild');
+ expect(obj).to.respondTo('addChildAt');
+ expect(obj).to.respondTo('swapChildren');
+ expect(obj).to.respondTo('getChildAt');
+ expect(obj).to.respondTo('removeChild');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('children.length', 0);
+}
diff --git a/test/lib/pixi/display/Sprite.js b/test/lib/pixi/display/Sprite.js
new file mode 100644
index 0000000..cc7a2d6
--- /dev/null
+++ b/test/lib/pixi/display/Sprite.js
@@ -0,0 +1,28 @@
+
+function pixi_display_Sprite_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Sprite);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', true);
+ expect(obj).to.have.property('stage', null);
+
+ expect(obj).to.have.property('anchor');
+ pixi_core_Point_confirm(obj.anchor, 0, 0);
+
+ expect(obj).to.have.property('blendMode', PIXI.blendModes.NORMAL);
+ expect(obj).to.have.property('width', 1); // TODO: is 1 expected
+ expect(obj).to.have.property('height', 1); // TODO: is 1 expected
+
+ // FIXME: Just make this a boolean that is always there
+ expect(!!obj.updateFrame).to.equal(obj.texture.baseTexture.hasLoaded);
+
+ expect(obj).to.have.property('texture');
+ pixi_textures_Texture_confirmNew(obj.texture, done);
+}
diff --git a/test/lib/pixi/extras/Strip.js b/test/lib/pixi/extras/Strip.js
new file mode 100644
index 0000000..8927a8a
--- /dev/null
+++ b/test/lib/pixi/extras/Strip.js
@@ -0,0 +1,12 @@
+
+function pixi_extras_Strip_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Strip);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ // TODO: Test properties
+}
diff --git a/test/lib/pixi/textures/Texture.js b/test/lib/pixi/textures/Texture.js
new file mode 100644
index 0000000..d5867b6
--- /dev/null
+++ b/test/lib/pixi/textures/Texture.js
@@ -0,0 +1,31 @@
+
+function pixi_textures_Texture_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ function confirmFrameDone() {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, obj.baseTexture.width, obj.baseTexture.height);
+
+ expect(obj).to.have.property('width', obj.baseTexture.width);
+ expect(obj).to.have.property('height', obj.baseTexture.height);
+ done();
+ }
+
+ expect(obj).to.be.an.instanceof(PIXI.Texture);
+ pixi_utils_EventTarget_like(obj);
+
+ expect(obj).to.have.property('baseTexture')
+ .and.to.be.an.instanceof(PIXI.BaseTexture);
+
+ expect(obj).to.have.property('scope', obj);
+
+ expect(obj).to.have.property('trim');
+ pixi_core_Point_confirm(obj.trim, 0, 0);
+
+ expect(obj).to.have.property('frame');
+ if (obj.baseTexture.hasLoaded) {
+ confirmFrameDone();
+ } else {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, 1, 1);
+ obj.addEventListener('update', confirmFrameDone);
+ }
+}
diff --git a/test/lib/pixi/utils/EventTarget.js b/test/lib/pixi/utils/EventTarget.js
new file mode 100644
index 0000000..7b1dcfa
--- /dev/null
+++ b/test/lib/pixi/utils/EventTarget.js
@@ -0,0 +1,8 @@
+
+function pixi_utils_EventTarget_like(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.respondTo('addEventListener');
+ expect(obj).to.respondTo('dispatchEvent');
+ expect(obj).to.respondTo('removeEventListener');
+}
diff --git a/test/lib/qunit-1.11.0.css b/test/lib/qunit-1.11.0.css
deleted file mode 100644
index d7fc0c8..0000000
--- a/test/lib/qunit-1.11.0.css
+++ /dev/null
@@ -1,244 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-/** Font Family and Sizes */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
- font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
-}
-
-#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
-#qunit-tests { font-size: smaller; }
-
-
-/** Resets */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter {
- margin: 0;
- padding: 0;
-}
-
-
-/** Header */
-
-#qunit-header {
- padding: 0.5em 0 0.5em 1em;
-
- color: #8699a4;
- background-color: #0d3349;
-
- font-size: 1.5em;
- line-height: 1em;
- font-weight: normal;
-
- border-radius: 5px 5px 0 0;
- -moz-border-radius: 5px 5px 0 0;
- -webkit-border-top-right-radius: 5px;
- -webkit-border-top-left-radius: 5px;
-}
-
-#qunit-header a {
- text-decoration: none;
- color: #c2ccd1;
-}
-
-#qunit-header a:hover,
-#qunit-header a:focus {
- color: #fff;
-}
-
-#qunit-testrunner-toolbar label {
- display: inline-block;
- padding: 0 .5em 0 .1em;
-}
-
-#qunit-banner {
- height: 5px;
-}
-
-#qunit-testrunner-toolbar {
- padding: 0.5em 0 0.5em 2em;
- color: #5E740B;
- background-color: #eee;
- overflow: hidden;
-}
-
-#qunit-userAgent {
- padding: 0.5em 0 0.5em 2.5em;
- background-color: #2b81af;
- color: #fff;
- text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
-}
-
-#qunit-modulefilter-container {
- float: right;
-}
-
-/** Tests: Pass/Fail */
-
-#qunit-tests {
- list-style-position: inside;
-}
-
-#qunit-tests li {
- padding: 0.4em 0.5em 0.4em 2.5em;
- border-bottom: 1px solid #fff;
- list-style-position: inside;
-}
-
-#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running {
- display: none;
-}
-
-#qunit-tests li strong {
- cursor: pointer;
-}
-
-#qunit-tests li a {
- padding: 0.5em;
- color: #c2ccd1;
- text-decoration: none;
-}
-#qunit-tests li a:hover,
-#qunit-tests li a:focus {
- color: #000;
-}
-
-#qunit-tests li .runtime {
- float: right;
- font-size: smaller;
-}
-
-.qunit-assert-list {
- margin-top: 0.5em;
- padding: 0.5em;
-
- background-color: #fff;
-
- border-radius: 5px;
- -moz-border-radius: 5px;
- -webkit-border-radius: 5px;
-}
-
-.qunit-collapsed {
- display: none;
-}
-
-#qunit-tests table {
- border-collapse: collapse;
- margin-top: .2em;
-}
-
-#qunit-tests th {
- text-align: right;
- vertical-align: top;
- padding: 0 .5em 0 0;
-}
-
-#qunit-tests td {
- vertical-align: top;
-}
-
-#qunit-tests pre {
- margin: 0;
- white-space: pre-wrap;
- word-wrap: break-word;
-}
-
-#qunit-tests del {
- background-color: #e0f2be;
- color: #374e0c;
- text-decoration: none;
-}
-
-#qunit-tests ins {
- background-color: #ffcaca;
- color: #500;
- text-decoration: none;
-}
-
-/*** Test Counts */
-
-#qunit-tests b.counts { color: black; }
-#qunit-tests b.passed { color: #5E740B; }
-#qunit-tests b.failed { color: #710909; }
-
-#qunit-tests li li {
- padding: 5px;
- background-color: #fff;
- border-bottom: none;
- list-style-position: inside;
-}
-
-/*** Passing Styles */
-
-#qunit-tests li li.pass {
- color: #3c510c;
- background-color: #fff;
- border-left: 10px solid #C6E746;
-}
-
-#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
-#qunit-tests .pass .test-name { color: #366097; }
-
-#qunit-tests .pass .test-actual,
-#qunit-tests .pass .test-expected { color: #999999; }
-
-#qunit-banner.qunit-pass { background-color: #C6E746; }
-
-/*** Failing Styles */
-
-#qunit-tests li li.fail {
- color: #710909;
- background-color: #fff;
- border-left: 10px solid #EE5757;
- white-space: pre;
-}
-
-#qunit-tests > li:last-child {
- border-radius: 0 0 5px 5px;
- -moz-border-radius: 0 0 5px 5px;
- -webkit-border-bottom-right-radius: 5px;
- -webkit-border-bottom-left-radius: 5px;
-}
-
-#qunit-tests .fail { color: #000000; background-color: #EE5757; }
-#qunit-tests .fail .test-name,
-#qunit-tests .fail .module-name { color: #000000; }
-
-#qunit-tests .fail .test-actual { color: #EE5757; }
-#qunit-tests .fail .test-expected { color: green; }
-
-#qunit-banner.qunit-fail { background-color: #EE5757; }
-
-
-/** Result */
-
-#qunit-testresult {
- padding: 0.5em 0.5em 0.5em 2.5em;
-
- color: #2b81af;
- background-color: #D2E0E6;
-
- border-bottom: 1px solid white;
-}
-#qunit-testresult .module-name {
- font-weight: bold;
-}
-
-/** Fixture */
-
-#qunit-fixture {
- position: absolute;
- top: -10000px;
- left: -10000px;
- width: 1000px;
- height: 1000px;
-}
diff --git a/test/lib/qunit-1.11.0.js b/test/lib/qunit-1.11.0.js
deleted file mode 100644
index 302545f..0000000
--- a/test/lib/qunit-1.11.0.js
+++ /dev/null
@@ -1,2152 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-(function( window ) {
-
-var QUnit,
- assert,
- config,
- onErrorFnPrev,
- testId = 0,
- fileName = (sourceFromStacktrace( 0 ) || "" ).replace(/(:\d+)+\)?/, "").replace(/.+\//, ""),
- toString = Object.prototype.toString,
- hasOwn = Object.prototype.hasOwnProperty,
- // Keep a local reference to Date (GH-283)
- Date = window.Date,
- defined = {
- setTimeout: typeof window.setTimeout !== "undefined",
- sessionStorage: (function() {
- var x = "qunit-test-string";
- try {
- sessionStorage.setItem( x, x );
- sessionStorage.removeItem( x );
- return true;
- } catch( e ) {
- return false;
- }
- }())
- },
- /**
- * Provides a normalized error string, correcting an issue
- * with IE 7 (and prior) where Error.prototype.toString is
- * not properly implemented
- *
- * Based on http://es5.github.com/#x15.11.4.4
- *
- * @param {String|Error} error
- * @return {String} error message
- */
- errorString = function( error ) {
- var name, message,
- errorString = error.toString();
- if ( errorString.substring( 0, 7 ) === "[object" ) {
- name = error.name ? error.name.toString() : "Error";
- message = error.message ? error.message.toString() : "";
- if ( name && message ) {
- return name + ": " + message;
- } else if ( name ) {
- return name;
- } else if ( message ) {
- return message;
- } else {
- return "Error";
- }
- } else {
- return errorString;
- }
- },
- /**
- * Makes a clone of an object using only Array or Object as base,
- * and copies over the own enumerable properties.
- *
- * @param {Object} obj
- * @return {Object} New object with only the own properties (recursively).
- */
- objectValues = function( obj ) {
- // Grunt 0.3.x uses an older version of jshint that still has jshint/jshint#392.
- /*jshint newcap: false */
- var key, val,
- vals = QUnit.is( "array", obj ) ? [] : {};
- for ( key in obj ) {
- if ( hasOwn.call( obj, key ) ) {
- val = obj[key];
- vals[key] = val === Object(val) ? objectValues(val) : val;
- }
- }
- return vals;
- };
-
-function Test( settings ) {
- extend( this, settings );
- this.assertions = [];
- this.testNumber = ++Test.count;
-}
-
-Test.count = 0;
-
-Test.prototype = {
- init: function() {
- var a, b, li,
- tests = id( "qunit-tests" );
-
- if ( tests ) {
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml;
-
- // `a` initialized at top of scope
- a = document.createElement( "a" );
- a.innerHTML = "Rerun";
- a.href = QUnit.url({ testNumber: this.testNumber });
-
- li = document.createElement( "li" );
- li.appendChild( b );
- li.appendChild( a );
- li.className = "running";
- li.id = this.id = "qunit-test-output" + testId++;
-
- tests.appendChild( li );
- }
- },
- setup: function() {
- if ( this.module !== config.previousModule ) {
- if ( config.previousModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.previousModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
- config.previousModule = this.module;
- config.moduleStats = { all: 0, bad: 0 };
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- } else if ( config.autorun ) {
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- }
-
- config.current = this;
-
- this.testEnvironment = extend({
- setup: function() {},
- teardown: function() {}
- }, this.moduleTestEnvironment );
-
- this.started = +new Date();
- runLoggingCallbacks( "testStart", QUnit, {
- name: this.testName,
- module: this.module
- });
-
- // allow utility functions to access the current test environment
- // TODO why??
- QUnit.current_testEnvironment = this.testEnvironment;
-
- if ( !config.pollution ) {
- saveGlobal();
- }
- if ( config.notrycatch ) {
- this.testEnvironment.setup.call( this.testEnvironment );
- return;
- }
- try {
- this.testEnvironment.setup.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Setup failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- },
- run: function() {
- config.current = this;
-
- var running = id( "qunit-testresult" );
-
- if ( running ) {
- running.innerHTML = "Running:
" + this.nameHtml;
- }
-
- if ( this.async ) {
- QUnit.stop();
- }
-
- this.callbackStarted = +new Date();
-
- if ( config.notrycatch ) {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- return;
- }
-
- try {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- } catch( e ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
-
- QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + " " + this.stack + ": " + ( e.message || e ), extractStacktrace( e, 0 ) );
- // else next test will carry the responsibility
- saveGlobal();
-
- // Restart the tests if they're blocking
- if ( config.blocking ) {
- QUnit.start();
- }
- }
- },
- teardown: function() {
- config.current = this;
- if ( config.notrycatch ) {
- if ( typeof this.callbackRuntime === "undefined" ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
- }
- this.testEnvironment.teardown.call( this.testEnvironment );
- return;
- } else {
- try {
- this.testEnvironment.teardown.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Teardown failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- }
- checkPollution();
- },
- finish: function() {
- config.current = this;
- if ( config.requireExpects && this.expected === null ) {
- QUnit.pushFailure( "Expected number of assertions to be defined, but expect() was not called.", this.stack );
- } else if ( this.expected !== null && this.expected !== this.assertions.length ) {
- QUnit.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack );
- } else if ( this.expected === null && !this.assertions.length ) {
- QUnit.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions.", this.stack );
- }
-
- var i, assertion, a, b, time, li, ol,
- test = this,
- good = 0,
- bad = 0,
- tests = id( "qunit-tests" );
-
- this.runtime = +new Date() - this.started;
- config.stats.all += this.assertions.length;
- config.moduleStats.all += this.assertions.length;
-
- if ( tests ) {
- ol = document.createElement( "ol" );
- ol.className = "qunit-assert-list";
-
- for ( i = 0; i < this.assertions.length; i++ ) {
- assertion = this.assertions[i];
-
- li = document.createElement( "li" );
- li.className = assertion.result ? "pass" : "fail";
- li.innerHTML = assertion.message || ( assertion.result ? "okay" : "failed" );
- ol.appendChild( li );
-
- if ( assertion.result ) {
- good++;
- } else {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
-
- // store result when possible
- if ( QUnit.config.reorder && defined.sessionStorage ) {
- if ( bad ) {
- sessionStorage.setItem( "qunit-test-" + this.module + "-" + this.testName, bad );
- } else {
- sessionStorage.removeItem( "qunit-test-" + this.module + "-" + this.testName );
- }
- }
-
- if ( bad === 0 ) {
- addClass( ol, "qunit-collapsed" );
- }
-
- // `b` initialized at top of scope
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml + " (" + bad + ", " + good + ", " + this.assertions.length + ")";
-
- addEvent(b, "click", function() {
- var next = b.parentNode.lastChild,
- collapsed = hasClass( next, "qunit-collapsed" );
- ( collapsed ? removeClass : addClass )( next, "qunit-collapsed" );
- });
-
- addEvent(b, "dblclick", function( e ) {
- var target = e && e.target ? e.target : window.event.srcElement;
- if ( target.nodeName.toLowerCase() === "span" || target.nodeName.toLowerCase() === "b" ) {
- target = target.parentNode;
- }
- if ( window.location && target.nodeName.toLowerCase() === "strong" ) {
- window.location = QUnit.url({ testNumber: test.testNumber });
- }
- });
-
- // `time` initialized at top of scope
- time = document.createElement( "span" );
- time.className = "runtime";
- time.innerHTML = this.runtime + " ms";
-
- // `li` initialized at top of scope
- li = id( this.id );
- li.className = bad ? "fail" : "pass";
- li.removeChild( li.firstChild );
- a = li.firstChild;
- li.appendChild( b );
- li.appendChild( a );
- li.appendChild( time );
- li.appendChild( ol );
-
- } else {
- for ( i = 0; i < this.assertions.length; i++ ) {
- if ( !this.assertions[i].result ) {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
- }
-
- runLoggingCallbacks( "testDone", QUnit, {
- name: this.testName,
- module: this.module,
- failed: bad,
- passed: this.assertions.length - bad,
- total: this.assertions.length,
- duration: this.runtime
- });
-
- QUnit.reset();
-
- config.current = undefined;
- },
-
- queue: function() {
- var bad,
- test = this;
-
- synchronize(function() {
- test.init();
- });
- function run() {
- // each of these can by async
- synchronize(function() {
- test.setup();
- });
- synchronize(function() {
- test.run();
- });
- synchronize(function() {
- test.teardown();
- });
- synchronize(function() {
- test.finish();
- });
- }
-
- // `bad` initialized at top of scope
- // defer when previous test run passed, if storage is available
- bad = QUnit.config.reorder && defined.sessionStorage &&
- +sessionStorage.getItem( "qunit-test-" + this.module + "-" + this.testName );
-
- if ( bad ) {
- run();
- } else {
- synchronize( run, true );
- }
- }
-};
-
-// Root QUnit object.
-// `QUnit` initialized at top of scope
-QUnit = {
-
- // call on start of module test to prepend name to all tests
- module: function( name, testEnvironment ) {
- config.currentModule = name;
- config.currentModuleTestEnvironment = testEnvironment;
- config.modules[name] = true;
- },
-
- asyncTest: function( testName, expected, callback ) {
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- QUnit.test( testName, expected, callback, true );
- },
-
- test: function( testName, expected, callback, async ) {
- var test,
- nameHtml = "" + escapeText( testName ) + "";
-
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- if ( config.currentModule ) {
- nameHtml = "" + escapeText( config.currentModule ) + ": " + nameHtml;
- }
-
- test = new Test({
- nameHtml: nameHtml,
- testName: testName,
- expected: expected,
- async: async,
- callback: callback,
- module: config.currentModule,
- moduleTestEnvironment: config.currentModuleTestEnvironment,
- stack: sourceFromStacktrace( 2 )
- });
-
- if ( !validTest( test ) ) {
- return;
- }
-
- test.queue();
- },
-
- // Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through.
- expect: function( asserts ) {
- if (arguments.length === 1) {
- config.current.expected = asserts;
- } else {
- return config.current.expected;
- }
- },
-
- start: function( count ) {
- // QUnit hasn't been initialized yet.
- // Note: RequireJS (et al) may delay onLoad
- if ( config.semaphore === undefined ) {
- QUnit.begin(function() {
- // This is triggered at the top of QUnit.load, push start() to the event loop, to allow QUnit.load to finish first
- setTimeout(function() {
- QUnit.start( count );
- });
- });
- return;
- }
-
- config.semaphore -= count || 1;
- // don't start until equal number of stop-calls
- if ( config.semaphore > 0 ) {
- return;
- }
- // ignore if start is called more often then stop
- if ( config.semaphore < 0 ) {
- config.semaphore = 0;
- QUnit.pushFailure( "Called start() while already started (QUnit.config.semaphore was 0 already)", null, sourceFromStacktrace(2) );
- return;
- }
- // A slight delay, to avoid any current callbacks
- if ( defined.setTimeout ) {
- window.setTimeout(function() {
- if ( config.semaphore > 0 ) {
- return;
- }
- if ( config.timeout ) {
- clearTimeout( config.timeout );
- }
-
- config.blocking = false;
- process( true );
- }, 13);
- } else {
- config.blocking = false;
- process( true );
- }
- },
-
- stop: function( count ) {
- config.semaphore += count || 1;
- config.blocking = true;
-
- if ( config.testTimeout && defined.setTimeout ) {
- clearTimeout( config.timeout );
- config.timeout = window.setTimeout(function() {
- QUnit.ok( false, "Test timed out" );
- config.semaphore = 1;
- QUnit.start();
- }, config.testTimeout );
- }
- }
-};
-
-// `assert` initialized at top of scope
-// Asssert helpers
-// All of these must either call QUnit.push() or manually do:
-// - runLoggingCallbacks( "log", .. );
-// - config.current.assertions.push({ .. });
-// We attach it to the QUnit object *after* we expose the public API,
-// otherwise `assert` will become a global variable in browsers (#341).
-assert = {
- /**
- * Asserts rough true-ish result.
- * @name ok
- * @function
- * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" );
- */
- ok: function( result, msg ) {
- if ( !config.current ) {
- throw new Error( "ok() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
- result = !!result;
-
- var source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: msg
- };
-
- msg = escapeText( msg || (result ? "okay" : "failed" ) );
- msg = "" + msg + "";
-
- if ( !result ) {
- source = sourceFromStacktrace( 2 );
- if ( source ) {
- details.source = source;
- msg += "Source: | " + escapeText( source ) + " |
---|
";
- }
- }
- runLoggingCallbacks( "log", QUnit, details );
- config.current.assertions.push({
- result: result,
- message: msg
- });
- },
-
- /**
- * Assert that the first two arguments are equal, with an optional message.
- * Prints out both actual and expected values.
- * @name equal
- * @function
- * @example equal( format( "Received {0} bytes.", 2), "Received 2 bytes.", "format() replaces {0} with next argument" );
- */
- equal: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected == actual, actual, expected, message );
- },
-
- /**
- * @name notEqual
- * @function
- */
- notEqual: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected != actual, actual, expected, message );
- },
-
- /**
- * @name propEqual
- * @function
- */
- propEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notPropEqual
- * @function
- */
- notPropEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name deepEqual
- * @function
- */
- deepEqual: function( actual, expected, message ) {
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notDeepEqual
- * @function
- */
- notDeepEqual: function( actual, expected, message ) {
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name strictEqual
- * @function
- */
- strictEqual: function( actual, expected, message ) {
- QUnit.push( expected === actual, actual, expected, message );
- },
-
- /**
- * @name notStrictEqual
- * @function
- */
- notStrictEqual: function( actual, expected, message ) {
- QUnit.push( expected !== actual, actual, expected, message );
- },
-
- "throws": function( block, expected, message ) {
- var actual,
- expectedOutput = expected,
- ok = false;
-
- // 'expected' is optional
- if ( typeof expected === "string" ) {
- message = expected;
- expected = null;
- }
-
- config.current.ignoreGlobalErrors = true;
- try {
- block.call( config.current.testEnvironment );
- } catch (e) {
- actual = e;
- }
- config.current.ignoreGlobalErrors = false;
-
- if ( actual ) {
- // we don't want to validate thrown error
- if ( !expected ) {
- ok = true;
- expectedOutput = null;
- // expected is a regexp
- } else if ( QUnit.objectType( expected ) === "regexp" ) {
- ok = expected.test( errorString( actual ) );
- // expected is a constructor
- } else if ( actual instanceof expected ) {
- ok = true;
- // expected is a validation function which returns true is validation passed
- } else if ( expected.call( {}, actual ) === true ) {
- expectedOutput = null;
- ok = true;
- }
-
- QUnit.push( ok, actual, expectedOutput, message );
- } else {
- QUnit.pushFailure( message, null, 'No exception was thrown.' );
- }
- }
-};
-
-/**
- * @deprecate since 1.8.0
- * Kept assertion helpers in root for backwards compatibility.
- */
-extend( QUnit, assert );
-
-/**
- * @deprecated since 1.9.0
- * Kept root "raises()" for backwards compatibility.
- * (Note that we don't introduce assert.raises).
- */
-QUnit.raises = assert[ "throws" ];
-
-/**
- * @deprecated since 1.0.0, replaced with error pushes since 1.3.0
- * Kept to avoid TypeErrors for undefined methods.
- */
-QUnit.equals = function() {
- QUnit.push( false, false, false, "QUnit.equals has been deprecated since 2009 (e88049a0), use QUnit.equal instead" );
-};
-QUnit.same = function() {
- QUnit.push( false, false, false, "QUnit.same has been deprecated since 2009 (e88049a0), use QUnit.deepEqual instead" );
-};
-
-// We want access to the constructor's prototype
-(function() {
- function F() {}
- F.prototype = QUnit;
- QUnit = new F();
- // Make F QUnit's constructor so that we can add to the prototype later
- QUnit.constructor = F;
-}());
-
-/**
- * Config object: Maintain internal state
- * Later exposed as QUnit.config
- * `config` initialized at top of scope
- */
-config = {
- // The queue of tests to run
- queue: [],
-
- // block until document ready
- blocking: true,
-
- // when enabled, show only failing tests
- // gets persisted through sessionStorage and can be changed in UI via checkbox
- hidepassed: false,
-
- // by default, run previously failed tests first
- // very useful in combination with "Hide passed tests" checked
- reorder: true,
-
- // by default, modify document.title when suite is done
- altertitle: true,
-
- // when enabled, all tests must call expect()
- requireExpects: false,
-
- // add checkboxes that are persisted in the query-string
- // when enabled, the id is set to `true` as a `QUnit.config` property
- urlConfig: [
- {
- id: "noglobals",
- label: "Check for Globals",
- tooltip: "Enabling this will test if any test introduces new properties on the `window` object. Stored as query-strings."
- },
- {
- id: "notrycatch",
- label: "No try-catch",
- tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging exceptions in IE reasonable. Stored as query-strings."
- }
- ],
-
- // Set of all modules.
- modules: {},
-
- // logging callback queues
- begin: [],
- done: [],
- log: [],
- testStart: [],
- testDone: [],
- moduleStart: [],
- moduleDone: []
-};
-
-// Export global variables, unless an 'exports' object exists,
-// in that case we assume we're in CommonJS (dealt with on the bottom of the script)
-if ( typeof exports === "undefined" ) {
- extend( window, QUnit );
-
- // Expose QUnit object
- window.QUnit = QUnit;
-}
-
-// Initialize more QUnit.config and QUnit.urlParams
-(function() {
- var i,
- location = window.location || { search: "", protocol: "file:" },
- params = location.search.slice( 1 ).split( "&" ),
- length = params.length,
- urlParams = {},
- current;
-
- if ( params[ 0 ] ) {
- for ( i = 0; i < length; i++ ) {
- current = params[ i ].split( "=" );
- current[ 0 ] = decodeURIComponent( current[ 0 ] );
- // allow just a key to turn on a flag, e.g., test.html?noglobals
- current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true;
- urlParams[ current[ 0 ] ] = current[ 1 ];
- }
- }
-
- QUnit.urlParams = urlParams;
-
- // String search anywhere in moduleName+testName
- config.filter = urlParams.filter;
-
- // Exact match of the module name
- config.module = urlParams.module;
-
- config.testNumber = parseInt( urlParams.testNumber, 10 ) || null;
-
- // Figure out if we're running the tests from a server or not
- QUnit.isLocal = location.protocol === "file:";
-}());
-
-// Extend QUnit object,
-// these after set here because they should not be exposed as global functions
-extend( QUnit, {
- assert: assert,
-
- config: config,
-
- // Initialize the configuration options
- init: function() {
- extend( config, {
- stats: { all: 0, bad: 0 },
- moduleStats: { all: 0, bad: 0 },
- started: +new Date(),
- updateRate: 1000,
- blocking: false,
- autostart: true,
- autorun: false,
- filter: "",
- queue: [],
- semaphore: 1
- });
-
- var tests, banner, result,
- qunit = id( "qunit" );
-
- if ( qunit ) {
- qunit.innerHTML =
- "" +
- "" +
- "" +
- "" +
- "
";
- }
-
- tests = id( "qunit-tests" );
- banner = id( "qunit-banner" );
- result = id( "qunit-testresult" );
-
- if ( tests ) {
- tests.innerHTML = "";
- }
-
- if ( banner ) {
- banner.className = "";
- }
-
- if ( result ) {
- result.parentNode.removeChild( result );
- }
-
- if ( tests ) {
- result = document.createElement( "p" );
- result.id = "qunit-testresult";
- result.className = "result";
- tests.parentNode.insertBefore( result, tests );
- result.innerHTML = "Running...
";
- }
- },
-
- // Resets the test setup. Useful for tests that modify the DOM.
- reset: function() {
- var fixture = id( "qunit-fixture" );
- if ( fixture ) {
- fixture.innerHTML = config.fixture;
- }
- },
-
- // Trigger an event on an element.
- // @example triggerEvent( document.body, "click" );
- triggerEvent: function( elem, type, event ) {
- if ( document.createEvent ) {
- event = document.createEvent( "MouseEvents" );
- event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView,
- 0, 0, 0, 0, 0, false, false, false, false, 0, null);
-
- elem.dispatchEvent( event );
- } else if ( elem.fireEvent ) {
- elem.fireEvent( "on" + type );
- }
- },
-
- // Safe object type checking
- is: function( type, obj ) {
- return QUnit.objectType( obj ) === type;
- },
-
- objectType: function( obj ) {
- if ( typeof obj === "undefined" ) {
- return "undefined";
- // consider: typeof null === object
- }
- if ( obj === null ) {
- return "null";
- }
-
- var match = toString.call( obj ).match(/^\[object\s(.*)\]$/),
- type = match && match[1] || "";
-
- switch ( type ) {
- case "Number":
- if ( isNaN(obj) ) {
- return "nan";
- }
- return "number";
- case "String":
- case "Boolean":
- case "Array":
- case "Date":
- case "RegExp":
- case "Function":
- return type.toLowerCase();
- }
- if ( typeof obj === "object" ) {
- return "object";
- }
- return undefined;
- },
-
- push: function( result, actual, expected, message ) {
- if ( !config.current ) {
- throw new Error( "assertion outside test context, was " + sourceFromStacktrace() );
- }
-
- var output, source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: message,
- actual: actual,
- expected: expected
- };
-
- message = escapeText( message ) || ( result ? "okay" : "failed" );
- message = "" + message + "";
- output = message;
-
- if ( !result ) {
- expected = escapeText( QUnit.jsDump.parse(expected) );
- actual = escapeText( QUnit.jsDump.parse(actual) );
- output += "Expected: | " + expected + " |
";
-
- if ( actual !== expected ) {
- output += "Result: | " + actual + " |
";
- output += "Diff: | " + QUnit.diff( expected, actual ) + " |
";
- }
-
- source = sourceFromStacktrace();
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
- }
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: !!result,
- message: output
- });
- },
-
- pushFailure: function( message, source, actual ) {
- if ( !config.current ) {
- throw new Error( "pushFailure() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
-
- var output,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: false,
- message: message
- };
-
- message = escapeText( message ) || "error";
- message = "" + message + "";
- output = message;
-
- output += "";
-
- if ( actual ) {
- output += "Result: | " + escapeText( actual ) + " |
";
- }
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: false,
- message: output
- });
- },
-
- url: function( params ) {
- params = extend( extend( {}, QUnit.urlParams ), params );
- var key,
- querystring = "?";
-
- for ( key in params ) {
- if ( !hasOwn.call( params, key ) ) {
- continue;
- }
- querystring += encodeURIComponent( key ) + "=" +
- encodeURIComponent( params[ key ] ) + "&";
- }
- return window.location.protocol + "//" + window.location.host +
- window.location.pathname + querystring.slice( 0, -1 );
- },
-
- extend: extend,
- id: id,
- addEvent: addEvent
- // load, equiv, jsDump, diff: Attached later
-});
-
-/**
- * @deprecated: Created for backwards compatibility with test runner that set the hook function
- * into QUnit.{hook}, instead of invoking it and passing the hook function.
- * QUnit.constructor is set to the empty F() above so that we can add to it's prototype here.
- * Doing this allows us to tell if the following methods have been overwritten on the actual
- * QUnit object.
- */
-extend( QUnit.constructor.prototype, {
-
- // Logging callbacks; all receive a single argument with the listed properties
- // run test/logs.html for any related changes
- begin: registerLoggingCallback( "begin" ),
-
- // done: { failed, passed, total, runtime }
- done: registerLoggingCallback( "done" ),
-
- // log: { result, actual, expected, message }
- log: registerLoggingCallback( "log" ),
-
- // testStart: { name }
- testStart: registerLoggingCallback( "testStart" ),
-
- // testDone: { name, failed, passed, total, duration }
- testDone: registerLoggingCallback( "testDone" ),
-
- // moduleStart: { name }
- moduleStart: registerLoggingCallback( "moduleStart" ),
-
- // moduleDone: { name, failed, passed, total }
- moduleDone: registerLoggingCallback( "moduleDone" )
-});
-
-if ( typeof document === "undefined" || document.readyState === "complete" ) {
- config.autorun = true;
-}
-
-QUnit.load = function() {
- runLoggingCallbacks( "begin", QUnit, {} );
-
- // Initialize the config, saving the execution queue
- var banner, filter, i, label, len, main, ol, toolbar, userAgent, val,
- urlConfigCheckboxesContainer, urlConfigCheckboxes, moduleFilter,
- numModules = 0,
- moduleFilterHtml = "",
- urlConfigHtml = "",
- oldconfig = extend( {}, config );
-
- QUnit.init();
- extend(config, oldconfig);
-
- config.blocking = false;
-
- len = config.urlConfig.length;
-
- for ( i = 0; i < len; i++ ) {
- val = config.urlConfig[i];
- if ( typeof val === "string" ) {
- val = {
- id: val,
- label: val,
- tooltip: "[no tooltip available]"
- };
- }
- config[ val.id ] = QUnit.urlParams[ val.id ];
- urlConfigHtml += "";
- }
-
- moduleFilterHtml += "";
-
- // `userAgent` initialized at top of scope
- userAgent = id( "qunit-userAgent" );
- if ( userAgent ) {
- userAgent.innerHTML = navigator.userAgent;
- }
-
- // `banner` initialized at top of scope
- banner = id( "qunit-header" );
- if ( banner ) {
- banner.innerHTML = "" + banner.innerHTML + " ";
- }
-
- // `toolbar` initialized at top of scope
- toolbar = id( "qunit-testrunner-toolbar" );
- if ( toolbar ) {
- // `filter` initialized at top of scope
- filter = document.createElement( "input" );
- filter.type = "checkbox";
- filter.id = "qunit-filter-pass";
-
- addEvent( filter, "click", function() {
- var tmp,
- ol = document.getElementById( "qunit-tests" );
-
- if ( filter.checked ) {
- ol.className = ol.className + " hidepass";
- } else {
- tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " ";
- ol.className = tmp.replace( / hidepass /, " " );
- }
- if ( defined.sessionStorage ) {
- if (filter.checked) {
- sessionStorage.setItem( "qunit-filter-passed-tests", "true" );
- } else {
- sessionStorage.removeItem( "qunit-filter-passed-tests" );
- }
- }
- });
-
- if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem( "qunit-filter-passed-tests" ) ) {
- filter.checked = true;
- // `ol` initialized at top of scope
- ol = document.getElementById( "qunit-tests" );
- ol.className = ol.className + " hidepass";
- }
- toolbar.appendChild( filter );
-
- // `label` initialized at top of scope
- label = document.createElement( "label" );
- label.setAttribute( "for", "qunit-filter-pass" );
- label.setAttribute( "title", "Only show tests and assertons that fail. Stored in sessionStorage." );
- label.innerHTML = "Hide passed tests";
- toolbar.appendChild( label );
-
- urlConfigCheckboxesContainer = document.createElement("span");
- urlConfigCheckboxesContainer.innerHTML = urlConfigHtml;
- urlConfigCheckboxes = urlConfigCheckboxesContainer.getElementsByTagName("input");
- // For oldIE support:
- // * Add handlers to the individual elements instead of the container
- // * Use "click" instead of "change"
- // * Fallback from event.target to event.srcElement
- addEvents( urlConfigCheckboxes, "click", function( event ) {
- var params = {},
- target = event.target || event.srcElement;
- params[ target.name ] = target.checked ? true : undefined;
- window.location = QUnit.url( params );
- });
- toolbar.appendChild( urlConfigCheckboxesContainer );
-
- if (numModules > 1) {
- moduleFilter = document.createElement( 'span' );
- moduleFilter.setAttribute( 'id', 'qunit-modulefilter-container' );
- moduleFilter.innerHTML = moduleFilterHtml;
- addEvent( moduleFilter.lastChild, "change", function() {
- var selectBox = moduleFilter.getElementsByTagName("select")[0],
- selectedModule = decodeURIComponent(selectBox.options[selectBox.selectedIndex].value);
-
- window.location = QUnit.url( { module: ( selectedModule === "" ) ? undefined : selectedModule } );
- });
- toolbar.appendChild(moduleFilter);
- }
- }
-
- // `main` initialized at top of scope
- main = id( "qunit-fixture" );
- if ( main ) {
- config.fixture = main.innerHTML;
- }
-
- if ( config.autostart ) {
- QUnit.start();
- }
-};
-
-addEvent( window, "load", QUnit.load );
-
-// `onErrorFnPrev` initialized at top of scope
-// Preserve other handlers
-onErrorFnPrev = window.onerror;
-
-// Cover uncaught exceptions
-// Returning true will surpress the default browser handler,
-// returning false will let it run.
-window.onerror = function ( error, filePath, linerNr ) {
- var ret = false;
- if ( onErrorFnPrev ) {
- ret = onErrorFnPrev( error, filePath, linerNr );
- }
-
- // Treat return value as window.onerror itself does,
- // Only do our handling if not surpressed.
- if ( ret !== true ) {
- if ( QUnit.config.current ) {
- if ( QUnit.config.current.ignoreGlobalErrors ) {
- return true;
- }
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- } else {
- QUnit.test( "global failure", extend( function() {
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- }, { validTest: validTest } ) );
- }
- return false;
- }
-
- return ret;
-};
-
-function done() {
- config.autorun = true;
-
- // Log the last module results
- if ( config.currentModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.currentModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
-
- var i, key,
- banner = id( "qunit-banner" ),
- tests = id( "qunit-tests" ),
- runtime = +new Date() - config.started,
- passed = config.stats.all - config.stats.bad,
- html = [
- "Tests completed in ",
- runtime,
- " milliseconds.
",
- "",
- passed,
- " assertions of ",
- config.stats.all,
- " passed, ",
- config.stats.bad,
- " failed."
- ].join( "" );
-
- if ( banner ) {
- banner.className = ( config.stats.bad ? "qunit-fail" : "qunit-pass" );
- }
-
- if ( tests ) {
- id( "qunit-testresult" ).innerHTML = html;
- }
-
- if ( config.altertitle && typeof document !== "undefined" && document.title ) {
- // show ✖ for good, ✔ for bad suite result in title
- // use escape sequences in case file gets loaded with non-utf-8-charset
- document.title = [
- ( config.stats.bad ? "\u2716" : "\u2714" ),
- document.title.replace( /^[\u2714\u2716] /i, "" )
- ].join( " " );
- }
-
- // clear own sessionStorage items if all tests passed
- if ( config.reorder && defined.sessionStorage && config.stats.bad === 0 ) {
- // `key` & `i` initialized at top of scope
- for ( i = 0; i < sessionStorage.length; i++ ) {
- key = sessionStorage.key( i++ );
- if ( key.indexOf( "qunit-test-" ) === 0 ) {
- sessionStorage.removeItem( key );
- }
- }
- }
-
- // scroll back to top to show results
- if ( window.scrollTo ) {
- window.scrollTo(0, 0);
- }
-
- runLoggingCallbacks( "done", QUnit, {
- failed: config.stats.bad,
- passed: passed,
- total: config.stats.all,
- runtime: runtime
- });
-}
-
-/** @return Boolean: true if this test should be ran */
-function validTest( test ) {
- var include,
- filter = config.filter && config.filter.toLowerCase(),
- module = config.module && config.module.toLowerCase(),
- fullName = (test.module + ": " + test.testName).toLowerCase();
-
- // Internally-generated tests are always valid
- if ( test.callback && test.callback.validTest === validTest ) {
- delete test.callback.validTest;
- return true;
- }
-
- if ( config.testNumber ) {
- return test.testNumber === config.testNumber;
- }
-
- if ( module && ( !test.module || test.module.toLowerCase() !== module ) ) {
- return false;
- }
-
- if ( !filter ) {
- return true;
- }
-
- include = filter.charAt( 0 ) !== "!";
- if ( !include ) {
- filter = filter.slice( 1 );
- }
-
- // If the filter matches, we need to honour include
- if ( fullName.indexOf( filter ) !== -1 ) {
- return include;
- }
-
- // Otherwise, do the opposite
- return !include;
-}
-
-// so far supports only Firefox, Chrome and Opera (buggy), Safari (for real exceptions)
-// Later Safari and IE10 are supposed to support error.stack as well
-// See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack
-function extractStacktrace( e, offset ) {
- offset = offset === undefined ? 3 : offset;
-
- var stack, include, i;
-
- if ( e.stacktrace ) {
- // Opera
- return e.stacktrace.split( "\n" )[ offset + 3 ];
- } else if ( e.stack ) {
- // Firefox, Chrome
- stack = e.stack.split( "\n" );
- if (/^error$/i.test( stack[0] ) ) {
- stack.shift();
- }
- if ( fileName ) {
- include = [];
- for ( i = offset; i < stack.length; i++ ) {
- if ( stack[ i ].indexOf( fileName ) !== -1 ) {
- break;
- }
- include.push( stack[ i ] );
- }
- if ( include.length ) {
- return include.join( "\n" );
- }
- }
- return stack[ offset ];
- } else if ( e.sourceURL ) {
- // Safari, PhantomJS
- // hopefully one day Safari provides actual stacktraces
- // exclude useless self-reference for generated Error objects
- if ( /qunit.js$/.test( e.sourceURL ) ) {
- return;
- }
- // for actual exceptions, this is useful
- return e.sourceURL + ":" + e.line;
- }
-}
-function sourceFromStacktrace( offset ) {
- try {
- throw new Error();
- } catch ( e ) {
- return extractStacktrace( e, offset );
- }
-}
-
-/**
- * Escape text for attribute or text content.
- */
-function escapeText( s ) {
- if ( !s ) {
- return "";
- }
- s = s + "";
- // Both single quotes and double quotes (for attributes)
- return s.replace( /['"<>&]/g, function( s ) {
- switch( s ) {
- case '\'':
- return ''';
- case '"':
- return '"';
- case '<':
- return '<';
- case '>':
- return '>';
- case '&':
- return '&';
- }
- });
-}
-
-function synchronize( callback, last ) {
- config.queue.push( callback );
-
- if ( config.autorun && !config.blocking ) {
- process( last );
- }
-}
-
-function process( last ) {
- function next() {
- process( last );
- }
- var start = new Date().getTime();
- config.depth = config.depth ? config.depth + 1 : 1;
-
- while ( config.queue.length && !config.blocking ) {
- if ( !defined.setTimeout || config.updateRate <= 0 || ( ( new Date().getTime() - start ) < config.updateRate ) ) {
- config.queue.shift()();
- } else {
- window.setTimeout( next, 13 );
- break;
- }
- }
- config.depth--;
- if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) {
- done();
- }
-}
-
-function saveGlobal() {
- config.pollution = [];
-
- if ( config.noglobals ) {
- for ( var key in window ) {
- // in Opera sometimes DOM element ids show up here, ignore them
- if ( !hasOwn.call( window, key ) || /^qunit-test-output/.test( key ) ) {
- continue;
- }
- config.pollution.push( key );
- }
- }
-}
-
-function checkPollution() {
- var newGlobals,
- deletedGlobals,
- old = config.pollution;
-
- saveGlobal();
-
- newGlobals = diff( config.pollution, old );
- if ( newGlobals.length > 0 ) {
- QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join(", ") );
- }
-
- deletedGlobals = diff( old, config.pollution );
- if ( deletedGlobals.length > 0 ) {
- QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join(", ") );
- }
-}
-
-// returns a new Array with the elements that are in a but not in b
-function diff( a, b ) {
- var i, j,
- result = a.slice();
-
- for ( i = 0; i < result.length; i++ ) {
- for ( j = 0; j < b.length; j++ ) {
- if ( result[i] === b[j] ) {
- result.splice( i, 1 );
- i--;
- break;
- }
- }
- }
- return result;
-}
-
-function extend( a, b ) {
- for ( var prop in b ) {
- if ( b[ prop ] === undefined ) {
- delete a[ prop ];
-
- // Avoid "Member not found" error in IE8 caused by setting window.constructor
- } else if ( prop !== "constructor" || a !== window ) {
- a[ prop ] = b[ prop ];
- }
- }
-
- return a;
-}
-
-/**
- * @param {HTMLElement} elem
- * @param {string} type
- * @param {Function} fn
- */
-function addEvent( elem, type, fn ) {
- // Standards-based browsers
- if ( elem.addEventListener ) {
- elem.addEventListener( type, fn, false );
- // IE
- } else {
- elem.attachEvent( "on" + type, fn );
- }
-}
-
-/**
- * @param {Array|NodeList} elems
- * @param {string} type
- * @param {Function} fn
- */
-function addEvents( elems, type, fn ) {
- var i = elems.length;
- while ( i-- ) {
- addEvent( elems[i], type, fn );
- }
-}
-
-function hasClass( elem, name ) {
- return (" " + elem.className + " ").indexOf(" " + name + " ") > -1;
-}
-
-function addClass( elem, name ) {
- if ( !hasClass( elem, name ) ) {
- elem.className += (elem.className ? " " : "") + name;
- }
-}
-
-function removeClass( elem, name ) {
- var set = " " + elem.className + " ";
- // Class name may appear multiple times
- while ( set.indexOf(" " + name + " ") > -1 ) {
- set = set.replace(" " + name + " " , " ");
- }
- // If possible, trim it for prettiness, but not neccecarily
- elem.className = window.jQuery ? jQuery.trim( set ) : ( set.trim ? set.trim() : set );
-}
-
-function id( name ) {
- return !!( typeof document !== "undefined" && document && document.getElementById ) &&
- document.getElementById( name );
-}
-
-function registerLoggingCallback( key ) {
- return function( callback ) {
- config[key].push( callback );
- };
-}
-
-// Supports deprecated method of completely overwriting logging callbacks
-function runLoggingCallbacks( key, scope, args ) {
- var i, callbacks;
- if ( QUnit.hasOwnProperty( key ) ) {
- QUnit[ key ].call(scope, args );
- } else {
- callbacks = config[ key ];
- for ( i = 0; i < callbacks.length; i++ ) {
- callbacks[ i ].call( scope, args );
- }
- }
-}
-
-// Test for equality any JavaScript type.
-// Author: Philippe Rathé
-QUnit.equiv = (function() {
-
- // Call the o related callback with the given arguments.
- function bindCallbacks( o, callbacks, args ) {
- var prop = QUnit.objectType( o );
- if ( prop ) {
- if ( QUnit.objectType( callbacks[ prop ] ) === "function" ) {
- return callbacks[ prop ].apply( callbacks, args );
- } else {
- return callbacks[ prop ]; // or undefined
- }
- }
- }
-
- // the real equiv function
- var innerEquiv,
- // stack to decide between skip/abort functions
- callers = [],
- // stack to avoiding loops from circular referencing
- parents = [],
-
- getProto = Object.getPrototypeOf || function ( obj ) {
- return obj.__proto__;
- },
- callbacks = (function () {
-
- // for string, boolean, number and null
- function useStrictEquality( b, a ) {
- /*jshint eqeqeq:false */
- if ( b instanceof a.constructor || a instanceof b.constructor ) {
- // to catch short annotaion VS 'new' annotation of a
- // declaration
- // e.g. var i = 1;
- // var j = new Number(1);
- return a == b;
- } else {
- return a === b;
- }
- }
-
- return {
- "string": useStrictEquality,
- "boolean": useStrictEquality,
- "number": useStrictEquality,
- "null": useStrictEquality,
- "undefined": useStrictEquality,
-
- "nan": function( b ) {
- return isNaN( b );
- },
-
- "date": function( b, a ) {
- return QUnit.objectType( b ) === "date" && a.valueOf() === b.valueOf();
- },
-
- "regexp": function( b, a ) {
- return QUnit.objectType( b ) === "regexp" &&
- // the regex itself
- a.source === b.source &&
- // and its modifers
- a.global === b.global &&
- // (gmi) ...
- a.ignoreCase === b.ignoreCase &&
- a.multiline === b.multiline &&
- a.sticky === b.sticky;
- },
-
- // - skip when the property is a method of an instance (OOP)
- // - abort otherwise,
- // initial === would have catch identical references anyway
- "function": function() {
- var caller = callers[callers.length - 1];
- return caller !== Object && typeof caller !== "undefined";
- },
-
- "array": function( b, a ) {
- var i, j, len, loop;
-
- // b could be an object literal here
- if ( QUnit.objectType( b ) !== "array" ) {
- return false;
- }
-
- len = a.length;
- if ( len !== b.length ) {
- // safe and faster
- return false;
- }
-
- // track reference to avoid circular references
- parents.push( a );
- for ( i = 0; i < len; i++ ) {
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- loop = true;// dont rewalk array
- }
- }
- if ( !loop && !innerEquiv(a[i], b[i]) ) {
- parents.pop();
- return false;
- }
- }
- parents.pop();
- return true;
- },
-
- "object": function( b, a ) {
- var i, j, loop,
- // Default to true
- eq = true,
- aProperties = [],
- bProperties = [];
-
- // comparing constructors is more strict than using
- // instanceof
- if ( a.constructor !== b.constructor ) {
- // Allow objects with no prototype to be equivalent to
- // objects with Object as their constructor.
- if ( !(( getProto(a) === null && getProto(b) === Object.prototype ) ||
- ( getProto(b) === null && getProto(a) === Object.prototype ) ) ) {
- return false;
- }
- }
-
- // stack constructor before traversing properties
- callers.push( a.constructor );
- // track reference to avoid circular references
- parents.push( a );
-
- for ( i in a ) { // be strict: don't ensures hasOwnProperty
- // and go deep
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- // don't go down the same path twice
- loop = true;
- }
- }
- aProperties.push(i); // collect a's properties
-
- if (!loop && !innerEquiv( a[i], b[i] ) ) {
- eq = false;
- break;
- }
- }
-
- callers.pop(); // unstack, we are done
- parents.pop();
-
- for ( i in b ) {
- bProperties.push( i ); // collect b's properties
- }
-
- // Ensures identical properties name
- return eq && innerEquiv( aProperties.sort(), bProperties.sort() );
- }
- };
- }());
-
- innerEquiv = function() { // can take multiple arguments
- var args = [].slice.apply( arguments );
- if ( args.length < 2 ) {
- return true; // end transition
- }
-
- return (function( a, b ) {
- if ( a === b ) {
- return true; // catch the most you can
- } else if ( a === null || b === null || typeof a === "undefined" ||
- typeof b === "undefined" ||
- QUnit.objectType(a) !== QUnit.objectType(b) ) {
- return false; // don't lose time with error prone cases
- } else {
- return bindCallbacks(a, callbacks, [ b, a ]);
- }
-
- // apply transition with (1..n) arguments
- }( args[0], args[1] ) && arguments.callee.apply( this, args.splice(1, args.length - 1 )) );
- };
-
- return innerEquiv;
-}());
-
-/**
- * jsDump Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com |
- * http://flesler.blogspot.com Licensed under BSD
- * (http://www.opensource.org/licenses/bsd-license.php) Date: 5/15/2008
- *
- * @projectDescription Advanced and extensible data dumping for Javascript.
- * @version 1.0.0
- * @author Ariel Flesler
- * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html}
- */
-QUnit.jsDump = (function() {
- function quote( str ) {
- return '"' + str.toString().replace( /"/g, '\\"' ) + '"';
- }
- function literal( o ) {
- return o + "";
- }
- function join( pre, arr, post ) {
- var s = jsDump.separator(),
- base = jsDump.indent(),
- inner = jsDump.indent(1);
- if ( arr.join ) {
- arr = arr.join( "," + s + inner );
- }
- if ( !arr ) {
- return pre + post;
- }
- return [ pre, inner + arr, base + post ].join(s);
- }
- function array( arr, stack ) {
- var i = arr.length, ret = new Array(i);
- this.up();
- while ( i-- ) {
- ret[i] = this.parse( arr[i] , undefined , stack);
- }
- this.down();
- return join( "[", ret, "]" );
- }
-
- var reName = /^function (\w+)/,
- jsDump = {
- // type is used mostly internally, you can fix a (custom)type in advance
- parse: function( obj, type, stack ) {
- stack = stack || [ ];
- var inStack, res,
- parser = this.parsers[ type || this.typeOf(obj) ];
-
- type = typeof parser;
- inStack = inArray( obj, stack );
-
- if ( inStack !== -1 ) {
- return "recursion(" + (inStack - stack.length) + ")";
- }
- if ( type === "function" ) {
- stack.push( obj );
- res = parser.call( this, obj, stack );
- stack.pop();
- return res;
- }
- return ( type === "string" ) ? parser : this.parsers.error;
- },
- typeOf: function( obj ) {
- var type;
- if ( obj === null ) {
- type = "null";
- } else if ( typeof obj === "undefined" ) {
- type = "undefined";
- } else if ( QUnit.is( "regexp", obj) ) {
- type = "regexp";
- } else if ( QUnit.is( "date", obj) ) {
- type = "date";
- } else if ( QUnit.is( "function", obj) ) {
- type = "function";
- } else if ( typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined" ) {
- type = "window";
- } else if ( obj.nodeType === 9 ) {
- type = "document";
- } else if ( obj.nodeType ) {
- type = "node";
- } else if (
- // native arrays
- toString.call( obj ) === "[object Array]" ||
- // NodeList objects
- ( typeof obj.length === "number" && typeof obj.item !== "undefined" && ( obj.length ? obj.item(0) === obj[0] : ( obj.item( 0 ) === null && typeof obj[0] === "undefined" ) ) )
- ) {
- type = "array";
- } else if ( obj.constructor === Error.prototype.constructor ) {
- type = "error";
- } else {
- type = typeof obj;
- }
- return type;
- },
- separator: function() {
- return this.multiline ? this.HTML ? "
" : "\n" : this.HTML ? " " : " ";
- },
- // extra can be a number, shortcut for increasing-calling-decreasing
- indent: function( extra ) {
- if ( !this.multiline ) {
- return "";
- }
- var chr = this.indentChar;
- if ( this.HTML ) {
- chr = chr.replace( /\t/g, " " ).replace( / /g, " " );
- }
- return new Array( this._depth_ + (extra||0) ).join(chr);
- },
- up: function( a ) {
- this._depth_ += a || 1;
- },
- down: function( a ) {
- this._depth_ -= a || 1;
- },
- setParser: function( name, parser ) {
- this.parsers[name] = parser;
- },
- // The next 3 are exposed so you can use them
- quote: quote,
- literal: literal,
- join: join,
- //
- _depth_: 1,
- // This is the list of parsers, to modify them, use jsDump.setParser
- parsers: {
- window: "[Window]",
- document: "[Document]",
- error: function(error) {
- return "Error(\"" + error.message + "\")";
- },
- unknown: "[Unknown]",
- "null": "null",
- "undefined": "undefined",
- "function": function( fn ) {
- var ret = "function",
- // functions never have name in IE
- name = "name" in fn ? fn.name : (reName.exec(fn) || [])[1];
-
- if ( name ) {
- ret += " " + name;
- }
- ret += "( ";
-
- ret = [ ret, QUnit.jsDump.parse( fn, "functionArgs" ), "){" ].join( "" );
- return join( ret, QUnit.jsDump.parse(fn,"functionCode" ), "}" );
- },
- array: array,
- nodelist: array,
- "arguments": array,
- object: function( map, stack ) {
- var ret = [ ], keys, key, val, i;
- QUnit.jsDump.up();
- keys = [];
- for ( key in map ) {
- keys.push( key );
- }
- keys.sort();
- for ( i = 0; i < keys.length; i++ ) {
- key = keys[ i ];
- val = map[ key ];
- ret.push( QUnit.jsDump.parse( key, "key" ) + ": " + QUnit.jsDump.parse( val, undefined, stack ) );
- }
- QUnit.jsDump.down();
- return join( "{", ret, "}" );
- },
- node: function( node ) {
- var len, i, val,
- open = QUnit.jsDump.HTML ? "<" : "<",
- close = QUnit.jsDump.HTML ? ">" : ">",
- tag = node.nodeName.toLowerCase(),
- ret = open + tag,
- attrs = node.attributes;
-
- if ( attrs ) {
- for ( i = 0, len = attrs.length; i < len; i++ ) {
- val = attrs[i].nodeValue;
- // IE6 includes all attributes in .attributes, even ones not explicitly set.
- // Those have values like undefined, null, 0, false, "" or "inherit".
- if ( val && val !== "inherit" ) {
- ret += " " + attrs[i].nodeName + "=" + QUnit.jsDump.parse( val, "attribute" );
- }
- }
- }
- ret += close;
-
- // Show content of TextNode or CDATASection
- if ( node.nodeType === 3 || node.nodeType === 4 ) {
- ret += node.nodeValue;
- }
-
- return ret + open + "/" + tag + close;
- },
- // function calls it internally, it's the arguments part of the function
- functionArgs: function( fn ) {
- var args,
- l = fn.length;
-
- if ( !l ) {
- return "";
- }
-
- args = new Array(l);
- while ( l-- ) {
- // 97 is 'a'
- args[l] = String.fromCharCode(97+l);
- }
- return " " + args.join( ", " ) + " ";
- },
- // object calls it internally, the key part of an item in a map
- key: quote,
- // function calls it internally, it's the content of the function
- functionCode: "[code]",
- // node calls it internally, it's an html attribute value
- attribute: quote,
- string: quote,
- date: quote,
- regexp: literal,
- number: literal,
- "boolean": literal
- },
- // if true, entities are escaped ( <, >, \t, space and \n )
- HTML: false,
- // indentation unit
- indentChar: " ",
- // if true, items in a collection, are separated by a \n, else just a space.
- multiline: true
- };
-
- return jsDump;
-}());
-
-// from jquery.js
-function inArray( elem, array ) {
- if ( array.indexOf ) {
- return array.indexOf( elem );
- }
-
- for ( var i = 0, length = array.length; i < length; i++ ) {
- if ( array[ i ] === elem ) {
- return i;
- }
- }
-
- return -1;
-}
-
-/*
- * Javascript Diff Algorithm
- * By John Resig (http://ejohn.org/)
- * Modified by Chu Alan "sprite"
- *
- * Released under the MIT license.
- *
- * More Info:
- * http://ejohn.org/projects/javascript-diff-algorithm/
- *
- * Usage: QUnit.diff(expected, actual)
- *
- * QUnit.diff( "the quick brown fox jumped over", "the quick fox jumps over" ) == "the quick brown fox jumped jumps over"
- */
-QUnit.diff = (function() {
- /*jshint eqeqeq:false, eqnull:true */
- function diff( o, n ) {
- var i,
- ns = {},
- os = {};
-
- for ( i = 0; i < n.length; i++ ) {
- if ( !hasOwn.call( ns, n[i] ) ) {
- ns[ n[i] ] = {
- rows: [],
- o: null
- };
- }
- ns[ n[i] ].rows.push( i );
- }
-
- for ( i = 0; i < o.length; i++ ) {
- if ( !hasOwn.call( os, o[i] ) ) {
- os[ o[i] ] = {
- rows: [],
- n: null
- };
- }
- os[ o[i] ].rows.push( i );
- }
-
- for ( i in ns ) {
- if ( !hasOwn.call( ns, i ) ) {
- continue;
- }
- if ( ns[i].rows.length === 1 && hasOwn.call( os, i ) && os[i].rows.length === 1 ) {
- n[ ns[i].rows[0] ] = {
- text: n[ ns[i].rows[0] ],
- row: os[i].rows[0]
- };
- o[ os[i].rows[0] ] = {
- text: o[ os[i].rows[0] ],
- row: ns[i].rows[0]
- };
- }
- }
-
- for ( i = 0; i < n.length - 1; i++ ) {
- if ( n[i].text != null && n[ i + 1 ].text == null && n[i].row + 1 < o.length && o[ n[i].row + 1 ].text == null &&
- n[ i + 1 ] == o[ n[i].row + 1 ] ) {
-
- n[ i + 1 ] = {
- text: n[ i + 1 ],
- row: n[i].row + 1
- };
- o[ n[i].row + 1 ] = {
- text: o[ n[i].row + 1 ],
- row: i + 1
- };
- }
- }
-
- for ( i = n.length - 1; i > 0; i-- ) {
- if ( n[i].text != null && n[ i - 1 ].text == null && n[i].row > 0 && o[ n[i].row - 1 ].text == null &&
- n[ i - 1 ] == o[ n[i].row - 1 ]) {
-
- n[ i - 1 ] = {
- text: n[ i - 1 ],
- row: n[i].row - 1
- };
- o[ n[i].row - 1 ] = {
- text: o[ n[i].row - 1 ],
- row: i - 1
- };
- }
- }
-
- return {
- o: o,
- n: n
- };
- }
-
- return function( o, n ) {
- o = o.replace( /\s+$/, "" );
- n = n.replace( /\s+$/, "" );
-
- var i, pre,
- str = "",
- out = diff( o === "" ? [] : o.split(/\s+/), n === "" ? [] : n.split(/\s+/) ),
- oSpace = o.match(/\s+/g),
- nSpace = n.match(/\s+/g);
-
- if ( oSpace == null ) {
- oSpace = [ " " ];
- }
- else {
- oSpace.push( " " );
- }
-
- if ( nSpace == null ) {
- nSpace = [ " " ];
- }
- else {
- nSpace.push( " " );
- }
-
- if ( out.n.length === 0 ) {
- for ( i = 0; i < out.o.length; i++ ) {
- str += "" + out.o[i] + oSpace[i] + "";
- }
- }
- else {
- if ( out.n[0].text == null ) {
- for ( n = 0; n < out.o.length && out.o[n].text == null; n++ ) {
- str += "" + out.o[n] + oSpace[n] + "";
- }
- }
-
- for ( i = 0; i < out.n.length; i++ ) {
- if (out.n[i].text == null) {
- str += "" + out.n[i] + nSpace[i] + "";
- }
- else {
- // `pre` initialized at top of scope
- pre = "";
-
- for ( n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++ ) {
- pre += "" + out.o[n] + oSpace[n] + "";
- }
- str += " " + out.n[i].text + nSpace[i] + pre;
- }
- }
- }
-
- return str;
- };
-}());
-
-// for CommonJS enviroments, export everything
-if ( typeof exports !== "undefined" ) {
- extend( exports, QUnit );
-}
-
-// get at whatever the global object is, like window in browsers
-}( (function() {return this;}.call()) ));
diff --git a/test/lib/require.js b/test/lib/require.js
deleted file mode 100644
index 987f865..0000000
--- a/test/lib/require.js
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- RequireJS 2.1.5 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.
- Available via the MIT or new BSD license.
- see: http://github.com/jrburke/requirejs for details
-*/
-var requirejs,require,define;
-(function(aa){function I(b){return"[object Function]"===L.call(b)}function J(b){return"[object Array]"===L.call(b)}function y(b,c){if(b){var d;for(d=0;dthis.depCount&&!this.defined){if(I(n)){if(this.events.error)try{e=i.execCb(c,n,b,e)}catch(d){a=d}else e=i.execCb(c,n,b,e);this.map.isDefine&&((b=this.module)&&void 0!==b.exports&&b.exports!==this.exports?e=b.exports:void 0===e&&this.usingExports&&(e=this.exports));if(a)return a.requireMap=this.map,a.requireModules=[this.map.id],a.requireType="define",v(this.error=
-a)}else e=n;this.exports=e;if(this.map.isDefine&&!this.ignore&&(q[c]=e,l.onResourceLoad))l.onResourceLoad(i,this.map,this.depMaps);x(c);this.defined=!0}this.defining=!1;this.defined&&!this.defineEmitted&&(this.defineEmitted=!0,this.emit("defined",this.exports),this.defineEmitComplete=!0)}}else this.fetch()}},callPlugin:function(){var a=this.map,b=a.id,d=j(a.prefix);this.depMaps.push(d);t(d,"defined",u(this,function(e){var n,d;d=this.map.name;var g=this.map.parentMap?this.map.parentMap.name:null,h=
-i.makeRequire(a.parentMap,{enableBuildCallback:!0});if(this.map.unnormalized){if(e.normalize&&(d=e.normalize(d,function(a){return c(a,g,!0)})||""),e=j(a.prefix+"!"+d,this.map.parentMap),t(e,"defined",u(this,function(a){this.init([],function(){return a},null,{enabled:!0,ignore:!0})})),d=m(p,e.id)){this.depMaps.push(e);if(this.events.error)d.on("error",u(this,function(a){this.emit("error",a)}));d.enable()}}else n=u(this,function(a){this.init([],function(){return a},null,{enabled:!0})}),n.error=u(this,
-function(a){this.inited=!0;this.error=a;a.requireModules=[b];G(p,function(a){0===a.map.id.indexOf(b+"_unnormalized")&&x(a.map.id)});v(a)}),n.fromText=u(this,function(e,c){var d=a.name,g=j(d),C=O;c&&(e=c);C&&(O=!1);r(g);s(k.config,b)&&(k.config[d]=k.config[b]);try{l.exec(e)}catch(ca){return v(B("fromtexteval","fromText eval for "+b+" failed: "+ca,ca,[b]))}C&&(O=!0);this.depMaps.push(g);i.completeLoad(d);h([d],n)}),e.load(a.name,h,n,k)}));i.enable(d,this);this.pluginMaps[d.id]=d},enable:function(){V[this.map.id]=
-this;this.enabling=this.enabled=!0;y(this.depMaps,u(this,function(a,b){var c,e;if("string"===typeof a){a=j(a,this.map.isDefine?this.map:this.map.parentMap,!1,!this.skipMap);this.depMaps[b]=a;if(c=m(N,a.id)){this.depExports[b]=c(this);return}this.depCount+=1;t(a,"defined",u(this,function(a){this.defineDep(b,a);this.check()}));this.errback&&t(a,"error",this.errback)}c=a.id;e=p[c];!s(N,c)&&(e&&!e.enabled)&&i.enable(a,this)}));G(this.pluginMaps,u(this,function(a){var b=m(p,a.id);b&&!b.enabled&&i.enable(a,
-this)}));this.enabling=!1;this.check()},on:function(a,b){var c=this.events[a];c||(c=this.events[a]=[]);c.push(b)},emit:function(a,b){y(this.events[a],function(a){a(b)});"error"===a&&delete this.events[a]}};i={config:k,contextName:b,registry:p,defined:q,urlFetched:U,defQueue:H,Module:Z,makeModuleMap:j,nextTick:l.nextTick,onError:v,configure:function(a){a.baseUrl&&"/"!==a.baseUrl.charAt(a.baseUrl.length-1)&&(a.baseUrl+="/");var b=k.pkgs,c=k.shim,e={paths:!0,config:!0,map:!0};G(a,function(a,b){e[b]?
-"map"===b?(k.map||(k.map={}),R(k[b],a,!0,!0)):R(k[b],a,!0):k[b]=a});a.shim&&(G(a.shim,function(a,b){J(a)&&(a={deps:a});if((a.exports||a.init)&&!a.exportsFn)a.exportsFn=i.makeShimExports(a);c[b]=a}),k.shim=c);a.packages&&(y(a.packages,function(a){a="string"===typeof a?{name:a}:a;b[a.name]={name:a.name,location:a.location||a.name,main:(a.main||"main").replace(ja,"").replace(ea,"")}}),k.pkgs=b);G(p,function(a,b){!a.inited&&!a.map.unnormalized&&(a.map=j(b))});if(a.deps||a.callback)i.require(a.deps||[],
-a.callback)},makeShimExports:function(a){return function(){var b;a.init&&(b=a.init.apply(aa,arguments));return b||a.exports&&ba(a.exports)}},makeRequire:function(a,f){function d(e,c,h){var g,k;f.enableBuildCallback&&(c&&I(c))&&(c.__requireJsBuild=!0);if("string"===typeof e){if(I(c))return v(B("requireargs","Invalid require call"),h);if(a&&s(N,e))return N[e](p[a.id]);if(l.get)return l.get(i,e,a,d);g=j(e,a,!1,!0);g=g.id;return!s(q,g)?v(B("notloaded",'Module name "'+g+'" has not been loaded yet for context: '+
-b+(a?"":". Use require([])"))):q[g]}L();i.nextTick(function(){L();k=r(j(null,a));k.skipMap=f.skipMap;k.init(e,c,h,{enabled:!0});D()});return d}f=f||{};R(d,{isBrowser:A,toUrl:function(b){var d,f=b.lastIndexOf("."),g=b.split("/")[0];if(-1!==f&&(!("."===g||".."===g)||1h.attachEvent.toString().indexOf("[native code"))&&!Y?(O=!0,h.attachEvent("onreadystatechange",b.onScriptLoad)):(h.addEventListener("load",b.onScriptLoad,!1),h.addEventListener("error",b.onScriptError,!1)),h.src=d,K=h,D?x.insertBefore(h,D):x.appendChild(h),K=null,h;if(da)try{importScripts(d),b.completeLoad(c)}catch(j){b.onError(B("importscripts","importScripts failed for "+c+" at "+d,j,[c]))}};A&&M(document.getElementsByTagName("script"),function(b){x||(x=
-b.parentNode);if(t=b.getAttribute("data-main"))return r.baseUrl||(E=t.split("/"),Q=E.pop(),fa=E.length?E.join("/")+"/":"./",r.baseUrl=fa,t=Q),t=t.replace(ea,""),r.deps=r.deps?r.deps.concat(t):[t],!0});define=function(b,c,d){var l,h;"string"!==typeof b&&(d=c,c=b,b=null);J(c)||(d=c,c=[]);!c.length&&I(d)&&d.length&&(d.toString().replace(la,"").replace(ma,function(b,d){c.push(d)}),c=(1===d.length?["require"]:["require","exports","module"]).concat(c));if(O){if(!(l=K))P&&"interactive"===P.readyState||M(document.getElementsByTagName("script"),
-function(b){if("interactive"===b.readyState)return P=b}),l=P;l&&(b||(b=l.getAttribute("data-requiremodule")),h=F[l.getAttribute("data-requirecontext")])}(h?h.defQueue:T).push([b,c,d])};define.amd={jQuery:!0};l.exec=function(b){return eval(b)};l(r)}})(this);
diff --git a/test/lib/resemble.js b/test/lib/resemble.js
new file mode 100644
index 0000000..1cb8c29
--- /dev/null
+++ b/test/lib/resemble.js
@@ -0,0 +1,535 @@
+/*
+Author: James Cryer
+Company: Huddle
+Last updated date: 21 Feb 2013
+URL: https://github.com/Huddle/Resemble.js
+*/
+
+(function(_this){
+ 'use strict';
+
+ _this['resemble'] = function( fileData ){
+
+ var data = {};
+ var images = [];
+ var updateCallbackArray = [];
+
+ var tolerance = { // between 0 and 255
+ red: 16,
+ green: 16,
+ blue: 16,
+ minBrightness: 16,
+ maxBrightness: 240
+ };
+
+ var ignoreAntialiasing = false;
+ var ignoreColors = false;
+
+ function triggerDataUpdate(){
+ var len = updateCallbackArray.length;
+ var i;
+ for(i=0;i tolerance.maxBrightness;
+ }
+
+ function getHue(r,g,b){
+
+ r = r / 255;
+ g = g / 255;
+ b = b / 255;
+ var max = Math.max(r, g, b), min = Math.min(r, g, b);
+ var h;
+ var d;
+
+ if (max == min){
+ h = 0; // achromatic
+ } else{
+ d = max - min;
+ switch(max){
+ case r: h = (g - b) / d + (g < b ? 6 : 0); break;
+ case g: h = (b - r) / d + 2; break;
+ case b: h = (r - g) / d + 4; break;
+ }
+ h /= 6;
+ }
+
+ return h;
+ }
+
+ function isAntialiased(sourcePix, data, cacheSet, verticalPos, horizontalPos, width){
+ var offset;
+ var targetPix;
+ var distance = 1;
+ var i;
+ var j;
+ var hasHighContrastSibling = 0;
+ var hasSiblingWithDifferentHue = 0;
+ var hasEquivilantSibling = 0;
+
+ addHueInfo(sourcePix);
+
+ for (i = distance*-1; i <= distance; i++){
+ for (j = distance*-1; j <= distance; j++){
+
+ if(i===0 && j===0){
+ // ignore source pixel
+ } else {
+
+ offset = ((verticalPos+j)*width + (horizontalPos+i)) * 4;
+ targetPix = getPixelInfo(data, offset, cacheSet);
+
+ if(targetPix === null){
+ continue;
+ }
+
+ addBrightnessInfo(targetPix);
+ addHueInfo(targetPix);
+
+ if( isContrasting(sourcePix, targetPix) ){
+ hasHighContrastSibling++;
+ }
+
+ if( isRGBSame(sourcePix,targetPix) ){
+ hasEquivilantSibling++;
+ }
+
+ if( Math.abs(targetPix.h - sourcePix.h) > 0.3 ){
+ hasSiblingWithDifferentHue++;
+ }
+
+ if( hasSiblingWithDifferentHue > 1 || hasHighContrastSibling > 1){
+ return true;
+ }
+ }
+ }
+ }
+
+ if(hasEquivilantSibling < 2){
+ return true;
+ }
+
+ return false;
+ }
+
+ function errorPixel(px, offset){
+ px[offset] = 255; //r
+ px[offset + 1] = 0; //g
+ px[offset + 2] = 255; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyPixel(px, offset, data){
+ px[offset] = data.r; //r
+ px[offset + 1] = data.g; //g
+ px[offset + 2] = data.b; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyGrayScalePixel(px, offset, data){
+ px[offset] = data.brightness; //r
+ px[offset + 1] = data.brightness; //g
+ px[offset + 2] = data.brightness; //b
+ px[offset + 3] = 255; //a
+ }
+
+
+ function getPixelInfo(data, offset, cacheSet){
+ var r;
+ var g;
+ var b;
+ var d;
+
+ if(typeof data[offset] !== 'undefined'){
+ r = data[offset];
+ g = data[offset+1];
+ b = data[offset+2];
+ d = {
+ r: r,
+ g: g,
+ b: b
+ };
+
+ return d;
+ } else {
+ return null;
+ }
+ }
+
+ function addBrightnessInfo(data){
+ data.brightness = getBrightness(data.r,data.g,data.b); // 'corrected' lightness
+ }
+
+ function addHueInfo(data){
+ data.h = getHue(data.r,data.g,data.b);
+ }
+
+ function analyseImages(img1, img2, width, height){
+
+ var hiddenCanvas = document.createElement('canvas');
+
+ var data1 = img1.data;
+ var data2 = img2.data;
+
+ hiddenCanvas.width = width;
+ hiddenCanvas.height = height;
+
+ var context = hiddenCanvas.getContext('2d');
+ var imgd = context.createImageData(width,height);
+ var targetPix = imgd.data;
+
+ var mismatchCount = 0;
+
+ var time = Date.now();
+
+ var skip;
+
+ if( (width > 1200 || height > 1200) && ignoreAntialiasing){
+ skip = 6;
+ }
+
+ loop(height, width, function(verticalPos, horizontalPos){
+
+ if(skip){ // only skip if the image isn't small
+ if(verticalPos % skip === 0 || horizontalPos % skip === 0){
+ return;
+ }
+ }
+
+ var offset = (verticalPos*width + horizontalPos) * 4;
+ var pixel1 = getPixelInfo(data1, offset, 1);
+ var pixel2 = getPixelInfo(data2, offset, 2);
+
+ if(pixel1 === null || pixel2 === null){
+ return;
+ }
+
+ if (ignoreColors){
+
+ addBrightnessInfo(pixel1);
+ addBrightnessInfo(pixel2);
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ return;
+ }
+
+ if( isRGBSimilar(pixel1, pixel2) ){
+ copyPixel(targetPix, offset, pixel2);
+
+ } else if( ignoreAntialiasing && (
+ addBrightnessInfo(pixel1), // jit pixel info augmentation looks a little weird, sorry.
+ addBrightnessInfo(pixel2),
+ isAntialiased(pixel1, data1, 1, verticalPos, horizontalPos, width) ||
+ isAntialiased(pixel2, data2, 2, verticalPos, horizontalPos, width)
+ )){
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+
+ });
+
+ data.misMatchPercentage = (mismatchCount / (height*width) * 100).toFixed(2);
+ data.analysisTime = Date.now() - time;
+
+ data.getImageDataUrl = function(text){
+ var barHeight = 0;
+
+ if(text){
+ barHeight = addLabel(text,context,hiddenCanvas);
+ }
+
+ context.putImageData(imgd, 0, barHeight);
+
+ return hiddenCanvas.toDataURL("image/png");
+ };
+ }
+
+ function addLabel(text, context, hiddenCanvas){
+ var textPadding = 2;
+
+ context.font = '12px sans-serif';
+
+ var textWidth = context.measureText(text).width + textPadding*2;
+ var barHeight = 22;
+
+ if(textWidth > hiddenCanvas.width){
+ hiddenCanvas.width = textWidth;
+ }
+
+ hiddenCanvas.height += barHeight;
+
+ context.fillStyle = "#666";
+ context.fillRect(0,0,hiddenCanvas.width,barHeight -4);
+ context.fillStyle = "#fff";
+ context.fillRect(0,barHeight -4,hiddenCanvas.width, 4);
+
+ context.fillStyle = "#fff";
+ context.textBaseline = "top";
+ context.font = '12px sans-serif';
+ context.fillText(text, textPadding, 1);
+
+ return barHeight;
+ }
+
+ function normalise(img, w, h){
+ var c;
+ var context;
+
+ if(img.height < h || img.width < w){
+ c = document.createElement('canvas');
+ c.width = w;
+ c.height = h;
+ context = c.getContext('2d');
+ context.putImageData(img, 0, 0);
+ return context.getImageData(0, 0, w, h);
+ }
+
+ return img;
+ }
+
+ function compare(one, two){
+
+ function onceWeHaveBoth(){
+ var width;
+ var height;
+ if(images.length === 2){
+ width = images[0].width > images[1].width ? images[0].width : images[1].width;
+ height = images[0].height > images[1].height ? images[0].height : images[1].height;
+
+ if( (images[0].width === images[1].width) && (images[0].height === images[1].height) ){
+ data.isSameDimensions = true;
+ } else {
+ data.isSameDimensions = false;
+ }
+
+ analyseImages( normalise(images[0],width, height), normalise(images[1],width, height), width, height);
+
+ triggerDataUpdate();
+ }
+ }
+
+ images = [];
+ loadImageData(one, onceWeHaveBoth);
+ loadImageData(two, onceWeHaveBoth);
+ }
+
+ function getCompareApi(param){
+
+ var secondFileData,
+ hasMethod = typeof param === 'function';
+
+ if( !hasMethod ){
+ // assume it's file data
+ secondFileData = param;
+ }
+
+ var self = {
+ ignoreNothing: function(){
+
+ tolerance.red = 16;
+ tolerance.green = 16;
+ tolerance.blue = 16;
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreAntialiasing: function(){
+
+ tolerance.red = 32;
+ tolerance.green = 32;
+ tolerance.blue = 32;
+ tolerance.minBrightness = 64;
+ tolerance.maxBrightness = 96;
+
+ ignoreAntialiasing = true;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreColors: function(){
+
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = true;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ onComplete: function( callback ){
+
+ updateCallbackArray.push(callback);
+
+ var wrapper = function(){
+ compare(fileData, secondFileData);
+ };
+
+ wrapper();
+
+ return getCompareApi(wrapper);
+ }
+ };
+
+ return self;
+ }
+
+ return {
+ onComplete: function( callback ){
+ updateCallbackArray.push(callback);
+ loadImageData(fileData, function(imageData, width, height){
+ parseImage(imageData.data, width, height);
+ });
+ },
+ compareTo: function(secondFileData){
+ return getCompareApi(secondFileData);
+ }
+ };
+
+ };
+}(this));
\ No newline at end of file
diff --git a/test/testsuite.js b/test/testsuite.js
deleted file mode 100644
index b486acb..0000000
--- a/test/testsuite.js
+++ /dev/null
@@ -1,36 +0,0 @@
-requirejs.config({
- baseUrl: '/test/unit/'
-});
-
-define(function(require) {
- var testModules = [
- 'Pixi',
- 'Point',
- 'Rectangle',
- 'DisplayObject',
- 'DisplayObjectContainer',
- 'Sprite',
- 'MovieClip',
- 'InteractionManager',
- 'Stage',
- 'utils/Utils',
- 'utils/EventTarget',
- 'utils/Matrix',
- 'utils/Detector',
- 'renderers/WebGLShaders',
- 'renderers/WebGLRenderer',
- 'renderers/WebGLBatch',
- 'renderers/CanvasRenderer',
- 'extras/Strip',
- 'extras/Rope',
- 'textures/BaseTexture',
- 'textures/Texture',
- 'loaders/SpriteSheetLoader',
- 'loaders/AssetLoader'
- ];
-
- // Resolve all testModules and then start the Test Runner.
- require(testModules, function() {
- QUnit.start();
- });
-});
\ No newline at end of file
diff --git a/test/textures/SpriteSheet-Aliens.png b/test/textures/SpriteSheet-Aliens.png
new file mode 100644
index 0000000..210acb1
--- /dev/null
+++ b/test/textures/SpriteSheet-Aliens.png
Binary files differ
diff --git a/test/textures/SpriteSheet-Explosion.png b/test/textures/SpriteSheet-Explosion.png
new file mode 100755
index 0000000..79e1a69
--- /dev/null
+++ b/test/textures/SpriteSheet-Explosion.png
Binary files differ
diff --git a/test/textures/bunny.png b/test/textures/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/textures/bunny.png
Binary files differ
diff --git a/test/unit/DisplayObject.js b/test/unit/DisplayObject.js
deleted file mode 100644
index 5e7e72f..0000000
--- a/test/unit/DisplayObject.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObject');
-});
diff --git a/test/unit/DisplayObjectContainer.js b/test/unit/DisplayObjectContainer.js
deleted file mode 100644
index b323959..0000000
--- a/test/unit/DisplayObjectContainer.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObjectContainer');
-});
diff --git a/test/unit/InteractionManager.js b/test/unit/InteractionManager.js
deleted file mode 100644
index e751f52..0000000
--- a/test/unit/InteractionManager.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('InteractionManager');
-});
diff --git a/test/unit/MovieClip.js b/test/unit/MovieClip.js
deleted file mode 100644
index 37d9446..0000000
--- a/test/unit/MovieClip.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('MovieClip');
-});
diff --git a/test/unit/Pixi.js b/test/unit/Pixi.js
deleted file mode 100644
index 36eee73..0000000
--- a/test/unit/Pixi.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Pixi');
-});
diff --git a/test/unit/Point.js b/test/unit/Point.js
deleted file mode 100644
index 983ff6e..0000000
--- a/test/unit/Point.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Point');
-});
diff --git a/test/unit/Rectangle.js b/test/unit/Rectangle.js
deleted file mode 100644
index 3b439ba..0000000
--- a/test/unit/Rectangle.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Rectangle');
-});
diff --git a/test/unit/Sprite.js b/test/unit/Sprite.js
deleted file mode 100644
index ed4f596..0000000
--- a/test/unit/Sprite.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Sprite');
-});
diff --git a/test/unit/Stage.js b/test/unit/Stage.js
deleted file mode 100644
index 2d70291..0000000
--- a/test/unit/Stage.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Stage');
-});
diff --git a/test/unit/extras/Rope.js b/test/unit/extras/Rope.js
deleted file mode 100644
index 5606f14..0000000
--- a/test/unit/extras/Rope.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Rope');
-});
diff --git a/test/unit/extras/Strip.js b/test/unit/extras/Strip.js
deleted file mode 100644
index 0134d3a..0000000
--- a/test/unit/extras/Strip.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Strip');
-});
diff --git a/test/unit/loaders/AssetLoader.js b/test/unit/loaders/AssetLoader.js
deleted file mode 100644
index 13b8443..0000000
--- a/test/unit/loaders/AssetLoader.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('AssetLoader');
-});
diff --git a/test/unit/loaders/SpriteSheetLoader.js b/test/unit/loaders/SpriteSheetLoader.js
deleted file mode 100644
index 8bf0cb2..0000000
--- a/test/unit/loaders/SpriteSheetLoader.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('SpriteSheetLoader');
-});
diff --git a/test/unit/pixi/InteractionManager.js b/test/unit/pixi/InteractionManager.js
new file mode 100644
index 0000000..ed3001f
--- /dev/null
+++ b/test/unit/pixi/InteractionManager.js
@@ -0,0 +1,10 @@
+describe('pixi/InteractionManager', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var InteractionManager = PIXI.InteractionManager;
+
+ it('Module exists', function () {
+ expect(InteractionManager).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/Pixi.js b/test/unit/pixi/Pixi.js
new file mode 100644
index 0000000..27debc1
--- /dev/null
+++ b/test/unit/pixi/Pixi.js
@@ -0,0 +1,9 @@
+describe('pixi/Pixi', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+
+ it('Module exists', function () {
+ expect(global).to.have.property('PIXI').and.to.be.an('object');
+ });
+});
diff --git a/test/unit/pixi/core/Circle.js b/test/unit/pixi/core/Circle.js
new file mode 100644
index 0000000..93a4456
--- /dev/null
+++ b/test/unit/pixi/core/Circle.js
@@ -0,0 +1,22 @@
+describe('pixi/core/Circle', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Circle = PIXI.Circle;
+
+ it('Module exists', function () {
+ expect(Circle).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Circle();
+
+ expect(obj).to.be.an.instanceof(Circle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', 0);
+ expect(obj).to.have.property('y', 0);
+ expect(obj).to.have.property('radius', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Ellipse.js b/test/unit/pixi/core/Ellipse.js
new file mode 100644
index 0000000..026b56f
--- /dev/null
+++ b/test/unit/pixi/core/Ellipse.js
@@ -0,0 +1,24 @@
+describe('pixi/core/Ellipse', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Ellipse = PIXI.Ellipse;
+
+ it('Module exists', function () {
+ expect(Ellipse).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Ellipse();
+
+ expect(obj).to.be.an.instanceof(Ellipse);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+ expect(obj).to.respondTo('getBounds');
+
+ expect(obj).to.have.property('x', 0);
+ expect(obj).to.have.property('y', 0);
+ expect(obj).to.have.property('width', 0);
+ expect(obj).to.have.property('height', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Matrix.js b/test/unit/pixi/core/Matrix.js
new file mode 100644
index 0000000..b48989e
--- /dev/null
+++ b/test/unit/pixi/core/Matrix.js
@@ -0,0 +1,30 @@
+describe('pixi/core/Matrix', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var mat3 = PIXI.mat3;
+ var mat4 = PIXI.mat4;
+ var Matrix = PIXI.Matrix;
+
+ it('Ensure determineMatrixArrayType works', function () {
+ expect(Matrix).to.be.a('function');
+ });
+
+ it('mat3 exists', function () {
+ expect(mat3).to.be.an('object');
+ });
+
+ it('Confirm new mat3 matrix', function () {
+ var matrix = new mat3.create();
+ pixi_core_Matrix_confirmNewMat3(matrix);
+ });
+
+ it('mat3 exists', function () {
+ expect(mat4).to.be.an('object');
+ });
+
+ it('Confirm new mat4 matrix', function () {
+ var matrix = new mat4.create();
+ pixi_core_Matrix_confirmNewMat4(matrix);
+ });
+});
diff --git a/test/unit/pixi/core/Point.js b/test/unit/pixi/core/Point.js
new file mode 100644
index 0000000..c4d5163
--- /dev/null
+++ b/test/unit/pixi/core/Point.js
@@ -0,0 +1,15 @@
+describe('pixi/core/Point', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Point = PIXI.Point;
+
+ it('Module exists', function () {
+ expect(Point).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Point();
+ pixi_core_Point_confirm(obj, 0, 0);
+ });
+});
diff --git a/test/unit/pixi/core/Polygon.js b/test/unit/pixi/core/Polygon.js
new file mode 100644
index 0000000..dc8c918
--- /dev/null
+++ b/test/unit/pixi/core/Polygon.js
@@ -0,0 +1,20 @@
+describe('pixi/core/Polygon', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Polygon = PIXI.Polygon;
+
+ it('Module exists', function () {
+ expect(Polygon).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Polygon();
+
+ expect(obj).to.be.an.instanceof(Polygon);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.deep.property('points.length', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Rectangle.js b/test/unit/pixi/core/Rectangle.js
new file mode 100644
index 0000000..d43316e
--- /dev/null
+++ b/test/unit/pixi/core/Rectangle.js
@@ -0,0 +1,15 @@
+describe('pixi/core/Rectangle', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Rectangle = PIXI.Rectangle;
+
+ it('Module exists', function () {
+ expect(Rectangle).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var rect = new Rectangle();
+ pixi_core_Rectangle_confirm(rect, 0, 0, 0, 0);
+ });
+});
diff --git a/test/unit/pixi/display/DisplayObject.js b/test/unit/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..40c6fbc
--- /dev/null
+++ b/test/unit/pixi/display/DisplayObject.js
@@ -0,0 +1,21 @@
+describe('pixi/display/DisplayObject', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var DisplayObject = PIXI.DisplayObject;
+
+ it('Module exists', function () {
+ expect(DisplayObject).to.be.a('function');
+ expect(PIXI).to.have.property('visibleCount', 0);
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new DisplayObject();
+
+ pixi_display_DisplayObject_confirmNew(obj);
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', false);
+ expect(obj).to.have.property('stage', null);
+ });
+});
diff --git a/test/unit/pixi/display/DisplayObjectContainer.js b/test/unit/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..ce7f02f
--- /dev/null
+++ b/test/unit/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,20 @@
+describe('pixi/display/DisplayObjectContainer', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var DisplayObjectContainer = PIXI.DisplayObjectContainer;
+
+ it('Module exists', function () {
+ expect(DisplayObjectContainer).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new DisplayObjectContainer();
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', false);
+ expect(obj).to.have.property('stage', null);
+ });
+});
diff --git a/test/unit/pixi/display/MovieClip.js b/test/unit/pixi/display/MovieClip.js
new file mode 100644
index 0000000..f3c6c6a
--- /dev/null
+++ b/test/unit/pixi/display/MovieClip.js
@@ -0,0 +1,33 @@
+describe('pixi/display/MovieClip', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var MovieClip = PIXI.MovieClip;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(MovieClip).to.be.a('function');
+ });
+
+ it('Confirm new instance', function (done) {
+ var texture = Texture.fromImage('/base/test/textures/SpriteSheet-Explosion.png');
+ var obj = new MovieClip([texture]);
+
+ pixi_display_Sprite_confirmNew(obj, done);
+
+ expect(obj).to.be.an.instanceof(MovieClip);
+ expect(obj).to.respondTo('stop');
+ expect(obj).to.respondTo('play');
+ expect(obj).to.respondTo('gotoAndStop');
+ expect(obj).to.respondTo('gotoAndPlay');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('textures.length', 1);
+ expect(obj).to.have.deep.property('textures[0]', texture);
+ expect(obj).to.have.property('animationSpeed', 1);
+ expect(obj).to.have.property('loop', true);
+ expect(obj).to.have.property('onComplete', null);
+ expect(obj).to.have.property('currentFrame', 0);
+ expect(obj).to.have.property('playing', false);
+ });
+});
diff --git a/test/unit/pixi/display/Sprite.js b/test/unit/pixi/display/Sprite.js
new file mode 100644
index 0000000..54e914f
--- /dev/null
+++ b/test/unit/pixi/display/Sprite.js
@@ -0,0 +1,25 @@
+describe('pixi/display/Sprite', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Sprite = PIXI.Sprite;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(Sprite).to.be.a('function');
+ expect(PIXI).to.have.deep.property('blendModes.NORMAL', 0);
+ expect(PIXI).to.have.deep.property('blendModes.SCREEN', 1);
+ });
+
+ it('Members exist', function () {
+ expect(Sprite).itself.to.respondTo('fromImage');
+ expect(Sprite).itself.to.respondTo('fromFrame');
+ });
+
+ it('Confirm new instance', function (done) {
+ var texture = Texture.fromImage('/base/test/textures/SpriteSheet-Aliens.png');
+ var obj = new Sprite(texture);
+
+ pixi_display_Sprite_confirmNew(obj, done);
+ });
+});
diff --git a/test/unit/pixi/display/Stage.js b/test/unit/pixi/display/Stage.js
new file mode 100644
index 0000000..3cc2a4d
--- /dev/null
+++ b/test/unit/pixi/display/Stage.js
@@ -0,0 +1,49 @@
+describe('pixi/display/Stage', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Stage = PIXI.Stage;
+ var InteractionManager = PIXI.InteractionManager;
+ var Rectangle = PIXI.Rectangle;
+
+ it('Module exists', function () {
+ expect(Stage).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Stage(null, true);
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(Stage);
+ expect(obj).to.respondTo('updateTransform');
+ expect(obj).to.respondTo('setBackgroundColor');
+ expect(obj).to.respondTo('getMousePosition');
+
+ // FIXME: duplicate member in DisplayObject
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ // FIXME: convert arg to bool in constructor
+ expect(obj).to.have.property('interactive', true);
+
+ expect(obj).to.have.property('interactionManager')
+ .and.to.be.an.instanceof(InteractionManager)
+ .and.to.have.property('stage', obj);
+
+ expect(obj).to.have.property('dirty', true);
+
+ expect(obj).to.have.property('stage', obj);
+
+ expect(obj).to.have.property('hitArea')
+ .and.to.be.an.instanceof(Rectangle);
+ pixi_core_Rectangle_confirm(obj.hitArea, 0, 0, 100000, 100000);
+
+ expect(obj).to.have.property('backgroundColor', 0x000000);
+ expect(obj).to.have.deep.property('backgroundColorSplit.length', 3);
+ expect(obj).to.have.deep.property('backgroundColorSplit[0]', 0);
+ expect(obj).to.have.deep.property('backgroundColorSplit[1]', 0);
+ expect(obj).to.have.deep.property('backgroundColorSplit[2]', 0);
+ expect(obj).to.have.property('backgroundColorString', '#000000');
+
+ expect(obj).to.have.property('worldVisible', true);
+ });
+});
diff --git a/test/unit/pixi/extras/CustomRenderable.js b/test/unit/pixi/extras/CustomRenderable.js
new file mode 100644
index 0000000..8d83cf0
--- /dev/null
+++ b/test/unit/pixi/extras/CustomRenderable.js
@@ -0,0 +1,21 @@
+describe('pixi/extras/CustomRenderable', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var CustomRenderable = PIXI.CustomRenderable;
+
+ it('Module exists', function () {
+ expect(CustomRenderable).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new CustomRenderable();
+
+ pixi_display_DisplayObject_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(CustomRenderable);
+ expect(obj).to.respondTo('renderCanvas');
+ expect(obj).to.respondTo('initWebGL');
+ expect(obj).to.respondTo('renderWebGL');
+ });
+});
diff --git a/test/unit/pixi/extras/Rope.js b/test/unit/pixi/extras/Rope.js
new file mode 100644
index 0000000..6ddaf83
--- /dev/null
+++ b/test/unit/pixi/extras/Rope.js
@@ -0,0 +1,26 @@
+describe('pixi/extras/Rope', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Rope = PIXI.Rope;
+ var Texture = PIXI.Texture;
+ var Point = PIXI.Point;
+
+ it('Module exists', function () {
+ expect(Rope).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var texture = Texture.fromImage('/base/test/textures/bunny.png');
+ var obj = new Rope(texture, [new Point(), new Point(5, 10), new Point(10, 20)]);
+
+ pixi_extras_Strip_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(Rope);
+ expect(obj).to.respondTo('refresh');
+ expect(obj).to.respondTo('updateTransform');
+ expect(obj).to.respondTo('setTexture');
+
+ // TODO: Test properties
+ });
+});
diff --git a/test/unit/pixi/extras/Spine.js b/test/unit/pixi/extras/Spine.js
new file mode 100644
index 0000000..0708bc0
--- /dev/null
+++ b/test/unit/pixi/extras/Spine.js
@@ -0,0 +1,10 @@
+describe('pixi/extras/Spine', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Spine = PIXI.Spine;
+
+ it('Module exists', function () {
+ expect(Spine).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/extras/Strip.js b/test/unit/pixi/extras/Strip.js
new file mode 100644
index 0000000..8e564e1
--- /dev/null
+++ b/test/unit/pixi/extras/Strip.js
@@ -0,0 +1,18 @@
+describe('pixi/extras/Strip', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Strip = PIXI.Strip;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(Strip).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var texture = Texture.fromImage('/base/test/textures/bunny.png');
+ var obj = new Strip(texture, 20, 10000);
+
+ pixi_extras_Strip_confirmNew(obj);
+ });
+});
diff --git a/test/unit/pixi/extras/TilingSprite.js b/test/unit/pixi/extras/TilingSprite.js
new file mode 100644
index 0000000..56aea14
--- /dev/null
+++ b/test/unit/pixi/extras/TilingSprite.js
@@ -0,0 +1,24 @@
+describe('pixi/extras/TilingSprite', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var TilingSprite = PIXI.TilingSprite;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(TilingSprite).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var texture = Texture.fromImage('/base/test/textures/bunny.png');
+ var obj = new TilingSprite(texture, 6000, 12000);
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(TilingSprite);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ // TODO: Test properties
+ });
+});
diff --git a/test/unit/pixi/filters/FilterBlock.js b/test/unit/pixi/filters/FilterBlock.js
new file mode 100644
index 0000000..870cec0
--- /dev/null
+++ b/test/unit/pixi/filters/FilterBlock.js
@@ -0,0 +1,10 @@
+describe('pixi/filters/FilterBlock', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var FilterBlock = PIXI.FilterBlock;
+
+ it('Module exists', function () {
+ expect(FilterBlock).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/filters/MaskFilter.js b/test/unit/pixi/filters/MaskFilter.js
new file mode 100644
index 0000000..32d6a45
--- /dev/null
+++ b/test/unit/pixi/filters/MaskFilter.js
@@ -0,0 +1,10 @@
+describe('pixi/filters/MaskFilter', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ // var MaskFilter = PIXI.MaskFilter;
+
+ // it('Module exists', function () {
+ // expect(MaskFilter).to.be.a('function');
+ // });
+});
diff --git a/test/unit/pixi/loaders/AssetLoader.js b/test/unit/pixi/loaders/AssetLoader.js
new file mode 100644
index 0000000..a0aa0b5
--- /dev/null
+++ b/test/unit/pixi/loaders/AssetLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/AssetLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var AssetLoader = PIXI.AssetLoader;
+
+ it('Module exists', function () {
+ expect(AssetLoader).to.be.a('function');
+ });
+});
diff --git a/.gitignore b/.gitignore
index 12e1b62..0b88317 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
node_modules
.DS_Store
-.project
\ No newline at end of file
+.project
+*.log
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..63e4d7c
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,8 @@
+language: node_js
+node_js:
+ - 0.10
+
+before_script:
+ - npm install -g grunt-cli
+ - export DISPLAY=:99.0
+ - sh -e /etc/init.d/xvfb start
diff --git a/Gruntfile.js b/Gruntfile.js
index b083b49..103938c 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -1,10 +1,12 @@
+'use strict';
+
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-connect');
- grunt.loadNpmTasks('grunt-contrib-qunit');
grunt.loadNpmTasks('grunt-contrib-yuidoc');
+ grunt.loadTasks('tasks');
var root = 'src/pixi/',
debug = 'bin/pixi.dev.js',
@@ -79,7 +81,7 @@
},
files: {
srcBlob: '<%= dirs.src %>/**/*.js',
- testBlob: '<%= dirs.test %>/unit/**/*.js',
+ testBlob: '<%= dirs.test %>/{functional,lib/pixi,unit}/**/*.js',
build: '<%= dirs.build %>/pixi.dev.js',
buildMin: '<%= dirs.build %>/pixi.js'
},
@@ -94,7 +96,12 @@
},
jshint: {
beforeconcat: srcFiles,
- test: ['<%= files.testBlob %>'],
+ test: {
+ src: ['<%= files.testBlob %>'],
+ options: {
+ expr: true
+ }
+ },
options: {
asi: true,
smarttabs: true
@@ -128,12 +135,6 @@
]
},
connect: {
- qunit: {
- options: {
- port: grunt.option('port-test') || 9002,
- base: './'
- }
- },
test: {
options: {
port: grunt.option('port-test') || 9002,
@@ -142,13 +143,6 @@
}
}
},
- qunit: {
- all: {
- options: {
- urls: ['http://localhost:' + (grunt.option('port-test') || 9002) + '/test/index.html']
- }
- }
- },
yuidoc: {
compile: {
name: '<%= pkg.name %>',
@@ -161,6 +155,13 @@
outdir: '<%= dirs.docs %>'
}
}
+ },
+ karma: {
+ unit: {
+ configFile: 'test/karma.conf.js',
+ // browsers: ['Chrome'],
+ singleRun: true
+ }
}
});
@@ -182,9 +183,10 @@
}
)
- grunt.registerTask('default', ['concat', 'uglify', 'distribute']);
grunt.registerTask('build', ['concat', 'uglify', 'distribute']);
- grunt.registerTask('test', ['build', 'connect:qunit', 'qunit']);
+ grunt.registerTask('test', ['concat', 'jshint:test', 'karma']);
grunt.registerTask('docs', ['yuidoc']);
-
-}
\ No newline at end of file
+ grunt.registerTask('default', ['test', 'uglify', 'distribute']);
+ // Travis CI task.
+ grunt.registerTask('travis', ['test']);
+}
diff --git a/README.md b/README.md
index c62ef86..690cfe4 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,8 @@

+[](http://travis-ci.org/drkibitz/pixi.js)
+
#### JavaScript 2D Renderer ####
The aim of this project is to provide a fast lightweight 2D library that works
diff --git a/package.json b/package.json
index b373240..1246a68 100644
--- a/package.json
+++ b/package.json
@@ -18,14 +18,21 @@
"main": "bin/pixi.js",
+ "scripts": {
+ "test": "grunt travis --verbose"
+ },
+
"dependencies": {},
"devDependencies": {
"grunt": "~0.4.x",
- "grunt-contrib-jshint": "0.3.x",
+ "grunt-contrib-jshint": "0.6.x",
"grunt-contrib-uglify": "0.2.x",
- "grunt-contrib-connect": "0.2.x",
- "grunt-contrib-qunit": "0.2.x",
+ "grunt-contrib-connect": "0.3.x",
"grunt-contrib-yuidoc": "0.4.x",
- "grunt-contrib-concat": "0.1.x"
+ "grunt-contrib-concat": "0.3.x",
+ "chai": "~1.7.0",
+ "karma": "0.11.0",
+ "karma-firefox-launcher": "0.1.0",
+ "karma-mocha": "0.1.0"
}
}
diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js
index a7c520e..ee82bbd 100644
--- a/src/pixi/InteractionManager.js
+++ b/src/pixi/InteractionManager.js
@@ -62,7 +62,6 @@
this.onTouchEnd = this.onTouchEnd.bind(this);
this.onTouchMove = this.onTouchMove.bind(this);
-
this.last = 0;
}
diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js
index 1a95d20..eef1059 100644
--- a/src/pixi/core/Ellipse.js
+++ b/src/pixi/core/Ellipse.js
@@ -78,7 +78,7 @@
return (normx + normy < 0.25);
}
-PIXI.Ellipse.getBounds = function()
+PIXI.Ellipse.prototype.getBounds = function()
{
return new PIXI.Rectangle(this.x, this.y, this.width, this.height);
}
diff --git a/tasks/karma.js b/tasks/karma.js
new file mode 100644
index 0000000..c340485
--- /dev/null
+++ b/tasks/karma.js
@@ -0,0 +1,27 @@
+'use strict';
+
+var path = require('path');
+var server = require('karma').server;
+
+module.exports = function (grunt) {
+ grunt.registerMultiTask('karma', 'run karma.', function() {
+ var done = this.async();
+ var options = this.options({
+ background: false
+ });
+ var data = this.data;
+
+ //merge options onto data, with data taking precedence
+ data = grunt.util._.merge(options, data);
+ data.configFile = path.resolve(data.configFile);
+ if (data.configFile) {
+ data.configFile = grunt.template.process(data.configFile);
+ }
+
+ server.start(
+ data,
+ function(code) {
+ done(!code);
+ });
+ });
+};
diff --git a/test/functional/example-1-basics/bunny.png b/test/functional/example-1-basics/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/functional/example-1-basics/bunny.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-30.png b/test/functional/example-1-basics/frame-30.png
new file mode 100644
index 0000000..96e3409
--- /dev/null
+++ b/test/functional/example-1-basics/frame-30.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-60.png b/test/functional/example-1-basics/frame-60.png
new file mode 100644
index 0000000..af3f4ce
--- /dev/null
+++ b/test/functional/example-1-basics/frame-60.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-90.png b/test/functional/example-1-basics/frame-90.png
new file mode 100644
index 0000000..099b823
--- /dev/null
+++ b/test/functional/example-1-basics/frame-90.png
Binary files differ
diff --git a/test/functional/example-1-basics/index.js b/test/functional/example-1-basics/index.js
new file mode 100644
index 0000000..7ae7a98
--- /dev/null
+++ b/test/functional/example-1-basics/index.js
@@ -0,0 +1,133 @@
+describe('Example 1 - Basics', function () {
+ 'use strict';
+
+ var baseUri = '/base/test/functional/example-1-basics';
+ var expect = chai.expect;
+ var currentFrame = 0;
+ var frameEvents = {};
+ var stage;
+ var renderer;
+ var bunny;
+
+ function onFrame(frame, callback) {
+ frameEvents[frame] = callback;
+ }
+
+ function animate() {
+ currentFrame += 1;
+
+ requestAnimFrame( animate );
+
+ // just for fun, lets rotate mr rabbit a little
+ bunny.rotation += 0.1;
+
+ // render the stage
+ renderer.render(stage);
+
+ if (frameEvents[currentFrame])
+ frameEvents[currentFrame](currentFrame);
+ }
+
+ function initScene() {
+ // create an new instance of a pixi stage
+ stage = new PIXI.Stage(0x66FF99);
+
+ // create a renderer instance
+ renderer = PIXI.autoDetectRenderer(400, 300);
+ console.log('Is PIXI.WebGLRenderer: ' + (renderer instanceof PIXI.WebGLRenderer));
+
+ // add the renderer view element to the DOM
+ document.body.appendChild(renderer.view);
+
+ requestAnimFrame( animate );
+
+ // create a texture from an image path
+ var texture = PIXI.Texture.fromImage(baseUri + "/bunny.png");
+ // create a new Sprite using the texture
+ bunny = new PIXI.Sprite(texture);
+
+ // center the sprites anchor point
+ bunny.anchor.x = 0.5;
+ bunny.anchor.y = 0.5;
+
+ // move the sprite t the center of the screen
+ bunny.position.x = 200;
+ bunny.position.y = 150;
+
+ stage.addChild(bunny);
+ }
+
+ it('assets loaded', function (done) {
+ var loader = new PIXI.AssetLoader([
+ baseUri + '/bunny.png',
+ baseUri + '/frame-30.png',
+ baseUri + '/frame-60.png',
+ baseUri + '/frame-90.png'
+ ]);
+ // loader.on('onProgress', function (event) {
+ // console.log(event.content);
+ // });
+ loader.on('onComplete', function (event) {
+ done();
+ initScene();
+ });
+ loader.load();
+ });
+
+ it('frame 30 should match', function (done) {
+ this.timeout(700);
+ onFrame(30, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-30.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 60 should match', function (done) {
+ this.timeout(1200);
+ onFrame(60, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-60.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 90 should match', function (done) {
+ this.timeout(1700);
+ onFrame(90, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-90.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ // it('capture something', function (done) {
+ // this.timeout(2000000);
+ // onFrame(30, function () {
+ // var img = new Image();
+ // img.src = renderer.view.toDataURL('image/png');
+ // document.body.appendChild(img);
+ // });
+ // });
+});
diff --git a/test/index.html b/test/index.html
deleted file mode 100644
index 9cbcac5..0000000
--- a/test/index.html
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
- Pixi.js Test Suite
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/test/karma.conf.js b/test/karma.conf.js
new file mode 100644
index 0000000..c66a696
--- /dev/null
+++ b/test/karma.conf.js
@@ -0,0 +1,82 @@
+module.exports = function(config) {
+ config.set({
+
+ // base path, that will be used to resolve files and exclude
+ basePath : '../',
+
+ frameworks : ['mocha'],
+
+ // list of files / patterns to load in the browser
+ files : [
+ 'node_modules/chai/chai.js',
+ 'bin/pixi.dev.js',
+ 'test/lib/**/*.js',
+ 'test/unit/**/*.js',
+ // 'test/functional/**/*.js',
+ {pattern: 'test/**/*.png', watched: false, included: false, served: true}
+ ],
+
+ // list of files to exclude
+ exclude : [],
+
+ // use dolts reporter, as travis terminal does not support escaping sequences
+ // possible values: 'dots', 'progress', 'junit', 'teamcity'
+ // CLI --reporters progress
+ reporters : ['progress'],
+
+ // web server port
+ // CLI --port 9876
+ port : 9876,
+
+ // cli runner port
+ // CLI --runner-port 9100
+ runnerPort : 9100,
+
+ // enable / disable colors in the output (reporters and logs)
+ // CLI --colors --no-colors
+ colors : true,
+
+ // level of logging
+ // possible values: karma.LOG_DISABLE || karma.LOG_ERROR || karma.LOG_WARN || karma.LOG_INFO || karma.LOG_DEBUG
+ // CLI --log-level debug
+ logLevel : config.LOG_DEBUG,
+
+ // enable / disable watching file and executing tests whenever any file changes
+ // CLI --auto-watch --no-auto-watch
+ autoWatch : false,
+
+ // Start these browsers, currently available:
+ // - Chrome
+ // - ChromeCanary
+ // - Firefox
+ // - Opera
+ // - Safari (only Mac)
+ // - PhantomJS
+ // - IE (only Windows)
+ // CLI --browsers Chrome,Firefox,Safari
+ browsers : ['Firefox'],
+
+ // If browser does not capture in given timeout [ms], kill it
+ // CLI --capture-timeout 5000
+ captureTimeout : 5000,
+
+ // Auto run tests on start (when browsers are captured) and exit
+ // CLI --single-run --no-single-run
+ singleRun : true,
+
+ // report which specs are slower than 500ms
+ // CLI --report-slower-than 500
+ reportSlowerThan : 1000,
+
+ preprocessors : {
+ // '**/client/js/*.js': 'coverage'
+ },
+
+ plugins : [
+ 'karma-mocha',
+ // 'karma-chrome-launcher',
+ 'karma-firefox-launcher',
+ // 'karma-phantomjs-launcher'
+ ]
+ });
+};
diff --git a/test/lib/pixi/core/Matrix.js b/test/lib/pixi/core/Matrix.js
new file mode 100644
index 0000000..d26386b
--- /dev/null
+++ b/test/lib/pixi/core/Matrix.js
@@ -0,0 +1,40 @@
+
+function pixi_core_Matrix_confirmNewMat3(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(1);
+ expect(matrix[5]).to.equal(0);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(1);
+}
+
+function pixi_core_Matrix_confirmNewMat4(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[0]).to.equal(1);
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(0);
+ expect(matrix[5]).to.equal(1);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(0);
+ expect(matrix[9]).to.equal(0);
+ expect(matrix[10]).to.equal(1);
+ expect(matrix[11]).to.equal(0);
+ expect(matrix[12]).to.equal(0);
+ expect(matrix[13]).to.equal(0);
+ expect(matrix[14]).to.equal(0);
+ expect(matrix[15]).to.equal(1);
+}
diff --git a/test/lib/pixi/core/Point.js b/test/lib/pixi/core/Point.js
new file mode 100644
index 0000000..e5df07b
--- /dev/null
+++ b/test/lib/pixi/core/Point.js
@@ -0,0 +1,10 @@
+
+function pixi_core_Point_confirm(obj, x, y) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Point);
+ expect(obj).to.respondTo('clone');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+}
diff --git a/test/lib/pixi/core/Rectangle.js b/test/lib/pixi/core/Rectangle.js
new file mode 100644
index 0000000..23f0d12
--- /dev/null
+++ b/test/lib/pixi/core/Rectangle.js
@@ -0,0 +1,13 @@
+
+function pixi_core_Rectangle_confirm(obj, x, y, width, height) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Rectangle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+ expect(obj).to.have.property('width', width);
+ expect(obj).to.have.property('height', height);
+}
diff --git a/test/lib/pixi/display/DisplayObject.js b/test/lib/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..1388a7f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObject.js
@@ -0,0 +1,43 @@
+
+function pixi_display_DisplayObject_confirmNew(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObject);
+ expect(obj).to.respondTo('setInteractive');
+ expect(obj).to.respondTo('addFilter');
+ expect(obj).to.respondTo('removeFilter');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.property('last', obj);
+ expect(obj).to.have.property('first', obj);
+
+ expect(obj).to.contain.property('position');
+ pixi_core_Point_confirm(obj.position, 0, 0);
+ expect(obj).to.contain.property('scale');
+ pixi_core_Point_confirm(obj.scale, 1, 1);
+ expect(obj).to.contain.property('pivot');
+ pixi_core_Point_confirm(obj.pivot, 0, 0);
+
+ expect(obj).to.have.property('rotation', 0);
+ expect(obj).to.have.property('alpha', 1);
+ expect(obj).to.have.property('visible', true);
+ expect(obj).to.have.property('buttonMode', false);
+ expect(obj).to.have.property('parent', null);
+ expect(obj).to.have.property('worldAlpha', 1);
+
+ expect(obj).to.have.property('hitArea');
+ expect(obj).to.have.property('interactive'); // TODO: Have a better default value
+ expect('mask' in obj).to.be.true; // TODO: Have a better default value
+ expect(obj.mask).to.be.undefined;
+
+ expect(obj).to.have.property('renderable');
+ expect(obj).to.have.property('stage');
+
+ expect(obj).to.have.deep.property('worldTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ expect(obj).to.have.deep.property('localTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.localTransform);
+
+ expect(obj).to.have.deep.property('color.length', 0);
+ expect(obj).to.have.property('dynamic', true);
+}
diff --git a/test/lib/pixi/display/DisplayObjectContainer.js b/test/lib/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..085c59f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,16 @@
+
+function pixi_display_DisplayObjectContainer_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObject_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObjectContainer);
+ expect(obj).to.respondTo('addChild');
+ expect(obj).to.respondTo('addChildAt');
+ expect(obj).to.respondTo('swapChildren');
+ expect(obj).to.respondTo('getChildAt');
+ expect(obj).to.respondTo('removeChild');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('children.length', 0);
+}
diff --git a/test/lib/pixi/display/Sprite.js b/test/lib/pixi/display/Sprite.js
new file mode 100644
index 0000000..cc7a2d6
--- /dev/null
+++ b/test/lib/pixi/display/Sprite.js
@@ -0,0 +1,28 @@
+
+function pixi_display_Sprite_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Sprite);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', true);
+ expect(obj).to.have.property('stage', null);
+
+ expect(obj).to.have.property('anchor');
+ pixi_core_Point_confirm(obj.anchor, 0, 0);
+
+ expect(obj).to.have.property('blendMode', PIXI.blendModes.NORMAL);
+ expect(obj).to.have.property('width', 1); // TODO: is 1 expected
+ expect(obj).to.have.property('height', 1); // TODO: is 1 expected
+
+ // FIXME: Just make this a boolean that is always there
+ expect(!!obj.updateFrame).to.equal(obj.texture.baseTexture.hasLoaded);
+
+ expect(obj).to.have.property('texture');
+ pixi_textures_Texture_confirmNew(obj.texture, done);
+}
diff --git a/test/lib/pixi/extras/Strip.js b/test/lib/pixi/extras/Strip.js
new file mode 100644
index 0000000..8927a8a
--- /dev/null
+++ b/test/lib/pixi/extras/Strip.js
@@ -0,0 +1,12 @@
+
+function pixi_extras_Strip_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Strip);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ // TODO: Test properties
+}
diff --git a/test/lib/pixi/textures/Texture.js b/test/lib/pixi/textures/Texture.js
new file mode 100644
index 0000000..d5867b6
--- /dev/null
+++ b/test/lib/pixi/textures/Texture.js
@@ -0,0 +1,31 @@
+
+function pixi_textures_Texture_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ function confirmFrameDone() {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, obj.baseTexture.width, obj.baseTexture.height);
+
+ expect(obj).to.have.property('width', obj.baseTexture.width);
+ expect(obj).to.have.property('height', obj.baseTexture.height);
+ done();
+ }
+
+ expect(obj).to.be.an.instanceof(PIXI.Texture);
+ pixi_utils_EventTarget_like(obj);
+
+ expect(obj).to.have.property('baseTexture')
+ .and.to.be.an.instanceof(PIXI.BaseTexture);
+
+ expect(obj).to.have.property('scope', obj);
+
+ expect(obj).to.have.property('trim');
+ pixi_core_Point_confirm(obj.trim, 0, 0);
+
+ expect(obj).to.have.property('frame');
+ if (obj.baseTexture.hasLoaded) {
+ confirmFrameDone();
+ } else {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, 1, 1);
+ obj.addEventListener('update', confirmFrameDone);
+ }
+}
diff --git a/test/lib/pixi/utils/EventTarget.js b/test/lib/pixi/utils/EventTarget.js
new file mode 100644
index 0000000..7b1dcfa
--- /dev/null
+++ b/test/lib/pixi/utils/EventTarget.js
@@ -0,0 +1,8 @@
+
+function pixi_utils_EventTarget_like(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.respondTo('addEventListener');
+ expect(obj).to.respondTo('dispatchEvent');
+ expect(obj).to.respondTo('removeEventListener');
+}
diff --git a/test/lib/qunit-1.11.0.css b/test/lib/qunit-1.11.0.css
deleted file mode 100644
index d7fc0c8..0000000
--- a/test/lib/qunit-1.11.0.css
+++ /dev/null
@@ -1,244 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-/** Font Family and Sizes */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
- font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
-}
-
-#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
-#qunit-tests { font-size: smaller; }
-
-
-/** Resets */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter {
- margin: 0;
- padding: 0;
-}
-
-
-/** Header */
-
-#qunit-header {
- padding: 0.5em 0 0.5em 1em;
-
- color: #8699a4;
- background-color: #0d3349;
-
- font-size: 1.5em;
- line-height: 1em;
- font-weight: normal;
-
- border-radius: 5px 5px 0 0;
- -moz-border-radius: 5px 5px 0 0;
- -webkit-border-top-right-radius: 5px;
- -webkit-border-top-left-radius: 5px;
-}
-
-#qunit-header a {
- text-decoration: none;
- color: #c2ccd1;
-}
-
-#qunit-header a:hover,
-#qunit-header a:focus {
- color: #fff;
-}
-
-#qunit-testrunner-toolbar label {
- display: inline-block;
- padding: 0 .5em 0 .1em;
-}
-
-#qunit-banner {
- height: 5px;
-}
-
-#qunit-testrunner-toolbar {
- padding: 0.5em 0 0.5em 2em;
- color: #5E740B;
- background-color: #eee;
- overflow: hidden;
-}
-
-#qunit-userAgent {
- padding: 0.5em 0 0.5em 2.5em;
- background-color: #2b81af;
- color: #fff;
- text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
-}
-
-#qunit-modulefilter-container {
- float: right;
-}
-
-/** Tests: Pass/Fail */
-
-#qunit-tests {
- list-style-position: inside;
-}
-
-#qunit-tests li {
- padding: 0.4em 0.5em 0.4em 2.5em;
- border-bottom: 1px solid #fff;
- list-style-position: inside;
-}
-
-#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running {
- display: none;
-}
-
-#qunit-tests li strong {
- cursor: pointer;
-}
-
-#qunit-tests li a {
- padding: 0.5em;
- color: #c2ccd1;
- text-decoration: none;
-}
-#qunit-tests li a:hover,
-#qunit-tests li a:focus {
- color: #000;
-}
-
-#qunit-tests li .runtime {
- float: right;
- font-size: smaller;
-}
-
-.qunit-assert-list {
- margin-top: 0.5em;
- padding: 0.5em;
-
- background-color: #fff;
-
- border-radius: 5px;
- -moz-border-radius: 5px;
- -webkit-border-radius: 5px;
-}
-
-.qunit-collapsed {
- display: none;
-}
-
-#qunit-tests table {
- border-collapse: collapse;
- margin-top: .2em;
-}
-
-#qunit-tests th {
- text-align: right;
- vertical-align: top;
- padding: 0 .5em 0 0;
-}
-
-#qunit-tests td {
- vertical-align: top;
-}
-
-#qunit-tests pre {
- margin: 0;
- white-space: pre-wrap;
- word-wrap: break-word;
-}
-
-#qunit-tests del {
- background-color: #e0f2be;
- color: #374e0c;
- text-decoration: none;
-}
-
-#qunit-tests ins {
- background-color: #ffcaca;
- color: #500;
- text-decoration: none;
-}
-
-/*** Test Counts */
-
-#qunit-tests b.counts { color: black; }
-#qunit-tests b.passed { color: #5E740B; }
-#qunit-tests b.failed { color: #710909; }
-
-#qunit-tests li li {
- padding: 5px;
- background-color: #fff;
- border-bottom: none;
- list-style-position: inside;
-}
-
-/*** Passing Styles */
-
-#qunit-tests li li.pass {
- color: #3c510c;
- background-color: #fff;
- border-left: 10px solid #C6E746;
-}
-
-#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
-#qunit-tests .pass .test-name { color: #366097; }
-
-#qunit-tests .pass .test-actual,
-#qunit-tests .pass .test-expected { color: #999999; }
-
-#qunit-banner.qunit-pass { background-color: #C6E746; }
-
-/*** Failing Styles */
-
-#qunit-tests li li.fail {
- color: #710909;
- background-color: #fff;
- border-left: 10px solid #EE5757;
- white-space: pre;
-}
-
-#qunit-tests > li:last-child {
- border-radius: 0 0 5px 5px;
- -moz-border-radius: 0 0 5px 5px;
- -webkit-border-bottom-right-radius: 5px;
- -webkit-border-bottom-left-radius: 5px;
-}
-
-#qunit-tests .fail { color: #000000; background-color: #EE5757; }
-#qunit-tests .fail .test-name,
-#qunit-tests .fail .module-name { color: #000000; }
-
-#qunit-tests .fail .test-actual { color: #EE5757; }
-#qunit-tests .fail .test-expected { color: green; }
-
-#qunit-banner.qunit-fail { background-color: #EE5757; }
-
-
-/** Result */
-
-#qunit-testresult {
- padding: 0.5em 0.5em 0.5em 2.5em;
-
- color: #2b81af;
- background-color: #D2E0E6;
-
- border-bottom: 1px solid white;
-}
-#qunit-testresult .module-name {
- font-weight: bold;
-}
-
-/** Fixture */
-
-#qunit-fixture {
- position: absolute;
- top: -10000px;
- left: -10000px;
- width: 1000px;
- height: 1000px;
-}
diff --git a/test/lib/qunit-1.11.0.js b/test/lib/qunit-1.11.0.js
deleted file mode 100644
index 302545f..0000000
--- a/test/lib/qunit-1.11.0.js
+++ /dev/null
@@ -1,2152 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-(function( window ) {
-
-var QUnit,
- assert,
- config,
- onErrorFnPrev,
- testId = 0,
- fileName = (sourceFromStacktrace( 0 ) || "" ).replace(/(:\d+)+\)?/, "").replace(/.+\//, ""),
- toString = Object.prototype.toString,
- hasOwn = Object.prototype.hasOwnProperty,
- // Keep a local reference to Date (GH-283)
- Date = window.Date,
- defined = {
- setTimeout: typeof window.setTimeout !== "undefined",
- sessionStorage: (function() {
- var x = "qunit-test-string";
- try {
- sessionStorage.setItem( x, x );
- sessionStorage.removeItem( x );
- return true;
- } catch( e ) {
- return false;
- }
- }())
- },
- /**
- * Provides a normalized error string, correcting an issue
- * with IE 7 (and prior) where Error.prototype.toString is
- * not properly implemented
- *
- * Based on http://es5.github.com/#x15.11.4.4
- *
- * @param {String|Error} error
- * @return {String} error message
- */
- errorString = function( error ) {
- var name, message,
- errorString = error.toString();
- if ( errorString.substring( 0, 7 ) === "[object" ) {
- name = error.name ? error.name.toString() : "Error";
- message = error.message ? error.message.toString() : "";
- if ( name && message ) {
- return name + ": " + message;
- } else if ( name ) {
- return name;
- } else if ( message ) {
- return message;
- } else {
- return "Error";
- }
- } else {
- return errorString;
- }
- },
- /**
- * Makes a clone of an object using only Array or Object as base,
- * and copies over the own enumerable properties.
- *
- * @param {Object} obj
- * @return {Object} New object with only the own properties (recursively).
- */
- objectValues = function( obj ) {
- // Grunt 0.3.x uses an older version of jshint that still has jshint/jshint#392.
- /*jshint newcap: false */
- var key, val,
- vals = QUnit.is( "array", obj ) ? [] : {};
- for ( key in obj ) {
- if ( hasOwn.call( obj, key ) ) {
- val = obj[key];
- vals[key] = val === Object(val) ? objectValues(val) : val;
- }
- }
- return vals;
- };
-
-function Test( settings ) {
- extend( this, settings );
- this.assertions = [];
- this.testNumber = ++Test.count;
-}
-
-Test.count = 0;
-
-Test.prototype = {
- init: function() {
- var a, b, li,
- tests = id( "qunit-tests" );
-
- if ( tests ) {
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml;
-
- // `a` initialized at top of scope
- a = document.createElement( "a" );
- a.innerHTML = "Rerun";
- a.href = QUnit.url({ testNumber: this.testNumber });
-
- li = document.createElement( "li" );
- li.appendChild( b );
- li.appendChild( a );
- li.className = "running";
- li.id = this.id = "qunit-test-output" + testId++;
-
- tests.appendChild( li );
- }
- },
- setup: function() {
- if ( this.module !== config.previousModule ) {
- if ( config.previousModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.previousModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
- config.previousModule = this.module;
- config.moduleStats = { all: 0, bad: 0 };
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- } else if ( config.autorun ) {
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- }
-
- config.current = this;
-
- this.testEnvironment = extend({
- setup: function() {},
- teardown: function() {}
- }, this.moduleTestEnvironment );
-
- this.started = +new Date();
- runLoggingCallbacks( "testStart", QUnit, {
- name: this.testName,
- module: this.module
- });
-
- // allow utility functions to access the current test environment
- // TODO why??
- QUnit.current_testEnvironment = this.testEnvironment;
-
- if ( !config.pollution ) {
- saveGlobal();
- }
- if ( config.notrycatch ) {
- this.testEnvironment.setup.call( this.testEnvironment );
- return;
- }
- try {
- this.testEnvironment.setup.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Setup failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- },
- run: function() {
- config.current = this;
-
- var running = id( "qunit-testresult" );
-
- if ( running ) {
- running.innerHTML = "Running:
" + this.nameHtml;
- }
-
- if ( this.async ) {
- QUnit.stop();
- }
-
- this.callbackStarted = +new Date();
-
- if ( config.notrycatch ) {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- return;
- }
-
- try {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- } catch( e ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
-
- QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + " " + this.stack + ": " + ( e.message || e ), extractStacktrace( e, 0 ) );
- // else next test will carry the responsibility
- saveGlobal();
-
- // Restart the tests if they're blocking
- if ( config.blocking ) {
- QUnit.start();
- }
- }
- },
- teardown: function() {
- config.current = this;
- if ( config.notrycatch ) {
- if ( typeof this.callbackRuntime === "undefined" ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
- }
- this.testEnvironment.teardown.call( this.testEnvironment );
- return;
- } else {
- try {
- this.testEnvironment.teardown.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Teardown failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- }
- checkPollution();
- },
- finish: function() {
- config.current = this;
- if ( config.requireExpects && this.expected === null ) {
- QUnit.pushFailure( "Expected number of assertions to be defined, but expect() was not called.", this.stack );
- } else if ( this.expected !== null && this.expected !== this.assertions.length ) {
- QUnit.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack );
- } else if ( this.expected === null && !this.assertions.length ) {
- QUnit.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions.", this.stack );
- }
-
- var i, assertion, a, b, time, li, ol,
- test = this,
- good = 0,
- bad = 0,
- tests = id( "qunit-tests" );
-
- this.runtime = +new Date() - this.started;
- config.stats.all += this.assertions.length;
- config.moduleStats.all += this.assertions.length;
-
- if ( tests ) {
- ol = document.createElement( "ol" );
- ol.className = "qunit-assert-list";
-
- for ( i = 0; i < this.assertions.length; i++ ) {
- assertion = this.assertions[i];
-
- li = document.createElement( "li" );
- li.className = assertion.result ? "pass" : "fail";
- li.innerHTML = assertion.message || ( assertion.result ? "okay" : "failed" );
- ol.appendChild( li );
-
- if ( assertion.result ) {
- good++;
- } else {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
-
- // store result when possible
- if ( QUnit.config.reorder && defined.sessionStorage ) {
- if ( bad ) {
- sessionStorage.setItem( "qunit-test-" + this.module + "-" + this.testName, bad );
- } else {
- sessionStorage.removeItem( "qunit-test-" + this.module + "-" + this.testName );
- }
- }
-
- if ( bad === 0 ) {
- addClass( ol, "qunit-collapsed" );
- }
-
- // `b` initialized at top of scope
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml + " (" + bad + ", " + good + ", " + this.assertions.length + ")";
-
- addEvent(b, "click", function() {
- var next = b.parentNode.lastChild,
- collapsed = hasClass( next, "qunit-collapsed" );
- ( collapsed ? removeClass : addClass )( next, "qunit-collapsed" );
- });
-
- addEvent(b, "dblclick", function( e ) {
- var target = e && e.target ? e.target : window.event.srcElement;
- if ( target.nodeName.toLowerCase() === "span" || target.nodeName.toLowerCase() === "b" ) {
- target = target.parentNode;
- }
- if ( window.location && target.nodeName.toLowerCase() === "strong" ) {
- window.location = QUnit.url({ testNumber: test.testNumber });
- }
- });
-
- // `time` initialized at top of scope
- time = document.createElement( "span" );
- time.className = "runtime";
- time.innerHTML = this.runtime + " ms";
-
- // `li` initialized at top of scope
- li = id( this.id );
- li.className = bad ? "fail" : "pass";
- li.removeChild( li.firstChild );
- a = li.firstChild;
- li.appendChild( b );
- li.appendChild( a );
- li.appendChild( time );
- li.appendChild( ol );
-
- } else {
- for ( i = 0; i < this.assertions.length; i++ ) {
- if ( !this.assertions[i].result ) {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
- }
-
- runLoggingCallbacks( "testDone", QUnit, {
- name: this.testName,
- module: this.module,
- failed: bad,
- passed: this.assertions.length - bad,
- total: this.assertions.length,
- duration: this.runtime
- });
-
- QUnit.reset();
-
- config.current = undefined;
- },
-
- queue: function() {
- var bad,
- test = this;
-
- synchronize(function() {
- test.init();
- });
- function run() {
- // each of these can by async
- synchronize(function() {
- test.setup();
- });
- synchronize(function() {
- test.run();
- });
- synchronize(function() {
- test.teardown();
- });
- synchronize(function() {
- test.finish();
- });
- }
-
- // `bad` initialized at top of scope
- // defer when previous test run passed, if storage is available
- bad = QUnit.config.reorder && defined.sessionStorage &&
- +sessionStorage.getItem( "qunit-test-" + this.module + "-" + this.testName );
-
- if ( bad ) {
- run();
- } else {
- synchronize( run, true );
- }
- }
-};
-
-// Root QUnit object.
-// `QUnit` initialized at top of scope
-QUnit = {
-
- // call on start of module test to prepend name to all tests
- module: function( name, testEnvironment ) {
- config.currentModule = name;
- config.currentModuleTestEnvironment = testEnvironment;
- config.modules[name] = true;
- },
-
- asyncTest: function( testName, expected, callback ) {
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- QUnit.test( testName, expected, callback, true );
- },
-
- test: function( testName, expected, callback, async ) {
- var test,
- nameHtml = "" + escapeText( testName ) + "";
-
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- if ( config.currentModule ) {
- nameHtml = "" + escapeText( config.currentModule ) + ": " + nameHtml;
- }
-
- test = new Test({
- nameHtml: nameHtml,
- testName: testName,
- expected: expected,
- async: async,
- callback: callback,
- module: config.currentModule,
- moduleTestEnvironment: config.currentModuleTestEnvironment,
- stack: sourceFromStacktrace( 2 )
- });
-
- if ( !validTest( test ) ) {
- return;
- }
-
- test.queue();
- },
-
- // Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through.
- expect: function( asserts ) {
- if (arguments.length === 1) {
- config.current.expected = asserts;
- } else {
- return config.current.expected;
- }
- },
-
- start: function( count ) {
- // QUnit hasn't been initialized yet.
- // Note: RequireJS (et al) may delay onLoad
- if ( config.semaphore === undefined ) {
- QUnit.begin(function() {
- // This is triggered at the top of QUnit.load, push start() to the event loop, to allow QUnit.load to finish first
- setTimeout(function() {
- QUnit.start( count );
- });
- });
- return;
- }
-
- config.semaphore -= count || 1;
- // don't start until equal number of stop-calls
- if ( config.semaphore > 0 ) {
- return;
- }
- // ignore if start is called more often then stop
- if ( config.semaphore < 0 ) {
- config.semaphore = 0;
- QUnit.pushFailure( "Called start() while already started (QUnit.config.semaphore was 0 already)", null, sourceFromStacktrace(2) );
- return;
- }
- // A slight delay, to avoid any current callbacks
- if ( defined.setTimeout ) {
- window.setTimeout(function() {
- if ( config.semaphore > 0 ) {
- return;
- }
- if ( config.timeout ) {
- clearTimeout( config.timeout );
- }
-
- config.blocking = false;
- process( true );
- }, 13);
- } else {
- config.blocking = false;
- process( true );
- }
- },
-
- stop: function( count ) {
- config.semaphore += count || 1;
- config.blocking = true;
-
- if ( config.testTimeout && defined.setTimeout ) {
- clearTimeout( config.timeout );
- config.timeout = window.setTimeout(function() {
- QUnit.ok( false, "Test timed out" );
- config.semaphore = 1;
- QUnit.start();
- }, config.testTimeout );
- }
- }
-};
-
-// `assert` initialized at top of scope
-// Asssert helpers
-// All of these must either call QUnit.push() or manually do:
-// - runLoggingCallbacks( "log", .. );
-// - config.current.assertions.push({ .. });
-// We attach it to the QUnit object *after* we expose the public API,
-// otherwise `assert` will become a global variable in browsers (#341).
-assert = {
- /**
- * Asserts rough true-ish result.
- * @name ok
- * @function
- * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" );
- */
- ok: function( result, msg ) {
- if ( !config.current ) {
- throw new Error( "ok() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
- result = !!result;
-
- var source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: msg
- };
-
- msg = escapeText( msg || (result ? "okay" : "failed" ) );
- msg = "" + msg + "";
-
- if ( !result ) {
- source = sourceFromStacktrace( 2 );
- if ( source ) {
- details.source = source;
- msg += "Source: | " + escapeText( source ) + " |
---|
";
- }
- }
- runLoggingCallbacks( "log", QUnit, details );
- config.current.assertions.push({
- result: result,
- message: msg
- });
- },
-
- /**
- * Assert that the first two arguments are equal, with an optional message.
- * Prints out both actual and expected values.
- * @name equal
- * @function
- * @example equal( format( "Received {0} bytes.", 2), "Received 2 bytes.", "format() replaces {0} with next argument" );
- */
- equal: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected == actual, actual, expected, message );
- },
-
- /**
- * @name notEqual
- * @function
- */
- notEqual: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected != actual, actual, expected, message );
- },
-
- /**
- * @name propEqual
- * @function
- */
- propEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notPropEqual
- * @function
- */
- notPropEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name deepEqual
- * @function
- */
- deepEqual: function( actual, expected, message ) {
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notDeepEqual
- * @function
- */
- notDeepEqual: function( actual, expected, message ) {
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name strictEqual
- * @function
- */
- strictEqual: function( actual, expected, message ) {
- QUnit.push( expected === actual, actual, expected, message );
- },
-
- /**
- * @name notStrictEqual
- * @function
- */
- notStrictEqual: function( actual, expected, message ) {
- QUnit.push( expected !== actual, actual, expected, message );
- },
-
- "throws": function( block, expected, message ) {
- var actual,
- expectedOutput = expected,
- ok = false;
-
- // 'expected' is optional
- if ( typeof expected === "string" ) {
- message = expected;
- expected = null;
- }
-
- config.current.ignoreGlobalErrors = true;
- try {
- block.call( config.current.testEnvironment );
- } catch (e) {
- actual = e;
- }
- config.current.ignoreGlobalErrors = false;
-
- if ( actual ) {
- // we don't want to validate thrown error
- if ( !expected ) {
- ok = true;
- expectedOutput = null;
- // expected is a regexp
- } else if ( QUnit.objectType( expected ) === "regexp" ) {
- ok = expected.test( errorString( actual ) );
- // expected is a constructor
- } else if ( actual instanceof expected ) {
- ok = true;
- // expected is a validation function which returns true is validation passed
- } else if ( expected.call( {}, actual ) === true ) {
- expectedOutput = null;
- ok = true;
- }
-
- QUnit.push( ok, actual, expectedOutput, message );
- } else {
- QUnit.pushFailure( message, null, 'No exception was thrown.' );
- }
- }
-};
-
-/**
- * @deprecate since 1.8.0
- * Kept assertion helpers in root for backwards compatibility.
- */
-extend( QUnit, assert );
-
-/**
- * @deprecated since 1.9.0
- * Kept root "raises()" for backwards compatibility.
- * (Note that we don't introduce assert.raises).
- */
-QUnit.raises = assert[ "throws" ];
-
-/**
- * @deprecated since 1.0.0, replaced with error pushes since 1.3.0
- * Kept to avoid TypeErrors for undefined methods.
- */
-QUnit.equals = function() {
- QUnit.push( false, false, false, "QUnit.equals has been deprecated since 2009 (e88049a0), use QUnit.equal instead" );
-};
-QUnit.same = function() {
- QUnit.push( false, false, false, "QUnit.same has been deprecated since 2009 (e88049a0), use QUnit.deepEqual instead" );
-};
-
-// We want access to the constructor's prototype
-(function() {
- function F() {}
- F.prototype = QUnit;
- QUnit = new F();
- // Make F QUnit's constructor so that we can add to the prototype later
- QUnit.constructor = F;
-}());
-
-/**
- * Config object: Maintain internal state
- * Later exposed as QUnit.config
- * `config` initialized at top of scope
- */
-config = {
- // The queue of tests to run
- queue: [],
-
- // block until document ready
- blocking: true,
-
- // when enabled, show only failing tests
- // gets persisted through sessionStorage and can be changed in UI via checkbox
- hidepassed: false,
-
- // by default, run previously failed tests first
- // very useful in combination with "Hide passed tests" checked
- reorder: true,
-
- // by default, modify document.title when suite is done
- altertitle: true,
-
- // when enabled, all tests must call expect()
- requireExpects: false,
-
- // add checkboxes that are persisted in the query-string
- // when enabled, the id is set to `true` as a `QUnit.config` property
- urlConfig: [
- {
- id: "noglobals",
- label: "Check for Globals",
- tooltip: "Enabling this will test if any test introduces new properties on the `window` object. Stored as query-strings."
- },
- {
- id: "notrycatch",
- label: "No try-catch",
- tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging exceptions in IE reasonable. Stored as query-strings."
- }
- ],
-
- // Set of all modules.
- modules: {},
-
- // logging callback queues
- begin: [],
- done: [],
- log: [],
- testStart: [],
- testDone: [],
- moduleStart: [],
- moduleDone: []
-};
-
-// Export global variables, unless an 'exports' object exists,
-// in that case we assume we're in CommonJS (dealt with on the bottom of the script)
-if ( typeof exports === "undefined" ) {
- extend( window, QUnit );
-
- // Expose QUnit object
- window.QUnit = QUnit;
-}
-
-// Initialize more QUnit.config and QUnit.urlParams
-(function() {
- var i,
- location = window.location || { search: "", protocol: "file:" },
- params = location.search.slice( 1 ).split( "&" ),
- length = params.length,
- urlParams = {},
- current;
-
- if ( params[ 0 ] ) {
- for ( i = 0; i < length; i++ ) {
- current = params[ i ].split( "=" );
- current[ 0 ] = decodeURIComponent( current[ 0 ] );
- // allow just a key to turn on a flag, e.g., test.html?noglobals
- current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true;
- urlParams[ current[ 0 ] ] = current[ 1 ];
- }
- }
-
- QUnit.urlParams = urlParams;
-
- // String search anywhere in moduleName+testName
- config.filter = urlParams.filter;
-
- // Exact match of the module name
- config.module = urlParams.module;
-
- config.testNumber = parseInt( urlParams.testNumber, 10 ) || null;
-
- // Figure out if we're running the tests from a server or not
- QUnit.isLocal = location.protocol === "file:";
-}());
-
-// Extend QUnit object,
-// these after set here because they should not be exposed as global functions
-extend( QUnit, {
- assert: assert,
-
- config: config,
-
- // Initialize the configuration options
- init: function() {
- extend( config, {
- stats: { all: 0, bad: 0 },
- moduleStats: { all: 0, bad: 0 },
- started: +new Date(),
- updateRate: 1000,
- blocking: false,
- autostart: true,
- autorun: false,
- filter: "",
- queue: [],
- semaphore: 1
- });
-
- var tests, banner, result,
- qunit = id( "qunit" );
-
- if ( qunit ) {
- qunit.innerHTML =
- "" +
- "" +
- "" +
- "" +
- "
";
- }
-
- tests = id( "qunit-tests" );
- banner = id( "qunit-banner" );
- result = id( "qunit-testresult" );
-
- if ( tests ) {
- tests.innerHTML = "";
- }
-
- if ( banner ) {
- banner.className = "";
- }
-
- if ( result ) {
- result.parentNode.removeChild( result );
- }
-
- if ( tests ) {
- result = document.createElement( "p" );
- result.id = "qunit-testresult";
- result.className = "result";
- tests.parentNode.insertBefore( result, tests );
- result.innerHTML = "Running...
";
- }
- },
-
- // Resets the test setup. Useful for tests that modify the DOM.
- reset: function() {
- var fixture = id( "qunit-fixture" );
- if ( fixture ) {
- fixture.innerHTML = config.fixture;
- }
- },
-
- // Trigger an event on an element.
- // @example triggerEvent( document.body, "click" );
- triggerEvent: function( elem, type, event ) {
- if ( document.createEvent ) {
- event = document.createEvent( "MouseEvents" );
- event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView,
- 0, 0, 0, 0, 0, false, false, false, false, 0, null);
-
- elem.dispatchEvent( event );
- } else if ( elem.fireEvent ) {
- elem.fireEvent( "on" + type );
- }
- },
-
- // Safe object type checking
- is: function( type, obj ) {
- return QUnit.objectType( obj ) === type;
- },
-
- objectType: function( obj ) {
- if ( typeof obj === "undefined" ) {
- return "undefined";
- // consider: typeof null === object
- }
- if ( obj === null ) {
- return "null";
- }
-
- var match = toString.call( obj ).match(/^\[object\s(.*)\]$/),
- type = match && match[1] || "";
-
- switch ( type ) {
- case "Number":
- if ( isNaN(obj) ) {
- return "nan";
- }
- return "number";
- case "String":
- case "Boolean":
- case "Array":
- case "Date":
- case "RegExp":
- case "Function":
- return type.toLowerCase();
- }
- if ( typeof obj === "object" ) {
- return "object";
- }
- return undefined;
- },
-
- push: function( result, actual, expected, message ) {
- if ( !config.current ) {
- throw new Error( "assertion outside test context, was " + sourceFromStacktrace() );
- }
-
- var output, source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: message,
- actual: actual,
- expected: expected
- };
-
- message = escapeText( message ) || ( result ? "okay" : "failed" );
- message = "" + message + "";
- output = message;
-
- if ( !result ) {
- expected = escapeText( QUnit.jsDump.parse(expected) );
- actual = escapeText( QUnit.jsDump.parse(actual) );
- output += "Expected: | " + expected + " |
";
-
- if ( actual !== expected ) {
- output += "Result: | " + actual + " |
";
- output += "Diff: | " + QUnit.diff( expected, actual ) + " |
";
- }
-
- source = sourceFromStacktrace();
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
- }
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: !!result,
- message: output
- });
- },
-
- pushFailure: function( message, source, actual ) {
- if ( !config.current ) {
- throw new Error( "pushFailure() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
-
- var output,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: false,
- message: message
- };
-
- message = escapeText( message ) || "error";
- message = "" + message + "";
- output = message;
-
- output += "";
-
- if ( actual ) {
- output += "Result: | " + escapeText( actual ) + " |
";
- }
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: false,
- message: output
- });
- },
-
- url: function( params ) {
- params = extend( extend( {}, QUnit.urlParams ), params );
- var key,
- querystring = "?";
-
- for ( key in params ) {
- if ( !hasOwn.call( params, key ) ) {
- continue;
- }
- querystring += encodeURIComponent( key ) + "=" +
- encodeURIComponent( params[ key ] ) + "&";
- }
- return window.location.protocol + "//" + window.location.host +
- window.location.pathname + querystring.slice( 0, -1 );
- },
-
- extend: extend,
- id: id,
- addEvent: addEvent
- // load, equiv, jsDump, diff: Attached later
-});
-
-/**
- * @deprecated: Created for backwards compatibility with test runner that set the hook function
- * into QUnit.{hook}, instead of invoking it and passing the hook function.
- * QUnit.constructor is set to the empty F() above so that we can add to it's prototype here.
- * Doing this allows us to tell if the following methods have been overwritten on the actual
- * QUnit object.
- */
-extend( QUnit.constructor.prototype, {
-
- // Logging callbacks; all receive a single argument with the listed properties
- // run test/logs.html for any related changes
- begin: registerLoggingCallback( "begin" ),
-
- // done: { failed, passed, total, runtime }
- done: registerLoggingCallback( "done" ),
-
- // log: { result, actual, expected, message }
- log: registerLoggingCallback( "log" ),
-
- // testStart: { name }
- testStart: registerLoggingCallback( "testStart" ),
-
- // testDone: { name, failed, passed, total, duration }
- testDone: registerLoggingCallback( "testDone" ),
-
- // moduleStart: { name }
- moduleStart: registerLoggingCallback( "moduleStart" ),
-
- // moduleDone: { name, failed, passed, total }
- moduleDone: registerLoggingCallback( "moduleDone" )
-});
-
-if ( typeof document === "undefined" || document.readyState === "complete" ) {
- config.autorun = true;
-}
-
-QUnit.load = function() {
- runLoggingCallbacks( "begin", QUnit, {} );
-
- // Initialize the config, saving the execution queue
- var banner, filter, i, label, len, main, ol, toolbar, userAgent, val,
- urlConfigCheckboxesContainer, urlConfigCheckboxes, moduleFilter,
- numModules = 0,
- moduleFilterHtml = "",
- urlConfigHtml = "",
- oldconfig = extend( {}, config );
-
- QUnit.init();
- extend(config, oldconfig);
-
- config.blocking = false;
-
- len = config.urlConfig.length;
-
- for ( i = 0; i < len; i++ ) {
- val = config.urlConfig[i];
- if ( typeof val === "string" ) {
- val = {
- id: val,
- label: val,
- tooltip: "[no tooltip available]"
- };
- }
- config[ val.id ] = QUnit.urlParams[ val.id ];
- urlConfigHtml += "";
- }
-
- moduleFilterHtml += "";
-
- // `userAgent` initialized at top of scope
- userAgent = id( "qunit-userAgent" );
- if ( userAgent ) {
- userAgent.innerHTML = navigator.userAgent;
- }
-
- // `banner` initialized at top of scope
- banner = id( "qunit-header" );
- if ( banner ) {
- banner.innerHTML = "" + banner.innerHTML + " ";
- }
-
- // `toolbar` initialized at top of scope
- toolbar = id( "qunit-testrunner-toolbar" );
- if ( toolbar ) {
- // `filter` initialized at top of scope
- filter = document.createElement( "input" );
- filter.type = "checkbox";
- filter.id = "qunit-filter-pass";
-
- addEvent( filter, "click", function() {
- var tmp,
- ol = document.getElementById( "qunit-tests" );
-
- if ( filter.checked ) {
- ol.className = ol.className + " hidepass";
- } else {
- tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " ";
- ol.className = tmp.replace( / hidepass /, " " );
- }
- if ( defined.sessionStorage ) {
- if (filter.checked) {
- sessionStorage.setItem( "qunit-filter-passed-tests", "true" );
- } else {
- sessionStorage.removeItem( "qunit-filter-passed-tests" );
- }
- }
- });
-
- if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem( "qunit-filter-passed-tests" ) ) {
- filter.checked = true;
- // `ol` initialized at top of scope
- ol = document.getElementById( "qunit-tests" );
- ol.className = ol.className + " hidepass";
- }
- toolbar.appendChild( filter );
-
- // `label` initialized at top of scope
- label = document.createElement( "label" );
- label.setAttribute( "for", "qunit-filter-pass" );
- label.setAttribute( "title", "Only show tests and assertons that fail. Stored in sessionStorage." );
- label.innerHTML = "Hide passed tests";
- toolbar.appendChild( label );
-
- urlConfigCheckboxesContainer = document.createElement("span");
- urlConfigCheckboxesContainer.innerHTML = urlConfigHtml;
- urlConfigCheckboxes = urlConfigCheckboxesContainer.getElementsByTagName("input");
- // For oldIE support:
- // * Add handlers to the individual elements instead of the container
- // * Use "click" instead of "change"
- // * Fallback from event.target to event.srcElement
- addEvents( urlConfigCheckboxes, "click", function( event ) {
- var params = {},
- target = event.target || event.srcElement;
- params[ target.name ] = target.checked ? true : undefined;
- window.location = QUnit.url( params );
- });
- toolbar.appendChild( urlConfigCheckboxesContainer );
-
- if (numModules > 1) {
- moduleFilter = document.createElement( 'span' );
- moduleFilter.setAttribute( 'id', 'qunit-modulefilter-container' );
- moduleFilter.innerHTML = moduleFilterHtml;
- addEvent( moduleFilter.lastChild, "change", function() {
- var selectBox = moduleFilter.getElementsByTagName("select")[0],
- selectedModule = decodeURIComponent(selectBox.options[selectBox.selectedIndex].value);
-
- window.location = QUnit.url( { module: ( selectedModule === "" ) ? undefined : selectedModule } );
- });
- toolbar.appendChild(moduleFilter);
- }
- }
-
- // `main` initialized at top of scope
- main = id( "qunit-fixture" );
- if ( main ) {
- config.fixture = main.innerHTML;
- }
-
- if ( config.autostart ) {
- QUnit.start();
- }
-};
-
-addEvent( window, "load", QUnit.load );
-
-// `onErrorFnPrev` initialized at top of scope
-// Preserve other handlers
-onErrorFnPrev = window.onerror;
-
-// Cover uncaught exceptions
-// Returning true will surpress the default browser handler,
-// returning false will let it run.
-window.onerror = function ( error, filePath, linerNr ) {
- var ret = false;
- if ( onErrorFnPrev ) {
- ret = onErrorFnPrev( error, filePath, linerNr );
- }
-
- // Treat return value as window.onerror itself does,
- // Only do our handling if not surpressed.
- if ( ret !== true ) {
- if ( QUnit.config.current ) {
- if ( QUnit.config.current.ignoreGlobalErrors ) {
- return true;
- }
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- } else {
- QUnit.test( "global failure", extend( function() {
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- }, { validTest: validTest } ) );
- }
- return false;
- }
-
- return ret;
-};
-
-function done() {
- config.autorun = true;
-
- // Log the last module results
- if ( config.currentModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.currentModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
-
- var i, key,
- banner = id( "qunit-banner" ),
- tests = id( "qunit-tests" ),
- runtime = +new Date() - config.started,
- passed = config.stats.all - config.stats.bad,
- html = [
- "Tests completed in ",
- runtime,
- " milliseconds.
",
- "",
- passed,
- " assertions of ",
- config.stats.all,
- " passed, ",
- config.stats.bad,
- " failed."
- ].join( "" );
-
- if ( banner ) {
- banner.className = ( config.stats.bad ? "qunit-fail" : "qunit-pass" );
- }
-
- if ( tests ) {
- id( "qunit-testresult" ).innerHTML = html;
- }
-
- if ( config.altertitle && typeof document !== "undefined" && document.title ) {
- // show ✖ for good, ✔ for bad suite result in title
- // use escape sequences in case file gets loaded with non-utf-8-charset
- document.title = [
- ( config.stats.bad ? "\u2716" : "\u2714" ),
- document.title.replace( /^[\u2714\u2716] /i, "" )
- ].join( " " );
- }
-
- // clear own sessionStorage items if all tests passed
- if ( config.reorder && defined.sessionStorage && config.stats.bad === 0 ) {
- // `key` & `i` initialized at top of scope
- for ( i = 0; i < sessionStorage.length; i++ ) {
- key = sessionStorage.key( i++ );
- if ( key.indexOf( "qunit-test-" ) === 0 ) {
- sessionStorage.removeItem( key );
- }
- }
- }
-
- // scroll back to top to show results
- if ( window.scrollTo ) {
- window.scrollTo(0, 0);
- }
-
- runLoggingCallbacks( "done", QUnit, {
- failed: config.stats.bad,
- passed: passed,
- total: config.stats.all,
- runtime: runtime
- });
-}
-
-/** @return Boolean: true if this test should be ran */
-function validTest( test ) {
- var include,
- filter = config.filter && config.filter.toLowerCase(),
- module = config.module && config.module.toLowerCase(),
- fullName = (test.module + ": " + test.testName).toLowerCase();
-
- // Internally-generated tests are always valid
- if ( test.callback && test.callback.validTest === validTest ) {
- delete test.callback.validTest;
- return true;
- }
-
- if ( config.testNumber ) {
- return test.testNumber === config.testNumber;
- }
-
- if ( module && ( !test.module || test.module.toLowerCase() !== module ) ) {
- return false;
- }
-
- if ( !filter ) {
- return true;
- }
-
- include = filter.charAt( 0 ) !== "!";
- if ( !include ) {
- filter = filter.slice( 1 );
- }
-
- // If the filter matches, we need to honour include
- if ( fullName.indexOf( filter ) !== -1 ) {
- return include;
- }
-
- // Otherwise, do the opposite
- return !include;
-}
-
-// so far supports only Firefox, Chrome and Opera (buggy), Safari (for real exceptions)
-// Later Safari and IE10 are supposed to support error.stack as well
-// See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack
-function extractStacktrace( e, offset ) {
- offset = offset === undefined ? 3 : offset;
-
- var stack, include, i;
-
- if ( e.stacktrace ) {
- // Opera
- return e.stacktrace.split( "\n" )[ offset + 3 ];
- } else if ( e.stack ) {
- // Firefox, Chrome
- stack = e.stack.split( "\n" );
- if (/^error$/i.test( stack[0] ) ) {
- stack.shift();
- }
- if ( fileName ) {
- include = [];
- for ( i = offset; i < stack.length; i++ ) {
- if ( stack[ i ].indexOf( fileName ) !== -1 ) {
- break;
- }
- include.push( stack[ i ] );
- }
- if ( include.length ) {
- return include.join( "\n" );
- }
- }
- return stack[ offset ];
- } else if ( e.sourceURL ) {
- // Safari, PhantomJS
- // hopefully one day Safari provides actual stacktraces
- // exclude useless self-reference for generated Error objects
- if ( /qunit.js$/.test( e.sourceURL ) ) {
- return;
- }
- // for actual exceptions, this is useful
- return e.sourceURL + ":" + e.line;
- }
-}
-function sourceFromStacktrace( offset ) {
- try {
- throw new Error();
- } catch ( e ) {
- return extractStacktrace( e, offset );
- }
-}
-
-/**
- * Escape text for attribute or text content.
- */
-function escapeText( s ) {
- if ( !s ) {
- return "";
- }
- s = s + "";
- // Both single quotes and double quotes (for attributes)
- return s.replace( /['"<>&]/g, function( s ) {
- switch( s ) {
- case '\'':
- return ''';
- case '"':
- return '"';
- case '<':
- return '<';
- case '>':
- return '>';
- case '&':
- return '&';
- }
- });
-}
-
-function synchronize( callback, last ) {
- config.queue.push( callback );
-
- if ( config.autorun && !config.blocking ) {
- process( last );
- }
-}
-
-function process( last ) {
- function next() {
- process( last );
- }
- var start = new Date().getTime();
- config.depth = config.depth ? config.depth + 1 : 1;
-
- while ( config.queue.length && !config.blocking ) {
- if ( !defined.setTimeout || config.updateRate <= 0 || ( ( new Date().getTime() - start ) < config.updateRate ) ) {
- config.queue.shift()();
- } else {
- window.setTimeout( next, 13 );
- break;
- }
- }
- config.depth--;
- if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) {
- done();
- }
-}
-
-function saveGlobal() {
- config.pollution = [];
-
- if ( config.noglobals ) {
- for ( var key in window ) {
- // in Opera sometimes DOM element ids show up here, ignore them
- if ( !hasOwn.call( window, key ) || /^qunit-test-output/.test( key ) ) {
- continue;
- }
- config.pollution.push( key );
- }
- }
-}
-
-function checkPollution() {
- var newGlobals,
- deletedGlobals,
- old = config.pollution;
-
- saveGlobal();
-
- newGlobals = diff( config.pollution, old );
- if ( newGlobals.length > 0 ) {
- QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join(", ") );
- }
-
- deletedGlobals = diff( old, config.pollution );
- if ( deletedGlobals.length > 0 ) {
- QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join(", ") );
- }
-}
-
-// returns a new Array with the elements that are in a but not in b
-function diff( a, b ) {
- var i, j,
- result = a.slice();
-
- for ( i = 0; i < result.length; i++ ) {
- for ( j = 0; j < b.length; j++ ) {
- if ( result[i] === b[j] ) {
- result.splice( i, 1 );
- i--;
- break;
- }
- }
- }
- return result;
-}
-
-function extend( a, b ) {
- for ( var prop in b ) {
- if ( b[ prop ] === undefined ) {
- delete a[ prop ];
-
- // Avoid "Member not found" error in IE8 caused by setting window.constructor
- } else if ( prop !== "constructor" || a !== window ) {
- a[ prop ] = b[ prop ];
- }
- }
-
- return a;
-}
-
-/**
- * @param {HTMLElement} elem
- * @param {string} type
- * @param {Function} fn
- */
-function addEvent( elem, type, fn ) {
- // Standards-based browsers
- if ( elem.addEventListener ) {
- elem.addEventListener( type, fn, false );
- // IE
- } else {
- elem.attachEvent( "on" + type, fn );
- }
-}
-
-/**
- * @param {Array|NodeList} elems
- * @param {string} type
- * @param {Function} fn
- */
-function addEvents( elems, type, fn ) {
- var i = elems.length;
- while ( i-- ) {
- addEvent( elems[i], type, fn );
- }
-}
-
-function hasClass( elem, name ) {
- return (" " + elem.className + " ").indexOf(" " + name + " ") > -1;
-}
-
-function addClass( elem, name ) {
- if ( !hasClass( elem, name ) ) {
- elem.className += (elem.className ? " " : "") + name;
- }
-}
-
-function removeClass( elem, name ) {
- var set = " " + elem.className + " ";
- // Class name may appear multiple times
- while ( set.indexOf(" " + name + " ") > -1 ) {
- set = set.replace(" " + name + " " , " ");
- }
- // If possible, trim it for prettiness, but not neccecarily
- elem.className = window.jQuery ? jQuery.trim( set ) : ( set.trim ? set.trim() : set );
-}
-
-function id( name ) {
- return !!( typeof document !== "undefined" && document && document.getElementById ) &&
- document.getElementById( name );
-}
-
-function registerLoggingCallback( key ) {
- return function( callback ) {
- config[key].push( callback );
- };
-}
-
-// Supports deprecated method of completely overwriting logging callbacks
-function runLoggingCallbacks( key, scope, args ) {
- var i, callbacks;
- if ( QUnit.hasOwnProperty( key ) ) {
- QUnit[ key ].call(scope, args );
- } else {
- callbacks = config[ key ];
- for ( i = 0; i < callbacks.length; i++ ) {
- callbacks[ i ].call( scope, args );
- }
- }
-}
-
-// Test for equality any JavaScript type.
-// Author: Philippe Rathé
-QUnit.equiv = (function() {
-
- // Call the o related callback with the given arguments.
- function bindCallbacks( o, callbacks, args ) {
- var prop = QUnit.objectType( o );
- if ( prop ) {
- if ( QUnit.objectType( callbacks[ prop ] ) === "function" ) {
- return callbacks[ prop ].apply( callbacks, args );
- } else {
- return callbacks[ prop ]; // or undefined
- }
- }
- }
-
- // the real equiv function
- var innerEquiv,
- // stack to decide between skip/abort functions
- callers = [],
- // stack to avoiding loops from circular referencing
- parents = [],
-
- getProto = Object.getPrototypeOf || function ( obj ) {
- return obj.__proto__;
- },
- callbacks = (function () {
-
- // for string, boolean, number and null
- function useStrictEquality( b, a ) {
- /*jshint eqeqeq:false */
- if ( b instanceof a.constructor || a instanceof b.constructor ) {
- // to catch short annotaion VS 'new' annotation of a
- // declaration
- // e.g. var i = 1;
- // var j = new Number(1);
- return a == b;
- } else {
- return a === b;
- }
- }
-
- return {
- "string": useStrictEquality,
- "boolean": useStrictEquality,
- "number": useStrictEquality,
- "null": useStrictEquality,
- "undefined": useStrictEquality,
-
- "nan": function( b ) {
- return isNaN( b );
- },
-
- "date": function( b, a ) {
- return QUnit.objectType( b ) === "date" && a.valueOf() === b.valueOf();
- },
-
- "regexp": function( b, a ) {
- return QUnit.objectType( b ) === "regexp" &&
- // the regex itself
- a.source === b.source &&
- // and its modifers
- a.global === b.global &&
- // (gmi) ...
- a.ignoreCase === b.ignoreCase &&
- a.multiline === b.multiline &&
- a.sticky === b.sticky;
- },
-
- // - skip when the property is a method of an instance (OOP)
- // - abort otherwise,
- // initial === would have catch identical references anyway
- "function": function() {
- var caller = callers[callers.length - 1];
- return caller !== Object && typeof caller !== "undefined";
- },
-
- "array": function( b, a ) {
- var i, j, len, loop;
-
- // b could be an object literal here
- if ( QUnit.objectType( b ) !== "array" ) {
- return false;
- }
-
- len = a.length;
- if ( len !== b.length ) {
- // safe and faster
- return false;
- }
-
- // track reference to avoid circular references
- parents.push( a );
- for ( i = 0; i < len; i++ ) {
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- loop = true;// dont rewalk array
- }
- }
- if ( !loop && !innerEquiv(a[i], b[i]) ) {
- parents.pop();
- return false;
- }
- }
- parents.pop();
- return true;
- },
-
- "object": function( b, a ) {
- var i, j, loop,
- // Default to true
- eq = true,
- aProperties = [],
- bProperties = [];
-
- // comparing constructors is more strict than using
- // instanceof
- if ( a.constructor !== b.constructor ) {
- // Allow objects with no prototype to be equivalent to
- // objects with Object as their constructor.
- if ( !(( getProto(a) === null && getProto(b) === Object.prototype ) ||
- ( getProto(b) === null && getProto(a) === Object.prototype ) ) ) {
- return false;
- }
- }
-
- // stack constructor before traversing properties
- callers.push( a.constructor );
- // track reference to avoid circular references
- parents.push( a );
-
- for ( i in a ) { // be strict: don't ensures hasOwnProperty
- // and go deep
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- // don't go down the same path twice
- loop = true;
- }
- }
- aProperties.push(i); // collect a's properties
-
- if (!loop && !innerEquiv( a[i], b[i] ) ) {
- eq = false;
- break;
- }
- }
-
- callers.pop(); // unstack, we are done
- parents.pop();
-
- for ( i in b ) {
- bProperties.push( i ); // collect b's properties
- }
-
- // Ensures identical properties name
- return eq && innerEquiv( aProperties.sort(), bProperties.sort() );
- }
- };
- }());
-
- innerEquiv = function() { // can take multiple arguments
- var args = [].slice.apply( arguments );
- if ( args.length < 2 ) {
- return true; // end transition
- }
-
- return (function( a, b ) {
- if ( a === b ) {
- return true; // catch the most you can
- } else if ( a === null || b === null || typeof a === "undefined" ||
- typeof b === "undefined" ||
- QUnit.objectType(a) !== QUnit.objectType(b) ) {
- return false; // don't lose time with error prone cases
- } else {
- return bindCallbacks(a, callbacks, [ b, a ]);
- }
-
- // apply transition with (1..n) arguments
- }( args[0], args[1] ) && arguments.callee.apply( this, args.splice(1, args.length - 1 )) );
- };
-
- return innerEquiv;
-}());
-
-/**
- * jsDump Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com |
- * http://flesler.blogspot.com Licensed under BSD
- * (http://www.opensource.org/licenses/bsd-license.php) Date: 5/15/2008
- *
- * @projectDescription Advanced and extensible data dumping for Javascript.
- * @version 1.0.0
- * @author Ariel Flesler
- * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html}
- */
-QUnit.jsDump = (function() {
- function quote( str ) {
- return '"' + str.toString().replace( /"/g, '\\"' ) + '"';
- }
- function literal( o ) {
- return o + "";
- }
- function join( pre, arr, post ) {
- var s = jsDump.separator(),
- base = jsDump.indent(),
- inner = jsDump.indent(1);
- if ( arr.join ) {
- arr = arr.join( "," + s + inner );
- }
- if ( !arr ) {
- return pre + post;
- }
- return [ pre, inner + arr, base + post ].join(s);
- }
- function array( arr, stack ) {
- var i = arr.length, ret = new Array(i);
- this.up();
- while ( i-- ) {
- ret[i] = this.parse( arr[i] , undefined , stack);
- }
- this.down();
- return join( "[", ret, "]" );
- }
-
- var reName = /^function (\w+)/,
- jsDump = {
- // type is used mostly internally, you can fix a (custom)type in advance
- parse: function( obj, type, stack ) {
- stack = stack || [ ];
- var inStack, res,
- parser = this.parsers[ type || this.typeOf(obj) ];
-
- type = typeof parser;
- inStack = inArray( obj, stack );
-
- if ( inStack !== -1 ) {
- return "recursion(" + (inStack - stack.length) + ")";
- }
- if ( type === "function" ) {
- stack.push( obj );
- res = parser.call( this, obj, stack );
- stack.pop();
- return res;
- }
- return ( type === "string" ) ? parser : this.parsers.error;
- },
- typeOf: function( obj ) {
- var type;
- if ( obj === null ) {
- type = "null";
- } else if ( typeof obj === "undefined" ) {
- type = "undefined";
- } else if ( QUnit.is( "regexp", obj) ) {
- type = "regexp";
- } else if ( QUnit.is( "date", obj) ) {
- type = "date";
- } else if ( QUnit.is( "function", obj) ) {
- type = "function";
- } else if ( typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined" ) {
- type = "window";
- } else if ( obj.nodeType === 9 ) {
- type = "document";
- } else if ( obj.nodeType ) {
- type = "node";
- } else if (
- // native arrays
- toString.call( obj ) === "[object Array]" ||
- // NodeList objects
- ( typeof obj.length === "number" && typeof obj.item !== "undefined" && ( obj.length ? obj.item(0) === obj[0] : ( obj.item( 0 ) === null && typeof obj[0] === "undefined" ) ) )
- ) {
- type = "array";
- } else if ( obj.constructor === Error.prototype.constructor ) {
- type = "error";
- } else {
- type = typeof obj;
- }
- return type;
- },
- separator: function() {
- return this.multiline ? this.HTML ? "
" : "\n" : this.HTML ? " " : " ";
- },
- // extra can be a number, shortcut for increasing-calling-decreasing
- indent: function( extra ) {
- if ( !this.multiline ) {
- return "";
- }
- var chr = this.indentChar;
- if ( this.HTML ) {
- chr = chr.replace( /\t/g, " " ).replace( / /g, " " );
- }
- return new Array( this._depth_ + (extra||0) ).join(chr);
- },
- up: function( a ) {
- this._depth_ += a || 1;
- },
- down: function( a ) {
- this._depth_ -= a || 1;
- },
- setParser: function( name, parser ) {
- this.parsers[name] = parser;
- },
- // The next 3 are exposed so you can use them
- quote: quote,
- literal: literal,
- join: join,
- //
- _depth_: 1,
- // This is the list of parsers, to modify them, use jsDump.setParser
- parsers: {
- window: "[Window]",
- document: "[Document]",
- error: function(error) {
- return "Error(\"" + error.message + "\")";
- },
- unknown: "[Unknown]",
- "null": "null",
- "undefined": "undefined",
- "function": function( fn ) {
- var ret = "function",
- // functions never have name in IE
- name = "name" in fn ? fn.name : (reName.exec(fn) || [])[1];
-
- if ( name ) {
- ret += " " + name;
- }
- ret += "( ";
-
- ret = [ ret, QUnit.jsDump.parse( fn, "functionArgs" ), "){" ].join( "" );
- return join( ret, QUnit.jsDump.parse(fn,"functionCode" ), "}" );
- },
- array: array,
- nodelist: array,
- "arguments": array,
- object: function( map, stack ) {
- var ret = [ ], keys, key, val, i;
- QUnit.jsDump.up();
- keys = [];
- for ( key in map ) {
- keys.push( key );
- }
- keys.sort();
- for ( i = 0; i < keys.length; i++ ) {
- key = keys[ i ];
- val = map[ key ];
- ret.push( QUnit.jsDump.parse( key, "key" ) + ": " + QUnit.jsDump.parse( val, undefined, stack ) );
- }
- QUnit.jsDump.down();
- return join( "{", ret, "}" );
- },
- node: function( node ) {
- var len, i, val,
- open = QUnit.jsDump.HTML ? "<" : "<",
- close = QUnit.jsDump.HTML ? ">" : ">",
- tag = node.nodeName.toLowerCase(),
- ret = open + tag,
- attrs = node.attributes;
-
- if ( attrs ) {
- for ( i = 0, len = attrs.length; i < len; i++ ) {
- val = attrs[i].nodeValue;
- // IE6 includes all attributes in .attributes, even ones not explicitly set.
- // Those have values like undefined, null, 0, false, "" or "inherit".
- if ( val && val !== "inherit" ) {
- ret += " " + attrs[i].nodeName + "=" + QUnit.jsDump.parse( val, "attribute" );
- }
- }
- }
- ret += close;
-
- // Show content of TextNode or CDATASection
- if ( node.nodeType === 3 || node.nodeType === 4 ) {
- ret += node.nodeValue;
- }
-
- return ret + open + "/" + tag + close;
- },
- // function calls it internally, it's the arguments part of the function
- functionArgs: function( fn ) {
- var args,
- l = fn.length;
-
- if ( !l ) {
- return "";
- }
-
- args = new Array(l);
- while ( l-- ) {
- // 97 is 'a'
- args[l] = String.fromCharCode(97+l);
- }
- return " " + args.join( ", " ) + " ";
- },
- // object calls it internally, the key part of an item in a map
- key: quote,
- // function calls it internally, it's the content of the function
- functionCode: "[code]",
- // node calls it internally, it's an html attribute value
- attribute: quote,
- string: quote,
- date: quote,
- regexp: literal,
- number: literal,
- "boolean": literal
- },
- // if true, entities are escaped ( <, >, \t, space and \n )
- HTML: false,
- // indentation unit
- indentChar: " ",
- // if true, items in a collection, are separated by a \n, else just a space.
- multiline: true
- };
-
- return jsDump;
-}());
-
-// from jquery.js
-function inArray( elem, array ) {
- if ( array.indexOf ) {
- return array.indexOf( elem );
- }
-
- for ( var i = 0, length = array.length; i < length; i++ ) {
- if ( array[ i ] === elem ) {
- return i;
- }
- }
-
- return -1;
-}
-
-/*
- * Javascript Diff Algorithm
- * By John Resig (http://ejohn.org/)
- * Modified by Chu Alan "sprite"
- *
- * Released under the MIT license.
- *
- * More Info:
- * http://ejohn.org/projects/javascript-diff-algorithm/
- *
- * Usage: QUnit.diff(expected, actual)
- *
- * QUnit.diff( "the quick brown fox jumped over", "the quick fox jumps over" ) == "the quick brown fox jumped jumps over"
- */
-QUnit.diff = (function() {
- /*jshint eqeqeq:false, eqnull:true */
- function diff( o, n ) {
- var i,
- ns = {},
- os = {};
-
- for ( i = 0; i < n.length; i++ ) {
- if ( !hasOwn.call( ns, n[i] ) ) {
- ns[ n[i] ] = {
- rows: [],
- o: null
- };
- }
- ns[ n[i] ].rows.push( i );
- }
-
- for ( i = 0; i < o.length; i++ ) {
- if ( !hasOwn.call( os, o[i] ) ) {
- os[ o[i] ] = {
- rows: [],
- n: null
- };
- }
- os[ o[i] ].rows.push( i );
- }
-
- for ( i in ns ) {
- if ( !hasOwn.call( ns, i ) ) {
- continue;
- }
- if ( ns[i].rows.length === 1 && hasOwn.call( os, i ) && os[i].rows.length === 1 ) {
- n[ ns[i].rows[0] ] = {
- text: n[ ns[i].rows[0] ],
- row: os[i].rows[0]
- };
- o[ os[i].rows[0] ] = {
- text: o[ os[i].rows[0] ],
- row: ns[i].rows[0]
- };
- }
- }
-
- for ( i = 0; i < n.length - 1; i++ ) {
- if ( n[i].text != null && n[ i + 1 ].text == null && n[i].row + 1 < o.length && o[ n[i].row + 1 ].text == null &&
- n[ i + 1 ] == o[ n[i].row + 1 ] ) {
-
- n[ i + 1 ] = {
- text: n[ i + 1 ],
- row: n[i].row + 1
- };
- o[ n[i].row + 1 ] = {
- text: o[ n[i].row + 1 ],
- row: i + 1
- };
- }
- }
-
- for ( i = n.length - 1; i > 0; i-- ) {
- if ( n[i].text != null && n[ i - 1 ].text == null && n[i].row > 0 && o[ n[i].row - 1 ].text == null &&
- n[ i - 1 ] == o[ n[i].row - 1 ]) {
-
- n[ i - 1 ] = {
- text: n[ i - 1 ],
- row: n[i].row - 1
- };
- o[ n[i].row - 1 ] = {
- text: o[ n[i].row - 1 ],
- row: i - 1
- };
- }
- }
-
- return {
- o: o,
- n: n
- };
- }
-
- return function( o, n ) {
- o = o.replace( /\s+$/, "" );
- n = n.replace( /\s+$/, "" );
-
- var i, pre,
- str = "",
- out = diff( o === "" ? [] : o.split(/\s+/), n === "" ? [] : n.split(/\s+/) ),
- oSpace = o.match(/\s+/g),
- nSpace = n.match(/\s+/g);
-
- if ( oSpace == null ) {
- oSpace = [ " " ];
- }
- else {
- oSpace.push( " " );
- }
-
- if ( nSpace == null ) {
- nSpace = [ " " ];
- }
- else {
- nSpace.push( " " );
- }
-
- if ( out.n.length === 0 ) {
- for ( i = 0; i < out.o.length; i++ ) {
- str += "" + out.o[i] + oSpace[i] + "";
- }
- }
- else {
- if ( out.n[0].text == null ) {
- for ( n = 0; n < out.o.length && out.o[n].text == null; n++ ) {
- str += "" + out.o[n] + oSpace[n] + "";
- }
- }
-
- for ( i = 0; i < out.n.length; i++ ) {
- if (out.n[i].text == null) {
- str += "" + out.n[i] + nSpace[i] + "";
- }
- else {
- // `pre` initialized at top of scope
- pre = "";
-
- for ( n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++ ) {
- pre += "" + out.o[n] + oSpace[n] + "";
- }
- str += " " + out.n[i].text + nSpace[i] + pre;
- }
- }
- }
-
- return str;
- };
-}());
-
-// for CommonJS enviroments, export everything
-if ( typeof exports !== "undefined" ) {
- extend( exports, QUnit );
-}
-
-// get at whatever the global object is, like window in browsers
-}( (function() {return this;}.call()) ));
diff --git a/test/lib/require.js b/test/lib/require.js
deleted file mode 100644
index 987f865..0000000
--- a/test/lib/require.js
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- RequireJS 2.1.5 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.
- Available via the MIT or new BSD license.
- see: http://github.com/jrburke/requirejs for details
-*/
-var requirejs,require,define;
-(function(aa){function I(b){return"[object Function]"===L.call(b)}function J(b){return"[object Array]"===L.call(b)}function y(b,c){if(b){var d;for(d=0;dthis.depCount&&!this.defined){if(I(n)){if(this.events.error)try{e=i.execCb(c,n,b,e)}catch(d){a=d}else e=i.execCb(c,n,b,e);this.map.isDefine&&((b=this.module)&&void 0!==b.exports&&b.exports!==this.exports?e=b.exports:void 0===e&&this.usingExports&&(e=this.exports));if(a)return a.requireMap=this.map,a.requireModules=[this.map.id],a.requireType="define",v(this.error=
-a)}else e=n;this.exports=e;if(this.map.isDefine&&!this.ignore&&(q[c]=e,l.onResourceLoad))l.onResourceLoad(i,this.map,this.depMaps);x(c);this.defined=!0}this.defining=!1;this.defined&&!this.defineEmitted&&(this.defineEmitted=!0,this.emit("defined",this.exports),this.defineEmitComplete=!0)}}else this.fetch()}},callPlugin:function(){var a=this.map,b=a.id,d=j(a.prefix);this.depMaps.push(d);t(d,"defined",u(this,function(e){var n,d;d=this.map.name;var g=this.map.parentMap?this.map.parentMap.name:null,h=
-i.makeRequire(a.parentMap,{enableBuildCallback:!0});if(this.map.unnormalized){if(e.normalize&&(d=e.normalize(d,function(a){return c(a,g,!0)})||""),e=j(a.prefix+"!"+d,this.map.parentMap),t(e,"defined",u(this,function(a){this.init([],function(){return a},null,{enabled:!0,ignore:!0})})),d=m(p,e.id)){this.depMaps.push(e);if(this.events.error)d.on("error",u(this,function(a){this.emit("error",a)}));d.enable()}}else n=u(this,function(a){this.init([],function(){return a},null,{enabled:!0})}),n.error=u(this,
-function(a){this.inited=!0;this.error=a;a.requireModules=[b];G(p,function(a){0===a.map.id.indexOf(b+"_unnormalized")&&x(a.map.id)});v(a)}),n.fromText=u(this,function(e,c){var d=a.name,g=j(d),C=O;c&&(e=c);C&&(O=!1);r(g);s(k.config,b)&&(k.config[d]=k.config[b]);try{l.exec(e)}catch(ca){return v(B("fromtexteval","fromText eval for "+b+" failed: "+ca,ca,[b]))}C&&(O=!0);this.depMaps.push(g);i.completeLoad(d);h([d],n)}),e.load(a.name,h,n,k)}));i.enable(d,this);this.pluginMaps[d.id]=d},enable:function(){V[this.map.id]=
-this;this.enabling=this.enabled=!0;y(this.depMaps,u(this,function(a,b){var c,e;if("string"===typeof a){a=j(a,this.map.isDefine?this.map:this.map.parentMap,!1,!this.skipMap);this.depMaps[b]=a;if(c=m(N,a.id)){this.depExports[b]=c(this);return}this.depCount+=1;t(a,"defined",u(this,function(a){this.defineDep(b,a);this.check()}));this.errback&&t(a,"error",this.errback)}c=a.id;e=p[c];!s(N,c)&&(e&&!e.enabled)&&i.enable(a,this)}));G(this.pluginMaps,u(this,function(a){var b=m(p,a.id);b&&!b.enabled&&i.enable(a,
-this)}));this.enabling=!1;this.check()},on:function(a,b){var c=this.events[a];c||(c=this.events[a]=[]);c.push(b)},emit:function(a,b){y(this.events[a],function(a){a(b)});"error"===a&&delete this.events[a]}};i={config:k,contextName:b,registry:p,defined:q,urlFetched:U,defQueue:H,Module:Z,makeModuleMap:j,nextTick:l.nextTick,onError:v,configure:function(a){a.baseUrl&&"/"!==a.baseUrl.charAt(a.baseUrl.length-1)&&(a.baseUrl+="/");var b=k.pkgs,c=k.shim,e={paths:!0,config:!0,map:!0};G(a,function(a,b){e[b]?
-"map"===b?(k.map||(k.map={}),R(k[b],a,!0,!0)):R(k[b],a,!0):k[b]=a});a.shim&&(G(a.shim,function(a,b){J(a)&&(a={deps:a});if((a.exports||a.init)&&!a.exportsFn)a.exportsFn=i.makeShimExports(a);c[b]=a}),k.shim=c);a.packages&&(y(a.packages,function(a){a="string"===typeof a?{name:a}:a;b[a.name]={name:a.name,location:a.location||a.name,main:(a.main||"main").replace(ja,"").replace(ea,"")}}),k.pkgs=b);G(p,function(a,b){!a.inited&&!a.map.unnormalized&&(a.map=j(b))});if(a.deps||a.callback)i.require(a.deps||[],
-a.callback)},makeShimExports:function(a){return function(){var b;a.init&&(b=a.init.apply(aa,arguments));return b||a.exports&&ba(a.exports)}},makeRequire:function(a,f){function d(e,c,h){var g,k;f.enableBuildCallback&&(c&&I(c))&&(c.__requireJsBuild=!0);if("string"===typeof e){if(I(c))return v(B("requireargs","Invalid require call"),h);if(a&&s(N,e))return N[e](p[a.id]);if(l.get)return l.get(i,e,a,d);g=j(e,a,!1,!0);g=g.id;return!s(q,g)?v(B("notloaded",'Module name "'+g+'" has not been loaded yet for context: '+
-b+(a?"":". Use require([])"))):q[g]}L();i.nextTick(function(){L();k=r(j(null,a));k.skipMap=f.skipMap;k.init(e,c,h,{enabled:!0});D()});return d}f=f||{};R(d,{isBrowser:A,toUrl:function(b){var d,f=b.lastIndexOf("."),g=b.split("/")[0];if(-1!==f&&(!("."===g||".."===g)||1h.attachEvent.toString().indexOf("[native code"))&&!Y?(O=!0,h.attachEvent("onreadystatechange",b.onScriptLoad)):(h.addEventListener("load",b.onScriptLoad,!1),h.addEventListener("error",b.onScriptError,!1)),h.src=d,K=h,D?x.insertBefore(h,D):x.appendChild(h),K=null,h;if(da)try{importScripts(d),b.completeLoad(c)}catch(j){b.onError(B("importscripts","importScripts failed for "+c+" at "+d,j,[c]))}};A&&M(document.getElementsByTagName("script"),function(b){x||(x=
-b.parentNode);if(t=b.getAttribute("data-main"))return r.baseUrl||(E=t.split("/"),Q=E.pop(),fa=E.length?E.join("/")+"/":"./",r.baseUrl=fa,t=Q),t=t.replace(ea,""),r.deps=r.deps?r.deps.concat(t):[t],!0});define=function(b,c,d){var l,h;"string"!==typeof b&&(d=c,c=b,b=null);J(c)||(d=c,c=[]);!c.length&&I(d)&&d.length&&(d.toString().replace(la,"").replace(ma,function(b,d){c.push(d)}),c=(1===d.length?["require"]:["require","exports","module"]).concat(c));if(O){if(!(l=K))P&&"interactive"===P.readyState||M(document.getElementsByTagName("script"),
-function(b){if("interactive"===b.readyState)return P=b}),l=P;l&&(b||(b=l.getAttribute("data-requiremodule")),h=F[l.getAttribute("data-requirecontext")])}(h?h.defQueue:T).push([b,c,d])};define.amd={jQuery:!0};l.exec=function(b){return eval(b)};l(r)}})(this);
diff --git a/test/lib/resemble.js b/test/lib/resemble.js
new file mode 100644
index 0000000..1cb8c29
--- /dev/null
+++ b/test/lib/resemble.js
@@ -0,0 +1,535 @@
+/*
+Author: James Cryer
+Company: Huddle
+Last updated date: 21 Feb 2013
+URL: https://github.com/Huddle/Resemble.js
+*/
+
+(function(_this){
+ 'use strict';
+
+ _this['resemble'] = function( fileData ){
+
+ var data = {};
+ var images = [];
+ var updateCallbackArray = [];
+
+ var tolerance = { // between 0 and 255
+ red: 16,
+ green: 16,
+ blue: 16,
+ minBrightness: 16,
+ maxBrightness: 240
+ };
+
+ var ignoreAntialiasing = false;
+ var ignoreColors = false;
+
+ function triggerDataUpdate(){
+ var len = updateCallbackArray.length;
+ var i;
+ for(i=0;i tolerance.maxBrightness;
+ }
+
+ function getHue(r,g,b){
+
+ r = r / 255;
+ g = g / 255;
+ b = b / 255;
+ var max = Math.max(r, g, b), min = Math.min(r, g, b);
+ var h;
+ var d;
+
+ if (max == min){
+ h = 0; // achromatic
+ } else{
+ d = max - min;
+ switch(max){
+ case r: h = (g - b) / d + (g < b ? 6 : 0); break;
+ case g: h = (b - r) / d + 2; break;
+ case b: h = (r - g) / d + 4; break;
+ }
+ h /= 6;
+ }
+
+ return h;
+ }
+
+ function isAntialiased(sourcePix, data, cacheSet, verticalPos, horizontalPos, width){
+ var offset;
+ var targetPix;
+ var distance = 1;
+ var i;
+ var j;
+ var hasHighContrastSibling = 0;
+ var hasSiblingWithDifferentHue = 0;
+ var hasEquivilantSibling = 0;
+
+ addHueInfo(sourcePix);
+
+ for (i = distance*-1; i <= distance; i++){
+ for (j = distance*-1; j <= distance; j++){
+
+ if(i===0 && j===0){
+ // ignore source pixel
+ } else {
+
+ offset = ((verticalPos+j)*width + (horizontalPos+i)) * 4;
+ targetPix = getPixelInfo(data, offset, cacheSet);
+
+ if(targetPix === null){
+ continue;
+ }
+
+ addBrightnessInfo(targetPix);
+ addHueInfo(targetPix);
+
+ if( isContrasting(sourcePix, targetPix) ){
+ hasHighContrastSibling++;
+ }
+
+ if( isRGBSame(sourcePix,targetPix) ){
+ hasEquivilantSibling++;
+ }
+
+ if( Math.abs(targetPix.h - sourcePix.h) > 0.3 ){
+ hasSiblingWithDifferentHue++;
+ }
+
+ if( hasSiblingWithDifferentHue > 1 || hasHighContrastSibling > 1){
+ return true;
+ }
+ }
+ }
+ }
+
+ if(hasEquivilantSibling < 2){
+ return true;
+ }
+
+ return false;
+ }
+
+ function errorPixel(px, offset){
+ px[offset] = 255; //r
+ px[offset + 1] = 0; //g
+ px[offset + 2] = 255; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyPixel(px, offset, data){
+ px[offset] = data.r; //r
+ px[offset + 1] = data.g; //g
+ px[offset + 2] = data.b; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyGrayScalePixel(px, offset, data){
+ px[offset] = data.brightness; //r
+ px[offset + 1] = data.brightness; //g
+ px[offset + 2] = data.brightness; //b
+ px[offset + 3] = 255; //a
+ }
+
+
+ function getPixelInfo(data, offset, cacheSet){
+ var r;
+ var g;
+ var b;
+ var d;
+
+ if(typeof data[offset] !== 'undefined'){
+ r = data[offset];
+ g = data[offset+1];
+ b = data[offset+2];
+ d = {
+ r: r,
+ g: g,
+ b: b
+ };
+
+ return d;
+ } else {
+ return null;
+ }
+ }
+
+ function addBrightnessInfo(data){
+ data.brightness = getBrightness(data.r,data.g,data.b); // 'corrected' lightness
+ }
+
+ function addHueInfo(data){
+ data.h = getHue(data.r,data.g,data.b);
+ }
+
+ function analyseImages(img1, img2, width, height){
+
+ var hiddenCanvas = document.createElement('canvas');
+
+ var data1 = img1.data;
+ var data2 = img2.data;
+
+ hiddenCanvas.width = width;
+ hiddenCanvas.height = height;
+
+ var context = hiddenCanvas.getContext('2d');
+ var imgd = context.createImageData(width,height);
+ var targetPix = imgd.data;
+
+ var mismatchCount = 0;
+
+ var time = Date.now();
+
+ var skip;
+
+ if( (width > 1200 || height > 1200) && ignoreAntialiasing){
+ skip = 6;
+ }
+
+ loop(height, width, function(verticalPos, horizontalPos){
+
+ if(skip){ // only skip if the image isn't small
+ if(verticalPos % skip === 0 || horizontalPos % skip === 0){
+ return;
+ }
+ }
+
+ var offset = (verticalPos*width + horizontalPos) * 4;
+ var pixel1 = getPixelInfo(data1, offset, 1);
+ var pixel2 = getPixelInfo(data2, offset, 2);
+
+ if(pixel1 === null || pixel2 === null){
+ return;
+ }
+
+ if (ignoreColors){
+
+ addBrightnessInfo(pixel1);
+ addBrightnessInfo(pixel2);
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ return;
+ }
+
+ if( isRGBSimilar(pixel1, pixel2) ){
+ copyPixel(targetPix, offset, pixel2);
+
+ } else if( ignoreAntialiasing && (
+ addBrightnessInfo(pixel1), // jit pixel info augmentation looks a little weird, sorry.
+ addBrightnessInfo(pixel2),
+ isAntialiased(pixel1, data1, 1, verticalPos, horizontalPos, width) ||
+ isAntialiased(pixel2, data2, 2, verticalPos, horizontalPos, width)
+ )){
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+
+ });
+
+ data.misMatchPercentage = (mismatchCount / (height*width) * 100).toFixed(2);
+ data.analysisTime = Date.now() - time;
+
+ data.getImageDataUrl = function(text){
+ var barHeight = 0;
+
+ if(text){
+ barHeight = addLabel(text,context,hiddenCanvas);
+ }
+
+ context.putImageData(imgd, 0, barHeight);
+
+ return hiddenCanvas.toDataURL("image/png");
+ };
+ }
+
+ function addLabel(text, context, hiddenCanvas){
+ var textPadding = 2;
+
+ context.font = '12px sans-serif';
+
+ var textWidth = context.measureText(text).width + textPadding*2;
+ var barHeight = 22;
+
+ if(textWidth > hiddenCanvas.width){
+ hiddenCanvas.width = textWidth;
+ }
+
+ hiddenCanvas.height += barHeight;
+
+ context.fillStyle = "#666";
+ context.fillRect(0,0,hiddenCanvas.width,barHeight -4);
+ context.fillStyle = "#fff";
+ context.fillRect(0,barHeight -4,hiddenCanvas.width, 4);
+
+ context.fillStyle = "#fff";
+ context.textBaseline = "top";
+ context.font = '12px sans-serif';
+ context.fillText(text, textPadding, 1);
+
+ return barHeight;
+ }
+
+ function normalise(img, w, h){
+ var c;
+ var context;
+
+ if(img.height < h || img.width < w){
+ c = document.createElement('canvas');
+ c.width = w;
+ c.height = h;
+ context = c.getContext('2d');
+ context.putImageData(img, 0, 0);
+ return context.getImageData(0, 0, w, h);
+ }
+
+ return img;
+ }
+
+ function compare(one, two){
+
+ function onceWeHaveBoth(){
+ var width;
+ var height;
+ if(images.length === 2){
+ width = images[0].width > images[1].width ? images[0].width : images[1].width;
+ height = images[0].height > images[1].height ? images[0].height : images[1].height;
+
+ if( (images[0].width === images[1].width) && (images[0].height === images[1].height) ){
+ data.isSameDimensions = true;
+ } else {
+ data.isSameDimensions = false;
+ }
+
+ analyseImages( normalise(images[0],width, height), normalise(images[1],width, height), width, height);
+
+ triggerDataUpdate();
+ }
+ }
+
+ images = [];
+ loadImageData(one, onceWeHaveBoth);
+ loadImageData(two, onceWeHaveBoth);
+ }
+
+ function getCompareApi(param){
+
+ var secondFileData,
+ hasMethod = typeof param === 'function';
+
+ if( !hasMethod ){
+ // assume it's file data
+ secondFileData = param;
+ }
+
+ var self = {
+ ignoreNothing: function(){
+
+ tolerance.red = 16;
+ tolerance.green = 16;
+ tolerance.blue = 16;
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreAntialiasing: function(){
+
+ tolerance.red = 32;
+ tolerance.green = 32;
+ tolerance.blue = 32;
+ tolerance.minBrightness = 64;
+ tolerance.maxBrightness = 96;
+
+ ignoreAntialiasing = true;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreColors: function(){
+
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = true;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ onComplete: function( callback ){
+
+ updateCallbackArray.push(callback);
+
+ var wrapper = function(){
+ compare(fileData, secondFileData);
+ };
+
+ wrapper();
+
+ return getCompareApi(wrapper);
+ }
+ };
+
+ return self;
+ }
+
+ return {
+ onComplete: function( callback ){
+ updateCallbackArray.push(callback);
+ loadImageData(fileData, function(imageData, width, height){
+ parseImage(imageData.data, width, height);
+ });
+ },
+ compareTo: function(secondFileData){
+ return getCompareApi(secondFileData);
+ }
+ };
+
+ };
+}(this));
\ No newline at end of file
diff --git a/test/testsuite.js b/test/testsuite.js
deleted file mode 100644
index b486acb..0000000
--- a/test/testsuite.js
+++ /dev/null
@@ -1,36 +0,0 @@
-requirejs.config({
- baseUrl: '/test/unit/'
-});
-
-define(function(require) {
- var testModules = [
- 'Pixi',
- 'Point',
- 'Rectangle',
- 'DisplayObject',
- 'DisplayObjectContainer',
- 'Sprite',
- 'MovieClip',
- 'InteractionManager',
- 'Stage',
- 'utils/Utils',
- 'utils/EventTarget',
- 'utils/Matrix',
- 'utils/Detector',
- 'renderers/WebGLShaders',
- 'renderers/WebGLRenderer',
- 'renderers/WebGLBatch',
- 'renderers/CanvasRenderer',
- 'extras/Strip',
- 'extras/Rope',
- 'textures/BaseTexture',
- 'textures/Texture',
- 'loaders/SpriteSheetLoader',
- 'loaders/AssetLoader'
- ];
-
- // Resolve all testModules and then start the Test Runner.
- require(testModules, function() {
- QUnit.start();
- });
-});
\ No newline at end of file
diff --git a/test/textures/SpriteSheet-Aliens.png b/test/textures/SpriteSheet-Aliens.png
new file mode 100644
index 0000000..210acb1
--- /dev/null
+++ b/test/textures/SpriteSheet-Aliens.png
Binary files differ
diff --git a/test/textures/SpriteSheet-Explosion.png b/test/textures/SpriteSheet-Explosion.png
new file mode 100755
index 0000000..79e1a69
--- /dev/null
+++ b/test/textures/SpriteSheet-Explosion.png
Binary files differ
diff --git a/test/textures/bunny.png b/test/textures/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/textures/bunny.png
Binary files differ
diff --git a/test/unit/DisplayObject.js b/test/unit/DisplayObject.js
deleted file mode 100644
index 5e7e72f..0000000
--- a/test/unit/DisplayObject.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObject');
-});
diff --git a/test/unit/DisplayObjectContainer.js b/test/unit/DisplayObjectContainer.js
deleted file mode 100644
index b323959..0000000
--- a/test/unit/DisplayObjectContainer.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObjectContainer');
-});
diff --git a/test/unit/InteractionManager.js b/test/unit/InteractionManager.js
deleted file mode 100644
index e751f52..0000000
--- a/test/unit/InteractionManager.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('InteractionManager');
-});
diff --git a/test/unit/MovieClip.js b/test/unit/MovieClip.js
deleted file mode 100644
index 37d9446..0000000
--- a/test/unit/MovieClip.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('MovieClip');
-});
diff --git a/test/unit/Pixi.js b/test/unit/Pixi.js
deleted file mode 100644
index 36eee73..0000000
--- a/test/unit/Pixi.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Pixi');
-});
diff --git a/test/unit/Point.js b/test/unit/Point.js
deleted file mode 100644
index 983ff6e..0000000
--- a/test/unit/Point.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Point');
-});
diff --git a/test/unit/Rectangle.js b/test/unit/Rectangle.js
deleted file mode 100644
index 3b439ba..0000000
--- a/test/unit/Rectangle.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Rectangle');
-});
diff --git a/test/unit/Sprite.js b/test/unit/Sprite.js
deleted file mode 100644
index ed4f596..0000000
--- a/test/unit/Sprite.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Sprite');
-});
diff --git a/test/unit/Stage.js b/test/unit/Stage.js
deleted file mode 100644
index 2d70291..0000000
--- a/test/unit/Stage.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Stage');
-});
diff --git a/test/unit/extras/Rope.js b/test/unit/extras/Rope.js
deleted file mode 100644
index 5606f14..0000000
--- a/test/unit/extras/Rope.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Rope');
-});
diff --git a/test/unit/extras/Strip.js b/test/unit/extras/Strip.js
deleted file mode 100644
index 0134d3a..0000000
--- a/test/unit/extras/Strip.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Strip');
-});
diff --git a/test/unit/loaders/AssetLoader.js b/test/unit/loaders/AssetLoader.js
deleted file mode 100644
index 13b8443..0000000
--- a/test/unit/loaders/AssetLoader.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('AssetLoader');
-});
diff --git a/test/unit/loaders/SpriteSheetLoader.js b/test/unit/loaders/SpriteSheetLoader.js
deleted file mode 100644
index 8bf0cb2..0000000
--- a/test/unit/loaders/SpriteSheetLoader.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('SpriteSheetLoader');
-});
diff --git a/test/unit/pixi/InteractionManager.js b/test/unit/pixi/InteractionManager.js
new file mode 100644
index 0000000..ed3001f
--- /dev/null
+++ b/test/unit/pixi/InteractionManager.js
@@ -0,0 +1,10 @@
+describe('pixi/InteractionManager', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var InteractionManager = PIXI.InteractionManager;
+
+ it('Module exists', function () {
+ expect(InteractionManager).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/Pixi.js b/test/unit/pixi/Pixi.js
new file mode 100644
index 0000000..27debc1
--- /dev/null
+++ b/test/unit/pixi/Pixi.js
@@ -0,0 +1,9 @@
+describe('pixi/Pixi', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+
+ it('Module exists', function () {
+ expect(global).to.have.property('PIXI').and.to.be.an('object');
+ });
+});
diff --git a/test/unit/pixi/core/Circle.js b/test/unit/pixi/core/Circle.js
new file mode 100644
index 0000000..93a4456
--- /dev/null
+++ b/test/unit/pixi/core/Circle.js
@@ -0,0 +1,22 @@
+describe('pixi/core/Circle', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Circle = PIXI.Circle;
+
+ it('Module exists', function () {
+ expect(Circle).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Circle();
+
+ expect(obj).to.be.an.instanceof(Circle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', 0);
+ expect(obj).to.have.property('y', 0);
+ expect(obj).to.have.property('radius', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Ellipse.js b/test/unit/pixi/core/Ellipse.js
new file mode 100644
index 0000000..026b56f
--- /dev/null
+++ b/test/unit/pixi/core/Ellipse.js
@@ -0,0 +1,24 @@
+describe('pixi/core/Ellipse', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Ellipse = PIXI.Ellipse;
+
+ it('Module exists', function () {
+ expect(Ellipse).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Ellipse();
+
+ expect(obj).to.be.an.instanceof(Ellipse);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+ expect(obj).to.respondTo('getBounds');
+
+ expect(obj).to.have.property('x', 0);
+ expect(obj).to.have.property('y', 0);
+ expect(obj).to.have.property('width', 0);
+ expect(obj).to.have.property('height', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Matrix.js b/test/unit/pixi/core/Matrix.js
new file mode 100644
index 0000000..b48989e
--- /dev/null
+++ b/test/unit/pixi/core/Matrix.js
@@ -0,0 +1,30 @@
+describe('pixi/core/Matrix', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var mat3 = PIXI.mat3;
+ var mat4 = PIXI.mat4;
+ var Matrix = PIXI.Matrix;
+
+ it('Ensure determineMatrixArrayType works', function () {
+ expect(Matrix).to.be.a('function');
+ });
+
+ it('mat3 exists', function () {
+ expect(mat3).to.be.an('object');
+ });
+
+ it('Confirm new mat3 matrix', function () {
+ var matrix = new mat3.create();
+ pixi_core_Matrix_confirmNewMat3(matrix);
+ });
+
+ it('mat3 exists', function () {
+ expect(mat4).to.be.an('object');
+ });
+
+ it('Confirm new mat4 matrix', function () {
+ var matrix = new mat4.create();
+ pixi_core_Matrix_confirmNewMat4(matrix);
+ });
+});
diff --git a/test/unit/pixi/core/Point.js b/test/unit/pixi/core/Point.js
new file mode 100644
index 0000000..c4d5163
--- /dev/null
+++ b/test/unit/pixi/core/Point.js
@@ -0,0 +1,15 @@
+describe('pixi/core/Point', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Point = PIXI.Point;
+
+ it('Module exists', function () {
+ expect(Point).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Point();
+ pixi_core_Point_confirm(obj, 0, 0);
+ });
+});
diff --git a/test/unit/pixi/core/Polygon.js b/test/unit/pixi/core/Polygon.js
new file mode 100644
index 0000000..dc8c918
--- /dev/null
+++ b/test/unit/pixi/core/Polygon.js
@@ -0,0 +1,20 @@
+describe('pixi/core/Polygon', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Polygon = PIXI.Polygon;
+
+ it('Module exists', function () {
+ expect(Polygon).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Polygon();
+
+ expect(obj).to.be.an.instanceof(Polygon);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.deep.property('points.length', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Rectangle.js b/test/unit/pixi/core/Rectangle.js
new file mode 100644
index 0000000..d43316e
--- /dev/null
+++ b/test/unit/pixi/core/Rectangle.js
@@ -0,0 +1,15 @@
+describe('pixi/core/Rectangle', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Rectangle = PIXI.Rectangle;
+
+ it('Module exists', function () {
+ expect(Rectangle).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var rect = new Rectangle();
+ pixi_core_Rectangle_confirm(rect, 0, 0, 0, 0);
+ });
+});
diff --git a/test/unit/pixi/display/DisplayObject.js b/test/unit/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..40c6fbc
--- /dev/null
+++ b/test/unit/pixi/display/DisplayObject.js
@@ -0,0 +1,21 @@
+describe('pixi/display/DisplayObject', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var DisplayObject = PIXI.DisplayObject;
+
+ it('Module exists', function () {
+ expect(DisplayObject).to.be.a('function');
+ expect(PIXI).to.have.property('visibleCount', 0);
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new DisplayObject();
+
+ pixi_display_DisplayObject_confirmNew(obj);
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', false);
+ expect(obj).to.have.property('stage', null);
+ });
+});
diff --git a/test/unit/pixi/display/DisplayObjectContainer.js b/test/unit/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..ce7f02f
--- /dev/null
+++ b/test/unit/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,20 @@
+describe('pixi/display/DisplayObjectContainer', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var DisplayObjectContainer = PIXI.DisplayObjectContainer;
+
+ it('Module exists', function () {
+ expect(DisplayObjectContainer).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new DisplayObjectContainer();
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', false);
+ expect(obj).to.have.property('stage', null);
+ });
+});
diff --git a/test/unit/pixi/display/MovieClip.js b/test/unit/pixi/display/MovieClip.js
new file mode 100644
index 0000000..f3c6c6a
--- /dev/null
+++ b/test/unit/pixi/display/MovieClip.js
@@ -0,0 +1,33 @@
+describe('pixi/display/MovieClip', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var MovieClip = PIXI.MovieClip;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(MovieClip).to.be.a('function');
+ });
+
+ it('Confirm new instance', function (done) {
+ var texture = Texture.fromImage('/base/test/textures/SpriteSheet-Explosion.png');
+ var obj = new MovieClip([texture]);
+
+ pixi_display_Sprite_confirmNew(obj, done);
+
+ expect(obj).to.be.an.instanceof(MovieClip);
+ expect(obj).to.respondTo('stop');
+ expect(obj).to.respondTo('play');
+ expect(obj).to.respondTo('gotoAndStop');
+ expect(obj).to.respondTo('gotoAndPlay');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('textures.length', 1);
+ expect(obj).to.have.deep.property('textures[0]', texture);
+ expect(obj).to.have.property('animationSpeed', 1);
+ expect(obj).to.have.property('loop', true);
+ expect(obj).to.have.property('onComplete', null);
+ expect(obj).to.have.property('currentFrame', 0);
+ expect(obj).to.have.property('playing', false);
+ });
+});
diff --git a/test/unit/pixi/display/Sprite.js b/test/unit/pixi/display/Sprite.js
new file mode 100644
index 0000000..54e914f
--- /dev/null
+++ b/test/unit/pixi/display/Sprite.js
@@ -0,0 +1,25 @@
+describe('pixi/display/Sprite', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Sprite = PIXI.Sprite;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(Sprite).to.be.a('function');
+ expect(PIXI).to.have.deep.property('blendModes.NORMAL', 0);
+ expect(PIXI).to.have.deep.property('blendModes.SCREEN', 1);
+ });
+
+ it('Members exist', function () {
+ expect(Sprite).itself.to.respondTo('fromImage');
+ expect(Sprite).itself.to.respondTo('fromFrame');
+ });
+
+ it('Confirm new instance', function (done) {
+ var texture = Texture.fromImage('/base/test/textures/SpriteSheet-Aliens.png');
+ var obj = new Sprite(texture);
+
+ pixi_display_Sprite_confirmNew(obj, done);
+ });
+});
diff --git a/test/unit/pixi/display/Stage.js b/test/unit/pixi/display/Stage.js
new file mode 100644
index 0000000..3cc2a4d
--- /dev/null
+++ b/test/unit/pixi/display/Stage.js
@@ -0,0 +1,49 @@
+describe('pixi/display/Stage', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Stage = PIXI.Stage;
+ var InteractionManager = PIXI.InteractionManager;
+ var Rectangle = PIXI.Rectangle;
+
+ it('Module exists', function () {
+ expect(Stage).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Stage(null, true);
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(Stage);
+ expect(obj).to.respondTo('updateTransform');
+ expect(obj).to.respondTo('setBackgroundColor');
+ expect(obj).to.respondTo('getMousePosition');
+
+ // FIXME: duplicate member in DisplayObject
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ // FIXME: convert arg to bool in constructor
+ expect(obj).to.have.property('interactive', true);
+
+ expect(obj).to.have.property('interactionManager')
+ .and.to.be.an.instanceof(InteractionManager)
+ .and.to.have.property('stage', obj);
+
+ expect(obj).to.have.property('dirty', true);
+
+ expect(obj).to.have.property('stage', obj);
+
+ expect(obj).to.have.property('hitArea')
+ .and.to.be.an.instanceof(Rectangle);
+ pixi_core_Rectangle_confirm(obj.hitArea, 0, 0, 100000, 100000);
+
+ expect(obj).to.have.property('backgroundColor', 0x000000);
+ expect(obj).to.have.deep.property('backgroundColorSplit.length', 3);
+ expect(obj).to.have.deep.property('backgroundColorSplit[0]', 0);
+ expect(obj).to.have.deep.property('backgroundColorSplit[1]', 0);
+ expect(obj).to.have.deep.property('backgroundColorSplit[2]', 0);
+ expect(obj).to.have.property('backgroundColorString', '#000000');
+
+ expect(obj).to.have.property('worldVisible', true);
+ });
+});
diff --git a/test/unit/pixi/extras/CustomRenderable.js b/test/unit/pixi/extras/CustomRenderable.js
new file mode 100644
index 0000000..8d83cf0
--- /dev/null
+++ b/test/unit/pixi/extras/CustomRenderable.js
@@ -0,0 +1,21 @@
+describe('pixi/extras/CustomRenderable', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var CustomRenderable = PIXI.CustomRenderable;
+
+ it('Module exists', function () {
+ expect(CustomRenderable).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new CustomRenderable();
+
+ pixi_display_DisplayObject_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(CustomRenderable);
+ expect(obj).to.respondTo('renderCanvas');
+ expect(obj).to.respondTo('initWebGL');
+ expect(obj).to.respondTo('renderWebGL');
+ });
+});
diff --git a/test/unit/pixi/extras/Rope.js b/test/unit/pixi/extras/Rope.js
new file mode 100644
index 0000000..6ddaf83
--- /dev/null
+++ b/test/unit/pixi/extras/Rope.js
@@ -0,0 +1,26 @@
+describe('pixi/extras/Rope', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Rope = PIXI.Rope;
+ var Texture = PIXI.Texture;
+ var Point = PIXI.Point;
+
+ it('Module exists', function () {
+ expect(Rope).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var texture = Texture.fromImage('/base/test/textures/bunny.png');
+ var obj = new Rope(texture, [new Point(), new Point(5, 10), new Point(10, 20)]);
+
+ pixi_extras_Strip_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(Rope);
+ expect(obj).to.respondTo('refresh');
+ expect(obj).to.respondTo('updateTransform');
+ expect(obj).to.respondTo('setTexture');
+
+ // TODO: Test properties
+ });
+});
diff --git a/test/unit/pixi/extras/Spine.js b/test/unit/pixi/extras/Spine.js
new file mode 100644
index 0000000..0708bc0
--- /dev/null
+++ b/test/unit/pixi/extras/Spine.js
@@ -0,0 +1,10 @@
+describe('pixi/extras/Spine', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Spine = PIXI.Spine;
+
+ it('Module exists', function () {
+ expect(Spine).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/extras/Strip.js b/test/unit/pixi/extras/Strip.js
new file mode 100644
index 0000000..8e564e1
--- /dev/null
+++ b/test/unit/pixi/extras/Strip.js
@@ -0,0 +1,18 @@
+describe('pixi/extras/Strip', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Strip = PIXI.Strip;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(Strip).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var texture = Texture.fromImage('/base/test/textures/bunny.png');
+ var obj = new Strip(texture, 20, 10000);
+
+ pixi_extras_Strip_confirmNew(obj);
+ });
+});
diff --git a/test/unit/pixi/extras/TilingSprite.js b/test/unit/pixi/extras/TilingSprite.js
new file mode 100644
index 0000000..56aea14
--- /dev/null
+++ b/test/unit/pixi/extras/TilingSprite.js
@@ -0,0 +1,24 @@
+describe('pixi/extras/TilingSprite', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var TilingSprite = PIXI.TilingSprite;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(TilingSprite).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var texture = Texture.fromImage('/base/test/textures/bunny.png');
+ var obj = new TilingSprite(texture, 6000, 12000);
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(TilingSprite);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ // TODO: Test properties
+ });
+});
diff --git a/test/unit/pixi/filters/FilterBlock.js b/test/unit/pixi/filters/FilterBlock.js
new file mode 100644
index 0000000..870cec0
--- /dev/null
+++ b/test/unit/pixi/filters/FilterBlock.js
@@ -0,0 +1,10 @@
+describe('pixi/filters/FilterBlock', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var FilterBlock = PIXI.FilterBlock;
+
+ it('Module exists', function () {
+ expect(FilterBlock).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/filters/MaskFilter.js b/test/unit/pixi/filters/MaskFilter.js
new file mode 100644
index 0000000..32d6a45
--- /dev/null
+++ b/test/unit/pixi/filters/MaskFilter.js
@@ -0,0 +1,10 @@
+describe('pixi/filters/MaskFilter', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ // var MaskFilter = PIXI.MaskFilter;
+
+ // it('Module exists', function () {
+ // expect(MaskFilter).to.be.a('function');
+ // });
+});
diff --git a/test/unit/pixi/loaders/AssetLoader.js b/test/unit/pixi/loaders/AssetLoader.js
new file mode 100644
index 0000000..a0aa0b5
--- /dev/null
+++ b/test/unit/pixi/loaders/AssetLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/AssetLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var AssetLoader = PIXI.AssetLoader;
+
+ it('Module exists', function () {
+ expect(AssetLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/BitmapFontLoader.js b/test/unit/pixi/loaders/BitmapFontLoader.js
new file mode 100644
index 0000000..6253c42
--- /dev/null
+++ b/test/unit/pixi/loaders/BitmapFontLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/BitmapFontLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var BitmapFontLoader = PIXI.BitmapFontLoader;
+
+ it('Module exists', function () {
+ expect(PIXI.BitmapFontLoader).to.be.a('function');
+ });
+});
diff --git a/.gitignore b/.gitignore
index 12e1b62..0b88317 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
node_modules
.DS_Store
-.project
\ No newline at end of file
+.project
+*.log
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..63e4d7c
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,8 @@
+language: node_js
+node_js:
+ - 0.10
+
+before_script:
+ - npm install -g grunt-cli
+ - export DISPLAY=:99.0
+ - sh -e /etc/init.d/xvfb start
diff --git a/Gruntfile.js b/Gruntfile.js
index b083b49..103938c 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -1,10 +1,12 @@
+'use strict';
+
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-connect');
- grunt.loadNpmTasks('grunt-contrib-qunit');
grunt.loadNpmTasks('grunt-contrib-yuidoc');
+ grunt.loadTasks('tasks');
var root = 'src/pixi/',
debug = 'bin/pixi.dev.js',
@@ -79,7 +81,7 @@
},
files: {
srcBlob: '<%= dirs.src %>/**/*.js',
- testBlob: '<%= dirs.test %>/unit/**/*.js',
+ testBlob: '<%= dirs.test %>/{functional,lib/pixi,unit}/**/*.js',
build: '<%= dirs.build %>/pixi.dev.js',
buildMin: '<%= dirs.build %>/pixi.js'
},
@@ -94,7 +96,12 @@
},
jshint: {
beforeconcat: srcFiles,
- test: ['<%= files.testBlob %>'],
+ test: {
+ src: ['<%= files.testBlob %>'],
+ options: {
+ expr: true
+ }
+ },
options: {
asi: true,
smarttabs: true
@@ -128,12 +135,6 @@
]
},
connect: {
- qunit: {
- options: {
- port: grunt.option('port-test') || 9002,
- base: './'
- }
- },
test: {
options: {
port: grunt.option('port-test') || 9002,
@@ -142,13 +143,6 @@
}
}
},
- qunit: {
- all: {
- options: {
- urls: ['http://localhost:' + (grunt.option('port-test') || 9002) + '/test/index.html']
- }
- }
- },
yuidoc: {
compile: {
name: '<%= pkg.name %>',
@@ -161,6 +155,13 @@
outdir: '<%= dirs.docs %>'
}
}
+ },
+ karma: {
+ unit: {
+ configFile: 'test/karma.conf.js',
+ // browsers: ['Chrome'],
+ singleRun: true
+ }
}
});
@@ -182,9 +183,10 @@
}
)
- grunt.registerTask('default', ['concat', 'uglify', 'distribute']);
grunt.registerTask('build', ['concat', 'uglify', 'distribute']);
- grunt.registerTask('test', ['build', 'connect:qunit', 'qunit']);
+ grunt.registerTask('test', ['concat', 'jshint:test', 'karma']);
grunt.registerTask('docs', ['yuidoc']);
-
-}
\ No newline at end of file
+ grunt.registerTask('default', ['test', 'uglify', 'distribute']);
+ // Travis CI task.
+ grunt.registerTask('travis', ['test']);
+}
diff --git a/README.md b/README.md
index c62ef86..690cfe4 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,8 @@

+[](http://travis-ci.org/drkibitz/pixi.js)
+
#### JavaScript 2D Renderer ####
The aim of this project is to provide a fast lightweight 2D library that works
diff --git a/package.json b/package.json
index b373240..1246a68 100644
--- a/package.json
+++ b/package.json
@@ -18,14 +18,21 @@
"main": "bin/pixi.js",
+ "scripts": {
+ "test": "grunt travis --verbose"
+ },
+
"dependencies": {},
"devDependencies": {
"grunt": "~0.4.x",
- "grunt-contrib-jshint": "0.3.x",
+ "grunt-contrib-jshint": "0.6.x",
"grunt-contrib-uglify": "0.2.x",
- "grunt-contrib-connect": "0.2.x",
- "grunt-contrib-qunit": "0.2.x",
+ "grunt-contrib-connect": "0.3.x",
"grunt-contrib-yuidoc": "0.4.x",
- "grunt-contrib-concat": "0.1.x"
+ "grunt-contrib-concat": "0.3.x",
+ "chai": "~1.7.0",
+ "karma": "0.11.0",
+ "karma-firefox-launcher": "0.1.0",
+ "karma-mocha": "0.1.0"
}
}
diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js
index a7c520e..ee82bbd 100644
--- a/src/pixi/InteractionManager.js
+++ b/src/pixi/InteractionManager.js
@@ -62,7 +62,6 @@
this.onTouchEnd = this.onTouchEnd.bind(this);
this.onTouchMove = this.onTouchMove.bind(this);
-
this.last = 0;
}
diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js
index 1a95d20..eef1059 100644
--- a/src/pixi/core/Ellipse.js
+++ b/src/pixi/core/Ellipse.js
@@ -78,7 +78,7 @@
return (normx + normy < 0.25);
}
-PIXI.Ellipse.getBounds = function()
+PIXI.Ellipse.prototype.getBounds = function()
{
return new PIXI.Rectangle(this.x, this.y, this.width, this.height);
}
diff --git a/tasks/karma.js b/tasks/karma.js
new file mode 100644
index 0000000..c340485
--- /dev/null
+++ b/tasks/karma.js
@@ -0,0 +1,27 @@
+'use strict';
+
+var path = require('path');
+var server = require('karma').server;
+
+module.exports = function (grunt) {
+ grunt.registerMultiTask('karma', 'run karma.', function() {
+ var done = this.async();
+ var options = this.options({
+ background: false
+ });
+ var data = this.data;
+
+ //merge options onto data, with data taking precedence
+ data = grunt.util._.merge(options, data);
+ data.configFile = path.resolve(data.configFile);
+ if (data.configFile) {
+ data.configFile = grunt.template.process(data.configFile);
+ }
+
+ server.start(
+ data,
+ function(code) {
+ done(!code);
+ });
+ });
+};
diff --git a/test/functional/example-1-basics/bunny.png b/test/functional/example-1-basics/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/functional/example-1-basics/bunny.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-30.png b/test/functional/example-1-basics/frame-30.png
new file mode 100644
index 0000000..96e3409
--- /dev/null
+++ b/test/functional/example-1-basics/frame-30.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-60.png b/test/functional/example-1-basics/frame-60.png
new file mode 100644
index 0000000..af3f4ce
--- /dev/null
+++ b/test/functional/example-1-basics/frame-60.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-90.png b/test/functional/example-1-basics/frame-90.png
new file mode 100644
index 0000000..099b823
--- /dev/null
+++ b/test/functional/example-1-basics/frame-90.png
Binary files differ
diff --git a/test/functional/example-1-basics/index.js b/test/functional/example-1-basics/index.js
new file mode 100644
index 0000000..7ae7a98
--- /dev/null
+++ b/test/functional/example-1-basics/index.js
@@ -0,0 +1,133 @@
+describe('Example 1 - Basics', function () {
+ 'use strict';
+
+ var baseUri = '/base/test/functional/example-1-basics';
+ var expect = chai.expect;
+ var currentFrame = 0;
+ var frameEvents = {};
+ var stage;
+ var renderer;
+ var bunny;
+
+ function onFrame(frame, callback) {
+ frameEvents[frame] = callback;
+ }
+
+ function animate() {
+ currentFrame += 1;
+
+ requestAnimFrame( animate );
+
+ // just for fun, lets rotate mr rabbit a little
+ bunny.rotation += 0.1;
+
+ // render the stage
+ renderer.render(stage);
+
+ if (frameEvents[currentFrame])
+ frameEvents[currentFrame](currentFrame);
+ }
+
+ function initScene() {
+ // create an new instance of a pixi stage
+ stage = new PIXI.Stage(0x66FF99);
+
+ // create a renderer instance
+ renderer = PIXI.autoDetectRenderer(400, 300);
+ console.log('Is PIXI.WebGLRenderer: ' + (renderer instanceof PIXI.WebGLRenderer));
+
+ // add the renderer view element to the DOM
+ document.body.appendChild(renderer.view);
+
+ requestAnimFrame( animate );
+
+ // create a texture from an image path
+ var texture = PIXI.Texture.fromImage(baseUri + "/bunny.png");
+ // create a new Sprite using the texture
+ bunny = new PIXI.Sprite(texture);
+
+ // center the sprites anchor point
+ bunny.anchor.x = 0.5;
+ bunny.anchor.y = 0.5;
+
+ // move the sprite t the center of the screen
+ bunny.position.x = 200;
+ bunny.position.y = 150;
+
+ stage.addChild(bunny);
+ }
+
+ it('assets loaded', function (done) {
+ var loader = new PIXI.AssetLoader([
+ baseUri + '/bunny.png',
+ baseUri + '/frame-30.png',
+ baseUri + '/frame-60.png',
+ baseUri + '/frame-90.png'
+ ]);
+ // loader.on('onProgress', function (event) {
+ // console.log(event.content);
+ // });
+ loader.on('onComplete', function (event) {
+ done();
+ initScene();
+ });
+ loader.load();
+ });
+
+ it('frame 30 should match', function (done) {
+ this.timeout(700);
+ onFrame(30, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-30.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 60 should match', function (done) {
+ this.timeout(1200);
+ onFrame(60, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-60.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 90 should match', function (done) {
+ this.timeout(1700);
+ onFrame(90, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-90.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ // it('capture something', function (done) {
+ // this.timeout(2000000);
+ // onFrame(30, function () {
+ // var img = new Image();
+ // img.src = renderer.view.toDataURL('image/png');
+ // document.body.appendChild(img);
+ // });
+ // });
+});
diff --git a/test/index.html b/test/index.html
deleted file mode 100644
index 9cbcac5..0000000
--- a/test/index.html
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
- Pixi.js Test Suite
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/test/karma.conf.js b/test/karma.conf.js
new file mode 100644
index 0000000..c66a696
--- /dev/null
+++ b/test/karma.conf.js
@@ -0,0 +1,82 @@
+module.exports = function(config) {
+ config.set({
+
+ // base path, that will be used to resolve files and exclude
+ basePath : '../',
+
+ frameworks : ['mocha'],
+
+ // list of files / patterns to load in the browser
+ files : [
+ 'node_modules/chai/chai.js',
+ 'bin/pixi.dev.js',
+ 'test/lib/**/*.js',
+ 'test/unit/**/*.js',
+ // 'test/functional/**/*.js',
+ {pattern: 'test/**/*.png', watched: false, included: false, served: true}
+ ],
+
+ // list of files to exclude
+ exclude : [],
+
+ // use dolts reporter, as travis terminal does not support escaping sequences
+ // possible values: 'dots', 'progress', 'junit', 'teamcity'
+ // CLI --reporters progress
+ reporters : ['progress'],
+
+ // web server port
+ // CLI --port 9876
+ port : 9876,
+
+ // cli runner port
+ // CLI --runner-port 9100
+ runnerPort : 9100,
+
+ // enable / disable colors in the output (reporters and logs)
+ // CLI --colors --no-colors
+ colors : true,
+
+ // level of logging
+ // possible values: karma.LOG_DISABLE || karma.LOG_ERROR || karma.LOG_WARN || karma.LOG_INFO || karma.LOG_DEBUG
+ // CLI --log-level debug
+ logLevel : config.LOG_DEBUG,
+
+ // enable / disable watching file and executing tests whenever any file changes
+ // CLI --auto-watch --no-auto-watch
+ autoWatch : false,
+
+ // Start these browsers, currently available:
+ // - Chrome
+ // - ChromeCanary
+ // - Firefox
+ // - Opera
+ // - Safari (only Mac)
+ // - PhantomJS
+ // - IE (only Windows)
+ // CLI --browsers Chrome,Firefox,Safari
+ browsers : ['Firefox'],
+
+ // If browser does not capture in given timeout [ms], kill it
+ // CLI --capture-timeout 5000
+ captureTimeout : 5000,
+
+ // Auto run tests on start (when browsers are captured) and exit
+ // CLI --single-run --no-single-run
+ singleRun : true,
+
+ // report which specs are slower than 500ms
+ // CLI --report-slower-than 500
+ reportSlowerThan : 1000,
+
+ preprocessors : {
+ // '**/client/js/*.js': 'coverage'
+ },
+
+ plugins : [
+ 'karma-mocha',
+ // 'karma-chrome-launcher',
+ 'karma-firefox-launcher',
+ // 'karma-phantomjs-launcher'
+ ]
+ });
+};
diff --git a/test/lib/pixi/core/Matrix.js b/test/lib/pixi/core/Matrix.js
new file mode 100644
index 0000000..d26386b
--- /dev/null
+++ b/test/lib/pixi/core/Matrix.js
@@ -0,0 +1,40 @@
+
+function pixi_core_Matrix_confirmNewMat3(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(1);
+ expect(matrix[5]).to.equal(0);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(1);
+}
+
+function pixi_core_Matrix_confirmNewMat4(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[0]).to.equal(1);
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(0);
+ expect(matrix[5]).to.equal(1);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(0);
+ expect(matrix[9]).to.equal(0);
+ expect(matrix[10]).to.equal(1);
+ expect(matrix[11]).to.equal(0);
+ expect(matrix[12]).to.equal(0);
+ expect(matrix[13]).to.equal(0);
+ expect(matrix[14]).to.equal(0);
+ expect(matrix[15]).to.equal(1);
+}
diff --git a/test/lib/pixi/core/Point.js b/test/lib/pixi/core/Point.js
new file mode 100644
index 0000000..e5df07b
--- /dev/null
+++ b/test/lib/pixi/core/Point.js
@@ -0,0 +1,10 @@
+
+function pixi_core_Point_confirm(obj, x, y) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Point);
+ expect(obj).to.respondTo('clone');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+}
diff --git a/test/lib/pixi/core/Rectangle.js b/test/lib/pixi/core/Rectangle.js
new file mode 100644
index 0000000..23f0d12
--- /dev/null
+++ b/test/lib/pixi/core/Rectangle.js
@@ -0,0 +1,13 @@
+
+function pixi_core_Rectangle_confirm(obj, x, y, width, height) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Rectangle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+ expect(obj).to.have.property('width', width);
+ expect(obj).to.have.property('height', height);
+}
diff --git a/test/lib/pixi/display/DisplayObject.js b/test/lib/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..1388a7f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObject.js
@@ -0,0 +1,43 @@
+
+function pixi_display_DisplayObject_confirmNew(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObject);
+ expect(obj).to.respondTo('setInteractive');
+ expect(obj).to.respondTo('addFilter');
+ expect(obj).to.respondTo('removeFilter');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.property('last', obj);
+ expect(obj).to.have.property('first', obj);
+
+ expect(obj).to.contain.property('position');
+ pixi_core_Point_confirm(obj.position, 0, 0);
+ expect(obj).to.contain.property('scale');
+ pixi_core_Point_confirm(obj.scale, 1, 1);
+ expect(obj).to.contain.property('pivot');
+ pixi_core_Point_confirm(obj.pivot, 0, 0);
+
+ expect(obj).to.have.property('rotation', 0);
+ expect(obj).to.have.property('alpha', 1);
+ expect(obj).to.have.property('visible', true);
+ expect(obj).to.have.property('buttonMode', false);
+ expect(obj).to.have.property('parent', null);
+ expect(obj).to.have.property('worldAlpha', 1);
+
+ expect(obj).to.have.property('hitArea');
+ expect(obj).to.have.property('interactive'); // TODO: Have a better default value
+ expect('mask' in obj).to.be.true; // TODO: Have a better default value
+ expect(obj.mask).to.be.undefined;
+
+ expect(obj).to.have.property('renderable');
+ expect(obj).to.have.property('stage');
+
+ expect(obj).to.have.deep.property('worldTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ expect(obj).to.have.deep.property('localTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.localTransform);
+
+ expect(obj).to.have.deep.property('color.length', 0);
+ expect(obj).to.have.property('dynamic', true);
+}
diff --git a/test/lib/pixi/display/DisplayObjectContainer.js b/test/lib/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..085c59f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,16 @@
+
+function pixi_display_DisplayObjectContainer_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObject_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObjectContainer);
+ expect(obj).to.respondTo('addChild');
+ expect(obj).to.respondTo('addChildAt');
+ expect(obj).to.respondTo('swapChildren');
+ expect(obj).to.respondTo('getChildAt');
+ expect(obj).to.respondTo('removeChild');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('children.length', 0);
+}
diff --git a/test/lib/pixi/display/Sprite.js b/test/lib/pixi/display/Sprite.js
new file mode 100644
index 0000000..cc7a2d6
--- /dev/null
+++ b/test/lib/pixi/display/Sprite.js
@@ -0,0 +1,28 @@
+
+function pixi_display_Sprite_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Sprite);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', true);
+ expect(obj).to.have.property('stage', null);
+
+ expect(obj).to.have.property('anchor');
+ pixi_core_Point_confirm(obj.anchor, 0, 0);
+
+ expect(obj).to.have.property('blendMode', PIXI.blendModes.NORMAL);
+ expect(obj).to.have.property('width', 1); // TODO: is 1 expected
+ expect(obj).to.have.property('height', 1); // TODO: is 1 expected
+
+ // FIXME: Just make this a boolean that is always there
+ expect(!!obj.updateFrame).to.equal(obj.texture.baseTexture.hasLoaded);
+
+ expect(obj).to.have.property('texture');
+ pixi_textures_Texture_confirmNew(obj.texture, done);
+}
diff --git a/test/lib/pixi/extras/Strip.js b/test/lib/pixi/extras/Strip.js
new file mode 100644
index 0000000..8927a8a
--- /dev/null
+++ b/test/lib/pixi/extras/Strip.js
@@ -0,0 +1,12 @@
+
+function pixi_extras_Strip_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Strip);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ // TODO: Test properties
+}
diff --git a/test/lib/pixi/textures/Texture.js b/test/lib/pixi/textures/Texture.js
new file mode 100644
index 0000000..d5867b6
--- /dev/null
+++ b/test/lib/pixi/textures/Texture.js
@@ -0,0 +1,31 @@
+
+function pixi_textures_Texture_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ function confirmFrameDone() {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, obj.baseTexture.width, obj.baseTexture.height);
+
+ expect(obj).to.have.property('width', obj.baseTexture.width);
+ expect(obj).to.have.property('height', obj.baseTexture.height);
+ done();
+ }
+
+ expect(obj).to.be.an.instanceof(PIXI.Texture);
+ pixi_utils_EventTarget_like(obj);
+
+ expect(obj).to.have.property('baseTexture')
+ .and.to.be.an.instanceof(PIXI.BaseTexture);
+
+ expect(obj).to.have.property('scope', obj);
+
+ expect(obj).to.have.property('trim');
+ pixi_core_Point_confirm(obj.trim, 0, 0);
+
+ expect(obj).to.have.property('frame');
+ if (obj.baseTexture.hasLoaded) {
+ confirmFrameDone();
+ } else {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, 1, 1);
+ obj.addEventListener('update', confirmFrameDone);
+ }
+}
diff --git a/test/lib/pixi/utils/EventTarget.js b/test/lib/pixi/utils/EventTarget.js
new file mode 100644
index 0000000..7b1dcfa
--- /dev/null
+++ b/test/lib/pixi/utils/EventTarget.js
@@ -0,0 +1,8 @@
+
+function pixi_utils_EventTarget_like(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.respondTo('addEventListener');
+ expect(obj).to.respondTo('dispatchEvent');
+ expect(obj).to.respondTo('removeEventListener');
+}
diff --git a/test/lib/qunit-1.11.0.css b/test/lib/qunit-1.11.0.css
deleted file mode 100644
index d7fc0c8..0000000
--- a/test/lib/qunit-1.11.0.css
+++ /dev/null
@@ -1,244 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-/** Font Family and Sizes */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
- font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
-}
-
-#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
-#qunit-tests { font-size: smaller; }
-
-
-/** Resets */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter {
- margin: 0;
- padding: 0;
-}
-
-
-/** Header */
-
-#qunit-header {
- padding: 0.5em 0 0.5em 1em;
-
- color: #8699a4;
- background-color: #0d3349;
-
- font-size: 1.5em;
- line-height: 1em;
- font-weight: normal;
-
- border-radius: 5px 5px 0 0;
- -moz-border-radius: 5px 5px 0 0;
- -webkit-border-top-right-radius: 5px;
- -webkit-border-top-left-radius: 5px;
-}
-
-#qunit-header a {
- text-decoration: none;
- color: #c2ccd1;
-}
-
-#qunit-header a:hover,
-#qunit-header a:focus {
- color: #fff;
-}
-
-#qunit-testrunner-toolbar label {
- display: inline-block;
- padding: 0 .5em 0 .1em;
-}
-
-#qunit-banner {
- height: 5px;
-}
-
-#qunit-testrunner-toolbar {
- padding: 0.5em 0 0.5em 2em;
- color: #5E740B;
- background-color: #eee;
- overflow: hidden;
-}
-
-#qunit-userAgent {
- padding: 0.5em 0 0.5em 2.5em;
- background-color: #2b81af;
- color: #fff;
- text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
-}
-
-#qunit-modulefilter-container {
- float: right;
-}
-
-/** Tests: Pass/Fail */
-
-#qunit-tests {
- list-style-position: inside;
-}
-
-#qunit-tests li {
- padding: 0.4em 0.5em 0.4em 2.5em;
- border-bottom: 1px solid #fff;
- list-style-position: inside;
-}
-
-#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running {
- display: none;
-}
-
-#qunit-tests li strong {
- cursor: pointer;
-}
-
-#qunit-tests li a {
- padding: 0.5em;
- color: #c2ccd1;
- text-decoration: none;
-}
-#qunit-tests li a:hover,
-#qunit-tests li a:focus {
- color: #000;
-}
-
-#qunit-tests li .runtime {
- float: right;
- font-size: smaller;
-}
-
-.qunit-assert-list {
- margin-top: 0.5em;
- padding: 0.5em;
-
- background-color: #fff;
-
- border-radius: 5px;
- -moz-border-radius: 5px;
- -webkit-border-radius: 5px;
-}
-
-.qunit-collapsed {
- display: none;
-}
-
-#qunit-tests table {
- border-collapse: collapse;
- margin-top: .2em;
-}
-
-#qunit-tests th {
- text-align: right;
- vertical-align: top;
- padding: 0 .5em 0 0;
-}
-
-#qunit-tests td {
- vertical-align: top;
-}
-
-#qunit-tests pre {
- margin: 0;
- white-space: pre-wrap;
- word-wrap: break-word;
-}
-
-#qunit-tests del {
- background-color: #e0f2be;
- color: #374e0c;
- text-decoration: none;
-}
-
-#qunit-tests ins {
- background-color: #ffcaca;
- color: #500;
- text-decoration: none;
-}
-
-/*** Test Counts */
-
-#qunit-tests b.counts { color: black; }
-#qunit-tests b.passed { color: #5E740B; }
-#qunit-tests b.failed { color: #710909; }
-
-#qunit-tests li li {
- padding: 5px;
- background-color: #fff;
- border-bottom: none;
- list-style-position: inside;
-}
-
-/*** Passing Styles */
-
-#qunit-tests li li.pass {
- color: #3c510c;
- background-color: #fff;
- border-left: 10px solid #C6E746;
-}
-
-#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
-#qunit-tests .pass .test-name { color: #366097; }
-
-#qunit-tests .pass .test-actual,
-#qunit-tests .pass .test-expected { color: #999999; }
-
-#qunit-banner.qunit-pass { background-color: #C6E746; }
-
-/*** Failing Styles */
-
-#qunit-tests li li.fail {
- color: #710909;
- background-color: #fff;
- border-left: 10px solid #EE5757;
- white-space: pre;
-}
-
-#qunit-tests > li:last-child {
- border-radius: 0 0 5px 5px;
- -moz-border-radius: 0 0 5px 5px;
- -webkit-border-bottom-right-radius: 5px;
- -webkit-border-bottom-left-radius: 5px;
-}
-
-#qunit-tests .fail { color: #000000; background-color: #EE5757; }
-#qunit-tests .fail .test-name,
-#qunit-tests .fail .module-name { color: #000000; }
-
-#qunit-tests .fail .test-actual { color: #EE5757; }
-#qunit-tests .fail .test-expected { color: green; }
-
-#qunit-banner.qunit-fail { background-color: #EE5757; }
-
-
-/** Result */
-
-#qunit-testresult {
- padding: 0.5em 0.5em 0.5em 2.5em;
-
- color: #2b81af;
- background-color: #D2E0E6;
-
- border-bottom: 1px solid white;
-}
-#qunit-testresult .module-name {
- font-weight: bold;
-}
-
-/** Fixture */
-
-#qunit-fixture {
- position: absolute;
- top: -10000px;
- left: -10000px;
- width: 1000px;
- height: 1000px;
-}
diff --git a/test/lib/qunit-1.11.0.js b/test/lib/qunit-1.11.0.js
deleted file mode 100644
index 302545f..0000000
--- a/test/lib/qunit-1.11.0.js
+++ /dev/null
@@ -1,2152 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-(function( window ) {
-
-var QUnit,
- assert,
- config,
- onErrorFnPrev,
- testId = 0,
- fileName = (sourceFromStacktrace( 0 ) || "" ).replace(/(:\d+)+\)?/, "").replace(/.+\//, ""),
- toString = Object.prototype.toString,
- hasOwn = Object.prototype.hasOwnProperty,
- // Keep a local reference to Date (GH-283)
- Date = window.Date,
- defined = {
- setTimeout: typeof window.setTimeout !== "undefined",
- sessionStorage: (function() {
- var x = "qunit-test-string";
- try {
- sessionStorage.setItem( x, x );
- sessionStorage.removeItem( x );
- return true;
- } catch( e ) {
- return false;
- }
- }())
- },
- /**
- * Provides a normalized error string, correcting an issue
- * with IE 7 (and prior) where Error.prototype.toString is
- * not properly implemented
- *
- * Based on http://es5.github.com/#x15.11.4.4
- *
- * @param {String|Error} error
- * @return {String} error message
- */
- errorString = function( error ) {
- var name, message,
- errorString = error.toString();
- if ( errorString.substring( 0, 7 ) === "[object" ) {
- name = error.name ? error.name.toString() : "Error";
- message = error.message ? error.message.toString() : "";
- if ( name && message ) {
- return name + ": " + message;
- } else if ( name ) {
- return name;
- } else if ( message ) {
- return message;
- } else {
- return "Error";
- }
- } else {
- return errorString;
- }
- },
- /**
- * Makes a clone of an object using only Array or Object as base,
- * and copies over the own enumerable properties.
- *
- * @param {Object} obj
- * @return {Object} New object with only the own properties (recursively).
- */
- objectValues = function( obj ) {
- // Grunt 0.3.x uses an older version of jshint that still has jshint/jshint#392.
- /*jshint newcap: false */
- var key, val,
- vals = QUnit.is( "array", obj ) ? [] : {};
- for ( key in obj ) {
- if ( hasOwn.call( obj, key ) ) {
- val = obj[key];
- vals[key] = val === Object(val) ? objectValues(val) : val;
- }
- }
- return vals;
- };
-
-function Test( settings ) {
- extend( this, settings );
- this.assertions = [];
- this.testNumber = ++Test.count;
-}
-
-Test.count = 0;
-
-Test.prototype = {
- init: function() {
- var a, b, li,
- tests = id( "qunit-tests" );
-
- if ( tests ) {
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml;
-
- // `a` initialized at top of scope
- a = document.createElement( "a" );
- a.innerHTML = "Rerun";
- a.href = QUnit.url({ testNumber: this.testNumber });
-
- li = document.createElement( "li" );
- li.appendChild( b );
- li.appendChild( a );
- li.className = "running";
- li.id = this.id = "qunit-test-output" + testId++;
-
- tests.appendChild( li );
- }
- },
- setup: function() {
- if ( this.module !== config.previousModule ) {
- if ( config.previousModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.previousModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
- config.previousModule = this.module;
- config.moduleStats = { all: 0, bad: 0 };
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- } else if ( config.autorun ) {
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- }
-
- config.current = this;
-
- this.testEnvironment = extend({
- setup: function() {},
- teardown: function() {}
- }, this.moduleTestEnvironment );
-
- this.started = +new Date();
- runLoggingCallbacks( "testStart", QUnit, {
- name: this.testName,
- module: this.module
- });
-
- // allow utility functions to access the current test environment
- // TODO why??
- QUnit.current_testEnvironment = this.testEnvironment;
-
- if ( !config.pollution ) {
- saveGlobal();
- }
- if ( config.notrycatch ) {
- this.testEnvironment.setup.call( this.testEnvironment );
- return;
- }
- try {
- this.testEnvironment.setup.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Setup failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- },
- run: function() {
- config.current = this;
-
- var running = id( "qunit-testresult" );
-
- if ( running ) {
- running.innerHTML = "Running:
" + this.nameHtml;
- }
-
- if ( this.async ) {
- QUnit.stop();
- }
-
- this.callbackStarted = +new Date();
-
- if ( config.notrycatch ) {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- return;
- }
-
- try {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- } catch( e ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
-
- QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + " " + this.stack + ": " + ( e.message || e ), extractStacktrace( e, 0 ) );
- // else next test will carry the responsibility
- saveGlobal();
-
- // Restart the tests if they're blocking
- if ( config.blocking ) {
- QUnit.start();
- }
- }
- },
- teardown: function() {
- config.current = this;
- if ( config.notrycatch ) {
- if ( typeof this.callbackRuntime === "undefined" ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
- }
- this.testEnvironment.teardown.call( this.testEnvironment );
- return;
- } else {
- try {
- this.testEnvironment.teardown.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Teardown failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- }
- checkPollution();
- },
- finish: function() {
- config.current = this;
- if ( config.requireExpects && this.expected === null ) {
- QUnit.pushFailure( "Expected number of assertions to be defined, but expect() was not called.", this.stack );
- } else if ( this.expected !== null && this.expected !== this.assertions.length ) {
- QUnit.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack );
- } else if ( this.expected === null && !this.assertions.length ) {
- QUnit.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions.", this.stack );
- }
-
- var i, assertion, a, b, time, li, ol,
- test = this,
- good = 0,
- bad = 0,
- tests = id( "qunit-tests" );
-
- this.runtime = +new Date() - this.started;
- config.stats.all += this.assertions.length;
- config.moduleStats.all += this.assertions.length;
-
- if ( tests ) {
- ol = document.createElement( "ol" );
- ol.className = "qunit-assert-list";
-
- for ( i = 0; i < this.assertions.length; i++ ) {
- assertion = this.assertions[i];
-
- li = document.createElement( "li" );
- li.className = assertion.result ? "pass" : "fail";
- li.innerHTML = assertion.message || ( assertion.result ? "okay" : "failed" );
- ol.appendChild( li );
-
- if ( assertion.result ) {
- good++;
- } else {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
-
- // store result when possible
- if ( QUnit.config.reorder && defined.sessionStorage ) {
- if ( bad ) {
- sessionStorage.setItem( "qunit-test-" + this.module + "-" + this.testName, bad );
- } else {
- sessionStorage.removeItem( "qunit-test-" + this.module + "-" + this.testName );
- }
- }
-
- if ( bad === 0 ) {
- addClass( ol, "qunit-collapsed" );
- }
-
- // `b` initialized at top of scope
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml + " (" + bad + ", " + good + ", " + this.assertions.length + ")";
-
- addEvent(b, "click", function() {
- var next = b.parentNode.lastChild,
- collapsed = hasClass( next, "qunit-collapsed" );
- ( collapsed ? removeClass : addClass )( next, "qunit-collapsed" );
- });
-
- addEvent(b, "dblclick", function( e ) {
- var target = e && e.target ? e.target : window.event.srcElement;
- if ( target.nodeName.toLowerCase() === "span" || target.nodeName.toLowerCase() === "b" ) {
- target = target.parentNode;
- }
- if ( window.location && target.nodeName.toLowerCase() === "strong" ) {
- window.location = QUnit.url({ testNumber: test.testNumber });
- }
- });
-
- // `time` initialized at top of scope
- time = document.createElement( "span" );
- time.className = "runtime";
- time.innerHTML = this.runtime + " ms";
-
- // `li` initialized at top of scope
- li = id( this.id );
- li.className = bad ? "fail" : "pass";
- li.removeChild( li.firstChild );
- a = li.firstChild;
- li.appendChild( b );
- li.appendChild( a );
- li.appendChild( time );
- li.appendChild( ol );
-
- } else {
- for ( i = 0; i < this.assertions.length; i++ ) {
- if ( !this.assertions[i].result ) {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
- }
-
- runLoggingCallbacks( "testDone", QUnit, {
- name: this.testName,
- module: this.module,
- failed: bad,
- passed: this.assertions.length - bad,
- total: this.assertions.length,
- duration: this.runtime
- });
-
- QUnit.reset();
-
- config.current = undefined;
- },
-
- queue: function() {
- var bad,
- test = this;
-
- synchronize(function() {
- test.init();
- });
- function run() {
- // each of these can by async
- synchronize(function() {
- test.setup();
- });
- synchronize(function() {
- test.run();
- });
- synchronize(function() {
- test.teardown();
- });
- synchronize(function() {
- test.finish();
- });
- }
-
- // `bad` initialized at top of scope
- // defer when previous test run passed, if storage is available
- bad = QUnit.config.reorder && defined.sessionStorage &&
- +sessionStorage.getItem( "qunit-test-" + this.module + "-" + this.testName );
-
- if ( bad ) {
- run();
- } else {
- synchronize( run, true );
- }
- }
-};
-
-// Root QUnit object.
-// `QUnit` initialized at top of scope
-QUnit = {
-
- // call on start of module test to prepend name to all tests
- module: function( name, testEnvironment ) {
- config.currentModule = name;
- config.currentModuleTestEnvironment = testEnvironment;
- config.modules[name] = true;
- },
-
- asyncTest: function( testName, expected, callback ) {
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- QUnit.test( testName, expected, callback, true );
- },
-
- test: function( testName, expected, callback, async ) {
- var test,
- nameHtml = "" + escapeText( testName ) + "";
-
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- if ( config.currentModule ) {
- nameHtml = "" + escapeText( config.currentModule ) + ": " + nameHtml;
- }
-
- test = new Test({
- nameHtml: nameHtml,
- testName: testName,
- expected: expected,
- async: async,
- callback: callback,
- module: config.currentModule,
- moduleTestEnvironment: config.currentModuleTestEnvironment,
- stack: sourceFromStacktrace( 2 )
- });
-
- if ( !validTest( test ) ) {
- return;
- }
-
- test.queue();
- },
-
- // Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through.
- expect: function( asserts ) {
- if (arguments.length === 1) {
- config.current.expected = asserts;
- } else {
- return config.current.expected;
- }
- },
-
- start: function( count ) {
- // QUnit hasn't been initialized yet.
- // Note: RequireJS (et al) may delay onLoad
- if ( config.semaphore === undefined ) {
- QUnit.begin(function() {
- // This is triggered at the top of QUnit.load, push start() to the event loop, to allow QUnit.load to finish first
- setTimeout(function() {
- QUnit.start( count );
- });
- });
- return;
- }
-
- config.semaphore -= count || 1;
- // don't start until equal number of stop-calls
- if ( config.semaphore > 0 ) {
- return;
- }
- // ignore if start is called more often then stop
- if ( config.semaphore < 0 ) {
- config.semaphore = 0;
- QUnit.pushFailure( "Called start() while already started (QUnit.config.semaphore was 0 already)", null, sourceFromStacktrace(2) );
- return;
- }
- // A slight delay, to avoid any current callbacks
- if ( defined.setTimeout ) {
- window.setTimeout(function() {
- if ( config.semaphore > 0 ) {
- return;
- }
- if ( config.timeout ) {
- clearTimeout( config.timeout );
- }
-
- config.blocking = false;
- process( true );
- }, 13);
- } else {
- config.blocking = false;
- process( true );
- }
- },
-
- stop: function( count ) {
- config.semaphore += count || 1;
- config.blocking = true;
-
- if ( config.testTimeout && defined.setTimeout ) {
- clearTimeout( config.timeout );
- config.timeout = window.setTimeout(function() {
- QUnit.ok( false, "Test timed out" );
- config.semaphore = 1;
- QUnit.start();
- }, config.testTimeout );
- }
- }
-};
-
-// `assert` initialized at top of scope
-// Asssert helpers
-// All of these must either call QUnit.push() or manually do:
-// - runLoggingCallbacks( "log", .. );
-// - config.current.assertions.push({ .. });
-// We attach it to the QUnit object *after* we expose the public API,
-// otherwise `assert` will become a global variable in browsers (#341).
-assert = {
- /**
- * Asserts rough true-ish result.
- * @name ok
- * @function
- * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" );
- */
- ok: function( result, msg ) {
- if ( !config.current ) {
- throw new Error( "ok() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
- result = !!result;
-
- var source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: msg
- };
-
- msg = escapeText( msg || (result ? "okay" : "failed" ) );
- msg = "" + msg + "";
-
- if ( !result ) {
- source = sourceFromStacktrace( 2 );
- if ( source ) {
- details.source = source;
- msg += "Source: | " + escapeText( source ) + " |
---|
";
- }
- }
- runLoggingCallbacks( "log", QUnit, details );
- config.current.assertions.push({
- result: result,
- message: msg
- });
- },
-
- /**
- * Assert that the first two arguments are equal, with an optional message.
- * Prints out both actual and expected values.
- * @name equal
- * @function
- * @example equal( format( "Received {0} bytes.", 2), "Received 2 bytes.", "format() replaces {0} with next argument" );
- */
- equal: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected == actual, actual, expected, message );
- },
-
- /**
- * @name notEqual
- * @function
- */
- notEqual: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected != actual, actual, expected, message );
- },
-
- /**
- * @name propEqual
- * @function
- */
- propEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notPropEqual
- * @function
- */
- notPropEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name deepEqual
- * @function
- */
- deepEqual: function( actual, expected, message ) {
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notDeepEqual
- * @function
- */
- notDeepEqual: function( actual, expected, message ) {
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name strictEqual
- * @function
- */
- strictEqual: function( actual, expected, message ) {
- QUnit.push( expected === actual, actual, expected, message );
- },
-
- /**
- * @name notStrictEqual
- * @function
- */
- notStrictEqual: function( actual, expected, message ) {
- QUnit.push( expected !== actual, actual, expected, message );
- },
-
- "throws": function( block, expected, message ) {
- var actual,
- expectedOutput = expected,
- ok = false;
-
- // 'expected' is optional
- if ( typeof expected === "string" ) {
- message = expected;
- expected = null;
- }
-
- config.current.ignoreGlobalErrors = true;
- try {
- block.call( config.current.testEnvironment );
- } catch (e) {
- actual = e;
- }
- config.current.ignoreGlobalErrors = false;
-
- if ( actual ) {
- // we don't want to validate thrown error
- if ( !expected ) {
- ok = true;
- expectedOutput = null;
- // expected is a regexp
- } else if ( QUnit.objectType( expected ) === "regexp" ) {
- ok = expected.test( errorString( actual ) );
- // expected is a constructor
- } else if ( actual instanceof expected ) {
- ok = true;
- // expected is a validation function which returns true is validation passed
- } else if ( expected.call( {}, actual ) === true ) {
- expectedOutput = null;
- ok = true;
- }
-
- QUnit.push( ok, actual, expectedOutput, message );
- } else {
- QUnit.pushFailure( message, null, 'No exception was thrown.' );
- }
- }
-};
-
-/**
- * @deprecate since 1.8.0
- * Kept assertion helpers in root for backwards compatibility.
- */
-extend( QUnit, assert );
-
-/**
- * @deprecated since 1.9.0
- * Kept root "raises()" for backwards compatibility.
- * (Note that we don't introduce assert.raises).
- */
-QUnit.raises = assert[ "throws" ];
-
-/**
- * @deprecated since 1.0.0, replaced with error pushes since 1.3.0
- * Kept to avoid TypeErrors for undefined methods.
- */
-QUnit.equals = function() {
- QUnit.push( false, false, false, "QUnit.equals has been deprecated since 2009 (e88049a0), use QUnit.equal instead" );
-};
-QUnit.same = function() {
- QUnit.push( false, false, false, "QUnit.same has been deprecated since 2009 (e88049a0), use QUnit.deepEqual instead" );
-};
-
-// We want access to the constructor's prototype
-(function() {
- function F() {}
- F.prototype = QUnit;
- QUnit = new F();
- // Make F QUnit's constructor so that we can add to the prototype later
- QUnit.constructor = F;
-}());
-
-/**
- * Config object: Maintain internal state
- * Later exposed as QUnit.config
- * `config` initialized at top of scope
- */
-config = {
- // The queue of tests to run
- queue: [],
-
- // block until document ready
- blocking: true,
-
- // when enabled, show only failing tests
- // gets persisted through sessionStorage and can be changed in UI via checkbox
- hidepassed: false,
-
- // by default, run previously failed tests first
- // very useful in combination with "Hide passed tests" checked
- reorder: true,
-
- // by default, modify document.title when suite is done
- altertitle: true,
-
- // when enabled, all tests must call expect()
- requireExpects: false,
-
- // add checkboxes that are persisted in the query-string
- // when enabled, the id is set to `true` as a `QUnit.config` property
- urlConfig: [
- {
- id: "noglobals",
- label: "Check for Globals",
- tooltip: "Enabling this will test if any test introduces new properties on the `window` object. Stored as query-strings."
- },
- {
- id: "notrycatch",
- label: "No try-catch",
- tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging exceptions in IE reasonable. Stored as query-strings."
- }
- ],
-
- // Set of all modules.
- modules: {},
-
- // logging callback queues
- begin: [],
- done: [],
- log: [],
- testStart: [],
- testDone: [],
- moduleStart: [],
- moduleDone: []
-};
-
-// Export global variables, unless an 'exports' object exists,
-// in that case we assume we're in CommonJS (dealt with on the bottom of the script)
-if ( typeof exports === "undefined" ) {
- extend( window, QUnit );
-
- // Expose QUnit object
- window.QUnit = QUnit;
-}
-
-// Initialize more QUnit.config and QUnit.urlParams
-(function() {
- var i,
- location = window.location || { search: "", protocol: "file:" },
- params = location.search.slice( 1 ).split( "&" ),
- length = params.length,
- urlParams = {},
- current;
-
- if ( params[ 0 ] ) {
- for ( i = 0; i < length; i++ ) {
- current = params[ i ].split( "=" );
- current[ 0 ] = decodeURIComponent( current[ 0 ] );
- // allow just a key to turn on a flag, e.g., test.html?noglobals
- current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true;
- urlParams[ current[ 0 ] ] = current[ 1 ];
- }
- }
-
- QUnit.urlParams = urlParams;
-
- // String search anywhere in moduleName+testName
- config.filter = urlParams.filter;
-
- // Exact match of the module name
- config.module = urlParams.module;
-
- config.testNumber = parseInt( urlParams.testNumber, 10 ) || null;
-
- // Figure out if we're running the tests from a server or not
- QUnit.isLocal = location.protocol === "file:";
-}());
-
-// Extend QUnit object,
-// these after set here because they should not be exposed as global functions
-extend( QUnit, {
- assert: assert,
-
- config: config,
-
- // Initialize the configuration options
- init: function() {
- extend( config, {
- stats: { all: 0, bad: 0 },
- moduleStats: { all: 0, bad: 0 },
- started: +new Date(),
- updateRate: 1000,
- blocking: false,
- autostart: true,
- autorun: false,
- filter: "",
- queue: [],
- semaphore: 1
- });
-
- var tests, banner, result,
- qunit = id( "qunit" );
-
- if ( qunit ) {
- qunit.innerHTML =
- "" +
- "" +
- "" +
- "" +
- "
";
- }
-
- tests = id( "qunit-tests" );
- banner = id( "qunit-banner" );
- result = id( "qunit-testresult" );
-
- if ( tests ) {
- tests.innerHTML = "";
- }
-
- if ( banner ) {
- banner.className = "";
- }
-
- if ( result ) {
- result.parentNode.removeChild( result );
- }
-
- if ( tests ) {
- result = document.createElement( "p" );
- result.id = "qunit-testresult";
- result.className = "result";
- tests.parentNode.insertBefore( result, tests );
- result.innerHTML = "Running...
";
- }
- },
-
- // Resets the test setup. Useful for tests that modify the DOM.
- reset: function() {
- var fixture = id( "qunit-fixture" );
- if ( fixture ) {
- fixture.innerHTML = config.fixture;
- }
- },
-
- // Trigger an event on an element.
- // @example triggerEvent( document.body, "click" );
- triggerEvent: function( elem, type, event ) {
- if ( document.createEvent ) {
- event = document.createEvent( "MouseEvents" );
- event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView,
- 0, 0, 0, 0, 0, false, false, false, false, 0, null);
-
- elem.dispatchEvent( event );
- } else if ( elem.fireEvent ) {
- elem.fireEvent( "on" + type );
- }
- },
-
- // Safe object type checking
- is: function( type, obj ) {
- return QUnit.objectType( obj ) === type;
- },
-
- objectType: function( obj ) {
- if ( typeof obj === "undefined" ) {
- return "undefined";
- // consider: typeof null === object
- }
- if ( obj === null ) {
- return "null";
- }
-
- var match = toString.call( obj ).match(/^\[object\s(.*)\]$/),
- type = match && match[1] || "";
-
- switch ( type ) {
- case "Number":
- if ( isNaN(obj) ) {
- return "nan";
- }
- return "number";
- case "String":
- case "Boolean":
- case "Array":
- case "Date":
- case "RegExp":
- case "Function":
- return type.toLowerCase();
- }
- if ( typeof obj === "object" ) {
- return "object";
- }
- return undefined;
- },
-
- push: function( result, actual, expected, message ) {
- if ( !config.current ) {
- throw new Error( "assertion outside test context, was " + sourceFromStacktrace() );
- }
-
- var output, source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: message,
- actual: actual,
- expected: expected
- };
-
- message = escapeText( message ) || ( result ? "okay" : "failed" );
- message = "" + message + "";
- output = message;
-
- if ( !result ) {
- expected = escapeText( QUnit.jsDump.parse(expected) );
- actual = escapeText( QUnit.jsDump.parse(actual) );
- output += "Expected: | " + expected + " |
";
-
- if ( actual !== expected ) {
- output += "Result: | " + actual + " |
";
- output += "Diff: | " + QUnit.diff( expected, actual ) + " |
";
- }
-
- source = sourceFromStacktrace();
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
- }
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: !!result,
- message: output
- });
- },
-
- pushFailure: function( message, source, actual ) {
- if ( !config.current ) {
- throw new Error( "pushFailure() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
-
- var output,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: false,
- message: message
- };
-
- message = escapeText( message ) || "error";
- message = "" + message + "";
- output = message;
-
- output += "";
-
- if ( actual ) {
- output += "Result: | " + escapeText( actual ) + " |
";
- }
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: false,
- message: output
- });
- },
-
- url: function( params ) {
- params = extend( extend( {}, QUnit.urlParams ), params );
- var key,
- querystring = "?";
-
- for ( key in params ) {
- if ( !hasOwn.call( params, key ) ) {
- continue;
- }
- querystring += encodeURIComponent( key ) + "=" +
- encodeURIComponent( params[ key ] ) + "&";
- }
- return window.location.protocol + "//" + window.location.host +
- window.location.pathname + querystring.slice( 0, -1 );
- },
-
- extend: extend,
- id: id,
- addEvent: addEvent
- // load, equiv, jsDump, diff: Attached later
-});
-
-/**
- * @deprecated: Created for backwards compatibility with test runner that set the hook function
- * into QUnit.{hook}, instead of invoking it and passing the hook function.
- * QUnit.constructor is set to the empty F() above so that we can add to it's prototype here.
- * Doing this allows us to tell if the following methods have been overwritten on the actual
- * QUnit object.
- */
-extend( QUnit.constructor.prototype, {
-
- // Logging callbacks; all receive a single argument with the listed properties
- // run test/logs.html for any related changes
- begin: registerLoggingCallback( "begin" ),
-
- // done: { failed, passed, total, runtime }
- done: registerLoggingCallback( "done" ),
-
- // log: { result, actual, expected, message }
- log: registerLoggingCallback( "log" ),
-
- // testStart: { name }
- testStart: registerLoggingCallback( "testStart" ),
-
- // testDone: { name, failed, passed, total, duration }
- testDone: registerLoggingCallback( "testDone" ),
-
- // moduleStart: { name }
- moduleStart: registerLoggingCallback( "moduleStart" ),
-
- // moduleDone: { name, failed, passed, total }
- moduleDone: registerLoggingCallback( "moduleDone" )
-});
-
-if ( typeof document === "undefined" || document.readyState === "complete" ) {
- config.autorun = true;
-}
-
-QUnit.load = function() {
- runLoggingCallbacks( "begin", QUnit, {} );
-
- // Initialize the config, saving the execution queue
- var banner, filter, i, label, len, main, ol, toolbar, userAgent, val,
- urlConfigCheckboxesContainer, urlConfigCheckboxes, moduleFilter,
- numModules = 0,
- moduleFilterHtml = "",
- urlConfigHtml = "",
- oldconfig = extend( {}, config );
-
- QUnit.init();
- extend(config, oldconfig);
-
- config.blocking = false;
-
- len = config.urlConfig.length;
-
- for ( i = 0; i < len; i++ ) {
- val = config.urlConfig[i];
- if ( typeof val === "string" ) {
- val = {
- id: val,
- label: val,
- tooltip: "[no tooltip available]"
- };
- }
- config[ val.id ] = QUnit.urlParams[ val.id ];
- urlConfigHtml += "";
- }
-
- moduleFilterHtml += "";
-
- // `userAgent` initialized at top of scope
- userAgent = id( "qunit-userAgent" );
- if ( userAgent ) {
- userAgent.innerHTML = navigator.userAgent;
- }
-
- // `banner` initialized at top of scope
- banner = id( "qunit-header" );
- if ( banner ) {
- banner.innerHTML = "" + banner.innerHTML + " ";
- }
-
- // `toolbar` initialized at top of scope
- toolbar = id( "qunit-testrunner-toolbar" );
- if ( toolbar ) {
- // `filter` initialized at top of scope
- filter = document.createElement( "input" );
- filter.type = "checkbox";
- filter.id = "qunit-filter-pass";
-
- addEvent( filter, "click", function() {
- var tmp,
- ol = document.getElementById( "qunit-tests" );
-
- if ( filter.checked ) {
- ol.className = ol.className + " hidepass";
- } else {
- tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " ";
- ol.className = tmp.replace( / hidepass /, " " );
- }
- if ( defined.sessionStorage ) {
- if (filter.checked) {
- sessionStorage.setItem( "qunit-filter-passed-tests", "true" );
- } else {
- sessionStorage.removeItem( "qunit-filter-passed-tests" );
- }
- }
- });
-
- if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem( "qunit-filter-passed-tests" ) ) {
- filter.checked = true;
- // `ol` initialized at top of scope
- ol = document.getElementById( "qunit-tests" );
- ol.className = ol.className + " hidepass";
- }
- toolbar.appendChild( filter );
-
- // `label` initialized at top of scope
- label = document.createElement( "label" );
- label.setAttribute( "for", "qunit-filter-pass" );
- label.setAttribute( "title", "Only show tests and assertons that fail. Stored in sessionStorage." );
- label.innerHTML = "Hide passed tests";
- toolbar.appendChild( label );
-
- urlConfigCheckboxesContainer = document.createElement("span");
- urlConfigCheckboxesContainer.innerHTML = urlConfigHtml;
- urlConfigCheckboxes = urlConfigCheckboxesContainer.getElementsByTagName("input");
- // For oldIE support:
- // * Add handlers to the individual elements instead of the container
- // * Use "click" instead of "change"
- // * Fallback from event.target to event.srcElement
- addEvents( urlConfigCheckboxes, "click", function( event ) {
- var params = {},
- target = event.target || event.srcElement;
- params[ target.name ] = target.checked ? true : undefined;
- window.location = QUnit.url( params );
- });
- toolbar.appendChild( urlConfigCheckboxesContainer );
-
- if (numModules > 1) {
- moduleFilter = document.createElement( 'span' );
- moduleFilter.setAttribute( 'id', 'qunit-modulefilter-container' );
- moduleFilter.innerHTML = moduleFilterHtml;
- addEvent( moduleFilter.lastChild, "change", function() {
- var selectBox = moduleFilter.getElementsByTagName("select")[0],
- selectedModule = decodeURIComponent(selectBox.options[selectBox.selectedIndex].value);
-
- window.location = QUnit.url( { module: ( selectedModule === "" ) ? undefined : selectedModule } );
- });
- toolbar.appendChild(moduleFilter);
- }
- }
-
- // `main` initialized at top of scope
- main = id( "qunit-fixture" );
- if ( main ) {
- config.fixture = main.innerHTML;
- }
-
- if ( config.autostart ) {
- QUnit.start();
- }
-};
-
-addEvent( window, "load", QUnit.load );
-
-// `onErrorFnPrev` initialized at top of scope
-// Preserve other handlers
-onErrorFnPrev = window.onerror;
-
-// Cover uncaught exceptions
-// Returning true will surpress the default browser handler,
-// returning false will let it run.
-window.onerror = function ( error, filePath, linerNr ) {
- var ret = false;
- if ( onErrorFnPrev ) {
- ret = onErrorFnPrev( error, filePath, linerNr );
- }
-
- // Treat return value as window.onerror itself does,
- // Only do our handling if not surpressed.
- if ( ret !== true ) {
- if ( QUnit.config.current ) {
- if ( QUnit.config.current.ignoreGlobalErrors ) {
- return true;
- }
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- } else {
- QUnit.test( "global failure", extend( function() {
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- }, { validTest: validTest } ) );
- }
- return false;
- }
-
- return ret;
-};
-
-function done() {
- config.autorun = true;
-
- // Log the last module results
- if ( config.currentModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.currentModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
-
- var i, key,
- banner = id( "qunit-banner" ),
- tests = id( "qunit-tests" ),
- runtime = +new Date() - config.started,
- passed = config.stats.all - config.stats.bad,
- html = [
- "Tests completed in ",
- runtime,
- " milliseconds.
",
- "",
- passed,
- " assertions of ",
- config.stats.all,
- " passed, ",
- config.stats.bad,
- " failed."
- ].join( "" );
-
- if ( banner ) {
- banner.className = ( config.stats.bad ? "qunit-fail" : "qunit-pass" );
- }
-
- if ( tests ) {
- id( "qunit-testresult" ).innerHTML = html;
- }
-
- if ( config.altertitle && typeof document !== "undefined" && document.title ) {
- // show ✖ for good, ✔ for bad suite result in title
- // use escape sequences in case file gets loaded with non-utf-8-charset
- document.title = [
- ( config.stats.bad ? "\u2716" : "\u2714" ),
- document.title.replace( /^[\u2714\u2716] /i, "" )
- ].join( " " );
- }
-
- // clear own sessionStorage items if all tests passed
- if ( config.reorder && defined.sessionStorage && config.stats.bad === 0 ) {
- // `key` & `i` initialized at top of scope
- for ( i = 0; i < sessionStorage.length; i++ ) {
- key = sessionStorage.key( i++ );
- if ( key.indexOf( "qunit-test-" ) === 0 ) {
- sessionStorage.removeItem( key );
- }
- }
- }
-
- // scroll back to top to show results
- if ( window.scrollTo ) {
- window.scrollTo(0, 0);
- }
-
- runLoggingCallbacks( "done", QUnit, {
- failed: config.stats.bad,
- passed: passed,
- total: config.stats.all,
- runtime: runtime
- });
-}
-
-/** @return Boolean: true if this test should be ran */
-function validTest( test ) {
- var include,
- filter = config.filter && config.filter.toLowerCase(),
- module = config.module && config.module.toLowerCase(),
- fullName = (test.module + ": " + test.testName).toLowerCase();
-
- // Internally-generated tests are always valid
- if ( test.callback && test.callback.validTest === validTest ) {
- delete test.callback.validTest;
- return true;
- }
-
- if ( config.testNumber ) {
- return test.testNumber === config.testNumber;
- }
-
- if ( module && ( !test.module || test.module.toLowerCase() !== module ) ) {
- return false;
- }
-
- if ( !filter ) {
- return true;
- }
-
- include = filter.charAt( 0 ) !== "!";
- if ( !include ) {
- filter = filter.slice( 1 );
- }
-
- // If the filter matches, we need to honour include
- if ( fullName.indexOf( filter ) !== -1 ) {
- return include;
- }
-
- // Otherwise, do the opposite
- return !include;
-}
-
-// so far supports only Firefox, Chrome and Opera (buggy), Safari (for real exceptions)
-// Later Safari and IE10 are supposed to support error.stack as well
-// See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack
-function extractStacktrace( e, offset ) {
- offset = offset === undefined ? 3 : offset;
-
- var stack, include, i;
-
- if ( e.stacktrace ) {
- // Opera
- return e.stacktrace.split( "\n" )[ offset + 3 ];
- } else if ( e.stack ) {
- // Firefox, Chrome
- stack = e.stack.split( "\n" );
- if (/^error$/i.test( stack[0] ) ) {
- stack.shift();
- }
- if ( fileName ) {
- include = [];
- for ( i = offset; i < stack.length; i++ ) {
- if ( stack[ i ].indexOf( fileName ) !== -1 ) {
- break;
- }
- include.push( stack[ i ] );
- }
- if ( include.length ) {
- return include.join( "\n" );
- }
- }
- return stack[ offset ];
- } else if ( e.sourceURL ) {
- // Safari, PhantomJS
- // hopefully one day Safari provides actual stacktraces
- // exclude useless self-reference for generated Error objects
- if ( /qunit.js$/.test( e.sourceURL ) ) {
- return;
- }
- // for actual exceptions, this is useful
- return e.sourceURL + ":" + e.line;
- }
-}
-function sourceFromStacktrace( offset ) {
- try {
- throw new Error();
- } catch ( e ) {
- return extractStacktrace( e, offset );
- }
-}
-
-/**
- * Escape text for attribute or text content.
- */
-function escapeText( s ) {
- if ( !s ) {
- return "";
- }
- s = s + "";
- // Both single quotes and double quotes (for attributes)
- return s.replace( /['"<>&]/g, function( s ) {
- switch( s ) {
- case '\'':
- return ''';
- case '"':
- return '"';
- case '<':
- return '<';
- case '>':
- return '>';
- case '&':
- return '&';
- }
- });
-}
-
-function synchronize( callback, last ) {
- config.queue.push( callback );
-
- if ( config.autorun && !config.blocking ) {
- process( last );
- }
-}
-
-function process( last ) {
- function next() {
- process( last );
- }
- var start = new Date().getTime();
- config.depth = config.depth ? config.depth + 1 : 1;
-
- while ( config.queue.length && !config.blocking ) {
- if ( !defined.setTimeout || config.updateRate <= 0 || ( ( new Date().getTime() - start ) < config.updateRate ) ) {
- config.queue.shift()();
- } else {
- window.setTimeout( next, 13 );
- break;
- }
- }
- config.depth--;
- if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) {
- done();
- }
-}
-
-function saveGlobal() {
- config.pollution = [];
-
- if ( config.noglobals ) {
- for ( var key in window ) {
- // in Opera sometimes DOM element ids show up here, ignore them
- if ( !hasOwn.call( window, key ) || /^qunit-test-output/.test( key ) ) {
- continue;
- }
- config.pollution.push( key );
- }
- }
-}
-
-function checkPollution() {
- var newGlobals,
- deletedGlobals,
- old = config.pollution;
-
- saveGlobal();
-
- newGlobals = diff( config.pollution, old );
- if ( newGlobals.length > 0 ) {
- QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join(", ") );
- }
-
- deletedGlobals = diff( old, config.pollution );
- if ( deletedGlobals.length > 0 ) {
- QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join(", ") );
- }
-}
-
-// returns a new Array with the elements that are in a but not in b
-function diff( a, b ) {
- var i, j,
- result = a.slice();
-
- for ( i = 0; i < result.length; i++ ) {
- for ( j = 0; j < b.length; j++ ) {
- if ( result[i] === b[j] ) {
- result.splice( i, 1 );
- i--;
- break;
- }
- }
- }
- return result;
-}
-
-function extend( a, b ) {
- for ( var prop in b ) {
- if ( b[ prop ] === undefined ) {
- delete a[ prop ];
-
- // Avoid "Member not found" error in IE8 caused by setting window.constructor
- } else if ( prop !== "constructor" || a !== window ) {
- a[ prop ] = b[ prop ];
- }
- }
-
- return a;
-}
-
-/**
- * @param {HTMLElement} elem
- * @param {string} type
- * @param {Function} fn
- */
-function addEvent( elem, type, fn ) {
- // Standards-based browsers
- if ( elem.addEventListener ) {
- elem.addEventListener( type, fn, false );
- // IE
- } else {
- elem.attachEvent( "on" + type, fn );
- }
-}
-
-/**
- * @param {Array|NodeList} elems
- * @param {string} type
- * @param {Function} fn
- */
-function addEvents( elems, type, fn ) {
- var i = elems.length;
- while ( i-- ) {
- addEvent( elems[i], type, fn );
- }
-}
-
-function hasClass( elem, name ) {
- return (" " + elem.className + " ").indexOf(" " + name + " ") > -1;
-}
-
-function addClass( elem, name ) {
- if ( !hasClass( elem, name ) ) {
- elem.className += (elem.className ? " " : "") + name;
- }
-}
-
-function removeClass( elem, name ) {
- var set = " " + elem.className + " ";
- // Class name may appear multiple times
- while ( set.indexOf(" " + name + " ") > -1 ) {
- set = set.replace(" " + name + " " , " ");
- }
- // If possible, trim it for prettiness, but not neccecarily
- elem.className = window.jQuery ? jQuery.trim( set ) : ( set.trim ? set.trim() : set );
-}
-
-function id( name ) {
- return !!( typeof document !== "undefined" && document && document.getElementById ) &&
- document.getElementById( name );
-}
-
-function registerLoggingCallback( key ) {
- return function( callback ) {
- config[key].push( callback );
- };
-}
-
-// Supports deprecated method of completely overwriting logging callbacks
-function runLoggingCallbacks( key, scope, args ) {
- var i, callbacks;
- if ( QUnit.hasOwnProperty( key ) ) {
- QUnit[ key ].call(scope, args );
- } else {
- callbacks = config[ key ];
- for ( i = 0; i < callbacks.length; i++ ) {
- callbacks[ i ].call( scope, args );
- }
- }
-}
-
-// Test for equality any JavaScript type.
-// Author: Philippe Rathé
-QUnit.equiv = (function() {
-
- // Call the o related callback with the given arguments.
- function bindCallbacks( o, callbacks, args ) {
- var prop = QUnit.objectType( o );
- if ( prop ) {
- if ( QUnit.objectType( callbacks[ prop ] ) === "function" ) {
- return callbacks[ prop ].apply( callbacks, args );
- } else {
- return callbacks[ prop ]; // or undefined
- }
- }
- }
-
- // the real equiv function
- var innerEquiv,
- // stack to decide between skip/abort functions
- callers = [],
- // stack to avoiding loops from circular referencing
- parents = [],
-
- getProto = Object.getPrototypeOf || function ( obj ) {
- return obj.__proto__;
- },
- callbacks = (function () {
-
- // for string, boolean, number and null
- function useStrictEquality( b, a ) {
- /*jshint eqeqeq:false */
- if ( b instanceof a.constructor || a instanceof b.constructor ) {
- // to catch short annotaion VS 'new' annotation of a
- // declaration
- // e.g. var i = 1;
- // var j = new Number(1);
- return a == b;
- } else {
- return a === b;
- }
- }
-
- return {
- "string": useStrictEquality,
- "boolean": useStrictEquality,
- "number": useStrictEquality,
- "null": useStrictEquality,
- "undefined": useStrictEquality,
-
- "nan": function( b ) {
- return isNaN( b );
- },
-
- "date": function( b, a ) {
- return QUnit.objectType( b ) === "date" && a.valueOf() === b.valueOf();
- },
-
- "regexp": function( b, a ) {
- return QUnit.objectType( b ) === "regexp" &&
- // the regex itself
- a.source === b.source &&
- // and its modifers
- a.global === b.global &&
- // (gmi) ...
- a.ignoreCase === b.ignoreCase &&
- a.multiline === b.multiline &&
- a.sticky === b.sticky;
- },
-
- // - skip when the property is a method of an instance (OOP)
- // - abort otherwise,
- // initial === would have catch identical references anyway
- "function": function() {
- var caller = callers[callers.length - 1];
- return caller !== Object && typeof caller !== "undefined";
- },
-
- "array": function( b, a ) {
- var i, j, len, loop;
-
- // b could be an object literal here
- if ( QUnit.objectType( b ) !== "array" ) {
- return false;
- }
-
- len = a.length;
- if ( len !== b.length ) {
- // safe and faster
- return false;
- }
-
- // track reference to avoid circular references
- parents.push( a );
- for ( i = 0; i < len; i++ ) {
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- loop = true;// dont rewalk array
- }
- }
- if ( !loop && !innerEquiv(a[i], b[i]) ) {
- parents.pop();
- return false;
- }
- }
- parents.pop();
- return true;
- },
-
- "object": function( b, a ) {
- var i, j, loop,
- // Default to true
- eq = true,
- aProperties = [],
- bProperties = [];
-
- // comparing constructors is more strict than using
- // instanceof
- if ( a.constructor !== b.constructor ) {
- // Allow objects with no prototype to be equivalent to
- // objects with Object as their constructor.
- if ( !(( getProto(a) === null && getProto(b) === Object.prototype ) ||
- ( getProto(b) === null && getProto(a) === Object.prototype ) ) ) {
- return false;
- }
- }
-
- // stack constructor before traversing properties
- callers.push( a.constructor );
- // track reference to avoid circular references
- parents.push( a );
-
- for ( i in a ) { // be strict: don't ensures hasOwnProperty
- // and go deep
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- // don't go down the same path twice
- loop = true;
- }
- }
- aProperties.push(i); // collect a's properties
-
- if (!loop && !innerEquiv( a[i], b[i] ) ) {
- eq = false;
- break;
- }
- }
-
- callers.pop(); // unstack, we are done
- parents.pop();
-
- for ( i in b ) {
- bProperties.push( i ); // collect b's properties
- }
-
- // Ensures identical properties name
- return eq && innerEquiv( aProperties.sort(), bProperties.sort() );
- }
- };
- }());
-
- innerEquiv = function() { // can take multiple arguments
- var args = [].slice.apply( arguments );
- if ( args.length < 2 ) {
- return true; // end transition
- }
-
- return (function( a, b ) {
- if ( a === b ) {
- return true; // catch the most you can
- } else if ( a === null || b === null || typeof a === "undefined" ||
- typeof b === "undefined" ||
- QUnit.objectType(a) !== QUnit.objectType(b) ) {
- return false; // don't lose time with error prone cases
- } else {
- return bindCallbacks(a, callbacks, [ b, a ]);
- }
-
- // apply transition with (1..n) arguments
- }( args[0], args[1] ) && arguments.callee.apply( this, args.splice(1, args.length - 1 )) );
- };
-
- return innerEquiv;
-}());
-
-/**
- * jsDump Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com |
- * http://flesler.blogspot.com Licensed under BSD
- * (http://www.opensource.org/licenses/bsd-license.php) Date: 5/15/2008
- *
- * @projectDescription Advanced and extensible data dumping for Javascript.
- * @version 1.0.0
- * @author Ariel Flesler
- * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html}
- */
-QUnit.jsDump = (function() {
- function quote( str ) {
- return '"' + str.toString().replace( /"/g, '\\"' ) + '"';
- }
- function literal( o ) {
- return o + "";
- }
- function join( pre, arr, post ) {
- var s = jsDump.separator(),
- base = jsDump.indent(),
- inner = jsDump.indent(1);
- if ( arr.join ) {
- arr = arr.join( "," + s + inner );
- }
- if ( !arr ) {
- return pre + post;
- }
- return [ pre, inner + arr, base + post ].join(s);
- }
- function array( arr, stack ) {
- var i = arr.length, ret = new Array(i);
- this.up();
- while ( i-- ) {
- ret[i] = this.parse( arr[i] , undefined , stack);
- }
- this.down();
- return join( "[", ret, "]" );
- }
-
- var reName = /^function (\w+)/,
- jsDump = {
- // type is used mostly internally, you can fix a (custom)type in advance
- parse: function( obj, type, stack ) {
- stack = stack || [ ];
- var inStack, res,
- parser = this.parsers[ type || this.typeOf(obj) ];
-
- type = typeof parser;
- inStack = inArray( obj, stack );
-
- if ( inStack !== -1 ) {
- return "recursion(" + (inStack - stack.length) + ")";
- }
- if ( type === "function" ) {
- stack.push( obj );
- res = parser.call( this, obj, stack );
- stack.pop();
- return res;
- }
- return ( type === "string" ) ? parser : this.parsers.error;
- },
- typeOf: function( obj ) {
- var type;
- if ( obj === null ) {
- type = "null";
- } else if ( typeof obj === "undefined" ) {
- type = "undefined";
- } else if ( QUnit.is( "regexp", obj) ) {
- type = "regexp";
- } else if ( QUnit.is( "date", obj) ) {
- type = "date";
- } else if ( QUnit.is( "function", obj) ) {
- type = "function";
- } else if ( typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined" ) {
- type = "window";
- } else if ( obj.nodeType === 9 ) {
- type = "document";
- } else if ( obj.nodeType ) {
- type = "node";
- } else if (
- // native arrays
- toString.call( obj ) === "[object Array]" ||
- // NodeList objects
- ( typeof obj.length === "number" && typeof obj.item !== "undefined" && ( obj.length ? obj.item(0) === obj[0] : ( obj.item( 0 ) === null && typeof obj[0] === "undefined" ) ) )
- ) {
- type = "array";
- } else if ( obj.constructor === Error.prototype.constructor ) {
- type = "error";
- } else {
- type = typeof obj;
- }
- return type;
- },
- separator: function() {
- return this.multiline ? this.HTML ? "
" : "\n" : this.HTML ? " " : " ";
- },
- // extra can be a number, shortcut for increasing-calling-decreasing
- indent: function( extra ) {
- if ( !this.multiline ) {
- return "";
- }
- var chr = this.indentChar;
- if ( this.HTML ) {
- chr = chr.replace( /\t/g, " " ).replace( / /g, " " );
- }
- return new Array( this._depth_ + (extra||0) ).join(chr);
- },
- up: function( a ) {
- this._depth_ += a || 1;
- },
- down: function( a ) {
- this._depth_ -= a || 1;
- },
- setParser: function( name, parser ) {
- this.parsers[name] = parser;
- },
- // The next 3 are exposed so you can use them
- quote: quote,
- literal: literal,
- join: join,
- //
- _depth_: 1,
- // This is the list of parsers, to modify them, use jsDump.setParser
- parsers: {
- window: "[Window]",
- document: "[Document]",
- error: function(error) {
- return "Error(\"" + error.message + "\")";
- },
- unknown: "[Unknown]",
- "null": "null",
- "undefined": "undefined",
- "function": function( fn ) {
- var ret = "function",
- // functions never have name in IE
- name = "name" in fn ? fn.name : (reName.exec(fn) || [])[1];
-
- if ( name ) {
- ret += " " + name;
- }
- ret += "( ";
-
- ret = [ ret, QUnit.jsDump.parse( fn, "functionArgs" ), "){" ].join( "" );
- return join( ret, QUnit.jsDump.parse(fn,"functionCode" ), "}" );
- },
- array: array,
- nodelist: array,
- "arguments": array,
- object: function( map, stack ) {
- var ret = [ ], keys, key, val, i;
- QUnit.jsDump.up();
- keys = [];
- for ( key in map ) {
- keys.push( key );
- }
- keys.sort();
- for ( i = 0; i < keys.length; i++ ) {
- key = keys[ i ];
- val = map[ key ];
- ret.push( QUnit.jsDump.parse( key, "key" ) + ": " + QUnit.jsDump.parse( val, undefined, stack ) );
- }
- QUnit.jsDump.down();
- return join( "{", ret, "}" );
- },
- node: function( node ) {
- var len, i, val,
- open = QUnit.jsDump.HTML ? "<" : "<",
- close = QUnit.jsDump.HTML ? ">" : ">",
- tag = node.nodeName.toLowerCase(),
- ret = open + tag,
- attrs = node.attributes;
-
- if ( attrs ) {
- for ( i = 0, len = attrs.length; i < len; i++ ) {
- val = attrs[i].nodeValue;
- // IE6 includes all attributes in .attributes, even ones not explicitly set.
- // Those have values like undefined, null, 0, false, "" or "inherit".
- if ( val && val !== "inherit" ) {
- ret += " " + attrs[i].nodeName + "=" + QUnit.jsDump.parse( val, "attribute" );
- }
- }
- }
- ret += close;
-
- // Show content of TextNode or CDATASection
- if ( node.nodeType === 3 || node.nodeType === 4 ) {
- ret += node.nodeValue;
- }
-
- return ret + open + "/" + tag + close;
- },
- // function calls it internally, it's the arguments part of the function
- functionArgs: function( fn ) {
- var args,
- l = fn.length;
-
- if ( !l ) {
- return "";
- }
-
- args = new Array(l);
- while ( l-- ) {
- // 97 is 'a'
- args[l] = String.fromCharCode(97+l);
- }
- return " " + args.join( ", " ) + " ";
- },
- // object calls it internally, the key part of an item in a map
- key: quote,
- // function calls it internally, it's the content of the function
- functionCode: "[code]",
- // node calls it internally, it's an html attribute value
- attribute: quote,
- string: quote,
- date: quote,
- regexp: literal,
- number: literal,
- "boolean": literal
- },
- // if true, entities are escaped ( <, >, \t, space and \n )
- HTML: false,
- // indentation unit
- indentChar: " ",
- // if true, items in a collection, are separated by a \n, else just a space.
- multiline: true
- };
-
- return jsDump;
-}());
-
-// from jquery.js
-function inArray( elem, array ) {
- if ( array.indexOf ) {
- return array.indexOf( elem );
- }
-
- for ( var i = 0, length = array.length; i < length; i++ ) {
- if ( array[ i ] === elem ) {
- return i;
- }
- }
-
- return -1;
-}
-
-/*
- * Javascript Diff Algorithm
- * By John Resig (http://ejohn.org/)
- * Modified by Chu Alan "sprite"
- *
- * Released under the MIT license.
- *
- * More Info:
- * http://ejohn.org/projects/javascript-diff-algorithm/
- *
- * Usage: QUnit.diff(expected, actual)
- *
- * QUnit.diff( "the quick brown fox jumped over", "the quick fox jumps over" ) == "the quick brown fox jumped jumps over"
- */
-QUnit.diff = (function() {
- /*jshint eqeqeq:false, eqnull:true */
- function diff( o, n ) {
- var i,
- ns = {},
- os = {};
-
- for ( i = 0; i < n.length; i++ ) {
- if ( !hasOwn.call( ns, n[i] ) ) {
- ns[ n[i] ] = {
- rows: [],
- o: null
- };
- }
- ns[ n[i] ].rows.push( i );
- }
-
- for ( i = 0; i < o.length; i++ ) {
- if ( !hasOwn.call( os, o[i] ) ) {
- os[ o[i] ] = {
- rows: [],
- n: null
- };
- }
- os[ o[i] ].rows.push( i );
- }
-
- for ( i in ns ) {
- if ( !hasOwn.call( ns, i ) ) {
- continue;
- }
- if ( ns[i].rows.length === 1 && hasOwn.call( os, i ) && os[i].rows.length === 1 ) {
- n[ ns[i].rows[0] ] = {
- text: n[ ns[i].rows[0] ],
- row: os[i].rows[0]
- };
- o[ os[i].rows[0] ] = {
- text: o[ os[i].rows[0] ],
- row: ns[i].rows[0]
- };
- }
- }
-
- for ( i = 0; i < n.length - 1; i++ ) {
- if ( n[i].text != null && n[ i + 1 ].text == null && n[i].row + 1 < o.length && o[ n[i].row + 1 ].text == null &&
- n[ i + 1 ] == o[ n[i].row + 1 ] ) {
-
- n[ i + 1 ] = {
- text: n[ i + 1 ],
- row: n[i].row + 1
- };
- o[ n[i].row + 1 ] = {
- text: o[ n[i].row + 1 ],
- row: i + 1
- };
- }
- }
-
- for ( i = n.length - 1; i > 0; i-- ) {
- if ( n[i].text != null && n[ i - 1 ].text == null && n[i].row > 0 && o[ n[i].row - 1 ].text == null &&
- n[ i - 1 ] == o[ n[i].row - 1 ]) {
-
- n[ i - 1 ] = {
- text: n[ i - 1 ],
- row: n[i].row - 1
- };
- o[ n[i].row - 1 ] = {
- text: o[ n[i].row - 1 ],
- row: i - 1
- };
- }
- }
-
- return {
- o: o,
- n: n
- };
- }
-
- return function( o, n ) {
- o = o.replace( /\s+$/, "" );
- n = n.replace( /\s+$/, "" );
-
- var i, pre,
- str = "",
- out = diff( o === "" ? [] : o.split(/\s+/), n === "" ? [] : n.split(/\s+/) ),
- oSpace = o.match(/\s+/g),
- nSpace = n.match(/\s+/g);
-
- if ( oSpace == null ) {
- oSpace = [ " " ];
- }
- else {
- oSpace.push( " " );
- }
-
- if ( nSpace == null ) {
- nSpace = [ " " ];
- }
- else {
- nSpace.push( " " );
- }
-
- if ( out.n.length === 0 ) {
- for ( i = 0; i < out.o.length; i++ ) {
- str += "" + out.o[i] + oSpace[i] + "";
- }
- }
- else {
- if ( out.n[0].text == null ) {
- for ( n = 0; n < out.o.length && out.o[n].text == null; n++ ) {
- str += "" + out.o[n] + oSpace[n] + "";
- }
- }
-
- for ( i = 0; i < out.n.length; i++ ) {
- if (out.n[i].text == null) {
- str += "" + out.n[i] + nSpace[i] + "";
- }
- else {
- // `pre` initialized at top of scope
- pre = "";
-
- for ( n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++ ) {
- pre += "" + out.o[n] + oSpace[n] + "";
- }
- str += " " + out.n[i].text + nSpace[i] + pre;
- }
- }
- }
-
- return str;
- };
-}());
-
-// for CommonJS enviroments, export everything
-if ( typeof exports !== "undefined" ) {
- extend( exports, QUnit );
-}
-
-// get at whatever the global object is, like window in browsers
-}( (function() {return this;}.call()) ));
diff --git a/test/lib/require.js b/test/lib/require.js
deleted file mode 100644
index 987f865..0000000
--- a/test/lib/require.js
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- RequireJS 2.1.5 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.
- Available via the MIT or new BSD license.
- see: http://github.com/jrburke/requirejs for details
-*/
-var requirejs,require,define;
-(function(aa){function I(b){return"[object Function]"===L.call(b)}function J(b){return"[object Array]"===L.call(b)}function y(b,c){if(b){var d;for(d=0;dthis.depCount&&!this.defined){if(I(n)){if(this.events.error)try{e=i.execCb(c,n,b,e)}catch(d){a=d}else e=i.execCb(c,n,b,e);this.map.isDefine&&((b=this.module)&&void 0!==b.exports&&b.exports!==this.exports?e=b.exports:void 0===e&&this.usingExports&&(e=this.exports));if(a)return a.requireMap=this.map,a.requireModules=[this.map.id],a.requireType="define",v(this.error=
-a)}else e=n;this.exports=e;if(this.map.isDefine&&!this.ignore&&(q[c]=e,l.onResourceLoad))l.onResourceLoad(i,this.map,this.depMaps);x(c);this.defined=!0}this.defining=!1;this.defined&&!this.defineEmitted&&(this.defineEmitted=!0,this.emit("defined",this.exports),this.defineEmitComplete=!0)}}else this.fetch()}},callPlugin:function(){var a=this.map,b=a.id,d=j(a.prefix);this.depMaps.push(d);t(d,"defined",u(this,function(e){var n,d;d=this.map.name;var g=this.map.parentMap?this.map.parentMap.name:null,h=
-i.makeRequire(a.parentMap,{enableBuildCallback:!0});if(this.map.unnormalized){if(e.normalize&&(d=e.normalize(d,function(a){return c(a,g,!0)})||""),e=j(a.prefix+"!"+d,this.map.parentMap),t(e,"defined",u(this,function(a){this.init([],function(){return a},null,{enabled:!0,ignore:!0})})),d=m(p,e.id)){this.depMaps.push(e);if(this.events.error)d.on("error",u(this,function(a){this.emit("error",a)}));d.enable()}}else n=u(this,function(a){this.init([],function(){return a},null,{enabled:!0})}),n.error=u(this,
-function(a){this.inited=!0;this.error=a;a.requireModules=[b];G(p,function(a){0===a.map.id.indexOf(b+"_unnormalized")&&x(a.map.id)});v(a)}),n.fromText=u(this,function(e,c){var d=a.name,g=j(d),C=O;c&&(e=c);C&&(O=!1);r(g);s(k.config,b)&&(k.config[d]=k.config[b]);try{l.exec(e)}catch(ca){return v(B("fromtexteval","fromText eval for "+b+" failed: "+ca,ca,[b]))}C&&(O=!0);this.depMaps.push(g);i.completeLoad(d);h([d],n)}),e.load(a.name,h,n,k)}));i.enable(d,this);this.pluginMaps[d.id]=d},enable:function(){V[this.map.id]=
-this;this.enabling=this.enabled=!0;y(this.depMaps,u(this,function(a,b){var c,e;if("string"===typeof a){a=j(a,this.map.isDefine?this.map:this.map.parentMap,!1,!this.skipMap);this.depMaps[b]=a;if(c=m(N,a.id)){this.depExports[b]=c(this);return}this.depCount+=1;t(a,"defined",u(this,function(a){this.defineDep(b,a);this.check()}));this.errback&&t(a,"error",this.errback)}c=a.id;e=p[c];!s(N,c)&&(e&&!e.enabled)&&i.enable(a,this)}));G(this.pluginMaps,u(this,function(a){var b=m(p,a.id);b&&!b.enabled&&i.enable(a,
-this)}));this.enabling=!1;this.check()},on:function(a,b){var c=this.events[a];c||(c=this.events[a]=[]);c.push(b)},emit:function(a,b){y(this.events[a],function(a){a(b)});"error"===a&&delete this.events[a]}};i={config:k,contextName:b,registry:p,defined:q,urlFetched:U,defQueue:H,Module:Z,makeModuleMap:j,nextTick:l.nextTick,onError:v,configure:function(a){a.baseUrl&&"/"!==a.baseUrl.charAt(a.baseUrl.length-1)&&(a.baseUrl+="/");var b=k.pkgs,c=k.shim,e={paths:!0,config:!0,map:!0};G(a,function(a,b){e[b]?
-"map"===b?(k.map||(k.map={}),R(k[b],a,!0,!0)):R(k[b],a,!0):k[b]=a});a.shim&&(G(a.shim,function(a,b){J(a)&&(a={deps:a});if((a.exports||a.init)&&!a.exportsFn)a.exportsFn=i.makeShimExports(a);c[b]=a}),k.shim=c);a.packages&&(y(a.packages,function(a){a="string"===typeof a?{name:a}:a;b[a.name]={name:a.name,location:a.location||a.name,main:(a.main||"main").replace(ja,"").replace(ea,"")}}),k.pkgs=b);G(p,function(a,b){!a.inited&&!a.map.unnormalized&&(a.map=j(b))});if(a.deps||a.callback)i.require(a.deps||[],
-a.callback)},makeShimExports:function(a){return function(){var b;a.init&&(b=a.init.apply(aa,arguments));return b||a.exports&&ba(a.exports)}},makeRequire:function(a,f){function d(e,c,h){var g,k;f.enableBuildCallback&&(c&&I(c))&&(c.__requireJsBuild=!0);if("string"===typeof e){if(I(c))return v(B("requireargs","Invalid require call"),h);if(a&&s(N,e))return N[e](p[a.id]);if(l.get)return l.get(i,e,a,d);g=j(e,a,!1,!0);g=g.id;return!s(q,g)?v(B("notloaded",'Module name "'+g+'" has not been loaded yet for context: '+
-b+(a?"":". Use require([])"))):q[g]}L();i.nextTick(function(){L();k=r(j(null,a));k.skipMap=f.skipMap;k.init(e,c,h,{enabled:!0});D()});return d}f=f||{};R(d,{isBrowser:A,toUrl:function(b){var d,f=b.lastIndexOf("."),g=b.split("/")[0];if(-1!==f&&(!("."===g||".."===g)||1h.attachEvent.toString().indexOf("[native code"))&&!Y?(O=!0,h.attachEvent("onreadystatechange",b.onScriptLoad)):(h.addEventListener("load",b.onScriptLoad,!1),h.addEventListener("error",b.onScriptError,!1)),h.src=d,K=h,D?x.insertBefore(h,D):x.appendChild(h),K=null,h;if(da)try{importScripts(d),b.completeLoad(c)}catch(j){b.onError(B("importscripts","importScripts failed for "+c+" at "+d,j,[c]))}};A&&M(document.getElementsByTagName("script"),function(b){x||(x=
-b.parentNode);if(t=b.getAttribute("data-main"))return r.baseUrl||(E=t.split("/"),Q=E.pop(),fa=E.length?E.join("/")+"/":"./",r.baseUrl=fa,t=Q),t=t.replace(ea,""),r.deps=r.deps?r.deps.concat(t):[t],!0});define=function(b,c,d){var l,h;"string"!==typeof b&&(d=c,c=b,b=null);J(c)||(d=c,c=[]);!c.length&&I(d)&&d.length&&(d.toString().replace(la,"").replace(ma,function(b,d){c.push(d)}),c=(1===d.length?["require"]:["require","exports","module"]).concat(c));if(O){if(!(l=K))P&&"interactive"===P.readyState||M(document.getElementsByTagName("script"),
-function(b){if("interactive"===b.readyState)return P=b}),l=P;l&&(b||(b=l.getAttribute("data-requiremodule")),h=F[l.getAttribute("data-requirecontext")])}(h?h.defQueue:T).push([b,c,d])};define.amd={jQuery:!0};l.exec=function(b){return eval(b)};l(r)}})(this);
diff --git a/test/lib/resemble.js b/test/lib/resemble.js
new file mode 100644
index 0000000..1cb8c29
--- /dev/null
+++ b/test/lib/resemble.js
@@ -0,0 +1,535 @@
+/*
+Author: James Cryer
+Company: Huddle
+Last updated date: 21 Feb 2013
+URL: https://github.com/Huddle/Resemble.js
+*/
+
+(function(_this){
+ 'use strict';
+
+ _this['resemble'] = function( fileData ){
+
+ var data = {};
+ var images = [];
+ var updateCallbackArray = [];
+
+ var tolerance = { // between 0 and 255
+ red: 16,
+ green: 16,
+ blue: 16,
+ minBrightness: 16,
+ maxBrightness: 240
+ };
+
+ var ignoreAntialiasing = false;
+ var ignoreColors = false;
+
+ function triggerDataUpdate(){
+ var len = updateCallbackArray.length;
+ var i;
+ for(i=0;i tolerance.maxBrightness;
+ }
+
+ function getHue(r,g,b){
+
+ r = r / 255;
+ g = g / 255;
+ b = b / 255;
+ var max = Math.max(r, g, b), min = Math.min(r, g, b);
+ var h;
+ var d;
+
+ if (max == min){
+ h = 0; // achromatic
+ } else{
+ d = max - min;
+ switch(max){
+ case r: h = (g - b) / d + (g < b ? 6 : 0); break;
+ case g: h = (b - r) / d + 2; break;
+ case b: h = (r - g) / d + 4; break;
+ }
+ h /= 6;
+ }
+
+ return h;
+ }
+
+ function isAntialiased(sourcePix, data, cacheSet, verticalPos, horizontalPos, width){
+ var offset;
+ var targetPix;
+ var distance = 1;
+ var i;
+ var j;
+ var hasHighContrastSibling = 0;
+ var hasSiblingWithDifferentHue = 0;
+ var hasEquivilantSibling = 0;
+
+ addHueInfo(sourcePix);
+
+ for (i = distance*-1; i <= distance; i++){
+ for (j = distance*-1; j <= distance; j++){
+
+ if(i===0 && j===0){
+ // ignore source pixel
+ } else {
+
+ offset = ((verticalPos+j)*width + (horizontalPos+i)) * 4;
+ targetPix = getPixelInfo(data, offset, cacheSet);
+
+ if(targetPix === null){
+ continue;
+ }
+
+ addBrightnessInfo(targetPix);
+ addHueInfo(targetPix);
+
+ if( isContrasting(sourcePix, targetPix) ){
+ hasHighContrastSibling++;
+ }
+
+ if( isRGBSame(sourcePix,targetPix) ){
+ hasEquivilantSibling++;
+ }
+
+ if( Math.abs(targetPix.h - sourcePix.h) > 0.3 ){
+ hasSiblingWithDifferentHue++;
+ }
+
+ if( hasSiblingWithDifferentHue > 1 || hasHighContrastSibling > 1){
+ return true;
+ }
+ }
+ }
+ }
+
+ if(hasEquivilantSibling < 2){
+ return true;
+ }
+
+ return false;
+ }
+
+ function errorPixel(px, offset){
+ px[offset] = 255; //r
+ px[offset + 1] = 0; //g
+ px[offset + 2] = 255; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyPixel(px, offset, data){
+ px[offset] = data.r; //r
+ px[offset + 1] = data.g; //g
+ px[offset + 2] = data.b; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyGrayScalePixel(px, offset, data){
+ px[offset] = data.brightness; //r
+ px[offset + 1] = data.brightness; //g
+ px[offset + 2] = data.brightness; //b
+ px[offset + 3] = 255; //a
+ }
+
+
+ function getPixelInfo(data, offset, cacheSet){
+ var r;
+ var g;
+ var b;
+ var d;
+
+ if(typeof data[offset] !== 'undefined'){
+ r = data[offset];
+ g = data[offset+1];
+ b = data[offset+2];
+ d = {
+ r: r,
+ g: g,
+ b: b
+ };
+
+ return d;
+ } else {
+ return null;
+ }
+ }
+
+ function addBrightnessInfo(data){
+ data.brightness = getBrightness(data.r,data.g,data.b); // 'corrected' lightness
+ }
+
+ function addHueInfo(data){
+ data.h = getHue(data.r,data.g,data.b);
+ }
+
+ function analyseImages(img1, img2, width, height){
+
+ var hiddenCanvas = document.createElement('canvas');
+
+ var data1 = img1.data;
+ var data2 = img2.data;
+
+ hiddenCanvas.width = width;
+ hiddenCanvas.height = height;
+
+ var context = hiddenCanvas.getContext('2d');
+ var imgd = context.createImageData(width,height);
+ var targetPix = imgd.data;
+
+ var mismatchCount = 0;
+
+ var time = Date.now();
+
+ var skip;
+
+ if( (width > 1200 || height > 1200) && ignoreAntialiasing){
+ skip = 6;
+ }
+
+ loop(height, width, function(verticalPos, horizontalPos){
+
+ if(skip){ // only skip if the image isn't small
+ if(verticalPos % skip === 0 || horizontalPos % skip === 0){
+ return;
+ }
+ }
+
+ var offset = (verticalPos*width + horizontalPos) * 4;
+ var pixel1 = getPixelInfo(data1, offset, 1);
+ var pixel2 = getPixelInfo(data2, offset, 2);
+
+ if(pixel1 === null || pixel2 === null){
+ return;
+ }
+
+ if (ignoreColors){
+
+ addBrightnessInfo(pixel1);
+ addBrightnessInfo(pixel2);
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ return;
+ }
+
+ if( isRGBSimilar(pixel1, pixel2) ){
+ copyPixel(targetPix, offset, pixel2);
+
+ } else if( ignoreAntialiasing && (
+ addBrightnessInfo(pixel1), // jit pixel info augmentation looks a little weird, sorry.
+ addBrightnessInfo(pixel2),
+ isAntialiased(pixel1, data1, 1, verticalPos, horizontalPos, width) ||
+ isAntialiased(pixel2, data2, 2, verticalPos, horizontalPos, width)
+ )){
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+
+ });
+
+ data.misMatchPercentage = (mismatchCount / (height*width) * 100).toFixed(2);
+ data.analysisTime = Date.now() - time;
+
+ data.getImageDataUrl = function(text){
+ var barHeight = 0;
+
+ if(text){
+ barHeight = addLabel(text,context,hiddenCanvas);
+ }
+
+ context.putImageData(imgd, 0, barHeight);
+
+ return hiddenCanvas.toDataURL("image/png");
+ };
+ }
+
+ function addLabel(text, context, hiddenCanvas){
+ var textPadding = 2;
+
+ context.font = '12px sans-serif';
+
+ var textWidth = context.measureText(text).width + textPadding*2;
+ var barHeight = 22;
+
+ if(textWidth > hiddenCanvas.width){
+ hiddenCanvas.width = textWidth;
+ }
+
+ hiddenCanvas.height += barHeight;
+
+ context.fillStyle = "#666";
+ context.fillRect(0,0,hiddenCanvas.width,barHeight -4);
+ context.fillStyle = "#fff";
+ context.fillRect(0,barHeight -4,hiddenCanvas.width, 4);
+
+ context.fillStyle = "#fff";
+ context.textBaseline = "top";
+ context.font = '12px sans-serif';
+ context.fillText(text, textPadding, 1);
+
+ return barHeight;
+ }
+
+ function normalise(img, w, h){
+ var c;
+ var context;
+
+ if(img.height < h || img.width < w){
+ c = document.createElement('canvas');
+ c.width = w;
+ c.height = h;
+ context = c.getContext('2d');
+ context.putImageData(img, 0, 0);
+ return context.getImageData(0, 0, w, h);
+ }
+
+ return img;
+ }
+
+ function compare(one, two){
+
+ function onceWeHaveBoth(){
+ var width;
+ var height;
+ if(images.length === 2){
+ width = images[0].width > images[1].width ? images[0].width : images[1].width;
+ height = images[0].height > images[1].height ? images[0].height : images[1].height;
+
+ if( (images[0].width === images[1].width) && (images[0].height === images[1].height) ){
+ data.isSameDimensions = true;
+ } else {
+ data.isSameDimensions = false;
+ }
+
+ analyseImages( normalise(images[0],width, height), normalise(images[1],width, height), width, height);
+
+ triggerDataUpdate();
+ }
+ }
+
+ images = [];
+ loadImageData(one, onceWeHaveBoth);
+ loadImageData(two, onceWeHaveBoth);
+ }
+
+ function getCompareApi(param){
+
+ var secondFileData,
+ hasMethod = typeof param === 'function';
+
+ if( !hasMethod ){
+ // assume it's file data
+ secondFileData = param;
+ }
+
+ var self = {
+ ignoreNothing: function(){
+
+ tolerance.red = 16;
+ tolerance.green = 16;
+ tolerance.blue = 16;
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreAntialiasing: function(){
+
+ tolerance.red = 32;
+ tolerance.green = 32;
+ tolerance.blue = 32;
+ tolerance.minBrightness = 64;
+ tolerance.maxBrightness = 96;
+
+ ignoreAntialiasing = true;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreColors: function(){
+
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = true;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ onComplete: function( callback ){
+
+ updateCallbackArray.push(callback);
+
+ var wrapper = function(){
+ compare(fileData, secondFileData);
+ };
+
+ wrapper();
+
+ return getCompareApi(wrapper);
+ }
+ };
+
+ return self;
+ }
+
+ return {
+ onComplete: function( callback ){
+ updateCallbackArray.push(callback);
+ loadImageData(fileData, function(imageData, width, height){
+ parseImage(imageData.data, width, height);
+ });
+ },
+ compareTo: function(secondFileData){
+ return getCompareApi(secondFileData);
+ }
+ };
+
+ };
+}(this));
\ No newline at end of file
diff --git a/test/testsuite.js b/test/testsuite.js
deleted file mode 100644
index b486acb..0000000
--- a/test/testsuite.js
+++ /dev/null
@@ -1,36 +0,0 @@
-requirejs.config({
- baseUrl: '/test/unit/'
-});
-
-define(function(require) {
- var testModules = [
- 'Pixi',
- 'Point',
- 'Rectangle',
- 'DisplayObject',
- 'DisplayObjectContainer',
- 'Sprite',
- 'MovieClip',
- 'InteractionManager',
- 'Stage',
- 'utils/Utils',
- 'utils/EventTarget',
- 'utils/Matrix',
- 'utils/Detector',
- 'renderers/WebGLShaders',
- 'renderers/WebGLRenderer',
- 'renderers/WebGLBatch',
- 'renderers/CanvasRenderer',
- 'extras/Strip',
- 'extras/Rope',
- 'textures/BaseTexture',
- 'textures/Texture',
- 'loaders/SpriteSheetLoader',
- 'loaders/AssetLoader'
- ];
-
- // Resolve all testModules and then start the Test Runner.
- require(testModules, function() {
- QUnit.start();
- });
-});
\ No newline at end of file
diff --git a/test/textures/SpriteSheet-Aliens.png b/test/textures/SpriteSheet-Aliens.png
new file mode 100644
index 0000000..210acb1
--- /dev/null
+++ b/test/textures/SpriteSheet-Aliens.png
Binary files differ
diff --git a/test/textures/SpriteSheet-Explosion.png b/test/textures/SpriteSheet-Explosion.png
new file mode 100755
index 0000000..79e1a69
--- /dev/null
+++ b/test/textures/SpriteSheet-Explosion.png
Binary files differ
diff --git a/test/textures/bunny.png b/test/textures/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/textures/bunny.png
Binary files differ
diff --git a/test/unit/DisplayObject.js b/test/unit/DisplayObject.js
deleted file mode 100644
index 5e7e72f..0000000
--- a/test/unit/DisplayObject.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObject');
-});
diff --git a/test/unit/DisplayObjectContainer.js b/test/unit/DisplayObjectContainer.js
deleted file mode 100644
index b323959..0000000
--- a/test/unit/DisplayObjectContainer.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObjectContainer');
-});
diff --git a/test/unit/InteractionManager.js b/test/unit/InteractionManager.js
deleted file mode 100644
index e751f52..0000000
--- a/test/unit/InteractionManager.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('InteractionManager');
-});
diff --git a/test/unit/MovieClip.js b/test/unit/MovieClip.js
deleted file mode 100644
index 37d9446..0000000
--- a/test/unit/MovieClip.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('MovieClip');
-});
diff --git a/test/unit/Pixi.js b/test/unit/Pixi.js
deleted file mode 100644
index 36eee73..0000000
--- a/test/unit/Pixi.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Pixi');
-});
diff --git a/test/unit/Point.js b/test/unit/Point.js
deleted file mode 100644
index 983ff6e..0000000
--- a/test/unit/Point.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Point');
-});
diff --git a/test/unit/Rectangle.js b/test/unit/Rectangle.js
deleted file mode 100644
index 3b439ba..0000000
--- a/test/unit/Rectangle.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Rectangle');
-});
diff --git a/test/unit/Sprite.js b/test/unit/Sprite.js
deleted file mode 100644
index ed4f596..0000000
--- a/test/unit/Sprite.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Sprite');
-});
diff --git a/test/unit/Stage.js b/test/unit/Stage.js
deleted file mode 100644
index 2d70291..0000000
--- a/test/unit/Stage.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Stage');
-});
diff --git a/test/unit/extras/Rope.js b/test/unit/extras/Rope.js
deleted file mode 100644
index 5606f14..0000000
--- a/test/unit/extras/Rope.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Rope');
-});
diff --git a/test/unit/extras/Strip.js b/test/unit/extras/Strip.js
deleted file mode 100644
index 0134d3a..0000000
--- a/test/unit/extras/Strip.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Strip');
-});
diff --git a/test/unit/loaders/AssetLoader.js b/test/unit/loaders/AssetLoader.js
deleted file mode 100644
index 13b8443..0000000
--- a/test/unit/loaders/AssetLoader.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('AssetLoader');
-});
diff --git a/test/unit/loaders/SpriteSheetLoader.js b/test/unit/loaders/SpriteSheetLoader.js
deleted file mode 100644
index 8bf0cb2..0000000
--- a/test/unit/loaders/SpriteSheetLoader.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('SpriteSheetLoader');
-});
diff --git a/test/unit/pixi/InteractionManager.js b/test/unit/pixi/InteractionManager.js
new file mode 100644
index 0000000..ed3001f
--- /dev/null
+++ b/test/unit/pixi/InteractionManager.js
@@ -0,0 +1,10 @@
+describe('pixi/InteractionManager', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var InteractionManager = PIXI.InteractionManager;
+
+ it('Module exists', function () {
+ expect(InteractionManager).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/Pixi.js b/test/unit/pixi/Pixi.js
new file mode 100644
index 0000000..27debc1
--- /dev/null
+++ b/test/unit/pixi/Pixi.js
@@ -0,0 +1,9 @@
+describe('pixi/Pixi', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+
+ it('Module exists', function () {
+ expect(global).to.have.property('PIXI').and.to.be.an('object');
+ });
+});
diff --git a/test/unit/pixi/core/Circle.js b/test/unit/pixi/core/Circle.js
new file mode 100644
index 0000000..93a4456
--- /dev/null
+++ b/test/unit/pixi/core/Circle.js
@@ -0,0 +1,22 @@
+describe('pixi/core/Circle', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Circle = PIXI.Circle;
+
+ it('Module exists', function () {
+ expect(Circle).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Circle();
+
+ expect(obj).to.be.an.instanceof(Circle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', 0);
+ expect(obj).to.have.property('y', 0);
+ expect(obj).to.have.property('radius', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Ellipse.js b/test/unit/pixi/core/Ellipse.js
new file mode 100644
index 0000000..026b56f
--- /dev/null
+++ b/test/unit/pixi/core/Ellipse.js
@@ -0,0 +1,24 @@
+describe('pixi/core/Ellipse', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Ellipse = PIXI.Ellipse;
+
+ it('Module exists', function () {
+ expect(Ellipse).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Ellipse();
+
+ expect(obj).to.be.an.instanceof(Ellipse);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+ expect(obj).to.respondTo('getBounds');
+
+ expect(obj).to.have.property('x', 0);
+ expect(obj).to.have.property('y', 0);
+ expect(obj).to.have.property('width', 0);
+ expect(obj).to.have.property('height', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Matrix.js b/test/unit/pixi/core/Matrix.js
new file mode 100644
index 0000000..b48989e
--- /dev/null
+++ b/test/unit/pixi/core/Matrix.js
@@ -0,0 +1,30 @@
+describe('pixi/core/Matrix', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var mat3 = PIXI.mat3;
+ var mat4 = PIXI.mat4;
+ var Matrix = PIXI.Matrix;
+
+ it('Ensure determineMatrixArrayType works', function () {
+ expect(Matrix).to.be.a('function');
+ });
+
+ it('mat3 exists', function () {
+ expect(mat3).to.be.an('object');
+ });
+
+ it('Confirm new mat3 matrix', function () {
+ var matrix = new mat3.create();
+ pixi_core_Matrix_confirmNewMat3(matrix);
+ });
+
+ it('mat3 exists', function () {
+ expect(mat4).to.be.an('object');
+ });
+
+ it('Confirm new mat4 matrix', function () {
+ var matrix = new mat4.create();
+ pixi_core_Matrix_confirmNewMat4(matrix);
+ });
+});
diff --git a/test/unit/pixi/core/Point.js b/test/unit/pixi/core/Point.js
new file mode 100644
index 0000000..c4d5163
--- /dev/null
+++ b/test/unit/pixi/core/Point.js
@@ -0,0 +1,15 @@
+describe('pixi/core/Point', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Point = PIXI.Point;
+
+ it('Module exists', function () {
+ expect(Point).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Point();
+ pixi_core_Point_confirm(obj, 0, 0);
+ });
+});
diff --git a/test/unit/pixi/core/Polygon.js b/test/unit/pixi/core/Polygon.js
new file mode 100644
index 0000000..dc8c918
--- /dev/null
+++ b/test/unit/pixi/core/Polygon.js
@@ -0,0 +1,20 @@
+describe('pixi/core/Polygon', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Polygon = PIXI.Polygon;
+
+ it('Module exists', function () {
+ expect(Polygon).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Polygon();
+
+ expect(obj).to.be.an.instanceof(Polygon);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.deep.property('points.length', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Rectangle.js b/test/unit/pixi/core/Rectangle.js
new file mode 100644
index 0000000..d43316e
--- /dev/null
+++ b/test/unit/pixi/core/Rectangle.js
@@ -0,0 +1,15 @@
+describe('pixi/core/Rectangle', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Rectangle = PIXI.Rectangle;
+
+ it('Module exists', function () {
+ expect(Rectangle).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var rect = new Rectangle();
+ pixi_core_Rectangle_confirm(rect, 0, 0, 0, 0);
+ });
+});
diff --git a/test/unit/pixi/display/DisplayObject.js b/test/unit/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..40c6fbc
--- /dev/null
+++ b/test/unit/pixi/display/DisplayObject.js
@@ -0,0 +1,21 @@
+describe('pixi/display/DisplayObject', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var DisplayObject = PIXI.DisplayObject;
+
+ it('Module exists', function () {
+ expect(DisplayObject).to.be.a('function');
+ expect(PIXI).to.have.property('visibleCount', 0);
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new DisplayObject();
+
+ pixi_display_DisplayObject_confirmNew(obj);
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', false);
+ expect(obj).to.have.property('stage', null);
+ });
+});
diff --git a/test/unit/pixi/display/DisplayObjectContainer.js b/test/unit/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..ce7f02f
--- /dev/null
+++ b/test/unit/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,20 @@
+describe('pixi/display/DisplayObjectContainer', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var DisplayObjectContainer = PIXI.DisplayObjectContainer;
+
+ it('Module exists', function () {
+ expect(DisplayObjectContainer).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new DisplayObjectContainer();
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', false);
+ expect(obj).to.have.property('stage', null);
+ });
+});
diff --git a/test/unit/pixi/display/MovieClip.js b/test/unit/pixi/display/MovieClip.js
new file mode 100644
index 0000000..f3c6c6a
--- /dev/null
+++ b/test/unit/pixi/display/MovieClip.js
@@ -0,0 +1,33 @@
+describe('pixi/display/MovieClip', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var MovieClip = PIXI.MovieClip;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(MovieClip).to.be.a('function');
+ });
+
+ it('Confirm new instance', function (done) {
+ var texture = Texture.fromImage('/base/test/textures/SpriteSheet-Explosion.png');
+ var obj = new MovieClip([texture]);
+
+ pixi_display_Sprite_confirmNew(obj, done);
+
+ expect(obj).to.be.an.instanceof(MovieClip);
+ expect(obj).to.respondTo('stop');
+ expect(obj).to.respondTo('play');
+ expect(obj).to.respondTo('gotoAndStop');
+ expect(obj).to.respondTo('gotoAndPlay');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('textures.length', 1);
+ expect(obj).to.have.deep.property('textures[0]', texture);
+ expect(obj).to.have.property('animationSpeed', 1);
+ expect(obj).to.have.property('loop', true);
+ expect(obj).to.have.property('onComplete', null);
+ expect(obj).to.have.property('currentFrame', 0);
+ expect(obj).to.have.property('playing', false);
+ });
+});
diff --git a/test/unit/pixi/display/Sprite.js b/test/unit/pixi/display/Sprite.js
new file mode 100644
index 0000000..54e914f
--- /dev/null
+++ b/test/unit/pixi/display/Sprite.js
@@ -0,0 +1,25 @@
+describe('pixi/display/Sprite', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Sprite = PIXI.Sprite;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(Sprite).to.be.a('function');
+ expect(PIXI).to.have.deep.property('blendModes.NORMAL', 0);
+ expect(PIXI).to.have.deep.property('blendModes.SCREEN', 1);
+ });
+
+ it('Members exist', function () {
+ expect(Sprite).itself.to.respondTo('fromImage');
+ expect(Sprite).itself.to.respondTo('fromFrame');
+ });
+
+ it('Confirm new instance', function (done) {
+ var texture = Texture.fromImage('/base/test/textures/SpriteSheet-Aliens.png');
+ var obj = new Sprite(texture);
+
+ pixi_display_Sprite_confirmNew(obj, done);
+ });
+});
diff --git a/test/unit/pixi/display/Stage.js b/test/unit/pixi/display/Stage.js
new file mode 100644
index 0000000..3cc2a4d
--- /dev/null
+++ b/test/unit/pixi/display/Stage.js
@@ -0,0 +1,49 @@
+describe('pixi/display/Stage', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Stage = PIXI.Stage;
+ var InteractionManager = PIXI.InteractionManager;
+ var Rectangle = PIXI.Rectangle;
+
+ it('Module exists', function () {
+ expect(Stage).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Stage(null, true);
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(Stage);
+ expect(obj).to.respondTo('updateTransform');
+ expect(obj).to.respondTo('setBackgroundColor');
+ expect(obj).to.respondTo('getMousePosition');
+
+ // FIXME: duplicate member in DisplayObject
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ // FIXME: convert arg to bool in constructor
+ expect(obj).to.have.property('interactive', true);
+
+ expect(obj).to.have.property('interactionManager')
+ .and.to.be.an.instanceof(InteractionManager)
+ .and.to.have.property('stage', obj);
+
+ expect(obj).to.have.property('dirty', true);
+
+ expect(obj).to.have.property('stage', obj);
+
+ expect(obj).to.have.property('hitArea')
+ .and.to.be.an.instanceof(Rectangle);
+ pixi_core_Rectangle_confirm(obj.hitArea, 0, 0, 100000, 100000);
+
+ expect(obj).to.have.property('backgroundColor', 0x000000);
+ expect(obj).to.have.deep.property('backgroundColorSplit.length', 3);
+ expect(obj).to.have.deep.property('backgroundColorSplit[0]', 0);
+ expect(obj).to.have.deep.property('backgroundColorSplit[1]', 0);
+ expect(obj).to.have.deep.property('backgroundColorSplit[2]', 0);
+ expect(obj).to.have.property('backgroundColorString', '#000000');
+
+ expect(obj).to.have.property('worldVisible', true);
+ });
+});
diff --git a/test/unit/pixi/extras/CustomRenderable.js b/test/unit/pixi/extras/CustomRenderable.js
new file mode 100644
index 0000000..8d83cf0
--- /dev/null
+++ b/test/unit/pixi/extras/CustomRenderable.js
@@ -0,0 +1,21 @@
+describe('pixi/extras/CustomRenderable', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var CustomRenderable = PIXI.CustomRenderable;
+
+ it('Module exists', function () {
+ expect(CustomRenderable).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new CustomRenderable();
+
+ pixi_display_DisplayObject_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(CustomRenderable);
+ expect(obj).to.respondTo('renderCanvas');
+ expect(obj).to.respondTo('initWebGL');
+ expect(obj).to.respondTo('renderWebGL');
+ });
+});
diff --git a/test/unit/pixi/extras/Rope.js b/test/unit/pixi/extras/Rope.js
new file mode 100644
index 0000000..6ddaf83
--- /dev/null
+++ b/test/unit/pixi/extras/Rope.js
@@ -0,0 +1,26 @@
+describe('pixi/extras/Rope', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Rope = PIXI.Rope;
+ var Texture = PIXI.Texture;
+ var Point = PIXI.Point;
+
+ it('Module exists', function () {
+ expect(Rope).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var texture = Texture.fromImage('/base/test/textures/bunny.png');
+ var obj = new Rope(texture, [new Point(), new Point(5, 10), new Point(10, 20)]);
+
+ pixi_extras_Strip_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(Rope);
+ expect(obj).to.respondTo('refresh');
+ expect(obj).to.respondTo('updateTransform');
+ expect(obj).to.respondTo('setTexture');
+
+ // TODO: Test properties
+ });
+});
diff --git a/test/unit/pixi/extras/Spine.js b/test/unit/pixi/extras/Spine.js
new file mode 100644
index 0000000..0708bc0
--- /dev/null
+++ b/test/unit/pixi/extras/Spine.js
@@ -0,0 +1,10 @@
+describe('pixi/extras/Spine', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Spine = PIXI.Spine;
+
+ it('Module exists', function () {
+ expect(Spine).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/extras/Strip.js b/test/unit/pixi/extras/Strip.js
new file mode 100644
index 0000000..8e564e1
--- /dev/null
+++ b/test/unit/pixi/extras/Strip.js
@@ -0,0 +1,18 @@
+describe('pixi/extras/Strip', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Strip = PIXI.Strip;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(Strip).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var texture = Texture.fromImage('/base/test/textures/bunny.png');
+ var obj = new Strip(texture, 20, 10000);
+
+ pixi_extras_Strip_confirmNew(obj);
+ });
+});
diff --git a/test/unit/pixi/extras/TilingSprite.js b/test/unit/pixi/extras/TilingSprite.js
new file mode 100644
index 0000000..56aea14
--- /dev/null
+++ b/test/unit/pixi/extras/TilingSprite.js
@@ -0,0 +1,24 @@
+describe('pixi/extras/TilingSprite', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var TilingSprite = PIXI.TilingSprite;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(TilingSprite).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var texture = Texture.fromImage('/base/test/textures/bunny.png');
+ var obj = new TilingSprite(texture, 6000, 12000);
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(TilingSprite);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ // TODO: Test properties
+ });
+});
diff --git a/test/unit/pixi/filters/FilterBlock.js b/test/unit/pixi/filters/FilterBlock.js
new file mode 100644
index 0000000..870cec0
--- /dev/null
+++ b/test/unit/pixi/filters/FilterBlock.js
@@ -0,0 +1,10 @@
+describe('pixi/filters/FilterBlock', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var FilterBlock = PIXI.FilterBlock;
+
+ it('Module exists', function () {
+ expect(FilterBlock).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/filters/MaskFilter.js b/test/unit/pixi/filters/MaskFilter.js
new file mode 100644
index 0000000..32d6a45
--- /dev/null
+++ b/test/unit/pixi/filters/MaskFilter.js
@@ -0,0 +1,10 @@
+describe('pixi/filters/MaskFilter', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ // var MaskFilter = PIXI.MaskFilter;
+
+ // it('Module exists', function () {
+ // expect(MaskFilter).to.be.a('function');
+ // });
+});
diff --git a/test/unit/pixi/loaders/AssetLoader.js b/test/unit/pixi/loaders/AssetLoader.js
new file mode 100644
index 0000000..a0aa0b5
--- /dev/null
+++ b/test/unit/pixi/loaders/AssetLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/AssetLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var AssetLoader = PIXI.AssetLoader;
+
+ it('Module exists', function () {
+ expect(AssetLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/BitmapFontLoader.js b/test/unit/pixi/loaders/BitmapFontLoader.js
new file mode 100644
index 0000000..6253c42
--- /dev/null
+++ b/test/unit/pixi/loaders/BitmapFontLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/BitmapFontLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var BitmapFontLoader = PIXI.BitmapFontLoader;
+
+ it('Module exists', function () {
+ expect(PIXI.BitmapFontLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/ImageLoader.js b/test/unit/pixi/loaders/ImageLoader.js
new file mode 100644
index 0000000..8b1f556
--- /dev/null
+++ b/test/unit/pixi/loaders/ImageLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/ImageLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var ImageLoader = PIXI.ImageLoader;
+
+ it('Module exists', function () {
+ expect(ImageLoader).to.be.a('function');
+ });
+});
diff --git a/.gitignore b/.gitignore
index 12e1b62..0b88317 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
node_modules
.DS_Store
-.project
\ No newline at end of file
+.project
+*.log
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..63e4d7c
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,8 @@
+language: node_js
+node_js:
+ - 0.10
+
+before_script:
+ - npm install -g grunt-cli
+ - export DISPLAY=:99.0
+ - sh -e /etc/init.d/xvfb start
diff --git a/Gruntfile.js b/Gruntfile.js
index b083b49..103938c 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -1,10 +1,12 @@
+'use strict';
+
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-connect');
- grunt.loadNpmTasks('grunt-contrib-qunit');
grunt.loadNpmTasks('grunt-contrib-yuidoc');
+ grunt.loadTasks('tasks');
var root = 'src/pixi/',
debug = 'bin/pixi.dev.js',
@@ -79,7 +81,7 @@
},
files: {
srcBlob: '<%= dirs.src %>/**/*.js',
- testBlob: '<%= dirs.test %>/unit/**/*.js',
+ testBlob: '<%= dirs.test %>/{functional,lib/pixi,unit}/**/*.js',
build: '<%= dirs.build %>/pixi.dev.js',
buildMin: '<%= dirs.build %>/pixi.js'
},
@@ -94,7 +96,12 @@
},
jshint: {
beforeconcat: srcFiles,
- test: ['<%= files.testBlob %>'],
+ test: {
+ src: ['<%= files.testBlob %>'],
+ options: {
+ expr: true
+ }
+ },
options: {
asi: true,
smarttabs: true
@@ -128,12 +135,6 @@
]
},
connect: {
- qunit: {
- options: {
- port: grunt.option('port-test') || 9002,
- base: './'
- }
- },
test: {
options: {
port: grunt.option('port-test') || 9002,
@@ -142,13 +143,6 @@
}
}
},
- qunit: {
- all: {
- options: {
- urls: ['http://localhost:' + (grunt.option('port-test') || 9002) + '/test/index.html']
- }
- }
- },
yuidoc: {
compile: {
name: '<%= pkg.name %>',
@@ -161,6 +155,13 @@
outdir: '<%= dirs.docs %>'
}
}
+ },
+ karma: {
+ unit: {
+ configFile: 'test/karma.conf.js',
+ // browsers: ['Chrome'],
+ singleRun: true
+ }
}
});
@@ -182,9 +183,10 @@
}
)
- grunt.registerTask('default', ['concat', 'uglify', 'distribute']);
grunt.registerTask('build', ['concat', 'uglify', 'distribute']);
- grunt.registerTask('test', ['build', 'connect:qunit', 'qunit']);
+ grunt.registerTask('test', ['concat', 'jshint:test', 'karma']);
grunt.registerTask('docs', ['yuidoc']);
-
-}
\ No newline at end of file
+ grunt.registerTask('default', ['test', 'uglify', 'distribute']);
+ // Travis CI task.
+ grunt.registerTask('travis', ['test']);
+}
diff --git a/README.md b/README.md
index c62ef86..690cfe4 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,8 @@

+[](http://travis-ci.org/drkibitz/pixi.js)
+
#### JavaScript 2D Renderer ####
The aim of this project is to provide a fast lightweight 2D library that works
diff --git a/package.json b/package.json
index b373240..1246a68 100644
--- a/package.json
+++ b/package.json
@@ -18,14 +18,21 @@
"main": "bin/pixi.js",
+ "scripts": {
+ "test": "grunt travis --verbose"
+ },
+
"dependencies": {},
"devDependencies": {
"grunt": "~0.4.x",
- "grunt-contrib-jshint": "0.3.x",
+ "grunt-contrib-jshint": "0.6.x",
"grunt-contrib-uglify": "0.2.x",
- "grunt-contrib-connect": "0.2.x",
- "grunt-contrib-qunit": "0.2.x",
+ "grunt-contrib-connect": "0.3.x",
"grunt-contrib-yuidoc": "0.4.x",
- "grunt-contrib-concat": "0.1.x"
+ "grunt-contrib-concat": "0.3.x",
+ "chai": "~1.7.0",
+ "karma": "0.11.0",
+ "karma-firefox-launcher": "0.1.0",
+ "karma-mocha": "0.1.0"
}
}
diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js
index a7c520e..ee82bbd 100644
--- a/src/pixi/InteractionManager.js
+++ b/src/pixi/InteractionManager.js
@@ -62,7 +62,6 @@
this.onTouchEnd = this.onTouchEnd.bind(this);
this.onTouchMove = this.onTouchMove.bind(this);
-
this.last = 0;
}
diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js
index 1a95d20..eef1059 100644
--- a/src/pixi/core/Ellipse.js
+++ b/src/pixi/core/Ellipse.js
@@ -78,7 +78,7 @@
return (normx + normy < 0.25);
}
-PIXI.Ellipse.getBounds = function()
+PIXI.Ellipse.prototype.getBounds = function()
{
return new PIXI.Rectangle(this.x, this.y, this.width, this.height);
}
diff --git a/tasks/karma.js b/tasks/karma.js
new file mode 100644
index 0000000..c340485
--- /dev/null
+++ b/tasks/karma.js
@@ -0,0 +1,27 @@
+'use strict';
+
+var path = require('path');
+var server = require('karma').server;
+
+module.exports = function (grunt) {
+ grunt.registerMultiTask('karma', 'run karma.', function() {
+ var done = this.async();
+ var options = this.options({
+ background: false
+ });
+ var data = this.data;
+
+ //merge options onto data, with data taking precedence
+ data = grunt.util._.merge(options, data);
+ data.configFile = path.resolve(data.configFile);
+ if (data.configFile) {
+ data.configFile = grunt.template.process(data.configFile);
+ }
+
+ server.start(
+ data,
+ function(code) {
+ done(!code);
+ });
+ });
+};
diff --git a/test/functional/example-1-basics/bunny.png b/test/functional/example-1-basics/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/functional/example-1-basics/bunny.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-30.png b/test/functional/example-1-basics/frame-30.png
new file mode 100644
index 0000000..96e3409
--- /dev/null
+++ b/test/functional/example-1-basics/frame-30.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-60.png b/test/functional/example-1-basics/frame-60.png
new file mode 100644
index 0000000..af3f4ce
--- /dev/null
+++ b/test/functional/example-1-basics/frame-60.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-90.png b/test/functional/example-1-basics/frame-90.png
new file mode 100644
index 0000000..099b823
--- /dev/null
+++ b/test/functional/example-1-basics/frame-90.png
Binary files differ
diff --git a/test/functional/example-1-basics/index.js b/test/functional/example-1-basics/index.js
new file mode 100644
index 0000000..7ae7a98
--- /dev/null
+++ b/test/functional/example-1-basics/index.js
@@ -0,0 +1,133 @@
+describe('Example 1 - Basics', function () {
+ 'use strict';
+
+ var baseUri = '/base/test/functional/example-1-basics';
+ var expect = chai.expect;
+ var currentFrame = 0;
+ var frameEvents = {};
+ var stage;
+ var renderer;
+ var bunny;
+
+ function onFrame(frame, callback) {
+ frameEvents[frame] = callback;
+ }
+
+ function animate() {
+ currentFrame += 1;
+
+ requestAnimFrame( animate );
+
+ // just for fun, lets rotate mr rabbit a little
+ bunny.rotation += 0.1;
+
+ // render the stage
+ renderer.render(stage);
+
+ if (frameEvents[currentFrame])
+ frameEvents[currentFrame](currentFrame);
+ }
+
+ function initScene() {
+ // create an new instance of a pixi stage
+ stage = new PIXI.Stage(0x66FF99);
+
+ // create a renderer instance
+ renderer = PIXI.autoDetectRenderer(400, 300);
+ console.log('Is PIXI.WebGLRenderer: ' + (renderer instanceof PIXI.WebGLRenderer));
+
+ // add the renderer view element to the DOM
+ document.body.appendChild(renderer.view);
+
+ requestAnimFrame( animate );
+
+ // create a texture from an image path
+ var texture = PIXI.Texture.fromImage(baseUri + "/bunny.png");
+ // create a new Sprite using the texture
+ bunny = new PIXI.Sprite(texture);
+
+ // center the sprites anchor point
+ bunny.anchor.x = 0.5;
+ bunny.anchor.y = 0.5;
+
+ // move the sprite t the center of the screen
+ bunny.position.x = 200;
+ bunny.position.y = 150;
+
+ stage.addChild(bunny);
+ }
+
+ it('assets loaded', function (done) {
+ var loader = new PIXI.AssetLoader([
+ baseUri + '/bunny.png',
+ baseUri + '/frame-30.png',
+ baseUri + '/frame-60.png',
+ baseUri + '/frame-90.png'
+ ]);
+ // loader.on('onProgress', function (event) {
+ // console.log(event.content);
+ // });
+ loader.on('onComplete', function (event) {
+ done();
+ initScene();
+ });
+ loader.load();
+ });
+
+ it('frame 30 should match', function (done) {
+ this.timeout(700);
+ onFrame(30, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-30.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 60 should match', function (done) {
+ this.timeout(1200);
+ onFrame(60, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-60.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 90 should match', function (done) {
+ this.timeout(1700);
+ onFrame(90, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-90.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ // it('capture something', function (done) {
+ // this.timeout(2000000);
+ // onFrame(30, function () {
+ // var img = new Image();
+ // img.src = renderer.view.toDataURL('image/png');
+ // document.body.appendChild(img);
+ // });
+ // });
+});
diff --git a/test/index.html b/test/index.html
deleted file mode 100644
index 9cbcac5..0000000
--- a/test/index.html
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
- Pixi.js Test Suite
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/test/karma.conf.js b/test/karma.conf.js
new file mode 100644
index 0000000..c66a696
--- /dev/null
+++ b/test/karma.conf.js
@@ -0,0 +1,82 @@
+module.exports = function(config) {
+ config.set({
+
+ // base path, that will be used to resolve files and exclude
+ basePath : '../',
+
+ frameworks : ['mocha'],
+
+ // list of files / patterns to load in the browser
+ files : [
+ 'node_modules/chai/chai.js',
+ 'bin/pixi.dev.js',
+ 'test/lib/**/*.js',
+ 'test/unit/**/*.js',
+ // 'test/functional/**/*.js',
+ {pattern: 'test/**/*.png', watched: false, included: false, served: true}
+ ],
+
+ // list of files to exclude
+ exclude : [],
+
+ // use dolts reporter, as travis terminal does not support escaping sequences
+ // possible values: 'dots', 'progress', 'junit', 'teamcity'
+ // CLI --reporters progress
+ reporters : ['progress'],
+
+ // web server port
+ // CLI --port 9876
+ port : 9876,
+
+ // cli runner port
+ // CLI --runner-port 9100
+ runnerPort : 9100,
+
+ // enable / disable colors in the output (reporters and logs)
+ // CLI --colors --no-colors
+ colors : true,
+
+ // level of logging
+ // possible values: karma.LOG_DISABLE || karma.LOG_ERROR || karma.LOG_WARN || karma.LOG_INFO || karma.LOG_DEBUG
+ // CLI --log-level debug
+ logLevel : config.LOG_DEBUG,
+
+ // enable / disable watching file and executing tests whenever any file changes
+ // CLI --auto-watch --no-auto-watch
+ autoWatch : false,
+
+ // Start these browsers, currently available:
+ // - Chrome
+ // - ChromeCanary
+ // - Firefox
+ // - Opera
+ // - Safari (only Mac)
+ // - PhantomJS
+ // - IE (only Windows)
+ // CLI --browsers Chrome,Firefox,Safari
+ browsers : ['Firefox'],
+
+ // If browser does not capture in given timeout [ms], kill it
+ // CLI --capture-timeout 5000
+ captureTimeout : 5000,
+
+ // Auto run tests on start (when browsers are captured) and exit
+ // CLI --single-run --no-single-run
+ singleRun : true,
+
+ // report which specs are slower than 500ms
+ // CLI --report-slower-than 500
+ reportSlowerThan : 1000,
+
+ preprocessors : {
+ // '**/client/js/*.js': 'coverage'
+ },
+
+ plugins : [
+ 'karma-mocha',
+ // 'karma-chrome-launcher',
+ 'karma-firefox-launcher',
+ // 'karma-phantomjs-launcher'
+ ]
+ });
+};
diff --git a/test/lib/pixi/core/Matrix.js b/test/lib/pixi/core/Matrix.js
new file mode 100644
index 0000000..d26386b
--- /dev/null
+++ b/test/lib/pixi/core/Matrix.js
@@ -0,0 +1,40 @@
+
+function pixi_core_Matrix_confirmNewMat3(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(1);
+ expect(matrix[5]).to.equal(0);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(1);
+}
+
+function pixi_core_Matrix_confirmNewMat4(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[0]).to.equal(1);
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(0);
+ expect(matrix[5]).to.equal(1);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(0);
+ expect(matrix[9]).to.equal(0);
+ expect(matrix[10]).to.equal(1);
+ expect(matrix[11]).to.equal(0);
+ expect(matrix[12]).to.equal(0);
+ expect(matrix[13]).to.equal(0);
+ expect(matrix[14]).to.equal(0);
+ expect(matrix[15]).to.equal(1);
+}
diff --git a/test/lib/pixi/core/Point.js b/test/lib/pixi/core/Point.js
new file mode 100644
index 0000000..e5df07b
--- /dev/null
+++ b/test/lib/pixi/core/Point.js
@@ -0,0 +1,10 @@
+
+function pixi_core_Point_confirm(obj, x, y) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Point);
+ expect(obj).to.respondTo('clone');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+}
diff --git a/test/lib/pixi/core/Rectangle.js b/test/lib/pixi/core/Rectangle.js
new file mode 100644
index 0000000..23f0d12
--- /dev/null
+++ b/test/lib/pixi/core/Rectangle.js
@@ -0,0 +1,13 @@
+
+function pixi_core_Rectangle_confirm(obj, x, y, width, height) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Rectangle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+ expect(obj).to.have.property('width', width);
+ expect(obj).to.have.property('height', height);
+}
diff --git a/test/lib/pixi/display/DisplayObject.js b/test/lib/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..1388a7f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObject.js
@@ -0,0 +1,43 @@
+
+function pixi_display_DisplayObject_confirmNew(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObject);
+ expect(obj).to.respondTo('setInteractive');
+ expect(obj).to.respondTo('addFilter');
+ expect(obj).to.respondTo('removeFilter');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.property('last', obj);
+ expect(obj).to.have.property('first', obj);
+
+ expect(obj).to.contain.property('position');
+ pixi_core_Point_confirm(obj.position, 0, 0);
+ expect(obj).to.contain.property('scale');
+ pixi_core_Point_confirm(obj.scale, 1, 1);
+ expect(obj).to.contain.property('pivot');
+ pixi_core_Point_confirm(obj.pivot, 0, 0);
+
+ expect(obj).to.have.property('rotation', 0);
+ expect(obj).to.have.property('alpha', 1);
+ expect(obj).to.have.property('visible', true);
+ expect(obj).to.have.property('buttonMode', false);
+ expect(obj).to.have.property('parent', null);
+ expect(obj).to.have.property('worldAlpha', 1);
+
+ expect(obj).to.have.property('hitArea');
+ expect(obj).to.have.property('interactive'); // TODO: Have a better default value
+ expect('mask' in obj).to.be.true; // TODO: Have a better default value
+ expect(obj.mask).to.be.undefined;
+
+ expect(obj).to.have.property('renderable');
+ expect(obj).to.have.property('stage');
+
+ expect(obj).to.have.deep.property('worldTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ expect(obj).to.have.deep.property('localTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.localTransform);
+
+ expect(obj).to.have.deep.property('color.length', 0);
+ expect(obj).to.have.property('dynamic', true);
+}
diff --git a/test/lib/pixi/display/DisplayObjectContainer.js b/test/lib/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..085c59f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,16 @@
+
+function pixi_display_DisplayObjectContainer_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObject_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObjectContainer);
+ expect(obj).to.respondTo('addChild');
+ expect(obj).to.respondTo('addChildAt');
+ expect(obj).to.respondTo('swapChildren');
+ expect(obj).to.respondTo('getChildAt');
+ expect(obj).to.respondTo('removeChild');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('children.length', 0);
+}
diff --git a/test/lib/pixi/display/Sprite.js b/test/lib/pixi/display/Sprite.js
new file mode 100644
index 0000000..cc7a2d6
--- /dev/null
+++ b/test/lib/pixi/display/Sprite.js
@@ -0,0 +1,28 @@
+
+function pixi_display_Sprite_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Sprite);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', true);
+ expect(obj).to.have.property('stage', null);
+
+ expect(obj).to.have.property('anchor');
+ pixi_core_Point_confirm(obj.anchor, 0, 0);
+
+ expect(obj).to.have.property('blendMode', PIXI.blendModes.NORMAL);
+ expect(obj).to.have.property('width', 1); // TODO: is 1 expected
+ expect(obj).to.have.property('height', 1); // TODO: is 1 expected
+
+ // FIXME: Just make this a boolean that is always there
+ expect(!!obj.updateFrame).to.equal(obj.texture.baseTexture.hasLoaded);
+
+ expect(obj).to.have.property('texture');
+ pixi_textures_Texture_confirmNew(obj.texture, done);
+}
diff --git a/test/lib/pixi/extras/Strip.js b/test/lib/pixi/extras/Strip.js
new file mode 100644
index 0000000..8927a8a
--- /dev/null
+++ b/test/lib/pixi/extras/Strip.js
@@ -0,0 +1,12 @@
+
+function pixi_extras_Strip_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Strip);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ // TODO: Test properties
+}
diff --git a/test/lib/pixi/textures/Texture.js b/test/lib/pixi/textures/Texture.js
new file mode 100644
index 0000000..d5867b6
--- /dev/null
+++ b/test/lib/pixi/textures/Texture.js
@@ -0,0 +1,31 @@
+
+function pixi_textures_Texture_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ function confirmFrameDone() {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, obj.baseTexture.width, obj.baseTexture.height);
+
+ expect(obj).to.have.property('width', obj.baseTexture.width);
+ expect(obj).to.have.property('height', obj.baseTexture.height);
+ done();
+ }
+
+ expect(obj).to.be.an.instanceof(PIXI.Texture);
+ pixi_utils_EventTarget_like(obj);
+
+ expect(obj).to.have.property('baseTexture')
+ .and.to.be.an.instanceof(PIXI.BaseTexture);
+
+ expect(obj).to.have.property('scope', obj);
+
+ expect(obj).to.have.property('trim');
+ pixi_core_Point_confirm(obj.trim, 0, 0);
+
+ expect(obj).to.have.property('frame');
+ if (obj.baseTexture.hasLoaded) {
+ confirmFrameDone();
+ } else {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, 1, 1);
+ obj.addEventListener('update', confirmFrameDone);
+ }
+}
diff --git a/test/lib/pixi/utils/EventTarget.js b/test/lib/pixi/utils/EventTarget.js
new file mode 100644
index 0000000..7b1dcfa
--- /dev/null
+++ b/test/lib/pixi/utils/EventTarget.js
@@ -0,0 +1,8 @@
+
+function pixi_utils_EventTarget_like(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.respondTo('addEventListener');
+ expect(obj).to.respondTo('dispatchEvent');
+ expect(obj).to.respondTo('removeEventListener');
+}
diff --git a/test/lib/qunit-1.11.0.css b/test/lib/qunit-1.11.0.css
deleted file mode 100644
index d7fc0c8..0000000
--- a/test/lib/qunit-1.11.0.css
+++ /dev/null
@@ -1,244 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-/** Font Family and Sizes */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
- font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
-}
-
-#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
-#qunit-tests { font-size: smaller; }
-
-
-/** Resets */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter {
- margin: 0;
- padding: 0;
-}
-
-
-/** Header */
-
-#qunit-header {
- padding: 0.5em 0 0.5em 1em;
-
- color: #8699a4;
- background-color: #0d3349;
-
- font-size: 1.5em;
- line-height: 1em;
- font-weight: normal;
-
- border-radius: 5px 5px 0 0;
- -moz-border-radius: 5px 5px 0 0;
- -webkit-border-top-right-radius: 5px;
- -webkit-border-top-left-radius: 5px;
-}
-
-#qunit-header a {
- text-decoration: none;
- color: #c2ccd1;
-}
-
-#qunit-header a:hover,
-#qunit-header a:focus {
- color: #fff;
-}
-
-#qunit-testrunner-toolbar label {
- display: inline-block;
- padding: 0 .5em 0 .1em;
-}
-
-#qunit-banner {
- height: 5px;
-}
-
-#qunit-testrunner-toolbar {
- padding: 0.5em 0 0.5em 2em;
- color: #5E740B;
- background-color: #eee;
- overflow: hidden;
-}
-
-#qunit-userAgent {
- padding: 0.5em 0 0.5em 2.5em;
- background-color: #2b81af;
- color: #fff;
- text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
-}
-
-#qunit-modulefilter-container {
- float: right;
-}
-
-/** Tests: Pass/Fail */
-
-#qunit-tests {
- list-style-position: inside;
-}
-
-#qunit-tests li {
- padding: 0.4em 0.5em 0.4em 2.5em;
- border-bottom: 1px solid #fff;
- list-style-position: inside;
-}
-
-#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running {
- display: none;
-}
-
-#qunit-tests li strong {
- cursor: pointer;
-}
-
-#qunit-tests li a {
- padding: 0.5em;
- color: #c2ccd1;
- text-decoration: none;
-}
-#qunit-tests li a:hover,
-#qunit-tests li a:focus {
- color: #000;
-}
-
-#qunit-tests li .runtime {
- float: right;
- font-size: smaller;
-}
-
-.qunit-assert-list {
- margin-top: 0.5em;
- padding: 0.5em;
-
- background-color: #fff;
-
- border-radius: 5px;
- -moz-border-radius: 5px;
- -webkit-border-radius: 5px;
-}
-
-.qunit-collapsed {
- display: none;
-}
-
-#qunit-tests table {
- border-collapse: collapse;
- margin-top: .2em;
-}
-
-#qunit-tests th {
- text-align: right;
- vertical-align: top;
- padding: 0 .5em 0 0;
-}
-
-#qunit-tests td {
- vertical-align: top;
-}
-
-#qunit-tests pre {
- margin: 0;
- white-space: pre-wrap;
- word-wrap: break-word;
-}
-
-#qunit-tests del {
- background-color: #e0f2be;
- color: #374e0c;
- text-decoration: none;
-}
-
-#qunit-tests ins {
- background-color: #ffcaca;
- color: #500;
- text-decoration: none;
-}
-
-/*** Test Counts */
-
-#qunit-tests b.counts { color: black; }
-#qunit-tests b.passed { color: #5E740B; }
-#qunit-tests b.failed { color: #710909; }
-
-#qunit-tests li li {
- padding: 5px;
- background-color: #fff;
- border-bottom: none;
- list-style-position: inside;
-}
-
-/*** Passing Styles */
-
-#qunit-tests li li.pass {
- color: #3c510c;
- background-color: #fff;
- border-left: 10px solid #C6E746;
-}
-
-#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
-#qunit-tests .pass .test-name { color: #366097; }
-
-#qunit-tests .pass .test-actual,
-#qunit-tests .pass .test-expected { color: #999999; }
-
-#qunit-banner.qunit-pass { background-color: #C6E746; }
-
-/*** Failing Styles */
-
-#qunit-tests li li.fail {
- color: #710909;
- background-color: #fff;
- border-left: 10px solid #EE5757;
- white-space: pre;
-}
-
-#qunit-tests > li:last-child {
- border-radius: 0 0 5px 5px;
- -moz-border-radius: 0 0 5px 5px;
- -webkit-border-bottom-right-radius: 5px;
- -webkit-border-bottom-left-radius: 5px;
-}
-
-#qunit-tests .fail { color: #000000; background-color: #EE5757; }
-#qunit-tests .fail .test-name,
-#qunit-tests .fail .module-name { color: #000000; }
-
-#qunit-tests .fail .test-actual { color: #EE5757; }
-#qunit-tests .fail .test-expected { color: green; }
-
-#qunit-banner.qunit-fail { background-color: #EE5757; }
-
-
-/** Result */
-
-#qunit-testresult {
- padding: 0.5em 0.5em 0.5em 2.5em;
-
- color: #2b81af;
- background-color: #D2E0E6;
-
- border-bottom: 1px solid white;
-}
-#qunit-testresult .module-name {
- font-weight: bold;
-}
-
-/** Fixture */
-
-#qunit-fixture {
- position: absolute;
- top: -10000px;
- left: -10000px;
- width: 1000px;
- height: 1000px;
-}
diff --git a/test/lib/qunit-1.11.0.js b/test/lib/qunit-1.11.0.js
deleted file mode 100644
index 302545f..0000000
--- a/test/lib/qunit-1.11.0.js
+++ /dev/null
@@ -1,2152 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-(function( window ) {
-
-var QUnit,
- assert,
- config,
- onErrorFnPrev,
- testId = 0,
- fileName = (sourceFromStacktrace( 0 ) || "" ).replace(/(:\d+)+\)?/, "").replace(/.+\//, ""),
- toString = Object.prototype.toString,
- hasOwn = Object.prototype.hasOwnProperty,
- // Keep a local reference to Date (GH-283)
- Date = window.Date,
- defined = {
- setTimeout: typeof window.setTimeout !== "undefined",
- sessionStorage: (function() {
- var x = "qunit-test-string";
- try {
- sessionStorage.setItem( x, x );
- sessionStorage.removeItem( x );
- return true;
- } catch( e ) {
- return false;
- }
- }())
- },
- /**
- * Provides a normalized error string, correcting an issue
- * with IE 7 (and prior) where Error.prototype.toString is
- * not properly implemented
- *
- * Based on http://es5.github.com/#x15.11.4.4
- *
- * @param {String|Error} error
- * @return {String} error message
- */
- errorString = function( error ) {
- var name, message,
- errorString = error.toString();
- if ( errorString.substring( 0, 7 ) === "[object" ) {
- name = error.name ? error.name.toString() : "Error";
- message = error.message ? error.message.toString() : "";
- if ( name && message ) {
- return name + ": " + message;
- } else if ( name ) {
- return name;
- } else if ( message ) {
- return message;
- } else {
- return "Error";
- }
- } else {
- return errorString;
- }
- },
- /**
- * Makes a clone of an object using only Array or Object as base,
- * and copies over the own enumerable properties.
- *
- * @param {Object} obj
- * @return {Object} New object with only the own properties (recursively).
- */
- objectValues = function( obj ) {
- // Grunt 0.3.x uses an older version of jshint that still has jshint/jshint#392.
- /*jshint newcap: false */
- var key, val,
- vals = QUnit.is( "array", obj ) ? [] : {};
- for ( key in obj ) {
- if ( hasOwn.call( obj, key ) ) {
- val = obj[key];
- vals[key] = val === Object(val) ? objectValues(val) : val;
- }
- }
- return vals;
- };
-
-function Test( settings ) {
- extend( this, settings );
- this.assertions = [];
- this.testNumber = ++Test.count;
-}
-
-Test.count = 0;
-
-Test.prototype = {
- init: function() {
- var a, b, li,
- tests = id( "qunit-tests" );
-
- if ( tests ) {
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml;
-
- // `a` initialized at top of scope
- a = document.createElement( "a" );
- a.innerHTML = "Rerun";
- a.href = QUnit.url({ testNumber: this.testNumber });
-
- li = document.createElement( "li" );
- li.appendChild( b );
- li.appendChild( a );
- li.className = "running";
- li.id = this.id = "qunit-test-output" + testId++;
-
- tests.appendChild( li );
- }
- },
- setup: function() {
- if ( this.module !== config.previousModule ) {
- if ( config.previousModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.previousModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
- config.previousModule = this.module;
- config.moduleStats = { all: 0, bad: 0 };
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- } else if ( config.autorun ) {
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- }
-
- config.current = this;
-
- this.testEnvironment = extend({
- setup: function() {},
- teardown: function() {}
- }, this.moduleTestEnvironment );
-
- this.started = +new Date();
- runLoggingCallbacks( "testStart", QUnit, {
- name: this.testName,
- module: this.module
- });
-
- // allow utility functions to access the current test environment
- // TODO why??
- QUnit.current_testEnvironment = this.testEnvironment;
-
- if ( !config.pollution ) {
- saveGlobal();
- }
- if ( config.notrycatch ) {
- this.testEnvironment.setup.call( this.testEnvironment );
- return;
- }
- try {
- this.testEnvironment.setup.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Setup failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- },
- run: function() {
- config.current = this;
-
- var running = id( "qunit-testresult" );
-
- if ( running ) {
- running.innerHTML = "Running:
" + this.nameHtml;
- }
-
- if ( this.async ) {
- QUnit.stop();
- }
-
- this.callbackStarted = +new Date();
-
- if ( config.notrycatch ) {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- return;
- }
-
- try {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- } catch( e ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
-
- QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + " " + this.stack + ": " + ( e.message || e ), extractStacktrace( e, 0 ) );
- // else next test will carry the responsibility
- saveGlobal();
-
- // Restart the tests if they're blocking
- if ( config.blocking ) {
- QUnit.start();
- }
- }
- },
- teardown: function() {
- config.current = this;
- if ( config.notrycatch ) {
- if ( typeof this.callbackRuntime === "undefined" ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
- }
- this.testEnvironment.teardown.call( this.testEnvironment );
- return;
- } else {
- try {
- this.testEnvironment.teardown.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Teardown failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- }
- checkPollution();
- },
- finish: function() {
- config.current = this;
- if ( config.requireExpects && this.expected === null ) {
- QUnit.pushFailure( "Expected number of assertions to be defined, but expect() was not called.", this.stack );
- } else if ( this.expected !== null && this.expected !== this.assertions.length ) {
- QUnit.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack );
- } else if ( this.expected === null && !this.assertions.length ) {
- QUnit.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions.", this.stack );
- }
-
- var i, assertion, a, b, time, li, ol,
- test = this,
- good = 0,
- bad = 0,
- tests = id( "qunit-tests" );
-
- this.runtime = +new Date() - this.started;
- config.stats.all += this.assertions.length;
- config.moduleStats.all += this.assertions.length;
-
- if ( tests ) {
- ol = document.createElement( "ol" );
- ol.className = "qunit-assert-list";
-
- for ( i = 0; i < this.assertions.length; i++ ) {
- assertion = this.assertions[i];
-
- li = document.createElement( "li" );
- li.className = assertion.result ? "pass" : "fail";
- li.innerHTML = assertion.message || ( assertion.result ? "okay" : "failed" );
- ol.appendChild( li );
-
- if ( assertion.result ) {
- good++;
- } else {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
-
- // store result when possible
- if ( QUnit.config.reorder && defined.sessionStorage ) {
- if ( bad ) {
- sessionStorage.setItem( "qunit-test-" + this.module + "-" + this.testName, bad );
- } else {
- sessionStorage.removeItem( "qunit-test-" + this.module + "-" + this.testName );
- }
- }
-
- if ( bad === 0 ) {
- addClass( ol, "qunit-collapsed" );
- }
-
- // `b` initialized at top of scope
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml + " (" + bad + ", " + good + ", " + this.assertions.length + ")";
-
- addEvent(b, "click", function() {
- var next = b.parentNode.lastChild,
- collapsed = hasClass( next, "qunit-collapsed" );
- ( collapsed ? removeClass : addClass )( next, "qunit-collapsed" );
- });
-
- addEvent(b, "dblclick", function( e ) {
- var target = e && e.target ? e.target : window.event.srcElement;
- if ( target.nodeName.toLowerCase() === "span" || target.nodeName.toLowerCase() === "b" ) {
- target = target.parentNode;
- }
- if ( window.location && target.nodeName.toLowerCase() === "strong" ) {
- window.location = QUnit.url({ testNumber: test.testNumber });
- }
- });
-
- // `time` initialized at top of scope
- time = document.createElement( "span" );
- time.className = "runtime";
- time.innerHTML = this.runtime + " ms";
-
- // `li` initialized at top of scope
- li = id( this.id );
- li.className = bad ? "fail" : "pass";
- li.removeChild( li.firstChild );
- a = li.firstChild;
- li.appendChild( b );
- li.appendChild( a );
- li.appendChild( time );
- li.appendChild( ol );
-
- } else {
- for ( i = 0; i < this.assertions.length; i++ ) {
- if ( !this.assertions[i].result ) {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
- }
-
- runLoggingCallbacks( "testDone", QUnit, {
- name: this.testName,
- module: this.module,
- failed: bad,
- passed: this.assertions.length - bad,
- total: this.assertions.length,
- duration: this.runtime
- });
-
- QUnit.reset();
-
- config.current = undefined;
- },
-
- queue: function() {
- var bad,
- test = this;
-
- synchronize(function() {
- test.init();
- });
- function run() {
- // each of these can by async
- synchronize(function() {
- test.setup();
- });
- synchronize(function() {
- test.run();
- });
- synchronize(function() {
- test.teardown();
- });
- synchronize(function() {
- test.finish();
- });
- }
-
- // `bad` initialized at top of scope
- // defer when previous test run passed, if storage is available
- bad = QUnit.config.reorder && defined.sessionStorage &&
- +sessionStorage.getItem( "qunit-test-" + this.module + "-" + this.testName );
-
- if ( bad ) {
- run();
- } else {
- synchronize( run, true );
- }
- }
-};
-
-// Root QUnit object.
-// `QUnit` initialized at top of scope
-QUnit = {
-
- // call on start of module test to prepend name to all tests
- module: function( name, testEnvironment ) {
- config.currentModule = name;
- config.currentModuleTestEnvironment = testEnvironment;
- config.modules[name] = true;
- },
-
- asyncTest: function( testName, expected, callback ) {
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- QUnit.test( testName, expected, callback, true );
- },
-
- test: function( testName, expected, callback, async ) {
- var test,
- nameHtml = "" + escapeText( testName ) + "";
-
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- if ( config.currentModule ) {
- nameHtml = "" + escapeText( config.currentModule ) + ": " + nameHtml;
- }
-
- test = new Test({
- nameHtml: nameHtml,
- testName: testName,
- expected: expected,
- async: async,
- callback: callback,
- module: config.currentModule,
- moduleTestEnvironment: config.currentModuleTestEnvironment,
- stack: sourceFromStacktrace( 2 )
- });
-
- if ( !validTest( test ) ) {
- return;
- }
-
- test.queue();
- },
-
- // Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through.
- expect: function( asserts ) {
- if (arguments.length === 1) {
- config.current.expected = asserts;
- } else {
- return config.current.expected;
- }
- },
-
- start: function( count ) {
- // QUnit hasn't been initialized yet.
- // Note: RequireJS (et al) may delay onLoad
- if ( config.semaphore === undefined ) {
- QUnit.begin(function() {
- // This is triggered at the top of QUnit.load, push start() to the event loop, to allow QUnit.load to finish first
- setTimeout(function() {
- QUnit.start( count );
- });
- });
- return;
- }
-
- config.semaphore -= count || 1;
- // don't start until equal number of stop-calls
- if ( config.semaphore > 0 ) {
- return;
- }
- // ignore if start is called more often then stop
- if ( config.semaphore < 0 ) {
- config.semaphore = 0;
- QUnit.pushFailure( "Called start() while already started (QUnit.config.semaphore was 0 already)", null, sourceFromStacktrace(2) );
- return;
- }
- // A slight delay, to avoid any current callbacks
- if ( defined.setTimeout ) {
- window.setTimeout(function() {
- if ( config.semaphore > 0 ) {
- return;
- }
- if ( config.timeout ) {
- clearTimeout( config.timeout );
- }
-
- config.blocking = false;
- process( true );
- }, 13);
- } else {
- config.blocking = false;
- process( true );
- }
- },
-
- stop: function( count ) {
- config.semaphore += count || 1;
- config.blocking = true;
-
- if ( config.testTimeout && defined.setTimeout ) {
- clearTimeout( config.timeout );
- config.timeout = window.setTimeout(function() {
- QUnit.ok( false, "Test timed out" );
- config.semaphore = 1;
- QUnit.start();
- }, config.testTimeout );
- }
- }
-};
-
-// `assert` initialized at top of scope
-// Asssert helpers
-// All of these must either call QUnit.push() or manually do:
-// - runLoggingCallbacks( "log", .. );
-// - config.current.assertions.push({ .. });
-// We attach it to the QUnit object *after* we expose the public API,
-// otherwise `assert` will become a global variable in browsers (#341).
-assert = {
- /**
- * Asserts rough true-ish result.
- * @name ok
- * @function
- * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" );
- */
- ok: function( result, msg ) {
- if ( !config.current ) {
- throw new Error( "ok() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
- result = !!result;
-
- var source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: msg
- };
-
- msg = escapeText( msg || (result ? "okay" : "failed" ) );
- msg = "" + msg + "";
-
- if ( !result ) {
- source = sourceFromStacktrace( 2 );
- if ( source ) {
- details.source = source;
- msg += "Source: | " + escapeText( source ) + " |
---|
";
- }
- }
- runLoggingCallbacks( "log", QUnit, details );
- config.current.assertions.push({
- result: result,
- message: msg
- });
- },
-
- /**
- * Assert that the first two arguments are equal, with an optional message.
- * Prints out both actual and expected values.
- * @name equal
- * @function
- * @example equal( format( "Received {0} bytes.", 2), "Received 2 bytes.", "format() replaces {0} with next argument" );
- */
- equal: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected == actual, actual, expected, message );
- },
-
- /**
- * @name notEqual
- * @function
- */
- notEqual: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected != actual, actual, expected, message );
- },
-
- /**
- * @name propEqual
- * @function
- */
- propEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notPropEqual
- * @function
- */
- notPropEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name deepEqual
- * @function
- */
- deepEqual: function( actual, expected, message ) {
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notDeepEqual
- * @function
- */
- notDeepEqual: function( actual, expected, message ) {
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name strictEqual
- * @function
- */
- strictEqual: function( actual, expected, message ) {
- QUnit.push( expected === actual, actual, expected, message );
- },
-
- /**
- * @name notStrictEqual
- * @function
- */
- notStrictEqual: function( actual, expected, message ) {
- QUnit.push( expected !== actual, actual, expected, message );
- },
-
- "throws": function( block, expected, message ) {
- var actual,
- expectedOutput = expected,
- ok = false;
-
- // 'expected' is optional
- if ( typeof expected === "string" ) {
- message = expected;
- expected = null;
- }
-
- config.current.ignoreGlobalErrors = true;
- try {
- block.call( config.current.testEnvironment );
- } catch (e) {
- actual = e;
- }
- config.current.ignoreGlobalErrors = false;
-
- if ( actual ) {
- // we don't want to validate thrown error
- if ( !expected ) {
- ok = true;
- expectedOutput = null;
- // expected is a regexp
- } else if ( QUnit.objectType( expected ) === "regexp" ) {
- ok = expected.test( errorString( actual ) );
- // expected is a constructor
- } else if ( actual instanceof expected ) {
- ok = true;
- // expected is a validation function which returns true is validation passed
- } else if ( expected.call( {}, actual ) === true ) {
- expectedOutput = null;
- ok = true;
- }
-
- QUnit.push( ok, actual, expectedOutput, message );
- } else {
- QUnit.pushFailure( message, null, 'No exception was thrown.' );
- }
- }
-};
-
-/**
- * @deprecate since 1.8.0
- * Kept assertion helpers in root for backwards compatibility.
- */
-extend( QUnit, assert );
-
-/**
- * @deprecated since 1.9.0
- * Kept root "raises()" for backwards compatibility.
- * (Note that we don't introduce assert.raises).
- */
-QUnit.raises = assert[ "throws" ];
-
-/**
- * @deprecated since 1.0.0, replaced with error pushes since 1.3.0
- * Kept to avoid TypeErrors for undefined methods.
- */
-QUnit.equals = function() {
- QUnit.push( false, false, false, "QUnit.equals has been deprecated since 2009 (e88049a0), use QUnit.equal instead" );
-};
-QUnit.same = function() {
- QUnit.push( false, false, false, "QUnit.same has been deprecated since 2009 (e88049a0), use QUnit.deepEqual instead" );
-};
-
-// We want access to the constructor's prototype
-(function() {
- function F() {}
- F.prototype = QUnit;
- QUnit = new F();
- // Make F QUnit's constructor so that we can add to the prototype later
- QUnit.constructor = F;
-}());
-
-/**
- * Config object: Maintain internal state
- * Later exposed as QUnit.config
- * `config` initialized at top of scope
- */
-config = {
- // The queue of tests to run
- queue: [],
-
- // block until document ready
- blocking: true,
-
- // when enabled, show only failing tests
- // gets persisted through sessionStorage and can be changed in UI via checkbox
- hidepassed: false,
-
- // by default, run previously failed tests first
- // very useful in combination with "Hide passed tests" checked
- reorder: true,
-
- // by default, modify document.title when suite is done
- altertitle: true,
-
- // when enabled, all tests must call expect()
- requireExpects: false,
-
- // add checkboxes that are persisted in the query-string
- // when enabled, the id is set to `true` as a `QUnit.config` property
- urlConfig: [
- {
- id: "noglobals",
- label: "Check for Globals",
- tooltip: "Enabling this will test if any test introduces new properties on the `window` object. Stored as query-strings."
- },
- {
- id: "notrycatch",
- label: "No try-catch",
- tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging exceptions in IE reasonable. Stored as query-strings."
- }
- ],
-
- // Set of all modules.
- modules: {},
-
- // logging callback queues
- begin: [],
- done: [],
- log: [],
- testStart: [],
- testDone: [],
- moduleStart: [],
- moduleDone: []
-};
-
-// Export global variables, unless an 'exports' object exists,
-// in that case we assume we're in CommonJS (dealt with on the bottom of the script)
-if ( typeof exports === "undefined" ) {
- extend( window, QUnit );
-
- // Expose QUnit object
- window.QUnit = QUnit;
-}
-
-// Initialize more QUnit.config and QUnit.urlParams
-(function() {
- var i,
- location = window.location || { search: "", protocol: "file:" },
- params = location.search.slice( 1 ).split( "&" ),
- length = params.length,
- urlParams = {},
- current;
-
- if ( params[ 0 ] ) {
- for ( i = 0; i < length; i++ ) {
- current = params[ i ].split( "=" );
- current[ 0 ] = decodeURIComponent( current[ 0 ] );
- // allow just a key to turn on a flag, e.g., test.html?noglobals
- current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true;
- urlParams[ current[ 0 ] ] = current[ 1 ];
- }
- }
-
- QUnit.urlParams = urlParams;
-
- // String search anywhere in moduleName+testName
- config.filter = urlParams.filter;
-
- // Exact match of the module name
- config.module = urlParams.module;
-
- config.testNumber = parseInt( urlParams.testNumber, 10 ) || null;
-
- // Figure out if we're running the tests from a server or not
- QUnit.isLocal = location.protocol === "file:";
-}());
-
-// Extend QUnit object,
-// these after set here because they should not be exposed as global functions
-extend( QUnit, {
- assert: assert,
-
- config: config,
-
- // Initialize the configuration options
- init: function() {
- extend( config, {
- stats: { all: 0, bad: 0 },
- moduleStats: { all: 0, bad: 0 },
- started: +new Date(),
- updateRate: 1000,
- blocking: false,
- autostart: true,
- autorun: false,
- filter: "",
- queue: [],
- semaphore: 1
- });
-
- var tests, banner, result,
- qunit = id( "qunit" );
-
- if ( qunit ) {
- qunit.innerHTML =
- "" +
- "" +
- "" +
- "" +
- "
";
- }
-
- tests = id( "qunit-tests" );
- banner = id( "qunit-banner" );
- result = id( "qunit-testresult" );
-
- if ( tests ) {
- tests.innerHTML = "";
- }
-
- if ( banner ) {
- banner.className = "";
- }
-
- if ( result ) {
- result.parentNode.removeChild( result );
- }
-
- if ( tests ) {
- result = document.createElement( "p" );
- result.id = "qunit-testresult";
- result.className = "result";
- tests.parentNode.insertBefore( result, tests );
- result.innerHTML = "Running...
";
- }
- },
-
- // Resets the test setup. Useful for tests that modify the DOM.
- reset: function() {
- var fixture = id( "qunit-fixture" );
- if ( fixture ) {
- fixture.innerHTML = config.fixture;
- }
- },
-
- // Trigger an event on an element.
- // @example triggerEvent( document.body, "click" );
- triggerEvent: function( elem, type, event ) {
- if ( document.createEvent ) {
- event = document.createEvent( "MouseEvents" );
- event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView,
- 0, 0, 0, 0, 0, false, false, false, false, 0, null);
-
- elem.dispatchEvent( event );
- } else if ( elem.fireEvent ) {
- elem.fireEvent( "on" + type );
- }
- },
-
- // Safe object type checking
- is: function( type, obj ) {
- return QUnit.objectType( obj ) === type;
- },
-
- objectType: function( obj ) {
- if ( typeof obj === "undefined" ) {
- return "undefined";
- // consider: typeof null === object
- }
- if ( obj === null ) {
- return "null";
- }
-
- var match = toString.call( obj ).match(/^\[object\s(.*)\]$/),
- type = match && match[1] || "";
-
- switch ( type ) {
- case "Number":
- if ( isNaN(obj) ) {
- return "nan";
- }
- return "number";
- case "String":
- case "Boolean":
- case "Array":
- case "Date":
- case "RegExp":
- case "Function":
- return type.toLowerCase();
- }
- if ( typeof obj === "object" ) {
- return "object";
- }
- return undefined;
- },
-
- push: function( result, actual, expected, message ) {
- if ( !config.current ) {
- throw new Error( "assertion outside test context, was " + sourceFromStacktrace() );
- }
-
- var output, source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: message,
- actual: actual,
- expected: expected
- };
-
- message = escapeText( message ) || ( result ? "okay" : "failed" );
- message = "" + message + "";
- output = message;
-
- if ( !result ) {
- expected = escapeText( QUnit.jsDump.parse(expected) );
- actual = escapeText( QUnit.jsDump.parse(actual) );
- output += "Expected: | " + expected + " |
";
-
- if ( actual !== expected ) {
- output += "Result: | " + actual + " |
";
- output += "Diff: | " + QUnit.diff( expected, actual ) + " |
";
- }
-
- source = sourceFromStacktrace();
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
- }
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: !!result,
- message: output
- });
- },
-
- pushFailure: function( message, source, actual ) {
- if ( !config.current ) {
- throw new Error( "pushFailure() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
-
- var output,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: false,
- message: message
- };
-
- message = escapeText( message ) || "error";
- message = "" + message + "";
- output = message;
-
- output += "";
-
- if ( actual ) {
- output += "Result: | " + escapeText( actual ) + " |
";
- }
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: false,
- message: output
- });
- },
-
- url: function( params ) {
- params = extend( extend( {}, QUnit.urlParams ), params );
- var key,
- querystring = "?";
-
- for ( key in params ) {
- if ( !hasOwn.call( params, key ) ) {
- continue;
- }
- querystring += encodeURIComponent( key ) + "=" +
- encodeURIComponent( params[ key ] ) + "&";
- }
- return window.location.protocol + "//" + window.location.host +
- window.location.pathname + querystring.slice( 0, -1 );
- },
-
- extend: extend,
- id: id,
- addEvent: addEvent
- // load, equiv, jsDump, diff: Attached later
-});
-
-/**
- * @deprecated: Created for backwards compatibility with test runner that set the hook function
- * into QUnit.{hook}, instead of invoking it and passing the hook function.
- * QUnit.constructor is set to the empty F() above so that we can add to it's prototype here.
- * Doing this allows us to tell if the following methods have been overwritten on the actual
- * QUnit object.
- */
-extend( QUnit.constructor.prototype, {
-
- // Logging callbacks; all receive a single argument with the listed properties
- // run test/logs.html for any related changes
- begin: registerLoggingCallback( "begin" ),
-
- // done: { failed, passed, total, runtime }
- done: registerLoggingCallback( "done" ),
-
- // log: { result, actual, expected, message }
- log: registerLoggingCallback( "log" ),
-
- // testStart: { name }
- testStart: registerLoggingCallback( "testStart" ),
-
- // testDone: { name, failed, passed, total, duration }
- testDone: registerLoggingCallback( "testDone" ),
-
- // moduleStart: { name }
- moduleStart: registerLoggingCallback( "moduleStart" ),
-
- // moduleDone: { name, failed, passed, total }
- moduleDone: registerLoggingCallback( "moduleDone" )
-});
-
-if ( typeof document === "undefined" || document.readyState === "complete" ) {
- config.autorun = true;
-}
-
-QUnit.load = function() {
- runLoggingCallbacks( "begin", QUnit, {} );
-
- // Initialize the config, saving the execution queue
- var banner, filter, i, label, len, main, ol, toolbar, userAgent, val,
- urlConfigCheckboxesContainer, urlConfigCheckboxes, moduleFilter,
- numModules = 0,
- moduleFilterHtml = "",
- urlConfigHtml = "",
- oldconfig = extend( {}, config );
-
- QUnit.init();
- extend(config, oldconfig);
-
- config.blocking = false;
-
- len = config.urlConfig.length;
-
- for ( i = 0; i < len; i++ ) {
- val = config.urlConfig[i];
- if ( typeof val === "string" ) {
- val = {
- id: val,
- label: val,
- tooltip: "[no tooltip available]"
- };
- }
- config[ val.id ] = QUnit.urlParams[ val.id ];
- urlConfigHtml += "";
- }
-
- moduleFilterHtml += "";
-
- // `userAgent` initialized at top of scope
- userAgent = id( "qunit-userAgent" );
- if ( userAgent ) {
- userAgent.innerHTML = navigator.userAgent;
- }
-
- // `banner` initialized at top of scope
- banner = id( "qunit-header" );
- if ( banner ) {
- banner.innerHTML = "" + banner.innerHTML + " ";
- }
-
- // `toolbar` initialized at top of scope
- toolbar = id( "qunit-testrunner-toolbar" );
- if ( toolbar ) {
- // `filter` initialized at top of scope
- filter = document.createElement( "input" );
- filter.type = "checkbox";
- filter.id = "qunit-filter-pass";
-
- addEvent( filter, "click", function() {
- var tmp,
- ol = document.getElementById( "qunit-tests" );
-
- if ( filter.checked ) {
- ol.className = ol.className + " hidepass";
- } else {
- tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " ";
- ol.className = tmp.replace( / hidepass /, " " );
- }
- if ( defined.sessionStorage ) {
- if (filter.checked) {
- sessionStorage.setItem( "qunit-filter-passed-tests", "true" );
- } else {
- sessionStorage.removeItem( "qunit-filter-passed-tests" );
- }
- }
- });
-
- if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem( "qunit-filter-passed-tests" ) ) {
- filter.checked = true;
- // `ol` initialized at top of scope
- ol = document.getElementById( "qunit-tests" );
- ol.className = ol.className + " hidepass";
- }
- toolbar.appendChild( filter );
-
- // `label` initialized at top of scope
- label = document.createElement( "label" );
- label.setAttribute( "for", "qunit-filter-pass" );
- label.setAttribute( "title", "Only show tests and assertons that fail. Stored in sessionStorage." );
- label.innerHTML = "Hide passed tests";
- toolbar.appendChild( label );
-
- urlConfigCheckboxesContainer = document.createElement("span");
- urlConfigCheckboxesContainer.innerHTML = urlConfigHtml;
- urlConfigCheckboxes = urlConfigCheckboxesContainer.getElementsByTagName("input");
- // For oldIE support:
- // * Add handlers to the individual elements instead of the container
- // * Use "click" instead of "change"
- // * Fallback from event.target to event.srcElement
- addEvents( urlConfigCheckboxes, "click", function( event ) {
- var params = {},
- target = event.target || event.srcElement;
- params[ target.name ] = target.checked ? true : undefined;
- window.location = QUnit.url( params );
- });
- toolbar.appendChild( urlConfigCheckboxesContainer );
-
- if (numModules > 1) {
- moduleFilter = document.createElement( 'span' );
- moduleFilter.setAttribute( 'id', 'qunit-modulefilter-container' );
- moduleFilter.innerHTML = moduleFilterHtml;
- addEvent( moduleFilter.lastChild, "change", function() {
- var selectBox = moduleFilter.getElementsByTagName("select")[0],
- selectedModule = decodeURIComponent(selectBox.options[selectBox.selectedIndex].value);
-
- window.location = QUnit.url( { module: ( selectedModule === "" ) ? undefined : selectedModule } );
- });
- toolbar.appendChild(moduleFilter);
- }
- }
-
- // `main` initialized at top of scope
- main = id( "qunit-fixture" );
- if ( main ) {
- config.fixture = main.innerHTML;
- }
-
- if ( config.autostart ) {
- QUnit.start();
- }
-};
-
-addEvent( window, "load", QUnit.load );
-
-// `onErrorFnPrev` initialized at top of scope
-// Preserve other handlers
-onErrorFnPrev = window.onerror;
-
-// Cover uncaught exceptions
-// Returning true will surpress the default browser handler,
-// returning false will let it run.
-window.onerror = function ( error, filePath, linerNr ) {
- var ret = false;
- if ( onErrorFnPrev ) {
- ret = onErrorFnPrev( error, filePath, linerNr );
- }
-
- // Treat return value as window.onerror itself does,
- // Only do our handling if not surpressed.
- if ( ret !== true ) {
- if ( QUnit.config.current ) {
- if ( QUnit.config.current.ignoreGlobalErrors ) {
- return true;
- }
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- } else {
- QUnit.test( "global failure", extend( function() {
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- }, { validTest: validTest } ) );
- }
- return false;
- }
-
- return ret;
-};
-
-function done() {
- config.autorun = true;
-
- // Log the last module results
- if ( config.currentModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.currentModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
-
- var i, key,
- banner = id( "qunit-banner" ),
- tests = id( "qunit-tests" ),
- runtime = +new Date() - config.started,
- passed = config.stats.all - config.stats.bad,
- html = [
- "Tests completed in ",
- runtime,
- " milliseconds.
",
- "",
- passed,
- " assertions of ",
- config.stats.all,
- " passed, ",
- config.stats.bad,
- " failed."
- ].join( "" );
-
- if ( banner ) {
- banner.className = ( config.stats.bad ? "qunit-fail" : "qunit-pass" );
- }
-
- if ( tests ) {
- id( "qunit-testresult" ).innerHTML = html;
- }
-
- if ( config.altertitle && typeof document !== "undefined" && document.title ) {
- // show ✖ for good, ✔ for bad suite result in title
- // use escape sequences in case file gets loaded with non-utf-8-charset
- document.title = [
- ( config.stats.bad ? "\u2716" : "\u2714" ),
- document.title.replace( /^[\u2714\u2716] /i, "" )
- ].join( " " );
- }
-
- // clear own sessionStorage items if all tests passed
- if ( config.reorder && defined.sessionStorage && config.stats.bad === 0 ) {
- // `key` & `i` initialized at top of scope
- for ( i = 0; i < sessionStorage.length; i++ ) {
- key = sessionStorage.key( i++ );
- if ( key.indexOf( "qunit-test-" ) === 0 ) {
- sessionStorage.removeItem( key );
- }
- }
- }
-
- // scroll back to top to show results
- if ( window.scrollTo ) {
- window.scrollTo(0, 0);
- }
-
- runLoggingCallbacks( "done", QUnit, {
- failed: config.stats.bad,
- passed: passed,
- total: config.stats.all,
- runtime: runtime
- });
-}
-
-/** @return Boolean: true if this test should be ran */
-function validTest( test ) {
- var include,
- filter = config.filter && config.filter.toLowerCase(),
- module = config.module && config.module.toLowerCase(),
- fullName = (test.module + ": " + test.testName).toLowerCase();
-
- // Internally-generated tests are always valid
- if ( test.callback && test.callback.validTest === validTest ) {
- delete test.callback.validTest;
- return true;
- }
-
- if ( config.testNumber ) {
- return test.testNumber === config.testNumber;
- }
-
- if ( module && ( !test.module || test.module.toLowerCase() !== module ) ) {
- return false;
- }
-
- if ( !filter ) {
- return true;
- }
-
- include = filter.charAt( 0 ) !== "!";
- if ( !include ) {
- filter = filter.slice( 1 );
- }
-
- // If the filter matches, we need to honour include
- if ( fullName.indexOf( filter ) !== -1 ) {
- return include;
- }
-
- // Otherwise, do the opposite
- return !include;
-}
-
-// so far supports only Firefox, Chrome and Opera (buggy), Safari (for real exceptions)
-// Later Safari and IE10 are supposed to support error.stack as well
-// See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack
-function extractStacktrace( e, offset ) {
- offset = offset === undefined ? 3 : offset;
-
- var stack, include, i;
-
- if ( e.stacktrace ) {
- // Opera
- return e.stacktrace.split( "\n" )[ offset + 3 ];
- } else if ( e.stack ) {
- // Firefox, Chrome
- stack = e.stack.split( "\n" );
- if (/^error$/i.test( stack[0] ) ) {
- stack.shift();
- }
- if ( fileName ) {
- include = [];
- for ( i = offset; i < stack.length; i++ ) {
- if ( stack[ i ].indexOf( fileName ) !== -1 ) {
- break;
- }
- include.push( stack[ i ] );
- }
- if ( include.length ) {
- return include.join( "\n" );
- }
- }
- return stack[ offset ];
- } else if ( e.sourceURL ) {
- // Safari, PhantomJS
- // hopefully one day Safari provides actual stacktraces
- // exclude useless self-reference for generated Error objects
- if ( /qunit.js$/.test( e.sourceURL ) ) {
- return;
- }
- // for actual exceptions, this is useful
- return e.sourceURL + ":" + e.line;
- }
-}
-function sourceFromStacktrace( offset ) {
- try {
- throw new Error();
- } catch ( e ) {
- return extractStacktrace( e, offset );
- }
-}
-
-/**
- * Escape text for attribute or text content.
- */
-function escapeText( s ) {
- if ( !s ) {
- return "";
- }
- s = s + "";
- // Both single quotes and double quotes (for attributes)
- return s.replace( /['"<>&]/g, function( s ) {
- switch( s ) {
- case '\'':
- return ''';
- case '"':
- return '"';
- case '<':
- return '<';
- case '>':
- return '>';
- case '&':
- return '&';
- }
- });
-}
-
-function synchronize( callback, last ) {
- config.queue.push( callback );
-
- if ( config.autorun && !config.blocking ) {
- process( last );
- }
-}
-
-function process( last ) {
- function next() {
- process( last );
- }
- var start = new Date().getTime();
- config.depth = config.depth ? config.depth + 1 : 1;
-
- while ( config.queue.length && !config.blocking ) {
- if ( !defined.setTimeout || config.updateRate <= 0 || ( ( new Date().getTime() - start ) < config.updateRate ) ) {
- config.queue.shift()();
- } else {
- window.setTimeout( next, 13 );
- break;
- }
- }
- config.depth--;
- if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) {
- done();
- }
-}
-
-function saveGlobal() {
- config.pollution = [];
-
- if ( config.noglobals ) {
- for ( var key in window ) {
- // in Opera sometimes DOM element ids show up here, ignore them
- if ( !hasOwn.call( window, key ) || /^qunit-test-output/.test( key ) ) {
- continue;
- }
- config.pollution.push( key );
- }
- }
-}
-
-function checkPollution() {
- var newGlobals,
- deletedGlobals,
- old = config.pollution;
-
- saveGlobal();
-
- newGlobals = diff( config.pollution, old );
- if ( newGlobals.length > 0 ) {
- QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join(", ") );
- }
-
- deletedGlobals = diff( old, config.pollution );
- if ( deletedGlobals.length > 0 ) {
- QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join(", ") );
- }
-}
-
-// returns a new Array with the elements that are in a but not in b
-function diff( a, b ) {
- var i, j,
- result = a.slice();
-
- for ( i = 0; i < result.length; i++ ) {
- for ( j = 0; j < b.length; j++ ) {
- if ( result[i] === b[j] ) {
- result.splice( i, 1 );
- i--;
- break;
- }
- }
- }
- return result;
-}
-
-function extend( a, b ) {
- for ( var prop in b ) {
- if ( b[ prop ] === undefined ) {
- delete a[ prop ];
-
- // Avoid "Member not found" error in IE8 caused by setting window.constructor
- } else if ( prop !== "constructor" || a !== window ) {
- a[ prop ] = b[ prop ];
- }
- }
-
- return a;
-}
-
-/**
- * @param {HTMLElement} elem
- * @param {string} type
- * @param {Function} fn
- */
-function addEvent( elem, type, fn ) {
- // Standards-based browsers
- if ( elem.addEventListener ) {
- elem.addEventListener( type, fn, false );
- // IE
- } else {
- elem.attachEvent( "on" + type, fn );
- }
-}
-
-/**
- * @param {Array|NodeList} elems
- * @param {string} type
- * @param {Function} fn
- */
-function addEvents( elems, type, fn ) {
- var i = elems.length;
- while ( i-- ) {
- addEvent( elems[i], type, fn );
- }
-}
-
-function hasClass( elem, name ) {
- return (" " + elem.className + " ").indexOf(" " + name + " ") > -1;
-}
-
-function addClass( elem, name ) {
- if ( !hasClass( elem, name ) ) {
- elem.className += (elem.className ? " " : "") + name;
- }
-}
-
-function removeClass( elem, name ) {
- var set = " " + elem.className + " ";
- // Class name may appear multiple times
- while ( set.indexOf(" " + name + " ") > -1 ) {
- set = set.replace(" " + name + " " , " ");
- }
- // If possible, trim it for prettiness, but not neccecarily
- elem.className = window.jQuery ? jQuery.trim( set ) : ( set.trim ? set.trim() : set );
-}
-
-function id( name ) {
- return !!( typeof document !== "undefined" && document && document.getElementById ) &&
- document.getElementById( name );
-}
-
-function registerLoggingCallback( key ) {
- return function( callback ) {
- config[key].push( callback );
- };
-}
-
-// Supports deprecated method of completely overwriting logging callbacks
-function runLoggingCallbacks( key, scope, args ) {
- var i, callbacks;
- if ( QUnit.hasOwnProperty( key ) ) {
- QUnit[ key ].call(scope, args );
- } else {
- callbacks = config[ key ];
- for ( i = 0; i < callbacks.length; i++ ) {
- callbacks[ i ].call( scope, args );
- }
- }
-}
-
-// Test for equality any JavaScript type.
-// Author: Philippe Rathé
-QUnit.equiv = (function() {
-
- // Call the o related callback with the given arguments.
- function bindCallbacks( o, callbacks, args ) {
- var prop = QUnit.objectType( o );
- if ( prop ) {
- if ( QUnit.objectType( callbacks[ prop ] ) === "function" ) {
- return callbacks[ prop ].apply( callbacks, args );
- } else {
- return callbacks[ prop ]; // or undefined
- }
- }
- }
-
- // the real equiv function
- var innerEquiv,
- // stack to decide between skip/abort functions
- callers = [],
- // stack to avoiding loops from circular referencing
- parents = [],
-
- getProto = Object.getPrototypeOf || function ( obj ) {
- return obj.__proto__;
- },
- callbacks = (function () {
-
- // for string, boolean, number and null
- function useStrictEquality( b, a ) {
- /*jshint eqeqeq:false */
- if ( b instanceof a.constructor || a instanceof b.constructor ) {
- // to catch short annotaion VS 'new' annotation of a
- // declaration
- // e.g. var i = 1;
- // var j = new Number(1);
- return a == b;
- } else {
- return a === b;
- }
- }
-
- return {
- "string": useStrictEquality,
- "boolean": useStrictEquality,
- "number": useStrictEquality,
- "null": useStrictEquality,
- "undefined": useStrictEquality,
-
- "nan": function( b ) {
- return isNaN( b );
- },
-
- "date": function( b, a ) {
- return QUnit.objectType( b ) === "date" && a.valueOf() === b.valueOf();
- },
-
- "regexp": function( b, a ) {
- return QUnit.objectType( b ) === "regexp" &&
- // the regex itself
- a.source === b.source &&
- // and its modifers
- a.global === b.global &&
- // (gmi) ...
- a.ignoreCase === b.ignoreCase &&
- a.multiline === b.multiline &&
- a.sticky === b.sticky;
- },
-
- // - skip when the property is a method of an instance (OOP)
- // - abort otherwise,
- // initial === would have catch identical references anyway
- "function": function() {
- var caller = callers[callers.length - 1];
- return caller !== Object && typeof caller !== "undefined";
- },
-
- "array": function( b, a ) {
- var i, j, len, loop;
-
- // b could be an object literal here
- if ( QUnit.objectType( b ) !== "array" ) {
- return false;
- }
-
- len = a.length;
- if ( len !== b.length ) {
- // safe and faster
- return false;
- }
-
- // track reference to avoid circular references
- parents.push( a );
- for ( i = 0; i < len; i++ ) {
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- loop = true;// dont rewalk array
- }
- }
- if ( !loop && !innerEquiv(a[i], b[i]) ) {
- parents.pop();
- return false;
- }
- }
- parents.pop();
- return true;
- },
-
- "object": function( b, a ) {
- var i, j, loop,
- // Default to true
- eq = true,
- aProperties = [],
- bProperties = [];
-
- // comparing constructors is more strict than using
- // instanceof
- if ( a.constructor !== b.constructor ) {
- // Allow objects with no prototype to be equivalent to
- // objects with Object as their constructor.
- if ( !(( getProto(a) === null && getProto(b) === Object.prototype ) ||
- ( getProto(b) === null && getProto(a) === Object.prototype ) ) ) {
- return false;
- }
- }
-
- // stack constructor before traversing properties
- callers.push( a.constructor );
- // track reference to avoid circular references
- parents.push( a );
-
- for ( i in a ) { // be strict: don't ensures hasOwnProperty
- // and go deep
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- // don't go down the same path twice
- loop = true;
- }
- }
- aProperties.push(i); // collect a's properties
-
- if (!loop && !innerEquiv( a[i], b[i] ) ) {
- eq = false;
- break;
- }
- }
-
- callers.pop(); // unstack, we are done
- parents.pop();
-
- for ( i in b ) {
- bProperties.push( i ); // collect b's properties
- }
-
- // Ensures identical properties name
- return eq && innerEquiv( aProperties.sort(), bProperties.sort() );
- }
- };
- }());
-
- innerEquiv = function() { // can take multiple arguments
- var args = [].slice.apply( arguments );
- if ( args.length < 2 ) {
- return true; // end transition
- }
-
- return (function( a, b ) {
- if ( a === b ) {
- return true; // catch the most you can
- } else if ( a === null || b === null || typeof a === "undefined" ||
- typeof b === "undefined" ||
- QUnit.objectType(a) !== QUnit.objectType(b) ) {
- return false; // don't lose time with error prone cases
- } else {
- return bindCallbacks(a, callbacks, [ b, a ]);
- }
-
- // apply transition with (1..n) arguments
- }( args[0], args[1] ) && arguments.callee.apply( this, args.splice(1, args.length - 1 )) );
- };
-
- return innerEquiv;
-}());
-
-/**
- * jsDump Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com |
- * http://flesler.blogspot.com Licensed under BSD
- * (http://www.opensource.org/licenses/bsd-license.php) Date: 5/15/2008
- *
- * @projectDescription Advanced and extensible data dumping for Javascript.
- * @version 1.0.0
- * @author Ariel Flesler
- * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html}
- */
-QUnit.jsDump = (function() {
- function quote( str ) {
- return '"' + str.toString().replace( /"/g, '\\"' ) + '"';
- }
- function literal( o ) {
- return o + "";
- }
- function join( pre, arr, post ) {
- var s = jsDump.separator(),
- base = jsDump.indent(),
- inner = jsDump.indent(1);
- if ( arr.join ) {
- arr = arr.join( "," + s + inner );
- }
- if ( !arr ) {
- return pre + post;
- }
- return [ pre, inner + arr, base + post ].join(s);
- }
- function array( arr, stack ) {
- var i = arr.length, ret = new Array(i);
- this.up();
- while ( i-- ) {
- ret[i] = this.parse( arr[i] , undefined , stack);
- }
- this.down();
- return join( "[", ret, "]" );
- }
-
- var reName = /^function (\w+)/,
- jsDump = {
- // type is used mostly internally, you can fix a (custom)type in advance
- parse: function( obj, type, stack ) {
- stack = stack || [ ];
- var inStack, res,
- parser = this.parsers[ type || this.typeOf(obj) ];
-
- type = typeof parser;
- inStack = inArray( obj, stack );
-
- if ( inStack !== -1 ) {
- return "recursion(" + (inStack - stack.length) + ")";
- }
- if ( type === "function" ) {
- stack.push( obj );
- res = parser.call( this, obj, stack );
- stack.pop();
- return res;
- }
- return ( type === "string" ) ? parser : this.parsers.error;
- },
- typeOf: function( obj ) {
- var type;
- if ( obj === null ) {
- type = "null";
- } else if ( typeof obj === "undefined" ) {
- type = "undefined";
- } else if ( QUnit.is( "regexp", obj) ) {
- type = "regexp";
- } else if ( QUnit.is( "date", obj) ) {
- type = "date";
- } else if ( QUnit.is( "function", obj) ) {
- type = "function";
- } else if ( typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined" ) {
- type = "window";
- } else if ( obj.nodeType === 9 ) {
- type = "document";
- } else if ( obj.nodeType ) {
- type = "node";
- } else if (
- // native arrays
- toString.call( obj ) === "[object Array]" ||
- // NodeList objects
- ( typeof obj.length === "number" && typeof obj.item !== "undefined" && ( obj.length ? obj.item(0) === obj[0] : ( obj.item( 0 ) === null && typeof obj[0] === "undefined" ) ) )
- ) {
- type = "array";
- } else if ( obj.constructor === Error.prototype.constructor ) {
- type = "error";
- } else {
- type = typeof obj;
- }
- return type;
- },
- separator: function() {
- return this.multiline ? this.HTML ? "
" : "\n" : this.HTML ? " " : " ";
- },
- // extra can be a number, shortcut for increasing-calling-decreasing
- indent: function( extra ) {
- if ( !this.multiline ) {
- return "";
- }
- var chr = this.indentChar;
- if ( this.HTML ) {
- chr = chr.replace( /\t/g, " " ).replace( / /g, " " );
- }
- return new Array( this._depth_ + (extra||0) ).join(chr);
- },
- up: function( a ) {
- this._depth_ += a || 1;
- },
- down: function( a ) {
- this._depth_ -= a || 1;
- },
- setParser: function( name, parser ) {
- this.parsers[name] = parser;
- },
- // The next 3 are exposed so you can use them
- quote: quote,
- literal: literal,
- join: join,
- //
- _depth_: 1,
- // This is the list of parsers, to modify them, use jsDump.setParser
- parsers: {
- window: "[Window]",
- document: "[Document]",
- error: function(error) {
- return "Error(\"" + error.message + "\")";
- },
- unknown: "[Unknown]",
- "null": "null",
- "undefined": "undefined",
- "function": function( fn ) {
- var ret = "function",
- // functions never have name in IE
- name = "name" in fn ? fn.name : (reName.exec(fn) || [])[1];
-
- if ( name ) {
- ret += " " + name;
- }
- ret += "( ";
-
- ret = [ ret, QUnit.jsDump.parse( fn, "functionArgs" ), "){" ].join( "" );
- return join( ret, QUnit.jsDump.parse(fn,"functionCode" ), "}" );
- },
- array: array,
- nodelist: array,
- "arguments": array,
- object: function( map, stack ) {
- var ret = [ ], keys, key, val, i;
- QUnit.jsDump.up();
- keys = [];
- for ( key in map ) {
- keys.push( key );
- }
- keys.sort();
- for ( i = 0; i < keys.length; i++ ) {
- key = keys[ i ];
- val = map[ key ];
- ret.push( QUnit.jsDump.parse( key, "key" ) + ": " + QUnit.jsDump.parse( val, undefined, stack ) );
- }
- QUnit.jsDump.down();
- return join( "{", ret, "}" );
- },
- node: function( node ) {
- var len, i, val,
- open = QUnit.jsDump.HTML ? "<" : "<",
- close = QUnit.jsDump.HTML ? ">" : ">",
- tag = node.nodeName.toLowerCase(),
- ret = open + tag,
- attrs = node.attributes;
-
- if ( attrs ) {
- for ( i = 0, len = attrs.length; i < len; i++ ) {
- val = attrs[i].nodeValue;
- // IE6 includes all attributes in .attributes, even ones not explicitly set.
- // Those have values like undefined, null, 0, false, "" or "inherit".
- if ( val && val !== "inherit" ) {
- ret += " " + attrs[i].nodeName + "=" + QUnit.jsDump.parse( val, "attribute" );
- }
- }
- }
- ret += close;
-
- // Show content of TextNode or CDATASection
- if ( node.nodeType === 3 || node.nodeType === 4 ) {
- ret += node.nodeValue;
- }
-
- return ret + open + "/" + tag + close;
- },
- // function calls it internally, it's the arguments part of the function
- functionArgs: function( fn ) {
- var args,
- l = fn.length;
-
- if ( !l ) {
- return "";
- }
-
- args = new Array(l);
- while ( l-- ) {
- // 97 is 'a'
- args[l] = String.fromCharCode(97+l);
- }
- return " " + args.join( ", " ) + " ";
- },
- // object calls it internally, the key part of an item in a map
- key: quote,
- // function calls it internally, it's the content of the function
- functionCode: "[code]",
- // node calls it internally, it's an html attribute value
- attribute: quote,
- string: quote,
- date: quote,
- regexp: literal,
- number: literal,
- "boolean": literal
- },
- // if true, entities are escaped ( <, >, \t, space and \n )
- HTML: false,
- // indentation unit
- indentChar: " ",
- // if true, items in a collection, are separated by a \n, else just a space.
- multiline: true
- };
-
- return jsDump;
-}());
-
-// from jquery.js
-function inArray( elem, array ) {
- if ( array.indexOf ) {
- return array.indexOf( elem );
- }
-
- for ( var i = 0, length = array.length; i < length; i++ ) {
- if ( array[ i ] === elem ) {
- return i;
- }
- }
-
- return -1;
-}
-
-/*
- * Javascript Diff Algorithm
- * By John Resig (http://ejohn.org/)
- * Modified by Chu Alan "sprite"
- *
- * Released under the MIT license.
- *
- * More Info:
- * http://ejohn.org/projects/javascript-diff-algorithm/
- *
- * Usage: QUnit.diff(expected, actual)
- *
- * QUnit.diff( "the quick brown fox jumped over", "the quick fox jumps over" ) == "the quick brown fox jumped jumps over"
- */
-QUnit.diff = (function() {
- /*jshint eqeqeq:false, eqnull:true */
- function diff( o, n ) {
- var i,
- ns = {},
- os = {};
-
- for ( i = 0; i < n.length; i++ ) {
- if ( !hasOwn.call( ns, n[i] ) ) {
- ns[ n[i] ] = {
- rows: [],
- o: null
- };
- }
- ns[ n[i] ].rows.push( i );
- }
-
- for ( i = 0; i < o.length; i++ ) {
- if ( !hasOwn.call( os, o[i] ) ) {
- os[ o[i] ] = {
- rows: [],
- n: null
- };
- }
- os[ o[i] ].rows.push( i );
- }
-
- for ( i in ns ) {
- if ( !hasOwn.call( ns, i ) ) {
- continue;
- }
- if ( ns[i].rows.length === 1 && hasOwn.call( os, i ) && os[i].rows.length === 1 ) {
- n[ ns[i].rows[0] ] = {
- text: n[ ns[i].rows[0] ],
- row: os[i].rows[0]
- };
- o[ os[i].rows[0] ] = {
- text: o[ os[i].rows[0] ],
- row: ns[i].rows[0]
- };
- }
- }
-
- for ( i = 0; i < n.length - 1; i++ ) {
- if ( n[i].text != null && n[ i + 1 ].text == null && n[i].row + 1 < o.length && o[ n[i].row + 1 ].text == null &&
- n[ i + 1 ] == o[ n[i].row + 1 ] ) {
-
- n[ i + 1 ] = {
- text: n[ i + 1 ],
- row: n[i].row + 1
- };
- o[ n[i].row + 1 ] = {
- text: o[ n[i].row + 1 ],
- row: i + 1
- };
- }
- }
-
- for ( i = n.length - 1; i > 0; i-- ) {
- if ( n[i].text != null && n[ i - 1 ].text == null && n[i].row > 0 && o[ n[i].row - 1 ].text == null &&
- n[ i - 1 ] == o[ n[i].row - 1 ]) {
-
- n[ i - 1 ] = {
- text: n[ i - 1 ],
- row: n[i].row - 1
- };
- o[ n[i].row - 1 ] = {
- text: o[ n[i].row - 1 ],
- row: i - 1
- };
- }
- }
-
- return {
- o: o,
- n: n
- };
- }
-
- return function( o, n ) {
- o = o.replace( /\s+$/, "" );
- n = n.replace( /\s+$/, "" );
-
- var i, pre,
- str = "",
- out = diff( o === "" ? [] : o.split(/\s+/), n === "" ? [] : n.split(/\s+/) ),
- oSpace = o.match(/\s+/g),
- nSpace = n.match(/\s+/g);
-
- if ( oSpace == null ) {
- oSpace = [ " " ];
- }
- else {
- oSpace.push( " " );
- }
-
- if ( nSpace == null ) {
- nSpace = [ " " ];
- }
- else {
- nSpace.push( " " );
- }
-
- if ( out.n.length === 0 ) {
- for ( i = 0; i < out.o.length; i++ ) {
- str += "" + out.o[i] + oSpace[i] + "";
- }
- }
- else {
- if ( out.n[0].text == null ) {
- for ( n = 0; n < out.o.length && out.o[n].text == null; n++ ) {
- str += "" + out.o[n] + oSpace[n] + "";
- }
- }
-
- for ( i = 0; i < out.n.length; i++ ) {
- if (out.n[i].text == null) {
- str += "" + out.n[i] + nSpace[i] + "";
- }
- else {
- // `pre` initialized at top of scope
- pre = "";
-
- for ( n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++ ) {
- pre += "" + out.o[n] + oSpace[n] + "";
- }
- str += " " + out.n[i].text + nSpace[i] + pre;
- }
- }
- }
-
- return str;
- };
-}());
-
-// for CommonJS enviroments, export everything
-if ( typeof exports !== "undefined" ) {
- extend( exports, QUnit );
-}
-
-// get at whatever the global object is, like window in browsers
-}( (function() {return this;}.call()) ));
diff --git a/test/lib/require.js b/test/lib/require.js
deleted file mode 100644
index 987f865..0000000
--- a/test/lib/require.js
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- RequireJS 2.1.5 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.
- Available via the MIT or new BSD license.
- see: http://github.com/jrburke/requirejs for details
-*/
-var requirejs,require,define;
-(function(aa){function I(b){return"[object Function]"===L.call(b)}function J(b){return"[object Array]"===L.call(b)}function y(b,c){if(b){var d;for(d=0;dthis.depCount&&!this.defined){if(I(n)){if(this.events.error)try{e=i.execCb(c,n,b,e)}catch(d){a=d}else e=i.execCb(c,n,b,e);this.map.isDefine&&((b=this.module)&&void 0!==b.exports&&b.exports!==this.exports?e=b.exports:void 0===e&&this.usingExports&&(e=this.exports));if(a)return a.requireMap=this.map,a.requireModules=[this.map.id],a.requireType="define",v(this.error=
-a)}else e=n;this.exports=e;if(this.map.isDefine&&!this.ignore&&(q[c]=e,l.onResourceLoad))l.onResourceLoad(i,this.map,this.depMaps);x(c);this.defined=!0}this.defining=!1;this.defined&&!this.defineEmitted&&(this.defineEmitted=!0,this.emit("defined",this.exports),this.defineEmitComplete=!0)}}else this.fetch()}},callPlugin:function(){var a=this.map,b=a.id,d=j(a.prefix);this.depMaps.push(d);t(d,"defined",u(this,function(e){var n,d;d=this.map.name;var g=this.map.parentMap?this.map.parentMap.name:null,h=
-i.makeRequire(a.parentMap,{enableBuildCallback:!0});if(this.map.unnormalized){if(e.normalize&&(d=e.normalize(d,function(a){return c(a,g,!0)})||""),e=j(a.prefix+"!"+d,this.map.parentMap),t(e,"defined",u(this,function(a){this.init([],function(){return a},null,{enabled:!0,ignore:!0})})),d=m(p,e.id)){this.depMaps.push(e);if(this.events.error)d.on("error",u(this,function(a){this.emit("error",a)}));d.enable()}}else n=u(this,function(a){this.init([],function(){return a},null,{enabled:!0})}),n.error=u(this,
-function(a){this.inited=!0;this.error=a;a.requireModules=[b];G(p,function(a){0===a.map.id.indexOf(b+"_unnormalized")&&x(a.map.id)});v(a)}),n.fromText=u(this,function(e,c){var d=a.name,g=j(d),C=O;c&&(e=c);C&&(O=!1);r(g);s(k.config,b)&&(k.config[d]=k.config[b]);try{l.exec(e)}catch(ca){return v(B("fromtexteval","fromText eval for "+b+" failed: "+ca,ca,[b]))}C&&(O=!0);this.depMaps.push(g);i.completeLoad(d);h([d],n)}),e.load(a.name,h,n,k)}));i.enable(d,this);this.pluginMaps[d.id]=d},enable:function(){V[this.map.id]=
-this;this.enabling=this.enabled=!0;y(this.depMaps,u(this,function(a,b){var c,e;if("string"===typeof a){a=j(a,this.map.isDefine?this.map:this.map.parentMap,!1,!this.skipMap);this.depMaps[b]=a;if(c=m(N,a.id)){this.depExports[b]=c(this);return}this.depCount+=1;t(a,"defined",u(this,function(a){this.defineDep(b,a);this.check()}));this.errback&&t(a,"error",this.errback)}c=a.id;e=p[c];!s(N,c)&&(e&&!e.enabled)&&i.enable(a,this)}));G(this.pluginMaps,u(this,function(a){var b=m(p,a.id);b&&!b.enabled&&i.enable(a,
-this)}));this.enabling=!1;this.check()},on:function(a,b){var c=this.events[a];c||(c=this.events[a]=[]);c.push(b)},emit:function(a,b){y(this.events[a],function(a){a(b)});"error"===a&&delete this.events[a]}};i={config:k,contextName:b,registry:p,defined:q,urlFetched:U,defQueue:H,Module:Z,makeModuleMap:j,nextTick:l.nextTick,onError:v,configure:function(a){a.baseUrl&&"/"!==a.baseUrl.charAt(a.baseUrl.length-1)&&(a.baseUrl+="/");var b=k.pkgs,c=k.shim,e={paths:!0,config:!0,map:!0};G(a,function(a,b){e[b]?
-"map"===b?(k.map||(k.map={}),R(k[b],a,!0,!0)):R(k[b],a,!0):k[b]=a});a.shim&&(G(a.shim,function(a,b){J(a)&&(a={deps:a});if((a.exports||a.init)&&!a.exportsFn)a.exportsFn=i.makeShimExports(a);c[b]=a}),k.shim=c);a.packages&&(y(a.packages,function(a){a="string"===typeof a?{name:a}:a;b[a.name]={name:a.name,location:a.location||a.name,main:(a.main||"main").replace(ja,"").replace(ea,"")}}),k.pkgs=b);G(p,function(a,b){!a.inited&&!a.map.unnormalized&&(a.map=j(b))});if(a.deps||a.callback)i.require(a.deps||[],
-a.callback)},makeShimExports:function(a){return function(){var b;a.init&&(b=a.init.apply(aa,arguments));return b||a.exports&&ba(a.exports)}},makeRequire:function(a,f){function d(e,c,h){var g,k;f.enableBuildCallback&&(c&&I(c))&&(c.__requireJsBuild=!0);if("string"===typeof e){if(I(c))return v(B("requireargs","Invalid require call"),h);if(a&&s(N,e))return N[e](p[a.id]);if(l.get)return l.get(i,e,a,d);g=j(e,a,!1,!0);g=g.id;return!s(q,g)?v(B("notloaded",'Module name "'+g+'" has not been loaded yet for context: '+
-b+(a?"":". Use require([])"))):q[g]}L();i.nextTick(function(){L();k=r(j(null,a));k.skipMap=f.skipMap;k.init(e,c,h,{enabled:!0});D()});return d}f=f||{};R(d,{isBrowser:A,toUrl:function(b){var d,f=b.lastIndexOf("."),g=b.split("/")[0];if(-1!==f&&(!("."===g||".."===g)||1h.attachEvent.toString().indexOf("[native code"))&&!Y?(O=!0,h.attachEvent("onreadystatechange",b.onScriptLoad)):(h.addEventListener("load",b.onScriptLoad,!1),h.addEventListener("error",b.onScriptError,!1)),h.src=d,K=h,D?x.insertBefore(h,D):x.appendChild(h),K=null,h;if(da)try{importScripts(d),b.completeLoad(c)}catch(j){b.onError(B("importscripts","importScripts failed for "+c+" at "+d,j,[c]))}};A&&M(document.getElementsByTagName("script"),function(b){x||(x=
-b.parentNode);if(t=b.getAttribute("data-main"))return r.baseUrl||(E=t.split("/"),Q=E.pop(),fa=E.length?E.join("/")+"/":"./",r.baseUrl=fa,t=Q),t=t.replace(ea,""),r.deps=r.deps?r.deps.concat(t):[t],!0});define=function(b,c,d){var l,h;"string"!==typeof b&&(d=c,c=b,b=null);J(c)||(d=c,c=[]);!c.length&&I(d)&&d.length&&(d.toString().replace(la,"").replace(ma,function(b,d){c.push(d)}),c=(1===d.length?["require"]:["require","exports","module"]).concat(c));if(O){if(!(l=K))P&&"interactive"===P.readyState||M(document.getElementsByTagName("script"),
-function(b){if("interactive"===b.readyState)return P=b}),l=P;l&&(b||(b=l.getAttribute("data-requiremodule")),h=F[l.getAttribute("data-requirecontext")])}(h?h.defQueue:T).push([b,c,d])};define.amd={jQuery:!0};l.exec=function(b){return eval(b)};l(r)}})(this);
diff --git a/test/lib/resemble.js b/test/lib/resemble.js
new file mode 100644
index 0000000..1cb8c29
--- /dev/null
+++ b/test/lib/resemble.js
@@ -0,0 +1,535 @@
+/*
+Author: James Cryer
+Company: Huddle
+Last updated date: 21 Feb 2013
+URL: https://github.com/Huddle/Resemble.js
+*/
+
+(function(_this){
+ 'use strict';
+
+ _this['resemble'] = function( fileData ){
+
+ var data = {};
+ var images = [];
+ var updateCallbackArray = [];
+
+ var tolerance = { // between 0 and 255
+ red: 16,
+ green: 16,
+ blue: 16,
+ minBrightness: 16,
+ maxBrightness: 240
+ };
+
+ var ignoreAntialiasing = false;
+ var ignoreColors = false;
+
+ function triggerDataUpdate(){
+ var len = updateCallbackArray.length;
+ var i;
+ for(i=0;i tolerance.maxBrightness;
+ }
+
+ function getHue(r,g,b){
+
+ r = r / 255;
+ g = g / 255;
+ b = b / 255;
+ var max = Math.max(r, g, b), min = Math.min(r, g, b);
+ var h;
+ var d;
+
+ if (max == min){
+ h = 0; // achromatic
+ } else{
+ d = max - min;
+ switch(max){
+ case r: h = (g - b) / d + (g < b ? 6 : 0); break;
+ case g: h = (b - r) / d + 2; break;
+ case b: h = (r - g) / d + 4; break;
+ }
+ h /= 6;
+ }
+
+ return h;
+ }
+
+ function isAntialiased(sourcePix, data, cacheSet, verticalPos, horizontalPos, width){
+ var offset;
+ var targetPix;
+ var distance = 1;
+ var i;
+ var j;
+ var hasHighContrastSibling = 0;
+ var hasSiblingWithDifferentHue = 0;
+ var hasEquivilantSibling = 0;
+
+ addHueInfo(sourcePix);
+
+ for (i = distance*-1; i <= distance; i++){
+ for (j = distance*-1; j <= distance; j++){
+
+ if(i===0 && j===0){
+ // ignore source pixel
+ } else {
+
+ offset = ((verticalPos+j)*width + (horizontalPos+i)) * 4;
+ targetPix = getPixelInfo(data, offset, cacheSet);
+
+ if(targetPix === null){
+ continue;
+ }
+
+ addBrightnessInfo(targetPix);
+ addHueInfo(targetPix);
+
+ if( isContrasting(sourcePix, targetPix) ){
+ hasHighContrastSibling++;
+ }
+
+ if( isRGBSame(sourcePix,targetPix) ){
+ hasEquivilantSibling++;
+ }
+
+ if( Math.abs(targetPix.h - sourcePix.h) > 0.3 ){
+ hasSiblingWithDifferentHue++;
+ }
+
+ if( hasSiblingWithDifferentHue > 1 || hasHighContrastSibling > 1){
+ return true;
+ }
+ }
+ }
+ }
+
+ if(hasEquivilantSibling < 2){
+ return true;
+ }
+
+ return false;
+ }
+
+ function errorPixel(px, offset){
+ px[offset] = 255; //r
+ px[offset + 1] = 0; //g
+ px[offset + 2] = 255; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyPixel(px, offset, data){
+ px[offset] = data.r; //r
+ px[offset + 1] = data.g; //g
+ px[offset + 2] = data.b; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyGrayScalePixel(px, offset, data){
+ px[offset] = data.brightness; //r
+ px[offset + 1] = data.brightness; //g
+ px[offset + 2] = data.brightness; //b
+ px[offset + 3] = 255; //a
+ }
+
+
+ function getPixelInfo(data, offset, cacheSet){
+ var r;
+ var g;
+ var b;
+ var d;
+
+ if(typeof data[offset] !== 'undefined'){
+ r = data[offset];
+ g = data[offset+1];
+ b = data[offset+2];
+ d = {
+ r: r,
+ g: g,
+ b: b
+ };
+
+ return d;
+ } else {
+ return null;
+ }
+ }
+
+ function addBrightnessInfo(data){
+ data.brightness = getBrightness(data.r,data.g,data.b); // 'corrected' lightness
+ }
+
+ function addHueInfo(data){
+ data.h = getHue(data.r,data.g,data.b);
+ }
+
+ function analyseImages(img1, img2, width, height){
+
+ var hiddenCanvas = document.createElement('canvas');
+
+ var data1 = img1.data;
+ var data2 = img2.data;
+
+ hiddenCanvas.width = width;
+ hiddenCanvas.height = height;
+
+ var context = hiddenCanvas.getContext('2d');
+ var imgd = context.createImageData(width,height);
+ var targetPix = imgd.data;
+
+ var mismatchCount = 0;
+
+ var time = Date.now();
+
+ var skip;
+
+ if( (width > 1200 || height > 1200) && ignoreAntialiasing){
+ skip = 6;
+ }
+
+ loop(height, width, function(verticalPos, horizontalPos){
+
+ if(skip){ // only skip if the image isn't small
+ if(verticalPos % skip === 0 || horizontalPos % skip === 0){
+ return;
+ }
+ }
+
+ var offset = (verticalPos*width + horizontalPos) * 4;
+ var pixel1 = getPixelInfo(data1, offset, 1);
+ var pixel2 = getPixelInfo(data2, offset, 2);
+
+ if(pixel1 === null || pixel2 === null){
+ return;
+ }
+
+ if (ignoreColors){
+
+ addBrightnessInfo(pixel1);
+ addBrightnessInfo(pixel2);
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ return;
+ }
+
+ if( isRGBSimilar(pixel1, pixel2) ){
+ copyPixel(targetPix, offset, pixel2);
+
+ } else if( ignoreAntialiasing && (
+ addBrightnessInfo(pixel1), // jit pixel info augmentation looks a little weird, sorry.
+ addBrightnessInfo(pixel2),
+ isAntialiased(pixel1, data1, 1, verticalPos, horizontalPos, width) ||
+ isAntialiased(pixel2, data2, 2, verticalPos, horizontalPos, width)
+ )){
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+
+ });
+
+ data.misMatchPercentage = (mismatchCount / (height*width) * 100).toFixed(2);
+ data.analysisTime = Date.now() - time;
+
+ data.getImageDataUrl = function(text){
+ var barHeight = 0;
+
+ if(text){
+ barHeight = addLabel(text,context,hiddenCanvas);
+ }
+
+ context.putImageData(imgd, 0, barHeight);
+
+ return hiddenCanvas.toDataURL("image/png");
+ };
+ }
+
+ function addLabel(text, context, hiddenCanvas){
+ var textPadding = 2;
+
+ context.font = '12px sans-serif';
+
+ var textWidth = context.measureText(text).width + textPadding*2;
+ var barHeight = 22;
+
+ if(textWidth > hiddenCanvas.width){
+ hiddenCanvas.width = textWidth;
+ }
+
+ hiddenCanvas.height += barHeight;
+
+ context.fillStyle = "#666";
+ context.fillRect(0,0,hiddenCanvas.width,barHeight -4);
+ context.fillStyle = "#fff";
+ context.fillRect(0,barHeight -4,hiddenCanvas.width, 4);
+
+ context.fillStyle = "#fff";
+ context.textBaseline = "top";
+ context.font = '12px sans-serif';
+ context.fillText(text, textPadding, 1);
+
+ return barHeight;
+ }
+
+ function normalise(img, w, h){
+ var c;
+ var context;
+
+ if(img.height < h || img.width < w){
+ c = document.createElement('canvas');
+ c.width = w;
+ c.height = h;
+ context = c.getContext('2d');
+ context.putImageData(img, 0, 0);
+ return context.getImageData(0, 0, w, h);
+ }
+
+ return img;
+ }
+
+ function compare(one, two){
+
+ function onceWeHaveBoth(){
+ var width;
+ var height;
+ if(images.length === 2){
+ width = images[0].width > images[1].width ? images[0].width : images[1].width;
+ height = images[0].height > images[1].height ? images[0].height : images[1].height;
+
+ if( (images[0].width === images[1].width) && (images[0].height === images[1].height) ){
+ data.isSameDimensions = true;
+ } else {
+ data.isSameDimensions = false;
+ }
+
+ analyseImages( normalise(images[0],width, height), normalise(images[1],width, height), width, height);
+
+ triggerDataUpdate();
+ }
+ }
+
+ images = [];
+ loadImageData(one, onceWeHaveBoth);
+ loadImageData(two, onceWeHaveBoth);
+ }
+
+ function getCompareApi(param){
+
+ var secondFileData,
+ hasMethod = typeof param === 'function';
+
+ if( !hasMethod ){
+ // assume it's file data
+ secondFileData = param;
+ }
+
+ var self = {
+ ignoreNothing: function(){
+
+ tolerance.red = 16;
+ tolerance.green = 16;
+ tolerance.blue = 16;
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreAntialiasing: function(){
+
+ tolerance.red = 32;
+ tolerance.green = 32;
+ tolerance.blue = 32;
+ tolerance.minBrightness = 64;
+ tolerance.maxBrightness = 96;
+
+ ignoreAntialiasing = true;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreColors: function(){
+
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = true;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ onComplete: function( callback ){
+
+ updateCallbackArray.push(callback);
+
+ var wrapper = function(){
+ compare(fileData, secondFileData);
+ };
+
+ wrapper();
+
+ return getCompareApi(wrapper);
+ }
+ };
+
+ return self;
+ }
+
+ return {
+ onComplete: function( callback ){
+ updateCallbackArray.push(callback);
+ loadImageData(fileData, function(imageData, width, height){
+ parseImage(imageData.data, width, height);
+ });
+ },
+ compareTo: function(secondFileData){
+ return getCompareApi(secondFileData);
+ }
+ };
+
+ };
+}(this));
\ No newline at end of file
diff --git a/test/testsuite.js b/test/testsuite.js
deleted file mode 100644
index b486acb..0000000
--- a/test/testsuite.js
+++ /dev/null
@@ -1,36 +0,0 @@
-requirejs.config({
- baseUrl: '/test/unit/'
-});
-
-define(function(require) {
- var testModules = [
- 'Pixi',
- 'Point',
- 'Rectangle',
- 'DisplayObject',
- 'DisplayObjectContainer',
- 'Sprite',
- 'MovieClip',
- 'InteractionManager',
- 'Stage',
- 'utils/Utils',
- 'utils/EventTarget',
- 'utils/Matrix',
- 'utils/Detector',
- 'renderers/WebGLShaders',
- 'renderers/WebGLRenderer',
- 'renderers/WebGLBatch',
- 'renderers/CanvasRenderer',
- 'extras/Strip',
- 'extras/Rope',
- 'textures/BaseTexture',
- 'textures/Texture',
- 'loaders/SpriteSheetLoader',
- 'loaders/AssetLoader'
- ];
-
- // Resolve all testModules and then start the Test Runner.
- require(testModules, function() {
- QUnit.start();
- });
-});
\ No newline at end of file
diff --git a/test/textures/SpriteSheet-Aliens.png b/test/textures/SpriteSheet-Aliens.png
new file mode 100644
index 0000000..210acb1
--- /dev/null
+++ b/test/textures/SpriteSheet-Aliens.png
Binary files differ
diff --git a/test/textures/SpriteSheet-Explosion.png b/test/textures/SpriteSheet-Explosion.png
new file mode 100755
index 0000000..79e1a69
--- /dev/null
+++ b/test/textures/SpriteSheet-Explosion.png
Binary files differ
diff --git a/test/textures/bunny.png b/test/textures/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/textures/bunny.png
Binary files differ
diff --git a/test/unit/DisplayObject.js b/test/unit/DisplayObject.js
deleted file mode 100644
index 5e7e72f..0000000
--- a/test/unit/DisplayObject.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObject');
-});
diff --git a/test/unit/DisplayObjectContainer.js b/test/unit/DisplayObjectContainer.js
deleted file mode 100644
index b323959..0000000
--- a/test/unit/DisplayObjectContainer.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObjectContainer');
-});
diff --git a/test/unit/InteractionManager.js b/test/unit/InteractionManager.js
deleted file mode 100644
index e751f52..0000000
--- a/test/unit/InteractionManager.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('InteractionManager');
-});
diff --git a/test/unit/MovieClip.js b/test/unit/MovieClip.js
deleted file mode 100644
index 37d9446..0000000
--- a/test/unit/MovieClip.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('MovieClip');
-});
diff --git a/test/unit/Pixi.js b/test/unit/Pixi.js
deleted file mode 100644
index 36eee73..0000000
--- a/test/unit/Pixi.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Pixi');
-});
diff --git a/test/unit/Point.js b/test/unit/Point.js
deleted file mode 100644
index 983ff6e..0000000
--- a/test/unit/Point.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Point');
-});
diff --git a/test/unit/Rectangle.js b/test/unit/Rectangle.js
deleted file mode 100644
index 3b439ba..0000000
--- a/test/unit/Rectangle.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Rectangle');
-});
diff --git a/test/unit/Sprite.js b/test/unit/Sprite.js
deleted file mode 100644
index ed4f596..0000000
--- a/test/unit/Sprite.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Sprite');
-});
diff --git a/test/unit/Stage.js b/test/unit/Stage.js
deleted file mode 100644
index 2d70291..0000000
--- a/test/unit/Stage.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Stage');
-});
diff --git a/test/unit/extras/Rope.js b/test/unit/extras/Rope.js
deleted file mode 100644
index 5606f14..0000000
--- a/test/unit/extras/Rope.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Rope');
-});
diff --git a/test/unit/extras/Strip.js b/test/unit/extras/Strip.js
deleted file mode 100644
index 0134d3a..0000000
--- a/test/unit/extras/Strip.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Strip');
-});
diff --git a/test/unit/loaders/AssetLoader.js b/test/unit/loaders/AssetLoader.js
deleted file mode 100644
index 13b8443..0000000
--- a/test/unit/loaders/AssetLoader.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('AssetLoader');
-});
diff --git a/test/unit/loaders/SpriteSheetLoader.js b/test/unit/loaders/SpriteSheetLoader.js
deleted file mode 100644
index 8bf0cb2..0000000
--- a/test/unit/loaders/SpriteSheetLoader.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('SpriteSheetLoader');
-});
diff --git a/test/unit/pixi/InteractionManager.js b/test/unit/pixi/InteractionManager.js
new file mode 100644
index 0000000..ed3001f
--- /dev/null
+++ b/test/unit/pixi/InteractionManager.js
@@ -0,0 +1,10 @@
+describe('pixi/InteractionManager', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var InteractionManager = PIXI.InteractionManager;
+
+ it('Module exists', function () {
+ expect(InteractionManager).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/Pixi.js b/test/unit/pixi/Pixi.js
new file mode 100644
index 0000000..27debc1
--- /dev/null
+++ b/test/unit/pixi/Pixi.js
@@ -0,0 +1,9 @@
+describe('pixi/Pixi', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+
+ it('Module exists', function () {
+ expect(global).to.have.property('PIXI').and.to.be.an('object');
+ });
+});
diff --git a/test/unit/pixi/core/Circle.js b/test/unit/pixi/core/Circle.js
new file mode 100644
index 0000000..93a4456
--- /dev/null
+++ b/test/unit/pixi/core/Circle.js
@@ -0,0 +1,22 @@
+describe('pixi/core/Circle', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Circle = PIXI.Circle;
+
+ it('Module exists', function () {
+ expect(Circle).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Circle();
+
+ expect(obj).to.be.an.instanceof(Circle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', 0);
+ expect(obj).to.have.property('y', 0);
+ expect(obj).to.have.property('radius', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Ellipse.js b/test/unit/pixi/core/Ellipse.js
new file mode 100644
index 0000000..026b56f
--- /dev/null
+++ b/test/unit/pixi/core/Ellipse.js
@@ -0,0 +1,24 @@
+describe('pixi/core/Ellipse', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Ellipse = PIXI.Ellipse;
+
+ it('Module exists', function () {
+ expect(Ellipse).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Ellipse();
+
+ expect(obj).to.be.an.instanceof(Ellipse);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+ expect(obj).to.respondTo('getBounds');
+
+ expect(obj).to.have.property('x', 0);
+ expect(obj).to.have.property('y', 0);
+ expect(obj).to.have.property('width', 0);
+ expect(obj).to.have.property('height', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Matrix.js b/test/unit/pixi/core/Matrix.js
new file mode 100644
index 0000000..b48989e
--- /dev/null
+++ b/test/unit/pixi/core/Matrix.js
@@ -0,0 +1,30 @@
+describe('pixi/core/Matrix', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var mat3 = PIXI.mat3;
+ var mat4 = PIXI.mat4;
+ var Matrix = PIXI.Matrix;
+
+ it('Ensure determineMatrixArrayType works', function () {
+ expect(Matrix).to.be.a('function');
+ });
+
+ it('mat3 exists', function () {
+ expect(mat3).to.be.an('object');
+ });
+
+ it('Confirm new mat3 matrix', function () {
+ var matrix = new mat3.create();
+ pixi_core_Matrix_confirmNewMat3(matrix);
+ });
+
+ it('mat3 exists', function () {
+ expect(mat4).to.be.an('object');
+ });
+
+ it('Confirm new mat4 matrix', function () {
+ var matrix = new mat4.create();
+ pixi_core_Matrix_confirmNewMat4(matrix);
+ });
+});
diff --git a/test/unit/pixi/core/Point.js b/test/unit/pixi/core/Point.js
new file mode 100644
index 0000000..c4d5163
--- /dev/null
+++ b/test/unit/pixi/core/Point.js
@@ -0,0 +1,15 @@
+describe('pixi/core/Point', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Point = PIXI.Point;
+
+ it('Module exists', function () {
+ expect(Point).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Point();
+ pixi_core_Point_confirm(obj, 0, 0);
+ });
+});
diff --git a/test/unit/pixi/core/Polygon.js b/test/unit/pixi/core/Polygon.js
new file mode 100644
index 0000000..dc8c918
--- /dev/null
+++ b/test/unit/pixi/core/Polygon.js
@@ -0,0 +1,20 @@
+describe('pixi/core/Polygon', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Polygon = PIXI.Polygon;
+
+ it('Module exists', function () {
+ expect(Polygon).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Polygon();
+
+ expect(obj).to.be.an.instanceof(Polygon);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.deep.property('points.length', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Rectangle.js b/test/unit/pixi/core/Rectangle.js
new file mode 100644
index 0000000..d43316e
--- /dev/null
+++ b/test/unit/pixi/core/Rectangle.js
@@ -0,0 +1,15 @@
+describe('pixi/core/Rectangle', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Rectangle = PIXI.Rectangle;
+
+ it('Module exists', function () {
+ expect(Rectangle).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var rect = new Rectangle();
+ pixi_core_Rectangle_confirm(rect, 0, 0, 0, 0);
+ });
+});
diff --git a/test/unit/pixi/display/DisplayObject.js b/test/unit/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..40c6fbc
--- /dev/null
+++ b/test/unit/pixi/display/DisplayObject.js
@@ -0,0 +1,21 @@
+describe('pixi/display/DisplayObject', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var DisplayObject = PIXI.DisplayObject;
+
+ it('Module exists', function () {
+ expect(DisplayObject).to.be.a('function');
+ expect(PIXI).to.have.property('visibleCount', 0);
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new DisplayObject();
+
+ pixi_display_DisplayObject_confirmNew(obj);
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', false);
+ expect(obj).to.have.property('stage', null);
+ });
+});
diff --git a/test/unit/pixi/display/DisplayObjectContainer.js b/test/unit/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..ce7f02f
--- /dev/null
+++ b/test/unit/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,20 @@
+describe('pixi/display/DisplayObjectContainer', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var DisplayObjectContainer = PIXI.DisplayObjectContainer;
+
+ it('Module exists', function () {
+ expect(DisplayObjectContainer).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new DisplayObjectContainer();
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', false);
+ expect(obj).to.have.property('stage', null);
+ });
+});
diff --git a/test/unit/pixi/display/MovieClip.js b/test/unit/pixi/display/MovieClip.js
new file mode 100644
index 0000000..f3c6c6a
--- /dev/null
+++ b/test/unit/pixi/display/MovieClip.js
@@ -0,0 +1,33 @@
+describe('pixi/display/MovieClip', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var MovieClip = PIXI.MovieClip;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(MovieClip).to.be.a('function');
+ });
+
+ it('Confirm new instance', function (done) {
+ var texture = Texture.fromImage('/base/test/textures/SpriteSheet-Explosion.png');
+ var obj = new MovieClip([texture]);
+
+ pixi_display_Sprite_confirmNew(obj, done);
+
+ expect(obj).to.be.an.instanceof(MovieClip);
+ expect(obj).to.respondTo('stop');
+ expect(obj).to.respondTo('play');
+ expect(obj).to.respondTo('gotoAndStop');
+ expect(obj).to.respondTo('gotoAndPlay');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('textures.length', 1);
+ expect(obj).to.have.deep.property('textures[0]', texture);
+ expect(obj).to.have.property('animationSpeed', 1);
+ expect(obj).to.have.property('loop', true);
+ expect(obj).to.have.property('onComplete', null);
+ expect(obj).to.have.property('currentFrame', 0);
+ expect(obj).to.have.property('playing', false);
+ });
+});
diff --git a/test/unit/pixi/display/Sprite.js b/test/unit/pixi/display/Sprite.js
new file mode 100644
index 0000000..54e914f
--- /dev/null
+++ b/test/unit/pixi/display/Sprite.js
@@ -0,0 +1,25 @@
+describe('pixi/display/Sprite', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Sprite = PIXI.Sprite;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(Sprite).to.be.a('function');
+ expect(PIXI).to.have.deep.property('blendModes.NORMAL', 0);
+ expect(PIXI).to.have.deep.property('blendModes.SCREEN', 1);
+ });
+
+ it('Members exist', function () {
+ expect(Sprite).itself.to.respondTo('fromImage');
+ expect(Sprite).itself.to.respondTo('fromFrame');
+ });
+
+ it('Confirm new instance', function (done) {
+ var texture = Texture.fromImage('/base/test/textures/SpriteSheet-Aliens.png');
+ var obj = new Sprite(texture);
+
+ pixi_display_Sprite_confirmNew(obj, done);
+ });
+});
diff --git a/test/unit/pixi/display/Stage.js b/test/unit/pixi/display/Stage.js
new file mode 100644
index 0000000..3cc2a4d
--- /dev/null
+++ b/test/unit/pixi/display/Stage.js
@@ -0,0 +1,49 @@
+describe('pixi/display/Stage', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Stage = PIXI.Stage;
+ var InteractionManager = PIXI.InteractionManager;
+ var Rectangle = PIXI.Rectangle;
+
+ it('Module exists', function () {
+ expect(Stage).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Stage(null, true);
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(Stage);
+ expect(obj).to.respondTo('updateTransform');
+ expect(obj).to.respondTo('setBackgroundColor');
+ expect(obj).to.respondTo('getMousePosition');
+
+ // FIXME: duplicate member in DisplayObject
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ // FIXME: convert arg to bool in constructor
+ expect(obj).to.have.property('interactive', true);
+
+ expect(obj).to.have.property('interactionManager')
+ .and.to.be.an.instanceof(InteractionManager)
+ .and.to.have.property('stage', obj);
+
+ expect(obj).to.have.property('dirty', true);
+
+ expect(obj).to.have.property('stage', obj);
+
+ expect(obj).to.have.property('hitArea')
+ .and.to.be.an.instanceof(Rectangle);
+ pixi_core_Rectangle_confirm(obj.hitArea, 0, 0, 100000, 100000);
+
+ expect(obj).to.have.property('backgroundColor', 0x000000);
+ expect(obj).to.have.deep.property('backgroundColorSplit.length', 3);
+ expect(obj).to.have.deep.property('backgroundColorSplit[0]', 0);
+ expect(obj).to.have.deep.property('backgroundColorSplit[1]', 0);
+ expect(obj).to.have.deep.property('backgroundColorSplit[2]', 0);
+ expect(obj).to.have.property('backgroundColorString', '#000000');
+
+ expect(obj).to.have.property('worldVisible', true);
+ });
+});
diff --git a/test/unit/pixi/extras/CustomRenderable.js b/test/unit/pixi/extras/CustomRenderable.js
new file mode 100644
index 0000000..8d83cf0
--- /dev/null
+++ b/test/unit/pixi/extras/CustomRenderable.js
@@ -0,0 +1,21 @@
+describe('pixi/extras/CustomRenderable', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var CustomRenderable = PIXI.CustomRenderable;
+
+ it('Module exists', function () {
+ expect(CustomRenderable).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new CustomRenderable();
+
+ pixi_display_DisplayObject_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(CustomRenderable);
+ expect(obj).to.respondTo('renderCanvas');
+ expect(obj).to.respondTo('initWebGL');
+ expect(obj).to.respondTo('renderWebGL');
+ });
+});
diff --git a/test/unit/pixi/extras/Rope.js b/test/unit/pixi/extras/Rope.js
new file mode 100644
index 0000000..6ddaf83
--- /dev/null
+++ b/test/unit/pixi/extras/Rope.js
@@ -0,0 +1,26 @@
+describe('pixi/extras/Rope', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Rope = PIXI.Rope;
+ var Texture = PIXI.Texture;
+ var Point = PIXI.Point;
+
+ it('Module exists', function () {
+ expect(Rope).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var texture = Texture.fromImage('/base/test/textures/bunny.png');
+ var obj = new Rope(texture, [new Point(), new Point(5, 10), new Point(10, 20)]);
+
+ pixi_extras_Strip_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(Rope);
+ expect(obj).to.respondTo('refresh');
+ expect(obj).to.respondTo('updateTransform');
+ expect(obj).to.respondTo('setTexture');
+
+ // TODO: Test properties
+ });
+});
diff --git a/test/unit/pixi/extras/Spine.js b/test/unit/pixi/extras/Spine.js
new file mode 100644
index 0000000..0708bc0
--- /dev/null
+++ b/test/unit/pixi/extras/Spine.js
@@ -0,0 +1,10 @@
+describe('pixi/extras/Spine', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Spine = PIXI.Spine;
+
+ it('Module exists', function () {
+ expect(Spine).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/extras/Strip.js b/test/unit/pixi/extras/Strip.js
new file mode 100644
index 0000000..8e564e1
--- /dev/null
+++ b/test/unit/pixi/extras/Strip.js
@@ -0,0 +1,18 @@
+describe('pixi/extras/Strip', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Strip = PIXI.Strip;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(Strip).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var texture = Texture.fromImage('/base/test/textures/bunny.png');
+ var obj = new Strip(texture, 20, 10000);
+
+ pixi_extras_Strip_confirmNew(obj);
+ });
+});
diff --git a/test/unit/pixi/extras/TilingSprite.js b/test/unit/pixi/extras/TilingSprite.js
new file mode 100644
index 0000000..56aea14
--- /dev/null
+++ b/test/unit/pixi/extras/TilingSprite.js
@@ -0,0 +1,24 @@
+describe('pixi/extras/TilingSprite', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var TilingSprite = PIXI.TilingSprite;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(TilingSprite).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var texture = Texture.fromImage('/base/test/textures/bunny.png');
+ var obj = new TilingSprite(texture, 6000, 12000);
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(TilingSprite);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ // TODO: Test properties
+ });
+});
diff --git a/test/unit/pixi/filters/FilterBlock.js b/test/unit/pixi/filters/FilterBlock.js
new file mode 100644
index 0000000..870cec0
--- /dev/null
+++ b/test/unit/pixi/filters/FilterBlock.js
@@ -0,0 +1,10 @@
+describe('pixi/filters/FilterBlock', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var FilterBlock = PIXI.FilterBlock;
+
+ it('Module exists', function () {
+ expect(FilterBlock).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/filters/MaskFilter.js b/test/unit/pixi/filters/MaskFilter.js
new file mode 100644
index 0000000..32d6a45
--- /dev/null
+++ b/test/unit/pixi/filters/MaskFilter.js
@@ -0,0 +1,10 @@
+describe('pixi/filters/MaskFilter', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ // var MaskFilter = PIXI.MaskFilter;
+
+ // it('Module exists', function () {
+ // expect(MaskFilter).to.be.a('function');
+ // });
+});
diff --git a/test/unit/pixi/loaders/AssetLoader.js b/test/unit/pixi/loaders/AssetLoader.js
new file mode 100644
index 0000000..a0aa0b5
--- /dev/null
+++ b/test/unit/pixi/loaders/AssetLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/AssetLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var AssetLoader = PIXI.AssetLoader;
+
+ it('Module exists', function () {
+ expect(AssetLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/BitmapFontLoader.js b/test/unit/pixi/loaders/BitmapFontLoader.js
new file mode 100644
index 0000000..6253c42
--- /dev/null
+++ b/test/unit/pixi/loaders/BitmapFontLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/BitmapFontLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var BitmapFontLoader = PIXI.BitmapFontLoader;
+
+ it('Module exists', function () {
+ expect(PIXI.BitmapFontLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/ImageLoader.js b/test/unit/pixi/loaders/ImageLoader.js
new file mode 100644
index 0000000..8b1f556
--- /dev/null
+++ b/test/unit/pixi/loaders/ImageLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/ImageLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var ImageLoader = PIXI.ImageLoader;
+
+ it('Module exists', function () {
+ expect(ImageLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/JsonLoader.js b/test/unit/pixi/loaders/JsonLoader.js
new file mode 100644
index 0000000..c577e83
--- /dev/null
+++ b/test/unit/pixi/loaders/JsonLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/JsonLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var JsonLoader = PIXI.JsonLoader;
+
+ it('Module exists', function () {
+ expect(JsonLoader).to.be.a('function');
+ });
+});
diff --git a/.gitignore b/.gitignore
index 12e1b62..0b88317 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
node_modules
.DS_Store
-.project
\ No newline at end of file
+.project
+*.log
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..63e4d7c
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,8 @@
+language: node_js
+node_js:
+ - 0.10
+
+before_script:
+ - npm install -g grunt-cli
+ - export DISPLAY=:99.0
+ - sh -e /etc/init.d/xvfb start
diff --git a/Gruntfile.js b/Gruntfile.js
index b083b49..103938c 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -1,10 +1,12 @@
+'use strict';
+
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-connect');
- grunt.loadNpmTasks('grunt-contrib-qunit');
grunt.loadNpmTasks('grunt-contrib-yuidoc');
+ grunt.loadTasks('tasks');
var root = 'src/pixi/',
debug = 'bin/pixi.dev.js',
@@ -79,7 +81,7 @@
},
files: {
srcBlob: '<%= dirs.src %>/**/*.js',
- testBlob: '<%= dirs.test %>/unit/**/*.js',
+ testBlob: '<%= dirs.test %>/{functional,lib/pixi,unit}/**/*.js',
build: '<%= dirs.build %>/pixi.dev.js',
buildMin: '<%= dirs.build %>/pixi.js'
},
@@ -94,7 +96,12 @@
},
jshint: {
beforeconcat: srcFiles,
- test: ['<%= files.testBlob %>'],
+ test: {
+ src: ['<%= files.testBlob %>'],
+ options: {
+ expr: true
+ }
+ },
options: {
asi: true,
smarttabs: true
@@ -128,12 +135,6 @@
]
},
connect: {
- qunit: {
- options: {
- port: grunt.option('port-test') || 9002,
- base: './'
- }
- },
test: {
options: {
port: grunt.option('port-test') || 9002,
@@ -142,13 +143,6 @@
}
}
},
- qunit: {
- all: {
- options: {
- urls: ['http://localhost:' + (grunt.option('port-test') || 9002) + '/test/index.html']
- }
- }
- },
yuidoc: {
compile: {
name: '<%= pkg.name %>',
@@ -161,6 +155,13 @@
outdir: '<%= dirs.docs %>'
}
}
+ },
+ karma: {
+ unit: {
+ configFile: 'test/karma.conf.js',
+ // browsers: ['Chrome'],
+ singleRun: true
+ }
}
});
@@ -182,9 +183,10 @@
}
)
- grunt.registerTask('default', ['concat', 'uglify', 'distribute']);
grunt.registerTask('build', ['concat', 'uglify', 'distribute']);
- grunt.registerTask('test', ['build', 'connect:qunit', 'qunit']);
+ grunt.registerTask('test', ['concat', 'jshint:test', 'karma']);
grunt.registerTask('docs', ['yuidoc']);
-
-}
\ No newline at end of file
+ grunt.registerTask('default', ['test', 'uglify', 'distribute']);
+ // Travis CI task.
+ grunt.registerTask('travis', ['test']);
+}
diff --git a/README.md b/README.md
index c62ef86..690cfe4 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,8 @@

+[](http://travis-ci.org/drkibitz/pixi.js)
+
#### JavaScript 2D Renderer ####
The aim of this project is to provide a fast lightweight 2D library that works
diff --git a/package.json b/package.json
index b373240..1246a68 100644
--- a/package.json
+++ b/package.json
@@ -18,14 +18,21 @@
"main": "bin/pixi.js",
+ "scripts": {
+ "test": "grunt travis --verbose"
+ },
+
"dependencies": {},
"devDependencies": {
"grunt": "~0.4.x",
- "grunt-contrib-jshint": "0.3.x",
+ "grunt-contrib-jshint": "0.6.x",
"grunt-contrib-uglify": "0.2.x",
- "grunt-contrib-connect": "0.2.x",
- "grunt-contrib-qunit": "0.2.x",
+ "grunt-contrib-connect": "0.3.x",
"grunt-contrib-yuidoc": "0.4.x",
- "grunt-contrib-concat": "0.1.x"
+ "grunt-contrib-concat": "0.3.x",
+ "chai": "~1.7.0",
+ "karma": "0.11.0",
+ "karma-firefox-launcher": "0.1.0",
+ "karma-mocha": "0.1.0"
}
}
diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js
index a7c520e..ee82bbd 100644
--- a/src/pixi/InteractionManager.js
+++ b/src/pixi/InteractionManager.js
@@ -62,7 +62,6 @@
this.onTouchEnd = this.onTouchEnd.bind(this);
this.onTouchMove = this.onTouchMove.bind(this);
-
this.last = 0;
}
diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js
index 1a95d20..eef1059 100644
--- a/src/pixi/core/Ellipse.js
+++ b/src/pixi/core/Ellipse.js
@@ -78,7 +78,7 @@
return (normx + normy < 0.25);
}
-PIXI.Ellipse.getBounds = function()
+PIXI.Ellipse.prototype.getBounds = function()
{
return new PIXI.Rectangle(this.x, this.y, this.width, this.height);
}
diff --git a/tasks/karma.js b/tasks/karma.js
new file mode 100644
index 0000000..c340485
--- /dev/null
+++ b/tasks/karma.js
@@ -0,0 +1,27 @@
+'use strict';
+
+var path = require('path');
+var server = require('karma').server;
+
+module.exports = function (grunt) {
+ grunt.registerMultiTask('karma', 'run karma.', function() {
+ var done = this.async();
+ var options = this.options({
+ background: false
+ });
+ var data = this.data;
+
+ //merge options onto data, with data taking precedence
+ data = grunt.util._.merge(options, data);
+ data.configFile = path.resolve(data.configFile);
+ if (data.configFile) {
+ data.configFile = grunt.template.process(data.configFile);
+ }
+
+ server.start(
+ data,
+ function(code) {
+ done(!code);
+ });
+ });
+};
diff --git a/test/functional/example-1-basics/bunny.png b/test/functional/example-1-basics/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/functional/example-1-basics/bunny.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-30.png b/test/functional/example-1-basics/frame-30.png
new file mode 100644
index 0000000..96e3409
--- /dev/null
+++ b/test/functional/example-1-basics/frame-30.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-60.png b/test/functional/example-1-basics/frame-60.png
new file mode 100644
index 0000000..af3f4ce
--- /dev/null
+++ b/test/functional/example-1-basics/frame-60.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-90.png b/test/functional/example-1-basics/frame-90.png
new file mode 100644
index 0000000..099b823
--- /dev/null
+++ b/test/functional/example-1-basics/frame-90.png
Binary files differ
diff --git a/test/functional/example-1-basics/index.js b/test/functional/example-1-basics/index.js
new file mode 100644
index 0000000..7ae7a98
--- /dev/null
+++ b/test/functional/example-1-basics/index.js
@@ -0,0 +1,133 @@
+describe('Example 1 - Basics', function () {
+ 'use strict';
+
+ var baseUri = '/base/test/functional/example-1-basics';
+ var expect = chai.expect;
+ var currentFrame = 0;
+ var frameEvents = {};
+ var stage;
+ var renderer;
+ var bunny;
+
+ function onFrame(frame, callback) {
+ frameEvents[frame] = callback;
+ }
+
+ function animate() {
+ currentFrame += 1;
+
+ requestAnimFrame( animate );
+
+ // just for fun, lets rotate mr rabbit a little
+ bunny.rotation += 0.1;
+
+ // render the stage
+ renderer.render(stage);
+
+ if (frameEvents[currentFrame])
+ frameEvents[currentFrame](currentFrame);
+ }
+
+ function initScene() {
+ // create an new instance of a pixi stage
+ stage = new PIXI.Stage(0x66FF99);
+
+ // create a renderer instance
+ renderer = PIXI.autoDetectRenderer(400, 300);
+ console.log('Is PIXI.WebGLRenderer: ' + (renderer instanceof PIXI.WebGLRenderer));
+
+ // add the renderer view element to the DOM
+ document.body.appendChild(renderer.view);
+
+ requestAnimFrame( animate );
+
+ // create a texture from an image path
+ var texture = PIXI.Texture.fromImage(baseUri + "/bunny.png");
+ // create a new Sprite using the texture
+ bunny = new PIXI.Sprite(texture);
+
+ // center the sprites anchor point
+ bunny.anchor.x = 0.5;
+ bunny.anchor.y = 0.5;
+
+ // move the sprite t the center of the screen
+ bunny.position.x = 200;
+ bunny.position.y = 150;
+
+ stage.addChild(bunny);
+ }
+
+ it('assets loaded', function (done) {
+ var loader = new PIXI.AssetLoader([
+ baseUri + '/bunny.png',
+ baseUri + '/frame-30.png',
+ baseUri + '/frame-60.png',
+ baseUri + '/frame-90.png'
+ ]);
+ // loader.on('onProgress', function (event) {
+ // console.log(event.content);
+ // });
+ loader.on('onComplete', function (event) {
+ done();
+ initScene();
+ });
+ loader.load();
+ });
+
+ it('frame 30 should match', function (done) {
+ this.timeout(700);
+ onFrame(30, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-30.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 60 should match', function (done) {
+ this.timeout(1200);
+ onFrame(60, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-60.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 90 should match', function (done) {
+ this.timeout(1700);
+ onFrame(90, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-90.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ // it('capture something', function (done) {
+ // this.timeout(2000000);
+ // onFrame(30, function () {
+ // var img = new Image();
+ // img.src = renderer.view.toDataURL('image/png');
+ // document.body.appendChild(img);
+ // });
+ // });
+});
diff --git a/test/index.html b/test/index.html
deleted file mode 100644
index 9cbcac5..0000000
--- a/test/index.html
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
- Pixi.js Test Suite
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/test/karma.conf.js b/test/karma.conf.js
new file mode 100644
index 0000000..c66a696
--- /dev/null
+++ b/test/karma.conf.js
@@ -0,0 +1,82 @@
+module.exports = function(config) {
+ config.set({
+
+ // base path, that will be used to resolve files and exclude
+ basePath : '../',
+
+ frameworks : ['mocha'],
+
+ // list of files / patterns to load in the browser
+ files : [
+ 'node_modules/chai/chai.js',
+ 'bin/pixi.dev.js',
+ 'test/lib/**/*.js',
+ 'test/unit/**/*.js',
+ // 'test/functional/**/*.js',
+ {pattern: 'test/**/*.png', watched: false, included: false, served: true}
+ ],
+
+ // list of files to exclude
+ exclude : [],
+
+ // use dolts reporter, as travis terminal does not support escaping sequences
+ // possible values: 'dots', 'progress', 'junit', 'teamcity'
+ // CLI --reporters progress
+ reporters : ['progress'],
+
+ // web server port
+ // CLI --port 9876
+ port : 9876,
+
+ // cli runner port
+ // CLI --runner-port 9100
+ runnerPort : 9100,
+
+ // enable / disable colors in the output (reporters and logs)
+ // CLI --colors --no-colors
+ colors : true,
+
+ // level of logging
+ // possible values: karma.LOG_DISABLE || karma.LOG_ERROR || karma.LOG_WARN || karma.LOG_INFO || karma.LOG_DEBUG
+ // CLI --log-level debug
+ logLevel : config.LOG_DEBUG,
+
+ // enable / disable watching file and executing tests whenever any file changes
+ // CLI --auto-watch --no-auto-watch
+ autoWatch : false,
+
+ // Start these browsers, currently available:
+ // - Chrome
+ // - ChromeCanary
+ // - Firefox
+ // - Opera
+ // - Safari (only Mac)
+ // - PhantomJS
+ // - IE (only Windows)
+ // CLI --browsers Chrome,Firefox,Safari
+ browsers : ['Firefox'],
+
+ // If browser does not capture in given timeout [ms], kill it
+ // CLI --capture-timeout 5000
+ captureTimeout : 5000,
+
+ // Auto run tests on start (when browsers are captured) and exit
+ // CLI --single-run --no-single-run
+ singleRun : true,
+
+ // report which specs are slower than 500ms
+ // CLI --report-slower-than 500
+ reportSlowerThan : 1000,
+
+ preprocessors : {
+ // '**/client/js/*.js': 'coverage'
+ },
+
+ plugins : [
+ 'karma-mocha',
+ // 'karma-chrome-launcher',
+ 'karma-firefox-launcher',
+ // 'karma-phantomjs-launcher'
+ ]
+ });
+};
diff --git a/test/lib/pixi/core/Matrix.js b/test/lib/pixi/core/Matrix.js
new file mode 100644
index 0000000..d26386b
--- /dev/null
+++ b/test/lib/pixi/core/Matrix.js
@@ -0,0 +1,40 @@
+
+function pixi_core_Matrix_confirmNewMat3(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(1);
+ expect(matrix[5]).to.equal(0);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(1);
+}
+
+function pixi_core_Matrix_confirmNewMat4(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[0]).to.equal(1);
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(0);
+ expect(matrix[5]).to.equal(1);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(0);
+ expect(matrix[9]).to.equal(0);
+ expect(matrix[10]).to.equal(1);
+ expect(matrix[11]).to.equal(0);
+ expect(matrix[12]).to.equal(0);
+ expect(matrix[13]).to.equal(0);
+ expect(matrix[14]).to.equal(0);
+ expect(matrix[15]).to.equal(1);
+}
diff --git a/test/lib/pixi/core/Point.js b/test/lib/pixi/core/Point.js
new file mode 100644
index 0000000..e5df07b
--- /dev/null
+++ b/test/lib/pixi/core/Point.js
@@ -0,0 +1,10 @@
+
+function pixi_core_Point_confirm(obj, x, y) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Point);
+ expect(obj).to.respondTo('clone');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+}
diff --git a/test/lib/pixi/core/Rectangle.js b/test/lib/pixi/core/Rectangle.js
new file mode 100644
index 0000000..23f0d12
--- /dev/null
+++ b/test/lib/pixi/core/Rectangle.js
@@ -0,0 +1,13 @@
+
+function pixi_core_Rectangle_confirm(obj, x, y, width, height) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Rectangle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+ expect(obj).to.have.property('width', width);
+ expect(obj).to.have.property('height', height);
+}
diff --git a/test/lib/pixi/display/DisplayObject.js b/test/lib/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..1388a7f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObject.js
@@ -0,0 +1,43 @@
+
+function pixi_display_DisplayObject_confirmNew(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObject);
+ expect(obj).to.respondTo('setInteractive');
+ expect(obj).to.respondTo('addFilter');
+ expect(obj).to.respondTo('removeFilter');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.property('last', obj);
+ expect(obj).to.have.property('first', obj);
+
+ expect(obj).to.contain.property('position');
+ pixi_core_Point_confirm(obj.position, 0, 0);
+ expect(obj).to.contain.property('scale');
+ pixi_core_Point_confirm(obj.scale, 1, 1);
+ expect(obj).to.contain.property('pivot');
+ pixi_core_Point_confirm(obj.pivot, 0, 0);
+
+ expect(obj).to.have.property('rotation', 0);
+ expect(obj).to.have.property('alpha', 1);
+ expect(obj).to.have.property('visible', true);
+ expect(obj).to.have.property('buttonMode', false);
+ expect(obj).to.have.property('parent', null);
+ expect(obj).to.have.property('worldAlpha', 1);
+
+ expect(obj).to.have.property('hitArea');
+ expect(obj).to.have.property('interactive'); // TODO: Have a better default value
+ expect('mask' in obj).to.be.true; // TODO: Have a better default value
+ expect(obj.mask).to.be.undefined;
+
+ expect(obj).to.have.property('renderable');
+ expect(obj).to.have.property('stage');
+
+ expect(obj).to.have.deep.property('worldTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ expect(obj).to.have.deep.property('localTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.localTransform);
+
+ expect(obj).to.have.deep.property('color.length', 0);
+ expect(obj).to.have.property('dynamic', true);
+}
diff --git a/test/lib/pixi/display/DisplayObjectContainer.js b/test/lib/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..085c59f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,16 @@
+
+function pixi_display_DisplayObjectContainer_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObject_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObjectContainer);
+ expect(obj).to.respondTo('addChild');
+ expect(obj).to.respondTo('addChildAt');
+ expect(obj).to.respondTo('swapChildren');
+ expect(obj).to.respondTo('getChildAt');
+ expect(obj).to.respondTo('removeChild');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('children.length', 0);
+}
diff --git a/test/lib/pixi/display/Sprite.js b/test/lib/pixi/display/Sprite.js
new file mode 100644
index 0000000..cc7a2d6
--- /dev/null
+++ b/test/lib/pixi/display/Sprite.js
@@ -0,0 +1,28 @@
+
+function pixi_display_Sprite_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Sprite);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', true);
+ expect(obj).to.have.property('stage', null);
+
+ expect(obj).to.have.property('anchor');
+ pixi_core_Point_confirm(obj.anchor, 0, 0);
+
+ expect(obj).to.have.property('blendMode', PIXI.blendModes.NORMAL);
+ expect(obj).to.have.property('width', 1); // TODO: is 1 expected
+ expect(obj).to.have.property('height', 1); // TODO: is 1 expected
+
+ // FIXME: Just make this a boolean that is always there
+ expect(!!obj.updateFrame).to.equal(obj.texture.baseTexture.hasLoaded);
+
+ expect(obj).to.have.property('texture');
+ pixi_textures_Texture_confirmNew(obj.texture, done);
+}
diff --git a/test/lib/pixi/extras/Strip.js b/test/lib/pixi/extras/Strip.js
new file mode 100644
index 0000000..8927a8a
--- /dev/null
+++ b/test/lib/pixi/extras/Strip.js
@@ -0,0 +1,12 @@
+
+function pixi_extras_Strip_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Strip);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ // TODO: Test properties
+}
diff --git a/test/lib/pixi/textures/Texture.js b/test/lib/pixi/textures/Texture.js
new file mode 100644
index 0000000..d5867b6
--- /dev/null
+++ b/test/lib/pixi/textures/Texture.js
@@ -0,0 +1,31 @@
+
+function pixi_textures_Texture_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ function confirmFrameDone() {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, obj.baseTexture.width, obj.baseTexture.height);
+
+ expect(obj).to.have.property('width', obj.baseTexture.width);
+ expect(obj).to.have.property('height', obj.baseTexture.height);
+ done();
+ }
+
+ expect(obj).to.be.an.instanceof(PIXI.Texture);
+ pixi_utils_EventTarget_like(obj);
+
+ expect(obj).to.have.property('baseTexture')
+ .and.to.be.an.instanceof(PIXI.BaseTexture);
+
+ expect(obj).to.have.property('scope', obj);
+
+ expect(obj).to.have.property('trim');
+ pixi_core_Point_confirm(obj.trim, 0, 0);
+
+ expect(obj).to.have.property('frame');
+ if (obj.baseTexture.hasLoaded) {
+ confirmFrameDone();
+ } else {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, 1, 1);
+ obj.addEventListener('update', confirmFrameDone);
+ }
+}
diff --git a/test/lib/pixi/utils/EventTarget.js b/test/lib/pixi/utils/EventTarget.js
new file mode 100644
index 0000000..7b1dcfa
--- /dev/null
+++ b/test/lib/pixi/utils/EventTarget.js
@@ -0,0 +1,8 @@
+
+function pixi_utils_EventTarget_like(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.respondTo('addEventListener');
+ expect(obj).to.respondTo('dispatchEvent');
+ expect(obj).to.respondTo('removeEventListener');
+}
diff --git a/test/lib/qunit-1.11.0.css b/test/lib/qunit-1.11.0.css
deleted file mode 100644
index d7fc0c8..0000000
--- a/test/lib/qunit-1.11.0.css
+++ /dev/null
@@ -1,244 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-/** Font Family and Sizes */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
- font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
-}
-
-#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
-#qunit-tests { font-size: smaller; }
-
-
-/** Resets */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter {
- margin: 0;
- padding: 0;
-}
-
-
-/** Header */
-
-#qunit-header {
- padding: 0.5em 0 0.5em 1em;
-
- color: #8699a4;
- background-color: #0d3349;
-
- font-size: 1.5em;
- line-height: 1em;
- font-weight: normal;
-
- border-radius: 5px 5px 0 0;
- -moz-border-radius: 5px 5px 0 0;
- -webkit-border-top-right-radius: 5px;
- -webkit-border-top-left-radius: 5px;
-}
-
-#qunit-header a {
- text-decoration: none;
- color: #c2ccd1;
-}
-
-#qunit-header a:hover,
-#qunit-header a:focus {
- color: #fff;
-}
-
-#qunit-testrunner-toolbar label {
- display: inline-block;
- padding: 0 .5em 0 .1em;
-}
-
-#qunit-banner {
- height: 5px;
-}
-
-#qunit-testrunner-toolbar {
- padding: 0.5em 0 0.5em 2em;
- color: #5E740B;
- background-color: #eee;
- overflow: hidden;
-}
-
-#qunit-userAgent {
- padding: 0.5em 0 0.5em 2.5em;
- background-color: #2b81af;
- color: #fff;
- text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
-}
-
-#qunit-modulefilter-container {
- float: right;
-}
-
-/** Tests: Pass/Fail */
-
-#qunit-tests {
- list-style-position: inside;
-}
-
-#qunit-tests li {
- padding: 0.4em 0.5em 0.4em 2.5em;
- border-bottom: 1px solid #fff;
- list-style-position: inside;
-}
-
-#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running {
- display: none;
-}
-
-#qunit-tests li strong {
- cursor: pointer;
-}
-
-#qunit-tests li a {
- padding: 0.5em;
- color: #c2ccd1;
- text-decoration: none;
-}
-#qunit-tests li a:hover,
-#qunit-tests li a:focus {
- color: #000;
-}
-
-#qunit-tests li .runtime {
- float: right;
- font-size: smaller;
-}
-
-.qunit-assert-list {
- margin-top: 0.5em;
- padding: 0.5em;
-
- background-color: #fff;
-
- border-radius: 5px;
- -moz-border-radius: 5px;
- -webkit-border-radius: 5px;
-}
-
-.qunit-collapsed {
- display: none;
-}
-
-#qunit-tests table {
- border-collapse: collapse;
- margin-top: .2em;
-}
-
-#qunit-tests th {
- text-align: right;
- vertical-align: top;
- padding: 0 .5em 0 0;
-}
-
-#qunit-tests td {
- vertical-align: top;
-}
-
-#qunit-tests pre {
- margin: 0;
- white-space: pre-wrap;
- word-wrap: break-word;
-}
-
-#qunit-tests del {
- background-color: #e0f2be;
- color: #374e0c;
- text-decoration: none;
-}
-
-#qunit-tests ins {
- background-color: #ffcaca;
- color: #500;
- text-decoration: none;
-}
-
-/*** Test Counts */
-
-#qunit-tests b.counts { color: black; }
-#qunit-tests b.passed { color: #5E740B; }
-#qunit-tests b.failed { color: #710909; }
-
-#qunit-tests li li {
- padding: 5px;
- background-color: #fff;
- border-bottom: none;
- list-style-position: inside;
-}
-
-/*** Passing Styles */
-
-#qunit-tests li li.pass {
- color: #3c510c;
- background-color: #fff;
- border-left: 10px solid #C6E746;
-}
-
-#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
-#qunit-tests .pass .test-name { color: #366097; }
-
-#qunit-tests .pass .test-actual,
-#qunit-tests .pass .test-expected { color: #999999; }
-
-#qunit-banner.qunit-pass { background-color: #C6E746; }
-
-/*** Failing Styles */
-
-#qunit-tests li li.fail {
- color: #710909;
- background-color: #fff;
- border-left: 10px solid #EE5757;
- white-space: pre;
-}
-
-#qunit-tests > li:last-child {
- border-radius: 0 0 5px 5px;
- -moz-border-radius: 0 0 5px 5px;
- -webkit-border-bottom-right-radius: 5px;
- -webkit-border-bottom-left-radius: 5px;
-}
-
-#qunit-tests .fail { color: #000000; background-color: #EE5757; }
-#qunit-tests .fail .test-name,
-#qunit-tests .fail .module-name { color: #000000; }
-
-#qunit-tests .fail .test-actual { color: #EE5757; }
-#qunit-tests .fail .test-expected { color: green; }
-
-#qunit-banner.qunit-fail { background-color: #EE5757; }
-
-
-/** Result */
-
-#qunit-testresult {
- padding: 0.5em 0.5em 0.5em 2.5em;
-
- color: #2b81af;
- background-color: #D2E0E6;
-
- border-bottom: 1px solid white;
-}
-#qunit-testresult .module-name {
- font-weight: bold;
-}
-
-/** Fixture */
-
-#qunit-fixture {
- position: absolute;
- top: -10000px;
- left: -10000px;
- width: 1000px;
- height: 1000px;
-}
diff --git a/test/lib/qunit-1.11.0.js b/test/lib/qunit-1.11.0.js
deleted file mode 100644
index 302545f..0000000
--- a/test/lib/qunit-1.11.0.js
+++ /dev/null
@@ -1,2152 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-(function( window ) {
-
-var QUnit,
- assert,
- config,
- onErrorFnPrev,
- testId = 0,
- fileName = (sourceFromStacktrace( 0 ) || "" ).replace(/(:\d+)+\)?/, "").replace(/.+\//, ""),
- toString = Object.prototype.toString,
- hasOwn = Object.prototype.hasOwnProperty,
- // Keep a local reference to Date (GH-283)
- Date = window.Date,
- defined = {
- setTimeout: typeof window.setTimeout !== "undefined",
- sessionStorage: (function() {
- var x = "qunit-test-string";
- try {
- sessionStorage.setItem( x, x );
- sessionStorage.removeItem( x );
- return true;
- } catch( e ) {
- return false;
- }
- }())
- },
- /**
- * Provides a normalized error string, correcting an issue
- * with IE 7 (and prior) where Error.prototype.toString is
- * not properly implemented
- *
- * Based on http://es5.github.com/#x15.11.4.4
- *
- * @param {String|Error} error
- * @return {String} error message
- */
- errorString = function( error ) {
- var name, message,
- errorString = error.toString();
- if ( errorString.substring( 0, 7 ) === "[object" ) {
- name = error.name ? error.name.toString() : "Error";
- message = error.message ? error.message.toString() : "";
- if ( name && message ) {
- return name + ": " + message;
- } else if ( name ) {
- return name;
- } else if ( message ) {
- return message;
- } else {
- return "Error";
- }
- } else {
- return errorString;
- }
- },
- /**
- * Makes a clone of an object using only Array or Object as base,
- * and copies over the own enumerable properties.
- *
- * @param {Object} obj
- * @return {Object} New object with only the own properties (recursively).
- */
- objectValues = function( obj ) {
- // Grunt 0.3.x uses an older version of jshint that still has jshint/jshint#392.
- /*jshint newcap: false */
- var key, val,
- vals = QUnit.is( "array", obj ) ? [] : {};
- for ( key in obj ) {
- if ( hasOwn.call( obj, key ) ) {
- val = obj[key];
- vals[key] = val === Object(val) ? objectValues(val) : val;
- }
- }
- return vals;
- };
-
-function Test( settings ) {
- extend( this, settings );
- this.assertions = [];
- this.testNumber = ++Test.count;
-}
-
-Test.count = 0;
-
-Test.prototype = {
- init: function() {
- var a, b, li,
- tests = id( "qunit-tests" );
-
- if ( tests ) {
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml;
-
- // `a` initialized at top of scope
- a = document.createElement( "a" );
- a.innerHTML = "Rerun";
- a.href = QUnit.url({ testNumber: this.testNumber });
-
- li = document.createElement( "li" );
- li.appendChild( b );
- li.appendChild( a );
- li.className = "running";
- li.id = this.id = "qunit-test-output" + testId++;
-
- tests.appendChild( li );
- }
- },
- setup: function() {
- if ( this.module !== config.previousModule ) {
- if ( config.previousModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.previousModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
- config.previousModule = this.module;
- config.moduleStats = { all: 0, bad: 0 };
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- } else if ( config.autorun ) {
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- }
-
- config.current = this;
-
- this.testEnvironment = extend({
- setup: function() {},
- teardown: function() {}
- }, this.moduleTestEnvironment );
-
- this.started = +new Date();
- runLoggingCallbacks( "testStart", QUnit, {
- name: this.testName,
- module: this.module
- });
-
- // allow utility functions to access the current test environment
- // TODO why??
- QUnit.current_testEnvironment = this.testEnvironment;
-
- if ( !config.pollution ) {
- saveGlobal();
- }
- if ( config.notrycatch ) {
- this.testEnvironment.setup.call( this.testEnvironment );
- return;
- }
- try {
- this.testEnvironment.setup.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Setup failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- },
- run: function() {
- config.current = this;
-
- var running = id( "qunit-testresult" );
-
- if ( running ) {
- running.innerHTML = "Running:
" + this.nameHtml;
- }
-
- if ( this.async ) {
- QUnit.stop();
- }
-
- this.callbackStarted = +new Date();
-
- if ( config.notrycatch ) {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- return;
- }
-
- try {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- } catch( e ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
-
- QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + " " + this.stack + ": " + ( e.message || e ), extractStacktrace( e, 0 ) );
- // else next test will carry the responsibility
- saveGlobal();
-
- // Restart the tests if they're blocking
- if ( config.blocking ) {
- QUnit.start();
- }
- }
- },
- teardown: function() {
- config.current = this;
- if ( config.notrycatch ) {
- if ( typeof this.callbackRuntime === "undefined" ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
- }
- this.testEnvironment.teardown.call( this.testEnvironment );
- return;
- } else {
- try {
- this.testEnvironment.teardown.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Teardown failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- }
- checkPollution();
- },
- finish: function() {
- config.current = this;
- if ( config.requireExpects && this.expected === null ) {
- QUnit.pushFailure( "Expected number of assertions to be defined, but expect() was not called.", this.stack );
- } else if ( this.expected !== null && this.expected !== this.assertions.length ) {
- QUnit.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack );
- } else if ( this.expected === null && !this.assertions.length ) {
- QUnit.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions.", this.stack );
- }
-
- var i, assertion, a, b, time, li, ol,
- test = this,
- good = 0,
- bad = 0,
- tests = id( "qunit-tests" );
-
- this.runtime = +new Date() - this.started;
- config.stats.all += this.assertions.length;
- config.moduleStats.all += this.assertions.length;
-
- if ( tests ) {
- ol = document.createElement( "ol" );
- ol.className = "qunit-assert-list";
-
- for ( i = 0; i < this.assertions.length; i++ ) {
- assertion = this.assertions[i];
-
- li = document.createElement( "li" );
- li.className = assertion.result ? "pass" : "fail";
- li.innerHTML = assertion.message || ( assertion.result ? "okay" : "failed" );
- ol.appendChild( li );
-
- if ( assertion.result ) {
- good++;
- } else {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
-
- // store result when possible
- if ( QUnit.config.reorder && defined.sessionStorage ) {
- if ( bad ) {
- sessionStorage.setItem( "qunit-test-" + this.module + "-" + this.testName, bad );
- } else {
- sessionStorage.removeItem( "qunit-test-" + this.module + "-" + this.testName );
- }
- }
-
- if ( bad === 0 ) {
- addClass( ol, "qunit-collapsed" );
- }
-
- // `b` initialized at top of scope
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml + " (" + bad + ", " + good + ", " + this.assertions.length + ")";
-
- addEvent(b, "click", function() {
- var next = b.parentNode.lastChild,
- collapsed = hasClass( next, "qunit-collapsed" );
- ( collapsed ? removeClass : addClass )( next, "qunit-collapsed" );
- });
-
- addEvent(b, "dblclick", function( e ) {
- var target = e && e.target ? e.target : window.event.srcElement;
- if ( target.nodeName.toLowerCase() === "span" || target.nodeName.toLowerCase() === "b" ) {
- target = target.parentNode;
- }
- if ( window.location && target.nodeName.toLowerCase() === "strong" ) {
- window.location = QUnit.url({ testNumber: test.testNumber });
- }
- });
-
- // `time` initialized at top of scope
- time = document.createElement( "span" );
- time.className = "runtime";
- time.innerHTML = this.runtime + " ms";
-
- // `li` initialized at top of scope
- li = id( this.id );
- li.className = bad ? "fail" : "pass";
- li.removeChild( li.firstChild );
- a = li.firstChild;
- li.appendChild( b );
- li.appendChild( a );
- li.appendChild( time );
- li.appendChild( ol );
-
- } else {
- for ( i = 0; i < this.assertions.length; i++ ) {
- if ( !this.assertions[i].result ) {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
- }
-
- runLoggingCallbacks( "testDone", QUnit, {
- name: this.testName,
- module: this.module,
- failed: bad,
- passed: this.assertions.length - bad,
- total: this.assertions.length,
- duration: this.runtime
- });
-
- QUnit.reset();
-
- config.current = undefined;
- },
-
- queue: function() {
- var bad,
- test = this;
-
- synchronize(function() {
- test.init();
- });
- function run() {
- // each of these can by async
- synchronize(function() {
- test.setup();
- });
- synchronize(function() {
- test.run();
- });
- synchronize(function() {
- test.teardown();
- });
- synchronize(function() {
- test.finish();
- });
- }
-
- // `bad` initialized at top of scope
- // defer when previous test run passed, if storage is available
- bad = QUnit.config.reorder && defined.sessionStorage &&
- +sessionStorage.getItem( "qunit-test-" + this.module + "-" + this.testName );
-
- if ( bad ) {
- run();
- } else {
- synchronize( run, true );
- }
- }
-};
-
-// Root QUnit object.
-// `QUnit` initialized at top of scope
-QUnit = {
-
- // call on start of module test to prepend name to all tests
- module: function( name, testEnvironment ) {
- config.currentModule = name;
- config.currentModuleTestEnvironment = testEnvironment;
- config.modules[name] = true;
- },
-
- asyncTest: function( testName, expected, callback ) {
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- QUnit.test( testName, expected, callback, true );
- },
-
- test: function( testName, expected, callback, async ) {
- var test,
- nameHtml = "" + escapeText( testName ) + "";
-
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- if ( config.currentModule ) {
- nameHtml = "" + escapeText( config.currentModule ) + ": " + nameHtml;
- }
-
- test = new Test({
- nameHtml: nameHtml,
- testName: testName,
- expected: expected,
- async: async,
- callback: callback,
- module: config.currentModule,
- moduleTestEnvironment: config.currentModuleTestEnvironment,
- stack: sourceFromStacktrace( 2 )
- });
-
- if ( !validTest( test ) ) {
- return;
- }
-
- test.queue();
- },
-
- // Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through.
- expect: function( asserts ) {
- if (arguments.length === 1) {
- config.current.expected = asserts;
- } else {
- return config.current.expected;
- }
- },
-
- start: function( count ) {
- // QUnit hasn't been initialized yet.
- // Note: RequireJS (et al) may delay onLoad
- if ( config.semaphore === undefined ) {
- QUnit.begin(function() {
- // This is triggered at the top of QUnit.load, push start() to the event loop, to allow QUnit.load to finish first
- setTimeout(function() {
- QUnit.start( count );
- });
- });
- return;
- }
-
- config.semaphore -= count || 1;
- // don't start until equal number of stop-calls
- if ( config.semaphore > 0 ) {
- return;
- }
- // ignore if start is called more often then stop
- if ( config.semaphore < 0 ) {
- config.semaphore = 0;
- QUnit.pushFailure( "Called start() while already started (QUnit.config.semaphore was 0 already)", null, sourceFromStacktrace(2) );
- return;
- }
- // A slight delay, to avoid any current callbacks
- if ( defined.setTimeout ) {
- window.setTimeout(function() {
- if ( config.semaphore > 0 ) {
- return;
- }
- if ( config.timeout ) {
- clearTimeout( config.timeout );
- }
-
- config.blocking = false;
- process( true );
- }, 13);
- } else {
- config.blocking = false;
- process( true );
- }
- },
-
- stop: function( count ) {
- config.semaphore += count || 1;
- config.blocking = true;
-
- if ( config.testTimeout && defined.setTimeout ) {
- clearTimeout( config.timeout );
- config.timeout = window.setTimeout(function() {
- QUnit.ok( false, "Test timed out" );
- config.semaphore = 1;
- QUnit.start();
- }, config.testTimeout );
- }
- }
-};
-
-// `assert` initialized at top of scope
-// Asssert helpers
-// All of these must either call QUnit.push() or manually do:
-// - runLoggingCallbacks( "log", .. );
-// - config.current.assertions.push({ .. });
-// We attach it to the QUnit object *after* we expose the public API,
-// otherwise `assert` will become a global variable in browsers (#341).
-assert = {
- /**
- * Asserts rough true-ish result.
- * @name ok
- * @function
- * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" );
- */
- ok: function( result, msg ) {
- if ( !config.current ) {
- throw new Error( "ok() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
- result = !!result;
-
- var source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: msg
- };
-
- msg = escapeText( msg || (result ? "okay" : "failed" ) );
- msg = "" + msg + "";
-
- if ( !result ) {
- source = sourceFromStacktrace( 2 );
- if ( source ) {
- details.source = source;
- msg += "Source: | " + escapeText( source ) + " |
---|
";
- }
- }
- runLoggingCallbacks( "log", QUnit, details );
- config.current.assertions.push({
- result: result,
- message: msg
- });
- },
-
- /**
- * Assert that the first two arguments are equal, with an optional message.
- * Prints out both actual and expected values.
- * @name equal
- * @function
- * @example equal( format( "Received {0} bytes.", 2), "Received 2 bytes.", "format() replaces {0} with next argument" );
- */
- equal: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected == actual, actual, expected, message );
- },
-
- /**
- * @name notEqual
- * @function
- */
- notEqual: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected != actual, actual, expected, message );
- },
-
- /**
- * @name propEqual
- * @function
- */
- propEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notPropEqual
- * @function
- */
- notPropEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name deepEqual
- * @function
- */
- deepEqual: function( actual, expected, message ) {
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notDeepEqual
- * @function
- */
- notDeepEqual: function( actual, expected, message ) {
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name strictEqual
- * @function
- */
- strictEqual: function( actual, expected, message ) {
- QUnit.push( expected === actual, actual, expected, message );
- },
-
- /**
- * @name notStrictEqual
- * @function
- */
- notStrictEqual: function( actual, expected, message ) {
- QUnit.push( expected !== actual, actual, expected, message );
- },
-
- "throws": function( block, expected, message ) {
- var actual,
- expectedOutput = expected,
- ok = false;
-
- // 'expected' is optional
- if ( typeof expected === "string" ) {
- message = expected;
- expected = null;
- }
-
- config.current.ignoreGlobalErrors = true;
- try {
- block.call( config.current.testEnvironment );
- } catch (e) {
- actual = e;
- }
- config.current.ignoreGlobalErrors = false;
-
- if ( actual ) {
- // we don't want to validate thrown error
- if ( !expected ) {
- ok = true;
- expectedOutput = null;
- // expected is a regexp
- } else if ( QUnit.objectType( expected ) === "regexp" ) {
- ok = expected.test( errorString( actual ) );
- // expected is a constructor
- } else if ( actual instanceof expected ) {
- ok = true;
- // expected is a validation function which returns true is validation passed
- } else if ( expected.call( {}, actual ) === true ) {
- expectedOutput = null;
- ok = true;
- }
-
- QUnit.push( ok, actual, expectedOutput, message );
- } else {
- QUnit.pushFailure( message, null, 'No exception was thrown.' );
- }
- }
-};
-
-/**
- * @deprecate since 1.8.0
- * Kept assertion helpers in root for backwards compatibility.
- */
-extend( QUnit, assert );
-
-/**
- * @deprecated since 1.9.0
- * Kept root "raises()" for backwards compatibility.
- * (Note that we don't introduce assert.raises).
- */
-QUnit.raises = assert[ "throws" ];
-
-/**
- * @deprecated since 1.0.0, replaced with error pushes since 1.3.0
- * Kept to avoid TypeErrors for undefined methods.
- */
-QUnit.equals = function() {
- QUnit.push( false, false, false, "QUnit.equals has been deprecated since 2009 (e88049a0), use QUnit.equal instead" );
-};
-QUnit.same = function() {
- QUnit.push( false, false, false, "QUnit.same has been deprecated since 2009 (e88049a0), use QUnit.deepEqual instead" );
-};
-
-// We want access to the constructor's prototype
-(function() {
- function F() {}
- F.prototype = QUnit;
- QUnit = new F();
- // Make F QUnit's constructor so that we can add to the prototype later
- QUnit.constructor = F;
-}());
-
-/**
- * Config object: Maintain internal state
- * Later exposed as QUnit.config
- * `config` initialized at top of scope
- */
-config = {
- // The queue of tests to run
- queue: [],
-
- // block until document ready
- blocking: true,
-
- // when enabled, show only failing tests
- // gets persisted through sessionStorage and can be changed in UI via checkbox
- hidepassed: false,
-
- // by default, run previously failed tests first
- // very useful in combination with "Hide passed tests" checked
- reorder: true,
-
- // by default, modify document.title when suite is done
- altertitle: true,
-
- // when enabled, all tests must call expect()
- requireExpects: false,
-
- // add checkboxes that are persisted in the query-string
- // when enabled, the id is set to `true` as a `QUnit.config` property
- urlConfig: [
- {
- id: "noglobals",
- label: "Check for Globals",
- tooltip: "Enabling this will test if any test introduces new properties on the `window` object. Stored as query-strings."
- },
- {
- id: "notrycatch",
- label: "No try-catch",
- tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging exceptions in IE reasonable. Stored as query-strings."
- }
- ],
-
- // Set of all modules.
- modules: {},
-
- // logging callback queues
- begin: [],
- done: [],
- log: [],
- testStart: [],
- testDone: [],
- moduleStart: [],
- moduleDone: []
-};
-
-// Export global variables, unless an 'exports' object exists,
-// in that case we assume we're in CommonJS (dealt with on the bottom of the script)
-if ( typeof exports === "undefined" ) {
- extend( window, QUnit );
-
- // Expose QUnit object
- window.QUnit = QUnit;
-}
-
-// Initialize more QUnit.config and QUnit.urlParams
-(function() {
- var i,
- location = window.location || { search: "", protocol: "file:" },
- params = location.search.slice( 1 ).split( "&" ),
- length = params.length,
- urlParams = {},
- current;
-
- if ( params[ 0 ] ) {
- for ( i = 0; i < length; i++ ) {
- current = params[ i ].split( "=" );
- current[ 0 ] = decodeURIComponent( current[ 0 ] );
- // allow just a key to turn on a flag, e.g., test.html?noglobals
- current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true;
- urlParams[ current[ 0 ] ] = current[ 1 ];
- }
- }
-
- QUnit.urlParams = urlParams;
-
- // String search anywhere in moduleName+testName
- config.filter = urlParams.filter;
-
- // Exact match of the module name
- config.module = urlParams.module;
-
- config.testNumber = parseInt( urlParams.testNumber, 10 ) || null;
-
- // Figure out if we're running the tests from a server or not
- QUnit.isLocal = location.protocol === "file:";
-}());
-
-// Extend QUnit object,
-// these after set here because they should not be exposed as global functions
-extend( QUnit, {
- assert: assert,
-
- config: config,
-
- // Initialize the configuration options
- init: function() {
- extend( config, {
- stats: { all: 0, bad: 0 },
- moduleStats: { all: 0, bad: 0 },
- started: +new Date(),
- updateRate: 1000,
- blocking: false,
- autostart: true,
- autorun: false,
- filter: "",
- queue: [],
- semaphore: 1
- });
-
- var tests, banner, result,
- qunit = id( "qunit" );
-
- if ( qunit ) {
- qunit.innerHTML =
- "" +
- "" +
- "" +
- "" +
- "
";
- }
-
- tests = id( "qunit-tests" );
- banner = id( "qunit-banner" );
- result = id( "qunit-testresult" );
-
- if ( tests ) {
- tests.innerHTML = "";
- }
-
- if ( banner ) {
- banner.className = "";
- }
-
- if ( result ) {
- result.parentNode.removeChild( result );
- }
-
- if ( tests ) {
- result = document.createElement( "p" );
- result.id = "qunit-testresult";
- result.className = "result";
- tests.parentNode.insertBefore( result, tests );
- result.innerHTML = "Running...
";
- }
- },
-
- // Resets the test setup. Useful for tests that modify the DOM.
- reset: function() {
- var fixture = id( "qunit-fixture" );
- if ( fixture ) {
- fixture.innerHTML = config.fixture;
- }
- },
-
- // Trigger an event on an element.
- // @example triggerEvent( document.body, "click" );
- triggerEvent: function( elem, type, event ) {
- if ( document.createEvent ) {
- event = document.createEvent( "MouseEvents" );
- event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView,
- 0, 0, 0, 0, 0, false, false, false, false, 0, null);
-
- elem.dispatchEvent( event );
- } else if ( elem.fireEvent ) {
- elem.fireEvent( "on" + type );
- }
- },
-
- // Safe object type checking
- is: function( type, obj ) {
- return QUnit.objectType( obj ) === type;
- },
-
- objectType: function( obj ) {
- if ( typeof obj === "undefined" ) {
- return "undefined";
- // consider: typeof null === object
- }
- if ( obj === null ) {
- return "null";
- }
-
- var match = toString.call( obj ).match(/^\[object\s(.*)\]$/),
- type = match && match[1] || "";
-
- switch ( type ) {
- case "Number":
- if ( isNaN(obj) ) {
- return "nan";
- }
- return "number";
- case "String":
- case "Boolean":
- case "Array":
- case "Date":
- case "RegExp":
- case "Function":
- return type.toLowerCase();
- }
- if ( typeof obj === "object" ) {
- return "object";
- }
- return undefined;
- },
-
- push: function( result, actual, expected, message ) {
- if ( !config.current ) {
- throw new Error( "assertion outside test context, was " + sourceFromStacktrace() );
- }
-
- var output, source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: message,
- actual: actual,
- expected: expected
- };
-
- message = escapeText( message ) || ( result ? "okay" : "failed" );
- message = "" + message + "";
- output = message;
-
- if ( !result ) {
- expected = escapeText( QUnit.jsDump.parse(expected) );
- actual = escapeText( QUnit.jsDump.parse(actual) );
- output += "Expected: | " + expected + " |
";
-
- if ( actual !== expected ) {
- output += "Result: | " + actual + " |
";
- output += "Diff: | " + QUnit.diff( expected, actual ) + " |
";
- }
-
- source = sourceFromStacktrace();
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
- }
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: !!result,
- message: output
- });
- },
-
- pushFailure: function( message, source, actual ) {
- if ( !config.current ) {
- throw new Error( "pushFailure() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
-
- var output,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: false,
- message: message
- };
-
- message = escapeText( message ) || "error";
- message = "" + message + "";
- output = message;
-
- output += "";
-
- if ( actual ) {
- output += "Result: | " + escapeText( actual ) + " |
";
- }
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: false,
- message: output
- });
- },
-
- url: function( params ) {
- params = extend( extend( {}, QUnit.urlParams ), params );
- var key,
- querystring = "?";
-
- for ( key in params ) {
- if ( !hasOwn.call( params, key ) ) {
- continue;
- }
- querystring += encodeURIComponent( key ) + "=" +
- encodeURIComponent( params[ key ] ) + "&";
- }
- return window.location.protocol + "//" + window.location.host +
- window.location.pathname + querystring.slice( 0, -1 );
- },
-
- extend: extend,
- id: id,
- addEvent: addEvent
- // load, equiv, jsDump, diff: Attached later
-});
-
-/**
- * @deprecated: Created for backwards compatibility with test runner that set the hook function
- * into QUnit.{hook}, instead of invoking it and passing the hook function.
- * QUnit.constructor is set to the empty F() above so that we can add to it's prototype here.
- * Doing this allows us to tell if the following methods have been overwritten on the actual
- * QUnit object.
- */
-extend( QUnit.constructor.prototype, {
-
- // Logging callbacks; all receive a single argument with the listed properties
- // run test/logs.html for any related changes
- begin: registerLoggingCallback( "begin" ),
-
- // done: { failed, passed, total, runtime }
- done: registerLoggingCallback( "done" ),
-
- // log: { result, actual, expected, message }
- log: registerLoggingCallback( "log" ),
-
- // testStart: { name }
- testStart: registerLoggingCallback( "testStart" ),
-
- // testDone: { name, failed, passed, total, duration }
- testDone: registerLoggingCallback( "testDone" ),
-
- // moduleStart: { name }
- moduleStart: registerLoggingCallback( "moduleStart" ),
-
- // moduleDone: { name, failed, passed, total }
- moduleDone: registerLoggingCallback( "moduleDone" )
-});
-
-if ( typeof document === "undefined" || document.readyState === "complete" ) {
- config.autorun = true;
-}
-
-QUnit.load = function() {
- runLoggingCallbacks( "begin", QUnit, {} );
-
- // Initialize the config, saving the execution queue
- var banner, filter, i, label, len, main, ol, toolbar, userAgent, val,
- urlConfigCheckboxesContainer, urlConfigCheckboxes, moduleFilter,
- numModules = 0,
- moduleFilterHtml = "",
- urlConfigHtml = "",
- oldconfig = extend( {}, config );
-
- QUnit.init();
- extend(config, oldconfig);
-
- config.blocking = false;
-
- len = config.urlConfig.length;
-
- for ( i = 0; i < len; i++ ) {
- val = config.urlConfig[i];
- if ( typeof val === "string" ) {
- val = {
- id: val,
- label: val,
- tooltip: "[no tooltip available]"
- };
- }
- config[ val.id ] = QUnit.urlParams[ val.id ];
- urlConfigHtml += "";
- }
-
- moduleFilterHtml += "";
-
- // `userAgent` initialized at top of scope
- userAgent = id( "qunit-userAgent" );
- if ( userAgent ) {
- userAgent.innerHTML = navigator.userAgent;
- }
-
- // `banner` initialized at top of scope
- banner = id( "qunit-header" );
- if ( banner ) {
- banner.innerHTML = "" + banner.innerHTML + " ";
- }
-
- // `toolbar` initialized at top of scope
- toolbar = id( "qunit-testrunner-toolbar" );
- if ( toolbar ) {
- // `filter` initialized at top of scope
- filter = document.createElement( "input" );
- filter.type = "checkbox";
- filter.id = "qunit-filter-pass";
-
- addEvent( filter, "click", function() {
- var tmp,
- ol = document.getElementById( "qunit-tests" );
-
- if ( filter.checked ) {
- ol.className = ol.className + " hidepass";
- } else {
- tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " ";
- ol.className = tmp.replace( / hidepass /, " " );
- }
- if ( defined.sessionStorage ) {
- if (filter.checked) {
- sessionStorage.setItem( "qunit-filter-passed-tests", "true" );
- } else {
- sessionStorage.removeItem( "qunit-filter-passed-tests" );
- }
- }
- });
-
- if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem( "qunit-filter-passed-tests" ) ) {
- filter.checked = true;
- // `ol` initialized at top of scope
- ol = document.getElementById( "qunit-tests" );
- ol.className = ol.className + " hidepass";
- }
- toolbar.appendChild( filter );
-
- // `label` initialized at top of scope
- label = document.createElement( "label" );
- label.setAttribute( "for", "qunit-filter-pass" );
- label.setAttribute( "title", "Only show tests and assertons that fail. Stored in sessionStorage." );
- label.innerHTML = "Hide passed tests";
- toolbar.appendChild( label );
-
- urlConfigCheckboxesContainer = document.createElement("span");
- urlConfigCheckboxesContainer.innerHTML = urlConfigHtml;
- urlConfigCheckboxes = urlConfigCheckboxesContainer.getElementsByTagName("input");
- // For oldIE support:
- // * Add handlers to the individual elements instead of the container
- // * Use "click" instead of "change"
- // * Fallback from event.target to event.srcElement
- addEvents( urlConfigCheckboxes, "click", function( event ) {
- var params = {},
- target = event.target || event.srcElement;
- params[ target.name ] = target.checked ? true : undefined;
- window.location = QUnit.url( params );
- });
- toolbar.appendChild( urlConfigCheckboxesContainer );
-
- if (numModules > 1) {
- moduleFilter = document.createElement( 'span' );
- moduleFilter.setAttribute( 'id', 'qunit-modulefilter-container' );
- moduleFilter.innerHTML = moduleFilterHtml;
- addEvent( moduleFilter.lastChild, "change", function() {
- var selectBox = moduleFilter.getElementsByTagName("select")[0],
- selectedModule = decodeURIComponent(selectBox.options[selectBox.selectedIndex].value);
-
- window.location = QUnit.url( { module: ( selectedModule === "" ) ? undefined : selectedModule } );
- });
- toolbar.appendChild(moduleFilter);
- }
- }
-
- // `main` initialized at top of scope
- main = id( "qunit-fixture" );
- if ( main ) {
- config.fixture = main.innerHTML;
- }
-
- if ( config.autostart ) {
- QUnit.start();
- }
-};
-
-addEvent( window, "load", QUnit.load );
-
-// `onErrorFnPrev` initialized at top of scope
-// Preserve other handlers
-onErrorFnPrev = window.onerror;
-
-// Cover uncaught exceptions
-// Returning true will surpress the default browser handler,
-// returning false will let it run.
-window.onerror = function ( error, filePath, linerNr ) {
- var ret = false;
- if ( onErrorFnPrev ) {
- ret = onErrorFnPrev( error, filePath, linerNr );
- }
-
- // Treat return value as window.onerror itself does,
- // Only do our handling if not surpressed.
- if ( ret !== true ) {
- if ( QUnit.config.current ) {
- if ( QUnit.config.current.ignoreGlobalErrors ) {
- return true;
- }
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- } else {
- QUnit.test( "global failure", extend( function() {
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- }, { validTest: validTest } ) );
- }
- return false;
- }
-
- return ret;
-};
-
-function done() {
- config.autorun = true;
-
- // Log the last module results
- if ( config.currentModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.currentModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
-
- var i, key,
- banner = id( "qunit-banner" ),
- tests = id( "qunit-tests" ),
- runtime = +new Date() - config.started,
- passed = config.stats.all - config.stats.bad,
- html = [
- "Tests completed in ",
- runtime,
- " milliseconds.
",
- "",
- passed,
- " assertions of ",
- config.stats.all,
- " passed, ",
- config.stats.bad,
- " failed."
- ].join( "" );
-
- if ( banner ) {
- banner.className = ( config.stats.bad ? "qunit-fail" : "qunit-pass" );
- }
-
- if ( tests ) {
- id( "qunit-testresult" ).innerHTML = html;
- }
-
- if ( config.altertitle && typeof document !== "undefined" && document.title ) {
- // show ✖ for good, ✔ for bad suite result in title
- // use escape sequences in case file gets loaded with non-utf-8-charset
- document.title = [
- ( config.stats.bad ? "\u2716" : "\u2714" ),
- document.title.replace( /^[\u2714\u2716] /i, "" )
- ].join( " " );
- }
-
- // clear own sessionStorage items if all tests passed
- if ( config.reorder && defined.sessionStorage && config.stats.bad === 0 ) {
- // `key` & `i` initialized at top of scope
- for ( i = 0; i < sessionStorage.length; i++ ) {
- key = sessionStorage.key( i++ );
- if ( key.indexOf( "qunit-test-" ) === 0 ) {
- sessionStorage.removeItem( key );
- }
- }
- }
-
- // scroll back to top to show results
- if ( window.scrollTo ) {
- window.scrollTo(0, 0);
- }
-
- runLoggingCallbacks( "done", QUnit, {
- failed: config.stats.bad,
- passed: passed,
- total: config.stats.all,
- runtime: runtime
- });
-}
-
-/** @return Boolean: true if this test should be ran */
-function validTest( test ) {
- var include,
- filter = config.filter && config.filter.toLowerCase(),
- module = config.module && config.module.toLowerCase(),
- fullName = (test.module + ": " + test.testName).toLowerCase();
-
- // Internally-generated tests are always valid
- if ( test.callback && test.callback.validTest === validTest ) {
- delete test.callback.validTest;
- return true;
- }
-
- if ( config.testNumber ) {
- return test.testNumber === config.testNumber;
- }
-
- if ( module && ( !test.module || test.module.toLowerCase() !== module ) ) {
- return false;
- }
-
- if ( !filter ) {
- return true;
- }
-
- include = filter.charAt( 0 ) !== "!";
- if ( !include ) {
- filter = filter.slice( 1 );
- }
-
- // If the filter matches, we need to honour include
- if ( fullName.indexOf( filter ) !== -1 ) {
- return include;
- }
-
- // Otherwise, do the opposite
- return !include;
-}
-
-// so far supports only Firefox, Chrome and Opera (buggy), Safari (for real exceptions)
-// Later Safari and IE10 are supposed to support error.stack as well
-// See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack
-function extractStacktrace( e, offset ) {
- offset = offset === undefined ? 3 : offset;
-
- var stack, include, i;
-
- if ( e.stacktrace ) {
- // Opera
- return e.stacktrace.split( "\n" )[ offset + 3 ];
- } else if ( e.stack ) {
- // Firefox, Chrome
- stack = e.stack.split( "\n" );
- if (/^error$/i.test( stack[0] ) ) {
- stack.shift();
- }
- if ( fileName ) {
- include = [];
- for ( i = offset; i < stack.length; i++ ) {
- if ( stack[ i ].indexOf( fileName ) !== -1 ) {
- break;
- }
- include.push( stack[ i ] );
- }
- if ( include.length ) {
- return include.join( "\n" );
- }
- }
- return stack[ offset ];
- } else if ( e.sourceURL ) {
- // Safari, PhantomJS
- // hopefully one day Safari provides actual stacktraces
- // exclude useless self-reference for generated Error objects
- if ( /qunit.js$/.test( e.sourceURL ) ) {
- return;
- }
- // for actual exceptions, this is useful
- return e.sourceURL + ":" + e.line;
- }
-}
-function sourceFromStacktrace( offset ) {
- try {
- throw new Error();
- } catch ( e ) {
- return extractStacktrace( e, offset );
- }
-}
-
-/**
- * Escape text for attribute or text content.
- */
-function escapeText( s ) {
- if ( !s ) {
- return "";
- }
- s = s + "";
- // Both single quotes and double quotes (for attributes)
- return s.replace( /['"<>&]/g, function( s ) {
- switch( s ) {
- case '\'':
- return ''';
- case '"':
- return '"';
- case '<':
- return '<';
- case '>':
- return '>';
- case '&':
- return '&';
- }
- });
-}
-
-function synchronize( callback, last ) {
- config.queue.push( callback );
-
- if ( config.autorun && !config.blocking ) {
- process( last );
- }
-}
-
-function process( last ) {
- function next() {
- process( last );
- }
- var start = new Date().getTime();
- config.depth = config.depth ? config.depth + 1 : 1;
-
- while ( config.queue.length && !config.blocking ) {
- if ( !defined.setTimeout || config.updateRate <= 0 || ( ( new Date().getTime() - start ) < config.updateRate ) ) {
- config.queue.shift()();
- } else {
- window.setTimeout( next, 13 );
- break;
- }
- }
- config.depth--;
- if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) {
- done();
- }
-}
-
-function saveGlobal() {
- config.pollution = [];
-
- if ( config.noglobals ) {
- for ( var key in window ) {
- // in Opera sometimes DOM element ids show up here, ignore them
- if ( !hasOwn.call( window, key ) || /^qunit-test-output/.test( key ) ) {
- continue;
- }
- config.pollution.push( key );
- }
- }
-}
-
-function checkPollution() {
- var newGlobals,
- deletedGlobals,
- old = config.pollution;
-
- saveGlobal();
-
- newGlobals = diff( config.pollution, old );
- if ( newGlobals.length > 0 ) {
- QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join(", ") );
- }
-
- deletedGlobals = diff( old, config.pollution );
- if ( deletedGlobals.length > 0 ) {
- QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join(", ") );
- }
-}
-
-// returns a new Array with the elements that are in a but not in b
-function diff( a, b ) {
- var i, j,
- result = a.slice();
-
- for ( i = 0; i < result.length; i++ ) {
- for ( j = 0; j < b.length; j++ ) {
- if ( result[i] === b[j] ) {
- result.splice( i, 1 );
- i--;
- break;
- }
- }
- }
- return result;
-}
-
-function extend( a, b ) {
- for ( var prop in b ) {
- if ( b[ prop ] === undefined ) {
- delete a[ prop ];
-
- // Avoid "Member not found" error in IE8 caused by setting window.constructor
- } else if ( prop !== "constructor" || a !== window ) {
- a[ prop ] = b[ prop ];
- }
- }
-
- return a;
-}
-
-/**
- * @param {HTMLElement} elem
- * @param {string} type
- * @param {Function} fn
- */
-function addEvent( elem, type, fn ) {
- // Standards-based browsers
- if ( elem.addEventListener ) {
- elem.addEventListener( type, fn, false );
- // IE
- } else {
- elem.attachEvent( "on" + type, fn );
- }
-}
-
-/**
- * @param {Array|NodeList} elems
- * @param {string} type
- * @param {Function} fn
- */
-function addEvents( elems, type, fn ) {
- var i = elems.length;
- while ( i-- ) {
- addEvent( elems[i], type, fn );
- }
-}
-
-function hasClass( elem, name ) {
- return (" " + elem.className + " ").indexOf(" " + name + " ") > -1;
-}
-
-function addClass( elem, name ) {
- if ( !hasClass( elem, name ) ) {
- elem.className += (elem.className ? " " : "") + name;
- }
-}
-
-function removeClass( elem, name ) {
- var set = " " + elem.className + " ";
- // Class name may appear multiple times
- while ( set.indexOf(" " + name + " ") > -1 ) {
- set = set.replace(" " + name + " " , " ");
- }
- // If possible, trim it for prettiness, but not neccecarily
- elem.className = window.jQuery ? jQuery.trim( set ) : ( set.trim ? set.trim() : set );
-}
-
-function id( name ) {
- return !!( typeof document !== "undefined" && document && document.getElementById ) &&
- document.getElementById( name );
-}
-
-function registerLoggingCallback( key ) {
- return function( callback ) {
- config[key].push( callback );
- };
-}
-
-// Supports deprecated method of completely overwriting logging callbacks
-function runLoggingCallbacks( key, scope, args ) {
- var i, callbacks;
- if ( QUnit.hasOwnProperty( key ) ) {
- QUnit[ key ].call(scope, args );
- } else {
- callbacks = config[ key ];
- for ( i = 0; i < callbacks.length; i++ ) {
- callbacks[ i ].call( scope, args );
- }
- }
-}
-
-// Test for equality any JavaScript type.
-// Author: Philippe Rathé
-QUnit.equiv = (function() {
-
- // Call the o related callback with the given arguments.
- function bindCallbacks( o, callbacks, args ) {
- var prop = QUnit.objectType( o );
- if ( prop ) {
- if ( QUnit.objectType( callbacks[ prop ] ) === "function" ) {
- return callbacks[ prop ].apply( callbacks, args );
- } else {
- return callbacks[ prop ]; // or undefined
- }
- }
- }
-
- // the real equiv function
- var innerEquiv,
- // stack to decide between skip/abort functions
- callers = [],
- // stack to avoiding loops from circular referencing
- parents = [],
-
- getProto = Object.getPrototypeOf || function ( obj ) {
- return obj.__proto__;
- },
- callbacks = (function () {
-
- // for string, boolean, number and null
- function useStrictEquality( b, a ) {
- /*jshint eqeqeq:false */
- if ( b instanceof a.constructor || a instanceof b.constructor ) {
- // to catch short annotaion VS 'new' annotation of a
- // declaration
- // e.g. var i = 1;
- // var j = new Number(1);
- return a == b;
- } else {
- return a === b;
- }
- }
-
- return {
- "string": useStrictEquality,
- "boolean": useStrictEquality,
- "number": useStrictEquality,
- "null": useStrictEquality,
- "undefined": useStrictEquality,
-
- "nan": function( b ) {
- return isNaN( b );
- },
-
- "date": function( b, a ) {
- return QUnit.objectType( b ) === "date" && a.valueOf() === b.valueOf();
- },
-
- "regexp": function( b, a ) {
- return QUnit.objectType( b ) === "regexp" &&
- // the regex itself
- a.source === b.source &&
- // and its modifers
- a.global === b.global &&
- // (gmi) ...
- a.ignoreCase === b.ignoreCase &&
- a.multiline === b.multiline &&
- a.sticky === b.sticky;
- },
-
- // - skip when the property is a method of an instance (OOP)
- // - abort otherwise,
- // initial === would have catch identical references anyway
- "function": function() {
- var caller = callers[callers.length - 1];
- return caller !== Object && typeof caller !== "undefined";
- },
-
- "array": function( b, a ) {
- var i, j, len, loop;
-
- // b could be an object literal here
- if ( QUnit.objectType( b ) !== "array" ) {
- return false;
- }
-
- len = a.length;
- if ( len !== b.length ) {
- // safe and faster
- return false;
- }
-
- // track reference to avoid circular references
- parents.push( a );
- for ( i = 0; i < len; i++ ) {
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- loop = true;// dont rewalk array
- }
- }
- if ( !loop && !innerEquiv(a[i], b[i]) ) {
- parents.pop();
- return false;
- }
- }
- parents.pop();
- return true;
- },
-
- "object": function( b, a ) {
- var i, j, loop,
- // Default to true
- eq = true,
- aProperties = [],
- bProperties = [];
-
- // comparing constructors is more strict than using
- // instanceof
- if ( a.constructor !== b.constructor ) {
- // Allow objects with no prototype to be equivalent to
- // objects with Object as their constructor.
- if ( !(( getProto(a) === null && getProto(b) === Object.prototype ) ||
- ( getProto(b) === null && getProto(a) === Object.prototype ) ) ) {
- return false;
- }
- }
-
- // stack constructor before traversing properties
- callers.push( a.constructor );
- // track reference to avoid circular references
- parents.push( a );
-
- for ( i in a ) { // be strict: don't ensures hasOwnProperty
- // and go deep
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- // don't go down the same path twice
- loop = true;
- }
- }
- aProperties.push(i); // collect a's properties
-
- if (!loop && !innerEquiv( a[i], b[i] ) ) {
- eq = false;
- break;
- }
- }
-
- callers.pop(); // unstack, we are done
- parents.pop();
-
- for ( i in b ) {
- bProperties.push( i ); // collect b's properties
- }
-
- // Ensures identical properties name
- return eq && innerEquiv( aProperties.sort(), bProperties.sort() );
- }
- };
- }());
-
- innerEquiv = function() { // can take multiple arguments
- var args = [].slice.apply( arguments );
- if ( args.length < 2 ) {
- return true; // end transition
- }
-
- return (function( a, b ) {
- if ( a === b ) {
- return true; // catch the most you can
- } else if ( a === null || b === null || typeof a === "undefined" ||
- typeof b === "undefined" ||
- QUnit.objectType(a) !== QUnit.objectType(b) ) {
- return false; // don't lose time with error prone cases
- } else {
- return bindCallbacks(a, callbacks, [ b, a ]);
- }
-
- // apply transition with (1..n) arguments
- }( args[0], args[1] ) && arguments.callee.apply( this, args.splice(1, args.length - 1 )) );
- };
-
- return innerEquiv;
-}());
-
-/**
- * jsDump Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com |
- * http://flesler.blogspot.com Licensed under BSD
- * (http://www.opensource.org/licenses/bsd-license.php) Date: 5/15/2008
- *
- * @projectDescription Advanced and extensible data dumping for Javascript.
- * @version 1.0.0
- * @author Ariel Flesler
- * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html}
- */
-QUnit.jsDump = (function() {
- function quote( str ) {
- return '"' + str.toString().replace( /"/g, '\\"' ) + '"';
- }
- function literal( o ) {
- return o + "";
- }
- function join( pre, arr, post ) {
- var s = jsDump.separator(),
- base = jsDump.indent(),
- inner = jsDump.indent(1);
- if ( arr.join ) {
- arr = arr.join( "," + s + inner );
- }
- if ( !arr ) {
- return pre + post;
- }
- return [ pre, inner + arr, base + post ].join(s);
- }
- function array( arr, stack ) {
- var i = arr.length, ret = new Array(i);
- this.up();
- while ( i-- ) {
- ret[i] = this.parse( arr[i] , undefined , stack);
- }
- this.down();
- return join( "[", ret, "]" );
- }
-
- var reName = /^function (\w+)/,
- jsDump = {
- // type is used mostly internally, you can fix a (custom)type in advance
- parse: function( obj, type, stack ) {
- stack = stack || [ ];
- var inStack, res,
- parser = this.parsers[ type || this.typeOf(obj) ];
-
- type = typeof parser;
- inStack = inArray( obj, stack );
-
- if ( inStack !== -1 ) {
- return "recursion(" + (inStack - stack.length) + ")";
- }
- if ( type === "function" ) {
- stack.push( obj );
- res = parser.call( this, obj, stack );
- stack.pop();
- return res;
- }
- return ( type === "string" ) ? parser : this.parsers.error;
- },
- typeOf: function( obj ) {
- var type;
- if ( obj === null ) {
- type = "null";
- } else if ( typeof obj === "undefined" ) {
- type = "undefined";
- } else if ( QUnit.is( "regexp", obj) ) {
- type = "regexp";
- } else if ( QUnit.is( "date", obj) ) {
- type = "date";
- } else if ( QUnit.is( "function", obj) ) {
- type = "function";
- } else if ( typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined" ) {
- type = "window";
- } else if ( obj.nodeType === 9 ) {
- type = "document";
- } else if ( obj.nodeType ) {
- type = "node";
- } else if (
- // native arrays
- toString.call( obj ) === "[object Array]" ||
- // NodeList objects
- ( typeof obj.length === "number" && typeof obj.item !== "undefined" && ( obj.length ? obj.item(0) === obj[0] : ( obj.item( 0 ) === null && typeof obj[0] === "undefined" ) ) )
- ) {
- type = "array";
- } else if ( obj.constructor === Error.prototype.constructor ) {
- type = "error";
- } else {
- type = typeof obj;
- }
- return type;
- },
- separator: function() {
- return this.multiline ? this.HTML ? "
" : "\n" : this.HTML ? " " : " ";
- },
- // extra can be a number, shortcut for increasing-calling-decreasing
- indent: function( extra ) {
- if ( !this.multiline ) {
- return "";
- }
- var chr = this.indentChar;
- if ( this.HTML ) {
- chr = chr.replace( /\t/g, " " ).replace( / /g, " " );
- }
- return new Array( this._depth_ + (extra||0) ).join(chr);
- },
- up: function( a ) {
- this._depth_ += a || 1;
- },
- down: function( a ) {
- this._depth_ -= a || 1;
- },
- setParser: function( name, parser ) {
- this.parsers[name] = parser;
- },
- // The next 3 are exposed so you can use them
- quote: quote,
- literal: literal,
- join: join,
- //
- _depth_: 1,
- // This is the list of parsers, to modify them, use jsDump.setParser
- parsers: {
- window: "[Window]",
- document: "[Document]",
- error: function(error) {
- return "Error(\"" + error.message + "\")";
- },
- unknown: "[Unknown]",
- "null": "null",
- "undefined": "undefined",
- "function": function( fn ) {
- var ret = "function",
- // functions never have name in IE
- name = "name" in fn ? fn.name : (reName.exec(fn) || [])[1];
-
- if ( name ) {
- ret += " " + name;
- }
- ret += "( ";
-
- ret = [ ret, QUnit.jsDump.parse( fn, "functionArgs" ), "){" ].join( "" );
- return join( ret, QUnit.jsDump.parse(fn,"functionCode" ), "}" );
- },
- array: array,
- nodelist: array,
- "arguments": array,
- object: function( map, stack ) {
- var ret = [ ], keys, key, val, i;
- QUnit.jsDump.up();
- keys = [];
- for ( key in map ) {
- keys.push( key );
- }
- keys.sort();
- for ( i = 0; i < keys.length; i++ ) {
- key = keys[ i ];
- val = map[ key ];
- ret.push( QUnit.jsDump.parse( key, "key" ) + ": " + QUnit.jsDump.parse( val, undefined, stack ) );
- }
- QUnit.jsDump.down();
- return join( "{", ret, "}" );
- },
- node: function( node ) {
- var len, i, val,
- open = QUnit.jsDump.HTML ? "<" : "<",
- close = QUnit.jsDump.HTML ? ">" : ">",
- tag = node.nodeName.toLowerCase(),
- ret = open + tag,
- attrs = node.attributes;
-
- if ( attrs ) {
- for ( i = 0, len = attrs.length; i < len; i++ ) {
- val = attrs[i].nodeValue;
- // IE6 includes all attributes in .attributes, even ones not explicitly set.
- // Those have values like undefined, null, 0, false, "" or "inherit".
- if ( val && val !== "inherit" ) {
- ret += " " + attrs[i].nodeName + "=" + QUnit.jsDump.parse( val, "attribute" );
- }
- }
- }
- ret += close;
-
- // Show content of TextNode or CDATASection
- if ( node.nodeType === 3 || node.nodeType === 4 ) {
- ret += node.nodeValue;
- }
-
- return ret + open + "/" + tag + close;
- },
- // function calls it internally, it's the arguments part of the function
- functionArgs: function( fn ) {
- var args,
- l = fn.length;
-
- if ( !l ) {
- return "";
- }
-
- args = new Array(l);
- while ( l-- ) {
- // 97 is 'a'
- args[l] = String.fromCharCode(97+l);
- }
- return " " + args.join( ", " ) + " ";
- },
- // object calls it internally, the key part of an item in a map
- key: quote,
- // function calls it internally, it's the content of the function
- functionCode: "[code]",
- // node calls it internally, it's an html attribute value
- attribute: quote,
- string: quote,
- date: quote,
- regexp: literal,
- number: literal,
- "boolean": literal
- },
- // if true, entities are escaped ( <, >, \t, space and \n )
- HTML: false,
- // indentation unit
- indentChar: " ",
- // if true, items in a collection, are separated by a \n, else just a space.
- multiline: true
- };
-
- return jsDump;
-}());
-
-// from jquery.js
-function inArray( elem, array ) {
- if ( array.indexOf ) {
- return array.indexOf( elem );
- }
-
- for ( var i = 0, length = array.length; i < length; i++ ) {
- if ( array[ i ] === elem ) {
- return i;
- }
- }
-
- return -1;
-}
-
-/*
- * Javascript Diff Algorithm
- * By John Resig (http://ejohn.org/)
- * Modified by Chu Alan "sprite"
- *
- * Released under the MIT license.
- *
- * More Info:
- * http://ejohn.org/projects/javascript-diff-algorithm/
- *
- * Usage: QUnit.diff(expected, actual)
- *
- * QUnit.diff( "the quick brown fox jumped over", "the quick fox jumps over" ) == "the quick brown fox jumped jumps over"
- */
-QUnit.diff = (function() {
- /*jshint eqeqeq:false, eqnull:true */
- function diff( o, n ) {
- var i,
- ns = {},
- os = {};
-
- for ( i = 0; i < n.length; i++ ) {
- if ( !hasOwn.call( ns, n[i] ) ) {
- ns[ n[i] ] = {
- rows: [],
- o: null
- };
- }
- ns[ n[i] ].rows.push( i );
- }
-
- for ( i = 0; i < o.length; i++ ) {
- if ( !hasOwn.call( os, o[i] ) ) {
- os[ o[i] ] = {
- rows: [],
- n: null
- };
- }
- os[ o[i] ].rows.push( i );
- }
-
- for ( i in ns ) {
- if ( !hasOwn.call( ns, i ) ) {
- continue;
- }
- if ( ns[i].rows.length === 1 && hasOwn.call( os, i ) && os[i].rows.length === 1 ) {
- n[ ns[i].rows[0] ] = {
- text: n[ ns[i].rows[0] ],
- row: os[i].rows[0]
- };
- o[ os[i].rows[0] ] = {
- text: o[ os[i].rows[0] ],
- row: ns[i].rows[0]
- };
- }
- }
-
- for ( i = 0; i < n.length - 1; i++ ) {
- if ( n[i].text != null && n[ i + 1 ].text == null && n[i].row + 1 < o.length && o[ n[i].row + 1 ].text == null &&
- n[ i + 1 ] == o[ n[i].row + 1 ] ) {
-
- n[ i + 1 ] = {
- text: n[ i + 1 ],
- row: n[i].row + 1
- };
- o[ n[i].row + 1 ] = {
- text: o[ n[i].row + 1 ],
- row: i + 1
- };
- }
- }
-
- for ( i = n.length - 1; i > 0; i-- ) {
- if ( n[i].text != null && n[ i - 1 ].text == null && n[i].row > 0 && o[ n[i].row - 1 ].text == null &&
- n[ i - 1 ] == o[ n[i].row - 1 ]) {
-
- n[ i - 1 ] = {
- text: n[ i - 1 ],
- row: n[i].row - 1
- };
- o[ n[i].row - 1 ] = {
- text: o[ n[i].row - 1 ],
- row: i - 1
- };
- }
- }
-
- return {
- o: o,
- n: n
- };
- }
-
- return function( o, n ) {
- o = o.replace( /\s+$/, "" );
- n = n.replace( /\s+$/, "" );
-
- var i, pre,
- str = "",
- out = diff( o === "" ? [] : o.split(/\s+/), n === "" ? [] : n.split(/\s+/) ),
- oSpace = o.match(/\s+/g),
- nSpace = n.match(/\s+/g);
-
- if ( oSpace == null ) {
- oSpace = [ " " ];
- }
- else {
- oSpace.push( " " );
- }
-
- if ( nSpace == null ) {
- nSpace = [ " " ];
- }
- else {
- nSpace.push( " " );
- }
-
- if ( out.n.length === 0 ) {
- for ( i = 0; i < out.o.length; i++ ) {
- str += "" + out.o[i] + oSpace[i] + "";
- }
- }
- else {
- if ( out.n[0].text == null ) {
- for ( n = 0; n < out.o.length && out.o[n].text == null; n++ ) {
- str += "" + out.o[n] + oSpace[n] + "";
- }
- }
-
- for ( i = 0; i < out.n.length; i++ ) {
- if (out.n[i].text == null) {
- str += "" + out.n[i] + nSpace[i] + "";
- }
- else {
- // `pre` initialized at top of scope
- pre = "";
-
- for ( n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++ ) {
- pre += "" + out.o[n] + oSpace[n] + "";
- }
- str += " " + out.n[i].text + nSpace[i] + pre;
- }
- }
- }
-
- return str;
- };
-}());
-
-// for CommonJS enviroments, export everything
-if ( typeof exports !== "undefined" ) {
- extend( exports, QUnit );
-}
-
-// get at whatever the global object is, like window in browsers
-}( (function() {return this;}.call()) ));
diff --git a/test/lib/require.js b/test/lib/require.js
deleted file mode 100644
index 987f865..0000000
--- a/test/lib/require.js
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- RequireJS 2.1.5 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.
- Available via the MIT or new BSD license.
- see: http://github.com/jrburke/requirejs for details
-*/
-var requirejs,require,define;
-(function(aa){function I(b){return"[object Function]"===L.call(b)}function J(b){return"[object Array]"===L.call(b)}function y(b,c){if(b){var d;for(d=0;dthis.depCount&&!this.defined){if(I(n)){if(this.events.error)try{e=i.execCb(c,n,b,e)}catch(d){a=d}else e=i.execCb(c,n,b,e);this.map.isDefine&&((b=this.module)&&void 0!==b.exports&&b.exports!==this.exports?e=b.exports:void 0===e&&this.usingExports&&(e=this.exports));if(a)return a.requireMap=this.map,a.requireModules=[this.map.id],a.requireType="define",v(this.error=
-a)}else e=n;this.exports=e;if(this.map.isDefine&&!this.ignore&&(q[c]=e,l.onResourceLoad))l.onResourceLoad(i,this.map,this.depMaps);x(c);this.defined=!0}this.defining=!1;this.defined&&!this.defineEmitted&&(this.defineEmitted=!0,this.emit("defined",this.exports),this.defineEmitComplete=!0)}}else this.fetch()}},callPlugin:function(){var a=this.map,b=a.id,d=j(a.prefix);this.depMaps.push(d);t(d,"defined",u(this,function(e){var n,d;d=this.map.name;var g=this.map.parentMap?this.map.parentMap.name:null,h=
-i.makeRequire(a.parentMap,{enableBuildCallback:!0});if(this.map.unnormalized){if(e.normalize&&(d=e.normalize(d,function(a){return c(a,g,!0)})||""),e=j(a.prefix+"!"+d,this.map.parentMap),t(e,"defined",u(this,function(a){this.init([],function(){return a},null,{enabled:!0,ignore:!0})})),d=m(p,e.id)){this.depMaps.push(e);if(this.events.error)d.on("error",u(this,function(a){this.emit("error",a)}));d.enable()}}else n=u(this,function(a){this.init([],function(){return a},null,{enabled:!0})}),n.error=u(this,
-function(a){this.inited=!0;this.error=a;a.requireModules=[b];G(p,function(a){0===a.map.id.indexOf(b+"_unnormalized")&&x(a.map.id)});v(a)}),n.fromText=u(this,function(e,c){var d=a.name,g=j(d),C=O;c&&(e=c);C&&(O=!1);r(g);s(k.config,b)&&(k.config[d]=k.config[b]);try{l.exec(e)}catch(ca){return v(B("fromtexteval","fromText eval for "+b+" failed: "+ca,ca,[b]))}C&&(O=!0);this.depMaps.push(g);i.completeLoad(d);h([d],n)}),e.load(a.name,h,n,k)}));i.enable(d,this);this.pluginMaps[d.id]=d},enable:function(){V[this.map.id]=
-this;this.enabling=this.enabled=!0;y(this.depMaps,u(this,function(a,b){var c,e;if("string"===typeof a){a=j(a,this.map.isDefine?this.map:this.map.parentMap,!1,!this.skipMap);this.depMaps[b]=a;if(c=m(N,a.id)){this.depExports[b]=c(this);return}this.depCount+=1;t(a,"defined",u(this,function(a){this.defineDep(b,a);this.check()}));this.errback&&t(a,"error",this.errback)}c=a.id;e=p[c];!s(N,c)&&(e&&!e.enabled)&&i.enable(a,this)}));G(this.pluginMaps,u(this,function(a){var b=m(p,a.id);b&&!b.enabled&&i.enable(a,
-this)}));this.enabling=!1;this.check()},on:function(a,b){var c=this.events[a];c||(c=this.events[a]=[]);c.push(b)},emit:function(a,b){y(this.events[a],function(a){a(b)});"error"===a&&delete this.events[a]}};i={config:k,contextName:b,registry:p,defined:q,urlFetched:U,defQueue:H,Module:Z,makeModuleMap:j,nextTick:l.nextTick,onError:v,configure:function(a){a.baseUrl&&"/"!==a.baseUrl.charAt(a.baseUrl.length-1)&&(a.baseUrl+="/");var b=k.pkgs,c=k.shim,e={paths:!0,config:!0,map:!0};G(a,function(a,b){e[b]?
-"map"===b?(k.map||(k.map={}),R(k[b],a,!0,!0)):R(k[b],a,!0):k[b]=a});a.shim&&(G(a.shim,function(a,b){J(a)&&(a={deps:a});if((a.exports||a.init)&&!a.exportsFn)a.exportsFn=i.makeShimExports(a);c[b]=a}),k.shim=c);a.packages&&(y(a.packages,function(a){a="string"===typeof a?{name:a}:a;b[a.name]={name:a.name,location:a.location||a.name,main:(a.main||"main").replace(ja,"").replace(ea,"")}}),k.pkgs=b);G(p,function(a,b){!a.inited&&!a.map.unnormalized&&(a.map=j(b))});if(a.deps||a.callback)i.require(a.deps||[],
-a.callback)},makeShimExports:function(a){return function(){var b;a.init&&(b=a.init.apply(aa,arguments));return b||a.exports&&ba(a.exports)}},makeRequire:function(a,f){function d(e,c,h){var g,k;f.enableBuildCallback&&(c&&I(c))&&(c.__requireJsBuild=!0);if("string"===typeof e){if(I(c))return v(B("requireargs","Invalid require call"),h);if(a&&s(N,e))return N[e](p[a.id]);if(l.get)return l.get(i,e,a,d);g=j(e,a,!1,!0);g=g.id;return!s(q,g)?v(B("notloaded",'Module name "'+g+'" has not been loaded yet for context: '+
-b+(a?"":". Use require([])"))):q[g]}L();i.nextTick(function(){L();k=r(j(null,a));k.skipMap=f.skipMap;k.init(e,c,h,{enabled:!0});D()});return d}f=f||{};R(d,{isBrowser:A,toUrl:function(b){var d,f=b.lastIndexOf("."),g=b.split("/")[0];if(-1!==f&&(!("."===g||".."===g)||1h.attachEvent.toString().indexOf("[native code"))&&!Y?(O=!0,h.attachEvent("onreadystatechange",b.onScriptLoad)):(h.addEventListener("load",b.onScriptLoad,!1),h.addEventListener("error",b.onScriptError,!1)),h.src=d,K=h,D?x.insertBefore(h,D):x.appendChild(h),K=null,h;if(da)try{importScripts(d),b.completeLoad(c)}catch(j){b.onError(B("importscripts","importScripts failed for "+c+" at "+d,j,[c]))}};A&&M(document.getElementsByTagName("script"),function(b){x||(x=
-b.parentNode);if(t=b.getAttribute("data-main"))return r.baseUrl||(E=t.split("/"),Q=E.pop(),fa=E.length?E.join("/")+"/":"./",r.baseUrl=fa,t=Q),t=t.replace(ea,""),r.deps=r.deps?r.deps.concat(t):[t],!0});define=function(b,c,d){var l,h;"string"!==typeof b&&(d=c,c=b,b=null);J(c)||(d=c,c=[]);!c.length&&I(d)&&d.length&&(d.toString().replace(la,"").replace(ma,function(b,d){c.push(d)}),c=(1===d.length?["require"]:["require","exports","module"]).concat(c));if(O){if(!(l=K))P&&"interactive"===P.readyState||M(document.getElementsByTagName("script"),
-function(b){if("interactive"===b.readyState)return P=b}),l=P;l&&(b||(b=l.getAttribute("data-requiremodule")),h=F[l.getAttribute("data-requirecontext")])}(h?h.defQueue:T).push([b,c,d])};define.amd={jQuery:!0};l.exec=function(b){return eval(b)};l(r)}})(this);
diff --git a/test/lib/resemble.js b/test/lib/resemble.js
new file mode 100644
index 0000000..1cb8c29
--- /dev/null
+++ b/test/lib/resemble.js
@@ -0,0 +1,535 @@
+/*
+Author: James Cryer
+Company: Huddle
+Last updated date: 21 Feb 2013
+URL: https://github.com/Huddle/Resemble.js
+*/
+
+(function(_this){
+ 'use strict';
+
+ _this['resemble'] = function( fileData ){
+
+ var data = {};
+ var images = [];
+ var updateCallbackArray = [];
+
+ var tolerance = { // between 0 and 255
+ red: 16,
+ green: 16,
+ blue: 16,
+ minBrightness: 16,
+ maxBrightness: 240
+ };
+
+ var ignoreAntialiasing = false;
+ var ignoreColors = false;
+
+ function triggerDataUpdate(){
+ var len = updateCallbackArray.length;
+ var i;
+ for(i=0;i tolerance.maxBrightness;
+ }
+
+ function getHue(r,g,b){
+
+ r = r / 255;
+ g = g / 255;
+ b = b / 255;
+ var max = Math.max(r, g, b), min = Math.min(r, g, b);
+ var h;
+ var d;
+
+ if (max == min){
+ h = 0; // achromatic
+ } else{
+ d = max - min;
+ switch(max){
+ case r: h = (g - b) / d + (g < b ? 6 : 0); break;
+ case g: h = (b - r) / d + 2; break;
+ case b: h = (r - g) / d + 4; break;
+ }
+ h /= 6;
+ }
+
+ return h;
+ }
+
+ function isAntialiased(sourcePix, data, cacheSet, verticalPos, horizontalPos, width){
+ var offset;
+ var targetPix;
+ var distance = 1;
+ var i;
+ var j;
+ var hasHighContrastSibling = 0;
+ var hasSiblingWithDifferentHue = 0;
+ var hasEquivilantSibling = 0;
+
+ addHueInfo(sourcePix);
+
+ for (i = distance*-1; i <= distance; i++){
+ for (j = distance*-1; j <= distance; j++){
+
+ if(i===0 && j===0){
+ // ignore source pixel
+ } else {
+
+ offset = ((verticalPos+j)*width + (horizontalPos+i)) * 4;
+ targetPix = getPixelInfo(data, offset, cacheSet);
+
+ if(targetPix === null){
+ continue;
+ }
+
+ addBrightnessInfo(targetPix);
+ addHueInfo(targetPix);
+
+ if( isContrasting(sourcePix, targetPix) ){
+ hasHighContrastSibling++;
+ }
+
+ if( isRGBSame(sourcePix,targetPix) ){
+ hasEquivilantSibling++;
+ }
+
+ if( Math.abs(targetPix.h - sourcePix.h) > 0.3 ){
+ hasSiblingWithDifferentHue++;
+ }
+
+ if( hasSiblingWithDifferentHue > 1 || hasHighContrastSibling > 1){
+ return true;
+ }
+ }
+ }
+ }
+
+ if(hasEquivilantSibling < 2){
+ return true;
+ }
+
+ return false;
+ }
+
+ function errorPixel(px, offset){
+ px[offset] = 255; //r
+ px[offset + 1] = 0; //g
+ px[offset + 2] = 255; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyPixel(px, offset, data){
+ px[offset] = data.r; //r
+ px[offset + 1] = data.g; //g
+ px[offset + 2] = data.b; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyGrayScalePixel(px, offset, data){
+ px[offset] = data.brightness; //r
+ px[offset + 1] = data.brightness; //g
+ px[offset + 2] = data.brightness; //b
+ px[offset + 3] = 255; //a
+ }
+
+
+ function getPixelInfo(data, offset, cacheSet){
+ var r;
+ var g;
+ var b;
+ var d;
+
+ if(typeof data[offset] !== 'undefined'){
+ r = data[offset];
+ g = data[offset+1];
+ b = data[offset+2];
+ d = {
+ r: r,
+ g: g,
+ b: b
+ };
+
+ return d;
+ } else {
+ return null;
+ }
+ }
+
+ function addBrightnessInfo(data){
+ data.brightness = getBrightness(data.r,data.g,data.b); // 'corrected' lightness
+ }
+
+ function addHueInfo(data){
+ data.h = getHue(data.r,data.g,data.b);
+ }
+
+ function analyseImages(img1, img2, width, height){
+
+ var hiddenCanvas = document.createElement('canvas');
+
+ var data1 = img1.data;
+ var data2 = img2.data;
+
+ hiddenCanvas.width = width;
+ hiddenCanvas.height = height;
+
+ var context = hiddenCanvas.getContext('2d');
+ var imgd = context.createImageData(width,height);
+ var targetPix = imgd.data;
+
+ var mismatchCount = 0;
+
+ var time = Date.now();
+
+ var skip;
+
+ if( (width > 1200 || height > 1200) && ignoreAntialiasing){
+ skip = 6;
+ }
+
+ loop(height, width, function(verticalPos, horizontalPos){
+
+ if(skip){ // only skip if the image isn't small
+ if(verticalPos % skip === 0 || horizontalPos % skip === 0){
+ return;
+ }
+ }
+
+ var offset = (verticalPos*width + horizontalPos) * 4;
+ var pixel1 = getPixelInfo(data1, offset, 1);
+ var pixel2 = getPixelInfo(data2, offset, 2);
+
+ if(pixel1 === null || pixel2 === null){
+ return;
+ }
+
+ if (ignoreColors){
+
+ addBrightnessInfo(pixel1);
+ addBrightnessInfo(pixel2);
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ return;
+ }
+
+ if( isRGBSimilar(pixel1, pixel2) ){
+ copyPixel(targetPix, offset, pixel2);
+
+ } else if( ignoreAntialiasing && (
+ addBrightnessInfo(pixel1), // jit pixel info augmentation looks a little weird, sorry.
+ addBrightnessInfo(pixel2),
+ isAntialiased(pixel1, data1, 1, verticalPos, horizontalPos, width) ||
+ isAntialiased(pixel2, data2, 2, verticalPos, horizontalPos, width)
+ )){
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+
+ });
+
+ data.misMatchPercentage = (mismatchCount / (height*width) * 100).toFixed(2);
+ data.analysisTime = Date.now() - time;
+
+ data.getImageDataUrl = function(text){
+ var barHeight = 0;
+
+ if(text){
+ barHeight = addLabel(text,context,hiddenCanvas);
+ }
+
+ context.putImageData(imgd, 0, barHeight);
+
+ return hiddenCanvas.toDataURL("image/png");
+ };
+ }
+
+ function addLabel(text, context, hiddenCanvas){
+ var textPadding = 2;
+
+ context.font = '12px sans-serif';
+
+ var textWidth = context.measureText(text).width + textPadding*2;
+ var barHeight = 22;
+
+ if(textWidth > hiddenCanvas.width){
+ hiddenCanvas.width = textWidth;
+ }
+
+ hiddenCanvas.height += barHeight;
+
+ context.fillStyle = "#666";
+ context.fillRect(0,0,hiddenCanvas.width,barHeight -4);
+ context.fillStyle = "#fff";
+ context.fillRect(0,barHeight -4,hiddenCanvas.width, 4);
+
+ context.fillStyle = "#fff";
+ context.textBaseline = "top";
+ context.font = '12px sans-serif';
+ context.fillText(text, textPadding, 1);
+
+ return barHeight;
+ }
+
+ function normalise(img, w, h){
+ var c;
+ var context;
+
+ if(img.height < h || img.width < w){
+ c = document.createElement('canvas');
+ c.width = w;
+ c.height = h;
+ context = c.getContext('2d');
+ context.putImageData(img, 0, 0);
+ return context.getImageData(0, 0, w, h);
+ }
+
+ return img;
+ }
+
+ function compare(one, two){
+
+ function onceWeHaveBoth(){
+ var width;
+ var height;
+ if(images.length === 2){
+ width = images[0].width > images[1].width ? images[0].width : images[1].width;
+ height = images[0].height > images[1].height ? images[0].height : images[1].height;
+
+ if( (images[0].width === images[1].width) && (images[0].height === images[1].height) ){
+ data.isSameDimensions = true;
+ } else {
+ data.isSameDimensions = false;
+ }
+
+ analyseImages( normalise(images[0],width, height), normalise(images[1],width, height), width, height);
+
+ triggerDataUpdate();
+ }
+ }
+
+ images = [];
+ loadImageData(one, onceWeHaveBoth);
+ loadImageData(two, onceWeHaveBoth);
+ }
+
+ function getCompareApi(param){
+
+ var secondFileData,
+ hasMethod = typeof param === 'function';
+
+ if( !hasMethod ){
+ // assume it's file data
+ secondFileData = param;
+ }
+
+ var self = {
+ ignoreNothing: function(){
+
+ tolerance.red = 16;
+ tolerance.green = 16;
+ tolerance.blue = 16;
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreAntialiasing: function(){
+
+ tolerance.red = 32;
+ tolerance.green = 32;
+ tolerance.blue = 32;
+ tolerance.minBrightness = 64;
+ tolerance.maxBrightness = 96;
+
+ ignoreAntialiasing = true;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreColors: function(){
+
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = true;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ onComplete: function( callback ){
+
+ updateCallbackArray.push(callback);
+
+ var wrapper = function(){
+ compare(fileData, secondFileData);
+ };
+
+ wrapper();
+
+ return getCompareApi(wrapper);
+ }
+ };
+
+ return self;
+ }
+
+ return {
+ onComplete: function( callback ){
+ updateCallbackArray.push(callback);
+ loadImageData(fileData, function(imageData, width, height){
+ parseImage(imageData.data, width, height);
+ });
+ },
+ compareTo: function(secondFileData){
+ return getCompareApi(secondFileData);
+ }
+ };
+
+ };
+}(this));
\ No newline at end of file
diff --git a/test/testsuite.js b/test/testsuite.js
deleted file mode 100644
index b486acb..0000000
--- a/test/testsuite.js
+++ /dev/null
@@ -1,36 +0,0 @@
-requirejs.config({
- baseUrl: '/test/unit/'
-});
-
-define(function(require) {
- var testModules = [
- 'Pixi',
- 'Point',
- 'Rectangle',
- 'DisplayObject',
- 'DisplayObjectContainer',
- 'Sprite',
- 'MovieClip',
- 'InteractionManager',
- 'Stage',
- 'utils/Utils',
- 'utils/EventTarget',
- 'utils/Matrix',
- 'utils/Detector',
- 'renderers/WebGLShaders',
- 'renderers/WebGLRenderer',
- 'renderers/WebGLBatch',
- 'renderers/CanvasRenderer',
- 'extras/Strip',
- 'extras/Rope',
- 'textures/BaseTexture',
- 'textures/Texture',
- 'loaders/SpriteSheetLoader',
- 'loaders/AssetLoader'
- ];
-
- // Resolve all testModules and then start the Test Runner.
- require(testModules, function() {
- QUnit.start();
- });
-});
\ No newline at end of file
diff --git a/test/textures/SpriteSheet-Aliens.png b/test/textures/SpriteSheet-Aliens.png
new file mode 100644
index 0000000..210acb1
--- /dev/null
+++ b/test/textures/SpriteSheet-Aliens.png
Binary files differ
diff --git a/test/textures/SpriteSheet-Explosion.png b/test/textures/SpriteSheet-Explosion.png
new file mode 100755
index 0000000..79e1a69
--- /dev/null
+++ b/test/textures/SpriteSheet-Explosion.png
Binary files differ
diff --git a/test/textures/bunny.png b/test/textures/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/textures/bunny.png
Binary files differ
diff --git a/test/unit/DisplayObject.js b/test/unit/DisplayObject.js
deleted file mode 100644
index 5e7e72f..0000000
--- a/test/unit/DisplayObject.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObject');
-});
diff --git a/test/unit/DisplayObjectContainer.js b/test/unit/DisplayObjectContainer.js
deleted file mode 100644
index b323959..0000000
--- a/test/unit/DisplayObjectContainer.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObjectContainer');
-});
diff --git a/test/unit/InteractionManager.js b/test/unit/InteractionManager.js
deleted file mode 100644
index e751f52..0000000
--- a/test/unit/InteractionManager.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('InteractionManager');
-});
diff --git a/test/unit/MovieClip.js b/test/unit/MovieClip.js
deleted file mode 100644
index 37d9446..0000000
--- a/test/unit/MovieClip.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('MovieClip');
-});
diff --git a/test/unit/Pixi.js b/test/unit/Pixi.js
deleted file mode 100644
index 36eee73..0000000
--- a/test/unit/Pixi.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Pixi');
-});
diff --git a/test/unit/Point.js b/test/unit/Point.js
deleted file mode 100644
index 983ff6e..0000000
--- a/test/unit/Point.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Point');
-});
diff --git a/test/unit/Rectangle.js b/test/unit/Rectangle.js
deleted file mode 100644
index 3b439ba..0000000
--- a/test/unit/Rectangle.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Rectangle');
-});
diff --git a/test/unit/Sprite.js b/test/unit/Sprite.js
deleted file mode 100644
index ed4f596..0000000
--- a/test/unit/Sprite.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Sprite');
-});
diff --git a/test/unit/Stage.js b/test/unit/Stage.js
deleted file mode 100644
index 2d70291..0000000
--- a/test/unit/Stage.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Stage');
-});
diff --git a/test/unit/extras/Rope.js b/test/unit/extras/Rope.js
deleted file mode 100644
index 5606f14..0000000
--- a/test/unit/extras/Rope.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Rope');
-});
diff --git a/test/unit/extras/Strip.js b/test/unit/extras/Strip.js
deleted file mode 100644
index 0134d3a..0000000
--- a/test/unit/extras/Strip.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Strip');
-});
diff --git a/test/unit/loaders/AssetLoader.js b/test/unit/loaders/AssetLoader.js
deleted file mode 100644
index 13b8443..0000000
--- a/test/unit/loaders/AssetLoader.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('AssetLoader');
-});
diff --git a/test/unit/loaders/SpriteSheetLoader.js b/test/unit/loaders/SpriteSheetLoader.js
deleted file mode 100644
index 8bf0cb2..0000000
--- a/test/unit/loaders/SpriteSheetLoader.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('SpriteSheetLoader');
-});
diff --git a/test/unit/pixi/InteractionManager.js b/test/unit/pixi/InteractionManager.js
new file mode 100644
index 0000000..ed3001f
--- /dev/null
+++ b/test/unit/pixi/InteractionManager.js
@@ -0,0 +1,10 @@
+describe('pixi/InteractionManager', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var InteractionManager = PIXI.InteractionManager;
+
+ it('Module exists', function () {
+ expect(InteractionManager).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/Pixi.js b/test/unit/pixi/Pixi.js
new file mode 100644
index 0000000..27debc1
--- /dev/null
+++ b/test/unit/pixi/Pixi.js
@@ -0,0 +1,9 @@
+describe('pixi/Pixi', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+
+ it('Module exists', function () {
+ expect(global).to.have.property('PIXI').and.to.be.an('object');
+ });
+});
diff --git a/test/unit/pixi/core/Circle.js b/test/unit/pixi/core/Circle.js
new file mode 100644
index 0000000..93a4456
--- /dev/null
+++ b/test/unit/pixi/core/Circle.js
@@ -0,0 +1,22 @@
+describe('pixi/core/Circle', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Circle = PIXI.Circle;
+
+ it('Module exists', function () {
+ expect(Circle).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Circle();
+
+ expect(obj).to.be.an.instanceof(Circle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', 0);
+ expect(obj).to.have.property('y', 0);
+ expect(obj).to.have.property('radius', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Ellipse.js b/test/unit/pixi/core/Ellipse.js
new file mode 100644
index 0000000..026b56f
--- /dev/null
+++ b/test/unit/pixi/core/Ellipse.js
@@ -0,0 +1,24 @@
+describe('pixi/core/Ellipse', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Ellipse = PIXI.Ellipse;
+
+ it('Module exists', function () {
+ expect(Ellipse).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Ellipse();
+
+ expect(obj).to.be.an.instanceof(Ellipse);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+ expect(obj).to.respondTo('getBounds');
+
+ expect(obj).to.have.property('x', 0);
+ expect(obj).to.have.property('y', 0);
+ expect(obj).to.have.property('width', 0);
+ expect(obj).to.have.property('height', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Matrix.js b/test/unit/pixi/core/Matrix.js
new file mode 100644
index 0000000..b48989e
--- /dev/null
+++ b/test/unit/pixi/core/Matrix.js
@@ -0,0 +1,30 @@
+describe('pixi/core/Matrix', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var mat3 = PIXI.mat3;
+ var mat4 = PIXI.mat4;
+ var Matrix = PIXI.Matrix;
+
+ it('Ensure determineMatrixArrayType works', function () {
+ expect(Matrix).to.be.a('function');
+ });
+
+ it('mat3 exists', function () {
+ expect(mat3).to.be.an('object');
+ });
+
+ it('Confirm new mat3 matrix', function () {
+ var matrix = new mat3.create();
+ pixi_core_Matrix_confirmNewMat3(matrix);
+ });
+
+ it('mat3 exists', function () {
+ expect(mat4).to.be.an('object');
+ });
+
+ it('Confirm new mat4 matrix', function () {
+ var matrix = new mat4.create();
+ pixi_core_Matrix_confirmNewMat4(matrix);
+ });
+});
diff --git a/test/unit/pixi/core/Point.js b/test/unit/pixi/core/Point.js
new file mode 100644
index 0000000..c4d5163
--- /dev/null
+++ b/test/unit/pixi/core/Point.js
@@ -0,0 +1,15 @@
+describe('pixi/core/Point', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Point = PIXI.Point;
+
+ it('Module exists', function () {
+ expect(Point).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Point();
+ pixi_core_Point_confirm(obj, 0, 0);
+ });
+});
diff --git a/test/unit/pixi/core/Polygon.js b/test/unit/pixi/core/Polygon.js
new file mode 100644
index 0000000..dc8c918
--- /dev/null
+++ b/test/unit/pixi/core/Polygon.js
@@ -0,0 +1,20 @@
+describe('pixi/core/Polygon', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Polygon = PIXI.Polygon;
+
+ it('Module exists', function () {
+ expect(Polygon).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Polygon();
+
+ expect(obj).to.be.an.instanceof(Polygon);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.deep.property('points.length', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Rectangle.js b/test/unit/pixi/core/Rectangle.js
new file mode 100644
index 0000000..d43316e
--- /dev/null
+++ b/test/unit/pixi/core/Rectangle.js
@@ -0,0 +1,15 @@
+describe('pixi/core/Rectangle', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Rectangle = PIXI.Rectangle;
+
+ it('Module exists', function () {
+ expect(Rectangle).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var rect = new Rectangle();
+ pixi_core_Rectangle_confirm(rect, 0, 0, 0, 0);
+ });
+});
diff --git a/test/unit/pixi/display/DisplayObject.js b/test/unit/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..40c6fbc
--- /dev/null
+++ b/test/unit/pixi/display/DisplayObject.js
@@ -0,0 +1,21 @@
+describe('pixi/display/DisplayObject', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var DisplayObject = PIXI.DisplayObject;
+
+ it('Module exists', function () {
+ expect(DisplayObject).to.be.a('function');
+ expect(PIXI).to.have.property('visibleCount', 0);
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new DisplayObject();
+
+ pixi_display_DisplayObject_confirmNew(obj);
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', false);
+ expect(obj).to.have.property('stage', null);
+ });
+});
diff --git a/test/unit/pixi/display/DisplayObjectContainer.js b/test/unit/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..ce7f02f
--- /dev/null
+++ b/test/unit/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,20 @@
+describe('pixi/display/DisplayObjectContainer', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var DisplayObjectContainer = PIXI.DisplayObjectContainer;
+
+ it('Module exists', function () {
+ expect(DisplayObjectContainer).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new DisplayObjectContainer();
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', false);
+ expect(obj).to.have.property('stage', null);
+ });
+});
diff --git a/test/unit/pixi/display/MovieClip.js b/test/unit/pixi/display/MovieClip.js
new file mode 100644
index 0000000..f3c6c6a
--- /dev/null
+++ b/test/unit/pixi/display/MovieClip.js
@@ -0,0 +1,33 @@
+describe('pixi/display/MovieClip', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var MovieClip = PIXI.MovieClip;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(MovieClip).to.be.a('function');
+ });
+
+ it('Confirm new instance', function (done) {
+ var texture = Texture.fromImage('/base/test/textures/SpriteSheet-Explosion.png');
+ var obj = new MovieClip([texture]);
+
+ pixi_display_Sprite_confirmNew(obj, done);
+
+ expect(obj).to.be.an.instanceof(MovieClip);
+ expect(obj).to.respondTo('stop');
+ expect(obj).to.respondTo('play');
+ expect(obj).to.respondTo('gotoAndStop');
+ expect(obj).to.respondTo('gotoAndPlay');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('textures.length', 1);
+ expect(obj).to.have.deep.property('textures[0]', texture);
+ expect(obj).to.have.property('animationSpeed', 1);
+ expect(obj).to.have.property('loop', true);
+ expect(obj).to.have.property('onComplete', null);
+ expect(obj).to.have.property('currentFrame', 0);
+ expect(obj).to.have.property('playing', false);
+ });
+});
diff --git a/test/unit/pixi/display/Sprite.js b/test/unit/pixi/display/Sprite.js
new file mode 100644
index 0000000..54e914f
--- /dev/null
+++ b/test/unit/pixi/display/Sprite.js
@@ -0,0 +1,25 @@
+describe('pixi/display/Sprite', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Sprite = PIXI.Sprite;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(Sprite).to.be.a('function');
+ expect(PIXI).to.have.deep.property('blendModes.NORMAL', 0);
+ expect(PIXI).to.have.deep.property('blendModes.SCREEN', 1);
+ });
+
+ it('Members exist', function () {
+ expect(Sprite).itself.to.respondTo('fromImage');
+ expect(Sprite).itself.to.respondTo('fromFrame');
+ });
+
+ it('Confirm new instance', function (done) {
+ var texture = Texture.fromImage('/base/test/textures/SpriteSheet-Aliens.png');
+ var obj = new Sprite(texture);
+
+ pixi_display_Sprite_confirmNew(obj, done);
+ });
+});
diff --git a/test/unit/pixi/display/Stage.js b/test/unit/pixi/display/Stage.js
new file mode 100644
index 0000000..3cc2a4d
--- /dev/null
+++ b/test/unit/pixi/display/Stage.js
@@ -0,0 +1,49 @@
+describe('pixi/display/Stage', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Stage = PIXI.Stage;
+ var InteractionManager = PIXI.InteractionManager;
+ var Rectangle = PIXI.Rectangle;
+
+ it('Module exists', function () {
+ expect(Stage).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Stage(null, true);
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(Stage);
+ expect(obj).to.respondTo('updateTransform');
+ expect(obj).to.respondTo('setBackgroundColor');
+ expect(obj).to.respondTo('getMousePosition');
+
+ // FIXME: duplicate member in DisplayObject
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ // FIXME: convert arg to bool in constructor
+ expect(obj).to.have.property('interactive', true);
+
+ expect(obj).to.have.property('interactionManager')
+ .and.to.be.an.instanceof(InteractionManager)
+ .and.to.have.property('stage', obj);
+
+ expect(obj).to.have.property('dirty', true);
+
+ expect(obj).to.have.property('stage', obj);
+
+ expect(obj).to.have.property('hitArea')
+ .and.to.be.an.instanceof(Rectangle);
+ pixi_core_Rectangle_confirm(obj.hitArea, 0, 0, 100000, 100000);
+
+ expect(obj).to.have.property('backgroundColor', 0x000000);
+ expect(obj).to.have.deep.property('backgroundColorSplit.length', 3);
+ expect(obj).to.have.deep.property('backgroundColorSplit[0]', 0);
+ expect(obj).to.have.deep.property('backgroundColorSplit[1]', 0);
+ expect(obj).to.have.deep.property('backgroundColorSplit[2]', 0);
+ expect(obj).to.have.property('backgroundColorString', '#000000');
+
+ expect(obj).to.have.property('worldVisible', true);
+ });
+});
diff --git a/test/unit/pixi/extras/CustomRenderable.js b/test/unit/pixi/extras/CustomRenderable.js
new file mode 100644
index 0000000..8d83cf0
--- /dev/null
+++ b/test/unit/pixi/extras/CustomRenderable.js
@@ -0,0 +1,21 @@
+describe('pixi/extras/CustomRenderable', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var CustomRenderable = PIXI.CustomRenderable;
+
+ it('Module exists', function () {
+ expect(CustomRenderable).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new CustomRenderable();
+
+ pixi_display_DisplayObject_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(CustomRenderable);
+ expect(obj).to.respondTo('renderCanvas');
+ expect(obj).to.respondTo('initWebGL');
+ expect(obj).to.respondTo('renderWebGL');
+ });
+});
diff --git a/test/unit/pixi/extras/Rope.js b/test/unit/pixi/extras/Rope.js
new file mode 100644
index 0000000..6ddaf83
--- /dev/null
+++ b/test/unit/pixi/extras/Rope.js
@@ -0,0 +1,26 @@
+describe('pixi/extras/Rope', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Rope = PIXI.Rope;
+ var Texture = PIXI.Texture;
+ var Point = PIXI.Point;
+
+ it('Module exists', function () {
+ expect(Rope).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var texture = Texture.fromImage('/base/test/textures/bunny.png');
+ var obj = new Rope(texture, [new Point(), new Point(5, 10), new Point(10, 20)]);
+
+ pixi_extras_Strip_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(Rope);
+ expect(obj).to.respondTo('refresh');
+ expect(obj).to.respondTo('updateTransform');
+ expect(obj).to.respondTo('setTexture');
+
+ // TODO: Test properties
+ });
+});
diff --git a/test/unit/pixi/extras/Spine.js b/test/unit/pixi/extras/Spine.js
new file mode 100644
index 0000000..0708bc0
--- /dev/null
+++ b/test/unit/pixi/extras/Spine.js
@@ -0,0 +1,10 @@
+describe('pixi/extras/Spine', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Spine = PIXI.Spine;
+
+ it('Module exists', function () {
+ expect(Spine).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/extras/Strip.js b/test/unit/pixi/extras/Strip.js
new file mode 100644
index 0000000..8e564e1
--- /dev/null
+++ b/test/unit/pixi/extras/Strip.js
@@ -0,0 +1,18 @@
+describe('pixi/extras/Strip', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Strip = PIXI.Strip;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(Strip).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var texture = Texture.fromImage('/base/test/textures/bunny.png');
+ var obj = new Strip(texture, 20, 10000);
+
+ pixi_extras_Strip_confirmNew(obj);
+ });
+});
diff --git a/test/unit/pixi/extras/TilingSprite.js b/test/unit/pixi/extras/TilingSprite.js
new file mode 100644
index 0000000..56aea14
--- /dev/null
+++ b/test/unit/pixi/extras/TilingSprite.js
@@ -0,0 +1,24 @@
+describe('pixi/extras/TilingSprite', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var TilingSprite = PIXI.TilingSprite;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(TilingSprite).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var texture = Texture.fromImage('/base/test/textures/bunny.png');
+ var obj = new TilingSprite(texture, 6000, 12000);
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(TilingSprite);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ // TODO: Test properties
+ });
+});
diff --git a/test/unit/pixi/filters/FilterBlock.js b/test/unit/pixi/filters/FilterBlock.js
new file mode 100644
index 0000000..870cec0
--- /dev/null
+++ b/test/unit/pixi/filters/FilterBlock.js
@@ -0,0 +1,10 @@
+describe('pixi/filters/FilterBlock', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var FilterBlock = PIXI.FilterBlock;
+
+ it('Module exists', function () {
+ expect(FilterBlock).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/filters/MaskFilter.js b/test/unit/pixi/filters/MaskFilter.js
new file mode 100644
index 0000000..32d6a45
--- /dev/null
+++ b/test/unit/pixi/filters/MaskFilter.js
@@ -0,0 +1,10 @@
+describe('pixi/filters/MaskFilter', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ // var MaskFilter = PIXI.MaskFilter;
+
+ // it('Module exists', function () {
+ // expect(MaskFilter).to.be.a('function');
+ // });
+});
diff --git a/test/unit/pixi/loaders/AssetLoader.js b/test/unit/pixi/loaders/AssetLoader.js
new file mode 100644
index 0000000..a0aa0b5
--- /dev/null
+++ b/test/unit/pixi/loaders/AssetLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/AssetLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var AssetLoader = PIXI.AssetLoader;
+
+ it('Module exists', function () {
+ expect(AssetLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/BitmapFontLoader.js b/test/unit/pixi/loaders/BitmapFontLoader.js
new file mode 100644
index 0000000..6253c42
--- /dev/null
+++ b/test/unit/pixi/loaders/BitmapFontLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/BitmapFontLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var BitmapFontLoader = PIXI.BitmapFontLoader;
+
+ it('Module exists', function () {
+ expect(PIXI.BitmapFontLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/ImageLoader.js b/test/unit/pixi/loaders/ImageLoader.js
new file mode 100644
index 0000000..8b1f556
--- /dev/null
+++ b/test/unit/pixi/loaders/ImageLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/ImageLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var ImageLoader = PIXI.ImageLoader;
+
+ it('Module exists', function () {
+ expect(ImageLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/JsonLoader.js b/test/unit/pixi/loaders/JsonLoader.js
new file mode 100644
index 0000000..c577e83
--- /dev/null
+++ b/test/unit/pixi/loaders/JsonLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/JsonLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var JsonLoader = PIXI.JsonLoader;
+
+ it('Module exists', function () {
+ expect(JsonLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/SpineLoader.js b/test/unit/pixi/loaders/SpineLoader.js
new file mode 100644
index 0000000..fdcc0b8
--- /dev/null
+++ b/test/unit/pixi/loaders/SpineLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/SpineLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var SpineLoader = PIXI.SpineLoader;
+
+ it('Module exists', function () {
+ expect(SpineLoader).to.be.a('function');
+ });
+});
diff --git a/.gitignore b/.gitignore
index 12e1b62..0b88317 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
node_modules
.DS_Store
-.project
\ No newline at end of file
+.project
+*.log
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..63e4d7c
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,8 @@
+language: node_js
+node_js:
+ - 0.10
+
+before_script:
+ - npm install -g grunt-cli
+ - export DISPLAY=:99.0
+ - sh -e /etc/init.d/xvfb start
diff --git a/Gruntfile.js b/Gruntfile.js
index b083b49..103938c 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -1,10 +1,12 @@
+'use strict';
+
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-connect');
- grunt.loadNpmTasks('grunt-contrib-qunit');
grunt.loadNpmTasks('grunt-contrib-yuidoc');
+ grunt.loadTasks('tasks');
var root = 'src/pixi/',
debug = 'bin/pixi.dev.js',
@@ -79,7 +81,7 @@
},
files: {
srcBlob: '<%= dirs.src %>/**/*.js',
- testBlob: '<%= dirs.test %>/unit/**/*.js',
+ testBlob: '<%= dirs.test %>/{functional,lib/pixi,unit}/**/*.js',
build: '<%= dirs.build %>/pixi.dev.js',
buildMin: '<%= dirs.build %>/pixi.js'
},
@@ -94,7 +96,12 @@
},
jshint: {
beforeconcat: srcFiles,
- test: ['<%= files.testBlob %>'],
+ test: {
+ src: ['<%= files.testBlob %>'],
+ options: {
+ expr: true
+ }
+ },
options: {
asi: true,
smarttabs: true
@@ -128,12 +135,6 @@
]
},
connect: {
- qunit: {
- options: {
- port: grunt.option('port-test') || 9002,
- base: './'
- }
- },
test: {
options: {
port: grunt.option('port-test') || 9002,
@@ -142,13 +143,6 @@
}
}
},
- qunit: {
- all: {
- options: {
- urls: ['http://localhost:' + (grunt.option('port-test') || 9002) + '/test/index.html']
- }
- }
- },
yuidoc: {
compile: {
name: '<%= pkg.name %>',
@@ -161,6 +155,13 @@
outdir: '<%= dirs.docs %>'
}
}
+ },
+ karma: {
+ unit: {
+ configFile: 'test/karma.conf.js',
+ // browsers: ['Chrome'],
+ singleRun: true
+ }
}
});
@@ -182,9 +183,10 @@
}
)
- grunt.registerTask('default', ['concat', 'uglify', 'distribute']);
grunt.registerTask('build', ['concat', 'uglify', 'distribute']);
- grunt.registerTask('test', ['build', 'connect:qunit', 'qunit']);
+ grunt.registerTask('test', ['concat', 'jshint:test', 'karma']);
grunt.registerTask('docs', ['yuidoc']);
-
-}
\ No newline at end of file
+ grunt.registerTask('default', ['test', 'uglify', 'distribute']);
+ // Travis CI task.
+ grunt.registerTask('travis', ['test']);
+}
diff --git a/README.md b/README.md
index c62ef86..690cfe4 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,8 @@

+[](http://travis-ci.org/drkibitz/pixi.js)
+
#### JavaScript 2D Renderer ####
The aim of this project is to provide a fast lightweight 2D library that works
diff --git a/package.json b/package.json
index b373240..1246a68 100644
--- a/package.json
+++ b/package.json
@@ -18,14 +18,21 @@
"main": "bin/pixi.js",
+ "scripts": {
+ "test": "grunt travis --verbose"
+ },
+
"dependencies": {},
"devDependencies": {
"grunt": "~0.4.x",
- "grunt-contrib-jshint": "0.3.x",
+ "grunt-contrib-jshint": "0.6.x",
"grunt-contrib-uglify": "0.2.x",
- "grunt-contrib-connect": "0.2.x",
- "grunt-contrib-qunit": "0.2.x",
+ "grunt-contrib-connect": "0.3.x",
"grunt-contrib-yuidoc": "0.4.x",
- "grunt-contrib-concat": "0.1.x"
+ "grunt-contrib-concat": "0.3.x",
+ "chai": "~1.7.0",
+ "karma": "0.11.0",
+ "karma-firefox-launcher": "0.1.0",
+ "karma-mocha": "0.1.0"
}
}
diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js
index a7c520e..ee82bbd 100644
--- a/src/pixi/InteractionManager.js
+++ b/src/pixi/InteractionManager.js
@@ -62,7 +62,6 @@
this.onTouchEnd = this.onTouchEnd.bind(this);
this.onTouchMove = this.onTouchMove.bind(this);
-
this.last = 0;
}
diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js
index 1a95d20..eef1059 100644
--- a/src/pixi/core/Ellipse.js
+++ b/src/pixi/core/Ellipse.js
@@ -78,7 +78,7 @@
return (normx + normy < 0.25);
}
-PIXI.Ellipse.getBounds = function()
+PIXI.Ellipse.prototype.getBounds = function()
{
return new PIXI.Rectangle(this.x, this.y, this.width, this.height);
}
diff --git a/tasks/karma.js b/tasks/karma.js
new file mode 100644
index 0000000..c340485
--- /dev/null
+++ b/tasks/karma.js
@@ -0,0 +1,27 @@
+'use strict';
+
+var path = require('path');
+var server = require('karma').server;
+
+module.exports = function (grunt) {
+ grunt.registerMultiTask('karma', 'run karma.', function() {
+ var done = this.async();
+ var options = this.options({
+ background: false
+ });
+ var data = this.data;
+
+ //merge options onto data, with data taking precedence
+ data = grunt.util._.merge(options, data);
+ data.configFile = path.resolve(data.configFile);
+ if (data.configFile) {
+ data.configFile = grunt.template.process(data.configFile);
+ }
+
+ server.start(
+ data,
+ function(code) {
+ done(!code);
+ });
+ });
+};
diff --git a/test/functional/example-1-basics/bunny.png b/test/functional/example-1-basics/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/functional/example-1-basics/bunny.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-30.png b/test/functional/example-1-basics/frame-30.png
new file mode 100644
index 0000000..96e3409
--- /dev/null
+++ b/test/functional/example-1-basics/frame-30.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-60.png b/test/functional/example-1-basics/frame-60.png
new file mode 100644
index 0000000..af3f4ce
--- /dev/null
+++ b/test/functional/example-1-basics/frame-60.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-90.png b/test/functional/example-1-basics/frame-90.png
new file mode 100644
index 0000000..099b823
--- /dev/null
+++ b/test/functional/example-1-basics/frame-90.png
Binary files differ
diff --git a/test/functional/example-1-basics/index.js b/test/functional/example-1-basics/index.js
new file mode 100644
index 0000000..7ae7a98
--- /dev/null
+++ b/test/functional/example-1-basics/index.js
@@ -0,0 +1,133 @@
+describe('Example 1 - Basics', function () {
+ 'use strict';
+
+ var baseUri = '/base/test/functional/example-1-basics';
+ var expect = chai.expect;
+ var currentFrame = 0;
+ var frameEvents = {};
+ var stage;
+ var renderer;
+ var bunny;
+
+ function onFrame(frame, callback) {
+ frameEvents[frame] = callback;
+ }
+
+ function animate() {
+ currentFrame += 1;
+
+ requestAnimFrame( animate );
+
+ // just for fun, lets rotate mr rabbit a little
+ bunny.rotation += 0.1;
+
+ // render the stage
+ renderer.render(stage);
+
+ if (frameEvents[currentFrame])
+ frameEvents[currentFrame](currentFrame);
+ }
+
+ function initScene() {
+ // create an new instance of a pixi stage
+ stage = new PIXI.Stage(0x66FF99);
+
+ // create a renderer instance
+ renderer = PIXI.autoDetectRenderer(400, 300);
+ console.log('Is PIXI.WebGLRenderer: ' + (renderer instanceof PIXI.WebGLRenderer));
+
+ // add the renderer view element to the DOM
+ document.body.appendChild(renderer.view);
+
+ requestAnimFrame( animate );
+
+ // create a texture from an image path
+ var texture = PIXI.Texture.fromImage(baseUri + "/bunny.png");
+ // create a new Sprite using the texture
+ bunny = new PIXI.Sprite(texture);
+
+ // center the sprites anchor point
+ bunny.anchor.x = 0.5;
+ bunny.anchor.y = 0.5;
+
+ // move the sprite t the center of the screen
+ bunny.position.x = 200;
+ bunny.position.y = 150;
+
+ stage.addChild(bunny);
+ }
+
+ it('assets loaded', function (done) {
+ var loader = new PIXI.AssetLoader([
+ baseUri + '/bunny.png',
+ baseUri + '/frame-30.png',
+ baseUri + '/frame-60.png',
+ baseUri + '/frame-90.png'
+ ]);
+ // loader.on('onProgress', function (event) {
+ // console.log(event.content);
+ // });
+ loader.on('onComplete', function (event) {
+ done();
+ initScene();
+ });
+ loader.load();
+ });
+
+ it('frame 30 should match', function (done) {
+ this.timeout(700);
+ onFrame(30, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-30.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 60 should match', function (done) {
+ this.timeout(1200);
+ onFrame(60, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-60.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 90 should match', function (done) {
+ this.timeout(1700);
+ onFrame(90, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-90.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ // it('capture something', function (done) {
+ // this.timeout(2000000);
+ // onFrame(30, function () {
+ // var img = new Image();
+ // img.src = renderer.view.toDataURL('image/png');
+ // document.body.appendChild(img);
+ // });
+ // });
+});
diff --git a/test/index.html b/test/index.html
deleted file mode 100644
index 9cbcac5..0000000
--- a/test/index.html
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
- Pixi.js Test Suite
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/test/karma.conf.js b/test/karma.conf.js
new file mode 100644
index 0000000..c66a696
--- /dev/null
+++ b/test/karma.conf.js
@@ -0,0 +1,82 @@
+module.exports = function(config) {
+ config.set({
+
+ // base path, that will be used to resolve files and exclude
+ basePath : '../',
+
+ frameworks : ['mocha'],
+
+ // list of files / patterns to load in the browser
+ files : [
+ 'node_modules/chai/chai.js',
+ 'bin/pixi.dev.js',
+ 'test/lib/**/*.js',
+ 'test/unit/**/*.js',
+ // 'test/functional/**/*.js',
+ {pattern: 'test/**/*.png', watched: false, included: false, served: true}
+ ],
+
+ // list of files to exclude
+ exclude : [],
+
+ // use dolts reporter, as travis terminal does not support escaping sequences
+ // possible values: 'dots', 'progress', 'junit', 'teamcity'
+ // CLI --reporters progress
+ reporters : ['progress'],
+
+ // web server port
+ // CLI --port 9876
+ port : 9876,
+
+ // cli runner port
+ // CLI --runner-port 9100
+ runnerPort : 9100,
+
+ // enable / disable colors in the output (reporters and logs)
+ // CLI --colors --no-colors
+ colors : true,
+
+ // level of logging
+ // possible values: karma.LOG_DISABLE || karma.LOG_ERROR || karma.LOG_WARN || karma.LOG_INFO || karma.LOG_DEBUG
+ // CLI --log-level debug
+ logLevel : config.LOG_DEBUG,
+
+ // enable / disable watching file and executing tests whenever any file changes
+ // CLI --auto-watch --no-auto-watch
+ autoWatch : false,
+
+ // Start these browsers, currently available:
+ // - Chrome
+ // - ChromeCanary
+ // - Firefox
+ // - Opera
+ // - Safari (only Mac)
+ // - PhantomJS
+ // - IE (only Windows)
+ // CLI --browsers Chrome,Firefox,Safari
+ browsers : ['Firefox'],
+
+ // If browser does not capture in given timeout [ms], kill it
+ // CLI --capture-timeout 5000
+ captureTimeout : 5000,
+
+ // Auto run tests on start (when browsers are captured) and exit
+ // CLI --single-run --no-single-run
+ singleRun : true,
+
+ // report which specs are slower than 500ms
+ // CLI --report-slower-than 500
+ reportSlowerThan : 1000,
+
+ preprocessors : {
+ // '**/client/js/*.js': 'coverage'
+ },
+
+ plugins : [
+ 'karma-mocha',
+ // 'karma-chrome-launcher',
+ 'karma-firefox-launcher',
+ // 'karma-phantomjs-launcher'
+ ]
+ });
+};
diff --git a/test/lib/pixi/core/Matrix.js b/test/lib/pixi/core/Matrix.js
new file mode 100644
index 0000000..d26386b
--- /dev/null
+++ b/test/lib/pixi/core/Matrix.js
@@ -0,0 +1,40 @@
+
+function pixi_core_Matrix_confirmNewMat3(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(1);
+ expect(matrix[5]).to.equal(0);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(1);
+}
+
+function pixi_core_Matrix_confirmNewMat4(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[0]).to.equal(1);
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(0);
+ expect(matrix[5]).to.equal(1);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(0);
+ expect(matrix[9]).to.equal(0);
+ expect(matrix[10]).to.equal(1);
+ expect(matrix[11]).to.equal(0);
+ expect(matrix[12]).to.equal(0);
+ expect(matrix[13]).to.equal(0);
+ expect(matrix[14]).to.equal(0);
+ expect(matrix[15]).to.equal(1);
+}
diff --git a/test/lib/pixi/core/Point.js b/test/lib/pixi/core/Point.js
new file mode 100644
index 0000000..e5df07b
--- /dev/null
+++ b/test/lib/pixi/core/Point.js
@@ -0,0 +1,10 @@
+
+function pixi_core_Point_confirm(obj, x, y) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Point);
+ expect(obj).to.respondTo('clone');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+}
diff --git a/test/lib/pixi/core/Rectangle.js b/test/lib/pixi/core/Rectangle.js
new file mode 100644
index 0000000..23f0d12
--- /dev/null
+++ b/test/lib/pixi/core/Rectangle.js
@@ -0,0 +1,13 @@
+
+function pixi_core_Rectangle_confirm(obj, x, y, width, height) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Rectangle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+ expect(obj).to.have.property('width', width);
+ expect(obj).to.have.property('height', height);
+}
diff --git a/test/lib/pixi/display/DisplayObject.js b/test/lib/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..1388a7f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObject.js
@@ -0,0 +1,43 @@
+
+function pixi_display_DisplayObject_confirmNew(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObject);
+ expect(obj).to.respondTo('setInteractive');
+ expect(obj).to.respondTo('addFilter');
+ expect(obj).to.respondTo('removeFilter');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.property('last', obj);
+ expect(obj).to.have.property('first', obj);
+
+ expect(obj).to.contain.property('position');
+ pixi_core_Point_confirm(obj.position, 0, 0);
+ expect(obj).to.contain.property('scale');
+ pixi_core_Point_confirm(obj.scale, 1, 1);
+ expect(obj).to.contain.property('pivot');
+ pixi_core_Point_confirm(obj.pivot, 0, 0);
+
+ expect(obj).to.have.property('rotation', 0);
+ expect(obj).to.have.property('alpha', 1);
+ expect(obj).to.have.property('visible', true);
+ expect(obj).to.have.property('buttonMode', false);
+ expect(obj).to.have.property('parent', null);
+ expect(obj).to.have.property('worldAlpha', 1);
+
+ expect(obj).to.have.property('hitArea');
+ expect(obj).to.have.property('interactive'); // TODO: Have a better default value
+ expect('mask' in obj).to.be.true; // TODO: Have a better default value
+ expect(obj.mask).to.be.undefined;
+
+ expect(obj).to.have.property('renderable');
+ expect(obj).to.have.property('stage');
+
+ expect(obj).to.have.deep.property('worldTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ expect(obj).to.have.deep.property('localTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.localTransform);
+
+ expect(obj).to.have.deep.property('color.length', 0);
+ expect(obj).to.have.property('dynamic', true);
+}
diff --git a/test/lib/pixi/display/DisplayObjectContainer.js b/test/lib/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..085c59f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,16 @@
+
+function pixi_display_DisplayObjectContainer_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObject_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObjectContainer);
+ expect(obj).to.respondTo('addChild');
+ expect(obj).to.respondTo('addChildAt');
+ expect(obj).to.respondTo('swapChildren');
+ expect(obj).to.respondTo('getChildAt');
+ expect(obj).to.respondTo('removeChild');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('children.length', 0);
+}
diff --git a/test/lib/pixi/display/Sprite.js b/test/lib/pixi/display/Sprite.js
new file mode 100644
index 0000000..cc7a2d6
--- /dev/null
+++ b/test/lib/pixi/display/Sprite.js
@@ -0,0 +1,28 @@
+
+function pixi_display_Sprite_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Sprite);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', true);
+ expect(obj).to.have.property('stage', null);
+
+ expect(obj).to.have.property('anchor');
+ pixi_core_Point_confirm(obj.anchor, 0, 0);
+
+ expect(obj).to.have.property('blendMode', PIXI.blendModes.NORMAL);
+ expect(obj).to.have.property('width', 1); // TODO: is 1 expected
+ expect(obj).to.have.property('height', 1); // TODO: is 1 expected
+
+ // FIXME: Just make this a boolean that is always there
+ expect(!!obj.updateFrame).to.equal(obj.texture.baseTexture.hasLoaded);
+
+ expect(obj).to.have.property('texture');
+ pixi_textures_Texture_confirmNew(obj.texture, done);
+}
diff --git a/test/lib/pixi/extras/Strip.js b/test/lib/pixi/extras/Strip.js
new file mode 100644
index 0000000..8927a8a
--- /dev/null
+++ b/test/lib/pixi/extras/Strip.js
@@ -0,0 +1,12 @@
+
+function pixi_extras_Strip_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Strip);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ // TODO: Test properties
+}
diff --git a/test/lib/pixi/textures/Texture.js b/test/lib/pixi/textures/Texture.js
new file mode 100644
index 0000000..d5867b6
--- /dev/null
+++ b/test/lib/pixi/textures/Texture.js
@@ -0,0 +1,31 @@
+
+function pixi_textures_Texture_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ function confirmFrameDone() {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, obj.baseTexture.width, obj.baseTexture.height);
+
+ expect(obj).to.have.property('width', obj.baseTexture.width);
+ expect(obj).to.have.property('height', obj.baseTexture.height);
+ done();
+ }
+
+ expect(obj).to.be.an.instanceof(PIXI.Texture);
+ pixi_utils_EventTarget_like(obj);
+
+ expect(obj).to.have.property('baseTexture')
+ .and.to.be.an.instanceof(PIXI.BaseTexture);
+
+ expect(obj).to.have.property('scope', obj);
+
+ expect(obj).to.have.property('trim');
+ pixi_core_Point_confirm(obj.trim, 0, 0);
+
+ expect(obj).to.have.property('frame');
+ if (obj.baseTexture.hasLoaded) {
+ confirmFrameDone();
+ } else {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, 1, 1);
+ obj.addEventListener('update', confirmFrameDone);
+ }
+}
diff --git a/test/lib/pixi/utils/EventTarget.js b/test/lib/pixi/utils/EventTarget.js
new file mode 100644
index 0000000..7b1dcfa
--- /dev/null
+++ b/test/lib/pixi/utils/EventTarget.js
@@ -0,0 +1,8 @@
+
+function pixi_utils_EventTarget_like(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.respondTo('addEventListener');
+ expect(obj).to.respondTo('dispatchEvent');
+ expect(obj).to.respondTo('removeEventListener');
+}
diff --git a/test/lib/qunit-1.11.0.css b/test/lib/qunit-1.11.0.css
deleted file mode 100644
index d7fc0c8..0000000
--- a/test/lib/qunit-1.11.0.css
+++ /dev/null
@@ -1,244 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-/** Font Family and Sizes */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
- font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
-}
-
-#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
-#qunit-tests { font-size: smaller; }
-
-
-/** Resets */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter {
- margin: 0;
- padding: 0;
-}
-
-
-/** Header */
-
-#qunit-header {
- padding: 0.5em 0 0.5em 1em;
-
- color: #8699a4;
- background-color: #0d3349;
-
- font-size: 1.5em;
- line-height: 1em;
- font-weight: normal;
-
- border-radius: 5px 5px 0 0;
- -moz-border-radius: 5px 5px 0 0;
- -webkit-border-top-right-radius: 5px;
- -webkit-border-top-left-radius: 5px;
-}
-
-#qunit-header a {
- text-decoration: none;
- color: #c2ccd1;
-}
-
-#qunit-header a:hover,
-#qunit-header a:focus {
- color: #fff;
-}
-
-#qunit-testrunner-toolbar label {
- display: inline-block;
- padding: 0 .5em 0 .1em;
-}
-
-#qunit-banner {
- height: 5px;
-}
-
-#qunit-testrunner-toolbar {
- padding: 0.5em 0 0.5em 2em;
- color: #5E740B;
- background-color: #eee;
- overflow: hidden;
-}
-
-#qunit-userAgent {
- padding: 0.5em 0 0.5em 2.5em;
- background-color: #2b81af;
- color: #fff;
- text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
-}
-
-#qunit-modulefilter-container {
- float: right;
-}
-
-/** Tests: Pass/Fail */
-
-#qunit-tests {
- list-style-position: inside;
-}
-
-#qunit-tests li {
- padding: 0.4em 0.5em 0.4em 2.5em;
- border-bottom: 1px solid #fff;
- list-style-position: inside;
-}
-
-#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running {
- display: none;
-}
-
-#qunit-tests li strong {
- cursor: pointer;
-}
-
-#qunit-tests li a {
- padding: 0.5em;
- color: #c2ccd1;
- text-decoration: none;
-}
-#qunit-tests li a:hover,
-#qunit-tests li a:focus {
- color: #000;
-}
-
-#qunit-tests li .runtime {
- float: right;
- font-size: smaller;
-}
-
-.qunit-assert-list {
- margin-top: 0.5em;
- padding: 0.5em;
-
- background-color: #fff;
-
- border-radius: 5px;
- -moz-border-radius: 5px;
- -webkit-border-radius: 5px;
-}
-
-.qunit-collapsed {
- display: none;
-}
-
-#qunit-tests table {
- border-collapse: collapse;
- margin-top: .2em;
-}
-
-#qunit-tests th {
- text-align: right;
- vertical-align: top;
- padding: 0 .5em 0 0;
-}
-
-#qunit-tests td {
- vertical-align: top;
-}
-
-#qunit-tests pre {
- margin: 0;
- white-space: pre-wrap;
- word-wrap: break-word;
-}
-
-#qunit-tests del {
- background-color: #e0f2be;
- color: #374e0c;
- text-decoration: none;
-}
-
-#qunit-tests ins {
- background-color: #ffcaca;
- color: #500;
- text-decoration: none;
-}
-
-/*** Test Counts */
-
-#qunit-tests b.counts { color: black; }
-#qunit-tests b.passed { color: #5E740B; }
-#qunit-tests b.failed { color: #710909; }
-
-#qunit-tests li li {
- padding: 5px;
- background-color: #fff;
- border-bottom: none;
- list-style-position: inside;
-}
-
-/*** Passing Styles */
-
-#qunit-tests li li.pass {
- color: #3c510c;
- background-color: #fff;
- border-left: 10px solid #C6E746;
-}
-
-#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
-#qunit-tests .pass .test-name { color: #366097; }
-
-#qunit-tests .pass .test-actual,
-#qunit-tests .pass .test-expected { color: #999999; }
-
-#qunit-banner.qunit-pass { background-color: #C6E746; }
-
-/*** Failing Styles */
-
-#qunit-tests li li.fail {
- color: #710909;
- background-color: #fff;
- border-left: 10px solid #EE5757;
- white-space: pre;
-}
-
-#qunit-tests > li:last-child {
- border-radius: 0 0 5px 5px;
- -moz-border-radius: 0 0 5px 5px;
- -webkit-border-bottom-right-radius: 5px;
- -webkit-border-bottom-left-radius: 5px;
-}
-
-#qunit-tests .fail { color: #000000; background-color: #EE5757; }
-#qunit-tests .fail .test-name,
-#qunit-tests .fail .module-name { color: #000000; }
-
-#qunit-tests .fail .test-actual { color: #EE5757; }
-#qunit-tests .fail .test-expected { color: green; }
-
-#qunit-banner.qunit-fail { background-color: #EE5757; }
-
-
-/** Result */
-
-#qunit-testresult {
- padding: 0.5em 0.5em 0.5em 2.5em;
-
- color: #2b81af;
- background-color: #D2E0E6;
-
- border-bottom: 1px solid white;
-}
-#qunit-testresult .module-name {
- font-weight: bold;
-}
-
-/** Fixture */
-
-#qunit-fixture {
- position: absolute;
- top: -10000px;
- left: -10000px;
- width: 1000px;
- height: 1000px;
-}
diff --git a/test/lib/qunit-1.11.0.js b/test/lib/qunit-1.11.0.js
deleted file mode 100644
index 302545f..0000000
--- a/test/lib/qunit-1.11.0.js
+++ /dev/null
@@ -1,2152 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-(function( window ) {
-
-var QUnit,
- assert,
- config,
- onErrorFnPrev,
- testId = 0,
- fileName = (sourceFromStacktrace( 0 ) || "" ).replace(/(:\d+)+\)?/, "").replace(/.+\//, ""),
- toString = Object.prototype.toString,
- hasOwn = Object.prototype.hasOwnProperty,
- // Keep a local reference to Date (GH-283)
- Date = window.Date,
- defined = {
- setTimeout: typeof window.setTimeout !== "undefined",
- sessionStorage: (function() {
- var x = "qunit-test-string";
- try {
- sessionStorage.setItem( x, x );
- sessionStorage.removeItem( x );
- return true;
- } catch( e ) {
- return false;
- }
- }())
- },
- /**
- * Provides a normalized error string, correcting an issue
- * with IE 7 (and prior) where Error.prototype.toString is
- * not properly implemented
- *
- * Based on http://es5.github.com/#x15.11.4.4
- *
- * @param {String|Error} error
- * @return {String} error message
- */
- errorString = function( error ) {
- var name, message,
- errorString = error.toString();
- if ( errorString.substring( 0, 7 ) === "[object" ) {
- name = error.name ? error.name.toString() : "Error";
- message = error.message ? error.message.toString() : "";
- if ( name && message ) {
- return name + ": " + message;
- } else if ( name ) {
- return name;
- } else if ( message ) {
- return message;
- } else {
- return "Error";
- }
- } else {
- return errorString;
- }
- },
- /**
- * Makes a clone of an object using only Array or Object as base,
- * and copies over the own enumerable properties.
- *
- * @param {Object} obj
- * @return {Object} New object with only the own properties (recursively).
- */
- objectValues = function( obj ) {
- // Grunt 0.3.x uses an older version of jshint that still has jshint/jshint#392.
- /*jshint newcap: false */
- var key, val,
- vals = QUnit.is( "array", obj ) ? [] : {};
- for ( key in obj ) {
- if ( hasOwn.call( obj, key ) ) {
- val = obj[key];
- vals[key] = val === Object(val) ? objectValues(val) : val;
- }
- }
- return vals;
- };
-
-function Test( settings ) {
- extend( this, settings );
- this.assertions = [];
- this.testNumber = ++Test.count;
-}
-
-Test.count = 0;
-
-Test.prototype = {
- init: function() {
- var a, b, li,
- tests = id( "qunit-tests" );
-
- if ( tests ) {
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml;
-
- // `a` initialized at top of scope
- a = document.createElement( "a" );
- a.innerHTML = "Rerun";
- a.href = QUnit.url({ testNumber: this.testNumber });
-
- li = document.createElement( "li" );
- li.appendChild( b );
- li.appendChild( a );
- li.className = "running";
- li.id = this.id = "qunit-test-output" + testId++;
-
- tests.appendChild( li );
- }
- },
- setup: function() {
- if ( this.module !== config.previousModule ) {
- if ( config.previousModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.previousModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
- config.previousModule = this.module;
- config.moduleStats = { all: 0, bad: 0 };
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- } else if ( config.autorun ) {
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- }
-
- config.current = this;
-
- this.testEnvironment = extend({
- setup: function() {},
- teardown: function() {}
- }, this.moduleTestEnvironment );
-
- this.started = +new Date();
- runLoggingCallbacks( "testStart", QUnit, {
- name: this.testName,
- module: this.module
- });
-
- // allow utility functions to access the current test environment
- // TODO why??
- QUnit.current_testEnvironment = this.testEnvironment;
-
- if ( !config.pollution ) {
- saveGlobal();
- }
- if ( config.notrycatch ) {
- this.testEnvironment.setup.call( this.testEnvironment );
- return;
- }
- try {
- this.testEnvironment.setup.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Setup failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- },
- run: function() {
- config.current = this;
-
- var running = id( "qunit-testresult" );
-
- if ( running ) {
- running.innerHTML = "Running:
" + this.nameHtml;
- }
-
- if ( this.async ) {
- QUnit.stop();
- }
-
- this.callbackStarted = +new Date();
-
- if ( config.notrycatch ) {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- return;
- }
-
- try {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- } catch( e ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
-
- QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + " " + this.stack + ": " + ( e.message || e ), extractStacktrace( e, 0 ) );
- // else next test will carry the responsibility
- saveGlobal();
-
- // Restart the tests if they're blocking
- if ( config.blocking ) {
- QUnit.start();
- }
- }
- },
- teardown: function() {
- config.current = this;
- if ( config.notrycatch ) {
- if ( typeof this.callbackRuntime === "undefined" ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
- }
- this.testEnvironment.teardown.call( this.testEnvironment );
- return;
- } else {
- try {
- this.testEnvironment.teardown.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Teardown failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- }
- checkPollution();
- },
- finish: function() {
- config.current = this;
- if ( config.requireExpects && this.expected === null ) {
- QUnit.pushFailure( "Expected number of assertions to be defined, but expect() was not called.", this.stack );
- } else if ( this.expected !== null && this.expected !== this.assertions.length ) {
- QUnit.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack );
- } else if ( this.expected === null && !this.assertions.length ) {
- QUnit.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions.", this.stack );
- }
-
- var i, assertion, a, b, time, li, ol,
- test = this,
- good = 0,
- bad = 0,
- tests = id( "qunit-tests" );
-
- this.runtime = +new Date() - this.started;
- config.stats.all += this.assertions.length;
- config.moduleStats.all += this.assertions.length;
-
- if ( tests ) {
- ol = document.createElement( "ol" );
- ol.className = "qunit-assert-list";
-
- for ( i = 0; i < this.assertions.length; i++ ) {
- assertion = this.assertions[i];
-
- li = document.createElement( "li" );
- li.className = assertion.result ? "pass" : "fail";
- li.innerHTML = assertion.message || ( assertion.result ? "okay" : "failed" );
- ol.appendChild( li );
-
- if ( assertion.result ) {
- good++;
- } else {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
-
- // store result when possible
- if ( QUnit.config.reorder && defined.sessionStorage ) {
- if ( bad ) {
- sessionStorage.setItem( "qunit-test-" + this.module + "-" + this.testName, bad );
- } else {
- sessionStorage.removeItem( "qunit-test-" + this.module + "-" + this.testName );
- }
- }
-
- if ( bad === 0 ) {
- addClass( ol, "qunit-collapsed" );
- }
-
- // `b` initialized at top of scope
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml + " (" + bad + ", " + good + ", " + this.assertions.length + ")";
-
- addEvent(b, "click", function() {
- var next = b.parentNode.lastChild,
- collapsed = hasClass( next, "qunit-collapsed" );
- ( collapsed ? removeClass : addClass )( next, "qunit-collapsed" );
- });
-
- addEvent(b, "dblclick", function( e ) {
- var target = e && e.target ? e.target : window.event.srcElement;
- if ( target.nodeName.toLowerCase() === "span" || target.nodeName.toLowerCase() === "b" ) {
- target = target.parentNode;
- }
- if ( window.location && target.nodeName.toLowerCase() === "strong" ) {
- window.location = QUnit.url({ testNumber: test.testNumber });
- }
- });
-
- // `time` initialized at top of scope
- time = document.createElement( "span" );
- time.className = "runtime";
- time.innerHTML = this.runtime + " ms";
-
- // `li` initialized at top of scope
- li = id( this.id );
- li.className = bad ? "fail" : "pass";
- li.removeChild( li.firstChild );
- a = li.firstChild;
- li.appendChild( b );
- li.appendChild( a );
- li.appendChild( time );
- li.appendChild( ol );
-
- } else {
- for ( i = 0; i < this.assertions.length; i++ ) {
- if ( !this.assertions[i].result ) {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
- }
-
- runLoggingCallbacks( "testDone", QUnit, {
- name: this.testName,
- module: this.module,
- failed: bad,
- passed: this.assertions.length - bad,
- total: this.assertions.length,
- duration: this.runtime
- });
-
- QUnit.reset();
-
- config.current = undefined;
- },
-
- queue: function() {
- var bad,
- test = this;
-
- synchronize(function() {
- test.init();
- });
- function run() {
- // each of these can by async
- synchronize(function() {
- test.setup();
- });
- synchronize(function() {
- test.run();
- });
- synchronize(function() {
- test.teardown();
- });
- synchronize(function() {
- test.finish();
- });
- }
-
- // `bad` initialized at top of scope
- // defer when previous test run passed, if storage is available
- bad = QUnit.config.reorder && defined.sessionStorage &&
- +sessionStorage.getItem( "qunit-test-" + this.module + "-" + this.testName );
-
- if ( bad ) {
- run();
- } else {
- synchronize( run, true );
- }
- }
-};
-
-// Root QUnit object.
-// `QUnit` initialized at top of scope
-QUnit = {
-
- // call on start of module test to prepend name to all tests
- module: function( name, testEnvironment ) {
- config.currentModule = name;
- config.currentModuleTestEnvironment = testEnvironment;
- config.modules[name] = true;
- },
-
- asyncTest: function( testName, expected, callback ) {
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- QUnit.test( testName, expected, callback, true );
- },
-
- test: function( testName, expected, callback, async ) {
- var test,
- nameHtml = "" + escapeText( testName ) + "";
-
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- if ( config.currentModule ) {
- nameHtml = "" + escapeText( config.currentModule ) + ": " + nameHtml;
- }
-
- test = new Test({
- nameHtml: nameHtml,
- testName: testName,
- expected: expected,
- async: async,
- callback: callback,
- module: config.currentModule,
- moduleTestEnvironment: config.currentModuleTestEnvironment,
- stack: sourceFromStacktrace( 2 )
- });
-
- if ( !validTest( test ) ) {
- return;
- }
-
- test.queue();
- },
-
- // Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through.
- expect: function( asserts ) {
- if (arguments.length === 1) {
- config.current.expected = asserts;
- } else {
- return config.current.expected;
- }
- },
-
- start: function( count ) {
- // QUnit hasn't been initialized yet.
- // Note: RequireJS (et al) may delay onLoad
- if ( config.semaphore === undefined ) {
- QUnit.begin(function() {
- // This is triggered at the top of QUnit.load, push start() to the event loop, to allow QUnit.load to finish first
- setTimeout(function() {
- QUnit.start( count );
- });
- });
- return;
- }
-
- config.semaphore -= count || 1;
- // don't start until equal number of stop-calls
- if ( config.semaphore > 0 ) {
- return;
- }
- // ignore if start is called more often then stop
- if ( config.semaphore < 0 ) {
- config.semaphore = 0;
- QUnit.pushFailure( "Called start() while already started (QUnit.config.semaphore was 0 already)", null, sourceFromStacktrace(2) );
- return;
- }
- // A slight delay, to avoid any current callbacks
- if ( defined.setTimeout ) {
- window.setTimeout(function() {
- if ( config.semaphore > 0 ) {
- return;
- }
- if ( config.timeout ) {
- clearTimeout( config.timeout );
- }
-
- config.blocking = false;
- process( true );
- }, 13);
- } else {
- config.blocking = false;
- process( true );
- }
- },
-
- stop: function( count ) {
- config.semaphore += count || 1;
- config.blocking = true;
-
- if ( config.testTimeout && defined.setTimeout ) {
- clearTimeout( config.timeout );
- config.timeout = window.setTimeout(function() {
- QUnit.ok( false, "Test timed out" );
- config.semaphore = 1;
- QUnit.start();
- }, config.testTimeout );
- }
- }
-};
-
-// `assert` initialized at top of scope
-// Asssert helpers
-// All of these must either call QUnit.push() or manually do:
-// - runLoggingCallbacks( "log", .. );
-// - config.current.assertions.push({ .. });
-// We attach it to the QUnit object *after* we expose the public API,
-// otherwise `assert` will become a global variable in browsers (#341).
-assert = {
- /**
- * Asserts rough true-ish result.
- * @name ok
- * @function
- * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" );
- */
- ok: function( result, msg ) {
- if ( !config.current ) {
- throw new Error( "ok() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
- result = !!result;
-
- var source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: msg
- };
-
- msg = escapeText( msg || (result ? "okay" : "failed" ) );
- msg = "" + msg + "";
-
- if ( !result ) {
- source = sourceFromStacktrace( 2 );
- if ( source ) {
- details.source = source;
- msg += "Source: | " + escapeText( source ) + " |
---|
";
- }
- }
- runLoggingCallbacks( "log", QUnit, details );
- config.current.assertions.push({
- result: result,
- message: msg
- });
- },
-
- /**
- * Assert that the first two arguments are equal, with an optional message.
- * Prints out both actual and expected values.
- * @name equal
- * @function
- * @example equal( format( "Received {0} bytes.", 2), "Received 2 bytes.", "format() replaces {0} with next argument" );
- */
- equal: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected == actual, actual, expected, message );
- },
-
- /**
- * @name notEqual
- * @function
- */
- notEqual: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected != actual, actual, expected, message );
- },
-
- /**
- * @name propEqual
- * @function
- */
- propEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notPropEqual
- * @function
- */
- notPropEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name deepEqual
- * @function
- */
- deepEqual: function( actual, expected, message ) {
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notDeepEqual
- * @function
- */
- notDeepEqual: function( actual, expected, message ) {
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name strictEqual
- * @function
- */
- strictEqual: function( actual, expected, message ) {
- QUnit.push( expected === actual, actual, expected, message );
- },
-
- /**
- * @name notStrictEqual
- * @function
- */
- notStrictEqual: function( actual, expected, message ) {
- QUnit.push( expected !== actual, actual, expected, message );
- },
-
- "throws": function( block, expected, message ) {
- var actual,
- expectedOutput = expected,
- ok = false;
-
- // 'expected' is optional
- if ( typeof expected === "string" ) {
- message = expected;
- expected = null;
- }
-
- config.current.ignoreGlobalErrors = true;
- try {
- block.call( config.current.testEnvironment );
- } catch (e) {
- actual = e;
- }
- config.current.ignoreGlobalErrors = false;
-
- if ( actual ) {
- // we don't want to validate thrown error
- if ( !expected ) {
- ok = true;
- expectedOutput = null;
- // expected is a regexp
- } else if ( QUnit.objectType( expected ) === "regexp" ) {
- ok = expected.test( errorString( actual ) );
- // expected is a constructor
- } else if ( actual instanceof expected ) {
- ok = true;
- // expected is a validation function which returns true is validation passed
- } else if ( expected.call( {}, actual ) === true ) {
- expectedOutput = null;
- ok = true;
- }
-
- QUnit.push( ok, actual, expectedOutput, message );
- } else {
- QUnit.pushFailure( message, null, 'No exception was thrown.' );
- }
- }
-};
-
-/**
- * @deprecate since 1.8.0
- * Kept assertion helpers in root for backwards compatibility.
- */
-extend( QUnit, assert );
-
-/**
- * @deprecated since 1.9.0
- * Kept root "raises()" for backwards compatibility.
- * (Note that we don't introduce assert.raises).
- */
-QUnit.raises = assert[ "throws" ];
-
-/**
- * @deprecated since 1.0.0, replaced with error pushes since 1.3.0
- * Kept to avoid TypeErrors for undefined methods.
- */
-QUnit.equals = function() {
- QUnit.push( false, false, false, "QUnit.equals has been deprecated since 2009 (e88049a0), use QUnit.equal instead" );
-};
-QUnit.same = function() {
- QUnit.push( false, false, false, "QUnit.same has been deprecated since 2009 (e88049a0), use QUnit.deepEqual instead" );
-};
-
-// We want access to the constructor's prototype
-(function() {
- function F() {}
- F.prototype = QUnit;
- QUnit = new F();
- // Make F QUnit's constructor so that we can add to the prototype later
- QUnit.constructor = F;
-}());
-
-/**
- * Config object: Maintain internal state
- * Later exposed as QUnit.config
- * `config` initialized at top of scope
- */
-config = {
- // The queue of tests to run
- queue: [],
-
- // block until document ready
- blocking: true,
-
- // when enabled, show only failing tests
- // gets persisted through sessionStorage and can be changed in UI via checkbox
- hidepassed: false,
-
- // by default, run previously failed tests first
- // very useful in combination with "Hide passed tests" checked
- reorder: true,
-
- // by default, modify document.title when suite is done
- altertitle: true,
-
- // when enabled, all tests must call expect()
- requireExpects: false,
-
- // add checkboxes that are persisted in the query-string
- // when enabled, the id is set to `true` as a `QUnit.config` property
- urlConfig: [
- {
- id: "noglobals",
- label: "Check for Globals",
- tooltip: "Enabling this will test if any test introduces new properties on the `window` object. Stored as query-strings."
- },
- {
- id: "notrycatch",
- label: "No try-catch",
- tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging exceptions in IE reasonable. Stored as query-strings."
- }
- ],
-
- // Set of all modules.
- modules: {},
-
- // logging callback queues
- begin: [],
- done: [],
- log: [],
- testStart: [],
- testDone: [],
- moduleStart: [],
- moduleDone: []
-};
-
-// Export global variables, unless an 'exports' object exists,
-// in that case we assume we're in CommonJS (dealt with on the bottom of the script)
-if ( typeof exports === "undefined" ) {
- extend( window, QUnit );
-
- // Expose QUnit object
- window.QUnit = QUnit;
-}
-
-// Initialize more QUnit.config and QUnit.urlParams
-(function() {
- var i,
- location = window.location || { search: "", protocol: "file:" },
- params = location.search.slice( 1 ).split( "&" ),
- length = params.length,
- urlParams = {},
- current;
-
- if ( params[ 0 ] ) {
- for ( i = 0; i < length; i++ ) {
- current = params[ i ].split( "=" );
- current[ 0 ] = decodeURIComponent( current[ 0 ] );
- // allow just a key to turn on a flag, e.g., test.html?noglobals
- current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true;
- urlParams[ current[ 0 ] ] = current[ 1 ];
- }
- }
-
- QUnit.urlParams = urlParams;
-
- // String search anywhere in moduleName+testName
- config.filter = urlParams.filter;
-
- // Exact match of the module name
- config.module = urlParams.module;
-
- config.testNumber = parseInt( urlParams.testNumber, 10 ) || null;
-
- // Figure out if we're running the tests from a server or not
- QUnit.isLocal = location.protocol === "file:";
-}());
-
-// Extend QUnit object,
-// these after set here because they should not be exposed as global functions
-extend( QUnit, {
- assert: assert,
-
- config: config,
-
- // Initialize the configuration options
- init: function() {
- extend( config, {
- stats: { all: 0, bad: 0 },
- moduleStats: { all: 0, bad: 0 },
- started: +new Date(),
- updateRate: 1000,
- blocking: false,
- autostart: true,
- autorun: false,
- filter: "",
- queue: [],
- semaphore: 1
- });
-
- var tests, banner, result,
- qunit = id( "qunit" );
-
- if ( qunit ) {
- qunit.innerHTML =
- "" +
- "" +
- "" +
- "" +
- "
";
- }
-
- tests = id( "qunit-tests" );
- banner = id( "qunit-banner" );
- result = id( "qunit-testresult" );
-
- if ( tests ) {
- tests.innerHTML = "";
- }
-
- if ( banner ) {
- banner.className = "";
- }
-
- if ( result ) {
- result.parentNode.removeChild( result );
- }
-
- if ( tests ) {
- result = document.createElement( "p" );
- result.id = "qunit-testresult";
- result.className = "result";
- tests.parentNode.insertBefore( result, tests );
- result.innerHTML = "Running...
";
- }
- },
-
- // Resets the test setup. Useful for tests that modify the DOM.
- reset: function() {
- var fixture = id( "qunit-fixture" );
- if ( fixture ) {
- fixture.innerHTML = config.fixture;
- }
- },
-
- // Trigger an event on an element.
- // @example triggerEvent( document.body, "click" );
- triggerEvent: function( elem, type, event ) {
- if ( document.createEvent ) {
- event = document.createEvent( "MouseEvents" );
- event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView,
- 0, 0, 0, 0, 0, false, false, false, false, 0, null);
-
- elem.dispatchEvent( event );
- } else if ( elem.fireEvent ) {
- elem.fireEvent( "on" + type );
- }
- },
-
- // Safe object type checking
- is: function( type, obj ) {
- return QUnit.objectType( obj ) === type;
- },
-
- objectType: function( obj ) {
- if ( typeof obj === "undefined" ) {
- return "undefined";
- // consider: typeof null === object
- }
- if ( obj === null ) {
- return "null";
- }
-
- var match = toString.call( obj ).match(/^\[object\s(.*)\]$/),
- type = match && match[1] || "";
-
- switch ( type ) {
- case "Number":
- if ( isNaN(obj) ) {
- return "nan";
- }
- return "number";
- case "String":
- case "Boolean":
- case "Array":
- case "Date":
- case "RegExp":
- case "Function":
- return type.toLowerCase();
- }
- if ( typeof obj === "object" ) {
- return "object";
- }
- return undefined;
- },
-
- push: function( result, actual, expected, message ) {
- if ( !config.current ) {
- throw new Error( "assertion outside test context, was " + sourceFromStacktrace() );
- }
-
- var output, source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: message,
- actual: actual,
- expected: expected
- };
-
- message = escapeText( message ) || ( result ? "okay" : "failed" );
- message = "" + message + "";
- output = message;
-
- if ( !result ) {
- expected = escapeText( QUnit.jsDump.parse(expected) );
- actual = escapeText( QUnit.jsDump.parse(actual) );
- output += "Expected: | " + expected + " |
";
-
- if ( actual !== expected ) {
- output += "Result: | " + actual + " |
";
- output += "Diff: | " + QUnit.diff( expected, actual ) + " |
";
- }
-
- source = sourceFromStacktrace();
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
- }
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: !!result,
- message: output
- });
- },
-
- pushFailure: function( message, source, actual ) {
- if ( !config.current ) {
- throw new Error( "pushFailure() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
-
- var output,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: false,
- message: message
- };
-
- message = escapeText( message ) || "error";
- message = "" + message + "";
- output = message;
-
- output += "";
-
- if ( actual ) {
- output += "Result: | " + escapeText( actual ) + " |
";
- }
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: false,
- message: output
- });
- },
-
- url: function( params ) {
- params = extend( extend( {}, QUnit.urlParams ), params );
- var key,
- querystring = "?";
-
- for ( key in params ) {
- if ( !hasOwn.call( params, key ) ) {
- continue;
- }
- querystring += encodeURIComponent( key ) + "=" +
- encodeURIComponent( params[ key ] ) + "&";
- }
- return window.location.protocol + "//" + window.location.host +
- window.location.pathname + querystring.slice( 0, -1 );
- },
-
- extend: extend,
- id: id,
- addEvent: addEvent
- // load, equiv, jsDump, diff: Attached later
-});
-
-/**
- * @deprecated: Created for backwards compatibility with test runner that set the hook function
- * into QUnit.{hook}, instead of invoking it and passing the hook function.
- * QUnit.constructor is set to the empty F() above so that we can add to it's prototype here.
- * Doing this allows us to tell if the following methods have been overwritten on the actual
- * QUnit object.
- */
-extend( QUnit.constructor.prototype, {
-
- // Logging callbacks; all receive a single argument with the listed properties
- // run test/logs.html for any related changes
- begin: registerLoggingCallback( "begin" ),
-
- // done: { failed, passed, total, runtime }
- done: registerLoggingCallback( "done" ),
-
- // log: { result, actual, expected, message }
- log: registerLoggingCallback( "log" ),
-
- // testStart: { name }
- testStart: registerLoggingCallback( "testStart" ),
-
- // testDone: { name, failed, passed, total, duration }
- testDone: registerLoggingCallback( "testDone" ),
-
- // moduleStart: { name }
- moduleStart: registerLoggingCallback( "moduleStart" ),
-
- // moduleDone: { name, failed, passed, total }
- moduleDone: registerLoggingCallback( "moduleDone" )
-});
-
-if ( typeof document === "undefined" || document.readyState === "complete" ) {
- config.autorun = true;
-}
-
-QUnit.load = function() {
- runLoggingCallbacks( "begin", QUnit, {} );
-
- // Initialize the config, saving the execution queue
- var banner, filter, i, label, len, main, ol, toolbar, userAgent, val,
- urlConfigCheckboxesContainer, urlConfigCheckboxes, moduleFilter,
- numModules = 0,
- moduleFilterHtml = "",
- urlConfigHtml = "",
- oldconfig = extend( {}, config );
-
- QUnit.init();
- extend(config, oldconfig);
-
- config.blocking = false;
-
- len = config.urlConfig.length;
-
- for ( i = 0; i < len; i++ ) {
- val = config.urlConfig[i];
- if ( typeof val === "string" ) {
- val = {
- id: val,
- label: val,
- tooltip: "[no tooltip available]"
- };
- }
- config[ val.id ] = QUnit.urlParams[ val.id ];
- urlConfigHtml += "";
- }
-
- moduleFilterHtml += "";
-
- // `userAgent` initialized at top of scope
- userAgent = id( "qunit-userAgent" );
- if ( userAgent ) {
- userAgent.innerHTML = navigator.userAgent;
- }
-
- // `banner` initialized at top of scope
- banner = id( "qunit-header" );
- if ( banner ) {
- banner.innerHTML = "" + banner.innerHTML + " ";
- }
-
- // `toolbar` initialized at top of scope
- toolbar = id( "qunit-testrunner-toolbar" );
- if ( toolbar ) {
- // `filter` initialized at top of scope
- filter = document.createElement( "input" );
- filter.type = "checkbox";
- filter.id = "qunit-filter-pass";
-
- addEvent( filter, "click", function() {
- var tmp,
- ol = document.getElementById( "qunit-tests" );
-
- if ( filter.checked ) {
- ol.className = ol.className + " hidepass";
- } else {
- tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " ";
- ol.className = tmp.replace( / hidepass /, " " );
- }
- if ( defined.sessionStorage ) {
- if (filter.checked) {
- sessionStorage.setItem( "qunit-filter-passed-tests", "true" );
- } else {
- sessionStorage.removeItem( "qunit-filter-passed-tests" );
- }
- }
- });
-
- if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem( "qunit-filter-passed-tests" ) ) {
- filter.checked = true;
- // `ol` initialized at top of scope
- ol = document.getElementById( "qunit-tests" );
- ol.className = ol.className + " hidepass";
- }
- toolbar.appendChild( filter );
-
- // `label` initialized at top of scope
- label = document.createElement( "label" );
- label.setAttribute( "for", "qunit-filter-pass" );
- label.setAttribute( "title", "Only show tests and assertons that fail. Stored in sessionStorage." );
- label.innerHTML = "Hide passed tests";
- toolbar.appendChild( label );
-
- urlConfigCheckboxesContainer = document.createElement("span");
- urlConfigCheckboxesContainer.innerHTML = urlConfigHtml;
- urlConfigCheckboxes = urlConfigCheckboxesContainer.getElementsByTagName("input");
- // For oldIE support:
- // * Add handlers to the individual elements instead of the container
- // * Use "click" instead of "change"
- // * Fallback from event.target to event.srcElement
- addEvents( urlConfigCheckboxes, "click", function( event ) {
- var params = {},
- target = event.target || event.srcElement;
- params[ target.name ] = target.checked ? true : undefined;
- window.location = QUnit.url( params );
- });
- toolbar.appendChild( urlConfigCheckboxesContainer );
-
- if (numModules > 1) {
- moduleFilter = document.createElement( 'span' );
- moduleFilter.setAttribute( 'id', 'qunit-modulefilter-container' );
- moduleFilter.innerHTML = moduleFilterHtml;
- addEvent( moduleFilter.lastChild, "change", function() {
- var selectBox = moduleFilter.getElementsByTagName("select")[0],
- selectedModule = decodeURIComponent(selectBox.options[selectBox.selectedIndex].value);
-
- window.location = QUnit.url( { module: ( selectedModule === "" ) ? undefined : selectedModule } );
- });
- toolbar.appendChild(moduleFilter);
- }
- }
-
- // `main` initialized at top of scope
- main = id( "qunit-fixture" );
- if ( main ) {
- config.fixture = main.innerHTML;
- }
-
- if ( config.autostart ) {
- QUnit.start();
- }
-};
-
-addEvent( window, "load", QUnit.load );
-
-// `onErrorFnPrev` initialized at top of scope
-// Preserve other handlers
-onErrorFnPrev = window.onerror;
-
-// Cover uncaught exceptions
-// Returning true will surpress the default browser handler,
-// returning false will let it run.
-window.onerror = function ( error, filePath, linerNr ) {
- var ret = false;
- if ( onErrorFnPrev ) {
- ret = onErrorFnPrev( error, filePath, linerNr );
- }
-
- // Treat return value as window.onerror itself does,
- // Only do our handling if not surpressed.
- if ( ret !== true ) {
- if ( QUnit.config.current ) {
- if ( QUnit.config.current.ignoreGlobalErrors ) {
- return true;
- }
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- } else {
- QUnit.test( "global failure", extend( function() {
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- }, { validTest: validTest } ) );
- }
- return false;
- }
-
- return ret;
-};
-
-function done() {
- config.autorun = true;
-
- // Log the last module results
- if ( config.currentModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.currentModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
-
- var i, key,
- banner = id( "qunit-banner" ),
- tests = id( "qunit-tests" ),
- runtime = +new Date() - config.started,
- passed = config.stats.all - config.stats.bad,
- html = [
- "Tests completed in ",
- runtime,
- " milliseconds.
",
- "",
- passed,
- " assertions of ",
- config.stats.all,
- " passed, ",
- config.stats.bad,
- " failed."
- ].join( "" );
-
- if ( banner ) {
- banner.className = ( config.stats.bad ? "qunit-fail" : "qunit-pass" );
- }
-
- if ( tests ) {
- id( "qunit-testresult" ).innerHTML = html;
- }
-
- if ( config.altertitle && typeof document !== "undefined" && document.title ) {
- // show ✖ for good, ✔ for bad suite result in title
- // use escape sequences in case file gets loaded with non-utf-8-charset
- document.title = [
- ( config.stats.bad ? "\u2716" : "\u2714" ),
- document.title.replace( /^[\u2714\u2716] /i, "" )
- ].join( " " );
- }
-
- // clear own sessionStorage items if all tests passed
- if ( config.reorder && defined.sessionStorage && config.stats.bad === 0 ) {
- // `key` & `i` initialized at top of scope
- for ( i = 0; i < sessionStorage.length; i++ ) {
- key = sessionStorage.key( i++ );
- if ( key.indexOf( "qunit-test-" ) === 0 ) {
- sessionStorage.removeItem( key );
- }
- }
- }
-
- // scroll back to top to show results
- if ( window.scrollTo ) {
- window.scrollTo(0, 0);
- }
-
- runLoggingCallbacks( "done", QUnit, {
- failed: config.stats.bad,
- passed: passed,
- total: config.stats.all,
- runtime: runtime
- });
-}
-
-/** @return Boolean: true if this test should be ran */
-function validTest( test ) {
- var include,
- filter = config.filter && config.filter.toLowerCase(),
- module = config.module && config.module.toLowerCase(),
- fullName = (test.module + ": " + test.testName).toLowerCase();
-
- // Internally-generated tests are always valid
- if ( test.callback && test.callback.validTest === validTest ) {
- delete test.callback.validTest;
- return true;
- }
-
- if ( config.testNumber ) {
- return test.testNumber === config.testNumber;
- }
-
- if ( module && ( !test.module || test.module.toLowerCase() !== module ) ) {
- return false;
- }
-
- if ( !filter ) {
- return true;
- }
-
- include = filter.charAt( 0 ) !== "!";
- if ( !include ) {
- filter = filter.slice( 1 );
- }
-
- // If the filter matches, we need to honour include
- if ( fullName.indexOf( filter ) !== -1 ) {
- return include;
- }
-
- // Otherwise, do the opposite
- return !include;
-}
-
-// so far supports only Firefox, Chrome and Opera (buggy), Safari (for real exceptions)
-// Later Safari and IE10 are supposed to support error.stack as well
-// See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack
-function extractStacktrace( e, offset ) {
- offset = offset === undefined ? 3 : offset;
-
- var stack, include, i;
-
- if ( e.stacktrace ) {
- // Opera
- return e.stacktrace.split( "\n" )[ offset + 3 ];
- } else if ( e.stack ) {
- // Firefox, Chrome
- stack = e.stack.split( "\n" );
- if (/^error$/i.test( stack[0] ) ) {
- stack.shift();
- }
- if ( fileName ) {
- include = [];
- for ( i = offset; i < stack.length; i++ ) {
- if ( stack[ i ].indexOf( fileName ) !== -1 ) {
- break;
- }
- include.push( stack[ i ] );
- }
- if ( include.length ) {
- return include.join( "\n" );
- }
- }
- return stack[ offset ];
- } else if ( e.sourceURL ) {
- // Safari, PhantomJS
- // hopefully one day Safari provides actual stacktraces
- // exclude useless self-reference for generated Error objects
- if ( /qunit.js$/.test( e.sourceURL ) ) {
- return;
- }
- // for actual exceptions, this is useful
- return e.sourceURL + ":" + e.line;
- }
-}
-function sourceFromStacktrace( offset ) {
- try {
- throw new Error();
- } catch ( e ) {
- return extractStacktrace( e, offset );
- }
-}
-
-/**
- * Escape text for attribute or text content.
- */
-function escapeText( s ) {
- if ( !s ) {
- return "";
- }
- s = s + "";
- // Both single quotes and double quotes (for attributes)
- return s.replace( /['"<>&]/g, function( s ) {
- switch( s ) {
- case '\'':
- return ''';
- case '"':
- return '"';
- case '<':
- return '<';
- case '>':
- return '>';
- case '&':
- return '&';
- }
- });
-}
-
-function synchronize( callback, last ) {
- config.queue.push( callback );
-
- if ( config.autorun && !config.blocking ) {
- process( last );
- }
-}
-
-function process( last ) {
- function next() {
- process( last );
- }
- var start = new Date().getTime();
- config.depth = config.depth ? config.depth + 1 : 1;
-
- while ( config.queue.length && !config.blocking ) {
- if ( !defined.setTimeout || config.updateRate <= 0 || ( ( new Date().getTime() - start ) < config.updateRate ) ) {
- config.queue.shift()();
- } else {
- window.setTimeout( next, 13 );
- break;
- }
- }
- config.depth--;
- if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) {
- done();
- }
-}
-
-function saveGlobal() {
- config.pollution = [];
-
- if ( config.noglobals ) {
- for ( var key in window ) {
- // in Opera sometimes DOM element ids show up here, ignore them
- if ( !hasOwn.call( window, key ) || /^qunit-test-output/.test( key ) ) {
- continue;
- }
- config.pollution.push( key );
- }
- }
-}
-
-function checkPollution() {
- var newGlobals,
- deletedGlobals,
- old = config.pollution;
-
- saveGlobal();
-
- newGlobals = diff( config.pollution, old );
- if ( newGlobals.length > 0 ) {
- QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join(", ") );
- }
-
- deletedGlobals = diff( old, config.pollution );
- if ( deletedGlobals.length > 0 ) {
- QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join(", ") );
- }
-}
-
-// returns a new Array with the elements that are in a but not in b
-function diff( a, b ) {
- var i, j,
- result = a.slice();
-
- for ( i = 0; i < result.length; i++ ) {
- for ( j = 0; j < b.length; j++ ) {
- if ( result[i] === b[j] ) {
- result.splice( i, 1 );
- i--;
- break;
- }
- }
- }
- return result;
-}
-
-function extend( a, b ) {
- for ( var prop in b ) {
- if ( b[ prop ] === undefined ) {
- delete a[ prop ];
-
- // Avoid "Member not found" error in IE8 caused by setting window.constructor
- } else if ( prop !== "constructor" || a !== window ) {
- a[ prop ] = b[ prop ];
- }
- }
-
- return a;
-}
-
-/**
- * @param {HTMLElement} elem
- * @param {string} type
- * @param {Function} fn
- */
-function addEvent( elem, type, fn ) {
- // Standards-based browsers
- if ( elem.addEventListener ) {
- elem.addEventListener( type, fn, false );
- // IE
- } else {
- elem.attachEvent( "on" + type, fn );
- }
-}
-
-/**
- * @param {Array|NodeList} elems
- * @param {string} type
- * @param {Function} fn
- */
-function addEvents( elems, type, fn ) {
- var i = elems.length;
- while ( i-- ) {
- addEvent( elems[i], type, fn );
- }
-}
-
-function hasClass( elem, name ) {
- return (" " + elem.className + " ").indexOf(" " + name + " ") > -1;
-}
-
-function addClass( elem, name ) {
- if ( !hasClass( elem, name ) ) {
- elem.className += (elem.className ? " " : "") + name;
- }
-}
-
-function removeClass( elem, name ) {
- var set = " " + elem.className + " ";
- // Class name may appear multiple times
- while ( set.indexOf(" " + name + " ") > -1 ) {
- set = set.replace(" " + name + " " , " ");
- }
- // If possible, trim it for prettiness, but not neccecarily
- elem.className = window.jQuery ? jQuery.trim( set ) : ( set.trim ? set.trim() : set );
-}
-
-function id( name ) {
- return !!( typeof document !== "undefined" && document && document.getElementById ) &&
- document.getElementById( name );
-}
-
-function registerLoggingCallback( key ) {
- return function( callback ) {
- config[key].push( callback );
- };
-}
-
-// Supports deprecated method of completely overwriting logging callbacks
-function runLoggingCallbacks( key, scope, args ) {
- var i, callbacks;
- if ( QUnit.hasOwnProperty( key ) ) {
- QUnit[ key ].call(scope, args );
- } else {
- callbacks = config[ key ];
- for ( i = 0; i < callbacks.length; i++ ) {
- callbacks[ i ].call( scope, args );
- }
- }
-}
-
-// Test for equality any JavaScript type.
-// Author: Philippe Rathé
-QUnit.equiv = (function() {
-
- // Call the o related callback with the given arguments.
- function bindCallbacks( o, callbacks, args ) {
- var prop = QUnit.objectType( o );
- if ( prop ) {
- if ( QUnit.objectType( callbacks[ prop ] ) === "function" ) {
- return callbacks[ prop ].apply( callbacks, args );
- } else {
- return callbacks[ prop ]; // or undefined
- }
- }
- }
-
- // the real equiv function
- var innerEquiv,
- // stack to decide between skip/abort functions
- callers = [],
- // stack to avoiding loops from circular referencing
- parents = [],
-
- getProto = Object.getPrototypeOf || function ( obj ) {
- return obj.__proto__;
- },
- callbacks = (function () {
-
- // for string, boolean, number and null
- function useStrictEquality( b, a ) {
- /*jshint eqeqeq:false */
- if ( b instanceof a.constructor || a instanceof b.constructor ) {
- // to catch short annotaion VS 'new' annotation of a
- // declaration
- // e.g. var i = 1;
- // var j = new Number(1);
- return a == b;
- } else {
- return a === b;
- }
- }
-
- return {
- "string": useStrictEquality,
- "boolean": useStrictEquality,
- "number": useStrictEquality,
- "null": useStrictEquality,
- "undefined": useStrictEquality,
-
- "nan": function( b ) {
- return isNaN( b );
- },
-
- "date": function( b, a ) {
- return QUnit.objectType( b ) === "date" && a.valueOf() === b.valueOf();
- },
-
- "regexp": function( b, a ) {
- return QUnit.objectType( b ) === "regexp" &&
- // the regex itself
- a.source === b.source &&
- // and its modifers
- a.global === b.global &&
- // (gmi) ...
- a.ignoreCase === b.ignoreCase &&
- a.multiline === b.multiline &&
- a.sticky === b.sticky;
- },
-
- // - skip when the property is a method of an instance (OOP)
- // - abort otherwise,
- // initial === would have catch identical references anyway
- "function": function() {
- var caller = callers[callers.length - 1];
- return caller !== Object && typeof caller !== "undefined";
- },
-
- "array": function( b, a ) {
- var i, j, len, loop;
-
- // b could be an object literal here
- if ( QUnit.objectType( b ) !== "array" ) {
- return false;
- }
-
- len = a.length;
- if ( len !== b.length ) {
- // safe and faster
- return false;
- }
-
- // track reference to avoid circular references
- parents.push( a );
- for ( i = 0; i < len; i++ ) {
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- loop = true;// dont rewalk array
- }
- }
- if ( !loop && !innerEquiv(a[i], b[i]) ) {
- parents.pop();
- return false;
- }
- }
- parents.pop();
- return true;
- },
-
- "object": function( b, a ) {
- var i, j, loop,
- // Default to true
- eq = true,
- aProperties = [],
- bProperties = [];
-
- // comparing constructors is more strict than using
- // instanceof
- if ( a.constructor !== b.constructor ) {
- // Allow objects with no prototype to be equivalent to
- // objects with Object as their constructor.
- if ( !(( getProto(a) === null && getProto(b) === Object.prototype ) ||
- ( getProto(b) === null && getProto(a) === Object.prototype ) ) ) {
- return false;
- }
- }
-
- // stack constructor before traversing properties
- callers.push( a.constructor );
- // track reference to avoid circular references
- parents.push( a );
-
- for ( i in a ) { // be strict: don't ensures hasOwnProperty
- // and go deep
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- // don't go down the same path twice
- loop = true;
- }
- }
- aProperties.push(i); // collect a's properties
-
- if (!loop && !innerEquiv( a[i], b[i] ) ) {
- eq = false;
- break;
- }
- }
-
- callers.pop(); // unstack, we are done
- parents.pop();
-
- for ( i in b ) {
- bProperties.push( i ); // collect b's properties
- }
-
- // Ensures identical properties name
- return eq && innerEquiv( aProperties.sort(), bProperties.sort() );
- }
- };
- }());
-
- innerEquiv = function() { // can take multiple arguments
- var args = [].slice.apply( arguments );
- if ( args.length < 2 ) {
- return true; // end transition
- }
-
- return (function( a, b ) {
- if ( a === b ) {
- return true; // catch the most you can
- } else if ( a === null || b === null || typeof a === "undefined" ||
- typeof b === "undefined" ||
- QUnit.objectType(a) !== QUnit.objectType(b) ) {
- return false; // don't lose time with error prone cases
- } else {
- return bindCallbacks(a, callbacks, [ b, a ]);
- }
-
- // apply transition with (1..n) arguments
- }( args[0], args[1] ) && arguments.callee.apply( this, args.splice(1, args.length - 1 )) );
- };
-
- return innerEquiv;
-}());
-
-/**
- * jsDump Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com |
- * http://flesler.blogspot.com Licensed under BSD
- * (http://www.opensource.org/licenses/bsd-license.php) Date: 5/15/2008
- *
- * @projectDescription Advanced and extensible data dumping for Javascript.
- * @version 1.0.0
- * @author Ariel Flesler
- * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html}
- */
-QUnit.jsDump = (function() {
- function quote( str ) {
- return '"' + str.toString().replace( /"/g, '\\"' ) + '"';
- }
- function literal( o ) {
- return o + "";
- }
- function join( pre, arr, post ) {
- var s = jsDump.separator(),
- base = jsDump.indent(),
- inner = jsDump.indent(1);
- if ( arr.join ) {
- arr = arr.join( "," + s + inner );
- }
- if ( !arr ) {
- return pre + post;
- }
- return [ pre, inner + arr, base + post ].join(s);
- }
- function array( arr, stack ) {
- var i = arr.length, ret = new Array(i);
- this.up();
- while ( i-- ) {
- ret[i] = this.parse( arr[i] , undefined , stack);
- }
- this.down();
- return join( "[", ret, "]" );
- }
-
- var reName = /^function (\w+)/,
- jsDump = {
- // type is used mostly internally, you can fix a (custom)type in advance
- parse: function( obj, type, stack ) {
- stack = stack || [ ];
- var inStack, res,
- parser = this.parsers[ type || this.typeOf(obj) ];
-
- type = typeof parser;
- inStack = inArray( obj, stack );
-
- if ( inStack !== -1 ) {
- return "recursion(" + (inStack - stack.length) + ")";
- }
- if ( type === "function" ) {
- stack.push( obj );
- res = parser.call( this, obj, stack );
- stack.pop();
- return res;
- }
- return ( type === "string" ) ? parser : this.parsers.error;
- },
- typeOf: function( obj ) {
- var type;
- if ( obj === null ) {
- type = "null";
- } else if ( typeof obj === "undefined" ) {
- type = "undefined";
- } else if ( QUnit.is( "regexp", obj) ) {
- type = "regexp";
- } else if ( QUnit.is( "date", obj) ) {
- type = "date";
- } else if ( QUnit.is( "function", obj) ) {
- type = "function";
- } else if ( typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined" ) {
- type = "window";
- } else if ( obj.nodeType === 9 ) {
- type = "document";
- } else if ( obj.nodeType ) {
- type = "node";
- } else if (
- // native arrays
- toString.call( obj ) === "[object Array]" ||
- // NodeList objects
- ( typeof obj.length === "number" && typeof obj.item !== "undefined" && ( obj.length ? obj.item(0) === obj[0] : ( obj.item( 0 ) === null && typeof obj[0] === "undefined" ) ) )
- ) {
- type = "array";
- } else if ( obj.constructor === Error.prototype.constructor ) {
- type = "error";
- } else {
- type = typeof obj;
- }
- return type;
- },
- separator: function() {
- return this.multiline ? this.HTML ? "
" : "\n" : this.HTML ? " " : " ";
- },
- // extra can be a number, shortcut for increasing-calling-decreasing
- indent: function( extra ) {
- if ( !this.multiline ) {
- return "";
- }
- var chr = this.indentChar;
- if ( this.HTML ) {
- chr = chr.replace( /\t/g, " " ).replace( / /g, " " );
- }
- return new Array( this._depth_ + (extra||0) ).join(chr);
- },
- up: function( a ) {
- this._depth_ += a || 1;
- },
- down: function( a ) {
- this._depth_ -= a || 1;
- },
- setParser: function( name, parser ) {
- this.parsers[name] = parser;
- },
- // The next 3 are exposed so you can use them
- quote: quote,
- literal: literal,
- join: join,
- //
- _depth_: 1,
- // This is the list of parsers, to modify them, use jsDump.setParser
- parsers: {
- window: "[Window]",
- document: "[Document]",
- error: function(error) {
- return "Error(\"" + error.message + "\")";
- },
- unknown: "[Unknown]",
- "null": "null",
- "undefined": "undefined",
- "function": function( fn ) {
- var ret = "function",
- // functions never have name in IE
- name = "name" in fn ? fn.name : (reName.exec(fn) || [])[1];
-
- if ( name ) {
- ret += " " + name;
- }
- ret += "( ";
-
- ret = [ ret, QUnit.jsDump.parse( fn, "functionArgs" ), "){" ].join( "" );
- return join( ret, QUnit.jsDump.parse(fn,"functionCode" ), "}" );
- },
- array: array,
- nodelist: array,
- "arguments": array,
- object: function( map, stack ) {
- var ret = [ ], keys, key, val, i;
- QUnit.jsDump.up();
- keys = [];
- for ( key in map ) {
- keys.push( key );
- }
- keys.sort();
- for ( i = 0; i < keys.length; i++ ) {
- key = keys[ i ];
- val = map[ key ];
- ret.push( QUnit.jsDump.parse( key, "key" ) + ": " + QUnit.jsDump.parse( val, undefined, stack ) );
- }
- QUnit.jsDump.down();
- return join( "{", ret, "}" );
- },
- node: function( node ) {
- var len, i, val,
- open = QUnit.jsDump.HTML ? "<" : "<",
- close = QUnit.jsDump.HTML ? ">" : ">",
- tag = node.nodeName.toLowerCase(),
- ret = open + tag,
- attrs = node.attributes;
-
- if ( attrs ) {
- for ( i = 0, len = attrs.length; i < len; i++ ) {
- val = attrs[i].nodeValue;
- // IE6 includes all attributes in .attributes, even ones not explicitly set.
- // Those have values like undefined, null, 0, false, "" or "inherit".
- if ( val && val !== "inherit" ) {
- ret += " " + attrs[i].nodeName + "=" + QUnit.jsDump.parse( val, "attribute" );
- }
- }
- }
- ret += close;
-
- // Show content of TextNode or CDATASection
- if ( node.nodeType === 3 || node.nodeType === 4 ) {
- ret += node.nodeValue;
- }
-
- return ret + open + "/" + tag + close;
- },
- // function calls it internally, it's the arguments part of the function
- functionArgs: function( fn ) {
- var args,
- l = fn.length;
-
- if ( !l ) {
- return "";
- }
-
- args = new Array(l);
- while ( l-- ) {
- // 97 is 'a'
- args[l] = String.fromCharCode(97+l);
- }
- return " " + args.join( ", " ) + " ";
- },
- // object calls it internally, the key part of an item in a map
- key: quote,
- // function calls it internally, it's the content of the function
- functionCode: "[code]",
- // node calls it internally, it's an html attribute value
- attribute: quote,
- string: quote,
- date: quote,
- regexp: literal,
- number: literal,
- "boolean": literal
- },
- // if true, entities are escaped ( <, >, \t, space and \n )
- HTML: false,
- // indentation unit
- indentChar: " ",
- // if true, items in a collection, are separated by a \n, else just a space.
- multiline: true
- };
-
- return jsDump;
-}());
-
-// from jquery.js
-function inArray( elem, array ) {
- if ( array.indexOf ) {
- return array.indexOf( elem );
- }
-
- for ( var i = 0, length = array.length; i < length; i++ ) {
- if ( array[ i ] === elem ) {
- return i;
- }
- }
-
- return -1;
-}
-
-/*
- * Javascript Diff Algorithm
- * By John Resig (http://ejohn.org/)
- * Modified by Chu Alan "sprite"
- *
- * Released under the MIT license.
- *
- * More Info:
- * http://ejohn.org/projects/javascript-diff-algorithm/
- *
- * Usage: QUnit.diff(expected, actual)
- *
- * QUnit.diff( "the quick brown fox jumped over", "the quick fox jumps over" ) == "the quick brown fox jumped jumps over"
- */
-QUnit.diff = (function() {
- /*jshint eqeqeq:false, eqnull:true */
- function diff( o, n ) {
- var i,
- ns = {},
- os = {};
-
- for ( i = 0; i < n.length; i++ ) {
- if ( !hasOwn.call( ns, n[i] ) ) {
- ns[ n[i] ] = {
- rows: [],
- o: null
- };
- }
- ns[ n[i] ].rows.push( i );
- }
-
- for ( i = 0; i < o.length; i++ ) {
- if ( !hasOwn.call( os, o[i] ) ) {
- os[ o[i] ] = {
- rows: [],
- n: null
- };
- }
- os[ o[i] ].rows.push( i );
- }
-
- for ( i in ns ) {
- if ( !hasOwn.call( ns, i ) ) {
- continue;
- }
- if ( ns[i].rows.length === 1 && hasOwn.call( os, i ) && os[i].rows.length === 1 ) {
- n[ ns[i].rows[0] ] = {
- text: n[ ns[i].rows[0] ],
- row: os[i].rows[0]
- };
- o[ os[i].rows[0] ] = {
- text: o[ os[i].rows[0] ],
- row: ns[i].rows[0]
- };
- }
- }
-
- for ( i = 0; i < n.length - 1; i++ ) {
- if ( n[i].text != null && n[ i + 1 ].text == null && n[i].row + 1 < o.length && o[ n[i].row + 1 ].text == null &&
- n[ i + 1 ] == o[ n[i].row + 1 ] ) {
-
- n[ i + 1 ] = {
- text: n[ i + 1 ],
- row: n[i].row + 1
- };
- o[ n[i].row + 1 ] = {
- text: o[ n[i].row + 1 ],
- row: i + 1
- };
- }
- }
-
- for ( i = n.length - 1; i > 0; i-- ) {
- if ( n[i].text != null && n[ i - 1 ].text == null && n[i].row > 0 && o[ n[i].row - 1 ].text == null &&
- n[ i - 1 ] == o[ n[i].row - 1 ]) {
-
- n[ i - 1 ] = {
- text: n[ i - 1 ],
- row: n[i].row - 1
- };
- o[ n[i].row - 1 ] = {
- text: o[ n[i].row - 1 ],
- row: i - 1
- };
- }
- }
-
- return {
- o: o,
- n: n
- };
- }
-
- return function( o, n ) {
- o = o.replace( /\s+$/, "" );
- n = n.replace( /\s+$/, "" );
-
- var i, pre,
- str = "",
- out = diff( o === "" ? [] : o.split(/\s+/), n === "" ? [] : n.split(/\s+/) ),
- oSpace = o.match(/\s+/g),
- nSpace = n.match(/\s+/g);
-
- if ( oSpace == null ) {
- oSpace = [ " " ];
- }
- else {
- oSpace.push( " " );
- }
-
- if ( nSpace == null ) {
- nSpace = [ " " ];
- }
- else {
- nSpace.push( " " );
- }
-
- if ( out.n.length === 0 ) {
- for ( i = 0; i < out.o.length; i++ ) {
- str += "" + out.o[i] + oSpace[i] + "";
- }
- }
- else {
- if ( out.n[0].text == null ) {
- for ( n = 0; n < out.o.length && out.o[n].text == null; n++ ) {
- str += "" + out.o[n] + oSpace[n] + "";
- }
- }
-
- for ( i = 0; i < out.n.length; i++ ) {
- if (out.n[i].text == null) {
- str += "" + out.n[i] + nSpace[i] + "";
- }
- else {
- // `pre` initialized at top of scope
- pre = "";
-
- for ( n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++ ) {
- pre += "" + out.o[n] + oSpace[n] + "";
- }
- str += " " + out.n[i].text + nSpace[i] + pre;
- }
- }
- }
-
- return str;
- };
-}());
-
-// for CommonJS enviroments, export everything
-if ( typeof exports !== "undefined" ) {
- extend( exports, QUnit );
-}
-
-// get at whatever the global object is, like window in browsers
-}( (function() {return this;}.call()) ));
diff --git a/test/lib/require.js b/test/lib/require.js
deleted file mode 100644
index 987f865..0000000
--- a/test/lib/require.js
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- RequireJS 2.1.5 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.
- Available via the MIT or new BSD license.
- see: http://github.com/jrburke/requirejs for details
-*/
-var requirejs,require,define;
-(function(aa){function I(b){return"[object Function]"===L.call(b)}function J(b){return"[object Array]"===L.call(b)}function y(b,c){if(b){var d;for(d=0;dthis.depCount&&!this.defined){if(I(n)){if(this.events.error)try{e=i.execCb(c,n,b,e)}catch(d){a=d}else e=i.execCb(c,n,b,e);this.map.isDefine&&((b=this.module)&&void 0!==b.exports&&b.exports!==this.exports?e=b.exports:void 0===e&&this.usingExports&&(e=this.exports));if(a)return a.requireMap=this.map,a.requireModules=[this.map.id],a.requireType="define",v(this.error=
-a)}else e=n;this.exports=e;if(this.map.isDefine&&!this.ignore&&(q[c]=e,l.onResourceLoad))l.onResourceLoad(i,this.map,this.depMaps);x(c);this.defined=!0}this.defining=!1;this.defined&&!this.defineEmitted&&(this.defineEmitted=!0,this.emit("defined",this.exports),this.defineEmitComplete=!0)}}else this.fetch()}},callPlugin:function(){var a=this.map,b=a.id,d=j(a.prefix);this.depMaps.push(d);t(d,"defined",u(this,function(e){var n,d;d=this.map.name;var g=this.map.parentMap?this.map.parentMap.name:null,h=
-i.makeRequire(a.parentMap,{enableBuildCallback:!0});if(this.map.unnormalized){if(e.normalize&&(d=e.normalize(d,function(a){return c(a,g,!0)})||""),e=j(a.prefix+"!"+d,this.map.parentMap),t(e,"defined",u(this,function(a){this.init([],function(){return a},null,{enabled:!0,ignore:!0})})),d=m(p,e.id)){this.depMaps.push(e);if(this.events.error)d.on("error",u(this,function(a){this.emit("error",a)}));d.enable()}}else n=u(this,function(a){this.init([],function(){return a},null,{enabled:!0})}),n.error=u(this,
-function(a){this.inited=!0;this.error=a;a.requireModules=[b];G(p,function(a){0===a.map.id.indexOf(b+"_unnormalized")&&x(a.map.id)});v(a)}),n.fromText=u(this,function(e,c){var d=a.name,g=j(d),C=O;c&&(e=c);C&&(O=!1);r(g);s(k.config,b)&&(k.config[d]=k.config[b]);try{l.exec(e)}catch(ca){return v(B("fromtexteval","fromText eval for "+b+" failed: "+ca,ca,[b]))}C&&(O=!0);this.depMaps.push(g);i.completeLoad(d);h([d],n)}),e.load(a.name,h,n,k)}));i.enable(d,this);this.pluginMaps[d.id]=d},enable:function(){V[this.map.id]=
-this;this.enabling=this.enabled=!0;y(this.depMaps,u(this,function(a,b){var c,e;if("string"===typeof a){a=j(a,this.map.isDefine?this.map:this.map.parentMap,!1,!this.skipMap);this.depMaps[b]=a;if(c=m(N,a.id)){this.depExports[b]=c(this);return}this.depCount+=1;t(a,"defined",u(this,function(a){this.defineDep(b,a);this.check()}));this.errback&&t(a,"error",this.errback)}c=a.id;e=p[c];!s(N,c)&&(e&&!e.enabled)&&i.enable(a,this)}));G(this.pluginMaps,u(this,function(a){var b=m(p,a.id);b&&!b.enabled&&i.enable(a,
-this)}));this.enabling=!1;this.check()},on:function(a,b){var c=this.events[a];c||(c=this.events[a]=[]);c.push(b)},emit:function(a,b){y(this.events[a],function(a){a(b)});"error"===a&&delete this.events[a]}};i={config:k,contextName:b,registry:p,defined:q,urlFetched:U,defQueue:H,Module:Z,makeModuleMap:j,nextTick:l.nextTick,onError:v,configure:function(a){a.baseUrl&&"/"!==a.baseUrl.charAt(a.baseUrl.length-1)&&(a.baseUrl+="/");var b=k.pkgs,c=k.shim,e={paths:!0,config:!0,map:!0};G(a,function(a,b){e[b]?
-"map"===b?(k.map||(k.map={}),R(k[b],a,!0,!0)):R(k[b],a,!0):k[b]=a});a.shim&&(G(a.shim,function(a,b){J(a)&&(a={deps:a});if((a.exports||a.init)&&!a.exportsFn)a.exportsFn=i.makeShimExports(a);c[b]=a}),k.shim=c);a.packages&&(y(a.packages,function(a){a="string"===typeof a?{name:a}:a;b[a.name]={name:a.name,location:a.location||a.name,main:(a.main||"main").replace(ja,"").replace(ea,"")}}),k.pkgs=b);G(p,function(a,b){!a.inited&&!a.map.unnormalized&&(a.map=j(b))});if(a.deps||a.callback)i.require(a.deps||[],
-a.callback)},makeShimExports:function(a){return function(){var b;a.init&&(b=a.init.apply(aa,arguments));return b||a.exports&&ba(a.exports)}},makeRequire:function(a,f){function d(e,c,h){var g,k;f.enableBuildCallback&&(c&&I(c))&&(c.__requireJsBuild=!0);if("string"===typeof e){if(I(c))return v(B("requireargs","Invalid require call"),h);if(a&&s(N,e))return N[e](p[a.id]);if(l.get)return l.get(i,e,a,d);g=j(e,a,!1,!0);g=g.id;return!s(q,g)?v(B("notloaded",'Module name "'+g+'" has not been loaded yet for context: '+
-b+(a?"":". Use require([])"))):q[g]}L();i.nextTick(function(){L();k=r(j(null,a));k.skipMap=f.skipMap;k.init(e,c,h,{enabled:!0});D()});return d}f=f||{};R(d,{isBrowser:A,toUrl:function(b){var d,f=b.lastIndexOf("."),g=b.split("/")[0];if(-1!==f&&(!("."===g||".."===g)||1h.attachEvent.toString().indexOf("[native code"))&&!Y?(O=!0,h.attachEvent("onreadystatechange",b.onScriptLoad)):(h.addEventListener("load",b.onScriptLoad,!1),h.addEventListener("error",b.onScriptError,!1)),h.src=d,K=h,D?x.insertBefore(h,D):x.appendChild(h),K=null,h;if(da)try{importScripts(d),b.completeLoad(c)}catch(j){b.onError(B("importscripts","importScripts failed for "+c+" at "+d,j,[c]))}};A&&M(document.getElementsByTagName("script"),function(b){x||(x=
-b.parentNode);if(t=b.getAttribute("data-main"))return r.baseUrl||(E=t.split("/"),Q=E.pop(),fa=E.length?E.join("/")+"/":"./",r.baseUrl=fa,t=Q),t=t.replace(ea,""),r.deps=r.deps?r.deps.concat(t):[t],!0});define=function(b,c,d){var l,h;"string"!==typeof b&&(d=c,c=b,b=null);J(c)||(d=c,c=[]);!c.length&&I(d)&&d.length&&(d.toString().replace(la,"").replace(ma,function(b,d){c.push(d)}),c=(1===d.length?["require"]:["require","exports","module"]).concat(c));if(O){if(!(l=K))P&&"interactive"===P.readyState||M(document.getElementsByTagName("script"),
-function(b){if("interactive"===b.readyState)return P=b}),l=P;l&&(b||(b=l.getAttribute("data-requiremodule")),h=F[l.getAttribute("data-requirecontext")])}(h?h.defQueue:T).push([b,c,d])};define.amd={jQuery:!0};l.exec=function(b){return eval(b)};l(r)}})(this);
diff --git a/test/lib/resemble.js b/test/lib/resemble.js
new file mode 100644
index 0000000..1cb8c29
--- /dev/null
+++ b/test/lib/resemble.js
@@ -0,0 +1,535 @@
+/*
+Author: James Cryer
+Company: Huddle
+Last updated date: 21 Feb 2013
+URL: https://github.com/Huddle/Resemble.js
+*/
+
+(function(_this){
+ 'use strict';
+
+ _this['resemble'] = function( fileData ){
+
+ var data = {};
+ var images = [];
+ var updateCallbackArray = [];
+
+ var tolerance = { // between 0 and 255
+ red: 16,
+ green: 16,
+ blue: 16,
+ minBrightness: 16,
+ maxBrightness: 240
+ };
+
+ var ignoreAntialiasing = false;
+ var ignoreColors = false;
+
+ function triggerDataUpdate(){
+ var len = updateCallbackArray.length;
+ var i;
+ for(i=0;i tolerance.maxBrightness;
+ }
+
+ function getHue(r,g,b){
+
+ r = r / 255;
+ g = g / 255;
+ b = b / 255;
+ var max = Math.max(r, g, b), min = Math.min(r, g, b);
+ var h;
+ var d;
+
+ if (max == min){
+ h = 0; // achromatic
+ } else{
+ d = max - min;
+ switch(max){
+ case r: h = (g - b) / d + (g < b ? 6 : 0); break;
+ case g: h = (b - r) / d + 2; break;
+ case b: h = (r - g) / d + 4; break;
+ }
+ h /= 6;
+ }
+
+ return h;
+ }
+
+ function isAntialiased(sourcePix, data, cacheSet, verticalPos, horizontalPos, width){
+ var offset;
+ var targetPix;
+ var distance = 1;
+ var i;
+ var j;
+ var hasHighContrastSibling = 0;
+ var hasSiblingWithDifferentHue = 0;
+ var hasEquivilantSibling = 0;
+
+ addHueInfo(sourcePix);
+
+ for (i = distance*-1; i <= distance; i++){
+ for (j = distance*-1; j <= distance; j++){
+
+ if(i===0 && j===0){
+ // ignore source pixel
+ } else {
+
+ offset = ((verticalPos+j)*width + (horizontalPos+i)) * 4;
+ targetPix = getPixelInfo(data, offset, cacheSet);
+
+ if(targetPix === null){
+ continue;
+ }
+
+ addBrightnessInfo(targetPix);
+ addHueInfo(targetPix);
+
+ if( isContrasting(sourcePix, targetPix) ){
+ hasHighContrastSibling++;
+ }
+
+ if( isRGBSame(sourcePix,targetPix) ){
+ hasEquivilantSibling++;
+ }
+
+ if( Math.abs(targetPix.h - sourcePix.h) > 0.3 ){
+ hasSiblingWithDifferentHue++;
+ }
+
+ if( hasSiblingWithDifferentHue > 1 || hasHighContrastSibling > 1){
+ return true;
+ }
+ }
+ }
+ }
+
+ if(hasEquivilantSibling < 2){
+ return true;
+ }
+
+ return false;
+ }
+
+ function errorPixel(px, offset){
+ px[offset] = 255; //r
+ px[offset + 1] = 0; //g
+ px[offset + 2] = 255; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyPixel(px, offset, data){
+ px[offset] = data.r; //r
+ px[offset + 1] = data.g; //g
+ px[offset + 2] = data.b; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyGrayScalePixel(px, offset, data){
+ px[offset] = data.brightness; //r
+ px[offset + 1] = data.brightness; //g
+ px[offset + 2] = data.brightness; //b
+ px[offset + 3] = 255; //a
+ }
+
+
+ function getPixelInfo(data, offset, cacheSet){
+ var r;
+ var g;
+ var b;
+ var d;
+
+ if(typeof data[offset] !== 'undefined'){
+ r = data[offset];
+ g = data[offset+1];
+ b = data[offset+2];
+ d = {
+ r: r,
+ g: g,
+ b: b
+ };
+
+ return d;
+ } else {
+ return null;
+ }
+ }
+
+ function addBrightnessInfo(data){
+ data.brightness = getBrightness(data.r,data.g,data.b); // 'corrected' lightness
+ }
+
+ function addHueInfo(data){
+ data.h = getHue(data.r,data.g,data.b);
+ }
+
+ function analyseImages(img1, img2, width, height){
+
+ var hiddenCanvas = document.createElement('canvas');
+
+ var data1 = img1.data;
+ var data2 = img2.data;
+
+ hiddenCanvas.width = width;
+ hiddenCanvas.height = height;
+
+ var context = hiddenCanvas.getContext('2d');
+ var imgd = context.createImageData(width,height);
+ var targetPix = imgd.data;
+
+ var mismatchCount = 0;
+
+ var time = Date.now();
+
+ var skip;
+
+ if( (width > 1200 || height > 1200) && ignoreAntialiasing){
+ skip = 6;
+ }
+
+ loop(height, width, function(verticalPos, horizontalPos){
+
+ if(skip){ // only skip if the image isn't small
+ if(verticalPos % skip === 0 || horizontalPos % skip === 0){
+ return;
+ }
+ }
+
+ var offset = (verticalPos*width + horizontalPos) * 4;
+ var pixel1 = getPixelInfo(data1, offset, 1);
+ var pixel2 = getPixelInfo(data2, offset, 2);
+
+ if(pixel1 === null || pixel2 === null){
+ return;
+ }
+
+ if (ignoreColors){
+
+ addBrightnessInfo(pixel1);
+ addBrightnessInfo(pixel2);
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ return;
+ }
+
+ if( isRGBSimilar(pixel1, pixel2) ){
+ copyPixel(targetPix, offset, pixel2);
+
+ } else if( ignoreAntialiasing && (
+ addBrightnessInfo(pixel1), // jit pixel info augmentation looks a little weird, sorry.
+ addBrightnessInfo(pixel2),
+ isAntialiased(pixel1, data1, 1, verticalPos, horizontalPos, width) ||
+ isAntialiased(pixel2, data2, 2, verticalPos, horizontalPos, width)
+ )){
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+
+ });
+
+ data.misMatchPercentage = (mismatchCount / (height*width) * 100).toFixed(2);
+ data.analysisTime = Date.now() - time;
+
+ data.getImageDataUrl = function(text){
+ var barHeight = 0;
+
+ if(text){
+ barHeight = addLabel(text,context,hiddenCanvas);
+ }
+
+ context.putImageData(imgd, 0, barHeight);
+
+ return hiddenCanvas.toDataURL("image/png");
+ };
+ }
+
+ function addLabel(text, context, hiddenCanvas){
+ var textPadding = 2;
+
+ context.font = '12px sans-serif';
+
+ var textWidth = context.measureText(text).width + textPadding*2;
+ var barHeight = 22;
+
+ if(textWidth > hiddenCanvas.width){
+ hiddenCanvas.width = textWidth;
+ }
+
+ hiddenCanvas.height += barHeight;
+
+ context.fillStyle = "#666";
+ context.fillRect(0,0,hiddenCanvas.width,barHeight -4);
+ context.fillStyle = "#fff";
+ context.fillRect(0,barHeight -4,hiddenCanvas.width, 4);
+
+ context.fillStyle = "#fff";
+ context.textBaseline = "top";
+ context.font = '12px sans-serif';
+ context.fillText(text, textPadding, 1);
+
+ return barHeight;
+ }
+
+ function normalise(img, w, h){
+ var c;
+ var context;
+
+ if(img.height < h || img.width < w){
+ c = document.createElement('canvas');
+ c.width = w;
+ c.height = h;
+ context = c.getContext('2d');
+ context.putImageData(img, 0, 0);
+ return context.getImageData(0, 0, w, h);
+ }
+
+ return img;
+ }
+
+ function compare(one, two){
+
+ function onceWeHaveBoth(){
+ var width;
+ var height;
+ if(images.length === 2){
+ width = images[0].width > images[1].width ? images[0].width : images[1].width;
+ height = images[0].height > images[1].height ? images[0].height : images[1].height;
+
+ if( (images[0].width === images[1].width) && (images[0].height === images[1].height) ){
+ data.isSameDimensions = true;
+ } else {
+ data.isSameDimensions = false;
+ }
+
+ analyseImages( normalise(images[0],width, height), normalise(images[1],width, height), width, height);
+
+ triggerDataUpdate();
+ }
+ }
+
+ images = [];
+ loadImageData(one, onceWeHaveBoth);
+ loadImageData(two, onceWeHaveBoth);
+ }
+
+ function getCompareApi(param){
+
+ var secondFileData,
+ hasMethod = typeof param === 'function';
+
+ if( !hasMethod ){
+ // assume it's file data
+ secondFileData = param;
+ }
+
+ var self = {
+ ignoreNothing: function(){
+
+ tolerance.red = 16;
+ tolerance.green = 16;
+ tolerance.blue = 16;
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreAntialiasing: function(){
+
+ tolerance.red = 32;
+ tolerance.green = 32;
+ tolerance.blue = 32;
+ tolerance.minBrightness = 64;
+ tolerance.maxBrightness = 96;
+
+ ignoreAntialiasing = true;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreColors: function(){
+
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = true;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ onComplete: function( callback ){
+
+ updateCallbackArray.push(callback);
+
+ var wrapper = function(){
+ compare(fileData, secondFileData);
+ };
+
+ wrapper();
+
+ return getCompareApi(wrapper);
+ }
+ };
+
+ return self;
+ }
+
+ return {
+ onComplete: function( callback ){
+ updateCallbackArray.push(callback);
+ loadImageData(fileData, function(imageData, width, height){
+ parseImage(imageData.data, width, height);
+ });
+ },
+ compareTo: function(secondFileData){
+ return getCompareApi(secondFileData);
+ }
+ };
+
+ };
+}(this));
\ No newline at end of file
diff --git a/test/testsuite.js b/test/testsuite.js
deleted file mode 100644
index b486acb..0000000
--- a/test/testsuite.js
+++ /dev/null
@@ -1,36 +0,0 @@
-requirejs.config({
- baseUrl: '/test/unit/'
-});
-
-define(function(require) {
- var testModules = [
- 'Pixi',
- 'Point',
- 'Rectangle',
- 'DisplayObject',
- 'DisplayObjectContainer',
- 'Sprite',
- 'MovieClip',
- 'InteractionManager',
- 'Stage',
- 'utils/Utils',
- 'utils/EventTarget',
- 'utils/Matrix',
- 'utils/Detector',
- 'renderers/WebGLShaders',
- 'renderers/WebGLRenderer',
- 'renderers/WebGLBatch',
- 'renderers/CanvasRenderer',
- 'extras/Strip',
- 'extras/Rope',
- 'textures/BaseTexture',
- 'textures/Texture',
- 'loaders/SpriteSheetLoader',
- 'loaders/AssetLoader'
- ];
-
- // Resolve all testModules and then start the Test Runner.
- require(testModules, function() {
- QUnit.start();
- });
-});
\ No newline at end of file
diff --git a/test/textures/SpriteSheet-Aliens.png b/test/textures/SpriteSheet-Aliens.png
new file mode 100644
index 0000000..210acb1
--- /dev/null
+++ b/test/textures/SpriteSheet-Aliens.png
Binary files differ
diff --git a/test/textures/SpriteSheet-Explosion.png b/test/textures/SpriteSheet-Explosion.png
new file mode 100755
index 0000000..79e1a69
--- /dev/null
+++ b/test/textures/SpriteSheet-Explosion.png
Binary files differ
diff --git a/test/textures/bunny.png b/test/textures/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/textures/bunny.png
Binary files differ
diff --git a/test/unit/DisplayObject.js b/test/unit/DisplayObject.js
deleted file mode 100644
index 5e7e72f..0000000
--- a/test/unit/DisplayObject.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObject');
-});
diff --git a/test/unit/DisplayObjectContainer.js b/test/unit/DisplayObjectContainer.js
deleted file mode 100644
index b323959..0000000
--- a/test/unit/DisplayObjectContainer.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObjectContainer');
-});
diff --git a/test/unit/InteractionManager.js b/test/unit/InteractionManager.js
deleted file mode 100644
index e751f52..0000000
--- a/test/unit/InteractionManager.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('InteractionManager');
-});
diff --git a/test/unit/MovieClip.js b/test/unit/MovieClip.js
deleted file mode 100644
index 37d9446..0000000
--- a/test/unit/MovieClip.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('MovieClip');
-});
diff --git a/test/unit/Pixi.js b/test/unit/Pixi.js
deleted file mode 100644
index 36eee73..0000000
--- a/test/unit/Pixi.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Pixi');
-});
diff --git a/test/unit/Point.js b/test/unit/Point.js
deleted file mode 100644
index 983ff6e..0000000
--- a/test/unit/Point.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Point');
-});
diff --git a/test/unit/Rectangle.js b/test/unit/Rectangle.js
deleted file mode 100644
index 3b439ba..0000000
--- a/test/unit/Rectangle.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Rectangle');
-});
diff --git a/test/unit/Sprite.js b/test/unit/Sprite.js
deleted file mode 100644
index ed4f596..0000000
--- a/test/unit/Sprite.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Sprite');
-});
diff --git a/test/unit/Stage.js b/test/unit/Stage.js
deleted file mode 100644
index 2d70291..0000000
--- a/test/unit/Stage.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Stage');
-});
diff --git a/test/unit/extras/Rope.js b/test/unit/extras/Rope.js
deleted file mode 100644
index 5606f14..0000000
--- a/test/unit/extras/Rope.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Rope');
-});
diff --git a/test/unit/extras/Strip.js b/test/unit/extras/Strip.js
deleted file mode 100644
index 0134d3a..0000000
--- a/test/unit/extras/Strip.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Strip');
-});
diff --git a/test/unit/loaders/AssetLoader.js b/test/unit/loaders/AssetLoader.js
deleted file mode 100644
index 13b8443..0000000
--- a/test/unit/loaders/AssetLoader.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('AssetLoader');
-});
diff --git a/test/unit/loaders/SpriteSheetLoader.js b/test/unit/loaders/SpriteSheetLoader.js
deleted file mode 100644
index 8bf0cb2..0000000
--- a/test/unit/loaders/SpriteSheetLoader.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('SpriteSheetLoader');
-});
diff --git a/test/unit/pixi/InteractionManager.js b/test/unit/pixi/InteractionManager.js
new file mode 100644
index 0000000..ed3001f
--- /dev/null
+++ b/test/unit/pixi/InteractionManager.js
@@ -0,0 +1,10 @@
+describe('pixi/InteractionManager', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var InteractionManager = PIXI.InteractionManager;
+
+ it('Module exists', function () {
+ expect(InteractionManager).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/Pixi.js b/test/unit/pixi/Pixi.js
new file mode 100644
index 0000000..27debc1
--- /dev/null
+++ b/test/unit/pixi/Pixi.js
@@ -0,0 +1,9 @@
+describe('pixi/Pixi', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+
+ it('Module exists', function () {
+ expect(global).to.have.property('PIXI').and.to.be.an('object');
+ });
+});
diff --git a/test/unit/pixi/core/Circle.js b/test/unit/pixi/core/Circle.js
new file mode 100644
index 0000000..93a4456
--- /dev/null
+++ b/test/unit/pixi/core/Circle.js
@@ -0,0 +1,22 @@
+describe('pixi/core/Circle', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Circle = PIXI.Circle;
+
+ it('Module exists', function () {
+ expect(Circle).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Circle();
+
+ expect(obj).to.be.an.instanceof(Circle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', 0);
+ expect(obj).to.have.property('y', 0);
+ expect(obj).to.have.property('radius', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Ellipse.js b/test/unit/pixi/core/Ellipse.js
new file mode 100644
index 0000000..026b56f
--- /dev/null
+++ b/test/unit/pixi/core/Ellipse.js
@@ -0,0 +1,24 @@
+describe('pixi/core/Ellipse', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Ellipse = PIXI.Ellipse;
+
+ it('Module exists', function () {
+ expect(Ellipse).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Ellipse();
+
+ expect(obj).to.be.an.instanceof(Ellipse);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+ expect(obj).to.respondTo('getBounds');
+
+ expect(obj).to.have.property('x', 0);
+ expect(obj).to.have.property('y', 0);
+ expect(obj).to.have.property('width', 0);
+ expect(obj).to.have.property('height', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Matrix.js b/test/unit/pixi/core/Matrix.js
new file mode 100644
index 0000000..b48989e
--- /dev/null
+++ b/test/unit/pixi/core/Matrix.js
@@ -0,0 +1,30 @@
+describe('pixi/core/Matrix', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var mat3 = PIXI.mat3;
+ var mat4 = PIXI.mat4;
+ var Matrix = PIXI.Matrix;
+
+ it('Ensure determineMatrixArrayType works', function () {
+ expect(Matrix).to.be.a('function');
+ });
+
+ it('mat3 exists', function () {
+ expect(mat3).to.be.an('object');
+ });
+
+ it('Confirm new mat3 matrix', function () {
+ var matrix = new mat3.create();
+ pixi_core_Matrix_confirmNewMat3(matrix);
+ });
+
+ it('mat3 exists', function () {
+ expect(mat4).to.be.an('object');
+ });
+
+ it('Confirm new mat4 matrix', function () {
+ var matrix = new mat4.create();
+ pixi_core_Matrix_confirmNewMat4(matrix);
+ });
+});
diff --git a/test/unit/pixi/core/Point.js b/test/unit/pixi/core/Point.js
new file mode 100644
index 0000000..c4d5163
--- /dev/null
+++ b/test/unit/pixi/core/Point.js
@@ -0,0 +1,15 @@
+describe('pixi/core/Point', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Point = PIXI.Point;
+
+ it('Module exists', function () {
+ expect(Point).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Point();
+ pixi_core_Point_confirm(obj, 0, 0);
+ });
+});
diff --git a/test/unit/pixi/core/Polygon.js b/test/unit/pixi/core/Polygon.js
new file mode 100644
index 0000000..dc8c918
--- /dev/null
+++ b/test/unit/pixi/core/Polygon.js
@@ -0,0 +1,20 @@
+describe('pixi/core/Polygon', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Polygon = PIXI.Polygon;
+
+ it('Module exists', function () {
+ expect(Polygon).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Polygon();
+
+ expect(obj).to.be.an.instanceof(Polygon);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.deep.property('points.length', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Rectangle.js b/test/unit/pixi/core/Rectangle.js
new file mode 100644
index 0000000..d43316e
--- /dev/null
+++ b/test/unit/pixi/core/Rectangle.js
@@ -0,0 +1,15 @@
+describe('pixi/core/Rectangle', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Rectangle = PIXI.Rectangle;
+
+ it('Module exists', function () {
+ expect(Rectangle).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var rect = new Rectangle();
+ pixi_core_Rectangle_confirm(rect, 0, 0, 0, 0);
+ });
+});
diff --git a/test/unit/pixi/display/DisplayObject.js b/test/unit/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..40c6fbc
--- /dev/null
+++ b/test/unit/pixi/display/DisplayObject.js
@@ -0,0 +1,21 @@
+describe('pixi/display/DisplayObject', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var DisplayObject = PIXI.DisplayObject;
+
+ it('Module exists', function () {
+ expect(DisplayObject).to.be.a('function');
+ expect(PIXI).to.have.property('visibleCount', 0);
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new DisplayObject();
+
+ pixi_display_DisplayObject_confirmNew(obj);
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', false);
+ expect(obj).to.have.property('stage', null);
+ });
+});
diff --git a/test/unit/pixi/display/DisplayObjectContainer.js b/test/unit/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..ce7f02f
--- /dev/null
+++ b/test/unit/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,20 @@
+describe('pixi/display/DisplayObjectContainer', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var DisplayObjectContainer = PIXI.DisplayObjectContainer;
+
+ it('Module exists', function () {
+ expect(DisplayObjectContainer).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new DisplayObjectContainer();
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', false);
+ expect(obj).to.have.property('stage', null);
+ });
+});
diff --git a/test/unit/pixi/display/MovieClip.js b/test/unit/pixi/display/MovieClip.js
new file mode 100644
index 0000000..f3c6c6a
--- /dev/null
+++ b/test/unit/pixi/display/MovieClip.js
@@ -0,0 +1,33 @@
+describe('pixi/display/MovieClip', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var MovieClip = PIXI.MovieClip;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(MovieClip).to.be.a('function');
+ });
+
+ it('Confirm new instance', function (done) {
+ var texture = Texture.fromImage('/base/test/textures/SpriteSheet-Explosion.png');
+ var obj = new MovieClip([texture]);
+
+ pixi_display_Sprite_confirmNew(obj, done);
+
+ expect(obj).to.be.an.instanceof(MovieClip);
+ expect(obj).to.respondTo('stop');
+ expect(obj).to.respondTo('play');
+ expect(obj).to.respondTo('gotoAndStop');
+ expect(obj).to.respondTo('gotoAndPlay');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('textures.length', 1);
+ expect(obj).to.have.deep.property('textures[0]', texture);
+ expect(obj).to.have.property('animationSpeed', 1);
+ expect(obj).to.have.property('loop', true);
+ expect(obj).to.have.property('onComplete', null);
+ expect(obj).to.have.property('currentFrame', 0);
+ expect(obj).to.have.property('playing', false);
+ });
+});
diff --git a/test/unit/pixi/display/Sprite.js b/test/unit/pixi/display/Sprite.js
new file mode 100644
index 0000000..54e914f
--- /dev/null
+++ b/test/unit/pixi/display/Sprite.js
@@ -0,0 +1,25 @@
+describe('pixi/display/Sprite', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Sprite = PIXI.Sprite;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(Sprite).to.be.a('function');
+ expect(PIXI).to.have.deep.property('blendModes.NORMAL', 0);
+ expect(PIXI).to.have.deep.property('blendModes.SCREEN', 1);
+ });
+
+ it('Members exist', function () {
+ expect(Sprite).itself.to.respondTo('fromImage');
+ expect(Sprite).itself.to.respondTo('fromFrame');
+ });
+
+ it('Confirm new instance', function (done) {
+ var texture = Texture.fromImage('/base/test/textures/SpriteSheet-Aliens.png');
+ var obj = new Sprite(texture);
+
+ pixi_display_Sprite_confirmNew(obj, done);
+ });
+});
diff --git a/test/unit/pixi/display/Stage.js b/test/unit/pixi/display/Stage.js
new file mode 100644
index 0000000..3cc2a4d
--- /dev/null
+++ b/test/unit/pixi/display/Stage.js
@@ -0,0 +1,49 @@
+describe('pixi/display/Stage', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Stage = PIXI.Stage;
+ var InteractionManager = PIXI.InteractionManager;
+ var Rectangle = PIXI.Rectangle;
+
+ it('Module exists', function () {
+ expect(Stage).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Stage(null, true);
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(Stage);
+ expect(obj).to.respondTo('updateTransform');
+ expect(obj).to.respondTo('setBackgroundColor');
+ expect(obj).to.respondTo('getMousePosition');
+
+ // FIXME: duplicate member in DisplayObject
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ // FIXME: convert arg to bool in constructor
+ expect(obj).to.have.property('interactive', true);
+
+ expect(obj).to.have.property('interactionManager')
+ .and.to.be.an.instanceof(InteractionManager)
+ .and.to.have.property('stage', obj);
+
+ expect(obj).to.have.property('dirty', true);
+
+ expect(obj).to.have.property('stage', obj);
+
+ expect(obj).to.have.property('hitArea')
+ .and.to.be.an.instanceof(Rectangle);
+ pixi_core_Rectangle_confirm(obj.hitArea, 0, 0, 100000, 100000);
+
+ expect(obj).to.have.property('backgroundColor', 0x000000);
+ expect(obj).to.have.deep.property('backgroundColorSplit.length', 3);
+ expect(obj).to.have.deep.property('backgroundColorSplit[0]', 0);
+ expect(obj).to.have.deep.property('backgroundColorSplit[1]', 0);
+ expect(obj).to.have.deep.property('backgroundColorSplit[2]', 0);
+ expect(obj).to.have.property('backgroundColorString', '#000000');
+
+ expect(obj).to.have.property('worldVisible', true);
+ });
+});
diff --git a/test/unit/pixi/extras/CustomRenderable.js b/test/unit/pixi/extras/CustomRenderable.js
new file mode 100644
index 0000000..8d83cf0
--- /dev/null
+++ b/test/unit/pixi/extras/CustomRenderable.js
@@ -0,0 +1,21 @@
+describe('pixi/extras/CustomRenderable', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var CustomRenderable = PIXI.CustomRenderable;
+
+ it('Module exists', function () {
+ expect(CustomRenderable).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new CustomRenderable();
+
+ pixi_display_DisplayObject_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(CustomRenderable);
+ expect(obj).to.respondTo('renderCanvas');
+ expect(obj).to.respondTo('initWebGL');
+ expect(obj).to.respondTo('renderWebGL');
+ });
+});
diff --git a/test/unit/pixi/extras/Rope.js b/test/unit/pixi/extras/Rope.js
new file mode 100644
index 0000000..6ddaf83
--- /dev/null
+++ b/test/unit/pixi/extras/Rope.js
@@ -0,0 +1,26 @@
+describe('pixi/extras/Rope', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Rope = PIXI.Rope;
+ var Texture = PIXI.Texture;
+ var Point = PIXI.Point;
+
+ it('Module exists', function () {
+ expect(Rope).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var texture = Texture.fromImage('/base/test/textures/bunny.png');
+ var obj = new Rope(texture, [new Point(), new Point(5, 10), new Point(10, 20)]);
+
+ pixi_extras_Strip_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(Rope);
+ expect(obj).to.respondTo('refresh');
+ expect(obj).to.respondTo('updateTransform');
+ expect(obj).to.respondTo('setTexture');
+
+ // TODO: Test properties
+ });
+});
diff --git a/test/unit/pixi/extras/Spine.js b/test/unit/pixi/extras/Spine.js
new file mode 100644
index 0000000..0708bc0
--- /dev/null
+++ b/test/unit/pixi/extras/Spine.js
@@ -0,0 +1,10 @@
+describe('pixi/extras/Spine', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Spine = PIXI.Spine;
+
+ it('Module exists', function () {
+ expect(Spine).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/extras/Strip.js b/test/unit/pixi/extras/Strip.js
new file mode 100644
index 0000000..8e564e1
--- /dev/null
+++ b/test/unit/pixi/extras/Strip.js
@@ -0,0 +1,18 @@
+describe('pixi/extras/Strip', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Strip = PIXI.Strip;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(Strip).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var texture = Texture.fromImage('/base/test/textures/bunny.png');
+ var obj = new Strip(texture, 20, 10000);
+
+ pixi_extras_Strip_confirmNew(obj);
+ });
+});
diff --git a/test/unit/pixi/extras/TilingSprite.js b/test/unit/pixi/extras/TilingSprite.js
new file mode 100644
index 0000000..56aea14
--- /dev/null
+++ b/test/unit/pixi/extras/TilingSprite.js
@@ -0,0 +1,24 @@
+describe('pixi/extras/TilingSprite', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var TilingSprite = PIXI.TilingSprite;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(TilingSprite).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var texture = Texture.fromImage('/base/test/textures/bunny.png');
+ var obj = new TilingSprite(texture, 6000, 12000);
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(TilingSprite);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ // TODO: Test properties
+ });
+});
diff --git a/test/unit/pixi/filters/FilterBlock.js b/test/unit/pixi/filters/FilterBlock.js
new file mode 100644
index 0000000..870cec0
--- /dev/null
+++ b/test/unit/pixi/filters/FilterBlock.js
@@ -0,0 +1,10 @@
+describe('pixi/filters/FilterBlock', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var FilterBlock = PIXI.FilterBlock;
+
+ it('Module exists', function () {
+ expect(FilterBlock).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/filters/MaskFilter.js b/test/unit/pixi/filters/MaskFilter.js
new file mode 100644
index 0000000..32d6a45
--- /dev/null
+++ b/test/unit/pixi/filters/MaskFilter.js
@@ -0,0 +1,10 @@
+describe('pixi/filters/MaskFilter', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ // var MaskFilter = PIXI.MaskFilter;
+
+ // it('Module exists', function () {
+ // expect(MaskFilter).to.be.a('function');
+ // });
+});
diff --git a/test/unit/pixi/loaders/AssetLoader.js b/test/unit/pixi/loaders/AssetLoader.js
new file mode 100644
index 0000000..a0aa0b5
--- /dev/null
+++ b/test/unit/pixi/loaders/AssetLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/AssetLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var AssetLoader = PIXI.AssetLoader;
+
+ it('Module exists', function () {
+ expect(AssetLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/BitmapFontLoader.js b/test/unit/pixi/loaders/BitmapFontLoader.js
new file mode 100644
index 0000000..6253c42
--- /dev/null
+++ b/test/unit/pixi/loaders/BitmapFontLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/BitmapFontLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var BitmapFontLoader = PIXI.BitmapFontLoader;
+
+ it('Module exists', function () {
+ expect(PIXI.BitmapFontLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/ImageLoader.js b/test/unit/pixi/loaders/ImageLoader.js
new file mode 100644
index 0000000..8b1f556
--- /dev/null
+++ b/test/unit/pixi/loaders/ImageLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/ImageLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var ImageLoader = PIXI.ImageLoader;
+
+ it('Module exists', function () {
+ expect(ImageLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/JsonLoader.js b/test/unit/pixi/loaders/JsonLoader.js
new file mode 100644
index 0000000..c577e83
--- /dev/null
+++ b/test/unit/pixi/loaders/JsonLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/JsonLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var JsonLoader = PIXI.JsonLoader;
+
+ it('Module exists', function () {
+ expect(JsonLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/SpineLoader.js b/test/unit/pixi/loaders/SpineLoader.js
new file mode 100644
index 0000000..fdcc0b8
--- /dev/null
+++ b/test/unit/pixi/loaders/SpineLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/SpineLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var SpineLoader = PIXI.SpineLoader;
+
+ it('Module exists', function () {
+ expect(SpineLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/SpriteSheetLoader.js b/test/unit/pixi/loaders/SpriteSheetLoader.js
new file mode 100644
index 0000000..57beb27
--- /dev/null
+++ b/test/unit/pixi/loaders/SpriteSheetLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/SpriteSheetLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var SpriteSheetLoader = PIXI.SpriteSheetLoader;
+
+ it('Module exists', function () {
+ expect(SpriteSheetLoader).to.be.a('function');
+ });
+});
diff --git a/.gitignore b/.gitignore
index 12e1b62..0b88317 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
node_modules
.DS_Store
-.project
\ No newline at end of file
+.project
+*.log
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..63e4d7c
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,8 @@
+language: node_js
+node_js:
+ - 0.10
+
+before_script:
+ - npm install -g grunt-cli
+ - export DISPLAY=:99.0
+ - sh -e /etc/init.d/xvfb start
diff --git a/Gruntfile.js b/Gruntfile.js
index b083b49..103938c 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -1,10 +1,12 @@
+'use strict';
+
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-connect');
- grunt.loadNpmTasks('grunt-contrib-qunit');
grunt.loadNpmTasks('grunt-contrib-yuidoc');
+ grunt.loadTasks('tasks');
var root = 'src/pixi/',
debug = 'bin/pixi.dev.js',
@@ -79,7 +81,7 @@
},
files: {
srcBlob: '<%= dirs.src %>/**/*.js',
- testBlob: '<%= dirs.test %>/unit/**/*.js',
+ testBlob: '<%= dirs.test %>/{functional,lib/pixi,unit}/**/*.js',
build: '<%= dirs.build %>/pixi.dev.js',
buildMin: '<%= dirs.build %>/pixi.js'
},
@@ -94,7 +96,12 @@
},
jshint: {
beforeconcat: srcFiles,
- test: ['<%= files.testBlob %>'],
+ test: {
+ src: ['<%= files.testBlob %>'],
+ options: {
+ expr: true
+ }
+ },
options: {
asi: true,
smarttabs: true
@@ -128,12 +135,6 @@
]
},
connect: {
- qunit: {
- options: {
- port: grunt.option('port-test') || 9002,
- base: './'
- }
- },
test: {
options: {
port: grunt.option('port-test') || 9002,
@@ -142,13 +143,6 @@
}
}
},
- qunit: {
- all: {
- options: {
- urls: ['http://localhost:' + (grunt.option('port-test') || 9002) + '/test/index.html']
- }
- }
- },
yuidoc: {
compile: {
name: '<%= pkg.name %>',
@@ -161,6 +155,13 @@
outdir: '<%= dirs.docs %>'
}
}
+ },
+ karma: {
+ unit: {
+ configFile: 'test/karma.conf.js',
+ // browsers: ['Chrome'],
+ singleRun: true
+ }
}
});
@@ -182,9 +183,10 @@
}
)
- grunt.registerTask('default', ['concat', 'uglify', 'distribute']);
grunt.registerTask('build', ['concat', 'uglify', 'distribute']);
- grunt.registerTask('test', ['build', 'connect:qunit', 'qunit']);
+ grunt.registerTask('test', ['concat', 'jshint:test', 'karma']);
grunt.registerTask('docs', ['yuidoc']);
-
-}
\ No newline at end of file
+ grunt.registerTask('default', ['test', 'uglify', 'distribute']);
+ // Travis CI task.
+ grunt.registerTask('travis', ['test']);
+}
diff --git a/README.md b/README.md
index c62ef86..690cfe4 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,8 @@

+[](http://travis-ci.org/drkibitz/pixi.js)
+
#### JavaScript 2D Renderer ####
The aim of this project is to provide a fast lightweight 2D library that works
diff --git a/package.json b/package.json
index b373240..1246a68 100644
--- a/package.json
+++ b/package.json
@@ -18,14 +18,21 @@
"main": "bin/pixi.js",
+ "scripts": {
+ "test": "grunt travis --verbose"
+ },
+
"dependencies": {},
"devDependencies": {
"grunt": "~0.4.x",
- "grunt-contrib-jshint": "0.3.x",
+ "grunt-contrib-jshint": "0.6.x",
"grunt-contrib-uglify": "0.2.x",
- "grunt-contrib-connect": "0.2.x",
- "grunt-contrib-qunit": "0.2.x",
+ "grunt-contrib-connect": "0.3.x",
"grunt-contrib-yuidoc": "0.4.x",
- "grunt-contrib-concat": "0.1.x"
+ "grunt-contrib-concat": "0.3.x",
+ "chai": "~1.7.0",
+ "karma": "0.11.0",
+ "karma-firefox-launcher": "0.1.0",
+ "karma-mocha": "0.1.0"
}
}
diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js
index a7c520e..ee82bbd 100644
--- a/src/pixi/InteractionManager.js
+++ b/src/pixi/InteractionManager.js
@@ -62,7 +62,6 @@
this.onTouchEnd = this.onTouchEnd.bind(this);
this.onTouchMove = this.onTouchMove.bind(this);
-
this.last = 0;
}
diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js
index 1a95d20..eef1059 100644
--- a/src/pixi/core/Ellipse.js
+++ b/src/pixi/core/Ellipse.js
@@ -78,7 +78,7 @@
return (normx + normy < 0.25);
}
-PIXI.Ellipse.getBounds = function()
+PIXI.Ellipse.prototype.getBounds = function()
{
return new PIXI.Rectangle(this.x, this.y, this.width, this.height);
}
diff --git a/tasks/karma.js b/tasks/karma.js
new file mode 100644
index 0000000..c340485
--- /dev/null
+++ b/tasks/karma.js
@@ -0,0 +1,27 @@
+'use strict';
+
+var path = require('path');
+var server = require('karma').server;
+
+module.exports = function (grunt) {
+ grunt.registerMultiTask('karma', 'run karma.', function() {
+ var done = this.async();
+ var options = this.options({
+ background: false
+ });
+ var data = this.data;
+
+ //merge options onto data, with data taking precedence
+ data = grunt.util._.merge(options, data);
+ data.configFile = path.resolve(data.configFile);
+ if (data.configFile) {
+ data.configFile = grunt.template.process(data.configFile);
+ }
+
+ server.start(
+ data,
+ function(code) {
+ done(!code);
+ });
+ });
+};
diff --git a/test/functional/example-1-basics/bunny.png b/test/functional/example-1-basics/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/functional/example-1-basics/bunny.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-30.png b/test/functional/example-1-basics/frame-30.png
new file mode 100644
index 0000000..96e3409
--- /dev/null
+++ b/test/functional/example-1-basics/frame-30.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-60.png b/test/functional/example-1-basics/frame-60.png
new file mode 100644
index 0000000..af3f4ce
--- /dev/null
+++ b/test/functional/example-1-basics/frame-60.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-90.png b/test/functional/example-1-basics/frame-90.png
new file mode 100644
index 0000000..099b823
--- /dev/null
+++ b/test/functional/example-1-basics/frame-90.png
Binary files differ
diff --git a/test/functional/example-1-basics/index.js b/test/functional/example-1-basics/index.js
new file mode 100644
index 0000000..7ae7a98
--- /dev/null
+++ b/test/functional/example-1-basics/index.js
@@ -0,0 +1,133 @@
+describe('Example 1 - Basics', function () {
+ 'use strict';
+
+ var baseUri = '/base/test/functional/example-1-basics';
+ var expect = chai.expect;
+ var currentFrame = 0;
+ var frameEvents = {};
+ var stage;
+ var renderer;
+ var bunny;
+
+ function onFrame(frame, callback) {
+ frameEvents[frame] = callback;
+ }
+
+ function animate() {
+ currentFrame += 1;
+
+ requestAnimFrame( animate );
+
+ // just for fun, lets rotate mr rabbit a little
+ bunny.rotation += 0.1;
+
+ // render the stage
+ renderer.render(stage);
+
+ if (frameEvents[currentFrame])
+ frameEvents[currentFrame](currentFrame);
+ }
+
+ function initScene() {
+ // create an new instance of a pixi stage
+ stage = new PIXI.Stage(0x66FF99);
+
+ // create a renderer instance
+ renderer = PIXI.autoDetectRenderer(400, 300);
+ console.log('Is PIXI.WebGLRenderer: ' + (renderer instanceof PIXI.WebGLRenderer));
+
+ // add the renderer view element to the DOM
+ document.body.appendChild(renderer.view);
+
+ requestAnimFrame( animate );
+
+ // create a texture from an image path
+ var texture = PIXI.Texture.fromImage(baseUri + "/bunny.png");
+ // create a new Sprite using the texture
+ bunny = new PIXI.Sprite(texture);
+
+ // center the sprites anchor point
+ bunny.anchor.x = 0.5;
+ bunny.anchor.y = 0.5;
+
+ // move the sprite t the center of the screen
+ bunny.position.x = 200;
+ bunny.position.y = 150;
+
+ stage.addChild(bunny);
+ }
+
+ it('assets loaded', function (done) {
+ var loader = new PIXI.AssetLoader([
+ baseUri + '/bunny.png',
+ baseUri + '/frame-30.png',
+ baseUri + '/frame-60.png',
+ baseUri + '/frame-90.png'
+ ]);
+ // loader.on('onProgress', function (event) {
+ // console.log(event.content);
+ // });
+ loader.on('onComplete', function (event) {
+ done();
+ initScene();
+ });
+ loader.load();
+ });
+
+ it('frame 30 should match', function (done) {
+ this.timeout(700);
+ onFrame(30, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-30.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 60 should match', function (done) {
+ this.timeout(1200);
+ onFrame(60, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-60.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 90 should match', function (done) {
+ this.timeout(1700);
+ onFrame(90, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-90.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ // it('capture something', function (done) {
+ // this.timeout(2000000);
+ // onFrame(30, function () {
+ // var img = new Image();
+ // img.src = renderer.view.toDataURL('image/png');
+ // document.body.appendChild(img);
+ // });
+ // });
+});
diff --git a/test/index.html b/test/index.html
deleted file mode 100644
index 9cbcac5..0000000
--- a/test/index.html
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
- Pixi.js Test Suite
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/test/karma.conf.js b/test/karma.conf.js
new file mode 100644
index 0000000..c66a696
--- /dev/null
+++ b/test/karma.conf.js
@@ -0,0 +1,82 @@
+module.exports = function(config) {
+ config.set({
+
+ // base path, that will be used to resolve files and exclude
+ basePath : '../',
+
+ frameworks : ['mocha'],
+
+ // list of files / patterns to load in the browser
+ files : [
+ 'node_modules/chai/chai.js',
+ 'bin/pixi.dev.js',
+ 'test/lib/**/*.js',
+ 'test/unit/**/*.js',
+ // 'test/functional/**/*.js',
+ {pattern: 'test/**/*.png', watched: false, included: false, served: true}
+ ],
+
+ // list of files to exclude
+ exclude : [],
+
+ // use dolts reporter, as travis terminal does not support escaping sequences
+ // possible values: 'dots', 'progress', 'junit', 'teamcity'
+ // CLI --reporters progress
+ reporters : ['progress'],
+
+ // web server port
+ // CLI --port 9876
+ port : 9876,
+
+ // cli runner port
+ // CLI --runner-port 9100
+ runnerPort : 9100,
+
+ // enable / disable colors in the output (reporters and logs)
+ // CLI --colors --no-colors
+ colors : true,
+
+ // level of logging
+ // possible values: karma.LOG_DISABLE || karma.LOG_ERROR || karma.LOG_WARN || karma.LOG_INFO || karma.LOG_DEBUG
+ // CLI --log-level debug
+ logLevel : config.LOG_DEBUG,
+
+ // enable / disable watching file and executing tests whenever any file changes
+ // CLI --auto-watch --no-auto-watch
+ autoWatch : false,
+
+ // Start these browsers, currently available:
+ // - Chrome
+ // - ChromeCanary
+ // - Firefox
+ // - Opera
+ // - Safari (only Mac)
+ // - PhantomJS
+ // - IE (only Windows)
+ // CLI --browsers Chrome,Firefox,Safari
+ browsers : ['Firefox'],
+
+ // If browser does not capture in given timeout [ms], kill it
+ // CLI --capture-timeout 5000
+ captureTimeout : 5000,
+
+ // Auto run tests on start (when browsers are captured) and exit
+ // CLI --single-run --no-single-run
+ singleRun : true,
+
+ // report which specs are slower than 500ms
+ // CLI --report-slower-than 500
+ reportSlowerThan : 1000,
+
+ preprocessors : {
+ // '**/client/js/*.js': 'coverage'
+ },
+
+ plugins : [
+ 'karma-mocha',
+ // 'karma-chrome-launcher',
+ 'karma-firefox-launcher',
+ // 'karma-phantomjs-launcher'
+ ]
+ });
+};
diff --git a/test/lib/pixi/core/Matrix.js b/test/lib/pixi/core/Matrix.js
new file mode 100644
index 0000000..d26386b
--- /dev/null
+++ b/test/lib/pixi/core/Matrix.js
@@ -0,0 +1,40 @@
+
+function pixi_core_Matrix_confirmNewMat3(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(1);
+ expect(matrix[5]).to.equal(0);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(1);
+}
+
+function pixi_core_Matrix_confirmNewMat4(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[0]).to.equal(1);
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(0);
+ expect(matrix[5]).to.equal(1);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(0);
+ expect(matrix[9]).to.equal(0);
+ expect(matrix[10]).to.equal(1);
+ expect(matrix[11]).to.equal(0);
+ expect(matrix[12]).to.equal(0);
+ expect(matrix[13]).to.equal(0);
+ expect(matrix[14]).to.equal(0);
+ expect(matrix[15]).to.equal(1);
+}
diff --git a/test/lib/pixi/core/Point.js b/test/lib/pixi/core/Point.js
new file mode 100644
index 0000000..e5df07b
--- /dev/null
+++ b/test/lib/pixi/core/Point.js
@@ -0,0 +1,10 @@
+
+function pixi_core_Point_confirm(obj, x, y) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Point);
+ expect(obj).to.respondTo('clone');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+}
diff --git a/test/lib/pixi/core/Rectangle.js b/test/lib/pixi/core/Rectangle.js
new file mode 100644
index 0000000..23f0d12
--- /dev/null
+++ b/test/lib/pixi/core/Rectangle.js
@@ -0,0 +1,13 @@
+
+function pixi_core_Rectangle_confirm(obj, x, y, width, height) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Rectangle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+ expect(obj).to.have.property('width', width);
+ expect(obj).to.have.property('height', height);
+}
diff --git a/test/lib/pixi/display/DisplayObject.js b/test/lib/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..1388a7f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObject.js
@@ -0,0 +1,43 @@
+
+function pixi_display_DisplayObject_confirmNew(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObject);
+ expect(obj).to.respondTo('setInteractive');
+ expect(obj).to.respondTo('addFilter');
+ expect(obj).to.respondTo('removeFilter');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.property('last', obj);
+ expect(obj).to.have.property('first', obj);
+
+ expect(obj).to.contain.property('position');
+ pixi_core_Point_confirm(obj.position, 0, 0);
+ expect(obj).to.contain.property('scale');
+ pixi_core_Point_confirm(obj.scale, 1, 1);
+ expect(obj).to.contain.property('pivot');
+ pixi_core_Point_confirm(obj.pivot, 0, 0);
+
+ expect(obj).to.have.property('rotation', 0);
+ expect(obj).to.have.property('alpha', 1);
+ expect(obj).to.have.property('visible', true);
+ expect(obj).to.have.property('buttonMode', false);
+ expect(obj).to.have.property('parent', null);
+ expect(obj).to.have.property('worldAlpha', 1);
+
+ expect(obj).to.have.property('hitArea');
+ expect(obj).to.have.property('interactive'); // TODO: Have a better default value
+ expect('mask' in obj).to.be.true; // TODO: Have a better default value
+ expect(obj.mask).to.be.undefined;
+
+ expect(obj).to.have.property('renderable');
+ expect(obj).to.have.property('stage');
+
+ expect(obj).to.have.deep.property('worldTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ expect(obj).to.have.deep.property('localTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.localTransform);
+
+ expect(obj).to.have.deep.property('color.length', 0);
+ expect(obj).to.have.property('dynamic', true);
+}
diff --git a/test/lib/pixi/display/DisplayObjectContainer.js b/test/lib/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..085c59f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,16 @@
+
+function pixi_display_DisplayObjectContainer_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObject_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObjectContainer);
+ expect(obj).to.respondTo('addChild');
+ expect(obj).to.respondTo('addChildAt');
+ expect(obj).to.respondTo('swapChildren');
+ expect(obj).to.respondTo('getChildAt');
+ expect(obj).to.respondTo('removeChild');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('children.length', 0);
+}
diff --git a/test/lib/pixi/display/Sprite.js b/test/lib/pixi/display/Sprite.js
new file mode 100644
index 0000000..cc7a2d6
--- /dev/null
+++ b/test/lib/pixi/display/Sprite.js
@@ -0,0 +1,28 @@
+
+function pixi_display_Sprite_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Sprite);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', true);
+ expect(obj).to.have.property('stage', null);
+
+ expect(obj).to.have.property('anchor');
+ pixi_core_Point_confirm(obj.anchor, 0, 0);
+
+ expect(obj).to.have.property('blendMode', PIXI.blendModes.NORMAL);
+ expect(obj).to.have.property('width', 1); // TODO: is 1 expected
+ expect(obj).to.have.property('height', 1); // TODO: is 1 expected
+
+ // FIXME: Just make this a boolean that is always there
+ expect(!!obj.updateFrame).to.equal(obj.texture.baseTexture.hasLoaded);
+
+ expect(obj).to.have.property('texture');
+ pixi_textures_Texture_confirmNew(obj.texture, done);
+}
diff --git a/test/lib/pixi/extras/Strip.js b/test/lib/pixi/extras/Strip.js
new file mode 100644
index 0000000..8927a8a
--- /dev/null
+++ b/test/lib/pixi/extras/Strip.js
@@ -0,0 +1,12 @@
+
+function pixi_extras_Strip_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Strip);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ // TODO: Test properties
+}
diff --git a/test/lib/pixi/textures/Texture.js b/test/lib/pixi/textures/Texture.js
new file mode 100644
index 0000000..d5867b6
--- /dev/null
+++ b/test/lib/pixi/textures/Texture.js
@@ -0,0 +1,31 @@
+
+function pixi_textures_Texture_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ function confirmFrameDone() {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, obj.baseTexture.width, obj.baseTexture.height);
+
+ expect(obj).to.have.property('width', obj.baseTexture.width);
+ expect(obj).to.have.property('height', obj.baseTexture.height);
+ done();
+ }
+
+ expect(obj).to.be.an.instanceof(PIXI.Texture);
+ pixi_utils_EventTarget_like(obj);
+
+ expect(obj).to.have.property('baseTexture')
+ .and.to.be.an.instanceof(PIXI.BaseTexture);
+
+ expect(obj).to.have.property('scope', obj);
+
+ expect(obj).to.have.property('trim');
+ pixi_core_Point_confirm(obj.trim, 0, 0);
+
+ expect(obj).to.have.property('frame');
+ if (obj.baseTexture.hasLoaded) {
+ confirmFrameDone();
+ } else {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, 1, 1);
+ obj.addEventListener('update', confirmFrameDone);
+ }
+}
diff --git a/test/lib/pixi/utils/EventTarget.js b/test/lib/pixi/utils/EventTarget.js
new file mode 100644
index 0000000..7b1dcfa
--- /dev/null
+++ b/test/lib/pixi/utils/EventTarget.js
@@ -0,0 +1,8 @@
+
+function pixi_utils_EventTarget_like(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.respondTo('addEventListener');
+ expect(obj).to.respondTo('dispatchEvent');
+ expect(obj).to.respondTo('removeEventListener');
+}
diff --git a/test/lib/qunit-1.11.0.css b/test/lib/qunit-1.11.0.css
deleted file mode 100644
index d7fc0c8..0000000
--- a/test/lib/qunit-1.11.0.css
+++ /dev/null
@@ -1,244 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-/** Font Family and Sizes */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
- font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
-}
-
-#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
-#qunit-tests { font-size: smaller; }
-
-
-/** Resets */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter {
- margin: 0;
- padding: 0;
-}
-
-
-/** Header */
-
-#qunit-header {
- padding: 0.5em 0 0.5em 1em;
-
- color: #8699a4;
- background-color: #0d3349;
-
- font-size: 1.5em;
- line-height: 1em;
- font-weight: normal;
-
- border-radius: 5px 5px 0 0;
- -moz-border-radius: 5px 5px 0 0;
- -webkit-border-top-right-radius: 5px;
- -webkit-border-top-left-radius: 5px;
-}
-
-#qunit-header a {
- text-decoration: none;
- color: #c2ccd1;
-}
-
-#qunit-header a:hover,
-#qunit-header a:focus {
- color: #fff;
-}
-
-#qunit-testrunner-toolbar label {
- display: inline-block;
- padding: 0 .5em 0 .1em;
-}
-
-#qunit-banner {
- height: 5px;
-}
-
-#qunit-testrunner-toolbar {
- padding: 0.5em 0 0.5em 2em;
- color: #5E740B;
- background-color: #eee;
- overflow: hidden;
-}
-
-#qunit-userAgent {
- padding: 0.5em 0 0.5em 2.5em;
- background-color: #2b81af;
- color: #fff;
- text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
-}
-
-#qunit-modulefilter-container {
- float: right;
-}
-
-/** Tests: Pass/Fail */
-
-#qunit-tests {
- list-style-position: inside;
-}
-
-#qunit-tests li {
- padding: 0.4em 0.5em 0.4em 2.5em;
- border-bottom: 1px solid #fff;
- list-style-position: inside;
-}
-
-#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running {
- display: none;
-}
-
-#qunit-tests li strong {
- cursor: pointer;
-}
-
-#qunit-tests li a {
- padding: 0.5em;
- color: #c2ccd1;
- text-decoration: none;
-}
-#qunit-tests li a:hover,
-#qunit-tests li a:focus {
- color: #000;
-}
-
-#qunit-tests li .runtime {
- float: right;
- font-size: smaller;
-}
-
-.qunit-assert-list {
- margin-top: 0.5em;
- padding: 0.5em;
-
- background-color: #fff;
-
- border-radius: 5px;
- -moz-border-radius: 5px;
- -webkit-border-radius: 5px;
-}
-
-.qunit-collapsed {
- display: none;
-}
-
-#qunit-tests table {
- border-collapse: collapse;
- margin-top: .2em;
-}
-
-#qunit-tests th {
- text-align: right;
- vertical-align: top;
- padding: 0 .5em 0 0;
-}
-
-#qunit-tests td {
- vertical-align: top;
-}
-
-#qunit-tests pre {
- margin: 0;
- white-space: pre-wrap;
- word-wrap: break-word;
-}
-
-#qunit-tests del {
- background-color: #e0f2be;
- color: #374e0c;
- text-decoration: none;
-}
-
-#qunit-tests ins {
- background-color: #ffcaca;
- color: #500;
- text-decoration: none;
-}
-
-/*** Test Counts */
-
-#qunit-tests b.counts { color: black; }
-#qunit-tests b.passed { color: #5E740B; }
-#qunit-tests b.failed { color: #710909; }
-
-#qunit-tests li li {
- padding: 5px;
- background-color: #fff;
- border-bottom: none;
- list-style-position: inside;
-}
-
-/*** Passing Styles */
-
-#qunit-tests li li.pass {
- color: #3c510c;
- background-color: #fff;
- border-left: 10px solid #C6E746;
-}
-
-#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
-#qunit-tests .pass .test-name { color: #366097; }
-
-#qunit-tests .pass .test-actual,
-#qunit-tests .pass .test-expected { color: #999999; }
-
-#qunit-banner.qunit-pass { background-color: #C6E746; }
-
-/*** Failing Styles */
-
-#qunit-tests li li.fail {
- color: #710909;
- background-color: #fff;
- border-left: 10px solid #EE5757;
- white-space: pre;
-}
-
-#qunit-tests > li:last-child {
- border-radius: 0 0 5px 5px;
- -moz-border-radius: 0 0 5px 5px;
- -webkit-border-bottom-right-radius: 5px;
- -webkit-border-bottom-left-radius: 5px;
-}
-
-#qunit-tests .fail { color: #000000; background-color: #EE5757; }
-#qunit-tests .fail .test-name,
-#qunit-tests .fail .module-name { color: #000000; }
-
-#qunit-tests .fail .test-actual { color: #EE5757; }
-#qunit-tests .fail .test-expected { color: green; }
-
-#qunit-banner.qunit-fail { background-color: #EE5757; }
-
-
-/** Result */
-
-#qunit-testresult {
- padding: 0.5em 0.5em 0.5em 2.5em;
-
- color: #2b81af;
- background-color: #D2E0E6;
-
- border-bottom: 1px solid white;
-}
-#qunit-testresult .module-name {
- font-weight: bold;
-}
-
-/** Fixture */
-
-#qunit-fixture {
- position: absolute;
- top: -10000px;
- left: -10000px;
- width: 1000px;
- height: 1000px;
-}
diff --git a/test/lib/qunit-1.11.0.js b/test/lib/qunit-1.11.0.js
deleted file mode 100644
index 302545f..0000000
--- a/test/lib/qunit-1.11.0.js
+++ /dev/null
@@ -1,2152 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-(function( window ) {
-
-var QUnit,
- assert,
- config,
- onErrorFnPrev,
- testId = 0,
- fileName = (sourceFromStacktrace( 0 ) || "" ).replace(/(:\d+)+\)?/, "").replace(/.+\//, ""),
- toString = Object.prototype.toString,
- hasOwn = Object.prototype.hasOwnProperty,
- // Keep a local reference to Date (GH-283)
- Date = window.Date,
- defined = {
- setTimeout: typeof window.setTimeout !== "undefined",
- sessionStorage: (function() {
- var x = "qunit-test-string";
- try {
- sessionStorage.setItem( x, x );
- sessionStorage.removeItem( x );
- return true;
- } catch( e ) {
- return false;
- }
- }())
- },
- /**
- * Provides a normalized error string, correcting an issue
- * with IE 7 (and prior) where Error.prototype.toString is
- * not properly implemented
- *
- * Based on http://es5.github.com/#x15.11.4.4
- *
- * @param {String|Error} error
- * @return {String} error message
- */
- errorString = function( error ) {
- var name, message,
- errorString = error.toString();
- if ( errorString.substring( 0, 7 ) === "[object" ) {
- name = error.name ? error.name.toString() : "Error";
- message = error.message ? error.message.toString() : "";
- if ( name && message ) {
- return name + ": " + message;
- } else if ( name ) {
- return name;
- } else if ( message ) {
- return message;
- } else {
- return "Error";
- }
- } else {
- return errorString;
- }
- },
- /**
- * Makes a clone of an object using only Array or Object as base,
- * and copies over the own enumerable properties.
- *
- * @param {Object} obj
- * @return {Object} New object with only the own properties (recursively).
- */
- objectValues = function( obj ) {
- // Grunt 0.3.x uses an older version of jshint that still has jshint/jshint#392.
- /*jshint newcap: false */
- var key, val,
- vals = QUnit.is( "array", obj ) ? [] : {};
- for ( key in obj ) {
- if ( hasOwn.call( obj, key ) ) {
- val = obj[key];
- vals[key] = val === Object(val) ? objectValues(val) : val;
- }
- }
- return vals;
- };
-
-function Test( settings ) {
- extend( this, settings );
- this.assertions = [];
- this.testNumber = ++Test.count;
-}
-
-Test.count = 0;
-
-Test.prototype = {
- init: function() {
- var a, b, li,
- tests = id( "qunit-tests" );
-
- if ( tests ) {
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml;
-
- // `a` initialized at top of scope
- a = document.createElement( "a" );
- a.innerHTML = "Rerun";
- a.href = QUnit.url({ testNumber: this.testNumber });
-
- li = document.createElement( "li" );
- li.appendChild( b );
- li.appendChild( a );
- li.className = "running";
- li.id = this.id = "qunit-test-output" + testId++;
-
- tests.appendChild( li );
- }
- },
- setup: function() {
- if ( this.module !== config.previousModule ) {
- if ( config.previousModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.previousModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
- config.previousModule = this.module;
- config.moduleStats = { all: 0, bad: 0 };
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- } else if ( config.autorun ) {
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- }
-
- config.current = this;
-
- this.testEnvironment = extend({
- setup: function() {},
- teardown: function() {}
- }, this.moduleTestEnvironment );
-
- this.started = +new Date();
- runLoggingCallbacks( "testStart", QUnit, {
- name: this.testName,
- module: this.module
- });
-
- // allow utility functions to access the current test environment
- // TODO why??
- QUnit.current_testEnvironment = this.testEnvironment;
-
- if ( !config.pollution ) {
- saveGlobal();
- }
- if ( config.notrycatch ) {
- this.testEnvironment.setup.call( this.testEnvironment );
- return;
- }
- try {
- this.testEnvironment.setup.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Setup failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- },
- run: function() {
- config.current = this;
-
- var running = id( "qunit-testresult" );
-
- if ( running ) {
- running.innerHTML = "Running:
" + this.nameHtml;
- }
-
- if ( this.async ) {
- QUnit.stop();
- }
-
- this.callbackStarted = +new Date();
-
- if ( config.notrycatch ) {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- return;
- }
-
- try {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- } catch( e ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
-
- QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + " " + this.stack + ": " + ( e.message || e ), extractStacktrace( e, 0 ) );
- // else next test will carry the responsibility
- saveGlobal();
-
- // Restart the tests if they're blocking
- if ( config.blocking ) {
- QUnit.start();
- }
- }
- },
- teardown: function() {
- config.current = this;
- if ( config.notrycatch ) {
- if ( typeof this.callbackRuntime === "undefined" ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
- }
- this.testEnvironment.teardown.call( this.testEnvironment );
- return;
- } else {
- try {
- this.testEnvironment.teardown.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Teardown failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- }
- checkPollution();
- },
- finish: function() {
- config.current = this;
- if ( config.requireExpects && this.expected === null ) {
- QUnit.pushFailure( "Expected number of assertions to be defined, but expect() was not called.", this.stack );
- } else if ( this.expected !== null && this.expected !== this.assertions.length ) {
- QUnit.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack );
- } else if ( this.expected === null && !this.assertions.length ) {
- QUnit.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions.", this.stack );
- }
-
- var i, assertion, a, b, time, li, ol,
- test = this,
- good = 0,
- bad = 0,
- tests = id( "qunit-tests" );
-
- this.runtime = +new Date() - this.started;
- config.stats.all += this.assertions.length;
- config.moduleStats.all += this.assertions.length;
-
- if ( tests ) {
- ol = document.createElement( "ol" );
- ol.className = "qunit-assert-list";
-
- for ( i = 0; i < this.assertions.length; i++ ) {
- assertion = this.assertions[i];
-
- li = document.createElement( "li" );
- li.className = assertion.result ? "pass" : "fail";
- li.innerHTML = assertion.message || ( assertion.result ? "okay" : "failed" );
- ol.appendChild( li );
-
- if ( assertion.result ) {
- good++;
- } else {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
-
- // store result when possible
- if ( QUnit.config.reorder && defined.sessionStorage ) {
- if ( bad ) {
- sessionStorage.setItem( "qunit-test-" + this.module + "-" + this.testName, bad );
- } else {
- sessionStorage.removeItem( "qunit-test-" + this.module + "-" + this.testName );
- }
- }
-
- if ( bad === 0 ) {
- addClass( ol, "qunit-collapsed" );
- }
-
- // `b` initialized at top of scope
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml + " (" + bad + ", " + good + ", " + this.assertions.length + ")";
-
- addEvent(b, "click", function() {
- var next = b.parentNode.lastChild,
- collapsed = hasClass( next, "qunit-collapsed" );
- ( collapsed ? removeClass : addClass )( next, "qunit-collapsed" );
- });
-
- addEvent(b, "dblclick", function( e ) {
- var target = e && e.target ? e.target : window.event.srcElement;
- if ( target.nodeName.toLowerCase() === "span" || target.nodeName.toLowerCase() === "b" ) {
- target = target.parentNode;
- }
- if ( window.location && target.nodeName.toLowerCase() === "strong" ) {
- window.location = QUnit.url({ testNumber: test.testNumber });
- }
- });
-
- // `time` initialized at top of scope
- time = document.createElement( "span" );
- time.className = "runtime";
- time.innerHTML = this.runtime + " ms";
-
- // `li` initialized at top of scope
- li = id( this.id );
- li.className = bad ? "fail" : "pass";
- li.removeChild( li.firstChild );
- a = li.firstChild;
- li.appendChild( b );
- li.appendChild( a );
- li.appendChild( time );
- li.appendChild( ol );
-
- } else {
- for ( i = 0; i < this.assertions.length; i++ ) {
- if ( !this.assertions[i].result ) {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
- }
-
- runLoggingCallbacks( "testDone", QUnit, {
- name: this.testName,
- module: this.module,
- failed: bad,
- passed: this.assertions.length - bad,
- total: this.assertions.length,
- duration: this.runtime
- });
-
- QUnit.reset();
-
- config.current = undefined;
- },
-
- queue: function() {
- var bad,
- test = this;
-
- synchronize(function() {
- test.init();
- });
- function run() {
- // each of these can by async
- synchronize(function() {
- test.setup();
- });
- synchronize(function() {
- test.run();
- });
- synchronize(function() {
- test.teardown();
- });
- synchronize(function() {
- test.finish();
- });
- }
-
- // `bad` initialized at top of scope
- // defer when previous test run passed, if storage is available
- bad = QUnit.config.reorder && defined.sessionStorage &&
- +sessionStorage.getItem( "qunit-test-" + this.module + "-" + this.testName );
-
- if ( bad ) {
- run();
- } else {
- synchronize( run, true );
- }
- }
-};
-
-// Root QUnit object.
-// `QUnit` initialized at top of scope
-QUnit = {
-
- // call on start of module test to prepend name to all tests
- module: function( name, testEnvironment ) {
- config.currentModule = name;
- config.currentModuleTestEnvironment = testEnvironment;
- config.modules[name] = true;
- },
-
- asyncTest: function( testName, expected, callback ) {
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- QUnit.test( testName, expected, callback, true );
- },
-
- test: function( testName, expected, callback, async ) {
- var test,
- nameHtml = "" + escapeText( testName ) + "";
-
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- if ( config.currentModule ) {
- nameHtml = "" + escapeText( config.currentModule ) + ": " + nameHtml;
- }
-
- test = new Test({
- nameHtml: nameHtml,
- testName: testName,
- expected: expected,
- async: async,
- callback: callback,
- module: config.currentModule,
- moduleTestEnvironment: config.currentModuleTestEnvironment,
- stack: sourceFromStacktrace( 2 )
- });
-
- if ( !validTest( test ) ) {
- return;
- }
-
- test.queue();
- },
-
- // Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through.
- expect: function( asserts ) {
- if (arguments.length === 1) {
- config.current.expected = asserts;
- } else {
- return config.current.expected;
- }
- },
-
- start: function( count ) {
- // QUnit hasn't been initialized yet.
- // Note: RequireJS (et al) may delay onLoad
- if ( config.semaphore === undefined ) {
- QUnit.begin(function() {
- // This is triggered at the top of QUnit.load, push start() to the event loop, to allow QUnit.load to finish first
- setTimeout(function() {
- QUnit.start( count );
- });
- });
- return;
- }
-
- config.semaphore -= count || 1;
- // don't start until equal number of stop-calls
- if ( config.semaphore > 0 ) {
- return;
- }
- // ignore if start is called more often then stop
- if ( config.semaphore < 0 ) {
- config.semaphore = 0;
- QUnit.pushFailure( "Called start() while already started (QUnit.config.semaphore was 0 already)", null, sourceFromStacktrace(2) );
- return;
- }
- // A slight delay, to avoid any current callbacks
- if ( defined.setTimeout ) {
- window.setTimeout(function() {
- if ( config.semaphore > 0 ) {
- return;
- }
- if ( config.timeout ) {
- clearTimeout( config.timeout );
- }
-
- config.blocking = false;
- process( true );
- }, 13);
- } else {
- config.blocking = false;
- process( true );
- }
- },
-
- stop: function( count ) {
- config.semaphore += count || 1;
- config.blocking = true;
-
- if ( config.testTimeout && defined.setTimeout ) {
- clearTimeout( config.timeout );
- config.timeout = window.setTimeout(function() {
- QUnit.ok( false, "Test timed out" );
- config.semaphore = 1;
- QUnit.start();
- }, config.testTimeout );
- }
- }
-};
-
-// `assert` initialized at top of scope
-// Asssert helpers
-// All of these must either call QUnit.push() or manually do:
-// - runLoggingCallbacks( "log", .. );
-// - config.current.assertions.push({ .. });
-// We attach it to the QUnit object *after* we expose the public API,
-// otherwise `assert` will become a global variable in browsers (#341).
-assert = {
- /**
- * Asserts rough true-ish result.
- * @name ok
- * @function
- * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" );
- */
- ok: function( result, msg ) {
- if ( !config.current ) {
- throw new Error( "ok() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
- result = !!result;
-
- var source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: msg
- };
-
- msg = escapeText( msg || (result ? "okay" : "failed" ) );
- msg = "" + msg + "";
-
- if ( !result ) {
- source = sourceFromStacktrace( 2 );
- if ( source ) {
- details.source = source;
- msg += "Source: | " + escapeText( source ) + " |
---|
";
- }
- }
- runLoggingCallbacks( "log", QUnit, details );
- config.current.assertions.push({
- result: result,
- message: msg
- });
- },
-
- /**
- * Assert that the first two arguments are equal, with an optional message.
- * Prints out both actual and expected values.
- * @name equal
- * @function
- * @example equal( format( "Received {0} bytes.", 2), "Received 2 bytes.", "format() replaces {0} with next argument" );
- */
- equal: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected == actual, actual, expected, message );
- },
-
- /**
- * @name notEqual
- * @function
- */
- notEqual: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected != actual, actual, expected, message );
- },
-
- /**
- * @name propEqual
- * @function
- */
- propEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notPropEqual
- * @function
- */
- notPropEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name deepEqual
- * @function
- */
- deepEqual: function( actual, expected, message ) {
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notDeepEqual
- * @function
- */
- notDeepEqual: function( actual, expected, message ) {
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name strictEqual
- * @function
- */
- strictEqual: function( actual, expected, message ) {
- QUnit.push( expected === actual, actual, expected, message );
- },
-
- /**
- * @name notStrictEqual
- * @function
- */
- notStrictEqual: function( actual, expected, message ) {
- QUnit.push( expected !== actual, actual, expected, message );
- },
-
- "throws": function( block, expected, message ) {
- var actual,
- expectedOutput = expected,
- ok = false;
-
- // 'expected' is optional
- if ( typeof expected === "string" ) {
- message = expected;
- expected = null;
- }
-
- config.current.ignoreGlobalErrors = true;
- try {
- block.call( config.current.testEnvironment );
- } catch (e) {
- actual = e;
- }
- config.current.ignoreGlobalErrors = false;
-
- if ( actual ) {
- // we don't want to validate thrown error
- if ( !expected ) {
- ok = true;
- expectedOutput = null;
- // expected is a regexp
- } else if ( QUnit.objectType( expected ) === "regexp" ) {
- ok = expected.test( errorString( actual ) );
- // expected is a constructor
- } else if ( actual instanceof expected ) {
- ok = true;
- // expected is a validation function which returns true is validation passed
- } else if ( expected.call( {}, actual ) === true ) {
- expectedOutput = null;
- ok = true;
- }
-
- QUnit.push( ok, actual, expectedOutput, message );
- } else {
- QUnit.pushFailure( message, null, 'No exception was thrown.' );
- }
- }
-};
-
-/**
- * @deprecate since 1.8.0
- * Kept assertion helpers in root for backwards compatibility.
- */
-extend( QUnit, assert );
-
-/**
- * @deprecated since 1.9.0
- * Kept root "raises()" for backwards compatibility.
- * (Note that we don't introduce assert.raises).
- */
-QUnit.raises = assert[ "throws" ];
-
-/**
- * @deprecated since 1.0.0, replaced with error pushes since 1.3.0
- * Kept to avoid TypeErrors for undefined methods.
- */
-QUnit.equals = function() {
- QUnit.push( false, false, false, "QUnit.equals has been deprecated since 2009 (e88049a0), use QUnit.equal instead" );
-};
-QUnit.same = function() {
- QUnit.push( false, false, false, "QUnit.same has been deprecated since 2009 (e88049a0), use QUnit.deepEqual instead" );
-};
-
-// We want access to the constructor's prototype
-(function() {
- function F() {}
- F.prototype = QUnit;
- QUnit = new F();
- // Make F QUnit's constructor so that we can add to the prototype later
- QUnit.constructor = F;
-}());
-
-/**
- * Config object: Maintain internal state
- * Later exposed as QUnit.config
- * `config` initialized at top of scope
- */
-config = {
- // The queue of tests to run
- queue: [],
-
- // block until document ready
- blocking: true,
-
- // when enabled, show only failing tests
- // gets persisted through sessionStorage and can be changed in UI via checkbox
- hidepassed: false,
-
- // by default, run previously failed tests first
- // very useful in combination with "Hide passed tests" checked
- reorder: true,
-
- // by default, modify document.title when suite is done
- altertitle: true,
-
- // when enabled, all tests must call expect()
- requireExpects: false,
-
- // add checkboxes that are persisted in the query-string
- // when enabled, the id is set to `true` as a `QUnit.config` property
- urlConfig: [
- {
- id: "noglobals",
- label: "Check for Globals",
- tooltip: "Enabling this will test if any test introduces new properties on the `window` object. Stored as query-strings."
- },
- {
- id: "notrycatch",
- label: "No try-catch",
- tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging exceptions in IE reasonable. Stored as query-strings."
- }
- ],
-
- // Set of all modules.
- modules: {},
-
- // logging callback queues
- begin: [],
- done: [],
- log: [],
- testStart: [],
- testDone: [],
- moduleStart: [],
- moduleDone: []
-};
-
-// Export global variables, unless an 'exports' object exists,
-// in that case we assume we're in CommonJS (dealt with on the bottom of the script)
-if ( typeof exports === "undefined" ) {
- extend( window, QUnit );
-
- // Expose QUnit object
- window.QUnit = QUnit;
-}
-
-// Initialize more QUnit.config and QUnit.urlParams
-(function() {
- var i,
- location = window.location || { search: "", protocol: "file:" },
- params = location.search.slice( 1 ).split( "&" ),
- length = params.length,
- urlParams = {},
- current;
-
- if ( params[ 0 ] ) {
- for ( i = 0; i < length; i++ ) {
- current = params[ i ].split( "=" );
- current[ 0 ] = decodeURIComponent( current[ 0 ] );
- // allow just a key to turn on a flag, e.g., test.html?noglobals
- current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true;
- urlParams[ current[ 0 ] ] = current[ 1 ];
- }
- }
-
- QUnit.urlParams = urlParams;
-
- // String search anywhere in moduleName+testName
- config.filter = urlParams.filter;
-
- // Exact match of the module name
- config.module = urlParams.module;
-
- config.testNumber = parseInt( urlParams.testNumber, 10 ) || null;
-
- // Figure out if we're running the tests from a server or not
- QUnit.isLocal = location.protocol === "file:";
-}());
-
-// Extend QUnit object,
-// these after set here because they should not be exposed as global functions
-extend( QUnit, {
- assert: assert,
-
- config: config,
-
- // Initialize the configuration options
- init: function() {
- extend( config, {
- stats: { all: 0, bad: 0 },
- moduleStats: { all: 0, bad: 0 },
- started: +new Date(),
- updateRate: 1000,
- blocking: false,
- autostart: true,
- autorun: false,
- filter: "",
- queue: [],
- semaphore: 1
- });
-
- var tests, banner, result,
- qunit = id( "qunit" );
-
- if ( qunit ) {
- qunit.innerHTML =
- "" +
- "" +
- "" +
- "" +
- "
";
- }
-
- tests = id( "qunit-tests" );
- banner = id( "qunit-banner" );
- result = id( "qunit-testresult" );
-
- if ( tests ) {
- tests.innerHTML = "";
- }
-
- if ( banner ) {
- banner.className = "";
- }
-
- if ( result ) {
- result.parentNode.removeChild( result );
- }
-
- if ( tests ) {
- result = document.createElement( "p" );
- result.id = "qunit-testresult";
- result.className = "result";
- tests.parentNode.insertBefore( result, tests );
- result.innerHTML = "Running...
";
- }
- },
-
- // Resets the test setup. Useful for tests that modify the DOM.
- reset: function() {
- var fixture = id( "qunit-fixture" );
- if ( fixture ) {
- fixture.innerHTML = config.fixture;
- }
- },
-
- // Trigger an event on an element.
- // @example triggerEvent( document.body, "click" );
- triggerEvent: function( elem, type, event ) {
- if ( document.createEvent ) {
- event = document.createEvent( "MouseEvents" );
- event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView,
- 0, 0, 0, 0, 0, false, false, false, false, 0, null);
-
- elem.dispatchEvent( event );
- } else if ( elem.fireEvent ) {
- elem.fireEvent( "on" + type );
- }
- },
-
- // Safe object type checking
- is: function( type, obj ) {
- return QUnit.objectType( obj ) === type;
- },
-
- objectType: function( obj ) {
- if ( typeof obj === "undefined" ) {
- return "undefined";
- // consider: typeof null === object
- }
- if ( obj === null ) {
- return "null";
- }
-
- var match = toString.call( obj ).match(/^\[object\s(.*)\]$/),
- type = match && match[1] || "";
-
- switch ( type ) {
- case "Number":
- if ( isNaN(obj) ) {
- return "nan";
- }
- return "number";
- case "String":
- case "Boolean":
- case "Array":
- case "Date":
- case "RegExp":
- case "Function":
- return type.toLowerCase();
- }
- if ( typeof obj === "object" ) {
- return "object";
- }
- return undefined;
- },
-
- push: function( result, actual, expected, message ) {
- if ( !config.current ) {
- throw new Error( "assertion outside test context, was " + sourceFromStacktrace() );
- }
-
- var output, source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: message,
- actual: actual,
- expected: expected
- };
-
- message = escapeText( message ) || ( result ? "okay" : "failed" );
- message = "" + message + "";
- output = message;
-
- if ( !result ) {
- expected = escapeText( QUnit.jsDump.parse(expected) );
- actual = escapeText( QUnit.jsDump.parse(actual) );
- output += "Expected: | " + expected + " |
";
-
- if ( actual !== expected ) {
- output += "Result: | " + actual + " |
";
- output += "Diff: | " + QUnit.diff( expected, actual ) + " |
";
- }
-
- source = sourceFromStacktrace();
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
- }
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: !!result,
- message: output
- });
- },
-
- pushFailure: function( message, source, actual ) {
- if ( !config.current ) {
- throw new Error( "pushFailure() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
-
- var output,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: false,
- message: message
- };
-
- message = escapeText( message ) || "error";
- message = "" + message + "";
- output = message;
-
- output += "";
-
- if ( actual ) {
- output += "Result: | " + escapeText( actual ) + " |
";
- }
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: false,
- message: output
- });
- },
-
- url: function( params ) {
- params = extend( extend( {}, QUnit.urlParams ), params );
- var key,
- querystring = "?";
-
- for ( key in params ) {
- if ( !hasOwn.call( params, key ) ) {
- continue;
- }
- querystring += encodeURIComponent( key ) + "=" +
- encodeURIComponent( params[ key ] ) + "&";
- }
- return window.location.protocol + "//" + window.location.host +
- window.location.pathname + querystring.slice( 0, -1 );
- },
-
- extend: extend,
- id: id,
- addEvent: addEvent
- // load, equiv, jsDump, diff: Attached later
-});
-
-/**
- * @deprecated: Created for backwards compatibility with test runner that set the hook function
- * into QUnit.{hook}, instead of invoking it and passing the hook function.
- * QUnit.constructor is set to the empty F() above so that we can add to it's prototype here.
- * Doing this allows us to tell if the following methods have been overwritten on the actual
- * QUnit object.
- */
-extend( QUnit.constructor.prototype, {
-
- // Logging callbacks; all receive a single argument with the listed properties
- // run test/logs.html for any related changes
- begin: registerLoggingCallback( "begin" ),
-
- // done: { failed, passed, total, runtime }
- done: registerLoggingCallback( "done" ),
-
- // log: { result, actual, expected, message }
- log: registerLoggingCallback( "log" ),
-
- // testStart: { name }
- testStart: registerLoggingCallback( "testStart" ),
-
- // testDone: { name, failed, passed, total, duration }
- testDone: registerLoggingCallback( "testDone" ),
-
- // moduleStart: { name }
- moduleStart: registerLoggingCallback( "moduleStart" ),
-
- // moduleDone: { name, failed, passed, total }
- moduleDone: registerLoggingCallback( "moduleDone" )
-});
-
-if ( typeof document === "undefined" || document.readyState === "complete" ) {
- config.autorun = true;
-}
-
-QUnit.load = function() {
- runLoggingCallbacks( "begin", QUnit, {} );
-
- // Initialize the config, saving the execution queue
- var banner, filter, i, label, len, main, ol, toolbar, userAgent, val,
- urlConfigCheckboxesContainer, urlConfigCheckboxes, moduleFilter,
- numModules = 0,
- moduleFilterHtml = "",
- urlConfigHtml = "",
- oldconfig = extend( {}, config );
-
- QUnit.init();
- extend(config, oldconfig);
-
- config.blocking = false;
-
- len = config.urlConfig.length;
-
- for ( i = 0; i < len; i++ ) {
- val = config.urlConfig[i];
- if ( typeof val === "string" ) {
- val = {
- id: val,
- label: val,
- tooltip: "[no tooltip available]"
- };
- }
- config[ val.id ] = QUnit.urlParams[ val.id ];
- urlConfigHtml += "";
- }
-
- moduleFilterHtml += "";
-
- // `userAgent` initialized at top of scope
- userAgent = id( "qunit-userAgent" );
- if ( userAgent ) {
- userAgent.innerHTML = navigator.userAgent;
- }
-
- // `banner` initialized at top of scope
- banner = id( "qunit-header" );
- if ( banner ) {
- banner.innerHTML = "" + banner.innerHTML + " ";
- }
-
- // `toolbar` initialized at top of scope
- toolbar = id( "qunit-testrunner-toolbar" );
- if ( toolbar ) {
- // `filter` initialized at top of scope
- filter = document.createElement( "input" );
- filter.type = "checkbox";
- filter.id = "qunit-filter-pass";
-
- addEvent( filter, "click", function() {
- var tmp,
- ol = document.getElementById( "qunit-tests" );
-
- if ( filter.checked ) {
- ol.className = ol.className + " hidepass";
- } else {
- tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " ";
- ol.className = tmp.replace( / hidepass /, " " );
- }
- if ( defined.sessionStorage ) {
- if (filter.checked) {
- sessionStorage.setItem( "qunit-filter-passed-tests", "true" );
- } else {
- sessionStorage.removeItem( "qunit-filter-passed-tests" );
- }
- }
- });
-
- if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem( "qunit-filter-passed-tests" ) ) {
- filter.checked = true;
- // `ol` initialized at top of scope
- ol = document.getElementById( "qunit-tests" );
- ol.className = ol.className + " hidepass";
- }
- toolbar.appendChild( filter );
-
- // `label` initialized at top of scope
- label = document.createElement( "label" );
- label.setAttribute( "for", "qunit-filter-pass" );
- label.setAttribute( "title", "Only show tests and assertons that fail. Stored in sessionStorage." );
- label.innerHTML = "Hide passed tests";
- toolbar.appendChild( label );
-
- urlConfigCheckboxesContainer = document.createElement("span");
- urlConfigCheckboxesContainer.innerHTML = urlConfigHtml;
- urlConfigCheckboxes = urlConfigCheckboxesContainer.getElementsByTagName("input");
- // For oldIE support:
- // * Add handlers to the individual elements instead of the container
- // * Use "click" instead of "change"
- // * Fallback from event.target to event.srcElement
- addEvents( urlConfigCheckboxes, "click", function( event ) {
- var params = {},
- target = event.target || event.srcElement;
- params[ target.name ] = target.checked ? true : undefined;
- window.location = QUnit.url( params );
- });
- toolbar.appendChild( urlConfigCheckboxesContainer );
-
- if (numModules > 1) {
- moduleFilter = document.createElement( 'span' );
- moduleFilter.setAttribute( 'id', 'qunit-modulefilter-container' );
- moduleFilter.innerHTML = moduleFilterHtml;
- addEvent( moduleFilter.lastChild, "change", function() {
- var selectBox = moduleFilter.getElementsByTagName("select")[0],
- selectedModule = decodeURIComponent(selectBox.options[selectBox.selectedIndex].value);
-
- window.location = QUnit.url( { module: ( selectedModule === "" ) ? undefined : selectedModule } );
- });
- toolbar.appendChild(moduleFilter);
- }
- }
-
- // `main` initialized at top of scope
- main = id( "qunit-fixture" );
- if ( main ) {
- config.fixture = main.innerHTML;
- }
-
- if ( config.autostart ) {
- QUnit.start();
- }
-};
-
-addEvent( window, "load", QUnit.load );
-
-// `onErrorFnPrev` initialized at top of scope
-// Preserve other handlers
-onErrorFnPrev = window.onerror;
-
-// Cover uncaught exceptions
-// Returning true will surpress the default browser handler,
-// returning false will let it run.
-window.onerror = function ( error, filePath, linerNr ) {
- var ret = false;
- if ( onErrorFnPrev ) {
- ret = onErrorFnPrev( error, filePath, linerNr );
- }
-
- // Treat return value as window.onerror itself does,
- // Only do our handling if not surpressed.
- if ( ret !== true ) {
- if ( QUnit.config.current ) {
- if ( QUnit.config.current.ignoreGlobalErrors ) {
- return true;
- }
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- } else {
- QUnit.test( "global failure", extend( function() {
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- }, { validTest: validTest } ) );
- }
- return false;
- }
-
- return ret;
-};
-
-function done() {
- config.autorun = true;
-
- // Log the last module results
- if ( config.currentModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.currentModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
-
- var i, key,
- banner = id( "qunit-banner" ),
- tests = id( "qunit-tests" ),
- runtime = +new Date() - config.started,
- passed = config.stats.all - config.stats.bad,
- html = [
- "Tests completed in ",
- runtime,
- " milliseconds.
",
- "",
- passed,
- " assertions of ",
- config.stats.all,
- " passed, ",
- config.stats.bad,
- " failed."
- ].join( "" );
-
- if ( banner ) {
- banner.className = ( config.stats.bad ? "qunit-fail" : "qunit-pass" );
- }
-
- if ( tests ) {
- id( "qunit-testresult" ).innerHTML = html;
- }
-
- if ( config.altertitle && typeof document !== "undefined" && document.title ) {
- // show ✖ for good, ✔ for bad suite result in title
- // use escape sequences in case file gets loaded with non-utf-8-charset
- document.title = [
- ( config.stats.bad ? "\u2716" : "\u2714" ),
- document.title.replace( /^[\u2714\u2716] /i, "" )
- ].join( " " );
- }
-
- // clear own sessionStorage items if all tests passed
- if ( config.reorder && defined.sessionStorage && config.stats.bad === 0 ) {
- // `key` & `i` initialized at top of scope
- for ( i = 0; i < sessionStorage.length; i++ ) {
- key = sessionStorage.key( i++ );
- if ( key.indexOf( "qunit-test-" ) === 0 ) {
- sessionStorage.removeItem( key );
- }
- }
- }
-
- // scroll back to top to show results
- if ( window.scrollTo ) {
- window.scrollTo(0, 0);
- }
-
- runLoggingCallbacks( "done", QUnit, {
- failed: config.stats.bad,
- passed: passed,
- total: config.stats.all,
- runtime: runtime
- });
-}
-
-/** @return Boolean: true if this test should be ran */
-function validTest( test ) {
- var include,
- filter = config.filter && config.filter.toLowerCase(),
- module = config.module && config.module.toLowerCase(),
- fullName = (test.module + ": " + test.testName).toLowerCase();
-
- // Internally-generated tests are always valid
- if ( test.callback && test.callback.validTest === validTest ) {
- delete test.callback.validTest;
- return true;
- }
-
- if ( config.testNumber ) {
- return test.testNumber === config.testNumber;
- }
-
- if ( module && ( !test.module || test.module.toLowerCase() !== module ) ) {
- return false;
- }
-
- if ( !filter ) {
- return true;
- }
-
- include = filter.charAt( 0 ) !== "!";
- if ( !include ) {
- filter = filter.slice( 1 );
- }
-
- // If the filter matches, we need to honour include
- if ( fullName.indexOf( filter ) !== -1 ) {
- return include;
- }
-
- // Otherwise, do the opposite
- return !include;
-}
-
-// so far supports only Firefox, Chrome and Opera (buggy), Safari (for real exceptions)
-// Later Safari and IE10 are supposed to support error.stack as well
-// See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack
-function extractStacktrace( e, offset ) {
- offset = offset === undefined ? 3 : offset;
-
- var stack, include, i;
-
- if ( e.stacktrace ) {
- // Opera
- return e.stacktrace.split( "\n" )[ offset + 3 ];
- } else if ( e.stack ) {
- // Firefox, Chrome
- stack = e.stack.split( "\n" );
- if (/^error$/i.test( stack[0] ) ) {
- stack.shift();
- }
- if ( fileName ) {
- include = [];
- for ( i = offset; i < stack.length; i++ ) {
- if ( stack[ i ].indexOf( fileName ) !== -1 ) {
- break;
- }
- include.push( stack[ i ] );
- }
- if ( include.length ) {
- return include.join( "\n" );
- }
- }
- return stack[ offset ];
- } else if ( e.sourceURL ) {
- // Safari, PhantomJS
- // hopefully one day Safari provides actual stacktraces
- // exclude useless self-reference for generated Error objects
- if ( /qunit.js$/.test( e.sourceURL ) ) {
- return;
- }
- // for actual exceptions, this is useful
- return e.sourceURL + ":" + e.line;
- }
-}
-function sourceFromStacktrace( offset ) {
- try {
- throw new Error();
- } catch ( e ) {
- return extractStacktrace( e, offset );
- }
-}
-
-/**
- * Escape text for attribute or text content.
- */
-function escapeText( s ) {
- if ( !s ) {
- return "";
- }
- s = s + "";
- // Both single quotes and double quotes (for attributes)
- return s.replace( /['"<>&]/g, function( s ) {
- switch( s ) {
- case '\'':
- return ''';
- case '"':
- return '"';
- case '<':
- return '<';
- case '>':
- return '>';
- case '&':
- return '&';
- }
- });
-}
-
-function synchronize( callback, last ) {
- config.queue.push( callback );
-
- if ( config.autorun && !config.blocking ) {
- process( last );
- }
-}
-
-function process( last ) {
- function next() {
- process( last );
- }
- var start = new Date().getTime();
- config.depth = config.depth ? config.depth + 1 : 1;
-
- while ( config.queue.length && !config.blocking ) {
- if ( !defined.setTimeout || config.updateRate <= 0 || ( ( new Date().getTime() - start ) < config.updateRate ) ) {
- config.queue.shift()();
- } else {
- window.setTimeout( next, 13 );
- break;
- }
- }
- config.depth--;
- if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) {
- done();
- }
-}
-
-function saveGlobal() {
- config.pollution = [];
-
- if ( config.noglobals ) {
- for ( var key in window ) {
- // in Opera sometimes DOM element ids show up here, ignore them
- if ( !hasOwn.call( window, key ) || /^qunit-test-output/.test( key ) ) {
- continue;
- }
- config.pollution.push( key );
- }
- }
-}
-
-function checkPollution() {
- var newGlobals,
- deletedGlobals,
- old = config.pollution;
-
- saveGlobal();
-
- newGlobals = diff( config.pollution, old );
- if ( newGlobals.length > 0 ) {
- QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join(", ") );
- }
-
- deletedGlobals = diff( old, config.pollution );
- if ( deletedGlobals.length > 0 ) {
- QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join(", ") );
- }
-}
-
-// returns a new Array with the elements that are in a but not in b
-function diff( a, b ) {
- var i, j,
- result = a.slice();
-
- for ( i = 0; i < result.length; i++ ) {
- for ( j = 0; j < b.length; j++ ) {
- if ( result[i] === b[j] ) {
- result.splice( i, 1 );
- i--;
- break;
- }
- }
- }
- return result;
-}
-
-function extend( a, b ) {
- for ( var prop in b ) {
- if ( b[ prop ] === undefined ) {
- delete a[ prop ];
-
- // Avoid "Member not found" error in IE8 caused by setting window.constructor
- } else if ( prop !== "constructor" || a !== window ) {
- a[ prop ] = b[ prop ];
- }
- }
-
- return a;
-}
-
-/**
- * @param {HTMLElement} elem
- * @param {string} type
- * @param {Function} fn
- */
-function addEvent( elem, type, fn ) {
- // Standards-based browsers
- if ( elem.addEventListener ) {
- elem.addEventListener( type, fn, false );
- // IE
- } else {
- elem.attachEvent( "on" + type, fn );
- }
-}
-
-/**
- * @param {Array|NodeList} elems
- * @param {string} type
- * @param {Function} fn
- */
-function addEvents( elems, type, fn ) {
- var i = elems.length;
- while ( i-- ) {
- addEvent( elems[i], type, fn );
- }
-}
-
-function hasClass( elem, name ) {
- return (" " + elem.className + " ").indexOf(" " + name + " ") > -1;
-}
-
-function addClass( elem, name ) {
- if ( !hasClass( elem, name ) ) {
- elem.className += (elem.className ? " " : "") + name;
- }
-}
-
-function removeClass( elem, name ) {
- var set = " " + elem.className + " ";
- // Class name may appear multiple times
- while ( set.indexOf(" " + name + " ") > -1 ) {
- set = set.replace(" " + name + " " , " ");
- }
- // If possible, trim it for prettiness, but not neccecarily
- elem.className = window.jQuery ? jQuery.trim( set ) : ( set.trim ? set.trim() : set );
-}
-
-function id( name ) {
- return !!( typeof document !== "undefined" && document && document.getElementById ) &&
- document.getElementById( name );
-}
-
-function registerLoggingCallback( key ) {
- return function( callback ) {
- config[key].push( callback );
- };
-}
-
-// Supports deprecated method of completely overwriting logging callbacks
-function runLoggingCallbacks( key, scope, args ) {
- var i, callbacks;
- if ( QUnit.hasOwnProperty( key ) ) {
- QUnit[ key ].call(scope, args );
- } else {
- callbacks = config[ key ];
- for ( i = 0; i < callbacks.length; i++ ) {
- callbacks[ i ].call( scope, args );
- }
- }
-}
-
-// Test for equality any JavaScript type.
-// Author: Philippe Rathé
-QUnit.equiv = (function() {
-
- // Call the o related callback with the given arguments.
- function bindCallbacks( o, callbacks, args ) {
- var prop = QUnit.objectType( o );
- if ( prop ) {
- if ( QUnit.objectType( callbacks[ prop ] ) === "function" ) {
- return callbacks[ prop ].apply( callbacks, args );
- } else {
- return callbacks[ prop ]; // or undefined
- }
- }
- }
-
- // the real equiv function
- var innerEquiv,
- // stack to decide between skip/abort functions
- callers = [],
- // stack to avoiding loops from circular referencing
- parents = [],
-
- getProto = Object.getPrototypeOf || function ( obj ) {
- return obj.__proto__;
- },
- callbacks = (function () {
-
- // for string, boolean, number and null
- function useStrictEquality( b, a ) {
- /*jshint eqeqeq:false */
- if ( b instanceof a.constructor || a instanceof b.constructor ) {
- // to catch short annotaion VS 'new' annotation of a
- // declaration
- // e.g. var i = 1;
- // var j = new Number(1);
- return a == b;
- } else {
- return a === b;
- }
- }
-
- return {
- "string": useStrictEquality,
- "boolean": useStrictEquality,
- "number": useStrictEquality,
- "null": useStrictEquality,
- "undefined": useStrictEquality,
-
- "nan": function( b ) {
- return isNaN( b );
- },
-
- "date": function( b, a ) {
- return QUnit.objectType( b ) === "date" && a.valueOf() === b.valueOf();
- },
-
- "regexp": function( b, a ) {
- return QUnit.objectType( b ) === "regexp" &&
- // the regex itself
- a.source === b.source &&
- // and its modifers
- a.global === b.global &&
- // (gmi) ...
- a.ignoreCase === b.ignoreCase &&
- a.multiline === b.multiline &&
- a.sticky === b.sticky;
- },
-
- // - skip when the property is a method of an instance (OOP)
- // - abort otherwise,
- // initial === would have catch identical references anyway
- "function": function() {
- var caller = callers[callers.length - 1];
- return caller !== Object && typeof caller !== "undefined";
- },
-
- "array": function( b, a ) {
- var i, j, len, loop;
-
- // b could be an object literal here
- if ( QUnit.objectType( b ) !== "array" ) {
- return false;
- }
-
- len = a.length;
- if ( len !== b.length ) {
- // safe and faster
- return false;
- }
-
- // track reference to avoid circular references
- parents.push( a );
- for ( i = 0; i < len; i++ ) {
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- loop = true;// dont rewalk array
- }
- }
- if ( !loop && !innerEquiv(a[i], b[i]) ) {
- parents.pop();
- return false;
- }
- }
- parents.pop();
- return true;
- },
-
- "object": function( b, a ) {
- var i, j, loop,
- // Default to true
- eq = true,
- aProperties = [],
- bProperties = [];
-
- // comparing constructors is more strict than using
- // instanceof
- if ( a.constructor !== b.constructor ) {
- // Allow objects with no prototype to be equivalent to
- // objects with Object as their constructor.
- if ( !(( getProto(a) === null && getProto(b) === Object.prototype ) ||
- ( getProto(b) === null && getProto(a) === Object.prototype ) ) ) {
- return false;
- }
- }
-
- // stack constructor before traversing properties
- callers.push( a.constructor );
- // track reference to avoid circular references
- parents.push( a );
-
- for ( i in a ) { // be strict: don't ensures hasOwnProperty
- // and go deep
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- // don't go down the same path twice
- loop = true;
- }
- }
- aProperties.push(i); // collect a's properties
-
- if (!loop && !innerEquiv( a[i], b[i] ) ) {
- eq = false;
- break;
- }
- }
-
- callers.pop(); // unstack, we are done
- parents.pop();
-
- for ( i in b ) {
- bProperties.push( i ); // collect b's properties
- }
-
- // Ensures identical properties name
- return eq && innerEquiv( aProperties.sort(), bProperties.sort() );
- }
- };
- }());
-
- innerEquiv = function() { // can take multiple arguments
- var args = [].slice.apply( arguments );
- if ( args.length < 2 ) {
- return true; // end transition
- }
-
- return (function( a, b ) {
- if ( a === b ) {
- return true; // catch the most you can
- } else if ( a === null || b === null || typeof a === "undefined" ||
- typeof b === "undefined" ||
- QUnit.objectType(a) !== QUnit.objectType(b) ) {
- return false; // don't lose time with error prone cases
- } else {
- return bindCallbacks(a, callbacks, [ b, a ]);
- }
-
- // apply transition with (1..n) arguments
- }( args[0], args[1] ) && arguments.callee.apply( this, args.splice(1, args.length - 1 )) );
- };
-
- return innerEquiv;
-}());
-
-/**
- * jsDump Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com |
- * http://flesler.blogspot.com Licensed under BSD
- * (http://www.opensource.org/licenses/bsd-license.php) Date: 5/15/2008
- *
- * @projectDescription Advanced and extensible data dumping for Javascript.
- * @version 1.0.0
- * @author Ariel Flesler
- * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html}
- */
-QUnit.jsDump = (function() {
- function quote( str ) {
- return '"' + str.toString().replace( /"/g, '\\"' ) + '"';
- }
- function literal( o ) {
- return o + "";
- }
- function join( pre, arr, post ) {
- var s = jsDump.separator(),
- base = jsDump.indent(),
- inner = jsDump.indent(1);
- if ( arr.join ) {
- arr = arr.join( "," + s + inner );
- }
- if ( !arr ) {
- return pre + post;
- }
- return [ pre, inner + arr, base + post ].join(s);
- }
- function array( arr, stack ) {
- var i = arr.length, ret = new Array(i);
- this.up();
- while ( i-- ) {
- ret[i] = this.parse( arr[i] , undefined , stack);
- }
- this.down();
- return join( "[", ret, "]" );
- }
-
- var reName = /^function (\w+)/,
- jsDump = {
- // type is used mostly internally, you can fix a (custom)type in advance
- parse: function( obj, type, stack ) {
- stack = stack || [ ];
- var inStack, res,
- parser = this.parsers[ type || this.typeOf(obj) ];
-
- type = typeof parser;
- inStack = inArray( obj, stack );
-
- if ( inStack !== -1 ) {
- return "recursion(" + (inStack - stack.length) + ")";
- }
- if ( type === "function" ) {
- stack.push( obj );
- res = parser.call( this, obj, stack );
- stack.pop();
- return res;
- }
- return ( type === "string" ) ? parser : this.parsers.error;
- },
- typeOf: function( obj ) {
- var type;
- if ( obj === null ) {
- type = "null";
- } else if ( typeof obj === "undefined" ) {
- type = "undefined";
- } else if ( QUnit.is( "regexp", obj) ) {
- type = "regexp";
- } else if ( QUnit.is( "date", obj) ) {
- type = "date";
- } else if ( QUnit.is( "function", obj) ) {
- type = "function";
- } else if ( typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined" ) {
- type = "window";
- } else if ( obj.nodeType === 9 ) {
- type = "document";
- } else if ( obj.nodeType ) {
- type = "node";
- } else if (
- // native arrays
- toString.call( obj ) === "[object Array]" ||
- // NodeList objects
- ( typeof obj.length === "number" && typeof obj.item !== "undefined" && ( obj.length ? obj.item(0) === obj[0] : ( obj.item( 0 ) === null && typeof obj[0] === "undefined" ) ) )
- ) {
- type = "array";
- } else if ( obj.constructor === Error.prototype.constructor ) {
- type = "error";
- } else {
- type = typeof obj;
- }
- return type;
- },
- separator: function() {
- return this.multiline ? this.HTML ? "
" : "\n" : this.HTML ? " " : " ";
- },
- // extra can be a number, shortcut for increasing-calling-decreasing
- indent: function( extra ) {
- if ( !this.multiline ) {
- return "";
- }
- var chr = this.indentChar;
- if ( this.HTML ) {
- chr = chr.replace( /\t/g, " " ).replace( / /g, " " );
- }
- return new Array( this._depth_ + (extra||0) ).join(chr);
- },
- up: function( a ) {
- this._depth_ += a || 1;
- },
- down: function( a ) {
- this._depth_ -= a || 1;
- },
- setParser: function( name, parser ) {
- this.parsers[name] = parser;
- },
- // The next 3 are exposed so you can use them
- quote: quote,
- literal: literal,
- join: join,
- //
- _depth_: 1,
- // This is the list of parsers, to modify them, use jsDump.setParser
- parsers: {
- window: "[Window]",
- document: "[Document]",
- error: function(error) {
- return "Error(\"" + error.message + "\")";
- },
- unknown: "[Unknown]",
- "null": "null",
- "undefined": "undefined",
- "function": function( fn ) {
- var ret = "function",
- // functions never have name in IE
- name = "name" in fn ? fn.name : (reName.exec(fn) || [])[1];
-
- if ( name ) {
- ret += " " + name;
- }
- ret += "( ";
-
- ret = [ ret, QUnit.jsDump.parse( fn, "functionArgs" ), "){" ].join( "" );
- return join( ret, QUnit.jsDump.parse(fn,"functionCode" ), "}" );
- },
- array: array,
- nodelist: array,
- "arguments": array,
- object: function( map, stack ) {
- var ret = [ ], keys, key, val, i;
- QUnit.jsDump.up();
- keys = [];
- for ( key in map ) {
- keys.push( key );
- }
- keys.sort();
- for ( i = 0; i < keys.length; i++ ) {
- key = keys[ i ];
- val = map[ key ];
- ret.push( QUnit.jsDump.parse( key, "key" ) + ": " + QUnit.jsDump.parse( val, undefined, stack ) );
- }
- QUnit.jsDump.down();
- return join( "{", ret, "}" );
- },
- node: function( node ) {
- var len, i, val,
- open = QUnit.jsDump.HTML ? "<" : "<",
- close = QUnit.jsDump.HTML ? ">" : ">",
- tag = node.nodeName.toLowerCase(),
- ret = open + tag,
- attrs = node.attributes;
-
- if ( attrs ) {
- for ( i = 0, len = attrs.length; i < len; i++ ) {
- val = attrs[i].nodeValue;
- // IE6 includes all attributes in .attributes, even ones not explicitly set.
- // Those have values like undefined, null, 0, false, "" or "inherit".
- if ( val && val !== "inherit" ) {
- ret += " " + attrs[i].nodeName + "=" + QUnit.jsDump.parse( val, "attribute" );
- }
- }
- }
- ret += close;
-
- // Show content of TextNode or CDATASection
- if ( node.nodeType === 3 || node.nodeType === 4 ) {
- ret += node.nodeValue;
- }
-
- return ret + open + "/" + tag + close;
- },
- // function calls it internally, it's the arguments part of the function
- functionArgs: function( fn ) {
- var args,
- l = fn.length;
-
- if ( !l ) {
- return "";
- }
-
- args = new Array(l);
- while ( l-- ) {
- // 97 is 'a'
- args[l] = String.fromCharCode(97+l);
- }
- return " " + args.join( ", " ) + " ";
- },
- // object calls it internally, the key part of an item in a map
- key: quote,
- // function calls it internally, it's the content of the function
- functionCode: "[code]",
- // node calls it internally, it's an html attribute value
- attribute: quote,
- string: quote,
- date: quote,
- regexp: literal,
- number: literal,
- "boolean": literal
- },
- // if true, entities are escaped ( <, >, \t, space and \n )
- HTML: false,
- // indentation unit
- indentChar: " ",
- // if true, items in a collection, are separated by a \n, else just a space.
- multiline: true
- };
-
- return jsDump;
-}());
-
-// from jquery.js
-function inArray( elem, array ) {
- if ( array.indexOf ) {
- return array.indexOf( elem );
- }
-
- for ( var i = 0, length = array.length; i < length; i++ ) {
- if ( array[ i ] === elem ) {
- return i;
- }
- }
-
- return -1;
-}
-
-/*
- * Javascript Diff Algorithm
- * By John Resig (http://ejohn.org/)
- * Modified by Chu Alan "sprite"
- *
- * Released under the MIT license.
- *
- * More Info:
- * http://ejohn.org/projects/javascript-diff-algorithm/
- *
- * Usage: QUnit.diff(expected, actual)
- *
- * QUnit.diff( "the quick brown fox jumped over", "the quick fox jumps over" ) == "the quick brown fox jumped jumps over"
- */
-QUnit.diff = (function() {
- /*jshint eqeqeq:false, eqnull:true */
- function diff( o, n ) {
- var i,
- ns = {},
- os = {};
-
- for ( i = 0; i < n.length; i++ ) {
- if ( !hasOwn.call( ns, n[i] ) ) {
- ns[ n[i] ] = {
- rows: [],
- o: null
- };
- }
- ns[ n[i] ].rows.push( i );
- }
-
- for ( i = 0; i < o.length; i++ ) {
- if ( !hasOwn.call( os, o[i] ) ) {
- os[ o[i] ] = {
- rows: [],
- n: null
- };
- }
- os[ o[i] ].rows.push( i );
- }
-
- for ( i in ns ) {
- if ( !hasOwn.call( ns, i ) ) {
- continue;
- }
- if ( ns[i].rows.length === 1 && hasOwn.call( os, i ) && os[i].rows.length === 1 ) {
- n[ ns[i].rows[0] ] = {
- text: n[ ns[i].rows[0] ],
- row: os[i].rows[0]
- };
- o[ os[i].rows[0] ] = {
- text: o[ os[i].rows[0] ],
- row: ns[i].rows[0]
- };
- }
- }
-
- for ( i = 0; i < n.length - 1; i++ ) {
- if ( n[i].text != null && n[ i + 1 ].text == null && n[i].row + 1 < o.length && o[ n[i].row + 1 ].text == null &&
- n[ i + 1 ] == o[ n[i].row + 1 ] ) {
-
- n[ i + 1 ] = {
- text: n[ i + 1 ],
- row: n[i].row + 1
- };
- o[ n[i].row + 1 ] = {
- text: o[ n[i].row + 1 ],
- row: i + 1
- };
- }
- }
-
- for ( i = n.length - 1; i > 0; i-- ) {
- if ( n[i].text != null && n[ i - 1 ].text == null && n[i].row > 0 && o[ n[i].row - 1 ].text == null &&
- n[ i - 1 ] == o[ n[i].row - 1 ]) {
-
- n[ i - 1 ] = {
- text: n[ i - 1 ],
- row: n[i].row - 1
- };
- o[ n[i].row - 1 ] = {
- text: o[ n[i].row - 1 ],
- row: i - 1
- };
- }
- }
-
- return {
- o: o,
- n: n
- };
- }
-
- return function( o, n ) {
- o = o.replace( /\s+$/, "" );
- n = n.replace( /\s+$/, "" );
-
- var i, pre,
- str = "",
- out = diff( o === "" ? [] : o.split(/\s+/), n === "" ? [] : n.split(/\s+/) ),
- oSpace = o.match(/\s+/g),
- nSpace = n.match(/\s+/g);
-
- if ( oSpace == null ) {
- oSpace = [ " " ];
- }
- else {
- oSpace.push( " " );
- }
-
- if ( nSpace == null ) {
- nSpace = [ " " ];
- }
- else {
- nSpace.push( " " );
- }
-
- if ( out.n.length === 0 ) {
- for ( i = 0; i < out.o.length; i++ ) {
- str += "" + out.o[i] + oSpace[i] + "";
- }
- }
- else {
- if ( out.n[0].text == null ) {
- for ( n = 0; n < out.o.length && out.o[n].text == null; n++ ) {
- str += "" + out.o[n] + oSpace[n] + "";
- }
- }
-
- for ( i = 0; i < out.n.length; i++ ) {
- if (out.n[i].text == null) {
- str += "" + out.n[i] + nSpace[i] + "";
- }
- else {
- // `pre` initialized at top of scope
- pre = "";
-
- for ( n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++ ) {
- pre += "" + out.o[n] + oSpace[n] + "";
- }
- str += " " + out.n[i].text + nSpace[i] + pre;
- }
- }
- }
-
- return str;
- };
-}());
-
-// for CommonJS enviroments, export everything
-if ( typeof exports !== "undefined" ) {
- extend( exports, QUnit );
-}
-
-// get at whatever the global object is, like window in browsers
-}( (function() {return this;}.call()) ));
diff --git a/test/lib/require.js b/test/lib/require.js
deleted file mode 100644
index 987f865..0000000
--- a/test/lib/require.js
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- RequireJS 2.1.5 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.
- Available via the MIT or new BSD license.
- see: http://github.com/jrburke/requirejs for details
-*/
-var requirejs,require,define;
-(function(aa){function I(b){return"[object Function]"===L.call(b)}function J(b){return"[object Array]"===L.call(b)}function y(b,c){if(b){var d;for(d=0;dthis.depCount&&!this.defined){if(I(n)){if(this.events.error)try{e=i.execCb(c,n,b,e)}catch(d){a=d}else e=i.execCb(c,n,b,e);this.map.isDefine&&((b=this.module)&&void 0!==b.exports&&b.exports!==this.exports?e=b.exports:void 0===e&&this.usingExports&&(e=this.exports));if(a)return a.requireMap=this.map,a.requireModules=[this.map.id],a.requireType="define",v(this.error=
-a)}else e=n;this.exports=e;if(this.map.isDefine&&!this.ignore&&(q[c]=e,l.onResourceLoad))l.onResourceLoad(i,this.map,this.depMaps);x(c);this.defined=!0}this.defining=!1;this.defined&&!this.defineEmitted&&(this.defineEmitted=!0,this.emit("defined",this.exports),this.defineEmitComplete=!0)}}else this.fetch()}},callPlugin:function(){var a=this.map,b=a.id,d=j(a.prefix);this.depMaps.push(d);t(d,"defined",u(this,function(e){var n,d;d=this.map.name;var g=this.map.parentMap?this.map.parentMap.name:null,h=
-i.makeRequire(a.parentMap,{enableBuildCallback:!0});if(this.map.unnormalized){if(e.normalize&&(d=e.normalize(d,function(a){return c(a,g,!0)})||""),e=j(a.prefix+"!"+d,this.map.parentMap),t(e,"defined",u(this,function(a){this.init([],function(){return a},null,{enabled:!0,ignore:!0})})),d=m(p,e.id)){this.depMaps.push(e);if(this.events.error)d.on("error",u(this,function(a){this.emit("error",a)}));d.enable()}}else n=u(this,function(a){this.init([],function(){return a},null,{enabled:!0})}),n.error=u(this,
-function(a){this.inited=!0;this.error=a;a.requireModules=[b];G(p,function(a){0===a.map.id.indexOf(b+"_unnormalized")&&x(a.map.id)});v(a)}),n.fromText=u(this,function(e,c){var d=a.name,g=j(d),C=O;c&&(e=c);C&&(O=!1);r(g);s(k.config,b)&&(k.config[d]=k.config[b]);try{l.exec(e)}catch(ca){return v(B("fromtexteval","fromText eval for "+b+" failed: "+ca,ca,[b]))}C&&(O=!0);this.depMaps.push(g);i.completeLoad(d);h([d],n)}),e.load(a.name,h,n,k)}));i.enable(d,this);this.pluginMaps[d.id]=d},enable:function(){V[this.map.id]=
-this;this.enabling=this.enabled=!0;y(this.depMaps,u(this,function(a,b){var c,e;if("string"===typeof a){a=j(a,this.map.isDefine?this.map:this.map.parentMap,!1,!this.skipMap);this.depMaps[b]=a;if(c=m(N,a.id)){this.depExports[b]=c(this);return}this.depCount+=1;t(a,"defined",u(this,function(a){this.defineDep(b,a);this.check()}));this.errback&&t(a,"error",this.errback)}c=a.id;e=p[c];!s(N,c)&&(e&&!e.enabled)&&i.enable(a,this)}));G(this.pluginMaps,u(this,function(a){var b=m(p,a.id);b&&!b.enabled&&i.enable(a,
-this)}));this.enabling=!1;this.check()},on:function(a,b){var c=this.events[a];c||(c=this.events[a]=[]);c.push(b)},emit:function(a,b){y(this.events[a],function(a){a(b)});"error"===a&&delete this.events[a]}};i={config:k,contextName:b,registry:p,defined:q,urlFetched:U,defQueue:H,Module:Z,makeModuleMap:j,nextTick:l.nextTick,onError:v,configure:function(a){a.baseUrl&&"/"!==a.baseUrl.charAt(a.baseUrl.length-1)&&(a.baseUrl+="/");var b=k.pkgs,c=k.shim,e={paths:!0,config:!0,map:!0};G(a,function(a,b){e[b]?
-"map"===b?(k.map||(k.map={}),R(k[b],a,!0,!0)):R(k[b],a,!0):k[b]=a});a.shim&&(G(a.shim,function(a,b){J(a)&&(a={deps:a});if((a.exports||a.init)&&!a.exportsFn)a.exportsFn=i.makeShimExports(a);c[b]=a}),k.shim=c);a.packages&&(y(a.packages,function(a){a="string"===typeof a?{name:a}:a;b[a.name]={name:a.name,location:a.location||a.name,main:(a.main||"main").replace(ja,"").replace(ea,"")}}),k.pkgs=b);G(p,function(a,b){!a.inited&&!a.map.unnormalized&&(a.map=j(b))});if(a.deps||a.callback)i.require(a.deps||[],
-a.callback)},makeShimExports:function(a){return function(){var b;a.init&&(b=a.init.apply(aa,arguments));return b||a.exports&&ba(a.exports)}},makeRequire:function(a,f){function d(e,c,h){var g,k;f.enableBuildCallback&&(c&&I(c))&&(c.__requireJsBuild=!0);if("string"===typeof e){if(I(c))return v(B("requireargs","Invalid require call"),h);if(a&&s(N,e))return N[e](p[a.id]);if(l.get)return l.get(i,e,a,d);g=j(e,a,!1,!0);g=g.id;return!s(q,g)?v(B("notloaded",'Module name "'+g+'" has not been loaded yet for context: '+
-b+(a?"":". Use require([])"))):q[g]}L();i.nextTick(function(){L();k=r(j(null,a));k.skipMap=f.skipMap;k.init(e,c,h,{enabled:!0});D()});return d}f=f||{};R(d,{isBrowser:A,toUrl:function(b){var d,f=b.lastIndexOf("."),g=b.split("/")[0];if(-1!==f&&(!("."===g||".."===g)||1h.attachEvent.toString().indexOf("[native code"))&&!Y?(O=!0,h.attachEvent("onreadystatechange",b.onScriptLoad)):(h.addEventListener("load",b.onScriptLoad,!1),h.addEventListener("error",b.onScriptError,!1)),h.src=d,K=h,D?x.insertBefore(h,D):x.appendChild(h),K=null,h;if(da)try{importScripts(d),b.completeLoad(c)}catch(j){b.onError(B("importscripts","importScripts failed for "+c+" at "+d,j,[c]))}};A&&M(document.getElementsByTagName("script"),function(b){x||(x=
-b.parentNode);if(t=b.getAttribute("data-main"))return r.baseUrl||(E=t.split("/"),Q=E.pop(),fa=E.length?E.join("/")+"/":"./",r.baseUrl=fa,t=Q),t=t.replace(ea,""),r.deps=r.deps?r.deps.concat(t):[t],!0});define=function(b,c,d){var l,h;"string"!==typeof b&&(d=c,c=b,b=null);J(c)||(d=c,c=[]);!c.length&&I(d)&&d.length&&(d.toString().replace(la,"").replace(ma,function(b,d){c.push(d)}),c=(1===d.length?["require"]:["require","exports","module"]).concat(c));if(O){if(!(l=K))P&&"interactive"===P.readyState||M(document.getElementsByTagName("script"),
-function(b){if("interactive"===b.readyState)return P=b}),l=P;l&&(b||(b=l.getAttribute("data-requiremodule")),h=F[l.getAttribute("data-requirecontext")])}(h?h.defQueue:T).push([b,c,d])};define.amd={jQuery:!0};l.exec=function(b){return eval(b)};l(r)}})(this);
diff --git a/test/lib/resemble.js b/test/lib/resemble.js
new file mode 100644
index 0000000..1cb8c29
--- /dev/null
+++ b/test/lib/resemble.js
@@ -0,0 +1,535 @@
+/*
+Author: James Cryer
+Company: Huddle
+Last updated date: 21 Feb 2013
+URL: https://github.com/Huddle/Resemble.js
+*/
+
+(function(_this){
+ 'use strict';
+
+ _this['resemble'] = function( fileData ){
+
+ var data = {};
+ var images = [];
+ var updateCallbackArray = [];
+
+ var tolerance = { // between 0 and 255
+ red: 16,
+ green: 16,
+ blue: 16,
+ minBrightness: 16,
+ maxBrightness: 240
+ };
+
+ var ignoreAntialiasing = false;
+ var ignoreColors = false;
+
+ function triggerDataUpdate(){
+ var len = updateCallbackArray.length;
+ var i;
+ for(i=0;i tolerance.maxBrightness;
+ }
+
+ function getHue(r,g,b){
+
+ r = r / 255;
+ g = g / 255;
+ b = b / 255;
+ var max = Math.max(r, g, b), min = Math.min(r, g, b);
+ var h;
+ var d;
+
+ if (max == min){
+ h = 0; // achromatic
+ } else{
+ d = max - min;
+ switch(max){
+ case r: h = (g - b) / d + (g < b ? 6 : 0); break;
+ case g: h = (b - r) / d + 2; break;
+ case b: h = (r - g) / d + 4; break;
+ }
+ h /= 6;
+ }
+
+ return h;
+ }
+
+ function isAntialiased(sourcePix, data, cacheSet, verticalPos, horizontalPos, width){
+ var offset;
+ var targetPix;
+ var distance = 1;
+ var i;
+ var j;
+ var hasHighContrastSibling = 0;
+ var hasSiblingWithDifferentHue = 0;
+ var hasEquivilantSibling = 0;
+
+ addHueInfo(sourcePix);
+
+ for (i = distance*-1; i <= distance; i++){
+ for (j = distance*-1; j <= distance; j++){
+
+ if(i===0 && j===0){
+ // ignore source pixel
+ } else {
+
+ offset = ((verticalPos+j)*width + (horizontalPos+i)) * 4;
+ targetPix = getPixelInfo(data, offset, cacheSet);
+
+ if(targetPix === null){
+ continue;
+ }
+
+ addBrightnessInfo(targetPix);
+ addHueInfo(targetPix);
+
+ if( isContrasting(sourcePix, targetPix) ){
+ hasHighContrastSibling++;
+ }
+
+ if( isRGBSame(sourcePix,targetPix) ){
+ hasEquivilantSibling++;
+ }
+
+ if( Math.abs(targetPix.h - sourcePix.h) > 0.3 ){
+ hasSiblingWithDifferentHue++;
+ }
+
+ if( hasSiblingWithDifferentHue > 1 || hasHighContrastSibling > 1){
+ return true;
+ }
+ }
+ }
+ }
+
+ if(hasEquivilantSibling < 2){
+ return true;
+ }
+
+ return false;
+ }
+
+ function errorPixel(px, offset){
+ px[offset] = 255; //r
+ px[offset + 1] = 0; //g
+ px[offset + 2] = 255; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyPixel(px, offset, data){
+ px[offset] = data.r; //r
+ px[offset + 1] = data.g; //g
+ px[offset + 2] = data.b; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyGrayScalePixel(px, offset, data){
+ px[offset] = data.brightness; //r
+ px[offset + 1] = data.brightness; //g
+ px[offset + 2] = data.brightness; //b
+ px[offset + 3] = 255; //a
+ }
+
+
+ function getPixelInfo(data, offset, cacheSet){
+ var r;
+ var g;
+ var b;
+ var d;
+
+ if(typeof data[offset] !== 'undefined'){
+ r = data[offset];
+ g = data[offset+1];
+ b = data[offset+2];
+ d = {
+ r: r,
+ g: g,
+ b: b
+ };
+
+ return d;
+ } else {
+ return null;
+ }
+ }
+
+ function addBrightnessInfo(data){
+ data.brightness = getBrightness(data.r,data.g,data.b); // 'corrected' lightness
+ }
+
+ function addHueInfo(data){
+ data.h = getHue(data.r,data.g,data.b);
+ }
+
+ function analyseImages(img1, img2, width, height){
+
+ var hiddenCanvas = document.createElement('canvas');
+
+ var data1 = img1.data;
+ var data2 = img2.data;
+
+ hiddenCanvas.width = width;
+ hiddenCanvas.height = height;
+
+ var context = hiddenCanvas.getContext('2d');
+ var imgd = context.createImageData(width,height);
+ var targetPix = imgd.data;
+
+ var mismatchCount = 0;
+
+ var time = Date.now();
+
+ var skip;
+
+ if( (width > 1200 || height > 1200) && ignoreAntialiasing){
+ skip = 6;
+ }
+
+ loop(height, width, function(verticalPos, horizontalPos){
+
+ if(skip){ // only skip if the image isn't small
+ if(verticalPos % skip === 0 || horizontalPos % skip === 0){
+ return;
+ }
+ }
+
+ var offset = (verticalPos*width + horizontalPos) * 4;
+ var pixel1 = getPixelInfo(data1, offset, 1);
+ var pixel2 = getPixelInfo(data2, offset, 2);
+
+ if(pixel1 === null || pixel2 === null){
+ return;
+ }
+
+ if (ignoreColors){
+
+ addBrightnessInfo(pixel1);
+ addBrightnessInfo(pixel2);
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ return;
+ }
+
+ if( isRGBSimilar(pixel1, pixel2) ){
+ copyPixel(targetPix, offset, pixel2);
+
+ } else if( ignoreAntialiasing && (
+ addBrightnessInfo(pixel1), // jit pixel info augmentation looks a little weird, sorry.
+ addBrightnessInfo(pixel2),
+ isAntialiased(pixel1, data1, 1, verticalPos, horizontalPos, width) ||
+ isAntialiased(pixel2, data2, 2, verticalPos, horizontalPos, width)
+ )){
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+
+ });
+
+ data.misMatchPercentage = (mismatchCount / (height*width) * 100).toFixed(2);
+ data.analysisTime = Date.now() - time;
+
+ data.getImageDataUrl = function(text){
+ var barHeight = 0;
+
+ if(text){
+ barHeight = addLabel(text,context,hiddenCanvas);
+ }
+
+ context.putImageData(imgd, 0, barHeight);
+
+ return hiddenCanvas.toDataURL("image/png");
+ };
+ }
+
+ function addLabel(text, context, hiddenCanvas){
+ var textPadding = 2;
+
+ context.font = '12px sans-serif';
+
+ var textWidth = context.measureText(text).width + textPadding*2;
+ var barHeight = 22;
+
+ if(textWidth > hiddenCanvas.width){
+ hiddenCanvas.width = textWidth;
+ }
+
+ hiddenCanvas.height += barHeight;
+
+ context.fillStyle = "#666";
+ context.fillRect(0,0,hiddenCanvas.width,barHeight -4);
+ context.fillStyle = "#fff";
+ context.fillRect(0,barHeight -4,hiddenCanvas.width, 4);
+
+ context.fillStyle = "#fff";
+ context.textBaseline = "top";
+ context.font = '12px sans-serif';
+ context.fillText(text, textPadding, 1);
+
+ return barHeight;
+ }
+
+ function normalise(img, w, h){
+ var c;
+ var context;
+
+ if(img.height < h || img.width < w){
+ c = document.createElement('canvas');
+ c.width = w;
+ c.height = h;
+ context = c.getContext('2d');
+ context.putImageData(img, 0, 0);
+ return context.getImageData(0, 0, w, h);
+ }
+
+ return img;
+ }
+
+ function compare(one, two){
+
+ function onceWeHaveBoth(){
+ var width;
+ var height;
+ if(images.length === 2){
+ width = images[0].width > images[1].width ? images[0].width : images[1].width;
+ height = images[0].height > images[1].height ? images[0].height : images[1].height;
+
+ if( (images[0].width === images[1].width) && (images[0].height === images[1].height) ){
+ data.isSameDimensions = true;
+ } else {
+ data.isSameDimensions = false;
+ }
+
+ analyseImages( normalise(images[0],width, height), normalise(images[1],width, height), width, height);
+
+ triggerDataUpdate();
+ }
+ }
+
+ images = [];
+ loadImageData(one, onceWeHaveBoth);
+ loadImageData(two, onceWeHaveBoth);
+ }
+
+ function getCompareApi(param){
+
+ var secondFileData,
+ hasMethod = typeof param === 'function';
+
+ if( !hasMethod ){
+ // assume it's file data
+ secondFileData = param;
+ }
+
+ var self = {
+ ignoreNothing: function(){
+
+ tolerance.red = 16;
+ tolerance.green = 16;
+ tolerance.blue = 16;
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreAntialiasing: function(){
+
+ tolerance.red = 32;
+ tolerance.green = 32;
+ tolerance.blue = 32;
+ tolerance.minBrightness = 64;
+ tolerance.maxBrightness = 96;
+
+ ignoreAntialiasing = true;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreColors: function(){
+
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = true;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ onComplete: function( callback ){
+
+ updateCallbackArray.push(callback);
+
+ var wrapper = function(){
+ compare(fileData, secondFileData);
+ };
+
+ wrapper();
+
+ return getCompareApi(wrapper);
+ }
+ };
+
+ return self;
+ }
+
+ return {
+ onComplete: function( callback ){
+ updateCallbackArray.push(callback);
+ loadImageData(fileData, function(imageData, width, height){
+ parseImage(imageData.data, width, height);
+ });
+ },
+ compareTo: function(secondFileData){
+ return getCompareApi(secondFileData);
+ }
+ };
+
+ };
+}(this));
\ No newline at end of file
diff --git a/test/testsuite.js b/test/testsuite.js
deleted file mode 100644
index b486acb..0000000
--- a/test/testsuite.js
+++ /dev/null
@@ -1,36 +0,0 @@
-requirejs.config({
- baseUrl: '/test/unit/'
-});
-
-define(function(require) {
- var testModules = [
- 'Pixi',
- 'Point',
- 'Rectangle',
- 'DisplayObject',
- 'DisplayObjectContainer',
- 'Sprite',
- 'MovieClip',
- 'InteractionManager',
- 'Stage',
- 'utils/Utils',
- 'utils/EventTarget',
- 'utils/Matrix',
- 'utils/Detector',
- 'renderers/WebGLShaders',
- 'renderers/WebGLRenderer',
- 'renderers/WebGLBatch',
- 'renderers/CanvasRenderer',
- 'extras/Strip',
- 'extras/Rope',
- 'textures/BaseTexture',
- 'textures/Texture',
- 'loaders/SpriteSheetLoader',
- 'loaders/AssetLoader'
- ];
-
- // Resolve all testModules and then start the Test Runner.
- require(testModules, function() {
- QUnit.start();
- });
-});
\ No newline at end of file
diff --git a/test/textures/SpriteSheet-Aliens.png b/test/textures/SpriteSheet-Aliens.png
new file mode 100644
index 0000000..210acb1
--- /dev/null
+++ b/test/textures/SpriteSheet-Aliens.png
Binary files differ
diff --git a/test/textures/SpriteSheet-Explosion.png b/test/textures/SpriteSheet-Explosion.png
new file mode 100755
index 0000000..79e1a69
--- /dev/null
+++ b/test/textures/SpriteSheet-Explosion.png
Binary files differ
diff --git a/test/textures/bunny.png b/test/textures/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/textures/bunny.png
Binary files differ
diff --git a/test/unit/DisplayObject.js b/test/unit/DisplayObject.js
deleted file mode 100644
index 5e7e72f..0000000
--- a/test/unit/DisplayObject.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObject');
-});
diff --git a/test/unit/DisplayObjectContainer.js b/test/unit/DisplayObjectContainer.js
deleted file mode 100644
index b323959..0000000
--- a/test/unit/DisplayObjectContainer.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObjectContainer');
-});
diff --git a/test/unit/InteractionManager.js b/test/unit/InteractionManager.js
deleted file mode 100644
index e751f52..0000000
--- a/test/unit/InteractionManager.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('InteractionManager');
-});
diff --git a/test/unit/MovieClip.js b/test/unit/MovieClip.js
deleted file mode 100644
index 37d9446..0000000
--- a/test/unit/MovieClip.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('MovieClip');
-});
diff --git a/test/unit/Pixi.js b/test/unit/Pixi.js
deleted file mode 100644
index 36eee73..0000000
--- a/test/unit/Pixi.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Pixi');
-});
diff --git a/test/unit/Point.js b/test/unit/Point.js
deleted file mode 100644
index 983ff6e..0000000
--- a/test/unit/Point.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Point');
-});
diff --git a/test/unit/Rectangle.js b/test/unit/Rectangle.js
deleted file mode 100644
index 3b439ba..0000000
--- a/test/unit/Rectangle.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Rectangle');
-});
diff --git a/test/unit/Sprite.js b/test/unit/Sprite.js
deleted file mode 100644
index ed4f596..0000000
--- a/test/unit/Sprite.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Sprite');
-});
diff --git a/test/unit/Stage.js b/test/unit/Stage.js
deleted file mode 100644
index 2d70291..0000000
--- a/test/unit/Stage.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Stage');
-});
diff --git a/test/unit/extras/Rope.js b/test/unit/extras/Rope.js
deleted file mode 100644
index 5606f14..0000000
--- a/test/unit/extras/Rope.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Rope');
-});
diff --git a/test/unit/extras/Strip.js b/test/unit/extras/Strip.js
deleted file mode 100644
index 0134d3a..0000000
--- a/test/unit/extras/Strip.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Strip');
-});
diff --git a/test/unit/loaders/AssetLoader.js b/test/unit/loaders/AssetLoader.js
deleted file mode 100644
index 13b8443..0000000
--- a/test/unit/loaders/AssetLoader.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('AssetLoader');
-});
diff --git a/test/unit/loaders/SpriteSheetLoader.js b/test/unit/loaders/SpriteSheetLoader.js
deleted file mode 100644
index 8bf0cb2..0000000
--- a/test/unit/loaders/SpriteSheetLoader.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('SpriteSheetLoader');
-});
diff --git a/test/unit/pixi/InteractionManager.js b/test/unit/pixi/InteractionManager.js
new file mode 100644
index 0000000..ed3001f
--- /dev/null
+++ b/test/unit/pixi/InteractionManager.js
@@ -0,0 +1,10 @@
+describe('pixi/InteractionManager', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var InteractionManager = PIXI.InteractionManager;
+
+ it('Module exists', function () {
+ expect(InteractionManager).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/Pixi.js b/test/unit/pixi/Pixi.js
new file mode 100644
index 0000000..27debc1
--- /dev/null
+++ b/test/unit/pixi/Pixi.js
@@ -0,0 +1,9 @@
+describe('pixi/Pixi', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+
+ it('Module exists', function () {
+ expect(global).to.have.property('PIXI').and.to.be.an('object');
+ });
+});
diff --git a/test/unit/pixi/core/Circle.js b/test/unit/pixi/core/Circle.js
new file mode 100644
index 0000000..93a4456
--- /dev/null
+++ b/test/unit/pixi/core/Circle.js
@@ -0,0 +1,22 @@
+describe('pixi/core/Circle', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Circle = PIXI.Circle;
+
+ it('Module exists', function () {
+ expect(Circle).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Circle();
+
+ expect(obj).to.be.an.instanceof(Circle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', 0);
+ expect(obj).to.have.property('y', 0);
+ expect(obj).to.have.property('radius', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Ellipse.js b/test/unit/pixi/core/Ellipse.js
new file mode 100644
index 0000000..026b56f
--- /dev/null
+++ b/test/unit/pixi/core/Ellipse.js
@@ -0,0 +1,24 @@
+describe('pixi/core/Ellipse', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Ellipse = PIXI.Ellipse;
+
+ it('Module exists', function () {
+ expect(Ellipse).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Ellipse();
+
+ expect(obj).to.be.an.instanceof(Ellipse);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+ expect(obj).to.respondTo('getBounds');
+
+ expect(obj).to.have.property('x', 0);
+ expect(obj).to.have.property('y', 0);
+ expect(obj).to.have.property('width', 0);
+ expect(obj).to.have.property('height', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Matrix.js b/test/unit/pixi/core/Matrix.js
new file mode 100644
index 0000000..b48989e
--- /dev/null
+++ b/test/unit/pixi/core/Matrix.js
@@ -0,0 +1,30 @@
+describe('pixi/core/Matrix', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var mat3 = PIXI.mat3;
+ var mat4 = PIXI.mat4;
+ var Matrix = PIXI.Matrix;
+
+ it('Ensure determineMatrixArrayType works', function () {
+ expect(Matrix).to.be.a('function');
+ });
+
+ it('mat3 exists', function () {
+ expect(mat3).to.be.an('object');
+ });
+
+ it('Confirm new mat3 matrix', function () {
+ var matrix = new mat3.create();
+ pixi_core_Matrix_confirmNewMat3(matrix);
+ });
+
+ it('mat3 exists', function () {
+ expect(mat4).to.be.an('object');
+ });
+
+ it('Confirm new mat4 matrix', function () {
+ var matrix = new mat4.create();
+ pixi_core_Matrix_confirmNewMat4(matrix);
+ });
+});
diff --git a/test/unit/pixi/core/Point.js b/test/unit/pixi/core/Point.js
new file mode 100644
index 0000000..c4d5163
--- /dev/null
+++ b/test/unit/pixi/core/Point.js
@@ -0,0 +1,15 @@
+describe('pixi/core/Point', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Point = PIXI.Point;
+
+ it('Module exists', function () {
+ expect(Point).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Point();
+ pixi_core_Point_confirm(obj, 0, 0);
+ });
+});
diff --git a/test/unit/pixi/core/Polygon.js b/test/unit/pixi/core/Polygon.js
new file mode 100644
index 0000000..dc8c918
--- /dev/null
+++ b/test/unit/pixi/core/Polygon.js
@@ -0,0 +1,20 @@
+describe('pixi/core/Polygon', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Polygon = PIXI.Polygon;
+
+ it('Module exists', function () {
+ expect(Polygon).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Polygon();
+
+ expect(obj).to.be.an.instanceof(Polygon);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.deep.property('points.length', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Rectangle.js b/test/unit/pixi/core/Rectangle.js
new file mode 100644
index 0000000..d43316e
--- /dev/null
+++ b/test/unit/pixi/core/Rectangle.js
@@ -0,0 +1,15 @@
+describe('pixi/core/Rectangle', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Rectangle = PIXI.Rectangle;
+
+ it('Module exists', function () {
+ expect(Rectangle).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var rect = new Rectangle();
+ pixi_core_Rectangle_confirm(rect, 0, 0, 0, 0);
+ });
+});
diff --git a/test/unit/pixi/display/DisplayObject.js b/test/unit/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..40c6fbc
--- /dev/null
+++ b/test/unit/pixi/display/DisplayObject.js
@@ -0,0 +1,21 @@
+describe('pixi/display/DisplayObject', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var DisplayObject = PIXI.DisplayObject;
+
+ it('Module exists', function () {
+ expect(DisplayObject).to.be.a('function');
+ expect(PIXI).to.have.property('visibleCount', 0);
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new DisplayObject();
+
+ pixi_display_DisplayObject_confirmNew(obj);
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', false);
+ expect(obj).to.have.property('stage', null);
+ });
+});
diff --git a/test/unit/pixi/display/DisplayObjectContainer.js b/test/unit/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..ce7f02f
--- /dev/null
+++ b/test/unit/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,20 @@
+describe('pixi/display/DisplayObjectContainer', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var DisplayObjectContainer = PIXI.DisplayObjectContainer;
+
+ it('Module exists', function () {
+ expect(DisplayObjectContainer).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new DisplayObjectContainer();
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', false);
+ expect(obj).to.have.property('stage', null);
+ });
+});
diff --git a/test/unit/pixi/display/MovieClip.js b/test/unit/pixi/display/MovieClip.js
new file mode 100644
index 0000000..f3c6c6a
--- /dev/null
+++ b/test/unit/pixi/display/MovieClip.js
@@ -0,0 +1,33 @@
+describe('pixi/display/MovieClip', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var MovieClip = PIXI.MovieClip;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(MovieClip).to.be.a('function');
+ });
+
+ it('Confirm new instance', function (done) {
+ var texture = Texture.fromImage('/base/test/textures/SpriteSheet-Explosion.png');
+ var obj = new MovieClip([texture]);
+
+ pixi_display_Sprite_confirmNew(obj, done);
+
+ expect(obj).to.be.an.instanceof(MovieClip);
+ expect(obj).to.respondTo('stop');
+ expect(obj).to.respondTo('play');
+ expect(obj).to.respondTo('gotoAndStop');
+ expect(obj).to.respondTo('gotoAndPlay');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('textures.length', 1);
+ expect(obj).to.have.deep.property('textures[0]', texture);
+ expect(obj).to.have.property('animationSpeed', 1);
+ expect(obj).to.have.property('loop', true);
+ expect(obj).to.have.property('onComplete', null);
+ expect(obj).to.have.property('currentFrame', 0);
+ expect(obj).to.have.property('playing', false);
+ });
+});
diff --git a/test/unit/pixi/display/Sprite.js b/test/unit/pixi/display/Sprite.js
new file mode 100644
index 0000000..54e914f
--- /dev/null
+++ b/test/unit/pixi/display/Sprite.js
@@ -0,0 +1,25 @@
+describe('pixi/display/Sprite', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Sprite = PIXI.Sprite;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(Sprite).to.be.a('function');
+ expect(PIXI).to.have.deep.property('blendModes.NORMAL', 0);
+ expect(PIXI).to.have.deep.property('blendModes.SCREEN', 1);
+ });
+
+ it('Members exist', function () {
+ expect(Sprite).itself.to.respondTo('fromImage');
+ expect(Sprite).itself.to.respondTo('fromFrame');
+ });
+
+ it('Confirm new instance', function (done) {
+ var texture = Texture.fromImage('/base/test/textures/SpriteSheet-Aliens.png');
+ var obj = new Sprite(texture);
+
+ pixi_display_Sprite_confirmNew(obj, done);
+ });
+});
diff --git a/test/unit/pixi/display/Stage.js b/test/unit/pixi/display/Stage.js
new file mode 100644
index 0000000..3cc2a4d
--- /dev/null
+++ b/test/unit/pixi/display/Stage.js
@@ -0,0 +1,49 @@
+describe('pixi/display/Stage', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Stage = PIXI.Stage;
+ var InteractionManager = PIXI.InteractionManager;
+ var Rectangle = PIXI.Rectangle;
+
+ it('Module exists', function () {
+ expect(Stage).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Stage(null, true);
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(Stage);
+ expect(obj).to.respondTo('updateTransform');
+ expect(obj).to.respondTo('setBackgroundColor');
+ expect(obj).to.respondTo('getMousePosition');
+
+ // FIXME: duplicate member in DisplayObject
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ // FIXME: convert arg to bool in constructor
+ expect(obj).to.have.property('interactive', true);
+
+ expect(obj).to.have.property('interactionManager')
+ .and.to.be.an.instanceof(InteractionManager)
+ .and.to.have.property('stage', obj);
+
+ expect(obj).to.have.property('dirty', true);
+
+ expect(obj).to.have.property('stage', obj);
+
+ expect(obj).to.have.property('hitArea')
+ .and.to.be.an.instanceof(Rectangle);
+ pixi_core_Rectangle_confirm(obj.hitArea, 0, 0, 100000, 100000);
+
+ expect(obj).to.have.property('backgroundColor', 0x000000);
+ expect(obj).to.have.deep.property('backgroundColorSplit.length', 3);
+ expect(obj).to.have.deep.property('backgroundColorSplit[0]', 0);
+ expect(obj).to.have.deep.property('backgroundColorSplit[1]', 0);
+ expect(obj).to.have.deep.property('backgroundColorSplit[2]', 0);
+ expect(obj).to.have.property('backgroundColorString', '#000000');
+
+ expect(obj).to.have.property('worldVisible', true);
+ });
+});
diff --git a/test/unit/pixi/extras/CustomRenderable.js b/test/unit/pixi/extras/CustomRenderable.js
new file mode 100644
index 0000000..8d83cf0
--- /dev/null
+++ b/test/unit/pixi/extras/CustomRenderable.js
@@ -0,0 +1,21 @@
+describe('pixi/extras/CustomRenderable', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var CustomRenderable = PIXI.CustomRenderable;
+
+ it('Module exists', function () {
+ expect(CustomRenderable).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new CustomRenderable();
+
+ pixi_display_DisplayObject_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(CustomRenderable);
+ expect(obj).to.respondTo('renderCanvas');
+ expect(obj).to.respondTo('initWebGL');
+ expect(obj).to.respondTo('renderWebGL');
+ });
+});
diff --git a/test/unit/pixi/extras/Rope.js b/test/unit/pixi/extras/Rope.js
new file mode 100644
index 0000000..6ddaf83
--- /dev/null
+++ b/test/unit/pixi/extras/Rope.js
@@ -0,0 +1,26 @@
+describe('pixi/extras/Rope', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Rope = PIXI.Rope;
+ var Texture = PIXI.Texture;
+ var Point = PIXI.Point;
+
+ it('Module exists', function () {
+ expect(Rope).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var texture = Texture.fromImage('/base/test/textures/bunny.png');
+ var obj = new Rope(texture, [new Point(), new Point(5, 10), new Point(10, 20)]);
+
+ pixi_extras_Strip_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(Rope);
+ expect(obj).to.respondTo('refresh');
+ expect(obj).to.respondTo('updateTransform');
+ expect(obj).to.respondTo('setTexture');
+
+ // TODO: Test properties
+ });
+});
diff --git a/test/unit/pixi/extras/Spine.js b/test/unit/pixi/extras/Spine.js
new file mode 100644
index 0000000..0708bc0
--- /dev/null
+++ b/test/unit/pixi/extras/Spine.js
@@ -0,0 +1,10 @@
+describe('pixi/extras/Spine', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Spine = PIXI.Spine;
+
+ it('Module exists', function () {
+ expect(Spine).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/extras/Strip.js b/test/unit/pixi/extras/Strip.js
new file mode 100644
index 0000000..8e564e1
--- /dev/null
+++ b/test/unit/pixi/extras/Strip.js
@@ -0,0 +1,18 @@
+describe('pixi/extras/Strip', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Strip = PIXI.Strip;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(Strip).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var texture = Texture.fromImage('/base/test/textures/bunny.png');
+ var obj = new Strip(texture, 20, 10000);
+
+ pixi_extras_Strip_confirmNew(obj);
+ });
+});
diff --git a/test/unit/pixi/extras/TilingSprite.js b/test/unit/pixi/extras/TilingSprite.js
new file mode 100644
index 0000000..56aea14
--- /dev/null
+++ b/test/unit/pixi/extras/TilingSprite.js
@@ -0,0 +1,24 @@
+describe('pixi/extras/TilingSprite', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var TilingSprite = PIXI.TilingSprite;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(TilingSprite).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var texture = Texture.fromImage('/base/test/textures/bunny.png');
+ var obj = new TilingSprite(texture, 6000, 12000);
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(TilingSprite);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ // TODO: Test properties
+ });
+});
diff --git a/test/unit/pixi/filters/FilterBlock.js b/test/unit/pixi/filters/FilterBlock.js
new file mode 100644
index 0000000..870cec0
--- /dev/null
+++ b/test/unit/pixi/filters/FilterBlock.js
@@ -0,0 +1,10 @@
+describe('pixi/filters/FilterBlock', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var FilterBlock = PIXI.FilterBlock;
+
+ it('Module exists', function () {
+ expect(FilterBlock).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/filters/MaskFilter.js b/test/unit/pixi/filters/MaskFilter.js
new file mode 100644
index 0000000..32d6a45
--- /dev/null
+++ b/test/unit/pixi/filters/MaskFilter.js
@@ -0,0 +1,10 @@
+describe('pixi/filters/MaskFilter', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ // var MaskFilter = PIXI.MaskFilter;
+
+ // it('Module exists', function () {
+ // expect(MaskFilter).to.be.a('function');
+ // });
+});
diff --git a/test/unit/pixi/loaders/AssetLoader.js b/test/unit/pixi/loaders/AssetLoader.js
new file mode 100644
index 0000000..a0aa0b5
--- /dev/null
+++ b/test/unit/pixi/loaders/AssetLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/AssetLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var AssetLoader = PIXI.AssetLoader;
+
+ it('Module exists', function () {
+ expect(AssetLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/BitmapFontLoader.js b/test/unit/pixi/loaders/BitmapFontLoader.js
new file mode 100644
index 0000000..6253c42
--- /dev/null
+++ b/test/unit/pixi/loaders/BitmapFontLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/BitmapFontLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var BitmapFontLoader = PIXI.BitmapFontLoader;
+
+ it('Module exists', function () {
+ expect(PIXI.BitmapFontLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/ImageLoader.js b/test/unit/pixi/loaders/ImageLoader.js
new file mode 100644
index 0000000..8b1f556
--- /dev/null
+++ b/test/unit/pixi/loaders/ImageLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/ImageLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var ImageLoader = PIXI.ImageLoader;
+
+ it('Module exists', function () {
+ expect(ImageLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/JsonLoader.js b/test/unit/pixi/loaders/JsonLoader.js
new file mode 100644
index 0000000..c577e83
--- /dev/null
+++ b/test/unit/pixi/loaders/JsonLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/JsonLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var JsonLoader = PIXI.JsonLoader;
+
+ it('Module exists', function () {
+ expect(JsonLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/SpineLoader.js b/test/unit/pixi/loaders/SpineLoader.js
new file mode 100644
index 0000000..fdcc0b8
--- /dev/null
+++ b/test/unit/pixi/loaders/SpineLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/SpineLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var SpineLoader = PIXI.SpineLoader;
+
+ it('Module exists', function () {
+ expect(SpineLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/SpriteSheetLoader.js b/test/unit/pixi/loaders/SpriteSheetLoader.js
new file mode 100644
index 0000000..57beb27
--- /dev/null
+++ b/test/unit/pixi/loaders/SpriteSheetLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/SpriteSheetLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var SpriteSheetLoader = PIXI.SpriteSheetLoader;
+
+ it('Module exists', function () {
+ expect(SpriteSheetLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/primitives/Graphics.js b/test/unit/pixi/primitives/Graphics.js
new file mode 100644
index 0000000..b8b3e5c
--- /dev/null
+++ b/test/unit/pixi/primitives/Graphics.js
@@ -0,0 +1,40 @@
+describe('pixi/primitives/Graphics', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Graphics = PIXI.Graphics;
+
+ it('Module exists', function () {
+ expect(Graphics).to.be.a('function');
+
+ expect(Graphics).itself.to.have.property('POLY', 0);
+ expect(Graphics).itself.to.have.property('RECT', 1);
+ expect(Graphics).itself.to.have.property('CIRC', 2);
+ expect(Graphics).itself.to.have.property('ELIP', 3);
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Graphics();
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(Graphics);
+ expect(obj).to.respondTo('lineStyle');
+ expect(obj).to.respondTo('lineStyle');
+ expect(obj).to.respondTo('moveTo');
+ expect(obj).to.respondTo('lineTo');
+ expect(obj).to.respondTo('beginFill');
+ expect(obj).to.respondTo('endFill');
+ expect(obj).to.respondTo('drawRect');
+ expect(obj).to.respondTo('drawCircle');
+ expect(obj).to.respondTo('drawElipse');
+ expect(obj).to.respondTo('clear');
+
+ expect(obj).to.have.property('renderable', true);
+ expect(obj).to.have.property('fillAlpha', 1);
+ expect(obj).to.have.property('lineWidth', 0);
+ expect(obj).to.have.property('lineColor', 'black');
+ expect(obj).to.have.deep.property('graphicsData.length', 0);
+ expect(obj).to.have.deep.property('currentPath.points.length', 0);
+ });
+});
diff --git a/.gitignore b/.gitignore
index 12e1b62..0b88317 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
node_modules
.DS_Store
-.project
\ No newline at end of file
+.project
+*.log
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..63e4d7c
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,8 @@
+language: node_js
+node_js:
+ - 0.10
+
+before_script:
+ - npm install -g grunt-cli
+ - export DISPLAY=:99.0
+ - sh -e /etc/init.d/xvfb start
diff --git a/Gruntfile.js b/Gruntfile.js
index b083b49..103938c 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -1,10 +1,12 @@
+'use strict';
+
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-connect');
- grunt.loadNpmTasks('grunt-contrib-qunit');
grunt.loadNpmTasks('grunt-contrib-yuidoc');
+ grunt.loadTasks('tasks');
var root = 'src/pixi/',
debug = 'bin/pixi.dev.js',
@@ -79,7 +81,7 @@
},
files: {
srcBlob: '<%= dirs.src %>/**/*.js',
- testBlob: '<%= dirs.test %>/unit/**/*.js',
+ testBlob: '<%= dirs.test %>/{functional,lib/pixi,unit}/**/*.js',
build: '<%= dirs.build %>/pixi.dev.js',
buildMin: '<%= dirs.build %>/pixi.js'
},
@@ -94,7 +96,12 @@
},
jshint: {
beforeconcat: srcFiles,
- test: ['<%= files.testBlob %>'],
+ test: {
+ src: ['<%= files.testBlob %>'],
+ options: {
+ expr: true
+ }
+ },
options: {
asi: true,
smarttabs: true
@@ -128,12 +135,6 @@
]
},
connect: {
- qunit: {
- options: {
- port: grunt.option('port-test') || 9002,
- base: './'
- }
- },
test: {
options: {
port: grunt.option('port-test') || 9002,
@@ -142,13 +143,6 @@
}
}
},
- qunit: {
- all: {
- options: {
- urls: ['http://localhost:' + (grunt.option('port-test') || 9002) + '/test/index.html']
- }
- }
- },
yuidoc: {
compile: {
name: '<%= pkg.name %>',
@@ -161,6 +155,13 @@
outdir: '<%= dirs.docs %>'
}
}
+ },
+ karma: {
+ unit: {
+ configFile: 'test/karma.conf.js',
+ // browsers: ['Chrome'],
+ singleRun: true
+ }
}
});
@@ -182,9 +183,10 @@
}
)
- grunt.registerTask('default', ['concat', 'uglify', 'distribute']);
grunt.registerTask('build', ['concat', 'uglify', 'distribute']);
- grunt.registerTask('test', ['build', 'connect:qunit', 'qunit']);
+ grunt.registerTask('test', ['concat', 'jshint:test', 'karma']);
grunt.registerTask('docs', ['yuidoc']);
-
-}
\ No newline at end of file
+ grunt.registerTask('default', ['test', 'uglify', 'distribute']);
+ // Travis CI task.
+ grunt.registerTask('travis', ['test']);
+}
diff --git a/README.md b/README.md
index c62ef86..690cfe4 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,8 @@

+[](http://travis-ci.org/drkibitz/pixi.js)
+
#### JavaScript 2D Renderer ####
The aim of this project is to provide a fast lightweight 2D library that works
diff --git a/package.json b/package.json
index b373240..1246a68 100644
--- a/package.json
+++ b/package.json
@@ -18,14 +18,21 @@
"main": "bin/pixi.js",
+ "scripts": {
+ "test": "grunt travis --verbose"
+ },
+
"dependencies": {},
"devDependencies": {
"grunt": "~0.4.x",
- "grunt-contrib-jshint": "0.3.x",
+ "grunt-contrib-jshint": "0.6.x",
"grunt-contrib-uglify": "0.2.x",
- "grunt-contrib-connect": "0.2.x",
- "grunt-contrib-qunit": "0.2.x",
+ "grunt-contrib-connect": "0.3.x",
"grunt-contrib-yuidoc": "0.4.x",
- "grunt-contrib-concat": "0.1.x"
+ "grunt-contrib-concat": "0.3.x",
+ "chai": "~1.7.0",
+ "karma": "0.11.0",
+ "karma-firefox-launcher": "0.1.0",
+ "karma-mocha": "0.1.0"
}
}
diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js
index a7c520e..ee82bbd 100644
--- a/src/pixi/InteractionManager.js
+++ b/src/pixi/InteractionManager.js
@@ -62,7 +62,6 @@
this.onTouchEnd = this.onTouchEnd.bind(this);
this.onTouchMove = this.onTouchMove.bind(this);
-
this.last = 0;
}
diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js
index 1a95d20..eef1059 100644
--- a/src/pixi/core/Ellipse.js
+++ b/src/pixi/core/Ellipse.js
@@ -78,7 +78,7 @@
return (normx + normy < 0.25);
}
-PIXI.Ellipse.getBounds = function()
+PIXI.Ellipse.prototype.getBounds = function()
{
return new PIXI.Rectangle(this.x, this.y, this.width, this.height);
}
diff --git a/tasks/karma.js b/tasks/karma.js
new file mode 100644
index 0000000..c340485
--- /dev/null
+++ b/tasks/karma.js
@@ -0,0 +1,27 @@
+'use strict';
+
+var path = require('path');
+var server = require('karma').server;
+
+module.exports = function (grunt) {
+ grunt.registerMultiTask('karma', 'run karma.', function() {
+ var done = this.async();
+ var options = this.options({
+ background: false
+ });
+ var data = this.data;
+
+ //merge options onto data, with data taking precedence
+ data = grunt.util._.merge(options, data);
+ data.configFile = path.resolve(data.configFile);
+ if (data.configFile) {
+ data.configFile = grunt.template.process(data.configFile);
+ }
+
+ server.start(
+ data,
+ function(code) {
+ done(!code);
+ });
+ });
+};
diff --git a/test/functional/example-1-basics/bunny.png b/test/functional/example-1-basics/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/functional/example-1-basics/bunny.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-30.png b/test/functional/example-1-basics/frame-30.png
new file mode 100644
index 0000000..96e3409
--- /dev/null
+++ b/test/functional/example-1-basics/frame-30.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-60.png b/test/functional/example-1-basics/frame-60.png
new file mode 100644
index 0000000..af3f4ce
--- /dev/null
+++ b/test/functional/example-1-basics/frame-60.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-90.png b/test/functional/example-1-basics/frame-90.png
new file mode 100644
index 0000000..099b823
--- /dev/null
+++ b/test/functional/example-1-basics/frame-90.png
Binary files differ
diff --git a/test/functional/example-1-basics/index.js b/test/functional/example-1-basics/index.js
new file mode 100644
index 0000000..7ae7a98
--- /dev/null
+++ b/test/functional/example-1-basics/index.js
@@ -0,0 +1,133 @@
+describe('Example 1 - Basics', function () {
+ 'use strict';
+
+ var baseUri = '/base/test/functional/example-1-basics';
+ var expect = chai.expect;
+ var currentFrame = 0;
+ var frameEvents = {};
+ var stage;
+ var renderer;
+ var bunny;
+
+ function onFrame(frame, callback) {
+ frameEvents[frame] = callback;
+ }
+
+ function animate() {
+ currentFrame += 1;
+
+ requestAnimFrame( animate );
+
+ // just for fun, lets rotate mr rabbit a little
+ bunny.rotation += 0.1;
+
+ // render the stage
+ renderer.render(stage);
+
+ if (frameEvents[currentFrame])
+ frameEvents[currentFrame](currentFrame);
+ }
+
+ function initScene() {
+ // create an new instance of a pixi stage
+ stage = new PIXI.Stage(0x66FF99);
+
+ // create a renderer instance
+ renderer = PIXI.autoDetectRenderer(400, 300);
+ console.log('Is PIXI.WebGLRenderer: ' + (renderer instanceof PIXI.WebGLRenderer));
+
+ // add the renderer view element to the DOM
+ document.body.appendChild(renderer.view);
+
+ requestAnimFrame( animate );
+
+ // create a texture from an image path
+ var texture = PIXI.Texture.fromImage(baseUri + "/bunny.png");
+ // create a new Sprite using the texture
+ bunny = new PIXI.Sprite(texture);
+
+ // center the sprites anchor point
+ bunny.anchor.x = 0.5;
+ bunny.anchor.y = 0.5;
+
+ // move the sprite t the center of the screen
+ bunny.position.x = 200;
+ bunny.position.y = 150;
+
+ stage.addChild(bunny);
+ }
+
+ it('assets loaded', function (done) {
+ var loader = new PIXI.AssetLoader([
+ baseUri + '/bunny.png',
+ baseUri + '/frame-30.png',
+ baseUri + '/frame-60.png',
+ baseUri + '/frame-90.png'
+ ]);
+ // loader.on('onProgress', function (event) {
+ // console.log(event.content);
+ // });
+ loader.on('onComplete', function (event) {
+ done();
+ initScene();
+ });
+ loader.load();
+ });
+
+ it('frame 30 should match', function (done) {
+ this.timeout(700);
+ onFrame(30, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-30.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 60 should match', function (done) {
+ this.timeout(1200);
+ onFrame(60, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-60.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 90 should match', function (done) {
+ this.timeout(1700);
+ onFrame(90, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-90.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ // it('capture something', function (done) {
+ // this.timeout(2000000);
+ // onFrame(30, function () {
+ // var img = new Image();
+ // img.src = renderer.view.toDataURL('image/png');
+ // document.body.appendChild(img);
+ // });
+ // });
+});
diff --git a/test/index.html b/test/index.html
deleted file mode 100644
index 9cbcac5..0000000
--- a/test/index.html
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
- Pixi.js Test Suite
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/test/karma.conf.js b/test/karma.conf.js
new file mode 100644
index 0000000..c66a696
--- /dev/null
+++ b/test/karma.conf.js
@@ -0,0 +1,82 @@
+module.exports = function(config) {
+ config.set({
+
+ // base path, that will be used to resolve files and exclude
+ basePath : '../',
+
+ frameworks : ['mocha'],
+
+ // list of files / patterns to load in the browser
+ files : [
+ 'node_modules/chai/chai.js',
+ 'bin/pixi.dev.js',
+ 'test/lib/**/*.js',
+ 'test/unit/**/*.js',
+ // 'test/functional/**/*.js',
+ {pattern: 'test/**/*.png', watched: false, included: false, served: true}
+ ],
+
+ // list of files to exclude
+ exclude : [],
+
+ // use dolts reporter, as travis terminal does not support escaping sequences
+ // possible values: 'dots', 'progress', 'junit', 'teamcity'
+ // CLI --reporters progress
+ reporters : ['progress'],
+
+ // web server port
+ // CLI --port 9876
+ port : 9876,
+
+ // cli runner port
+ // CLI --runner-port 9100
+ runnerPort : 9100,
+
+ // enable / disable colors in the output (reporters and logs)
+ // CLI --colors --no-colors
+ colors : true,
+
+ // level of logging
+ // possible values: karma.LOG_DISABLE || karma.LOG_ERROR || karma.LOG_WARN || karma.LOG_INFO || karma.LOG_DEBUG
+ // CLI --log-level debug
+ logLevel : config.LOG_DEBUG,
+
+ // enable / disable watching file and executing tests whenever any file changes
+ // CLI --auto-watch --no-auto-watch
+ autoWatch : false,
+
+ // Start these browsers, currently available:
+ // - Chrome
+ // - ChromeCanary
+ // - Firefox
+ // - Opera
+ // - Safari (only Mac)
+ // - PhantomJS
+ // - IE (only Windows)
+ // CLI --browsers Chrome,Firefox,Safari
+ browsers : ['Firefox'],
+
+ // If browser does not capture in given timeout [ms], kill it
+ // CLI --capture-timeout 5000
+ captureTimeout : 5000,
+
+ // Auto run tests on start (when browsers are captured) and exit
+ // CLI --single-run --no-single-run
+ singleRun : true,
+
+ // report which specs are slower than 500ms
+ // CLI --report-slower-than 500
+ reportSlowerThan : 1000,
+
+ preprocessors : {
+ // '**/client/js/*.js': 'coverage'
+ },
+
+ plugins : [
+ 'karma-mocha',
+ // 'karma-chrome-launcher',
+ 'karma-firefox-launcher',
+ // 'karma-phantomjs-launcher'
+ ]
+ });
+};
diff --git a/test/lib/pixi/core/Matrix.js b/test/lib/pixi/core/Matrix.js
new file mode 100644
index 0000000..d26386b
--- /dev/null
+++ b/test/lib/pixi/core/Matrix.js
@@ -0,0 +1,40 @@
+
+function pixi_core_Matrix_confirmNewMat3(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(1);
+ expect(matrix[5]).to.equal(0);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(1);
+}
+
+function pixi_core_Matrix_confirmNewMat4(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[0]).to.equal(1);
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(0);
+ expect(matrix[5]).to.equal(1);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(0);
+ expect(matrix[9]).to.equal(0);
+ expect(matrix[10]).to.equal(1);
+ expect(matrix[11]).to.equal(0);
+ expect(matrix[12]).to.equal(0);
+ expect(matrix[13]).to.equal(0);
+ expect(matrix[14]).to.equal(0);
+ expect(matrix[15]).to.equal(1);
+}
diff --git a/test/lib/pixi/core/Point.js b/test/lib/pixi/core/Point.js
new file mode 100644
index 0000000..e5df07b
--- /dev/null
+++ b/test/lib/pixi/core/Point.js
@@ -0,0 +1,10 @@
+
+function pixi_core_Point_confirm(obj, x, y) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Point);
+ expect(obj).to.respondTo('clone');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+}
diff --git a/test/lib/pixi/core/Rectangle.js b/test/lib/pixi/core/Rectangle.js
new file mode 100644
index 0000000..23f0d12
--- /dev/null
+++ b/test/lib/pixi/core/Rectangle.js
@@ -0,0 +1,13 @@
+
+function pixi_core_Rectangle_confirm(obj, x, y, width, height) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Rectangle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+ expect(obj).to.have.property('width', width);
+ expect(obj).to.have.property('height', height);
+}
diff --git a/test/lib/pixi/display/DisplayObject.js b/test/lib/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..1388a7f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObject.js
@@ -0,0 +1,43 @@
+
+function pixi_display_DisplayObject_confirmNew(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObject);
+ expect(obj).to.respondTo('setInteractive');
+ expect(obj).to.respondTo('addFilter');
+ expect(obj).to.respondTo('removeFilter');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.property('last', obj);
+ expect(obj).to.have.property('first', obj);
+
+ expect(obj).to.contain.property('position');
+ pixi_core_Point_confirm(obj.position, 0, 0);
+ expect(obj).to.contain.property('scale');
+ pixi_core_Point_confirm(obj.scale, 1, 1);
+ expect(obj).to.contain.property('pivot');
+ pixi_core_Point_confirm(obj.pivot, 0, 0);
+
+ expect(obj).to.have.property('rotation', 0);
+ expect(obj).to.have.property('alpha', 1);
+ expect(obj).to.have.property('visible', true);
+ expect(obj).to.have.property('buttonMode', false);
+ expect(obj).to.have.property('parent', null);
+ expect(obj).to.have.property('worldAlpha', 1);
+
+ expect(obj).to.have.property('hitArea');
+ expect(obj).to.have.property('interactive'); // TODO: Have a better default value
+ expect('mask' in obj).to.be.true; // TODO: Have a better default value
+ expect(obj.mask).to.be.undefined;
+
+ expect(obj).to.have.property('renderable');
+ expect(obj).to.have.property('stage');
+
+ expect(obj).to.have.deep.property('worldTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ expect(obj).to.have.deep.property('localTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.localTransform);
+
+ expect(obj).to.have.deep.property('color.length', 0);
+ expect(obj).to.have.property('dynamic', true);
+}
diff --git a/test/lib/pixi/display/DisplayObjectContainer.js b/test/lib/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..085c59f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,16 @@
+
+function pixi_display_DisplayObjectContainer_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObject_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObjectContainer);
+ expect(obj).to.respondTo('addChild');
+ expect(obj).to.respondTo('addChildAt');
+ expect(obj).to.respondTo('swapChildren');
+ expect(obj).to.respondTo('getChildAt');
+ expect(obj).to.respondTo('removeChild');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('children.length', 0);
+}
diff --git a/test/lib/pixi/display/Sprite.js b/test/lib/pixi/display/Sprite.js
new file mode 100644
index 0000000..cc7a2d6
--- /dev/null
+++ b/test/lib/pixi/display/Sprite.js
@@ -0,0 +1,28 @@
+
+function pixi_display_Sprite_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Sprite);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', true);
+ expect(obj).to.have.property('stage', null);
+
+ expect(obj).to.have.property('anchor');
+ pixi_core_Point_confirm(obj.anchor, 0, 0);
+
+ expect(obj).to.have.property('blendMode', PIXI.blendModes.NORMAL);
+ expect(obj).to.have.property('width', 1); // TODO: is 1 expected
+ expect(obj).to.have.property('height', 1); // TODO: is 1 expected
+
+ // FIXME: Just make this a boolean that is always there
+ expect(!!obj.updateFrame).to.equal(obj.texture.baseTexture.hasLoaded);
+
+ expect(obj).to.have.property('texture');
+ pixi_textures_Texture_confirmNew(obj.texture, done);
+}
diff --git a/test/lib/pixi/extras/Strip.js b/test/lib/pixi/extras/Strip.js
new file mode 100644
index 0000000..8927a8a
--- /dev/null
+++ b/test/lib/pixi/extras/Strip.js
@@ -0,0 +1,12 @@
+
+function pixi_extras_Strip_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Strip);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ // TODO: Test properties
+}
diff --git a/test/lib/pixi/textures/Texture.js b/test/lib/pixi/textures/Texture.js
new file mode 100644
index 0000000..d5867b6
--- /dev/null
+++ b/test/lib/pixi/textures/Texture.js
@@ -0,0 +1,31 @@
+
+function pixi_textures_Texture_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ function confirmFrameDone() {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, obj.baseTexture.width, obj.baseTexture.height);
+
+ expect(obj).to.have.property('width', obj.baseTexture.width);
+ expect(obj).to.have.property('height', obj.baseTexture.height);
+ done();
+ }
+
+ expect(obj).to.be.an.instanceof(PIXI.Texture);
+ pixi_utils_EventTarget_like(obj);
+
+ expect(obj).to.have.property('baseTexture')
+ .and.to.be.an.instanceof(PIXI.BaseTexture);
+
+ expect(obj).to.have.property('scope', obj);
+
+ expect(obj).to.have.property('trim');
+ pixi_core_Point_confirm(obj.trim, 0, 0);
+
+ expect(obj).to.have.property('frame');
+ if (obj.baseTexture.hasLoaded) {
+ confirmFrameDone();
+ } else {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, 1, 1);
+ obj.addEventListener('update', confirmFrameDone);
+ }
+}
diff --git a/test/lib/pixi/utils/EventTarget.js b/test/lib/pixi/utils/EventTarget.js
new file mode 100644
index 0000000..7b1dcfa
--- /dev/null
+++ b/test/lib/pixi/utils/EventTarget.js
@@ -0,0 +1,8 @@
+
+function pixi_utils_EventTarget_like(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.respondTo('addEventListener');
+ expect(obj).to.respondTo('dispatchEvent');
+ expect(obj).to.respondTo('removeEventListener');
+}
diff --git a/test/lib/qunit-1.11.0.css b/test/lib/qunit-1.11.0.css
deleted file mode 100644
index d7fc0c8..0000000
--- a/test/lib/qunit-1.11.0.css
+++ /dev/null
@@ -1,244 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-/** Font Family and Sizes */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
- font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
-}
-
-#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
-#qunit-tests { font-size: smaller; }
-
-
-/** Resets */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter {
- margin: 0;
- padding: 0;
-}
-
-
-/** Header */
-
-#qunit-header {
- padding: 0.5em 0 0.5em 1em;
-
- color: #8699a4;
- background-color: #0d3349;
-
- font-size: 1.5em;
- line-height: 1em;
- font-weight: normal;
-
- border-radius: 5px 5px 0 0;
- -moz-border-radius: 5px 5px 0 0;
- -webkit-border-top-right-radius: 5px;
- -webkit-border-top-left-radius: 5px;
-}
-
-#qunit-header a {
- text-decoration: none;
- color: #c2ccd1;
-}
-
-#qunit-header a:hover,
-#qunit-header a:focus {
- color: #fff;
-}
-
-#qunit-testrunner-toolbar label {
- display: inline-block;
- padding: 0 .5em 0 .1em;
-}
-
-#qunit-banner {
- height: 5px;
-}
-
-#qunit-testrunner-toolbar {
- padding: 0.5em 0 0.5em 2em;
- color: #5E740B;
- background-color: #eee;
- overflow: hidden;
-}
-
-#qunit-userAgent {
- padding: 0.5em 0 0.5em 2.5em;
- background-color: #2b81af;
- color: #fff;
- text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
-}
-
-#qunit-modulefilter-container {
- float: right;
-}
-
-/** Tests: Pass/Fail */
-
-#qunit-tests {
- list-style-position: inside;
-}
-
-#qunit-tests li {
- padding: 0.4em 0.5em 0.4em 2.5em;
- border-bottom: 1px solid #fff;
- list-style-position: inside;
-}
-
-#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running {
- display: none;
-}
-
-#qunit-tests li strong {
- cursor: pointer;
-}
-
-#qunit-tests li a {
- padding: 0.5em;
- color: #c2ccd1;
- text-decoration: none;
-}
-#qunit-tests li a:hover,
-#qunit-tests li a:focus {
- color: #000;
-}
-
-#qunit-tests li .runtime {
- float: right;
- font-size: smaller;
-}
-
-.qunit-assert-list {
- margin-top: 0.5em;
- padding: 0.5em;
-
- background-color: #fff;
-
- border-radius: 5px;
- -moz-border-radius: 5px;
- -webkit-border-radius: 5px;
-}
-
-.qunit-collapsed {
- display: none;
-}
-
-#qunit-tests table {
- border-collapse: collapse;
- margin-top: .2em;
-}
-
-#qunit-tests th {
- text-align: right;
- vertical-align: top;
- padding: 0 .5em 0 0;
-}
-
-#qunit-tests td {
- vertical-align: top;
-}
-
-#qunit-tests pre {
- margin: 0;
- white-space: pre-wrap;
- word-wrap: break-word;
-}
-
-#qunit-tests del {
- background-color: #e0f2be;
- color: #374e0c;
- text-decoration: none;
-}
-
-#qunit-tests ins {
- background-color: #ffcaca;
- color: #500;
- text-decoration: none;
-}
-
-/*** Test Counts */
-
-#qunit-tests b.counts { color: black; }
-#qunit-tests b.passed { color: #5E740B; }
-#qunit-tests b.failed { color: #710909; }
-
-#qunit-tests li li {
- padding: 5px;
- background-color: #fff;
- border-bottom: none;
- list-style-position: inside;
-}
-
-/*** Passing Styles */
-
-#qunit-tests li li.pass {
- color: #3c510c;
- background-color: #fff;
- border-left: 10px solid #C6E746;
-}
-
-#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
-#qunit-tests .pass .test-name { color: #366097; }
-
-#qunit-tests .pass .test-actual,
-#qunit-tests .pass .test-expected { color: #999999; }
-
-#qunit-banner.qunit-pass { background-color: #C6E746; }
-
-/*** Failing Styles */
-
-#qunit-tests li li.fail {
- color: #710909;
- background-color: #fff;
- border-left: 10px solid #EE5757;
- white-space: pre;
-}
-
-#qunit-tests > li:last-child {
- border-radius: 0 0 5px 5px;
- -moz-border-radius: 0 0 5px 5px;
- -webkit-border-bottom-right-radius: 5px;
- -webkit-border-bottom-left-radius: 5px;
-}
-
-#qunit-tests .fail { color: #000000; background-color: #EE5757; }
-#qunit-tests .fail .test-name,
-#qunit-tests .fail .module-name { color: #000000; }
-
-#qunit-tests .fail .test-actual { color: #EE5757; }
-#qunit-tests .fail .test-expected { color: green; }
-
-#qunit-banner.qunit-fail { background-color: #EE5757; }
-
-
-/** Result */
-
-#qunit-testresult {
- padding: 0.5em 0.5em 0.5em 2.5em;
-
- color: #2b81af;
- background-color: #D2E0E6;
-
- border-bottom: 1px solid white;
-}
-#qunit-testresult .module-name {
- font-weight: bold;
-}
-
-/** Fixture */
-
-#qunit-fixture {
- position: absolute;
- top: -10000px;
- left: -10000px;
- width: 1000px;
- height: 1000px;
-}
diff --git a/test/lib/qunit-1.11.0.js b/test/lib/qunit-1.11.0.js
deleted file mode 100644
index 302545f..0000000
--- a/test/lib/qunit-1.11.0.js
+++ /dev/null
@@ -1,2152 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-(function( window ) {
-
-var QUnit,
- assert,
- config,
- onErrorFnPrev,
- testId = 0,
- fileName = (sourceFromStacktrace( 0 ) || "" ).replace(/(:\d+)+\)?/, "").replace(/.+\//, ""),
- toString = Object.prototype.toString,
- hasOwn = Object.prototype.hasOwnProperty,
- // Keep a local reference to Date (GH-283)
- Date = window.Date,
- defined = {
- setTimeout: typeof window.setTimeout !== "undefined",
- sessionStorage: (function() {
- var x = "qunit-test-string";
- try {
- sessionStorage.setItem( x, x );
- sessionStorage.removeItem( x );
- return true;
- } catch( e ) {
- return false;
- }
- }())
- },
- /**
- * Provides a normalized error string, correcting an issue
- * with IE 7 (and prior) where Error.prototype.toString is
- * not properly implemented
- *
- * Based on http://es5.github.com/#x15.11.4.4
- *
- * @param {String|Error} error
- * @return {String} error message
- */
- errorString = function( error ) {
- var name, message,
- errorString = error.toString();
- if ( errorString.substring( 0, 7 ) === "[object" ) {
- name = error.name ? error.name.toString() : "Error";
- message = error.message ? error.message.toString() : "";
- if ( name && message ) {
- return name + ": " + message;
- } else if ( name ) {
- return name;
- } else if ( message ) {
- return message;
- } else {
- return "Error";
- }
- } else {
- return errorString;
- }
- },
- /**
- * Makes a clone of an object using only Array or Object as base,
- * and copies over the own enumerable properties.
- *
- * @param {Object} obj
- * @return {Object} New object with only the own properties (recursively).
- */
- objectValues = function( obj ) {
- // Grunt 0.3.x uses an older version of jshint that still has jshint/jshint#392.
- /*jshint newcap: false */
- var key, val,
- vals = QUnit.is( "array", obj ) ? [] : {};
- for ( key in obj ) {
- if ( hasOwn.call( obj, key ) ) {
- val = obj[key];
- vals[key] = val === Object(val) ? objectValues(val) : val;
- }
- }
- return vals;
- };
-
-function Test( settings ) {
- extend( this, settings );
- this.assertions = [];
- this.testNumber = ++Test.count;
-}
-
-Test.count = 0;
-
-Test.prototype = {
- init: function() {
- var a, b, li,
- tests = id( "qunit-tests" );
-
- if ( tests ) {
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml;
-
- // `a` initialized at top of scope
- a = document.createElement( "a" );
- a.innerHTML = "Rerun";
- a.href = QUnit.url({ testNumber: this.testNumber });
-
- li = document.createElement( "li" );
- li.appendChild( b );
- li.appendChild( a );
- li.className = "running";
- li.id = this.id = "qunit-test-output" + testId++;
-
- tests.appendChild( li );
- }
- },
- setup: function() {
- if ( this.module !== config.previousModule ) {
- if ( config.previousModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.previousModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
- config.previousModule = this.module;
- config.moduleStats = { all: 0, bad: 0 };
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- } else if ( config.autorun ) {
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- }
-
- config.current = this;
-
- this.testEnvironment = extend({
- setup: function() {},
- teardown: function() {}
- }, this.moduleTestEnvironment );
-
- this.started = +new Date();
- runLoggingCallbacks( "testStart", QUnit, {
- name: this.testName,
- module: this.module
- });
-
- // allow utility functions to access the current test environment
- // TODO why??
- QUnit.current_testEnvironment = this.testEnvironment;
-
- if ( !config.pollution ) {
- saveGlobal();
- }
- if ( config.notrycatch ) {
- this.testEnvironment.setup.call( this.testEnvironment );
- return;
- }
- try {
- this.testEnvironment.setup.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Setup failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- },
- run: function() {
- config.current = this;
-
- var running = id( "qunit-testresult" );
-
- if ( running ) {
- running.innerHTML = "Running:
" + this.nameHtml;
- }
-
- if ( this.async ) {
- QUnit.stop();
- }
-
- this.callbackStarted = +new Date();
-
- if ( config.notrycatch ) {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- return;
- }
-
- try {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- } catch( e ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
-
- QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + " " + this.stack + ": " + ( e.message || e ), extractStacktrace( e, 0 ) );
- // else next test will carry the responsibility
- saveGlobal();
-
- // Restart the tests if they're blocking
- if ( config.blocking ) {
- QUnit.start();
- }
- }
- },
- teardown: function() {
- config.current = this;
- if ( config.notrycatch ) {
- if ( typeof this.callbackRuntime === "undefined" ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
- }
- this.testEnvironment.teardown.call( this.testEnvironment );
- return;
- } else {
- try {
- this.testEnvironment.teardown.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Teardown failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- }
- checkPollution();
- },
- finish: function() {
- config.current = this;
- if ( config.requireExpects && this.expected === null ) {
- QUnit.pushFailure( "Expected number of assertions to be defined, but expect() was not called.", this.stack );
- } else if ( this.expected !== null && this.expected !== this.assertions.length ) {
- QUnit.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack );
- } else if ( this.expected === null && !this.assertions.length ) {
- QUnit.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions.", this.stack );
- }
-
- var i, assertion, a, b, time, li, ol,
- test = this,
- good = 0,
- bad = 0,
- tests = id( "qunit-tests" );
-
- this.runtime = +new Date() - this.started;
- config.stats.all += this.assertions.length;
- config.moduleStats.all += this.assertions.length;
-
- if ( tests ) {
- ol = document.createElement( "ol" );
- ol.className = "qunit-assert-list";
-
- for ( i = 0; i < this.assertions.length; i++ ) {
- assertion = this.assertions[i];
-
- li = document.createElement( "li" );
- li.className = assertion.result ? "pass" : "fail";
- li.innerHTML = assertion.message || ( assertion.result ? "okay" : "failed" );
- ol.appendChild( li );
-
- if ( assertion.result ) {
- good++;
- } else {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
-
- // store result when possible
- if ( QUnit.config.reorder && defined.sessionStorage ) {
- if ( bad ) {
- sessionStorage.setItem( "qunit-test-" + this.module + "-" + this.testName, bad );
- } else {
- sessionStorage.removeItem( "qunit-test-" + this.module + "-" + this.testName );
- }
- }
-
- if ( bad === 0 ) {
- addClass( ol, "qunit-collapsed" );
- }
-
- // `b` initialized at top of scope
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml + " (" + bad + ", " + good + ", " + this.assertions.length + ")";
-
- addEvent(b, "click", function() {
- var next = b.parentNode.lastChild,
- collapsed = hasClass( next, "qunit-collapsed" );
- ( collapsed ? removeClass : addClass )( next, "qunit-collapsed" );
- });
-
- addEvent(b, "dblclick", function( e ) {
- var target = e && e.target ? e.target : window.event.srcElement;
- if ( target.nodeName.toLowerCase() === "span" || target.nodeName.toLowerCase() === "b" ) {
- target = target.parentNode;
- }
- if ( window.location && target.nodeName.toLowerCase() === "strong" ) {
- window.location = QUnit.url({ testNumber: test.testNumber });
- }
- });
-
- // `time` initialized at top of scope
- time = document.createElement( "span" );
- time.className = "runtime";
- time.innerHTML = this.runtime + " ms";
-
- // `li` initialized at top of scope
- li = id( this.id );
- li.className = bad ? "fail" : "pass";
- li.removeChild( li.firstChild );
- a = li.firstChild;
- li.appendChild( b );
- li.appendChild( a );
- li.appendChild( time );
- li.appendChild( ol );
-
- } else {
- for ( i = 0; i < this.assertions.length; i++ ) {
- if ( !this.assertions[i].result ) {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
- }
-
- runLoggingCallbacks( "testDone", QUnit, {
- name: this.testName,
- module: this.module,
- failed: bad,
- passed: this.assertions.length - bad,
- total: this.assertions.length,
- duration: this.runtime
- });
-
- QUnit.reset();
-
- config.current = undefined;
- },
-
- queue: function() {
- var bad,
- test = this;
-
- synchronize(function() {
- test.init();
- });
- function run() {
- // each of these can by async
- synchronize(function() {
- test.setup();
- });
- synchronize(function() {
- test.run();
- });
- synchronize(function() {
- test.teardown();
- });
- synchronize(function() {
- test.finish();
- });
- }
-
- // `bad` initialized at top of scope
- // defer when previous test run passed, if storage is available
- bad = QUnit.config.reorder && defined.sessionStorage &&
- +sessionStorage.getItem( "qunit-test-" + this.module + "-" + this.testName );
-
- if ( bad ) {
- run();
- } else {
- synchronize( run, true );
- }
- }
-};
-
-// Root QUnit object.
-// `QUnit` initialized at top of scope
-QUnit = {
-
- // call on start of module test to prepend name to all tests
- module: function( name, testEnvironment ) {
- config.currentModule = name;
- config.currentModuleTestEnvironment = testEnvironment;
- config.modules[name] = true;
- },
-
- asyncTest: function( testName, expected, callback ) {
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- QUnit.test( testName, expected, callback, true );
- },
-
- test: function( testName, expected, callback, async ) {
- var test,
- nameHtml = "" + escapeText( testName ) + "";
-
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- if ( config.currentModule ) {
- nameHtml = "" + escapeText( config.currentModule ) + ": " + nameHtml;
- }
-
- test = new Test({
- nameHtml: nameHtml,
- testName: testName,
- expected: expected,
- async: async,
- callback: callback,
- module: config.currentModule,
- moduleTestEnvironment: config.currentModuleTestEnvironment,
- stack: sourceFromStacktrace( 2 )
- });
-
- if ( !validTest( test ) ) {
- return;
- }
-
- test.queue();
- },
-
- // Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through.
- expect: function( asserts ) {
- if (arguments.length === 1) {
- config.current.expected = asserts;
- } else {
- return config.current.expected;
- }
- },
-
- start: function( count ) {
- // QUnit hasn't been initialized yet.
- // Note: RequireJS (et al) may delay onLoad
- if ( config.semaphore === undefined ) {
- QUnit.begin(function() {
- // This is triggered at the top of QUnit.load, push start() to the event loop, to allow QUnit.load to finish first
- setTimeout(function() {
- QUnit.start( count );
- });
- });
- return;
- }
-
- config.semaphore -= count || 1;
- // don't start until equal number of stop-calls
- if ( config.semaphore > 0 ) {
- return;
- }
- // ignore if start is called more often then stop
- if ( config.semaphore < 0 ) {
- config.semaphore = 0;
- QUnit.pushFailure( "Called start() while already started (QUnit.config.semaphore was 0 already)", null, sourceFromStacktrace(2) );
- return;
- }
- // A slight delay, to avoid any current callbacks
- if ( defined.setTimeout ) {
- window.setTimeout(function() {
- if ( config.semaphore > 0 ) {
- return;
- }
- if ( config.timeout ) {
- clearTimeout( config.timeout );
- }
-
- config.blocking = false;
- process( true );
- }, 13);
- } else {
- config.blocking = false;
- process( true );
- }
- },
-
- stop: function( count ) {
- config.semaphore += count || 1;
- config.blocking = true;
-
- if ( config.testTimeout && defined.setTimeout ) {
- clearTimeout( config.timeout );
- config.timeout = window.setTimeout(function() {
- QUnit.ok( false, "Test timed out" );
- config.semaphore = 1;
- QUnit.start();
- }, config.testTimeout );
- }
- }
-};
-
-// `assert` initialized at top of scope
-// Asssert helpers
-// All of these must either call QUnit.push() or manually do:
-// - runLoggingCallbacks( "log", .. );
-// - config.current.assertions.push({ .. });
-// We attach it to the QUnit object *after* we expose the public API,
-// otherwise `assert` will become a global variable in browsers (#341).
-assert = {
- /**
- * Asserts rough true-ish result.
- * @name ok
- * @function
- * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" );
- */
- ok: function( result, msg ) {
- if ( !config.current ) {
- throw new Error( "ok() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
- result = !!result;
-
- var source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: msg
- };
-
- msg = escapeText( msg || (result ? "okay" : "failed" ) );
- msg = "" + msg + "";
-
- if ( !result ) {
- source = sourceFromStacktrace( 2 );
- if ( source ) {
- details.source = source;
- msg += "Source: | " + escapeText( source ) + " |
---|
";
- }
- }
- runLoggingCallbacks( "log", QUnit, details );
- config.current.assertions.push({
- result: result,
- message: msg
- });
- },
-
- /**
- * Assert that the first two arguments are equal, with an optional message.
- * Prints out both actual and expected values.
- * @name equal
- * @function
- * @example equal( format( "Received {0} bytes.", 2), "Received 2 bytes.", "format() replaces {0} with next argument" );
- */
- equal: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected == actual, actual, expected, message );
- },
-
- /**
- * @name notEqual
- * @function
- */
- notEqual: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected != actual, actual, expected, message );
- },
-
- /**
- * @name propEqual
- * @function
- */
- propEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notPropEqual
- * @function
- */
- notPropEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name deepEqual
- * @function
- */
- deepEqual: function( actual, expected, message ) {
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notDeepEqual
- * @function
- */
- notDeepEqual: function( actual, expected, message ) {
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name strictEqual
- * @function
- */
- strictEqual: function( actual, expected, message ) {
- QUnit.push( expected === actual, actual, expected, message );
- },
-
- /**
- * @name notStrictEqual
- * @function
- */
- notStrictEqual: function( actual, expected, message ) {
- QUnit.push( expected !== actual, actual, expected, message );
- },
-
- "throws": function( block, expected, message ) {
- var actual,
- expectedOutput = expected,
- ok = false;
-
- // 'expected' is optional
- if ( typeof expected === "string" ) {
- message = expected;
- expected = null;
- }
-
- config.current.ignoreGlobalErrors = true;
- try {
- block.call( config.current.testEnvironment );
- } catch (e) {
- actual = e;
- }
- config.current.ignoreGlobalErrors = false;
-
- if ( actual ) {
- // we don't want to validate thrown error
- if ( !expected ) {
- ok = true;
- expectedOutput = null;
- // expected is a regexp
- } else if ( QUnit.objectType( expected ) === "regexp" ) {
- ok = expected.test( errorString( actual ) );
- // expected is a constructor
- } else if ( actual instanceof expected ) {
- ok = true;
- // expected is a validation function which returns true is validation passed
- } else if ( expected.call( {}, actual ) === true ) {
- expectedOutput = null;
- ok = true;
- }
-
- QUnit.push( ok, actual, expectedOutput, message );
- } else {
- QUnit.pushFailure( message, null, 'No exception was thrown.' );
- }
- }
-};
-
-/**
- * @deprecate since 1.8.0
- * Kept assertion helpers in root for backwards compatibility.
- */
-extend( QUnit, assert );
-
-/**
- * @deprecated since 1.9.0
- * Kept root "raises()" for backwards compatibility.
- * (Note that we don't introduce assert.raises).
- */
-QUnit.raises = assert[ "throws" ];
-
-/**
- * @deprecated since 1.0.0, replaced with error pushes since 1.3.0
- * Kept to avoid TypeErrors for undefined methods.
- */
-QUnit.equals = function() {
- QUnit.push( false, false, false, "QUnit.equals has been deprecated since 2009 (e88049a0), use QUnit.equal instead" );
-};
-QUnit.same = function() {
- QUnit.push( false, false, false, "QUnit.same has been deprecated since 2009 (e88049a0), use QUnit.deepEqual instead" );
-};
-
-// We want access to the constructor's prototype
-(function() {
- function F() {}
- F.prototype = QUnit;
- QUnit = new F();
- // Make F QUnit's constructor so that we can add to the prototype later
- QUnit.constructor = F;
-}());
-
-/**
- * Config object: Maintain internal state
- * Later exposed as QUnit.config
- * `config` initialized at top of scope
- */
-config = {
- // The queue of tests to run
- queue: [],
-
- // block until document ready
- blocking: true,
-
- // when enabled, show only failing tests
- // gets persisted through sessionStorage and can be changed in UI via checkbox
- hidepassed: false,
-
- // by default, run previously failed tests first
- // very useful in combination with "Hide passed tests" checked
- reorder: true,
-
- // by default, modify document.title when suite is done
- altertitle: true,
-
- // when enabled, all tests must call expect()
- requireExpects: false,
-
- // add checkboxes that are persisted in the query-string
- // when enabled, the id is set to `true` as a `QUnit.config` property
- urlConfig: [
- {
- id: "noglobals",
- label: "Check for Globals",
- tooltip: "Enabling this will test if any test introduces new properties on the `window` object. Stored as query-strings."
- },
- {
- id: "notrycatch",
- label: "No try-catch",
- tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging exceptions in IE reasonable. Stored as query-strings."
- }
- ],
-
- // Set of all modules.
- modules: {},
-
- // logging callback queues
- begin: [],
- done: [],
- log: [],
- testStart: [],
- testDone: [],
- moduleStart: [],
- moduleDone: []
-};
-
-// Export global variables, unless an 'exports' object exists,
-// in that case we assume we're in CommonJS (dealt with on the bottom of the script)
-if ( typeof exports === "undefined" ) {
- extend( window, QUnit );
-
- // Expose QUnit object
- window.QUnit = QUnit;
-}
-
-// Initialize more QUnit.config and QUnit.urlParams
-(function() {
- var i,
- location = window.location || { search: "", protocol: "file:" },
- params = location.search.slice( 1 ).split( "&" ),
- length = params.length,
- urlParams = {},
- current;
-
- if ( params[ 0 ] ) {
- for ( i = 0; i < length; i++ ) {
- current = params[ i ].split( "=" );
- current[ 0 ] = decodeURIComponent( current[ 0 ] );
- // allow just a key to turn on a flag, e.g., test.html?noglobals
- current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true;
- urlParams[ current[ 0 ] ] = current[ 1 ];
- }
- }
-
- QUnit.urlParams = urlParams;
-
- // String search anywhere in moduleName+testName
- config.filter = urlParams.filter;
-
- // Exact match of the module name
- config.module = urlParams.module;
-
- config.testNumber = parseInt( urlParams.testNumber, 10 ) || null;
-
- // Figure out if we're running the tests from a server or not
- QUnit.isLocal = location.protocol === "file:";
-}());
-
-// Extend QUnit object,
-// these after set here because they should not be exposed as global functions
-extend( QUnit, {
- assert: assert,
-
- config: config,
-
- // Initialize the configuration options
- init: function() {
- extend( config, {
- stats: { all: 0, bad: 0 },
- moduleStats: { all: 0, bad: 0 },
- started: +new Date(),
- updateRate: 1000,
- blocking: false,
- autostart: true,
- autorun: false,
- filter: "",
- queue: [],
- semaphore: 1
- });
-
- var tests, banner, result,
- qunit = id( "qunit" );
-
- if ( qunit ) {
- qunit.innerHTML =
- "" +
- "" +
- "" +
- "" +
- "
";
- }
-
- tests = id( "qunit-tests" );
- banner = id( "qunit-banner" );
- result = id( "qunit-testresult" );
-
- if ( tests ) {
- tests.innerHTML = "";
- }
-
- if ( banner ) {
- banner.className = "";
- }
-
- if ( result ) {
- result.parentNode.removeChild( result );
- }
-
- if ( tests ) {
- result = document.createElement( "p" );
- result.id = "qunit-testresult";
- result.className = "result";
- tests.parentNode.insertBefore( result, tests );
- result.innerHTML = "Running...
";
- }
- },
-
- // Resets the test setup. Useful for tests that modify the DOM.
- reset: function() {
- var fixture = id( "qunit-fixture" );
- if ( fixture ) {
- fixture.innerHTML = config.fixture;
- }
- },
-
- // Trigger an event on an element.
- // @example triggerEvent( document.body, "click" );
- triggerEvent: function( elem, type, event ) {
- if ( document.createEvent ) {
- event = document.createEvent( "MouseEvents" );
- event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView,
- 0, 0, 0, 0, 0, false, false, false, false, 0, null);
-
- elem.dispatchEvent( event );
- } else if ( elem.fireEvent ) {
- elem.fireEvent( "on" + type );
- }
- },
-
- // Safe object type checking
- is: function( type, obj ) {
- return QUnit.objectType( obj ) === type;
- },
-
- objectType: function( obj ) {
- if ( typeof obj === "undefined" ) {
- return "undefined";
- // consider: typeof null === object
- }
- if ( obj === null ) {
- return "null";
- }
-
- var match = toString.call( obj ).match(/^\[object\s(.*)\]$/),
- type = match && match[1] || "";
-
- switch ( type ) {
- case "Number":
- if ( isNaN(obj) ) {
- return "nan";
- }
- return "number";
- case "String":
- case "Boolean":
- case "Array":
- case "Date":
- case "RegExp":
- case "Function":
- return type.toLowerCase();
- }
- if ( typeof obj === "object" ) {
- return "object";
- }
- return undefined;
- },
-
- push: function( result, actual, expected, message ) {
- if ( !config.current ) {
- throw new Error( "assertion outside test context, was " + sourceFromStacktrace() );
- }
-
- var output, source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: message,
- actual: actual,
- expected: expected
- };
-
- message = escapeText( message ) || ( result ? "okay" : "failed" );
- message = "" + message + "";
- output = message;
-
- if ( !result ) {
- expected = escapeText( QUnit.jsDump.parse(expected) );
- actual = escapeText( QUnit.jsDump.parse(actual) );
- output += "Expected: | " + expected + " |
";
-
- if ( actual !== expected ) {
- output += "Result: | " + actual + " |
";
- output += "Diff: | " + QUnit.diff( expected, actual ) + " |
";
- }
-
- source = sourceFromStacktrace();
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
- }
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: !!result,
- message: output
- });
- },
-
- pushFailure: function( message, source, actual ) {
- if ( !config.current ) {
- throw new Error( "pushFailure() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
-
- var output,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: false,
- message: message
- };
-
- message = escapeText( message ) || "error";
- message = "" + message + "";
- output = message;
-
- output += "";
-
- if ( actual ) {
- output += "Result: | " + escapeText( actual ) + " |
";
- }
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: false,
- message: output
- });
- },
-
- url: function( params ) {
- params = extend( extend( {}, QUnit.urlParams ), params );
- var key,
- querystring = "?";
-
- for ( key in params ) {
- if ( !hasOwn.call( params, key ) ) {
- continue;
- }
- querystring += encodeURIComponent( key ) + "=" +
- encodeURIComponent( params[ key ] ) + "&";
- }
- return window.location.protocol + "//" + window.location.host +
- window.location.pathname + querystring.slice( 0, -1 );
- },
-
- extend: extend,
- id: id,
- addEvent: addEvent
- // load, equiv, jsDump, diff: Attached later
-});
-
-/**
- * @deprecated: Created for backwards compatibility with test runner that set the hook function
- * into QUnit.{hook}, instead of invoking it and passing the hook function.
- * QUnit.constructor is set to the empty F() above so that we can add to it's prototype here.
- * Doing this allows us to tell if the following methods have been overwritten on the actual
- * QUnit object.
- */
-extend( QUnit.constructor.prototype, {
-
- // Logging callbacks; all receive a single argument with the listed properties
- // run test/logs.html for any related changes
- begin: registerLoggingCallback( "begin" ),
-
- // done: { failed, passed, total, runtime }
- done: registerLoggingCallback( "done" ),
-
- // log: { result, actual, expected, message }
- log: registerLoggingCallback( "log" ),
-
- // testStart: { name }
- testStart: registerLoggingCallback( "testStart" ),
-
- // testDone: { name, failed, passed, total, duration }
- testDone: registerLoggingCallback( "testDone" ),
-
- // moduleStart: { name }
- moduleStart: registerLoggingCallback( "moduleStart" ),
-
- // moduleDone: { name, failed, passed, total }
- moduleDone: registerLoggingCallback( "moduleDone" )
-});
-
-if ( typeof document === "undefined" || document.readyState === "complete" ) {
- config.autorun = true;
-}
-
-QUnit.load = function() {
- runLoggingCallbacks( "begin", QUnit, {} );
-
- // Initialize the config, saving the execution queue
- var banner, filter, i, label, len, main, ol, toolbar, userAgent, val,
- urlConfigCheckboxesContainer, urlConfigCheckboxes, moduleFilter,
- numModules = 0,
- moduleFilterHtml = "",
- urlConfigHtml = "",
- oldconfig = extend( {}, config );
-
- QUnit.init();
- extend(config, oldconfig);
-
- config.blocking = false;
-
- len = config.urlConfig.length;
-
- for ( i = 0; i < len; i++ ) {
- val = config.urlConfig[i];
- if ( typeof val === "string" ) {
- val = {
- id: val,
- label: val,
- tooltip: "[no tooltip available]"
- };
- }
- config[ val.id ] = QUnit.urlParams[ val.id ];
- urlConfigHtml += "";
- }
-
- moduleFilterHtml += "";
-
- // `userAgent` initialized at top of scope
- userAgent = id( "qunit-userAgent" );
- if ( userAgent ) {
- userAgent.innerHTML = navigator.userAgent;
- }
-
- // `banner` initialized at top of scope
- banner = id( "qunit-header" );
- if ( banner ) {
- banner.innerHTML = "" + banner.innerHTML + " ";
- }
-
- // `toolbar` initialized at top of scope
- toolbar = id( "qunit-testrunner-toolbar" );
- if ( toolbar ) {
- // `filter` initialized at top of scope
- filter = document.createElement( "input" );
- filter.type = "checkbox";
- filter.id = "qunit-filter-pass";
-
- addEvent( filter, "click", function() {
- var tmp,
- ol = document.getElementById( "qunit-tests" );
-
- if ( filter.checked ) {
- ol.className = ol.className + " hidepass";
- } else {
- tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " ";
- ol.className = tmp.replace( / hidepass /, " " );
- }
- if ( defined.sessionStorage ) {
- if (filter.checked) {
- sessionStorage.setItem( "qunit-filter-passed-tests", "true" );
- } else {
- sessionStorage.removeItem( "qunit-filter-passed-tests" );
- }
- }
- });
-
- if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem( "qunit-filter-passed-tests" ) ) {
- filter.checked = true;
- // `ol` initialized at top of scope
- ol = document.getElementById( "qunit-tests" );
- ol.className = ol.className + " hidepass";
- }
- toolbar.appendChild( filter );
-
- // `label` initialized at top of scope
- label = document.createElement( "label" );
- label.setAttribute( "for", "qunit-filter-pass" );
- label.setAttribute( "title", "Only show tests and assertons that fail. Stored in sessionStorage." );
- label.innerHTML = "Hide passed tests";
- toolbar.appendChild( label );
-
- urlConfigCheckboxesContainer = document.createElement("span");
- urlConfigCheckboxesContainer.innerHTML = urlConfigHtml;
- urlConfigCheckboxes = urlConfigCheckboxesContainer.getElementsByTagName("input");
- // For oldIE support:
- // * Add handlers to the individual elements instead of the container
- // * Use "click" instead of "change"
- // * Fallback from event.target to event.srcElement
- addEvents( urlConfigCheckboxes, "click", function( event ) {
- var params = {},
- target = event.target || event.srcElement;
- params[ target.name ] = target.checked ? true : undefined;
- window.location = QUnit.url( params );
- });
- toolbar.appendChild( urlConfigCheckboxesContainer );
-
- if (numModules > 1) {
- moduleFilter = document.createElement( 'span' );
- moduleFilter.setAttribute( 'id', 'qunit-modulefilter-container' );
- moduleFilter.innerHTML = moduleFilterHtml;
- addEvent( moduleFilter.lastChild, "change", function() {
- var selectBox = moduleFilter.getElementsByTagName("select")[0],
- selectedModule = decodeURIComponent(selectBox.options[selectBox.selectedIndex].value);
-
- window.location = QUnit.url( { module: ( selectedModule === "" ) ? undefined : selectedModule } );
- });
- toolbar.appendChild(moduleFilter);
- }
- }
-
- // `main` initialized at top of scope
- main = id( "qunit-fixture" );
- if ( main ) {
- config.fixture = main.innerHTML;
- }
-
- if ( config.autostart ) {
- QUnit.start();
- }
-};
-
-addEvent( window, "load", QUnit.load );
-
-// `onErrorFnPrev` initialized at top of scope
-// Preserve other handlers
-onErrorFnPrev = window.onerror;
-
-// Cover uncaught exceptions
-// Returning true will surpress the default browser handler,
-// returning false will let it run.
-window.onerror = function ( error, filePath, linerNr ) {
- var ret = false;
- if ( onErrorFnPrev ) {
- ret = onErrorFnPrev( error, filePath, linerNr );
- }
-
- // Treat return value as window.onerror itself does,
- // Only do our handling if not surpressed.
- if ( ret !== true ) {
- if ( QUnit.config.current ) {
- if ( QUnit.config.current.ignoreGlobalErrors ) {
- return true;
- }
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- } else {
- QUnit.test( "global failure", extend( function() {
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- }, { validTest: validTest } ) );
- }
- return false;
- }
-
- return ret;
-};
-
-function done() {
- config.autorun = true;
-
- // Log the last module results
- if ( config.currentModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.currentModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
-
- var i, key,
- banner = id( "qunit-banner" ),
- tests = id( "qunit-tests" ),
- runtime = +new Date() - config.started,
- passed = config.stats.all - config.stats.bad,
- html = [
- "Tests completed in ",
- runtime,
- " milliseconds.
",
- "",
- passed,
- " assertions of ",
- config.stats.all,
- " passed, ",
- config.stats.bad,
- " failed."
- ].join( "" );
-
- if ( banner ) {
- banner.className = ( config.stats.bad ? "qunit-fail" : "qunit-pass" );
- }
-
- if ( tests ) {
- id( "qunit-testresult" ).innerHTML = html;
- }
-
- if ( config.altertitle && typeof document !== "undefined" && document.title ) {
- // show ✖ for good, ✔ for bad suite result in title
- // use escape sequences in case file gets loaded with non-utf-8-charset
- document.title = [
- ( config.stats.bad ? "\u2716" : "\u2714" ),
- document.title.replace( /^[\u2714\u2716] /i, "" )
- ].join( " " );
- }
-
- // clear own sessionStorage items if all tests passed
- if ( config.reorder && defined.sessionStorage && config.stats.bad === 0 ) {
- // `key` & `i` initialized at top of scope
- for ( i = 0; i < sessionStorage.length; i++ ) {
- key = sessionStorage.key( i++ );
- if ( key.indexOf( "qunit-test-" ) === 0 ) {
- sessionStorage.removeItem( key );
- }
- }
- }
-
- // scroll back to top to show results
- if ( window.scrollTo ) {
- window.scrollTo(0, 0);
- }
-
- runLoggingCallbacks( "done", QUnit, {
- failed: config.stats.bad,
- passed: passed,
- total: config.stats.all,
- runtime: runtime
- });
-}
-
-/** @return Boolean: true if this test should be ran */
-function validTest( test ) {
- var include,
- filter = config.filter && config.filter.toLowerCase(),
- module = config.module && config.module.toLowerCase(),
- fullName = (test.module + ": " + test.testName).toLowerCase();
-
- // Internally-generated tests are always valid
- if ( test.callback && test.callback.validTest === validTest ) {
- delete test.callback.validTest;
- return true;
- }
-
- if ( config.testNumber ) {
- return test.testNumber === config.testNumber;
- }
-
- if ( module && ( !test.module || test.module.toLowerCase() !== module ) ) {
- return false;
- }
-
- if ( !filter ) {
- return true;
- }
-
- include = filter.charAt( 0 ) !== "!";
- if ( !include ) {
- filter = filter.slice( 1 );
- }
-
- // If the filter matches, we need to honour include
- if ( fullName.indexOf( filter ) !== -1 ) {
- return include;
- }
-
- // Otherwise, do the opposite
- return !include;
-}
-
-// so far supports only Firefox, Chrome and Opera (buggy), Safari (for real exceptions)
-// Later Safari and IE10 are supposed to support error.stack as well
-// See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack
-function extractStacktrace( e, offset ) {
- offset = offset === undefined ? 3 : offset;
-
- var stack, include, i;
-
- if ( e.stacktrace ) {
- // Opera
- return e.stacktrace.split( "\n" )[ offset + 3 ];
- } else if ( e.stack ) {
- // Firefox, Chrome
- stack = e.stack.split( "\n" );
- if (/^error$/i.test( stack[0] ) ) {
- stack.shift();
- }
- if ( fileName ) {
- include = [];
- for ( i = offset; i < stack.length; i++ ) {
- if ( stack[ i ].indexOf( fileName ) !== -1 ) {
- break;
- }
- include.push( stack[ i ] );
- }
- if ( include.length ) {
- return include.join( "\n" );
- }
- }
- return stack[ offset ];
- } else if ( e.sourceURL ) {
- // Safari, PhantomJS
- // hopefully one day Safari provides actual stacktraces
- // exclude useless self-reference for generated Error objects
- if ( /qunit.js$/.test( e.sourceURL ) ) {
- return;
- }
- // for actual exceptions, this is useful
- return e.sourceURL + ":" + e.line;
- }
-}
-function sourceFromStacktrace( offset ) {
- try {
- throw new Error();
- } catch ( e ) {
- return extractStacktrace( e, offset );
- }
-}
-
-/**
- * Escape text for attribute or text content.
- */
-function escapeText( s ) {
- if ( !s ) {
- return "";
- }
- s = s + "";
- // Both single quotes and double quotes (for attributes)
- return s.replace( /['"<>&]/g, function( s ) {
- switch( s ) {
- case '\'':
- return ''';
- case '"':
- return '"';
- case '<':
- return '<';
- case '>':
- return '>';
- case '&':
- return '&';
- }
- });
-}
-
-function synchronize( callback, last ) {
- config.queue.push( callback );
-
- if ( config.autorun && !config.blocking ) {
- process( last );
- }
-}
-
-function process( last ) {
- function next() {
- process( last );
- }
- var start = new Date().getTime();
- config.depth = config.depth ? config.depth + 1 : 1;
-
- while ( config.queue.length && !config.blocking ) {
- if ( !defined.setTimeout || config.updateRate <= 0 || ( ( new Date().getTime() - start ) < config.updateRate ) ) {
- config.queue.shift()();
- } else {
- window.setTimeout( next, 13 );
- break;
- }
- }
- config.depth--;
- if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) {
- done();
- }
-}
-
-function saveGlobal() {
- config.pollution = [];
-
- if ( config.noglobals ) {
- for ( var key in window ) {
- // in Opera sometimes DOM element ids show up here, ignore them
- if ( !hasOwn.call( window, key ) || /^qunit-test-output/.test( key ) ) {
- continue;
- }
- config.pollution.push( key );
- }
- }
-}
-
-function checkPollution() {
- var newGlobals,
- deletedGlobals,
- old = config.pollution;
-
- saveGlobal();
-
- newGlobals = diff( config.pollution, old );
- if ( newGlobals.length > 0 ) {
- QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join(", ") );
- }
-
- deletedGlobals = diff( old, config.pollution );
- if ( deletedGlobals.length > 0 ) {
- QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join(", ") );
- }
-}
-
-// returns a new Array with the elements that are in a but not in b
-function diff( a, b ) {
- var i, j,
- result = a.slice();
-
- for ( i = 0; i < result.length; i++ ) {
- for ( j = 0; j < b.length; j++ ) {
- if ( result[i] === b[j] ) {
- result.splice( i, 1 );
- i--;
- break;
- }
- }
- }
- return result;
-}
-
-function extend( a, b ) {
- for ( var prop in b ) {
- if ( b[ prop ] === undefined ) {
- delete a[ prop ];
-
- // Avoid "Member not found" error in IE8 caused by setting window.constructor
- } else if ( prop !== "constructor" || a !== window ) {
- a[ prop ] = b[ prop ];
- }
- }
-
- return a;
-}
-
-/**
- * @param {HTMLElement} elem
- * @param {string} type
- * @param {Function} fn
- */
-function addEvent( elem, type, fn ) {
- // Standards-based browsers
- if ( elem.addEventListener ) {
- elem.addEventListener( type, fn, false );
- // IE
- } else {
- elem.attachEvent( "on" + type, fn );
- }
-}
-
-/**
- * @param {Array|NodeList} elems
- * @param {string} type
- * @param {Function} fn
- */
-function addEvents( elems, type, fn ) {
- var i = elems.length;
- while ( i-- ) {
- addEvent( elems[i], type, fn );
- }
-}
-
-function hasClass( elem, name ) {
- return (" " + elem.className + " ").indexOf(" " + name + " ") > -1;
-}
-
-function addClass( elem, name ) {
- if ( !hasClass( elem, name ) ) {
- elem.className += (elem.className ? " " : "") + name;
- }
-}
-
-function removeClass( elem, name ) {
- var set = " " + elem.className + " ";
- // Class name may appear multiple times
- while ( set.indexOf(" " + name + " ") > -1 ) {
- set = set.replace(" " + name + " " , " ");
- }
- // If possible, trim it for prettiness, but not neccecarily
- elem.className = window.jQuery ? jQuery.trim( set ) : ( set.trim ? set.trim() : set );
-}
-
-function id( name ) {
- return !!( typeof document !== "undefined" && document && document.getElementById ) &&
- document.getElementById( name );
-}
-
-function registerLoggingCallback( key ) {
- return function( callback ) {
- config[key].push( callback );
- };
-}
-
-// Supports deprecated method of completely overwriting logging callbacks
-function runLoggingCallbacks( key, scope, args ) {
- var i, callbacks;
- if ( QUnit.hasOwnProperty( key ) ) {
- QUnit[ key ].call(scope, args );
- } else {
- callbacks = config[ key ];
- for ( i = 0; i < callbacks.length; i++ ) {
- callbacks[ i ].call( scope, args );
- }
- }
-}
-
-// Test for equality any JavaScript type.
-// Author: Philippe Rathé
-QUnit.equiv = (function() {
-
- // Call the o related callback with the given arguments.
- function bindCallbacks( o, callbacks, args ) {
- var prop = QUnit.objectType( o );
- if ( prop ) {
- if ( QUnit.objectType( callbacks[ prop ] ) === "function" ) {
- return callbacks[ prop ].apply( callbacks, args );
- } else {
- return callbacks[ prop ]; // or undefined
- }
- }
- }
-
- // the real equiv function
- var innerEquiv,
- // stack to decide between skip/abort functions
- callers = [],
- // stack to avoiding loops from circular referencing
- parents = [],
-
- getProto = Object.getPrototypeOf || function ( obj ) {
- return obj.__proto__;
- },
- callbacks = (function () {
-
- // for string, boolean, number and null
- function useStrictEquality( b, a ) {
- /*jshint eqeqeq:false */
- if ( b instanceof a.constructor || a instanceof b.constructor ) {
- // to catch short annotaion VS 'new' annotation of a
- // declaration
- // e.g. var i = 1;
- // var j = new Number(1);
- return a == b;
- } else {
- return a === b;
- }
- }
-
- return {
- "string": useStrictEquality,
- "boolean": useStrictEquality,
- "number": useStrictEquality,
- "null": useStrictEquality,
- "undefined": useStrictEquality,
-
- "nan": function( b ) {
- return isNaN( b );
- },
-
- "date": function( b, a ) {
- return QUnit.objectType( b ) === "date" && a.valueOf() === b.valueOf();
- },
-
- "regexp": function( b, a ) {
- return QUnit.objectType( b ) === "regexp" &&
- // the regex itself
- a.source === b.source &&
- // and its modifers
- a.global === b.global &&
- // (gmi) ...
- a.ignoreCase === b.ignoreCase &&
- a.multiline === b.multiline &&
- a.sticky === b.sticky;
- },
-
- // - skip when the property is a method of an instance (OOP)
- // - abort otherwise,
- // initial === would have catch identical references anyway
- "function": function() {
- var caller = callers[callers.length - 1];
- return caller !== Object && typeof caller !== "undefined";
- },
-
- "array": function( b, a ) {
- var i, j, len, loop;
-
- // b could be an object literal here
- if ( QUnit.objectType( b ) !== "array" ) {
- return false;
- }
-
- len = a.length;
- if ( len !== b.length ) {
- // safe and faster
- return false;
- }
-
- // track reference to avoid circular references
- parents.push( a );
- for ( i = 0; i < len; i++ ) {
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- loop = true;// dont rewalk array
- }
- }
- if ( !loop && !innerEquiv(a[i], b[i]) ) {
- parents.pop();
- return false;
- }
- }
- parents.pop();
- return true;
- },
-
- "object": function( b, a ) {
- var i, j, loop,
- // Default to true
- eq = true,
- aProperties = [],
- bProperties = [];
-
- // comparing constructors is more strict than using
- // instanceof
- if ( a.constructor !== b.constructor ) {
- // Allow objects with no prototype to be equivalent to
- // objects with Object as their constructor.
- if ( !(( getProto(a) === null && getProto(b) === Object.prototype ) ||
- ( getProto(b) === null && getProto(a) === Object.prototype ) ) ) {
- return false;
- }
- }
-
- // stack constructor before traversing properties
- callers.push( a.constructor );
- // track reference to avoid circular references
- parents.push( a );
-
- for ( i in a ) { // be strict: don't ensures hasOwnProperty
- // and go deep
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- // don't go down the same path twice
- loop = true;
- }
- }
- aProperties.push(i); // collect a's properties
-
- if (!loop && !innerEquiv( a[i], b[i] ) ) {
- eq = false;
- break;
- }
- }
-
- callers.pop(); // unstack, we are done
- parents.pop();
-
- for ( i in b ) {
- bProperties.push( i ); // collect b's properties
- }
-
- // Ensures identical properties name
- return eq && innerEquiv( aProperties.sort(), bProperties.sort() );
- }
- };
- }());
-
- innerEquiv = function() { // can take multiple arguments
- var args = [].slice.apply( arguments );
- if ( args.length < 2 ) {
- return true; // end transition
- }
-
- return (function( a, b ) {
- if ( a === b ) {
- return true; // catch the most you can
- } else if ( a === null || b === null || typeof a === "undefined" ||
- typeof b === "undefined" ||
- QUnit.objectType(a) !== QUnit.objectType(b) ) {
- return false; // don't lose time with error prone cases
- } else {
- return bindCallbacks(a, callbacks, [ b, a ]);
- }
-
- // apply transition with (1..n) arguments
- }( args[0], args[1] ) && arguments.callee.apply( this, args.splice(1, args.length - 1 )) );
- };
-
- return innerEquiv;
-}());
-
-/**
- * jsDump Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com |
- * http://flesler.blogspot.com Licensed under BSD
- * (http://www.opensource.org/licenses/bsd-license.php) Date: 5/15/2008
- *
- * @projectDescription Advanced and extensible data dumping for Javascript.
- * @version 1.0.0
- * @author Ariel Flesler
- * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html}
- */
-QUnit.jsDump = (function() {
- function quote( str ) {
- return '"' + str.toString().replace( /"/g, '\\"' ) + '"';
- }
- function literal( o ) {
- return o + "";
- }
- function join( pre, arr, post ) {
- var s = jsDump.separator(),
- base = jsDump.indent(),
- inner = jsDump.indent(1);
- if ( arr.join ) {
- arr = arr.join( "," + s + inner );
- }
- if ( !arr ) {
- return pre + post;
- }
- return [ pre, inner + arr, base + post ].join(s);
- }
- function array( arr, stack ) {
- var i = arr.length, ret = new Array(i);
- this.up();
- while ( i-- ) {
- ret[i] = this.parse( arr[i] , undefined , stack);
- }
- this.down();
- return join( "[", ret, "]" );
- }
-
- var reName = /^function (\w+)/,
- jsDump = {
- // type is used mostly internally, you can fix a (custom)type in advance
- parse: function( obj, type, stack ) {
- stack = stack || [ ];
- var inStack, res,
- parser = this.parsers[ type || this.typeOf(obj) ];
-
- type = typeof parser;
- inStack = inArray( obj, stack );
-
- if ( inStack !== -1 ) {
- return "recursion(" + (inStack - stack.length) + ")";
- }
- if ( type === "function" ) {
- stack.push( obj );
- res = parser.call( this, obj, stack );
- stack.pop();
- return res;
- }
- return ( type === "string" ) ? parser : this.parsers.error;
- },
- typeOf: function( obj ) {
- var type;
- if ( obj === null ) {
- type = "null";
- } else if ( typeof obj === "undefined" ) {
- type = "undefined";
- } else if ( QUnit.is( "regexp", obj) ) {
- type = "regexp";
- } else if ( QUnit.is( "date", obj) ) {
- type = "date";
- } else if ( QUnit.is( "function", obj) ) {
- type = "function";
- } else if ( typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined" ) {
- type = "window";
- } else if ( obj.nodeType === 9 ) {
- type = "document";
- } else if ( obj.nodeType ) {
- type = "node";
- } else if (
- // native arrays
- toString.call( obj ) === "[object Array]" ||
- // NodeList objects
- ( typeof obj.length === "number" && typeof obj.item !== "undefined" && ( obj.length ? obj.item(0) === obj[0] : ( obj.item( 0 ) === null && typeof obj[0] === "undefined" ) ) )
- ) {
- type = "array";
- } else if ( obj.constructor === Error.prototype.constructor ) {
- type = "error";
- } else {
- type = typeof obj;
- }
- return type;
- },
- separator: function() {
- return this.multiline ? this.HTML ? "
" : "\n" : this.HTML ? " " : " ";
- },
- // extra can be a number, shortcut for increasing-calling-decreasing
- indent: function( extra ) {
- if ( !this.multiline ) {
- return "";
- }
- var chr = this.indentChar;
- if ( this.HTML ) {
- chr = chr.replace( /\t/g, " " ).replace( / /g, " " );
- }
- return new Array( this._depth_ + (extra||0) ).join(chr);
- },
- up: function( a ) {
- this._depth_ += a || 1;
- },
- down: function( a ) {
- this._depth_ -= a || 1;
- },
- setParser: function( name, parser ) {
- this.parsers[name] = parser;
- },
- // The next 3 are exposed so you can use them
- quote: quote,
- literal: literal,
- join: join,
- //
- _depth_: 1,
- // This is the list of parsers, to modify them, use jsDump.setParser
- parsers: {
- window: "[Window]",
- document: "[Document]",
- error: function(error) {
- return "Error(\"" + error.message + "\")";
- },
- unknown: "[Unknown]",
- "null": "null",
- "undefined": "undefined",
- "function": function( fn ) {
- var ret = "function",
- // functions never have name in IE
- name = "name" in fn ? fn.name : (reName.exec(fn) || [])[1];
-
- if ( name ) {
- ret += " " + name;
- }
- ret += "( ";
-
- ret = [ ret, QUnit.jsDump.parse( fn, "functionArgs" ), "){" ].join( "" );
- return join( ret, QUnit.jsDump.parse(fn,"functionCode" ), "}" );
- },
- array: array,
- nodelist: array,
- "arguments": array,
- object: function( map, stack ) {
- var ret = [ ], keys, key, val, i;
- QUnit.jsDump.up();
- keys = [];
- for ( key in map ) {
- keys.push( key );
- }
- keys.sort();
- for ( i = 0; i < keys.length; i++ ) {
- key = keys[ i ];
- val = map[ key ];
- ret.push( QUnit.jsDump.parse( key, "key" ) + ": " + QUnit.jsDump.parse( val, undefined, stack ) );
- }
- QUnit.jsDump.down();
- return join( "{", ret, "}" );
- },
- node: function( node ) {
- var len, i, val,
- open = QUnit.jsDump.HTML ? "<" : "<",
- close = QUnit.jsDump.HTML ? ">" : ">",
- tag = node.nodeName.toLowerCase(),
- ret = open + tag,
- attrs = node.attributes;
-
- if ( attrs ) {
- for ( i = 0, len = attrs.length; i < len; i++ ) {
- val = attrs[i].nodeValue;
- // IE6 includes all attributes in .attributes, even ones not explicitly set.
- // Those have values like undefined, null, 0, false, "" or "inherit".
- if ( val && val !== "inherit" ) {
- ret += " " + attrs[i].nodeName + "=" + QUnit.jsDump.parse( val, "attribute" );
- }
- }
- }
- ret += close;
-
- // Show content of TextNode or CDATASection
- if ( node.nodeType === 3 || node.nodeType === 4 ) {
- ret += node.nodeValue;
- }
-
- return ret + open + "/" + tag + close;
- },
- // function calls it internally, it's the arguments part of the function
- functionArgs: function( fn ) {
- var args,
- l = fn.length;
-
- if ( !l ) {
- return "";
- }
-
- args = new Array(l);
- while ( l-- ) {
- // 97 is 'a'
- args[l] = String.fromCharCode(97+l);
- }
- return " " + args.join( ", " ) + " ";
- },
- // object calls it internally, the key part of an item in a map
- key: quote,
- // function calls it internally, it's the content of the function
- functionCode: "[code]",
- // node calls it internally, it's an html attribute value
- attribute: quote,
- string: quote,
- date: quote,
- regexp: literal,
- number: literal,
- "boolean": literal
- },
- // if true, entities are escaped ( <, >, \t, space and \n )
- HTML: false,
- // indentation unit
- indentChar: " ",
- // if true, items in a collection, are separated by a \n, else just a space.
- multiline: true
- };
-
- return jsDump;
-}());
-
-// from jquery.js
-function inArray( elem, array ) {
- if ( array.indexOf ) {
- return array.indexOf( elem );
- }
-
- for ( var i = 0, length = array.length; i < length; i++ ) {
- if ( array[ i ] === elem ) {
- return i;
- }
- }
-
- return -1;
-}
-
-/*
- * Javascript Diff Algorithm
- * By John Resig (http://ejohn.org/)
- * Modified by Chu Alan "sprite"
- *
- * Released under the MIT license.
- *
- * More Info:
- * http://ejohn.org/projects/javascript-diff-algorithm/
- *
- * Usage: QUnit.diff(expected, actual)
- *
- * QUnit.diff( "the quick brown fox jumped over", "the quick fox jumps over" ) == "the quick brown fox jumped jumps over"
- */
-QUnit.diff = (function() {
- /*jshint eqeqeq:false, eqnull:true */
- function diff( o, n ) {
- var i,
- ns = {},
- os = {};
-
- for ( i = 0; i < n.length; i++ ) {
- if ( !hasOwn.call( ns, n[i] ) ) {
- ns[ n[i] ] = {
- rows: [],
- o: null
- };
- }
- ns[ n[i] ].rows.push( i );
- }
-
- for ( i = 0; i < o.length; i++ ) {
- if ( !hasOwn.call( os, o[i] ) ) {
- os[ o[i] ] = {
- rows: [],
- n: null
- };
- }
- os[ o[i] ].rows.push( i );
- }
-
- for ( i in ns ) {
- if ( !hasOwn.call( ns, i ) ) {
- continue;
- }
- if ( ns[i].rows.length === 1 && hasOwn.call( os, i ) && os[i].rows.length === 1 ) {
- n[ ns[i].rows[0] ] = {
- text: n[ ns[i].rows[0] ],
- row: os[i].rows[0]
- };
- o[ os[i].rows[0] ] = {
- text: o[ os[i].rows[0] ],
- row: ns[i].rows[0]
- };
- }
- }
-
- for ( i = 0; i < n.length - 1; i++ ) {
- if ( n[i].text != null && n[ i + 1 ].text == null && n[i].row + 1 < o.length && o[ n[i].row + 1 ].text == null &&
- n[ i + 1 ] == o[ n[i].row + 1 ] ) {
-
- n[ i + 1 ] = {
- text: n[ i + 1 ],
- row: n[i].row + 1
- };
- o[ n[i].row + 1 ] = {
- text: o[ n[i].row + 1 ],
- row: i + 1
- };
- }
- }
-
- for ( i = n.length - 1; i > 0; i-- ) {
- if ( n[i].text != null && n[ i - 1 ].text == null && n[i].row > 0 && o[ n[i].row - 1 ].text == null &&
- n[ i - 1 ] == o[ n[i].row - 1 ]) {
-
- n[ i - 1 ] = {
- text: n[ i - 1 ],
- row: n[i].row - 1
- };
- o[ n[i].row - 1 ] = {
- text: o[ n[i].row - 1 ],
- row: i - 1
- };
- }
- }
-
- return {
- o: o,
- n: n
- };
- }
-
- return function( o, n ) {
- o = o.replace( /\s+$/, "" );
- n = n.replace( /\s+$/, "" );
-
- var i, pre,
- str = "",
- out = diff( o === "" ? [] : o.split(/\s+/), n === "" ? [] : n.split(/\s+/) ),
- oSpace = o.match(/\s+/g),
- nSpace = n.match(/\s+/g);
-
- if ( oSpace == null ) {
- oSpace = [ " " ];
- }
- else {
- oSpace.push( " " );
- }
-
- if ( nSpace == null ) {
- nSpace = [ " " ];
- }
- else {
- nSpace.push( " " );
- }
-
- if ( out.n.length === 0 ) {
- for ( i = 0; i < out.o.length; i++ ) {
- str += "" + out.o[i] + oSpace[i] + "";
- }
- }
- else {
- if ( out.n[0].text == null ) {
- for ( n = 0; n < out.o.length && out.o[n].text == null; n++ ) {
- str += "" + out.o[n] + oSpace[n] + "";
- }
- }
-
- for ( i = 0; i < out.n.length; i++ ) {
- if (out.n[i].text == null) {
- str += "" + out.n[i] + nSpace[i] + "";
- }
- else {
- // `pre` initialized at top of scope
- pre = "";
-
- for ( n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++ ) {
- pre += "" + out.o[n] + oSpace[n] + "";
- }
- str += " " + out.n[i].text + nSpace[i] + pre;
- }
- }
- }
-
- return str;
- };
-}());
-
-// for CommonJS enviroments, export everything
-if ( typeof exports !== "undefined" ) {
- extend( exports, QUnit );
-}
-
-// get at whatever the global object is, like window in browsers
-}( (function() {return this;}.call()) ));
diff --git a/test/lib/require.js b/test/lib/require.js
deleted file mode 100644
index 987f865..0000000
--- a/test/lib/require.js
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- RequireJS 2.1.5 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.
- Available via the MIT or new BSD license.
- see: http://github.com/jrburke/requirejs for details
-*/
-var requirejs,require,define;
-(function(aa){function I(b){return"[object Function]"===L.call(b)}function J(b){return"[object Array]"===L.call(b)}function y(b,c){if(b){var d;for(d=0;dthis.depCount&&!this.defined){if(I(n)){if(this.events.error)try{e=i.execCb(c,n,b,e)}catch(d){a=d}else e=i.execCb(c,n,b,e);this.map.isDefine&&((b=this.module)&&void 0!==b.exports&&b.exports!==this.exports?e=b.exports:void 0===e&&this.usingExports&&(e=this.exports));if(a)return a.requireMap=this.map,a.requireModules=[this.map.id],a.requireType="define",v(this.error=
-a)}else e=n;this.exports=e;if(this.map.isDefine&&!this.ignore&&(q[c]=e,l.onResourceLoad))l.onResourceLoad(i,this.map,this.depMaps);x(c);this.defined=!0}this.defining=!1;this.defined&&!this.defineEmitted&&(this.defineEmitted=!0,this.emit("defined",this.exports),this.defineEmitComplete=!0)}}else this.fetch()}},callPlugin:function(){var a=this.map,b=a.id,d=j(a.prefix);this.depMaps.push(d);t(d,"defined",u(this,function(e){var n,d;d=this.map.name;var g=this.map.parentMap?this.map.parentMap.name:null,h=
-i.makeRequire(a.parentMap,{enableBuildCallback:!0});if(this.map.unnormalized){if(e.normalize&&(d=e.normalize(d,function(a){return c(a,g,!0)})||""),e=j(a.prefix+"!"+d,this.map.parentMap),t(e,"defined",u(this,function(a){this.init([],function(){return a},null,{enabled:!0,ignore:!0})})),d=m(p,e.id)){this.depMaps.push(e);if(this.events.error)d.on("error",u(this,function(a){this.emit("error",a)}));d.enable()}}else n=u(this,function(a){this.init([],function(){return a},null,{enabled:!0})}),n.error=u(this,
-function(a){this.inited=!0;this.error=a;a.requireModules=[b];G(p,function(a){0===a.map.id.indexOf(b+"_unnormalized")&&x(a.map.id)});v(a)}),n.fromText=u(this,function(e,c){var d=a.name,g=j(d),C=O;c&&(e=c);C&&(O=!1);r(g);s(k.config,b)&&(k.config[d]=k.config[b]);try{l.exec(e)}catch(ca){return v(B("fromtexteval","fromText eval for "+b+" failed: "+ca,ca,[b]))}C&&(O=!0);this.depMaps.push(g);i.completeLoad(d);h([d],n)}),e.load(a.name,h,n,k)}));i.enable(d,this);this.pluginMaps[d.id]=d},enable:function(){V[this.map.id]=
-this;this.enabling=this.enabled=!0;y(this.depMaps,u(this,function(a,b){var c,e;if("string"===typeof a){a=j(a,this.map.isDefine?this.map:this.map.parentMap,!1,!this.skipMap);this.depMaps[b]=a;if(c=m(N,a.id)){this.depExports[b]=c(this);return}this.depCount+=1;t(a,"defined",u(this,function(a){this.defineDep(b,a);this.check()}));this.errback&&t(a,"error",this.errback)}c=a.id;e=p[c];!s(N,c)&&(e&&!e.enabled)&&i.enable(a,this)}));G(this.pluginMaps,u(this,function(a){var b=m(p,a.id);b&&!b.enabled&&i.enable(a,
-this)}));this.enabling=!1;this.check()},on:function(a,b){var c=this.events[a];c||(c=this.events[a]=[]);c.push(b)},emit:function(a,b){y(this.events[a],function(a){a(b)});"error"===a&&delete this.events[a]}};i={config:k,contextName:b,registry:p,defined:q,urlFetched:U,defQueue:H,Module:Z,makeModuleMap:j,nextTick:l.nextTick,onError:v,configure:function(a){a.baseUrl&&"/"!==a.baseUrl.charAt(a.baseUrl.length-1)&&(a.baseUrl+="/");var b=k.pkgs,c=k.shim,e={paths:!0,config:!0,map:!0};G(a,function(a,b){e[b]?
-"map"===b?(k.map||(k.map={}),R(k[b],a,!0,!0)):R(k[b],a,!0):k[b]=a});a.shim&&(G(a.shim,function(a,b){J(a)&&(a={deps:a});if((a.exports||a.init)&&!a.exportsFn)a.exportsFn=i.makeShimExports(a);c[b]=a}),k.shim=c);a.packages&&(y(a.packages,function(a){a="string"===typeof a?{name:a}:a;b[a.name]={name:a.name,location:a.location||a.name,main:(a.main||"main").replace(ja,"").replace(ea,"")}}),k.pkgs=b);G(p,function(a,b){!a.inited&&!a.map.unnormalized&&(a.map=j(b))});if(a.deps||a.callback)i.require(a.deps||[],
-a.callback)},makeShimExports:function(a){return function(){var b;a.init&&(b=a.init.apply(aa,arguments));return b||a.exports&&ba(a.exports)}},makeRequire:function(a,f){function d(e,c,h){var g,k;f.enableBuildCallback&&(c&&I(c))&&(c.__requireJsBuild=!0);if("string"===typeof e){if(I(c))return v(B("requireargs","Invalid require call"),h);if(a&&s(N,e))return N[e](p[a.id]);if(l.get)return l.get(i,e,a,d);g=j(e,a,!1,!0);g=g.id;return!s(q,g)?v(B("notloaded",'Module name "'+g+'" has not been loaded yet for context: '+
-b+(a?"":". Use require([])"))):q[g]}L();i.nextTick(function(){L();k=r(j(null,a));k.skipMap=f.skipMap;k.init(e,c,h,{enabled:!0});D()});return d}f=f||{};R(d,{isBrowser:A,toUrl:function(b){var d,f=b.lastIndexOf("."),g=b.split("/")[0];if(-1!==f&&(!("."===g||".."===g)||1h.attachEvent.toString().indexOf("[native code"))&&!Y?(O=!0,h.attachEvent("onreadystatechange",b.onScriptLoad)):(h.addEventListener("load",b.onScriptLoad,!1),h.addEventListener("error",b.onScriptError,!1)),h.src=d,K=h,D?x.insertBefore(h,D):x.appendChild(h),K=null,h;if(da)try{importScripts(d),b.completeLoad(c)}catch(j){b.onError(B("importscripts","importScripts failed for "+c+" at "+d,j,[c]))}};A&&M(document.getElementsByTagName("script"),function(b){x||(x=
-b.parentNode);if(t=b.getAttribute("data-main"))return r.baseUrl||(E=t.split("/"),Q=E.pop(),fa=E.length?E.join("/")+"/":"./",r.baseUrl=fa,t=Q),t=t.replace(ea,""),r.deps=r.deps?r.deps.concat(t):[t],!0});define=function(b,c,d){var l,h;"string"!==typeof b&&(d=c,c=b,b=null);J(c)||(d=c,c=[]);!c.length&&I(d)&&d.length&&(d.toString().replace(la,"").replace(ma,function(b,d){c.push(d)}),c=(1===d.length?["require"]:["require","exports","module"]).concat(c));if(O){if(!(l=K))P&&"interactive"===P.readyState||M(document.getElementsByTagName("script"),
-function(b){if("interactive"===b.readyState)return P=b}),l=P;l&&(b||(b=l.getAttribute("data-requiremodule")),h=F[l.getAttribute("data-requirecontext")])}(h?h.defQueue:T).push([b,c,d])};define.amd={jQuery:!0};l.exec=function(b){return eval(b)};l(r)}})(this);
diff --git a/test/lib/resemble.js b/test/lib/resemble.js
new file mode 100644
index 0000000..1cb8c29
--- /dev/null
+++ b/test/lib/resemble.js
@@ -0,0 +1,535 @@
+/*
+Author: James Cryer
+Company: Huddle
+Last updated date: 21 Feb 2013
+URL: https://github.com/Huddle/Resemble.js
+*/
+
+(function(_this){
+ 'use strict';
+
+ _this['resemble'] = function( fileData ){
+
+ var data = {};
+ var images = [];
+ var updateCallbackArray = [];
+
+ var tolerance = { // between 0 and 255
+ red: 16,
+ green: 16,
+ blue: 16,
+ minBrightness: 16,
+ maxBrightness: 240
+ };
+
+ var ignoreAntialiasing = false;
+ var ignoreColors = false;
+
+ function triggerDataUpdate(){
+ var len = updateCallbackArray.length;
+ var i;
+ for(i=0;i tolerance.maxBrightness;
+ }
+
+ function getHue(r,g,b){
+
+ r = r / 255;
+ g = g / 255;
+ b = b / 255;
+ var max = Math.max(r, g, b), min = Math.min(r, g, b);
+ var h;
+ var d;
+
+ if (max == min){
+ h = 0; // achromatic
+ } else{
+ d = max - min;
+ switch(max){
+ case r: h = (g - b) / d + (g < b ? 6 : 0); break;
+ case g: h = (b - r) / d + 2; break;
+ case b: h = (r - g) / d + 4; break;
+ }
+ h /= 6;
+ }
+
+ return h;
+ }
+
+ function isAntialiased(sourcePix, data, cacheSet, verticalPos, horizontalPos, width){
+ var offset;
+ var targetPix;
+ var distance = 1;
+ var i;
+ var j;
+ var hasHighContrastSibling = 0;
+ var hasSiblingWithDifferentHue = 0;
+ var hasEquivilantSibling = 0;
+
+ addHueInfo(sourcePix);
+
+ for (i = distance*-1; i <= distance; i++){
+ for (j = distance*-1; j <= distance; j++){
+
+ if(i===0 && j===0){
+ // ignore source pixel
+ } else {
+
+ offset = ((verticalPos+j)*width + (horizontalPos+i)) * 4;
+ targetPix = getPixelInfo(data, offset, cacheSet);
+
+ if(targetPix === null){
+ continue;
+ }
+
+ addBrightnessInfo(targetPix);
+ addHueInfo(targetPix);
+
+ if( isContrasting(sourcePix, targetPix) ){
+ hasHighContrastSibling++;
+ }
+
+ if( isRGBSame(sourcePix,targetPix) ){
+ hasEquivilantSibling++;
+ }
+
+ if( Math.abs(targetPix.h - sourcePix.h) > 0.3 ){
+ hasSiblingWithDifferentHue++;
+ }
+
+ if( hasSiblingWithDifferentHue > 1 || hasHighContrastSibling > 1){
+ return true;
+ }
+ }
+ }
+ }
+
+ if(hasEquivilantSibling < 2){
+ return true;
+ }
+
+ return false;
+ }
+
+ function errorPixel(px, offset){
+ px[offset] = 255; //r
+ px[offset + 1] = 0; //g
+ px[offset + 2] = 255; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyPixel(px, offset, data){
+ px[offset] = data.r; //r
+ px[offset + 1] = data.g; //g
+ px[offset + 2] = data.b; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyGrayScalePixel(px, offset, data){
+ px[offset] = data.brightness; //r
+ px[offset + 1] = data.brightness; //g
+ px[offset + 2] = data.brightness; //b
+ px[offset + 3] = 255; //a
+ }
+
+
+ function getPixelInfo(data, offset, cacheSet){
+ var r;
+ var g;
+ var b;
+ var d;
+
+ if(typeof data[offset] !== 'undefined'){
+ r = data[offset];
+ g = data[offset+1];
+ b = data[offset+2];
+ d = {
+ r: r,
+ g: g,
+ b: b
+ };
+
+ return d;
+ } else {
+ return null;
+ }
+ }
+
+ function addBrightnessInfo(data){
+ data.brightness = getBrightness(data.r,data.g,data.b); // 'corrected' lightness
+ }
+
+ function addHueInfo(data){
+ data.h = getHue(data.r,data.g,data.b);
+ }
+
+ function analyseImages(img1, img2, width, height){
+
+ var hiddenCanvas = document.createElement('canvas');
+
+ var data1 = img1.data;
+ var data2 = img2.data;
+
+ hiddenCanvas.width = width;
+ hiddenCanvas.height = height;
+
+ var context = hiddenCanvas.getContext('2d');
+ var imgd = context.createImageData(width,height);
+ var targetPix = imgd.data;
+
+ var mismatchCount = 0;
+
+ var time = Date.now();
+
+ var skip;
+
+ if( (width > 1200 || height > 1200) && ignoreAntialiasing){
+ skip = 6;
+ }
+
+ loop(height, width, function(verticalPos, horizontalPos){
+
+ if(skip){ // only skip if the image isn't small
+ if(verticalPos % skip === 0 || horizontalPos % skip === 0){
+ return;
+ }
+ }
+
+ var offset = (verticalPos*width + horizontalPos) * 4;
+ var pixel1 = getPixelInfo(data1, offset, 1);
+ var pixel2 = getPixelInfo(data2, offset, 2);
+
+ if(pixel1 === null || pixel2 === null){
+ return;
+ }
+
+ if (ignoreColors){
+
+ addBrightnessInfo(pixel1);
+ addBrightnessInfo(pixel2);
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ return;
+ }
+
+ if( isRGBSimilar(pixel1, pixel2) ){
+ copyPixel(targetPix, offset, pixel2);
+
+ } else if( ignoreAntialiasing && (
+ addBrightnessInfo(pixel1), // jit pixel info augmentation looks a little weird, sorry.
+ addBrightnessInfo(pixel2),
+ isAntialiased(pixel1, data1, 1, verticalPos, horizontalPos, width) ||
+ isAntialiased(pixel2, data2, 2, verticalPos, horizontalPos, width)
+ )){
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+
+ });
+
+ data.misMatchPercentage = (mismatchCount / (height*width) * 100).toFixed(2);
+ data.analysisTime = Date.now() - time;
+
+ data.getImageDataUrl = function(text){
+ var barHeight = 0;
+
+ if(text){
+ barHeight = addLabel(text,context,hiddenCanvas);
+ }
+
+ context.putImageData(imgd, 0, barHeight);
+
+ return hiddenCanvas.toDataURL("image/png");
+ };
+ }
+
+ function addLabel(text, context, hiddenCanvas){
+ var textPadding = 2;
+
+ context.font = '12px sans-serif';
+
+ var textWidth = context.measureText(text).width + textPadding*2;
+ var barHeight = 22;
+
+ if(textWidth > hiddenCanvas.width){
+ hiddenCanvas.width = textWidth;
+ }
+
+ hiddenCanvas.height += barHeight;
+
+ context.fillStyle = "#666";
+ context.fillRect(0,0,hiddenCanvas.width,barHeight -4);
+ context.fillStyle = "#fff";
+ context.fillRect(0,barHeight -4,hiddenCanvas.width, 4);
+
+ context.fillStyle = "#fff";
+ context.textBaseline = "top";
+ context.font = '12px sans-serif';
+ context.fillText(text, textPadding, 1);
+
+ return barHeight;
+ }
+
+ function normalise(img, w, h){
+ var c;
+ var context;
+
+ if(img.height < h || img.width < w){
+ c = document.createElement('canvas');
+ c.width = w;
+ c.height = h;
+ context = c.getContext('2d');
+ context.putImageData(img, 0, 0);
+ return context.getImageData(0, 0, w, h);
+ }
+
+ return img;
+ }
+
+ function compare(one, two){
+
+ function onceWeHaveBoth(){
+ var width;
+ var height;
+ if(images.length === 2){
+ width = images[0].width > images[1].width ? images[0].width : images[1].width;
+ height = images[0].height > images[1].height ? images[0].height : images[1].height;
+
+ if( (images[0].width === images[1].width) && (images[0].height === images[1].height) ){
+ data.isSameDimensions = true;
+ } else {
+ data.isSameDimensions = false;
+ }
+
+ analyseImages( normalise(images[0],width, height), normalise(images[1],width, height), width, height);
+
+ triggerDataUpdate();
+ }
+ }
+
+ images = [];
+ loadImageData(one, onceWeHaveBoth);
+ loadImageData(two, onceWeHaveBoth);
+ }
+
+ function getCompareApi(param){
+
+ var secondFileData,
+ hasMethod = typeof param === 'function';
+
+ if( !hasMethod ){
+ // assume it's file data
+ secondFileData = param;
+ }
+
+ var self = {
+ ignoreNothing: function(){
+
+ tolerance.red = 16;
+ tolerance.green = 16;
+ tolerance.blue = 16;
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreAntialiasing: function(){
+
+ tolerance.red = 32;
+ tolerance.green = 32;
+ tolerance.blue = 32;
+ tolerance.minBrightness = 64;
+ tolerance.maxBrightness = 96;
+
+ ignoreAntialiasing = true;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreColors: function(){
+
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = true;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ onComplete: function( callback ){
+
+ updateCallbackArray.push(callback);
+
+ var wrapper = function(){
+ compare(fileData, secondFileData);
+ };
+
+ wrapper();
+
+ return getCompareApi(wrapper);
+ }
+ };
+
+ return self;
+ }
+
+ return {
+ onComplete: function( callback ){
+ updateCallbackArray.push(callback);
+ loadImageData(fileData, function(imageData, width, height){
+ parseImage(imageData.data, width, height);
+ });
+ },
+ compareTo: function(secondFileData){
+ return getCompareApi(secondFileData);
+ }
+ };
+
+ };
+}(this));
\ No newline at end of file
diff --git a/test/testsuite.js b/test/testsuite.js
deleted file mode 100644
index b486acb..0000000
--- a/test/testsuite.js
+++ /dev/null
@@ -1,36 +0,0 @@
-requirejs.config({
- baseUrl: '/test/unit/'
-});
-
-define(function(require) {
- var testModules = [
- 'Pixi',
- 'Point',
- 'Rectangle',
- 'DisplayObject',
- 'DisplayObjectContainer',
- 'Sprite',
- 'MovieClip',
- 'InteractionManager',
- 'Stage',
- 'utils/Utils',
- 'utils/EventTarget',
- 'utils/Matrix',
- 'utils/Detector',
- 'renderers/WebGLShaders',
- 'renderers/WebGLRenderer',
- 'renderers/WebGLBatch',
- 'renderers/CanvasRenderer',
- 'extras/Strip',
- 'extras/Rope',
- 'textures/BaseTexture',
- 'textures/Texture',
- 'loaders/SpriteSheetLoader',
- 'loaders/AssetLoader'
- ];
-
- // Resolve all testModules and then start the Test Runner.
- require(testModules, function() {
- QUnit.start();
- });
-});
\ No newline at end of file
diff --git a/test/textures/SpriteSheet-Aliens.png b/test/textures/SpriteSheet-Aliens.png
new file mode 100644
index 0000000..210acb1
--- /dev/null
+++ b/test/textures/SpriteSheet-Aliens.png
Binary files differ
diff --git a/test/textures/SpriteSheet-Explosion.png b/test/textures/SpriteSheet-Explosion.png
new file mode 100755
index 0000000..79e1a69
--- /dev/null
+++ b/test/textures/SpriteSheet-Explosion.png
Binary files differ
diff --git a/test/textures/bunny.png b/test/textures/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/textures/bunny.png
Binary files differ
diff --git a/test/unit/DisplayObject.js b/test/unit/DisplayObject.js
deleted file mode 100644
index 5e7e72f..0000000
--- a/test/unit/DisplayObject.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObject');
-});
diff --git a/test/unit/DisplayObjectContainer.js b/test/unit/DisplayObjectContainer.js
deleted file mode 100644
index b323959..0000000
--- a/test/unit/DisplayObjectContainer.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObjectContainer');
-});
diff --git a/test/unit/InteractionManager.js b/test/unit/InteractionManager.js
deleted file mode 100644
index e751f52..0000000
--- a/test/unit/InteractionManager.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('InteractionManager');
-});
diff --git a/test/unit/MovieClip.js b/test/unit/MovieClip.js
deleted file mode 100644
index 37d9446..0000000
--- a/test/unit/MovieClip.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('MovieClip');
-});
diff --git a/test/unit/Pixi.js b/test/unit/Pixi.js
deleted file mode 100644
index 36eee73..0000000
--- a/test/unit/Pixi.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Pixi');
-});
diff --git a/test/unit/Point.js b/test/unit/Point.js
deleted file mode 100644
index 983ff6e..0000000
--- a/test/unit/Point.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Point');
-});
diff --git a/test/unit/Rectangle.js b/test/unit/Rectangle.js
deleted file mode 100644
index 3b439ba..0000000
--- a/test/unit/Rectangle.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Rectangle');
-});
diff --git a/test/unit/Sprite.js b/test/unit/Sprite.js
deleted file mode 100644
index ed4f596..0000000
--- a/test/unit/Sprite.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Sprite');
-});
diff --git a/test/unit/Stage.js b/test/unit/Stage.js
deleted file mode 100644
index 2d70291..0000000
--- a/test/unit/Stage.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Stage');
-});
diff --git a/test/unit/extras/Rope.js b/test/unit/extras/Rope.js
deleted file mode 100644
index 5606f14..0000000
--- a/test/unit/extras/Rope.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Rope');
-});
diff --git a/test/unit/extras/Strip.js b/test/unit/extras/Strip.js
deleted file mode 100644
index 0134d3a..0000000
--- a/test/unit/extras/Strip.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Strip');
-});
diff --git a/test/unit/loaders/AssetLoader.js b/test/unit/loaders/AssetLoader.js
deleted file mode 100644
index 13b8443..0000000
--- a/test/unit/loaders/AssetLoader.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('AssetLoader');
-});
diff --git a/test/unit/loaders/SpriteSheetLoader.js b/test/unit/loaders/SpriteSheetLoader.js
deleted file mode 100644
index 8bf0cb2..0000000
--- a/test/unit/loaders/SpriteSheetLoader.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('SpriteSheetLoader');
-});
diff --git a/test/unit/pixi/InteractionManager.js b/test/unit/pixi/InteractionManager.js
new file mode 100644
index 0000000..ed3001f
--- /dev/null
+++ b/test/unit/pixi/InteractionManager.js
@@ -0,0 +1,10 @@
+describe('pixi/InteractionManager', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var InteractionManager = PIXI.InteractionManager;
+
+ it('Module exists', function () {
+ expect(InteractionManager).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/Pixi.js b/test/unit/pixi/Pixi.js
new file mode 100644
index 0000000..27debc1
--- /dev/null
+++ b/test/unit/pixi/Pixi.js
@@ -0,0 +1,9 @@
+describe('pixi/Pixi', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+
+ it('Module exists', function () {
+ expect(global).to.have.property('PIXI').and.to.be.an('object');
+ });
+});
diff --git a/test/unit/pixi/core/Circle.js b/test/unit/pixi/core/Circle.js
new file mode 100644
index 0000000..93a4456
--- /dev/null
+++ b/test/unit/pixi/core/Circle.js
@@ -0,0 +1,22 @@
+describe('pixi/core/Circle', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Circle = PIXI.Circle;
+
+ it('Module exists', function () {
+ expect(Circle).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Circle();
+
+ expect(obj).to.be.an.instanceof(Circle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', 0);
+ expect(obj).to.have.property('y', 0);
+ expect(obj).to.have.property('radius', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Ellipse.js b/test/unit/pixi/core/Ellipse.js
new file mode 100644
index 0000000..026b56f
--- /dev/null
+++ b/test/unit/pixi/core/Ellipse.js
@@ -0,0 +1,24 @@
+describe('pixi/core/Ellipse', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Ellipse = PIXI.Ellipse;
+
+ it('Module exists', function () {
+ expect(Ellipse).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Ellipse();
+
+ expect(obj).to.be.an.instanceof(Ellipse);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+ expect(obj).to.respondTo('getBounds');
+
+ expect(obj).to.have.property('x', 0);
+ expect(obj).to.have.property('y', 0);
+ expect(obj).to.have.property('width', 0);
+ expect(obj).to.have.property('height', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Matrix.js b/test/unit/pixi/core/Matrix.js
new file mode 100644
index 0000000..b48989e
--- /dev/null
+++ b/test/unit/pixi/core/Matrix.js
@@ -0,0 +1,30 @@
+describe('pixi/core/Matrix', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var mat3 = PIXI.mat3;
+ var mat4 = PIXI.mat4;
+ var Matrix = PIXI.Matrix;
+
+ it('Ensure determineMatrixArrayType works', function () {
+ expect(Matrix).to.be.a('function');
+ });
+
+ it('mat3 exists', function () {
+ expect(mat3).to.be.an('object');
+ });
+
+ it('Confirm new mat3 matrix', function () {
+ var matrix = new mat3.create();
+ pixi_core_Matrix_confirmNewMat3(matrix);
+ });
+
+ it('mat3 exists', function () {
+ expect(mat4).to.be.an('object');
+ });
+
+ it('Confirm new mat4 matrix', function () {
+ var matrix = new mat4.create();
+ pixi_core_Matrix_confirmNewMat4(matrix);
+ });
+});
diff --git a/test/unit/pixi/core/Point.js b/test/unit/pixi/core/Point.js
new file mode 100644
index 0000000..c4d5163
--- /dev/null
+++ b/test/unit/pixi/core/Point.js
@@ -0,0 +1,15 @@
+describe('pixi/core/Point', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Point = PIXI.Point;
+
+ it('Module exists', function () {
+ expect(Point).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Point();
+ pixi_core_Point_confirm(obj, 0, 0);
+ });
+});
diff --git a/test/unit/pixi/core/Polygon.js b/test/unit/pixi/core/Polygon.js
new file mode 100644
index 0000000..dc8c918
--- /dev/null
+++ b/test/unit/pixi/core/Polygon.js
@@ -0,0 +1,20 @@
+describe('pixi/core/Polygon', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Polygon = PIXI.Polygon;
+
+ it('Module exists', function () {
+ expect(Polygon).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Polygon();
+
+ expect(obj).to.be.an.instanceof(Polygon);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.deep.property('points.length', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Rectangle.js b/test/unit/pixi/core/Rectangle.js
new file mode 100644
index 0000000..d43316e
--- /dev/null
+++ b/test/unit/pixi/core/Rectangle.js
@@ -0,0 +1,15 @@
+describe('pixi/core/Rectangle', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Rectangle = PIXI.Rectangle;
+
+ it('Module exists', function () {
+ expect(Rectangle).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var rect = new Rectangle();
+ pixi_core_Rectangle_confirm(rect, 0, 0, 0, 0);
+ });
+});
diff --git a/test/unit/pixi/display/DisplayObject.js b/test/unit/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..40c6fbc
--- /dev/null
+++ b/test/unit/pixi/display/DisplayObject.js
@@ -0,0 +1,21 @@
+describe('pixi/display/DisplayObject', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var DisplayObject = PIXI.DisplayObject;
+
+ it('Module exists', function () {
+ expect(DisplayObject).to.be.a('function');
+ expect(PIXI).to.have.property('visibleCount', 0);
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new DisplayObject();
+
+ pixi_display_DisplayObject_confirmNew(obj);
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', false);
+ expect(obj).to.have.property('stage', null);
+ });
+});
diff --git a/test/unit/pixi/display/DisplayObjectContainer.js b/test/unit/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..ce7f02f
--- /dev/null
+++ b/test/unit/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,20 @@
+describe('pixi/display/DisplayObjectContainer', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var DisplayObjectContainer = PIXI.DisplayObjectContainer;
+
+ it('Module exists', function () {
+ expect(DisplayObjectContainer).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new DisplayObjectContainer();
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', false);
+ expect(obj).to.have.property('stage', null);
+ });
+});
diff --git a/test/unit/pixi/display/MovieClip.js b/test/unit/pixi/display/MovieClip.js
new file mode 100644
index 0000000..f3c6c6a
--- /dev/null
+++ b/test/unit/pixi/display/MovieClip.js
@@ -0,0 +1,33 @@
+describe('pixi/display/MovieClip', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var MovieClip = PIXI.MovieClip;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(MovieClip).to.be.a('function');
+ });
+
+ it('Confirm new instance', function (done) {
+ var texture = Texture.fromImage('/base/test/textures/SpriteSheet-Explosion.png');
+ var obj = new MovieClip([texture]);
+
+ pixi_display_Sprite_confirmNew(obj, done);
+
+ expect(obj).to.be.an.instanceof(MovieClip);
+ expect(obj).to.respondTo('stop');
+ expect(obj).to.respondTo('play');
+ expect(obj).to.respondTo('gotoAndStop');
+ expect(obj).to.respondTo('gotoAndPlay');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('textures.length', 1);
+ expect(obj).to.have.deep.property('textures[0]', texture);
+ expect(obj).to.have.property('animationSpeed', 1);
+ expect(obj).to.have.property('loop', true);
+ expect(obj).to.have.property('onComplete', null);
+ expect(obj).to.have.property('currentFrame', 0);
+ expect(obj).to.have.property('playing', false);
+ });
+});
diff --git a/test/unit/pixi/display/Sprite.js b/test/unit/pixi/display/Sprite.js
new file mode 100644
index 0000000..54e914f
--- /dev/null
+++ b/test/unit/pixi/display/Sprite.js
@@ -0,0 +1,25 @@
+describe('pixi/display/Sprite', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Sprite = PIXI.Sprite;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(Sprite).to.be.a('function');
+ expect(PIXI).to.have.deep.property('blendModes.NORMAL', 0);
+ expect(PIXI).to.have.deep.property('blendModes.SCREEN', 1);
+ });
+
+ it('Members exist', function () {
+ expect(Sprite).itself.to.respondTo('fromImage');
+ expect(Sprite).itself.to.respondTo('fromFrame');
+ });
+
+ it('Confirm new instance', function (done) {
+ var texture = Texture.fromImage('/base/test/textures/SpriteSheet-Aliens.png');
+ var obj = new Sprite(texture);
+
+ pixi_display_Sprite_confirmNew(obj, done);
+ });
+});
diff --git a/test/unit/pixi/display/Stage.js b/test/unit/pixi/display/Stage.js
new file mode 100644
index 0000000..3cc2a4d
--- /dev/null
+++ b/test/unit/pixi/display/Stage.js
@@ -0,0 +1,49 @@
+describe('pixi/display/Stage', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Stage = PIXI.Stage;
+ var InteractionManager = PIXI.InteractionManager;
+ var Rectangle = PIXI.Rectangle;
+
+ it('Module exists', function () {
+ expect(Stage).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Stage(null, true);
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(Stage);
+ expect(obj).to.respondTo('updateTransform');
+ expect(obj).to.respondTo('setBackgroundColor');
+ expect(obj).to.respondTo('getMousePosition');
+
+ // FIXME: duplicate member in DisplayObject
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ // FIXME: convert arg to bool in constructor
+ expect(obj).to.have.property('interactive', true);
+
+ expect(obj).to.have.property('interactionManager')
+ .and.to.be.an.instanceof(InteractionManager)
+ .and.to.have.property('stage', obj);
+
+ expect(obj).to.have.property('dirty', true);
+
+ expect(obj).to.have.property('stage', obj);
+
+ expect(obj).to.have.property('hitArea')
+ .and.to.be.an.instanceof(Rectangle);
+ pixi_core_Rectangle_confirm(obj.hitArea, 0, 0, 100000, 100000);
+
+ expect(obj).to.have.property('backgroundColor', 0x000000);
+ expect(obj).to.have.deep.property('backgroundColorSplit.length', 3);
+ expect(obj).to.have.deep.property('backgroundColorSplit[0]', 0);
+ expect(obj).to.have.deep.property('backgroundColorSplit[1]', 0);
+ expect(obj).to.have.deep.property('backgroundColorSplit[2]', 0);
+ expect(obj).to.have.property('backgroundColorString', '#000000');
+
+ expect(obj).to.have.property('worldVisible', true);
+ });
+});
diff --git a/test/unit/pixi/extras/CustomRenderable.js b/test/unit/pixi/extras/CustomRenderable.js
new file mode 100644
index 0000000..8d83cf0
--- /dev/null
+++ b/test/unit/pixi/extras/CustomRenderable.js
@@ -0,0 +1,21 @@
+describe('pixi/extras/CustomRenderable', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var CustomRenderable = PIXI.CustomRenderable;
+
+ it('Module exists', function () {
+ expect(CustomRenderable).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new CustomRenderable();
+
+ pixi_display_DisplayObject_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(CustomRenderable);
+ expect(obj).to.respondTo('renderCanvas');
+ expect(obj).to.respondTo('initWebGL');
+ expect(obj).to.respondTo('renderWebGL');
+ });
+});
diff --git a/test/unit/pixi/extras/Rope.js b/test/unit/pixi/extras/Rope.js
new file mode 100644
index 0000000..6ddaf83
--- /dev/null
+++ b/test/unit/pixi/extras/Rope.js
@@ -0,0 +1,26 @@
+describe('pixi/extras/Rope', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Rope = PIXI.Rope;
+ var Texture = PIXI.Texture;
+ var Point = PIXI.Point;
+
+ it('Module exists', function () {
+ expect(Rope).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var texture = Texture.fromImage('/base/test/textures/bunny.png');
+ var obj = new Rope(texture, [new Point(), new Point(5, 10), new Point(10, 20)]);
+
+ pixi_extras_Strip_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(Rope);
+ expect(obj).to.respondTo('refresh');
+ expect(obj).to.respondTo('updateTransform');
+ expect(obj).to.respondTo('setTexture');
+
+ // TODO: Test properties
+ });
+});
diff --git a/test/unit/pixi/extras/Spine.js b/test/unit/pixi/extras/Spine.js
new file mode 100644
index 0000000..0708bc0
--- /dev/null
+++ b/test/unit/pixi/extras/Spine.js
@@ -0,0 +1,10 @@
+describe('pixi/extras/Spine', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Spine = PIXI.Spine;
+
+ it('Module exists', function () {
+ expect(Spine).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/extras/Strip.js b/test/unit/pixi/extras/Strip.js
new file mode 100644
index 0000000..8e564e1
--- /dev/null
+++ b/test/unit/pixi/extras/Strip.js
@@ -0,0 +1,18 @@
+describe('pixi/extras/Strip', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Strip = PIXI.Strip;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(Strip).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var texture = Texture.fromImage('/base/test/textures/bunny.png');
+ var obj = new Strip(texture, 20, 10000);
+
+ pixi_extras_Strip_confirmNew(obj);
+ });
+});
diff --git a/test/unit/pixi/extras/TilingSprite.js b/test/unit/pixi/extras/TilingSprite.js
new file mode 100644
index 0000000..56aea14
--- /dev/null
+++ b/test/unit/pixi/extras/TilingSprite.js
@@ -0,0 +1,24 @@
+describe('pixi/extras/TilingSprite', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var TilingSprite = PIXI.TilingSprite;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(TilingSprite).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var texture = Texture.fromImage('/base/test/textures/bunny.png');
+ var obj = new TilingSprite(texture, 6000, 12000);
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(TilingSprite);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ // TODO: Test properties
+ });
+});
diff --git a/test/unit/pixi/filters/FilterBlock.js b/test/unit/pixi/filters/FilterBlock.js
new file mode 100644
index 0000000..870cec0
--- /dev/null
+++ b/test/unit/pixi/filters/FilterBlock.js
@@ -0,0 +1,10 @@
+describe('pixi/filters/FilterBlock', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var FilterBlock = PIXI.FilterBlock;
+
+ it('Module exists', function () {
+ expect(FilterBlock).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/filters/MaskFilter.js b/test/unit/pixi/filters/MaskFilter.js
new file mode 100644
index 0000000..32d6a45
--- /dev/null
+++ b/test/unit/pixi/filters/MaskFilter.js
@@ -0,0 +1,10 @@
+describe('pixi/filters/MaskFilter', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ // var MaskFilter = PIXI.MaskFilter;
+
+ // it('Module exists', function () {
+ // expect(MaskFilter).to.be.a('function');
+ // });
+});
diff --git a/test/unit/pixi/loaders/AssetLoader.js b/test/unit/pixi/loaders/AssetLoader.js
new file mode 100644
index 0000000..a0aa0b5
--- /dev/null
+++ b/test/unit/pixi/loaders/AssetLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/AssetLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var AssetLoader = PIXI.AssetLoader;
+
+ it('Module exists', function () {
+ expect(AssetLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/BitmapFontLoader.js b/test/unit/pixi/loaders/BitmapFontLoader.js
new file mode 100644
index 0000000..6253c42
--- /dev/null
+++ b/test/unit/pixi/loaders/BitmapFontLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/BitmapFontLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var BitmapFontLoader = PIXI.BitmapFontLoader;
+
+ it('Module exists', function () {
+ expect(PIXI.BitmapFontLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/ImageLoader.js b/test/unit/pixi/loaders/ImageLoader.js
new file mode 100644
index 0000000..8b1f556
--- /dev/null
+++ b/test/unit/pixi/loaders/ImageLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/ImageLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var ImageLoader = PIXI.ImageLoader;
+
+ it('Module exists', function () {
+ expect(ImageLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/JsonLoader.js b/test/unit/pixi/loaders/JsonLoader.js
new file mode 100644
index 0000000..c577e83
--- /dev/null
+++ b/test/unit/pixi/loaders/JsonLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/JsonLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var JsonLoader = PIXI.JsonLoader;
+
+ it('Module exists', function () {
+ expect(JsonLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/SpineLoader.js b/test/unit/pixi/loaders/SpineLoader.js
new file mode 100644
index 0000000..fdcc0b8
--- /dev/null
+++ b/test/unit/pixi/loaders/SpineLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/SpineLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var SpineLoader = PIXI.SpineLoader;
+
+ it('Module exists', function () {
+ expect(SpineLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/SpriteSheetLoader.js b/test/unit/pixi/loaders/SpriteSheetLoader.js
new file mode 100644
index 0000000..57beb27
--- /dev/null
+++ b/test/unit/pixi/loaders/SpriteSheetLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/SpriteSheetLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var SpriteSheetLoader = PIXI.SpriteSheetLoader;
+
+ it('Module exists', function () {
+ expect(SpriteSheetLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/primitives/Graphics.js b/test/unit/pixi/primitives/Graphics.js
new file mode 100644
index 0000000..b8b3e5c
--- /dev/null
+++ b/test/unit/pixi/primitives/Graphics.js
@@ -0,0 +1,40 @@
+describe('pixi/primitives/Graphics', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Graphics = PIXI.Graphics;
+
+ it('Module exists', function () {
+ expect(Graphics).to.be.a('function');
+
+ expect(Graphics).itself.to.have.property('POLY', 0);
+ expect(Graphics).itself.to.have.property('RECT', 1);
+ expect(Graphics).itself.to.have.property('CIRC', 2);
+ expect(Graphics).itself.to.have.property('ELIP', 3);
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Graphics();
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(Graphics);
+ expect(obj).to.respondTo('lineStyle');
+ expect(obj).to.respondTo('lineStyle');
+ expect(obj).to.respondTo('moveTo');
+ expect(obj).to.respondTo('lineTo');
+ expect(obj).to.respondTo('beginFill');
+ expect(obj).to.respondTo('endFill');
+ expect(obj).to.respondTo('drawRect');
+ expect(obj).to.respondTo('drawCircle');
+ expect(obj).to.respondTo('drawElipse');
+ expect(obj).to.respondTo('clear');
+
+ expect(obj).to.have.property('renderable', true);
+ expect(obj).to.have.property('fillAlpha', 1);
+ expect(obj).to.have.property('lineWidth', 0);
+ expect(obj).to.have.property('lineColor', 'black');
+ expect(obj).to.have.deep.property('graphicsData.length', 0);
+ expect(obj).to.have.deep.property('currentPath.points.length', 0);
+ });
+});
diff --git a/test/unit/pixi/renderers/canvas/CanvasGraphics.js b/test/unit/pixi/renderers/canvas/CanvasGraphics.js
new file mode 100644
index 0000000..8f44472
--- /dev/null
+++ b/test/unit/pixi/renderers/canvas/CanvasGraphics.js
@@ -0,0 +1,15 @@
+describe('renders/canvas/CanvasGraphics', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var CanvasGraphics = PIXI.CanvasGraphics;
+
+ it('Module exists', function () {
+ expect(CanvasGraphics).to.be.a('function');
+ });
+
+ it('Members exist', function () {
+ expect(CanvasGraphics).itself.to.respondTo('renderGraphics');
+ expect(CanvasGraphics).itself.to.respondTo('renderGraphicsMask');
+ });
+});
diff --git a/.gitignore b/.gitignore
index 12e1b62..0b88317 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
node_modules
.DS_Store
-.project
\ No newline at end of file
+.project
+*.log
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..63e4d7c
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,8 @@
+language: node_js
+node_js:
+ - 0.10
+
+before_script:
+ - npm install -g grunt-cli
+ - export DISPLAY=:99.0
+ - sh -e /etc/init.d/xvfb start
diff --git a/Gruntfile.js b/Gruntfile.js
index b083b49..103938c 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -1,10 +1,12 @@
+'use strict';
+
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-connect');
- grunt.loadNpmTasks('grunt-contrib-qunit');
grunt.loadNpmTasks('grunt-contrib-yuidoc');
+ grunt.loadTasks('tasks');
var root = 'src/pixi/',
debug = 'bin/pixi.dev.js',
@@ -79,7 +81,7 @@
},
files: {
srcBlob: '<%= dirs.src %>/**/*.js',
- testBlob: '<%= dirs.test %>/unit/**/*.js',
+ testBlob: '<%= dirs.test %>/{functional,lib/pixi,unit}/**/*.js',
build: '<%= dirs.build %>/pixi.dev.js',
buildMin: '<%= dirs.build %>/pixi.js'
},
@@ -94,7 +96,12 @@
},
jshint: {
beforeconcat: srcFiles,
- test: ['<%= files.testBlob %>'],
+ test: {
+ src: ['<%= files.testBlob %>'],
+ options: {
+ expr: true
+ }
+ },
options: {
asi: true,
smarttabs: true
@@ -128,12 +135,6 @@
]
},
connect: {
- qunit: {
- options: {
- port: grunt.option('port-test') || 9002,
- base: './'
- }
- },
test: {
options: {
port: grunt.option('port-test') || 9002,
@@ -142,13 +143,6 @@
}
}
},
- qunit: {
- all: {
- options: {
- urls: ['http://localhost:' + (grunt.option('port-test') || 9002) + '/test/index.html']
- }
- }
- },
yuidoc: {
compile: {
name: '<%= pkg.name %>',
@@ -161,6 +155,13 @@
outdir: '<%= dirs.docs %>'
}
}
+ },
+ karma: {
+ unit: {
+ configFile: 'test/karma.conf.js',
+ // browsers: ['Chrome'],
+ singleRun: true
+ }
}
});
@@ -182,9 +183,10 @@
}
)
- grunt.registerTask('default', ['concat', 'uglify', 'distribute']);
grunt.registerTask('build', ['concat', 'uglify', 'distribute']);
- grunt.registerTask('test', ['build', 'connect:qunit', 'qunit']);
+ grunt.registerTask('test', ['concat', 'jshint:test', 'karma']);
grunt.registerTask('docs', ['yuidoc']);
-
-}
\ No newline at end of file
+ grunt.registerTask('default', ['test', 'uglify', 'distribute']);
+ // Travis CI task.
+ grunt.registerTask('travis', ['test']);
+}
diff --git a/README.md b/README.md
index c62ef86..690cfe4 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,8 @@

+[](http://travis-ci.org/drkibitz/pixi.js)
+
#### JavaScript 2D Renderer ####
The aim of this project is to provide a fast lightweight 2D library that works
diff --git a/package.json b/package.json
index b373240..1246a68 100644
--- a/package.json
+++ b/package.json
@@ -18,14 +18,21 @@
"main": "bin/pixi.js",
+ "scripts": {
+ "test": "grunt travis --verbose"
+ },
+
"dependencies": {},
"devDependencies": {
"grunt": "~0.4.x",
- "grunt-contrib-jshint": "0.3.x",
+ "grunt-contrib-jshint": "0.6.x",
"grunt-contrib-uglify": "0.2.x",
- "grunt-contrib-connect": "0.2.x",
- "grunt-contrib-qunit": "0.2.x",
+ "grunt-contrib-connect": "0.3.x",
"grunt-contrib-yuidoc": "0.4.x",
- "grunt-contrib-concat": "0.1.x"
+ "grunt-contrib-concat": "0.3.x",
+ "chai": "~1.7.0",
+ "karma": "0.11.0",
+ "karma-firefox-launcher": "0.1.0",
+ "karma-mocha": "0.1.0"
}
}
diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js
index a7c520e..ee82bbd 100644
--- a/src/pixi/InteractionManager.js
+++ b/src/pixi/InteractionManager.js
@@ -62,7 +62,6 @@
this.onTouchEnd = this.onTouchEnd.bind(this);
this.onTouchMove = this.onTouchMove.bind(this);
-
this.last = 0;
}
diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js
index 1a95d20..eef1059 100644
--- a/src/pixi/core/Ellipse.js
+++ b/src/pixi/core/Ellipse.js
@@ -78,7 +78,7 @@
return (normx + normy < 0.25);
}
-PIXI.Ellipse.getBounds = function()
+PIXI.Ellipse.prototype.getBounds = function()
{
return new PIXI.Rectangle(this.x, this.y, this.width, this.height);
}
diff --git a/tasks/karma.js b/tasks/karma.js
new file mode 100644
index 0000000..c340485
--- /dev/null
+++ b/tasks/karma.js
@@ -0,0 +1,27 @@
+'use strict';
+
+var path = require('path');
+var server = require('karma').server;
+
+module.exports = function (grunt) {
+ grunt.registerMultiTask('karma', 'run karma.', function() {
+ var done = this.async();
+ var options = this.options({
+ background: false
+ });
+ var data = this.data;
+
+ //merge options onto data, with data taking precedence
+ data = grunt.util._.merge(options, data);
+ data.configFile = path.resolve(data.configFile);
+ if (data.configFile) {
+ data.configFile = grunt.template.process(data.configFile);
+ }
+
+ server.start(
+ data,
+ function(code) {
+ done(!code);
+ });
+ });
+};
diff --git a/test/functional/example-1-basics/bunny.png b/test/functional/example-1-basics/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/functional/example-1-basics/bunny.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-30.png b/test/functional/example-1-basics/frame-30.png
new file mode 100644
index 0000000..96e3409
--- /dev/null
+++ b/test/functional/example-1-basics/frame-30.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-60.png b/test/functional/example-1-basics/frame-60.png
new file mode 100644
index 0000000..af3f4ce
--- /dev/null
+++ b/test/functional/example-1-basics/frame-60.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-90.png b/test/functional/example-1-basics/frame-90.png
new file mode 100644
index 0000000..099b823
--- /dev/null
+++ b/test/functional/example-1-basics/frame-90.png
Binary files differ
diff --git a/test/functional/example-1-basics/index.js b/test/functional/example-1-basics/index.js
new file mode 100644
index 0000000..7ae7a98
--- /dev/null
+++ b/test/functional/example-1-basics/index.js
@@ -0,0 +1,133 @@
+describe('Example 1 - Basics', function () {
+ 'use strict';
+
+ var baseUri = '/base/test/functional/example-1-basics';
+ var expect = chai.expect;
+ var currentFrame = 0;
+ var frameEvents = {};
+ var stage;
+ var renderer;
+ var bunny;
+
+ function onFrame(frame, callback) {
+ frameEvents[frame] = callback;
+ }
+
+ function animate() {
+ currentFrame += 1;
+
+ requestAnimFrame( animate );
+
+ // just for fun, lets rotate mr rabbit a little
+ bunny.rotation += 0.1;
+
+ // render the stage
+ renderer.render(stage);
+
+ if (frameEvents[currentFrame])
+ frameEvents[currentFrame](currentFrame);
+ }
+
+ function initScene() {
+ // create an new instance of a pixi stage
+ stage = new PIXI.Stage(0x66FF99);
+
+ // create a renderer instance
+ renderer = PIXI.autoDetectRenderer(400, 300);
+ console.log('Is PIXI.WebGLRenderer: ' + (renderer instanceof PIXI.WebGLRenderer));
+
+ // add the renderer view element to the DOM
+ document.body.appendChild(renderer.view);
+
+ requestAnimFrame( animate );
+
+ // create a texture from an image path
+ var texture = PIXI.Texture.fromImage(baseUri + "/bunny.png");
+ // create a new Sprite using the texture
+ bunny = new PIXI.Sprite(texture);
+
+ // center the sprites anchor point
+ bunny.anchor.x = 0.5;
+ bunny.anchor.y = 0.5;
+
+ // move the sprite t the center of the screen
+ bunny.position.x = 200;
+ bunny.position.y = 150;
+
+ stage.addChild(bunny);
+ }
+
+ it('assets loaded', function (done) {
+ var loader = new PIXI.AssetLoader([
+ baseUri + '/bunny.png',
+ baseUri + '/frame-30.png',
+ baseUri + '/frame-60.png',
+ baseUri + '/frame-90.png'
+ ]);
+ // loader.on('onProgress', function (event) {
+ // console.log(event.content);
+ // });
+ loader.on('onComplete', function (event) {
+ done();
+ initScene();
+ });
+ loader.load();
+ });
+
+ it('frame 30 should match', function (done) {
+ this.timeout(700);
+ onFrame(30, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-30.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 60 should match', function (done) {
+ this.timeout(1200);
+ onFrame(60, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-60.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 90 should match', function (done) {
+ this.timeout(1700);
+ onFrame(90, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-90.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ // it('capture something', function (done) {
+ // this.timeout(2000000);
+ // onFrame(30, function () {
+ // var img = new Image();
+ // img.src = renderer.view.toDataURL('image/png');
+ // document.body.appendChild(img);
+ // });
+ // });
+});
diff --git a/test/index.html b/test/index.html
deleted file mode 100644
index 9cbcac5..0000000
--- a/test/index.html
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
- Pixi.js Test Suite
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/test/karma.conf.js b/test/karma.conf.js
new file mode 100644
index 0000000..c66a696
--- /dev/null
+++ b/test/karma.conf.js
@@ -0,0 +1,82 @@
+module.exports = function(config) {
+ config.set({
+
+ // base path, that will be used to resolve files and exclude
+ basePath : '../',
+
+ frameworks : ['mocha'],
+
+ // list of files / patterns to load in the browser
+ files : [
+ 'node_modules/chai/chai.js',
+ 'bin/pixi.dev.js',
+ 'test/lib/**/*.js',
+ 'test/unit/**/*.js',
+ // 'test/functional/**/*.js',
+ {pattern: 'test/**/*.png', watched: false, included: false, served: true}
+ ],
+
+ // list of files to exclude
+ exclude : [],
+
+ // use dolts reporter, as travis terminal does not support escaping sequences
+ // possible values: 'dots', 'progress', 'junit', 'teamcity'
+ // CLI --reporters progress
+ reporters : ['progress'],
+
+ // web server port
+ // CLI --port 9876
+ port : 9876,
+
+ // cli runner port
+ // CLI --runner-port 9100
+ runnerPort : 9100,
+
+ // enable / disable colors in the output (reporters and logs)
+ // CLI --colors --no-colors
+ colors : true,
+
+ // level of logging
+ // possible values: karma.LOG_DISABLE || karma.LOG_ERROR || karma.LOG_WARN || karma.LOG_INFO || karma.LOG_DEBUG
+ // CLI --log-level debug
+ logLevel : config.LOG_DEBUG,
+
+ // enable / disable watching file and executing tests whenever any file changes
+ // CLI --auto-watch --no-auto-watch
+ autoWatch : false,
+
+ // Start these browsers, currently available:
+ // - Chrome
+ // - ChromeCanary
+ // - Firefox
+ // - Opera
+ // - Safari (only Mac)
+ // - PhantomJS
+ // - IE (only Windows)
+ // CLI --browsers Chrome,Firefox,Safari
+ browsers : ['Firefox'],
+
+ // If browser does not capture in given timeout [ms], kill it
+ // CLI --capture-timeout 5000
+ captureTimeout : 5000,
+
+ // Auto run tests on start (when browsers are captured) and exit
+ // CLI --single-run --no-single-run
+ singleRun : true,
+
+ // report which specs are slower than 500ms
+ // CLI --report-slower-than 500
+ reportSlowerThan : 1000,
+
+ preprocessors : {
+ // '**/client/js/*.js': 'coverage'
+ },
+
+ plugins : [
+ 'karma-mocha',
+ // 'karma-chrome-launcher',
+ 'karma-firefox-launcher',
+ // 'karma-phantomjs-launcher'
+ ]
+ });
+};
diff --git a/test/lib/pixi/core/Matrix.js b/test/lib/pixi/core/Matrix.js
new file mode 100644
index 0000000..d26386b
--- /dev/null
+++ b/test/lib/pixi/core/Matrix.js
@@ -0,0 +1,40 @@
+
+function pixi_core_Matrix_confirmNewMat3(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(1);
+ expect(matrix[5]).to.equal(0);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(1);
+}
+
+function pixi_core_Matrix_confirmNewMat4(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[0]).to.equal(1);
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(0);
+ expect(matrix[5]).to.equal(1);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(0);
+ expect(matrix[9]).to.equal(0);
+ expect(matrix[10]).to.equal(1);
+ expect(matrix[11]).to.equal(0);
+ expect(matrix[12]).to.equal(0);
+ expect(matrix[13]).to.equal(0);
+ expect(matrix[14]).to.equal(0);
+ expect(matrix[15]).to.equal(1);
+}
diff --git a/test/lib/pixi/core/Point.js b/test/lib/pixi/core/Point.js
new file mode 100644
index 0000000..e5df07b
--- /dev/null
+++ b/test/lib/pixi/core/Point.js
@@ -0,0 +1,10 @@
+
+function pixi_core_Point_confirm(obj, x, y) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Point);
+ expect(obj).to.respondTo('clone');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+}
diff --git a/test/lib/pixi/core/Rectangle.js b/test/lib/pixi/core/Rectangle.js
new file mode 100644
index 0000000..23f0d12
--- /dev/null
+++ b/test/lib/pixi/core/Rectangle.js
@@ -0,0 +1,13 @@
+
+function pixi_core_Rectangle_confirm(obj, x, y, width, height) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Rectangle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+ expect(obj).to.have.property('width', width);
+ expect(obj).to.have.property('height', height);
+}
diff --git a/test/lib/pixi/display/DisplayObject.js b/test/lib/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..1388a7f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObject.js
@@ -0,0 +1,43 @@
+
+function pixi_display_DisplayObject_confirmNew(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObject);
+ expect(obj).to.respondTo('setInteractive');
+ expect(obj).to.respondTo('addFilter');
+ expect(obj).to.respondTo('removeFilter');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.property('last', obj);
+ expect(obj).to.have.property('first', obj);
+
+ expect(obj).to.contain.property('position');
+ pixi_core_Point_confirm(obj.position, 0, 0);
+ expect(obj).to.contain.property('scale');
+ pixi_core_Point_confirm(obj.scale, 1, 1);
+ expect(obj).to.contain.property('pivot');
+ pixi_core_Point_confirm(obj.pivot, 0, 0);
+
+ expect(obj).to.have.property('rotation', 0);
+ expect(obj).to.have.property('alpha', 1);
+ expect(obj).to.have.property('visible', true);
+ expect(obj).to.have.property('buttonMode', false);
+ expect(obj).to.have.property('parent', null);
+ expect(obj).to.have.property('worldAlpha', 1);
+
+ expect(obj).to.have.property('hitArea');
+ expect(obj).to.have.property('interactive'); // TODO: Have a better default value
+ expect('mask' in obj).to.be.true; // TODO: Have a better default value
+ expect(obj.mask).to.be.undefined;
+
+ expect(obj).to.have.property('renderable');
+ expect(obj).to.have.property('stage');
+
+ expect(obj).to.have.deep.property('worldTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ expect(obj).to.have.deep.property('localTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.localTransform);
+
+ expect(obj).to.have.deep.property('color.length', 0);
+ expect(obj).to.have.property('dynamic', true);
+}
diff --git a/test/lib/pixi/display/DisplayObjectContainer.js b/test/lib/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..085c59f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,16 @@
+
+function pixi_display_DisplayObjectContainer_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObject_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObjectContainer);
+ expect(obj).to.respondTo('addChild');
+ expect(obj).to.respondTo('addChildAt');
+ expect(obj).to.respondTo('swapChildren');
+ expect(obj).to.respondTo('getChildAt');
+ expect(obj).to.respondTo('removeChild');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('children.length', 0);
+}
diff --git a/test/lib/pixi/display/Sprite.js b/test/lib/pixi/display/Sprite.js
new file mode 100644
index 0000000..cc7a2d6
--- /dev/null
+++ b/test/lib/pixi/display/Sprite.js
@@ -0,0 +1,28 @@
+
+function pixi_display_Sprite_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Sprite);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', true);
+ expect(obj).to.have.property('stage', null);
+
+ expect(obj).to.have.property('anchor');
+ pixi_core_Point_confirm(obj.anchor, 0, 0);
+
+ expect(obj).to.have.property('blendMode', PIXI.blendModes.NORMAL);
+ expect(obj).to.have.property('width', 1); // TODO: is 1 expected
+ expect(obj).to.have.property('height', 1); // TODO: is 1 expected
+
+ // FIXME: Just make this a boolean that is always there
+ expect(!!obj.updateFrame).to.equal(obj.texture.baseTexture.hasLoaded);
+
+ expect(obj).to.have.property('texture');
+ pixi_textures_Texture_confirmNew(obj.texture, done);
+}
diff --git a/test/lib/pixi/extras/Strip.js b/test/lib/pixi/extras/Strip.js
new file mode 100644
index 0000000..8927a8a
--- /dev/null
+++ b/test/lib/pixi/extras/Strip.js
@@ -0,0 +1,12 @@
+
+function pixi_extras_Strip_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Strip);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ // TODO: Test properties
+}
diff --git a/test/lib/pixi/textures/Texture.js b/test/lib/pixi/textures/Texture.js
new file mode 100644
index 0000000..d5867b6
--- /dev/null
+++ b/test/lib/pixi/textures/Texture.js
@@ -0,0 +1,31 @@
+
+function pixi_textures_Texture_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ function confirmFrameDone() {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, obj.baseTexture.width, obj.baseTexture.height);
+
+ expect(obj).to.have.property('width', obj.baseTexture.width);
+ expect(obj).to.have.property('height', obj.baseTexture.height);
+ done();
+ }
+
+ expect(obj).to.be.an.instanceof(PIXI.Texture);
+ pixi_utils_EventTarget_like(obj);
+
+ expect(obj).to.have.property('baseTexture')
+ .and.to.be.an.instanceof(PIXI.BaseTexture);
+
+ expect(obj).to.have.property('scope', obj);
+
+ expect(obj).to.have.property('trim');
+ pixi_core_Point_confirm(obj.trim, 0, 0);
+
+ expect(obj).to.have.property('frame');
+ if (obj.baseTexture.hasLoaded) {
+ confirmFrameDone();
+ } else {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, 1, 1);
+ obj.addEventListener('update', confirmFrameDone);
+ }
+}
diff --git a/test/lib/pixi/utils/EventTarget.js b/test/lib/pixi/utils/EventTarget.js
new file mode 100644
index 0000000..7b1dcfa
--- /dev/null
+++ b/test/lib/pixi/utils/EventTarget.js
@@ -0,0 +1,8 @@
+
+function pixi_utils_EventTarget_like(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.respondTo('addEventListener');
+ expect(obj).to.respondTo('dispatchEvent');
+ expect(obj).to.respondTo('removeEventListener');
+}
diff --git a/test/lib/qunit-1.11.0.css b/test/lib/qunit-1.11.0.css
deleted file mode 100644
index d7fc0c8..0000000
--- a/test/lib/qunit-1.11.0.css
+++ /dev/null
@@ -1,244 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-/** Font Family and Sizes */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
- font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
-}
-
-#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
-#qunit-tests { font-size: smaller; }
-
-
-/** Resets */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter {
- margin: 0;
- padding: 0;
-}
-
-
-/** Header */
-
-#qunit-header {
- padding: 0.5em 0 0.5em 1em;
-
- color: #8699a4;
- background-color: #0d3349;
-
- font-size: 1.5em;
- line-height: 1em;
- font-weight: normal;
-
- border-radius: 5px 5px 0 0;
- -moz-border-radius: 5px 5px 0 0;
- -webkit-border-top-right-radius: 5px;
- -webkit-border-top-left-radius: 5px;
-}
-
-#qunit-header a {
- text-decoration: none;
- color: #c2ccd1;
-}
-
-#qunit-header a:hover,
-#qunit-header a:focus {
- color: #fff;
-}
-
-#qunit-testrunner-toolbar label {
- display: inline-block;
- padding: 0 .5em 0 .1em;
-}
-
-#qunit-banner {
- height: 5px;
-}
-
-#qunit-testrunner-toolbar {
- padding: 0.5em 0 0.5em 2em;
- color: #5E740B;
- background-color: #eee;
- overflow: hidden;
-}
-
-#qunit-userAgent {
- padding: 0.5em 0 0.5em 2.5em;
- background-color: #2b81af;
- color: #fff;
- text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
-}
-
-#qunit-modulefilter-container {
- float: right;
-}
-
-/** Tests: Pass/Fail */
-
-#qunit-tests {
- list-style-position: inside;
-}
-
-#qunit-tests li {
- padding: 0.4em 0.5em 0.4em 2.5em;
- border-bottom: 1px solid #fff;
- list-style-position: inside;
-}
-
-#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running {
- display: none;
-}
-
-#qunit-tests li strong {
- cursor: pointer;
-}
-
-#qunit-tests li a {
- padding: 0.5em;
- color: #c2ccd1;
- text-decoration: none;
-}
-#qunit-tests li a:hover,
-#qunit-tests li a:focus {
- color: #000;
-}
-
-#qunit-tests li .runtime {
- float: right;
- font-size: smaller;
-}
-
-.qunit-assert-list {
- margin-top: 0.5em;
- padding: 0.5em;
-
- background-color: #fff;
-
- border-radius: 5px;
- -moz-border-radius: 5px;
- -webkit-border-radius: 5px;
-}
-
-.qunit-collapsed {
- display: none;
-}
-
-#qunit-tests table {
- border-collapse: collapse;
- margin-top: .2em;
-}
-
-#qunit-tests th {
- text-align: right;
- vertical-align: top;
- padding: 0 .5em 0 0;
-}
-
-#qunit-tests td {
- vertical-align: top;
-}
-
-#qunit-tests pre {
- margin: 0;
- white-space: pre-wrap;
- word-wrap: break-word;
-}
-
-#qunit-tests del {
- background-color: #e0f2be;
- color: #374e0c;
- text-decoration: none;
-}
-
-#qunit-tests ins {
- background-color: #ffcaca;
- color: #500;
- text-decoration: none;
-}
-
-/*** Test Counts */
-
-#qunit-tests b.counts { color: black; }
-#qunit-tests b.passed { color: #5E740B; }
-#qunit-tests b.failed { color: #710909; }
-
-#qunit-tests li li {
- padding: 5px;
- background-color: #fff;
- border-bottom: none;
- list-style-position: inside;
-}
-
-/*** Passing Styles */
-
-#qunit-tests li li.pass {
- color: #3c510c;
- background-color: #fff;
- border-left: 10px solid #C6E746;
-}
-
-#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
-#qunit-tests .pass .test-name { color: #366097; }
-
-#qunit-tests .pass .test-actual,
-#qunit-tests .pass .test-expected { color: #999999; }
-
-#qunit-banner.qunit-pass { background-color: #C6E746; }
-
-/*** Failing Styles */
-
-#qunit-tests li li.fail {
- color: #710909;
- background-color: #fff;
- border-left: 10px solid #EE5757;
- white-space: pre;
-}
-
-#qunit-tests > li:last-child {
- border-radius: 0 0 5px 5px;
- -moz-border-radius: 0 0 5px 5px;
- -webkit-border-bottom-right-radius: 5px;
- -webkit-border-bottom-left-radius: 5px;
-}
-
-#qunit-tests .fail { color: #000000; background-color: #EE5757; }
-#qunit-tests .fail .test-name,
-#qunit-tests .fail .module-name { color: #000000; }
-
-#qunit-tests .fail .test-actual { color: #EE5757; }
-#qunit-tests .fail .test-expected { color: green; }
-
-#qunit-banner.qunit-fail { background-color: #EE5757; }
-
-
-/** Result */
-
-#qunit-testresult {
- padding: 0.5em 0.5em 0.5em 2.5em;
-
- color: #2b81af;
- background-color: #D2E0E6;
-
- border-bottom: 1px solid white;
-}
-#qunit-testresult .module-name {
- font-weight: bold;
-}
-
-/** Fixture */
-
-#qunit-fixture {
- position: absolute;
- top: -10000px;
- left: -10000px;
- width: 1000px;
- height: 1000px;
-}
diff --git a/test/lib/qunit-1.11.0.js b/test/lib/qunit-1.11.0.js
deleted file mode 100644
index 302545f..0000000
--- a/test/lib/qunit-1.11.0.js
+++ /dev/null
@@ -1,2152 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-(function( window ) {
-
-var QUnit,
- assert,
- config,
- onErrorFnPrev,
- testId = 0,
- fileName = (sourceFromStacktrace( 0 ) || "" ).replace(/(:\d+)+\)?/, "").replace(/.+\//, ""),
- toString = Object.prototype.toString,
- hasOwn = Object.prototype.hasOwnProperty,
- // Keep a local reference to Date (GH-283)
- Date = window.Date,
- defined = {
- setTimeout: typeof window.setTimeout !== "undefined",
- sessionStorage: (function() {
- var x = "qunit-test-string";
- try {
- sessionStorage.setItem( x, x );
- sessionStorage.removeItem( x );
- return true;
- } catch( e ) {
- return false;
- }
- }())
- },
- /**
- * Provides a normalized error string, correcting an issue
- * with IE 7 (and prior) where Error.prototype.toString is
- * not properly implemented
- *
- * Based on http://es5.github.com/#x15.11.4.4
- *
- * @param {String|Error} error
- * @return {String} error message
- */
- errorString = function( error ) {
- var name, message,
- errorString = error.toString();
- if ( errorString.substring( 0, 7 ) === "[object" ) {
- name = error.name ? error.name.toString() : "Error";
- message = error.message ? error.message.toString() : "";
- if ( name && message ) {
- return name + ": " + message;
- } else if ( name ) {
- return name;
- } else if ( message ) {
- return message;
- } else {
- return "Error";
- }
- } else {
- return errorString;
- }
- },
- /**
- * Makes a clone of an object using only Array or Object as base,
- * and copies over the own enumerable properties.
- *
- * @param {Object} obj
- * @return {Object} New object with only the own properties (recursively).
- */
- objectValues = function( obj ) {
- // Grunt 0.3.x uses an older version of jshint that still has jshint/jshint#392.
- /*jshint newcap: false */
- var key, val,
- vals = QUnit.is( "array", obj ) ? [] : {};
- for ( key in obj ) {
- if ( hasOwn.call( obj, key ) ) {
- val = obj[key];
- vals[key] = val === Object(val) ? objectValues(val) : val;
- }
- }
- return vals;
- };
-
-function Test( settings ) {
- extend( this, settings );
- this.assertions = [];
- this.testNumber = ++Test.count;
-}
-
-Test.count = 0;
-
-Test.prototype = {
- init: function() {
- var a, b, li,
- tests = id( "qunit-tests" );
-
- if ( tests ) {
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml;
-
- // `a` initialized at top of scope
- a = document.createElement( "a" );
- a.innerHTML = "Rerun";
- a.href = QUnit.url({ testNumber: this.testNumber });
-
- li = document.createElement( "li" );
- li.appendChild( b );
- li.appendChild( a );
- li.className = "running";
- li.id = this.id = "qunit-test-output" + testId++;
-
- tests.appendChild( li );
- }
- },
- setup: function() {
- if ( this.module !== config.previousModule ) {
- if ( config.previousModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.previousModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
- config.previousModule = this.module;
- config.moduleStats = { all: 0, bad: 0 };
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- } else if ( config.autorun ) {
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- }
-
- config.current = this;
-
- this.testEnvironment = extend({
- setup: function() {},
- teardown: function() {}
- }, this.moduleTestEnvironment );
-
- this.started = +new Date();
- runLoggingCallbacks( "testStart", QUnit, {
- name: this.testName,
- module: this.module
- });
-
- // allow utility functions to access the current test environment
- // TODO why??
- QUnit.current_testEnvironment = this.testEnvironment;
-
- if ( !config.pollution ) {
- saveGlobal();
- }
- if ( config.notrycatch ) {
- this.testEnvironment.setup.call( this.testEnvironment );
- return;
- }
- try {
- this.testEnvironment.setup.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Setup failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- },
- run: function() {
- config.current = this;
-
- var running = id( "qunit-testresult" );
-
- if ( running ) {
- running.innerHTML = "Running:
" + this.nameHtml;
- }
-
- if ( this.async ) {
- QUnit.stop();
- }
-
- this.callbackStarted = +new Date();
-
- if ( config.notrycatch ) {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- return;
- }
-
- try {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- } catch( e ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
-
- QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + " " + this.stack + ": " + ( e.message || e ), extractStacktrace( e, 0 ) );
- // else next test will carry the responsibility
- saveGlobal();
-
- // Restart the tests if they're blocking
- if ( config.blocking ) {
- QUnit.start();
- }
- }
- },
- teardown: function() {
- config.current = this;
- if ( config.notrycatch ) {
- if ( typeof this.callbackRuntime === "undefined" ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
- }
- this.testEnvironment.teardown.call( this.testEnvironment );
- return;
- } else {
- try {
- this.testEnvironment.teardown.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Teardown failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- }
- checkPollution();
- },
- finish: function() {
- config.current = this;
- if ( config.requireExpects && this.expected === null ) {
- QUnit.pushFailure( "Expected number of assertions to be defined, but expect() was not called.", this.stack );
- } else if ( this.expected !== null && this.expected !== this.assertions.length ) {
- QUnit.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack );
- } else if ( this.expected === null && !this.assertions.length ) {
- QUnit.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions.", this.stack );
- }
-
- var i, assertion, a, b, time, li, ol,
- test = this,
- good = 0,
- bad = 0,
- tests = id( "qunit-tests" );
-
- this.runtime = +new Date() - this.started;
- config.stats.all += this.assertions.length;
- config.moduleStats.all += this.assertions.length;
-
- if ( tests ) {
- ol = document.createElement( "ol" );
- ol.className = "qunit-assert-list";
-
- for ( i = 0; i < this.assertions.length; i++ ) {
- assertion = this.assertions[i];
-
- li = document.createElement( "li" );
- li.className = assertion.result ? "pass" : "fail";
- li.innerHTML = assertion.message || ( assertion.result ? "okay" : "failed" );
- ol.appendChild( li );
-
- if ( assertion.result ) {
- good++;
- } else {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
-
- // store result when possible
- if ( QUnit.config.reorder && defined.sessionStorage ) {
- if ( bad ) {
- sessionStorage.setItem( "qunit-test-" + this.module + "-" + this.testName, bad );
- } else {
- sessionStorage.removeItem( "qunit-test-" + this.module + "-" + this.testName );
- }
- }
-
- if ( bad === 0 ) {
- addClass( ol, "qunit-collapsed" );
- }
-
- // `b` initialized at top of scope
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml + " (" + bad + ", " + good + ", " + this.assertions.length + ")";
-
- addEvent(b, "click", function() {
- var next = b.parentNode.lastChild,
- collapsed = hasClass( next, "qunit-collapsed" );
- ( collapsed ? removeClass : addClass )( next, "qunit-collapsed" );
- });
-
- addEvent(b, "dblclick", function( e ) {
- var target = e && e.target ? e.target : window.event.srcElement;
- if ( target.nodeName.toLowerCase() === "span" || target.nodeName.toLowerCase() === "b" ) {
- target = target.parentNode;
- }
- if ( window.location && target.nodeName.toLowerCase() === "strong" ) {
- window.location = QUnit.url({ testNumber: test.testNumber });
- }
- });
-
- // `time` initialized at top of scope
- time = document.createElement( "span" );
- time.className = "runtime";
- time.innerHTML = this.runtime + " ms";
-
- // `li` initialized at top of scope
- li = id( this.id );
- li.className = bad ? "fail" : "pass";
- li.removeChild( li.firstChild );
- a = li.firstChild;
- li.appendChild( b );
- li.appendChild( a );
- li.appendChild( time );
- li.appendChild( ol );
-
- } else {
- for ( i = 0; i < this.assertions.length; i++ ) {
- if ( !this.assertions[i].result ) {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
- }
-
- runLoggingCallbacks( "testDone", QUnit, {
- name: this.testName,
- module: this.module,
- failed: bad,
- passed: this.assertions.length - bad,
- total: this.assertions.length,
- duration: this.runtime
- });
-
- QUnit.reset();
-
- config.current = undefined;
- },
-
- queue: function() {
- var bad,
- test = this;
-
- synchronize(function() {
- test.init();
- });
- function run() {
- // each of these can by async
- synchronize(function() {
- test.setup();
- });
- synchronize(function() {
- test.run();
- });
- synchronize(function() {
- test.teardown();
- });
- synchronize(function() {
- test.finish();
- });
- }
-
- // `bad` initialized at top of scope
- // defer when previous test run passed, if storage is available
- bad = QUnit.config.reorder && defined.sessionStorage &&
- +sessionStorage.getItem( "qunit-test-" + this.module + "-" + this.testName );
-
- if ( bad ) {
- run();
- } else {
- synchronize( run, true );
- }
- }
-};
-
-// Root QUnit object.
-// `QUnit` initialized at top of scope
-QUnit = {
-
- // call on start of module test to prepend name to all tests
- module: function( name, testEnvironment ) {
- config.currentModule = name;
- config.currentModuleTestEnvironment = testEnvironment;
- config.modules[name] = true;
- },
-
- asyncTest: function( testName, expected, callback ) {
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- QUnit.test( testName, expected, callback, true );
- },
-
- test: function( testName, expected, callback, async ) {
- var test,
- nameHtml = "" + escapeText( testName ) + "";
-
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- if ( config.currentModule ) {
- nameHtml = "" + escapeText( config.currentModule ) + ": " + nameHtml;
- }
-
- test = new Test({
- nameHtml: nameHtml,
- testName: testName,
- expected: expected,
- async: async,
- callback: callback,
- module: config.currentModule,
- moduleTestEnvironment: config.currentModuleTestEnvironment,
- stack: sourceFromStacktrace( 2 )
- });
-
- if ( !validTest( test ) ) {
- return;
- }
-
- test.queue();
- },
-
- // Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through.
- expect: function( asserts ) {
- if (arguments.length === 1) {
- config.current.expected = asserts;
- } else {
- return config.current.expected;
- }
- },
-
- start: function( count ) {
- // QUnit hasn't been initialized yet.
- // Note: RequireJS (et al) may delay onLoad
- if ( config.semaphore === undefined ) {
- QUnit.begin(function() {
- // This is triggered at the top of QUnit.load, push start() to the event loop, to allow QUnit.load to finish first
- setTimeout(function() {
- QUnit.start( count );
- });
- });
- return;
- }
-
- config.semaphore -= count || 1;
- // don't start until equal number of stop-calls
- if ( config.semaphore > 0 ) {
- return;
- }
- // ignore if start is called more often then stop
- if ( config.semaphore < 0 ) {
- config.semaphore = 0;
- QUnit.pushFailure( "Called start() while already started (QUnit.config.semaphore was 0 already)", null, sourceFromStacktrace(2) );
- return;
- }
- // A slight delay, to avoid any current callbacks
- if ( defined.setTimeout ) {
- window.setTimeout(function() {
- if ( config.semaphore > 0 ) {
- return;
- }
- if ( config.timeout ) {
- clearTimeout( config.timeout );
- }
-
- config.blocking = false;
- process( true );
- }, 13);
- } else {
- config.blocking = false;
- process( true );
- }
- },
-
- stop: function( count ) {
- config.semaphore += count || 1;
- config.blocking = true;
-
- if ( config.testTimeout && defined.setTimeout ) {
- clearTimeout( config.timeout );
- config.timeout = window.setTimeout(function() {
- QUnit.ok( false, "Test timed out" );
- config.semaphore = 1;
- QUnit.start();
- }, config.testTimeout );
- }
- }
-};
-
-// `assert` initialized at top of scope
-// Asssert helpers
-// All of these must either call QUnit.push() or manually do:
-// - runLoggingCallbacks( "log", .. );
-// - config.current.assertions.push({ .. });
-// We attach it to the QUnit object *after* we expose the public API,
-// otherwise `assert` will become a global variable in browsers (#341).
-assert = {
- /**
- * Asserts rough true-ish result.
- * @name ok
- * @function
- * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" );
- */
- ok: function( result, msg ) {
- if ( !config.current ) {
- throw new Error( "ok() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
- result = !!result;
-
- var source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: msg
- };
-
- msg = escapeText( msg || (result ? "okay" : "failed" ) );
- msg = "" + msg + "";
-
- if ( !result ) {
- source = sourceFromStacktrace( 2 );
- if ( source ) {
- details.source = source;
- msg += "Source: | " + escapeText( source ) + " |
---|
";
- }
- }
- runLoggingCallbacks( "log", QUnit, details );
- config.current.assertions.push({
- result: result,
- message: msg
- });
- },
-
- /**
- * Assert that the first two arguments are equal, with an optional message.
- * Prints out both actual and expected values.
- * @name equal
- * @function
- * @example equal( format( "Received {0} bytes.", 2), "Received 2 bytes.", "format() replaces {0} with next argument" );
- */
- equal: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected == actual, actual, expected, message );
- },
-
- /**
- * @name notEqual
- * @function
- */
- notEqual: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected != actual, actual, expected, message );
- },
-
- /**
- * @name propEqual
- * @function
- */
- propEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notPropEqual
- * @function
- */
- notPropEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name deepEqual
- * @function
- */
- deepEqual: function( actual, expected, message ) {
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notDeepEqual
- * @function
- */
- notDeepEqual: function( actual, expected, message ) {
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name strictEqual
- * @function
- */
- strictEqual: function( actual, expected, message ) {
- QUnit.push( expected === actual, actual, expected, message );
- },
-
- /**
- * @name notStrictEqual
- * @function
- */
- notStrictEqual: function( actual, expected, message ) {
- QUnit.push( expected !== actual, actual, expected, message );
- },
-
- "throws": function( block, expected, message ) {
- var actual,
- expectedOutput = expected,
- ok = false;
-
- // 'expected' is optional
- if ( typeof expected === "string" ) {
- message = expected;
- expected = null;
- }
-
- config.current.ignoreGlobalErrors = true;
- try {
- block.call( config.current.testEnvironment );
- } catch (e) {
- actual = e;
- }
- config.current.ignoreGlobalErrors = false;
-
- if ( actual ) {
- // we don't want to validate thrown error
- if ( !expected ) {
- ok = true;
- expectedOutput = null;
- // expected is a regexp
- } else if ( QUnit.objectType( expected ) === "regexp" ) {
- ok = expected.test( errorString( actual ) );
- // expected is a constructor
- } else if ( actual instanceof expected ) {
- ok = true;
- // expected is a validation function which returns true is validation passed
- } else if ( expected.call( {}, actual ) === true ) {
- expectedOutput = null;
- ok = true;
- }
-
- QUnit.push( ok, actual, expectedOutput, message );
- } else {
- QUnit.pushFailure( message, null, 'No exception was thrown.' );
- }
- }
-};
-
-/**
- * @deprecate since 1.8.0
- * Kept assertion helpers in root for backwards compatibility.
- */
-extend( QUnit, assert );
-
-/**
- * @deprecated since 1.9.0
- * Kept root "raises()" for backwards compatibility.
- * (Note that we don't introduce assert.raises).
- */
-QUnit.raises = assert[ "throws" ];
-
-/**
- * @deprecated since 1.0.0, replaced with error pushes since 1.3.0
- * Kept to avoid TypeErrors for undefined methods.
- */
-QUnit.equals = function() {
- QUnit.push( false, false, false, "QUnit.equals has been deprecated since 2009 (e88049a0), use QUnit.equal instead" );
-};
-QUnit.same = function() {
- QUnit.push( false, false, false, "QUnit.same has been deprecated since 2009 (e88049a0), use QUnit.deepEqual instead" );
-};
-
-// We want access to the constructor's prototype
-(function() {
- function F() {}
- F.prototype = QUnit;
- QUnit = new F();
- // Make F QUnit's constructor so that we can add to the prototype later
- QUnit.constructor = F;
-}());
-
-/**
- * Config object: Maintain internal state
- * Later exposed as QUnit.config
- * `config` initialized at top of scope
- */
-config = {
- // The queue of tests to run
- queue: [],
-
- // block until document ready
- blocking: true,
-
- // when enabled, show only failing tests
- // gets persisted through sessionStorage and can be changed in UI via checkbox
- hidepassed: false,
-
- // by default, run previously failed tests first
- // very useful in combination with "Hide passed tests" checked
- reorder: true,
-
- // by default, modify document.title when suite is done
- altertitle: true,
-
- // when enabled, all tests must call expect()
- requireExpects: false,
-
- // add checkboxes that are persisted in the query-string
- // when enabled, the id is set to `true` as a `QUnit.config` property
- urlConfig: [
- {
- id: "noglobals",
- label: "Check for Globals",
- tooltip: "Enabling this will test if any test introduces new properties on the `window` object. Stored as query-strings."
- },
- {
- id: "notrycatch",
- label: "No try-catch",
- tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging exceptions in IE reasonable. Stored as query-strings."
- }
- ],
-
- // Set of all modules.
- modules: {},
-
- // logging callback queues
- begin: [],
- done: [],
- log: [],
- testStart: [],
- testDone: [],
- moduleStart: [],
- moduleDone: []
-};
-
-// Export global variables, unless an 'exports' object exists,
-// in that case we assume we're in CommonJS (dealt with on the bottom of the script)
-if ( typeof exports === "undefined" ) {
- extend( window, QUnit );
-
- // Expose QUnit object
- window.QUnit = QUnit;
-}
-
-// Initialize more QUnit.config and QUnit.urlParams
-(function() {
- var i,
- location = window.location || { search: "", protocol: "file:" },
- params = location.search.slice( 1 ).split( "&" ),
- length = params.length,
- urlParams = {},
- current;
-
- if ( params[ 0 ] ) {
- for ( i = 0; i < length; i++ ) {
- current = params[ i ].split( "=" );
- current[ 0 ] = decodeURIComponent( current[ 0 ] );
- // allow just a key to turn on a flag, e.g., test.html?noglobals
- current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true;
- urlParams[ current[ 0 ] ] = current[ 1 ];
- }
- }
-
- QUnit.urlParams = urlParams;
-
- // String search anywhere in moduleName+testName
- config.filter = urlParams.filter;
-
- // Exact match of the module name
- config.module = urlParams.module;
-
- config.testNumber = parseInt( urlParams.testNumber, 10 ) || null;
-
- // Figure out if we're running the tests from a server or not
- QUnit.isLocal = location.protocol === "file:";
-}());
-
-// Extend QUnit object,
-// these after set here because they should not be exposed as global functions
-extend( QUnit, {
- assert: assert,
-
- config: config,
-
- // Initialize the configuration options
- init: function() {
- extend( config, {
- stats: { all: 0, bad: 0 },
- moduleStats: { all: 0, bad: 0 },
- started: +new Date(),
- updateRate: 1000,
- blocking: false,
- autostart: true,
- autorun: false,
- filter: "",
- queue: [],
- semaphore: 1
- });
-
- var tests, banner, result,
- qunit = id( "qunit" );
-
- if ( qunit ) {
- qunit.innerHTML =
- "" +
- "" +
- "" +
- "" +
- "
";
- }
-
- tests = id( "qunit-tests" );
- banner = id( "qunit-banner" );
- result = id( "qunit-testresult" );
-
- if ( tests ) {
- tests.innerHTML = "";
- }
-
- if ( banner ) {
- banner.className = "";
- }
-
- if ( result ) {
- result.parentNode.removeChild( result );
- }
-
- if ( tests ) {
- result = document.createElement( "p" );
- result.id = "qunit-testresult";
- result.className = "result";
- tests.parentNode.insertBefore( result, tests );
- result.innerHTML = "Running...
";
- }
- },
-
- // Resets the test setup. Useful for tests that modify the DOM.
- reset: function() {
- var fixture = id( "qunit-fixture" );
- if ( fixture ) {
- fixture.innerHTML = config.fixture;
- }
- },
-
- // Trigger an event on an element.
- // @example triggerEvent( document.body, "click" );
- triggerEvent: function( elem, type, event ) {
- if ( document.createEvent ) {
- event = document.createEvent( "MouseEvents" );
- event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView,
- 0, 0, 0, 0, 0, false, false, false, false, 0, null);
-
- elem.dispatchEvent( event );
- } else if ( elem.fireEvent ) {
- elem.fireEvent( "on" + type );
- }
- },
-
- // Safe object type checking
- is: function( type, obj ) {
- return QUnit.objectType( obj ) === type;
- },
-
- objectType: function( obj ) {
- if ( typeof obj === "undefined" ) {
- return "undefined";
- // consider: typeof null === object
- }
- if ( obj === null ) {
- return "null";
- }
-
- var match = toString.call( obj ).match(/^\[object\s(.*)\]$/),
- type = match && match[1] || "";
-
- switch ( type ) {
- case "Number":
- if ( isNaN(obj) ) {
- return "nan";
- }
- return "number";
- case "String":
- case "Boolean":
- case "Array":
- case "Date":
- case "RegExp":
- case "Function":
- return type.toLowerCase();
- }
- if ( typeof obj === "object" ) {
- return "object";
- }
- return undefined;
- },
-
- push: function( result, actual, expected, message ) {
- if ( !config.current ) {
- throw new Error( "assertion outside test context, was " + sourceFromStacktrace() );
- }
-
- var output, source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: message,
- actual: actual,
- expected: expected
- };
-
- message = escapeText( message ) || ( result ? "okay" : "failed" );
- message = "" + message + "";
- output = message;
-
- if ( !result ) {
- expected = escapeText( QUnit.jsDump.parse(expected) );
- actual = escapeText( QUnit.jsDump.parse(actual) );
- output += "Expected: | " + expected + " |
";
-
- if ( actual !== expected ) {
- output += "Result: | " + actual + " |
";
- output += "Diff: | " + QUnit.diff( expected, actual ) + " |
";
- }
-
- source = sourceFromStacktrace();
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
- }
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: !!result,
- message: output
- });
- },
-
- pushFailure: function( message, source, actual ) {
- if ( !config.current ) {
- throw new Error( "pushFailure() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
-
- var output,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: false,
- message: message
- };
-
- message = escapeText( message ) || "error";
- message = "" + message + "";
- output = message;
-
- output += "";
-
- if ( actual ) {
- output += "Result: | " + escapeText( actual ) + " |
";
- }
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: false,
- message: output
- });
- },
-
- url: function( params ) {
- params = extend( extend( {}, QUnit.urlParams ), params );
- var key,
- querystring = "?";
-
- for ( key in params ) {
- if ( !hasOwn.call( params, key ) ) {
- continue;
- }
- querystring += encodeURIComponent( key ) + "=" +
- encodeURIComponent( params[ key ] ) + "&";
- }
- return window.location.protocol + "//" + window.location.host +
- window.location.pathname + querystring.slice( 0, -1 );
- },
-
- extend: extend,
- id: id,
- addEvent: addEvent
- // load, equiv, jsDump, diff: Attached later
-});
-
-/**
- * @deprecated: Created for backwards compatibility with test runner that set the hook function
- * into QUnit.{hook}, instead of invoking it and passing the hook function.
- * QUnit.constructor is set to the empty F() above so that we can add to it's prototype here.
- * Doing this allows us to tell if the following methods have been overwritten on the actual
- * QUnit object.
- */
-extend( QUnit.constructor.prototype, {
-
- // Logging callbacks; all receive a single argument with the listed properties
- // run test/logs.html for any related changes
- begin: registerLoggingCallback( "begin" ),
-
- // done: { failed, passed, total, runtime }
- done: registerLoggingCallback( "done" ),
-
- // log: { result, actual, expected, message }
- log: registerLoggingCallback( "log" ),
-
- // testStart: { name }
- testStart: registerLoggingCallback( "testStart" ),
-
- // testDone: { name, failed, passed, total, duration }
- testDone: registerLoggingCallback( "testDone" ),
-
- // moduleStart: { name }
- moduleStart: registerLoggingCallback( "moduleStart" ),
-
- // moduleDone: { name, failed, passed, total }
- moduleDone: registerLoggingCallback( "moduleDone" )
-});
-
-if ( typeof document === "undefined" || document.readyState === "complete" ) {
- config.autorun = true;
-}
-
-QUnit.load = function() {
- runLoggingCallbacks( "begin", QUnit, {} );
-
- // Initialize the config, saving the execution queue
- var banner, filter, i, label, len, main, ol, toolbar, userAgent, val,
- urlConfigCheckboxesContainer, urlConfigCheckboxes, moduleFilter,
- numModules = 0,
- moduleFilterHtml = "",
- urlConfigHtml = "",
- oldconfig = extend( {}, config );
-
- QUnit.init();
- extend(config, oldconfig);
-
- config.blocking = false;
-
- len = config.urlConfig.length;
-
- for ( i = 0; i < len; i++ ) {
- val = config.urlConfig[i];
- if ( typeof val === "string" ) {
- val = {
- id: val,
- label: val,
- tooltip: "[no tooltip available]"
- };
- }
- config[ val.id ] = QUnit.urlParams[ val.id ];
- urlConfigHtml += "";
- }
-
- moduleFilterHtml += "";
-
- // `userAgent` initialized at top of scope
- userAgent = id( "qunit-userAgent" );
- if ( userAgent ) {
- userAgent.innerHTML = navigator.userAgent;
- }
-
- // `banner` initialized at top of scope
- banner = id( "qunit-header" );
- if ( banner ) {
- banner.innerHTML = "" + banner.innerHTML + " ";
- }
-
- // `toolbar` initialized at top of scope
- toolbar = id( "qunit-testrunner-toolbar" );
- if ( toolbar ) {
- // `filter` initialized at top of scope
- filter = document.createElement( "input" );
- filter.type = "checkbox";
- filter.id = "qunit-filter-pass";
-
- addEvent( filter, "click", function() {
- var tmp,
- ol = document.getElementById( "qunit-tests" );
-
- if ( filter.checked ) {
- ol.className = ol.className + " hidepass";
- } else {
- tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " ";
- ol.className = tmp.replace( / hidepass /, " " );
- }
- if ( defined.sessionStorage ) {
- if (filter.checked) {
- sessionStorage.setItem( "qunit-filter-passed-tests", "true" );
- } else {
- sessionStorage.removeItem( "qunit-filter-passed-tests" );
- }
- }
- });
-
- if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem( "qunit-filter-passed-tests" ) ) {
- filter.checked = true;
- // `ol` initialized at top of scope
- ol = document.getElementById( "qunit-tests" );
- ol.className = ol.className + " hidepass";
- }
- toolbar.appendChild( filter );
-
- // `label` initialized at top of scope
- label = document.createElement( "label" );
- label.setAttribute( "for", "qunit-filter-pass" );
- label.setAttribute( "title", "Only show tests and assertons that fail. Stored in sessionStorage." );
- label.innerHTML = "Hide passed tests";
- toolbar.appendChild( label );
-
- urlConfigCheckboxesContainer = document.createElement("span");
- urlConfigCheckboxesContainer.innerHTML = urlConfigHtml;
- urlConfigCheckboxes = urlConfigCheckboxesContainer.getElementsByTagName("input");
- // For oldIE support:
- // * Add handlers to the individual elements instead of the container
- // * Use "click" instead of "change"
- // * Fallback from event.target to event.srcElement
- addEvents( urlConfigCheckboxes, "click", function( event ) {
- var params = {},
- target = event.target || event.srcElement;
- params[ target.name ] = target.checked ? true : undefined;
- window.location = QUnit.url( params );
- });
- toolbar.appendChild( urlConfigCheckboxesContainer );
-
- if (numModules > 1) {
- moduleFilter = document.createElement( 'span' );
- moduleFilter.setAttribute( 'id', 'qunit-modulefilter-container' );
- moduleFilter.innerHTML = moduleFilterHtml;
- addEvent( moduleFilter.lastChild, "change", function() {
- var selectBox = moduleFilter.getElementsByTagName("select")[0],
- selectedModule = decodeURIComponent(selectBox.options[selectBox.selectedIndex].value);
-
- window.location = QUnit.url( { module: ( selectedModule === "" ) ? undefined : selectedModule } );
- });
- toolbar.appendChild(moduleFilter);
- }
- }
-
- // `main` initialized at top of scope
- main = id( "qunit-fixture" );
- if ( main ) {
- config.fixture = main.innerHTML;
- }
-
- if ( config.autostart ) {
- QUnit.start();
- }
-};
-
-addEvent( window, "load", QUnit.load );
-
-// `onErrorFnPrev` initialized at top of scope
-// Preserve other handlers
-onErrorFnPrev = window.onerror;
-
-// Cover uncaught exceptions
-// Returning true will surpress the default browser handler,
-// returning false will let it run.
-window.onerror = function ( error, filePath, linerNr ) {
- var ret = false;
- if ( onErrorFnPrev ) {
- ret = onErrorFnPrev( error, filePath, linerNr );
- }
-
- // Treat return value as window.onerror itself does,
- // Only do our handling if not surpressed.
- if ( ret !== true ) {
- if ( QUnit.config.current ) {
- if ( QUnit.config.current.ignoreGlobalErrors ) {
- return true;
- }
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- } else {
- QUnit.test( "global failure", extend( function() {
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- }, { validTest: validTest } ) );
- }
- return false;
- }
-
- return ret;
-};
-
-function done() {
- config.autorun = true;
-
- // Log the last module results
- if ( config.currentModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.currentModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
-
- var i, key,
- banner = id( "qunit-banner" ),
- tests = id( "qunit-tests" ),
- runtime = +new Date() - config.started,
- passed = config.stats.all - config.stats.bad,
- html = [
- "Tests completed in ",
- runtime,
- " milliseconds.
",
- "",
- passed,
- " assertions of ",
- config.stats.all,
- " passed, ",
- config.stats.bad,
- " failed."
- ].join( "" );
-
- if ( banner ) {
- banner.className = ( config.stats.bad ? "qunit-fail" : "qunit-pass" );
- }
-
- if ( tests ) {
- id( "qunit-testresult" ).innerHTML = html;
- }
-
- if ( config.altertitle && typeof document !== "undefined" && document.title ) {
- // show ✖ for good, ✔ for bad suite result in title
- // use escape sequences in case file gets loaded with non-utf-8-charset
- document.title = [
- ( config.stats.bad ? "\u2716" : "\u2714" ),
- document.title.replace( /^[\u2714\u2716] /i, "" )
- ].join( " " );
- }
-
- // clear own sessionStorage items if all tests passed
- if ( config.reorder && defined.sessionStorage && config.stats.bad === 0 ) {
- // `key` & `i` initialized at top of scope
- for ( i = 0; i < sessionStorage.length; i++ ) {
- key = sessionStorage.key( i++ );
- if ( key.indexOf( "qunit-test-" ) === 0 ) {
- sessionStorage.removeItem( key );
- }
- }
- }
-
- // scroll back to top to show results
- if ( window.scrollTo ) {
- window.scrollTo(0, 0);
- }
-
- runLoggingCallbacks( "done", QUnit, {
- failed: config.stats.bad,
- passed: passed,
- total: config.stats.all,
- runtime: runtime
- });
-}
-
-/** @return Boolean: true if this test should be ran */
-function validTest( test ) {
- var include,
- filter = config.filter && config.filter.toLowerCase(),
- module = config.module && config.module.toLowerCase(),
- fullName = (test.module + ": " + test.testName).toLowerCase();
-
- // Internally-generated tests are always valid
- if ( test.callback && test.callback.validTest === validTest ) {
- delete test.callback.validTest;
- return true;
- }
-
- if ( config.testNumber ) {
- return test.testNumber === config.testNumber;
- }
-
- if ( module && ( !test.module || test.module.toLowerCase() !== module ) ) {
- return false;
- }
-
- if ( !filter ) {
- return true;
- }
-
- include = filter.charAt( 0 ) !== "!";
- if ( !include ) {
- filter = filter.slice( 1 );
- }
-
- // If the filter matches, we need to honour include
- if ( fullName.indexOf( filter ) !== -1 ) {
- return include;
- }
-
- // Otherwise, do the opposite
- return !include;
-}
-
-// so far supports only Firefox, Chrome and Opera (buggy), Safari (for real exceptions)
-// Later Safari and IE10 are supposed to support error.stack as well
-// See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack
-function extractStacktrace( e, offset ) {
- offset = offset === undefined ? 3 : offset;
-
- var stack, include, i;
-
- if ( e.stacktrace ) {
- // Opera
- return e.stacktrace.split( "\n" )[ offset + 3 ];
- } else if ( e.stack ) {
- // Firefox, Chrome
- stack = e.stack.split( "\n" );
- if (/^error$/i.test( stack[0] ) ) {
- stack.shift();
- }
- if ( fileName ) {
- include = [];
- for ( i = offset; i < stack.length; i++ ) {
- if ( stack[ i ].indexOf( fileName ) !== -1 ) {
- break;
- }
- include.push( stack[ i ] );
- }
- if ( include.length ) {
- return include.join( "\n" );
- }
- }
- return stack[ offset ];
- } else if ( e.sourceURL ) {
- // Safari, PhantomJS
- // hopefully one day Safari provides actual stacktraces
- // exclude useless self-reference for generated Error objects
- if ( /qunit.js$/.test( e.sourceURL ) ) {
- return;
- }
- // for actual exceptions, this is useful
- return e.sourceURL + ":" + e.line;
- }
-}
-function sourceFromStacktrace( offset ) {
- try {
- throw new Error();
- } catch ( e ) {
- return extractStacktrace( e, offset );
- }
-}
-
-/**
- * Escape text for attribute or text content.
- */
-function escapeText( s ) {
- if ( !s ) {
- return "";
- }
- s = s + "";
- // Both single quotes and double quotes (for attributes)
- return s.replace( /['"<>&]/g, function( s ) {
- switch( s ) {
- case '\'':
- return ''';
- case '"':
- return '"';
- case '<':
- return '<';
- case '>':
- return '>';
- case '&':
- return '&';
- }
- });
-}
-
-function synchronize( callback, last ) {
- config.queue.push( callback );
-
- if ( config.autorun && !config.blocking ) {
- process( last );
- }
-}
-
-function process( last ) {
- function next() {
- process( last );
- }
- var start = new Date().getTime();
- config.depth = config.depth ? config.depth + 1 : 1;
-
- while ( config.queue.length && !config.blocking ) {
- if ( !defined.setTimeout || config.updateRate <= 0 || ( ( new Date().getTime() - start ) < config.updateRate ) ) {
- config.queue.shift()();
- } else {
- window.setTimeout( next, 13 );
- break;
- }
- }
- config.depth--;
- if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) {
- done();
- }
-}
-
-function saveGlobal() {
- config.pollution = [];
-
- if ( config.noglobals ) {
- for ( var key in window ) {
- // in Opera sometimes DOM element ids show up here, ignore them
- if ( !hasOwn.call( window, key ) || /^qunit-test-output/.test( key ) ) {
- continue;
- }
- config.pollution.push( key );
- }
- }
-}
-
-function checkPollution() {
- var newGlobals,
- deletedGlobals,
- old = config.pollution;
-
- saveGlobal();
-
- newGlobals = diff( config.pollution, old );
- if ( newGlobals.length > 0 ) {
- QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join(", ") );
- }
-
- deletedGlobals = diff( old, config.pollution );
- if ( deletedGlobals.length > 0 ) {
- QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join(", ") );
- }
-}
-
-// returns a new Array with the elements that are in a but not in b
-function diff( a, b ) {
- var i, j,
- result = a.slice();
-
- for ( i = 0; i < result.length; i++ ) {
- for ( j = 0; j < b.length; j++ ) {
- if ( result[i] === b[j] ) {
- result.splice( i, 1 );
- i--;
- break;
- }
- }
- }
- return result;
-}
-
-function extend( a, b ) {
- for ( var prop in b ) {
- if ( b[ prop ] === undefined ) {
- delete a[ prop ];
-
- // Avoid "Member not found" error in IE8 caused by setting window.constructor
- } else if ( prop !== "constructor" || a !== window ) {
- a[ prop ] = b[ prop ];
- }
- }
-
- return a;
-}
-
-/**
- * @param {HTMLElement} elem
- * @param {string} type
- * @param {Function} fn
- */
-function addEvent( elem, type, fn ) {
- // Standards-based browsers
- if ( elem.addEventListener ) {
- elem.addEventListener( type, fn, false );
- // IE
- } else {
- elem.attachEvent( "on" + type, fn );
- }
-}
-
-/**
- * @param {Array|NodeList} elems
- * @param {string} type
- * @param {Function} fn
- */
-function addEvents( elems, type, fn ) {
- var i = elems.length;
- while ( i-- ) {
- addEvent( elems[i], type, fn );
- }
-}
-
-function hasClass( elem, name ) {
- return (" " + elem.className + " ").indexOf(" " + name + " ") > -1;
-}
-
-function addClass( elem, name ) {
- if ( !hasClass( elem, name ) ) {
- elem.className += (elem.className ? " " : "") + name;
- }
-}
-
-function removeClass( elem, name ) {
- var set = " " + elem.className + " ";
- // Class name may appear multiple times
- while ( set.indexOf(" " + name + " ") > -1 ) {
- set = set.replace(" " + name + " " , " ");
- }
- // If possible, trim it for prettiness, but not neccecarily
- elem.className = window.jQuery ? jQuery.trim( set ) : ( set.trim ? set.trim() : set );
-}
-
-function id( name ) {
- return !!( typeof document !== "undefined" && document && document.getElementById ) &&
- document.getElementById( name );
-}
-
-function registerLoggingCallback( key ) {
- return function( callback ) {
- config[key].push( callback );
- };
-}
-
-// Supports deprecated method of completely overwriting logging callbacks
-function runLoggingCallbacks( key, scope, args ) {
- var i, callbacks;
- if ( QUnit.hasOwnProperty( key ) ) {
- QUnit[ key ].call(scope, args );
- } else {
- callbacks = config[ key ];
- for ( i = 0; i < callbacks.length; i++ ) {
- callbacks[ i ].call( scope, args );
- }
- }
-}
-
-// Test for equality any JavaScript type.
-// Author: Philippe Rathé
-QUnit.equiv = (function() {
-
- // Call the o related callback with the given arguments.
- function bindCallbacks( o, callbacks, args ) {
- var prop = QUnit.objectType( o );
- if ( prop ) {
- if ( QUnit.objectType( callbacks[ prop ] ) === "function" ) {
- return callbacks[ prop ].apply( callbacks, args );
- } else {
- return callbacks[ prop ]; // or undefined
- }
- }
- }
-
- // the real equiv function
- var innerEquiv,
- // stack to decide between skip/abort functions
- callers = [],
- // stack to avoiding loops from circular referencing
- parents = [],
-
- getProto = Object.getPrototypeOf || function ( obj ) {
- return obj.__proto__;
- },
- callbacks = (function () {
-
- // for string, boolean, number and null
- function useStrictEquality( b, a ) {
- /*jshint eqeqeq:false */
- if ( b instanceof a.constructor || a instanceof b.constructor ) {
- // to catch short annotaion VS 'new' annotation of a
- // declaration
- // e.g. var i = 1;
- // var j = new Number(1);
- return a == b;
- } else {
- return a === b;
- }
- }
-
- return {
- "string": useStrictEquality,
- "boolean": useStrictEquality,
- "number": useStrictEquality,
- "null": useStrictEquality,
- "undefined": useStrictEquality,
-
- "nan": function( b ) {
- return isNaN( b );
- },
-
- "date": function( b, a ) {
- return QUnit.objectType( b ) === "date" && a.valueOf() === b.valueOf();
- },
-
- "regexp": function( b, a ) {
- return QUnit.objectType( b ) === "regexp" &&
- // the regex itself
- a.source === b.source &&
- // and its modifers
- a.global === b.global &&
- // (gmi) ...
- a.ignoreCase === b.ignoreCase &&
- a.multiline === b.multiline &&
- a.sticky === b.sticky;
- },
-
- // - skip when the property is a method of an instance (OOP)
- // - abort otherwise,
- // initial === would have catch identical references anyway
- "function": function() {
- var caller = callers[callers.length - 1];
- return caller !== Object && typeof caller !== "undefined";
- },
-
- "array": function( b, a ) {
- var i, j, len, loop;
-
- // b could be an object literal here
- if ( QUnit.objectType( b ) !== "array" ) {
- return false;
- }
-
- len = a.length;
- if ( len !== b.length ) {
- // safe and faster
- return false;
- }
-
- // track reference to avoid circular references
- parents.push( a );
- for ( i = 0; i < len; i++ ) {
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- loop = true;// dont rewalk array
- }
- }
- if ( !loop && !innerEquiv(a[i], b[i]) ) {
- parents.pop();
- return false;
- }
- }
- parents.pop();
- return true;
- },
-
- "object": function( b, a ) {
- var i, j, loop,
- // Default to true
- eq = true,
- aProperties = [],
- bProperties = [];
-
- // comparing constructors is more strict than using
- // instanceof
- if ( a.constructor !== b.constructor ) {
- // Allow objects with no prototype to be equivalent to
- // objects with Object as their constructor.
- if ( !(( getProto(a) === null && getProto(b) === Object.prototype ) ||
- ( getProto(b) === null && getProto(a) === Object.prototype ) ) ) {
- return false;
- }
- }
-
- // stack constructor before traversing properties
- callers.push( a.constructor );
- // track reference to avoid circular references
- parents.push( a );
-
- for ( i in a ) { // be strict: don't ensures hasOwnProperty
- // and go deep
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- // don't go down the same path twice
- loop = true;
- }
- }
- aProperties.push(i); // collect a's properties
-
- if (!loop && !innerEquiv( a[i], b[i] ) ) {
- eq = false;
- break;
- }
- }
-
- callers.pop(); // unstack, we are done
- parents.pop();
-
- for ( i in b ) {
- bProperties.push( i ); // collect b's properties
- }
-
- // Ensures identical properties name
- return eq && innerEquiv( aProperties.sort(), bProperties.sort() );
- }
- };
- }());
-
- innerEquiv = function() { // can take multiple arguments
- var args = [].slice.apply( arguments );
- if ( args.length < 2 ) {
- return true; // end transition
- }
-
- return (function( a, b ) {
- if ( a === b ) {
- return true; // catch the most you can
- } else if ( a === null || b === null || typeof a === "undefined" ||
- typeof b === "undefined" ||
- QUnit.objectType(a) !== QUnit.objectType(b) ) {
- return false; // don't lose time with error prone cases
- } else {
- return bindCallbacks(a, callbacks, [ b, a ]);
- }
-
- // apply transition with (1..n) arguments
- }( args[0], args[1] ) && arguments.callee.apply( this, args.splice(1, args.length - 1 )) );
- };
-
- return innerEquiv;
-}());
-
-/**
- * jsDump Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com |
- * http://flesler.blogspot.com Licensed under BSD
- * (http://www.opensource.org/licenses/bsd-license.php) Date: 5/15/2008
- *
- * @projectDescription Advanced and extensible data dumping for Javascript.
- * @version 1.0.0
- * @author Ariel Flesler
- * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html}
- */
-QUnit.jsDump = (function() {
- function quote( str ) {
- return '"' + str.toString().replace( /"/g, '\\"' ) + '"';
- }
- function literal( o ) {
- return o + "";
- }
- function join( pre, arr, post ) {
- var s = jsDump.separator(),
- base = jsDump.indent(),
- inner = jsDump.indent(1);
- if ( arr.join ) {
- arr = arr.join( "," + s + inner );
- }
- if ( !arr ) {
- return pre + post;
- }
- return [ pre, inner + arr, base + post ].join(s);
- }
- function array( arr, stack ) {
- var i = arr.length, ret = new Array(i);
- this.up();
- while ( i-- ) {
- ret[i] = this.parse( arr[i] , undefined , stack);
- }
- this.down();
- return join( "[", ret, "]" );
- }
-
- var reName = /^function (\w+)/,
- jsDump = {
- // type is used mostly internally, you can fix a (custom)type in advance
- parse: function( obj, type, stack ) {
- stack = stack || [ ];
- var inStack, res,
- parser = this.parsers[ type || this.typeOf(obj) ];
-
- type = typeof parser;
- inStack = inArray( obj, stack );
-
- if ( inStack !== -1 ) {
- return "recursion(" + (inStack - stack.length) + ")";
- }
- if ( type === "function" ) {
- stack.push( obj );
- res = parser.call( this, obj, stack );
- stack.pop();
- return res;
- }
- return ( type === "string" ) ? parser : this.parsers.error;
- },
- typeOf: function( obj ) {
- var type;
- if ( obj === null ) {
- type = "null";
- } else if ( typeof obj === "undefined" ) {
- type = "undefined";
- } else if ( QUnit.is( "regexp", obj) ) {
- type = "regexp";
- } else if ( QUnit.is( "date", obj) ) {
- type = "date";
- } else if ( QUnit.is( "function", obj) ) {
- type = "function";
- } else if ( typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined" ) {
- type = "window";
- } else if ( obj.nodeType === 9 ) {
- type = "document";
- } else if ( obj.nodeType ) {
- type = "node";
- } else if (
- // native arrays
- toString.call( obj ) === "[object Array]" ||
- // NodeList objects
- ( typeof obj.length === "number" && typeof obj.item !== "undefined" && ( obj.length ? obj.item(0) === obj[0] : ( obj.item( 0 ) === null && typeof obj[0] === "undefined" ) ) )
- ) {
- type = "array";
- } else if ( obj.constructor === Error.prototype.constructor ) {
- type = "error";
- } else {
- type = typeof obj;
- }
- return type;
- },
- separator: function() {
- return this.multiline ? this.HTML ? "
" : "\n" : this.HTML ? " " : " ";
- },
- // extra can be a number, shortcut for increasing-calling-decreasing
- indent: function( extra ) {
- if ( !this.multiline ) {
- return "";
- }
- var chr = this.indentChar;
- if ( this.HTML ) {
- chr = chr.replace( /\t/g, " " ).replace( / /g, " " );
- }
- return new Array( this._depth_ + (extra||0) ).join(chr);
- },
- up: function( a ) {
- this._depth_ += a || 1;
- },
- down: function( a ) {
- this._depth_ -= a || 1;
- },
- setParser: function( name, parser ) {
- this.parsers[name] = parser;
- },
- // The next 3 are exposed so you can use them
- quote: quote,
- literal: literal,
- join: join,
- //
- _depth_: 1,
- // This is the list of parsers, to modify them, use jsDump.setParser
- parsers: {
- window: "[Window]",
- document: "[Document]",
- error: function(error) {
- return "Error(\"" + error.message + "\")";
- },
- unknown: "[Unknown]",
- "null": "null",
- "undefined": "undefined",
- "function": function( fn ) {
- var ret = "function",
- // functions never have name in IE
- name = "name" in fn ? fn.name : (reName.exec(fn) || [])[1];
-
- if ( name ) {
- ret += " " + name;
- }
- ret += "( ";
-
- ret = [ ret, QUnit.jsDump.parse( fn, "functionArgs" ), "){" ].join( "" );
- return join( ret, QUnit.jsDump.parse(fn,"functionCode" ), "}" );
- },
- array: array,
- nodelist: array,
- "arguments": array,
- object: function( map, stack ) {
- var ret = [ ], keys, key, val, i;
- QUnit.jsDump.up();
- keys = [];
- for ( key in map ) {
- keys.push( key );
- }
- keys.sort();
- for ( i = 0; i < keys.length; i++ ) {
- key = keys[ i ];
- val = map[ key ];
- ret.push( QUnit.jsDump.parse( key, "key" ) + ": " + QUnit.jsDump.parse( val, undefined, stack ) );
- }
- QUnit.jsDump.down();
- return join( "{", ret, "}" );
- },
- node: function( node ) {
- var len, i, val,
- open = QUnit.jsDump.HTML ? "<" : "<",
- close = QUnit.jsDump.HTML ? ">" : ">",
- tag = node.nodeName.toLowerCase(),
- ret = open + tag,
- attrs = node.attributes;
-
- if ( attrs ) {
- for ( i = 0, len = attrs.length; i < len; i++ ) {
- val = attrs[i].nodeValue;
- // IE6 includes all attributes in .attributes, even ones not explicitly set.
- // Those have values like undefined, null, 0, false, "" or "inherit".
- if ( val && val !== "inherit" ) {
- ret += " " + attrs[i].nodeName + "=" + QUnit.jsDump.parse( val, "attribute" );
- }
- }
- }
- ret += close;
-
- // Show content of TextNode or CDATASection
- if ( node.nodeType === 3 || node.nodeType === 4 ) {
- ret += node.nodeValue;
- }
-
- return ret + open + "/" + tag + close;
- },
- // function calls it internally, it's the arguments part of the function
- functionArgs: function( fn ) {
- var args,
- l = fn.length;
-
- if ( !l ) {
- return "";
- }
-
- args = new Array(l);
- while ( l-- ) {
- // 97 is 'a'
- args[l] = String.fromCharCode(97+l);
- }
- return " " + args.join( ", " ) + " ";
- },
- // object calls it internally, the key part of an item in a map
- key: quote,
- // function calls it internally, it's the content of the function
- functionCode: "[code]",
- // node calls it internally, it's an html attribute value
- attribute: quote,
- string: quote,
- date: quote,
- regexp: literal,
- number: literal,
- "boolean": literal
- },
- // if true, entities are escaped ( <, >, \t, space and \n )
- HTML: false,
- // indentation unit
- indentChar: " ",
- // if true, items in a collection, are separated by a \n, else just a space.
- multiline: true
- };
-
- return jsDump;
-}());
-
-// from jquery.js
-function inArray( elem, array ) {
- if ( array.indexOf ) {
- return array.indexOf( elem );
- }
-
- for ( var i = 0, length = array.length; i < length; i++ ) {
- if ( array[ i ] === elem ) {
- return i;
- }
- }
-
- return -1;
-}
-
-/*
- * Javascript Diff Algorithm
- * By John Resig (http://ejohn.org/)
- * Modified by Chu Alan "sprite"
- *
- * Released under the MIT license.
- *
- * More Info:
- * http://ejohn.org/projects/javascript-diff-algorithm/
- *
- * Usage: QUnit.diff(expected, actual)
- *
- * QUnit.diff( "the quick brown fox jumped over", "the quick fox jumps over" ) == "the quick brown fox jumped jumps over"
- */
-QUnit.diff = (function() {
- /*jshint eqeqeq:false, eqnull:true */
- function diff( o, n ) {
- var i,
- ns = {},
- os = {};
-
- for ( i = 0; i < n.length; i++ ) {
- if ( !hasOwn.call( ns, n[i] ) ) {
- ns[ n[i] ] = {
- rows: [],
- o: null
- };
- }
- ns[ n[i] ].rows.push( i );
- }
-
- for ( i = 0; i < o.length; i++ ) {
- if ( !hasOwn.call( os, o[i] ) ) {
- os[ o[i] ] = {
- rows: [],
- n: null
- };
- }
- os[ o[i] ].rows.push( i );
- }
-
- for ( i in ns ) {
- if ( !hasOwn.call( ns, i ) ) {
- continue;
- }
- if ( ns[i].rows.length === 1 && hasOwn.call( os, i ) && os[i].rows.length === 1 ) {
- n[ ns[i].rows[0] ] = {
- text: n[ ns[i].rows[0] ],
- row: os[i].rows[0]
- };
- o[ os[i].rows[0] ] = {
- text: o[ os[i].rows[0] ],
- row: ns[i].rows[0]
- };
- }
- }
-
- for ( i = 0; i < n.length - 1; i++ ) {
- if ( n[i].text != null && n[ i + 1 ].text == null && n[i].row + 1 < o.length && o[ n[i].row + 1 ].text == null &&
- n[ i + 1 ] == o[ n[i].row + 1 ] ) {
-
- n[ i + 1 ] = {
- text: n[ i + 1 ],
- row: n[i].row + 1
- };
- o[ n[i].row + 1 ] = {
- text: o[ n[i].row + 1 ],
- row: i + 1
- };
- }
- }
-
- for ( i = n.length - 1; i > 0; i-- ) {
- if ( n[i].text != null && n[ i - 1 ].text == null && n[i].row > 0 && o[ n[i].row - 1 ].text == null &&
- n[ i - 1 ] == o[ n[i].row - 1 ]) {
-
- n[ i - 1 ] = {
- text: n[ i - 1 ],
- row: n[i].row - 1
- };
- o[ n[i].row - 1 ] = {
- text: o[ n[i].row - 1 ],
- row: i - 1
- };
- }
- }
-
- return {
- o: o,
- n: n
- };
- }
-
- return function( o, n ) {
- o = o.replace( /\s+$/, "" );
- n = n.replace( /\s+$/, "" );
-
- var i, pre,
- str = "",
- out = diff( o === "" ? [] : o.split(/\s+/), n === "" ? [] : n.split(/\s+/) ),
- oSpace = o.match(/\s+/g),
- nSpace = n.match(/\s+/g);
-
- if ( oSpace == null ) {
- oSpace = [ " " ];
- }
- else {
- oSpace.push( " " );
- }
-
- if ( nSpace == null ) {
- nSpace = [ " " ];
- }
- else {
- nSpace.push( " " );
- }
-
- if ( out.n.length === 0 ) {
- for ( i = 0; i < out.o.length; i++ ) {
- str += "" + out.o[i] + oSpace[i] + "";
- }
- }
- else {
- if ( out.n[0].text == null ) {
- for ( n = 0; n < out.o.length && out.o[n].text == null; n++ ) {
- str += "" + out.o[n] + oSpace[n] + "";
- }
- }
-
- for ( i = 0; i < out.n.length; i++ ) {
- if (out.n[i].text == null) {
- str += "" + out.n[i] + nSpace[i] + "";
- }
- else {
- // `pre` initialized at top of scope
- pre = "";
-
- for ( n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++ ) {
- pre += "" + out.o[n] + oSpace[n] + "";
- }
- str += " " + out.n[i].text + nSpace[i] + pre;
- }
- }
- }
-
- return str;
- };
-}());
-
-// for CommonJS enviroments, export everything
-if ( typeof exports !== "undefined" ) {
- extend( exports, QUnit );
-}
-
-// get at whatever the global object is, like window in browsers
-}( (function() {return this;}.call()) ));
diff --git a/test/lib/require.js b/test/lib/require.js
deleted file mode 100644
index 987f865..0000000
--- a/test/lib/require.js
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- RequireJS 2.1.5 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.
- Available via the MIT or new BSD license.
- see: http://github.com/jrburke/requirejs for details
-*/
-var requirejs,require,define;
-(function(aa){function I(b){return"[object Function]"===L.call(b)}function J(b){return"[object Array]"===L.call(b)}function y(b,c){if(b){var d;for(d=0;dthis.depCount&&!this.defined){if(I(n)){if(this.events.error)try{e=i.execCb(c,n,b,e)}catch(d){a=d}else e=i.execCb(c,n,b,e);this.map.isDefine&&((b=this.module)&&void 0!==b.exports&&b.exports!==this.exports?e=b.exports:void 0===e&&this.usingExports&&(e=this.exports));if(a)return a.requireMap=this.map,a.requireModules=[this.map.id],a.requireType="define",v(this.error=
-a)}else e=n;this.exports=e;if(this.map.isDefine&&!this.ignore&&(q[c]=e,l.onResourceLoad))l.onResourceLoad(i,this.map,this.depMaps);x(c);this.defined=!0}this.defining=!1;this.defined&&!this.defineEmitted&&(this.defineEmitted=!0,this.emit("defined",this.exports),this.defineEmitComplete=!0)}}else this.fetch()}},callPlugin:function(){var a=this.map,b=a.id,d=j(a.prefix);this.depMaps.push(d);t(d,"defined",u(this,function(e){var n,d;d=this.map.name;var g=this.map.parentMap?this.map.parentMap.name:null,h=
-i.makeRequire(a.parentMap,{enableBuildCallback:!0});if(this.map.unnormalized){if(e.normalize&&(d=e.normalize(d,function(a){return c(a,g,!0)})||""),e=j(a.prefix+"!"+d,this.map.parentMap),t(e,"defined",u(this,function(a){this.init([],function(){return a},null,{enabled:!0,ignore:!0})})),d=m(p,e.id)){this.depMaps.push(e);if(this.events.error)d.on("error",u(this,function(a){this.emit("error",a)}));d.enable()}}else n=u(this,function(a){this.init([],function(){return a},null,{enabled:!0})}),n.error=u(this,
-function(a){this.inited=!0;this.error=a;a.requireModules=[b];G(p,function(a){0===a.map.id.indexOf(b+"_unnormalized")&&x(a.map.id)});v(a)}),n.fromText=u(this,function(e,c){var d=a.name,g=j(d),C=O;c&&(e=c);C&&(O=!1);r(g);s(k.config,b)&&(k.config[d]=k.config[b]);try{l.exec(e)}catch(ca){return v(B("fromtexteval","fromText eval for "+b+" failed: "+ca,ca,[b]))}C&&(O=!0);this.depMaps.push(g);i.completeLoad(d);h([d],n)}),e.load(a.name,h,n,k)}));i.enable(d,this);this.pluginMaps[d.id]=d},enable:function(){V[this.map.id]=
-this;this.enabling=this.enabled=!0;y(this.depMaps,u(this,function(a,b){var c,e;if("string"===typeof a){a=j(a,this.map.isDefine?this.map:this.map.parentMap,!1,!this.skipMap);this.depMaps[b]=a;if(c=m(N,a.id)){this.depExports[b]=c(this);return}this.depCount+=1;t(a,"defined",u(this,function(a){this.defineDep(b,a);this.check()}));this.errback&&t(a,"error",this.errback)}c=a.id;e=p[c];!s(N,c)&&(e&&!e.enabled)&&i.enable(a,this)}));G(this.pluginMaps,u(this,function(a){var b=m(p,a.id);b&&!b.enabled&&i.enable(a,
-this)}));this.enabling=!1;this.check()},on:function(a,b){var c=this.events[a];c||(c=this.events[a]=[]);c.push(b)},emit:function(a,b){y(this.events[a],function(a){a(b)});"error"===a&&delete this.events[a]}};i={config:k,contextName:b,registry:p,defined:q,urlFetched:U,defQueue:H,Module:Z,makeModuleMap:j,nextTick:l.nextTick,onError:v,configure:function(a){a.baseUrl&&"/"!==a.baseUrl.charAt(a.baseUrl.length-1)&&(a.baseUrl+="/");var b=k.pkgs,c=k.shim,e={paths:!0,config:!0,map:!0};G(a,function(a,b){e[b]?
-"map"===b?(k.map||(k.map={}),R(k[b],a,!0,!0)):R(k[b],a,!0):k[b]=a});a.shim&&(G(a.shim,function(a,b){J(a)&&(a={deps:a});if((a.exports||a.init)&&!a.exportsFn)a.exportsFn=i.makeShimExports(a);c[b]=a}),k.shim=c);a.packages&&(y(a.packages,function(a){a="string"===typeof a?{name:a}:a;b[a.name]={name:a.name,location:a.location||a.name,main:(a.main||"main").replace(ja,"").replace(ea,"")}}),k.pkgs=b);G(p,function(a,b){!a.inited&&!a.map.unnormalized&&(a.map=j(b))});if(a.deps||a.callback)i.require(a.deps||[],
-a.callback)},makeShimExports:function(a){return function(){var b;a.init&&(b=a.init.apply(aa,arguments));return b||a.exports&&ba(a.exports)}},makeRequire:function(a,f){function d(e,c,h){var g,k;f.enableBuildCallback&&(c&&I(c))&&(c.__requireJsBuild=!0);if("string"===typeof e){if(I(c))return v(B("requireargs","Invalid require call"),h);if(a&&s(N,e))return N[e](p[a.id]);if(l.get)return l.get(i,e,a,d);g=j(e,a,!1,!0);g=g.id;return!s(q,g)?v(B("notloaded",'Module name "'+g+'" has not been loaded yet for context: '+
-b+(a?"":". Use require([])"))):q[g]}L();i.nextTick(function(){L();k=r(j(null,a));k.skipMap=f.skipMap;k.init(e,c,h,{enabled:!0});D()});return d}f=f||{};R(d,{isBrowser:A,toUrl:function(b){var d,f=b.lastIndexOf("."),g=b.split("/")[0];if(-1!==f&&(!("."===g||".."===g)||1h.attachEvent.toString().indexOf("[native code"))&&!Y?(O=!0,h.attachEvent("onreadystatechange",b.onScriptLoad)):(h.addEventListener("load",b.onScriptLoad,!1),h.addEventListener("error",b.onScriptError,!1)),h.src=d,K=h,D?x.insertBefore(h,D):x.appendChild(h),K=null,h;if(da)try{importScripts(d),b.completeLoad(c)}catch(j){b.onError(B("importscripts","importScripts failed for "+c+" at "+d,j,[c]))}};A&&M(document.getElementsByTagName("script"),function(b){x||(x=
-b.parentNode);if(t=b.getAttribute("data-main"))return r.baseUrl||(E=t.split("/"),Q=E.pop(),fa=E.length?E.join("/")+"/":"./",r.baseUrl=fa,t=Q),t=t.replace(ea,""),r.deps=r.deps?r.deps.concat(t):[t],!0});define=function(b,c,d){var l,h;"string"!==typeof b&&(d=c,c=b,b=null);J(c)||(d=c,c=[]);!c.length&&I(d)&&d.length&&(d.toString().replace(la,"").replace(ma,function(b,d){c.push(d)}),c=(1===d.length?["require"]:["require","exports","module"]).concat(c));if(O){if(!(l=K))P&&"interactive"===P.readyState||M(document.getElementsByTagName("script"),
-function(b){if("interactive"===b.readyState)return P=b}),l=P;l&&(b||(b=l.getAttribute("data-requiremodule")),h=F[l.getAttribute("data-requirecontext")])}(h?h.defQueue:T).push([b,c,d])};define.amd={jQuery:!0};l.exec=function(b){return eval(b)};l(r)}})(this);
diff --git a/test/lib/resemble.js b/test/lib/resemble.js
new file mode 100644
index 0000000..1cb8c29
--- /dev/null
+++ b/test/lib/resemble.js
@@ -0,0 +1,535 @@
+/*
+Author: James Cryer
+Company: Huddle
+Last updated date: 21 Feb 2013
+URL: https://github.com/Huddle/Resemble.js
+*/
+
+(function(_this){
+ 'use strict';
+
+ _this['resemble'] = function( fileData ){
+
+ var data = {};
+ var images = [];
+ var updateCallbackArray = [];
+
+ var tolerance = { // between 0 and 255
+ red: 16,
+ green: 16,
+ blue: 16,
+ minBrightness: 16,
+ maxBrightness: 240
+ };
+
+ var ignoreAntialiasing = false;
+ var ignoreColors = false;
+
+ function triggerDataUpdate(){
+ var len = updateCallbackArray.length;
+ var i;
+ for(i=0;i tolerance.maxBrightness;
+ }
+
+ function getHue(r,g,b){
+
+ r = r / 255;
+ g = g / 255;
+ b = b / 255;
+ var max = Math.max(r, g, b), min = Math.min(r, g, b);
+ var h;
+ var d;
+
+ if (max == min){
+ h = 0; // achromatic
+ } else{
+ d = max - min;
+ switch(max){
+ case r: h = (g - b) / d + (g < b ? 6 : 0); break;
+ case g: h = (b - r) / d + 2; break;
+ case b: h = (r - g) / d + 4; break;
+ }
+ h /= 6;
+ }
+
+ return h;
+ }
+
+ function isAntialiased(sourcePix, data, cacheSet, verticalPos, horizontalPos, width){
+ var offset;
+ var targetPix;
+ var distance = 1;
+ var i;
+ var j;
+ var hasHighContrastSibling = 0;
+ var hasSiblingWithDifferentHue = 0;
+ var hasEquivilantSibling = 0;
+
+ addHueInfo(sourcePix);
+
+ for (i = distance*-1; i <= distance; i++){
+ for (j = distance*-1; j <= distance; j++){
+
+ if(i===0 && j===0){
+ // ignore source pixel
+ } else {
+
+ offset = ((verticalPos+j)*width + (horizontalPos+i)) * 4;
+ targetPix = getPixelInfo(data, offset, cacheSet);
+
+ if(targetPix === null){
+ continue;
+ }
+
+ addBrightnessInfo(targetPix);
+ addHueInfo(targetPix);
+
+ if( isContrasting(sourcePix, targetPix) ){
+ hasHighContrastSibling++;
+ }
+
+ if( isRGBSame(sourcePix,targetPix) ){
+ hasEquivilantSibling++;
+ }
+
+ if( Math.abs(targetPix.h - sourcePix.h) > 0.3 ){
+ hasSiblingWithDifferentHue++;
+ }
+
+ if( hasSiblingWithDifferentHue > 1 || hasHighContrastSibling > 1){
+ return true;
+ }
+ }
+ }
+ }
+
+ if(hasEquivilantSibling < 2){
+ return true;
+ }
+
+ return false;
+ }
+
+ function errorPixel(px, offset){
+ px[offset] = 255; //r
+ px[offset + 1] = 0; //g
+ px[offset + 2] = 255; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyPixel(px, offset, data){
+ px[offset] = data.r; //r
+ px[offset + 1] = data.g; //g
+ px[offset + 2] = data.b; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyGrayScalePixel(px, offset, data){
+ px[offset] = data.brightness; //r
+ px[offset + 1] = data.brightness; //g
+ px[offset + 2] = data.brightness; //b
+ px[offset + 3] = 255; //a
+ }
+
+
+ function getPixelInfo(data, offset, cacheSet){
+ var r;
+ var g;
+ var b;
+ var d;
+
+ if(typeof data[offset] !== 'undefined'){
+ r = data[offset];
+ g = data[offset+1];
+ b = data[offset+2];
+ d = {
+ r: r,
+ g: g,
+ b: b
+ };
+
+ return d;
+ } else {
+ return null;
+ }
+ }
+
+ function addBrightnessInfo(data){
+ data.brightness = getBrightness(data.r,data.g,data.b); // 'corrected' lightness
+ }
+
+ function addHueInfo(data){
+ data.h = getHue(data.r,data.g,data.b);
+ }
+
+ function analyseImages(img1, img2, width, height){
+
+ var hiddenCanvas = document.createElement('canvas');
+
+ var data1 = img1.data;
+ var data2 = img2.data;
+
+ hiddenCanvas.width = width;
+ hiddenCanvas.height = height;
+
+ var context = hiddenCanvas.getContext('2d');
+ var imgd = context.createImageData(width,height);
+ var targetPix = imgd.data;
+
+ var mismatchCount = 0;
+
+ var time = Date.now();
+
+ var skip;
+
+ if( (width > 1200 || height > 1200) && ignoreAntialiasing){
+ skip = 6;
+ }
+
+ loop(height, width, function(verticalPos, horizontalPos){
+
+ if(skip){ // only skip if the image isn't small
+ if(verticalPos % skip === 0 || horizontalPos % skip === 0){
+ return;
+ }
+ }
+
+ var offset = (verticalPos*width + horizontalPos) * 4;
+ var pixel1 = getPixelInfo(data1, offset, 1);
+ var pixel2 = getPixelInfo(data2, offset, 2);
+
+ if(pixel1 === null || pixel2 === null){
+ return;
+ }
+
+ if (ignoreColors){
+
+ addBrightnessInfo(pixel1);
+ addBrightnessInfo(pixel2);
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ return;
+ }
+
+ if( isRGBSimilar(pixel1, pixel2) ){
+ copyPixel(targetPix, offset, pixel2);
+
+ } else if( ignoreAntialiasing && (
+ addBrightnessInfo(pixel1), // jit pixel info augmentation looks a little weird, sorry.
+ addBrightnessInfo(pixel2),
+ isAntialiased(pixel1, data1, 1, verticalPos, horizontalPos, width) ||
+ isAntialiased(pixel2, data2, 2, verticalPos, horizontalPos, width)
+ )){
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+
+ });
+
+ data.misMatchPercentage = (mismatchCount / (height*width) * 100).toFixed(2);
+ data.analysisTime = Date.now() - time;
+
+ data.getImageDataUrl = function(text){
+ var barHeight = 0;
+
+ if(text){
+ barHeight = addLabel(text,context,hiddenCanvas);
+ }
+
+ context.putImageData(imgd, 0, barHeight);
+
+ return hiddenCanvas.toDataURL("image/png");
+ };
+ }
+
+ function addLabel(text, context, hiddenCanvas){
+ var textPadding = 2;
+
+ context.font = '12px sans-serif';
+
+ var textWidth = context.measureText(text).width + textPadding*2;
+ var barHeight = 22;
+
+ if(textWidth > hiddenCanvas.width){
+ hiddenCanvas.width = textWidth;
+ }
+
+ hiddenCanvas.height += barHeight;
+
+ context.fillStyle = "#666";
+ context.fillRect(0,0,hiddenCanvas.width,barHeight -4);
+ context.fillStyle = "#fff";
+ context.fillRect(0,barHeight -4,hiddenCanvas.width, 4);
+
+ context.fillStyle = "#fff";
+ context.textBaseline = "top";
+ context.font = '12px sans-serif';
+ context.fillText(text, textPadding, 1);
+
+ return barHeight;
+ }
+
+ function normalise(img, w, h){
+ var c;
+ var context;
+
+ if(img.height < h || img.width < w){
+ c = document.createElement('canvas');
+ c.width = w;
+ c.height = h;
+ context = c.getContext('2d');
+ context.putImageData(img, 0, 0);
+ return context.getImageData(0, 0, w, h);
+ }
+
+ return img;
+ }
+
+ function compare(one, two){
+
+ function onceWeHaveBoth(){
+ var width;
+ var height;
+ if(images.length === 2){
+ width = images[0].width > images[1].width ? images[0].width : images[1].width;
+ height = images[0].height > images[1].height ? images[0].height : images[1].height;
+
+ if( (images[0].width === images[1].width) && (images[0].height === images[1].height) ){
+ data.isSameDimensions = true;
+ } else {
+ data.isSameDimensions = false;
+ }
+
+ analyseImages( normalise(images[0],width, height), normalise(images[1],width, height), width, height);
+
+ triggerDataUpdate();
+ }
+ }
+
+ images = [];
+ loadImageData(one, onceWeHaveBoth);
+ loadImageData(two, onceWeHaveBoth);
+ }
+
+ function getCompareApi(param){
+
+ var secondFileData,
+ hasMethod = typeof param === 'function';
+
+ if( !hasMethod ){
+ // assume it's file data
+ secondFileData = param;
+ }
+
+ var self = {
+ ignoreNothing: function(){
+
+ tolerance.red = 16;
+ tolerance.green = 16;
+ tolerance.blue = 16;
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreAntialiasing: function(){
+
+ tolerance.red = 32;
+ tolerance.green = 32;
+ tolerance.blue = 32;
+ tolerance.minBrightness = 64;
+ tolerance.maxBrightness = 96;
+
+ ignoreAntialiasing = true;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreColors: function(){
+
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = true;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ onComplete: function( callback ){
+
+ updateCallbackArray.push(callback);
+
+ var wrapper = function(){
+ compare(fileData, secondFileData);
+ };
+
+ wrapper();
+
+ return getCompareApi(wrapper);
+ }
+ };
+
+ return self;
+ }
+
+ return {
+ onComplete: function( callback ){
+ updateCallbackArray.push(callback);
+ loadImageData(fileData, function(imageData, width, height){
+ parseImage(imageData.data, width, height);
+ });
+ },
+ compareTo: function(secondFileData){
+ return getCompareApi(secondFileData);
+ }
+ };
+
+ };
+}(this));
\ No newline at end of file
diff --git a/test/testsuite.js b/test/testsuite.js
deleted file mode 100644
index b486acb..0000000
--- a/test/testsuite.js
+++ /dev/null
@@ -1,36 +0,0 @@
-requirejs.config({
- baseUrl: '/test/unit/'
-});
-
-define(function(require) {
- var testModules = [
- 'Pixi',
- 'Point',
- 'Rectangle',
- 'DisplayObject',
- 'DisplayObjectContainer',
- 'Sprite',
- 'MovieClip',
- 'InteractionManager',
- 'Stage',
- 'utils/Utils',
- 'utils/EventTarget',
- 'utils/Matrix',
- 'utils/Detector',
- 'renderers/WebGLShaders',
- 'renderers/WebGLRenderer',
- 'renderers/WebGLBatch',
- 'renderers/CanvasRenderer',
- 'extras/Strip',
- 'extras/Rope',
- 'textures/BaseTexture',
- 'textures/Texture',
- 'loaders/SpriteSheetLoader',
- 'loaders/AssetLoader'
- ];
-
- // Resolve all testModules and then start the Test Runner.
- require(testModules, function() {
- QUnit.start();
- });
-});
\ No newline at end of file
diff --git a/test/textures/SpriteSheet-Aliens.png b/test/textures/SpriteSheet-Aliens.png
new file mode 100644
index 0000000..210acb1
--- /dev/null
+++ b/test/textures/SpriteSheet-Aliens.png
Binary files differ
diff --git a/test/textures/SpriteSheet-Explosion.png b/test/textures/SpriteSheet-Explosion.png
new file mode 100755
index 0000000..79e1a69
--- /dev/null
+++ b/test/textures/SpriteSheet-Explosion.png
Binary files differ
diff --git a/test/textures/bunny.png b/test/textures/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/textures/bunny.png
Binary files differ
diff --git a/test/unit/DisplayObject.js b/test/unit/DisplayObject.js
deleted file mode 100644
index 5e7e72f..0000000
--- a/test/unit/DisplayObject.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObject');
-});
diff --git a/test/unit/DisplayObjectContainer.js b/test/unit/DisplayObjectContainer.js
deleted file mode 100644
index b323959..0000000
--- a/test/unit/DisplayObjectContainer.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObjectContainer');
-});
diff --git a/test/unit/InteractionManager.js b/test/unit/InteractionManager.js
deleted file mode 100644
index e751f52..0000000
--- a/test/unit/InteractionManager.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('InteractionManager');
-});
diff --git a/test/unit/MovieClip.js b/test/unit/MovieClip.js
deleted file mode 100644
index 37d9446..0000000
--- a/test/unit/MovieClip.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('MovieClip');
-});
diff --git a/test/unit/Pixi.js b/test/unit/Pixi.js
deleted file mode 100644
index 36eee73..0000000
--- a/test/unit/Pixi.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Pixi');
-});
diff --git a/test/unit/Point.js b/test/unit/Point.js
deleted file mode 100644
index 983ff6e..0000000
--- a/test/unit/Point.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Point');
-});
diff --git a/test/unit/Rectangle.js b/test/unit/Rectangle.js
deleted file mode 100644
index 3b439ba..0000000
--- a/test/unit/Rectangle.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Rectangle');
-});
diff --git a/test/unit/Sprite.js b/test/unit/Sprite.js
deleted file mode 100644
index ed4f596..0000000
--- a/test/unit/Sprite.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Sprite');
-});
diff --git a/test/unit/Stage.js b/test/unit/Stage.js
deleted file mode 100644
index 2d70291..0000000
--- a/test/unit/Stage.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Stage');
-});
diff --git a/test/unit/extras/Rope.js b/test/unit/extras/Rope.js
deleted file mode 100644
index 5606f14..0000000
--- a/test/unit/extras/Rope.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Rope');
-});
diff --git a/test/unit/extras/Strip.js b/test/unit/extras/Strip.js
deleted file mode 100644
index 0134d3a..0000000
--- a/test/unit/extras/Strip.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Strip');
-});
diff --git a/test/unit/loaders/AssetLoader.js b/test/unit/loaders/AssetLoader.js
deleted file mode 100644
index 13b8443..0000000
--- a/test/unit/loaders/AssetLoader.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('AssetLoader');
-});
diff --git a/test/unit/loaders/SpriteSheetLoader.js b/test/unit/loaders/SpriteSheetLoader.js
deleted file mode 100644
index 8bf0cb2..0000000
--- a/test/unit/loaders/SpriteSheetLoader.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('SpriteSheetLoader');
-});
diff --git a/test/unit/pixi/InteractionManager.js b/test/unit/pixi/InteractionManager.js
new file mode 100644
index 0000000..ed3001f
--- /dev/null
+++ b/test/unit/pixi/InteractionManager.js
@@ -0,0 +1,10 @@
+describe('pixi/InteractionManager', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var InteractionManager = PIXI.InteractionManager;
+
+ it('Module exists', function () {
+ expect(InteractionManager).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/Pixi.js b/test/unit/pixi/Pixi.js
new file mode 100644
index 0000000..27debc1
--- /dev/null
+++ b/test/unit/pixi/Pixi.js
@@ -0,0 +1,9 @@
+describe('pixi/Pixi', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+
+ it('Module exists', function () {
+ expect(global).to.have.property('PIXI').and.to.be.an('object');
+ });
+});
diff --git a/test/unit/pixi/core/Circle.js b/test/unit/pixi/core/Circle.js
new file mode 100644
index 0000000..93a4456
--- /dev/null
+++ b/test/unit/pixi/core/Circle.js
@@ -0,0 +1,22 @@
+describe('pixi/core/Circle', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Circle = PIXI.Circle;
+
+ it('Module exists', function () {
+ expect(Circle).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Circle();
+
+ expect(obj).to.be.an.instanceof(Circle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', 0);
+ expect(obj).to.have.property('y', 0);
+ expect(obj).to.have.property('radius', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Ellipse.js b/test/unit/pixi/core/Ellipse.js
new file mode 100644
index 0000000..026b56f
--- /dev/null
+++ b/test/unit/pixi/core/Ellipse.js
@@ -0,0 +1,24 @@
+describe('pixi/core/Ellipse', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Ellipse = PIXI.Ellipse;
+
+ it('Module exists', function () {
+ expect(Ellipse).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Ellipse();
+
+ expect(obj).to.be.an.instanceof(Ellipse);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+ expect(obj).to.respondTo('getBounds');
+
+ expect(obj).to.have.property('x', 0);
+ expect(obj).to.have.property('y', 0);
+ expect(obj).to.have.property('width', 0);
+ expect(obj).to.have.property('height', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Matrix.js b/test/unit/pixi/core/Matrix.js
new file mode 100644
index 0000000..b48989e
--- /dev/null
+++ b/test/unit/pixi/core/Matrix.js
@@ -0,0 +1,30 @@
+describe('pixi/core/Matrix', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var mat3 = PIXI.mat3;
+ var mat4 = PIXI.mat4;
+ var Matrix = PIXI.Matrix;
+
+ it('Ensure determineMatrixArrayType works', function () {
+ expect(Matrix).to.be.a('function');
+ });
+
+ it('mat3 exists', function () {
+ expect(mat3).to.be.an('object');
+ });
+
+ it('Confirm new mat3 matrix', function () {
+ var matrix = new mat3.create();
+ pixi_core_Matrix_confirmNewMat3(matrix);
+ });
+
+ it('mat3 exists', function () {
+ expect(mat4).to.be.an('object');
+ });
+
+ it('Confirm new mat4 matrix', function () {
+ var matrix = new mat4.create();
+ pixi_core_Matrix_confirmNewMat4(matrix);
+ });
+});
diff --git a/test/unit/pixi/core/Point.js b/test/unit/pixi/core/Point.js
new file mode 100644
index 0000000..c4d5163
--- /dev/null
+++ b/test/unit/pixi/core/Point.js
@@ -0,0 +1,15 @@
+describe('pixi/core/Point', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Point = PIXI.Point;
+
+ it('Module exists', function () {
+ expect(Point).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Point();
+ pixi_core_Point_confirm(obj, 0, 0);
+ });
+});
diff --git a/test/unit/pixi/core/Polygon.js b/test/unit/pixi/core/Polygon.js
new file mode 100644
index 0000000..dc8c918
--- /dev/null
+++ b/test/unit/pixi/core/Polygon.js
@@ -0,0 +1,20 @@
+describe('pixi/core/Polygon', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Polygon = PIXI.Polygon;
+
+ it('Module exists', function () {
+ expect(Polygon).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Polygon();
+
+ expect(obj).to.be.an.instanceof(Polygon);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.deep.property('points.length', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Rectangle.js b/test/unit/pixi/core/Rectangle.js
new file mode 100644
index 0000000..d43316e
--- /dev/null
+++ b/test/unit/pixi/core/Rectangle.js
@@ -0,0 +1,15 @@
+describe('pixi/core/Rectangle', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Rectangle = PIXI.Rectangle;
+
+ it('Module exists', function () {
+ expect(Rectangle).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var rect = new Rectangle();
+ pixi_core_Rectangle_confirm(rect, 0, 0, 0, 0);
+ });
+});
diff --git a/test/unit/pixi/display/DisplayObject.js b/test/unit/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..40c6fbc
--- /dev/null
+++ b/test/unit/pixi/display/DisplayObject.js
@@ -0,0 +1,21 @@
+describe('pixi/display/DisplayObject', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var DisplayObject = PIXI.DisplayObject;
+
+ it('Module exists', function () {
+ expect(DisplayObject).to.be.a('function');
+ expect(PIXI).to.have.property('visibleCount', 0);
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new DisplayObject();
+
+ pixi_display_DisplayObject_confirmNew(obj);
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', false);
+ expect(obj).to.have.property('stage', null);
+ });
+});
diff --git a/test/unit/pixi/display/DisplayObjectContainer.js b/test/unit/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..ce7f02f
--- /dev/null
+++ b/test/unit/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,20 @@
+describe('pixi/display/DisplayObjectContainer', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var DisplayObjectContainer = PIXI.DisplayObjectContainer;
+
+ it('Module exists', function () {
+ expect(DisplayObjectContainer).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new DisplayObjectContainer();
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', false);
+ expect(obj).to.have.property('stage', null);
+ });
+});
diff --git a/test/unit/pixi/display/MovieClip.js b/test/unit/pixi/display/MovieClip.js
new file mode 100644
index 0000000..f3c6c6a
--- /dev/null
+++ b/test/unit/pixi/display/MovieClip.js
@@ -0,0 +1,33 @@
+describe('pixi/display/MovieClip', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var MovieClip = PIXI.MovieClip;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(MovieClip).to.be.a('function');
+ });
+
+ it('Confirm new instance', function (done) {
+ var texture = Texture.fromImage('/base/test/textures/SpriteSheet-Explosion.png');
+ var obj = new MovieClip([texture]);
+
+ pixi_display_Sprite_confirmNew(obj, done);
+
+ expect(obj).to.be.an.instanceof(MovieClip);
+ expect(obj).to.respondTo('stop');
+ expect(obj).to.respondTo('play');
+ expect(obj).to.respondTo('gotoAndStop');
+ expect(obj).to.respondTo('gotoAndPlay');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('textures.length', 1);
+ expect(obj).to.have.deep.property('textures[0]', texture);
+ expect(obj).to.have.property('animationSpeed', 1);
+ expect(obj).to.have.property('loop', true);
+ expect(obj).to.have.property('onComplete', null);
+ expect(obj).to.have.property('currentFrame', 0);
+ expect(obj).to.have.property('playing', false);
+ });
+});
diff --git a/test/unit/pixi/display/Sprite.js b/test/unit/pixi/display/Sprite.js
new file mode 100644
index 0000000..54e914f
--- /dev/null
+++ b/test/unit/pixi/display/Sprite.js
@@ -0,0 +1,25 @@
+describe('pixi/display/Sprite', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Sprite = PIXI.Sprite;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(Sprite).to.be.a('function');
+ expect(PIXI).to.have.deep.property('blendModes.NORMAL', 0);
+ expect(PIXI).to.have.deep.property('blendModes.SCREEN', 1);
+ });
+
+ it('Members exist', function () {
+ expect(Sprite).itself.to.respondTo('fromImage');
+ expect(Sprite).itself.to.respondTo('fromFrame');
+ });
+
+ it('Confirm new instance', function (done) {
+ var texture = Texture.fromImage('/base/test/textures/SpriteSheet-Aliens.png');
+ var obj = new Sprite(texture);
+
+ pixi_display_Sprite_confirmNew(obj, done);
+ });
+});
diff --git a/test/unit/pixi/display/Stage.js b/test/unit/pixi/display/Stage.js
new file mode 100644
index 0000000..3cc2a4d
--- /dev/null
+++ b/test/unit/pixi/display/Stage.js
@@ -0,0 +1,49 @@
+describe('pixi/display/Stage', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Stage = PIXI.Stage;
+ var InteractionManager = PIXI.InteractionManager;
+ var Rectangle = PIXI.Rectangle;
+
+ it('Module exists', function () {
+ expect(Stage).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Stage(null, true);
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(Stage);
+ expect(obj).to.respondTo('updateTransform');
+ expect(obj).to.respondTo('setBackgroundColor');
+ expect(obj).to.respondTo('getMousePosition');
+
+ // FIXME: duplicate member in DisplayObject
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ // FIXME: convert arg to bool in constructor
+ expect(obj).to.have.property('interactive', true);
+
+ expect(obj).to.have.property('interactionManager')
+ .and.to.be.an.instanceof(InteractionManager)
+ .and.to.have.property('stage', obj);
+
+ expect(obj).to.have.property('dirty', true);
+
+ expect(obj).to.have.property('stage', obj);
+
+ expect(obj).to.have.property('hitArea')
+ .and.to.be.an.instanceof(Rectangle);
+ pixi_core_Rectangle_confirm(obj.hitArea, 0, 0, 100000, 100000);
+
+ expect(obj).to.have.property('backgroundColor', 0x000000);
+ expect(obj).to.have.deep.property('backgroundColorSplit.length', 3);
+ expect(obj).to.have.deep.property('backgroundColorSplit[0]', 0);
+ expect(obj).to.have.deep.property('backgroundColorSplit[1]', 0);
+ expect(obj).to.have.deep.property('backgroundColorSplit[2]', 0);
+ expect(obj).to.have.property('backgroundColorString', '#000000');
+
+ expect(obj).to.have.property('worldVisible', true);
+ });
+});
diff --git a/test/unit/pixi/extras/CustomRenderable.js b/test/unit/pixi/extras/CustomRenderable.js
new file mode 100644
index 0000000..8d83cf0
--- /dev/null
+++ b/test/unit/pixi/extras/CustomRenderable.js
@@ -0,0 +1,21 @@
+describe('pixi/extras/CustomRenderable', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var CustomRenderable = PIXI.CustomRenderable;
+
+ it('Module exists', function () {
+ expect(CustomRenderable).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new CustomRenderable();
+
+ pixi_display_DisplayObject_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(CustomRenderable);
+ expect(obj).to.respondTo('renderCanvas');
+ expect(obj).to.respondTo('initWebGL');
+ expect(obj).to.respondTo('renderWebGL');
+ });
+});
diff --git a/test/unit/pixi/extras/Rope.js b/test/unit/pixi/extras/Rope.js
new file mode 100644
index 0000000..6ddaf83
--- /dev/null
+++ b/test/unit/pixi/extras/Rope.js
@@ -0,0 +1,26 @@
+describe('pixi/extras/Rope', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Rope = PIXI.Rope;
+ var Texture = PIXI.Texture;
+ var Point = PIXI.Point;
+
+ it('Module exists', function () {
+ expect(Rope).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var texture = Texture.fromImage('/base/test/textures/bunny.png');
+ var obj = new Rope(texture, [new Point(), new Point(5, 10), new Point(10, 20)]);
+
+ pixi_extras_Strip_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(Rope);
+ expect(obj).to.respondTo('refresh');
+ expect(obj).to.respondTo('updateTransform');
+ expect(obj).to.respondTo('setTexture');
+
+ // TODO: Test properties
+ });
+});
diff --git a/test/unit/pixi/extras/Spine.js b/test/unit/pixi/extras/Spine.js
new file mode 100644
index 0000000..0708bc0
--- /dev/null
+++ b/test/unit/pixi/extras/Spine.js
@@ -0,0 +1,10 @@
+describe('pixi/extras/Spine', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Spine = PIXI.Spine;
+
+ it('Module exists', function () {
+ expect(Spine).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/extras/Strip.js b/test/unit/pixi/extras/Strip.js
new file mode 100644
index 0000000..8e564e1
--- /dev/null
+++ b/test/unit/pixi/extras/Strip.js
@@ -0,0 +1,18 @@
+describe('pixi/extras/Strip', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Strip = PIXI.Strip;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(Strip).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var texture = Texture.fromImage('/base/test/textures/bunny.png');
+ var obj = new Strip(texture, 20, 10000);
+
+ pixi_extras_Strip_confirmNew(obj);
+ });
+});
diff --git a/test/unit/pixi/extras/TilingSprite.js b/test/unit/pixi/extras/TilingSprite.js
new file mode 100644
index 0000000..56aea14
--- /dev/null
+++ b/test/unit/pixi/extras/TilingSprite.js
@@ -0,0 +1,24 @@
+describe('pixi/extras/TilingSprite', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var TilingSprite = PIXI.TilingSprite;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(TilingSprite).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var texture = Texture.fromImage('/base/test/textures/bunny.png');
+ var obj = new TilingSprite(texture, 6000, 12000);
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(TilingSprite);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ // TODO: Test properties
+ });
+});
diff --git a/test/unit/pixi/filters/FilterBlock.js b/test/unit/pixi/filters/FilterBlock.js
new file mode 100644
index 0000000..870cec0
--- /dev/null
+++ b/test/unit/pixi/filters/FilterBlock.js
@@ -0,0 +1,10 @@
+describe('pixi/filters/FilterBlock', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var FilterBlock = PIXI.FilterBlock;
+
+ it('Module exists', function () {
+ expect(FilterBlock).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/filters/MaskFilter.js b/test/unit/pixi/filters/MaskFilter.js
new file mode 100644
index 0000000..32d6a45
--- /dev/null
+++ b/test/unit/pixi/filters/MaskFilter.js
@@ -0,0 +1,10 @@
+describe('pixi/filters/MaskFilter', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ // var MaskFilter = PIXI.MaskFilter;
+
+ // it('Module exists', function () {
+ // expect(MaskFilter).to.be.a('function');
+ // });
+});
diff --git a/test/unit/pixi/loaders/AssetLoader.js b/test/unit/pixi/loaders/AssetLoader.js
new file mode 100644
index 0000000..a0aa0b5
--- /dev/null
+++ b/test/unit/pixi/loaders/AssetLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/AssetLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var AssetLoader = PIXI.AssetLoader;
+
+ it('Module exists', function () {
+ expect(AssetLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/BitmapFontLoader.js b/test/unit/pixi/loaders/BitmapFontLoader.js
new file mode 100644
index 0000000..6253c42
--- /dev/null
+++ b/test/unit/pixi/loaders/BitmapFontLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/BitmapFontLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var BitmapFontLoader = PIXI.BitmapFontLoader;
+
+ it('Module exists', function () {
+ expect(PIXI.BitmapFontLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/ImageLoader.js b/test/unit/pixi/loaders/ImageLoader.js
new file mode 100644
index 0000000..8b1f556
--- /dev/null
+++ b/test/unit/pixi/loaders/ImageLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/ImageLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var ImageLoader = PIXI.ImageLoader;
+
+ it('Module exists', function () {
+ expect(ImageLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/JsonLoader.js b/test/unit/pixi/loaders/JsonLoader.js
new file mode 100644
index 0000000..c577e83
--- /dev/null
+++ b/test/unit/pixi/loaders/JsonLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/JsonLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var JsonLoader = PIXI.JsonLoader;
+
+ it('Module exists', function () {
+ expect(JsonLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/SpineLoader.js b/test/unit/pixi/loaders/SpineLoader.js
new file mode 100644
index 0000000..fdcc0b8
--- /dev/null
+++ b/test/unit/pixi/loaders/SpineLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/SpineLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var SpineLoader = PIXI.SpineLoader;
+
+ it('Module exists', function () {
+ expect(SpineLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/SpriteSheetLoader.js b/test/unit/pixi/loaders/SpriteSheetLoader.js
new file mode 100644
index 0000000..57beb27
--- /dev/null
+++ b/test/unit/pixi/loaders/SpriteSheetLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/SpriteSheetLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var SpriteSheetLoader = PIXI.SpriteSheetLoader;
+
+ it('Module exists', function () {
+ expect(SpriteSheetLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/primitives/Graphics.js b/test/unit/pixi/primitives/Graphics.js
new file mode 100644
index 0000000..b8b3e5c
--- /dev/null
+++ b/test/unit/pixi/primitives/Graphics.js
@@ -0,0 +1,40 @@
+describe('pixi/primitives/Graphics', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Graphics = PIXI.Graphics;
+
+ it('Module exists', function () {
+ expect(Graphics).to.be.a('function');
+
+ expect(Graphics).itself.to.have.property('POLY', 0);
+ expect(Graphics).itself.to.have.property('RECT', 1);
+ expect(Graphics).itself.to.have.property('CIRC', 2);
+ expect(Graphics).itself.to.have.property('ELIP', 3);
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Graphics();
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(Graphics);
+ expect(obj).to.respondTo('lineStyle');
+ expect(obj).to.respondTo('lineStyle');
+ expect(obj).to.respondTo('moveTo');
+ expect(obj).to.respondTo('lineTo');
+ expect(obj).to.respondTo('beginFill');
+ expect(obj).to.respondTo('endFill');
+ expect(obj).to.respondTo('drawRect');
+ expect(obj).to.respondTo('drawCircle');
+ expect(obj).to.respondTo('drawElipse');
+ expect(obj).to.respondTo('clear');
+
+ expect(obj).to.have.property('renderable', true);
+ expect(obj).to.have.property('fillAlpha', 1);
+ expect(obj).to.have.property('lineWidth', 0);
+ expect(obj).to.have.property('lineColor', 'black');
+ expect(obj).to.have.deep.property('graphicsData.length', 0);
+ expect(obj).to.have.deep.property('currentPath.points.length', 0);
+ });
+});
diff --git a/test/unit/pixi/renderers/canvas/CanvasGraphics.js b/test/unit/pixi/renderers/canvas/CanvasGraphics.js
new file mode 100644
index 0000000..8f44472
--- /dev/null
+++ b/test/unit/pixi/renderers/canvas/CanvasGraphics.js
@@ -0,0 +1,15 @@
+describe('renders/canvas/CanvasGraphics', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var CanvasGraphics = PIXI.CanvasGraphics;
+
+ it('Module exists', function () {
+ expect(CanvasGraphics).to.be.a('function');
+ });
+
+ it('Members exist', function () {
+ expect(CanvasGraphics).itself.to.respondTo('renderGraphics');
+ expect(CanvasGraphics).itself.to.respondTo('renderGraphicsMask');
+ });
+});
diff --git a/test/unit/pixi/renderers/canvas/CanvasRenderer.js b/test/unit/pixi/renderers/canvas/CanvasRenderer.js
new file mode 100644
index 0000000..df3a12f
--- /dev/null
+++ b/test/unit/pixi/renderers/canvas/CanvasRenderer.js
@@ -0,0 +1,10 @@
+describe('renderers/canvas/CanvasRenderer', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var CanvasRenderer = PIXI.CanvasRenderer;
+
+ it('Module exists', function () {
+ expect(CanvasRenderer).to.be.a('function');
+ });
+});
diff --git a/.gitignore b/.gitignore
index 12e1b62..0b88317 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
node_modules
.DS_Store
-.project
\ No newline at end of file
+.project
+*.log
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..63e4d7c
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,8 @@
+language: node_js
+node_js:
+ - 0.10
+
+before_script:
+ - npm install -g grunt-cli
+ - export DISPLAY=:99.0
+ - sh -e /etc/init.d/xvfb start
diff --git a/Gruntfile.js b/Gruntfile.js
index b083b49..103938c 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -1,10 +1,12 @@
+'use strict';
+
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-connect');
- grunt.loadNpmTasks('grunt-contrib-qunit');
grunt.loadNpmTasks('grunt-contrib-yuidoc');
+ grunt.loadTasks('tasks');
var root = 'src/pixi/',
debug = 'bin/pixi.dev.js',
@@ -79,7 +81,7 @@
},
files: {
srcBlob: '<%= dirs.src %>/**/*.js',
- testBlob: '<%= dirs.test %>/unit/**/*.js',
+ testBlob: '<%= dirs.test %>/{functional,lib/pixi,unit}/**/*.js',
build: '<%= dirs.build %>/pixi.dev.js',
buildMin: '<%= dirs.build %>/pixi.js'
},
@@ -94,7 +96,12 @@
},
jshint: {
beforeconcat: srcFiles,
- test: ['<%= files.testBlob %>'],
+ test: {
+ src: ['<%= files.testBlob %>'],
+ options: {
+ expr: true
+ }
+ },
options: {
asi: true,
smarttabs: true
@@ -128,12 +135,6 @@
]
},
connect: {
- qunit: {
- options: {
- port: grunt.option('port-test') || 9002,
- base: './'
- }
- },
test: {
options: {
port: grunt.option('port-test') || 9002,
@@ -142,13 +143,6 @@
}
}
},
- qunit: {
- all: {
- options: {
- urls: ['http://localhost:' + (grunt.option('port-test') || 9002) + '/test/index.html']
- }
- }
- },
yuidoc: {
compile: {
name: '<%= pkg.name %>',
@@ -161,6 +155,13 @@
outdir: '<%= dirs.docs %>'
}
}
+ },
+ karma: {
+ unit: {
+ configFile: 'test/karma.conf.js',
+ // browsers: ['Chrome'],
+ singleRun: true
+ }
}
});
@@ -182,9 +183,10 @@
}
)
- grunt.registerTask('default', ['concat', 'uglify', 'distribute']);
grunt.registerTask('build', ['concat', 'uglify', 'distribute']);
- grunt.registerTask('test', ['build', 'connect:qunit', 'qunit']);
+ grunt.registerTask('test', ['concat', 'jshint:test', 'karma']);
grunt.registerTask('docs', ['yuidoc']);
-
-}
\ No newline at end of file
+ grunt.registerTask('default', ['test', 'uglify', 'distribute']);
+ // Travis CI task.
+ grunt.registerTask('travis', ['test']);
+}
diff --git a/README.md b/README.md
index c62ef86..690cfe4 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,8 @@

+[](http://travis-ci.org/drkibitz/pixi.js)
+
#### JavaScript 2D Renderer ####
The aim of this project is to provide a fast lightweight 2D library that works
diff --git a/package.json b/package.json
index b373240..1246a68 100644
--- a/package.json
+++ b/package.json
@@ -18,14 +18,21 @@
"main": "bin/pixi.js",
+ "scripts": {
+ "test": "grunt travis --verbose"
+ },
+
"dependencies": {},
"devDependencies": {
"grunt": "~0.4.x",
- "grunt-contrib-jshint": "0.3.x",
+ "grunt-contrib-jshint": "0.6.x",
"grunt-contrib-uglify": "0.2.x",
- "grunt-contrib-connect": "0.2.x",
- "grunt-contrib-qunit": "0.2.x",
+ "grunt-contrib-connect": "0.3.x",
"grunt-contrib-yuidoc": "0.4.x",
- "grunt-contrib-concat": "0.1.x"
+ "grunt-contrib-concat": "0.3.x",
+ "chai": "~1.7.0",
+ "karma": "0.11.0",
+ "karma-firefox-launcher": "0.1.0",
+ "karma-mocha": "0.1.0"
}
}
diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js
index a7c520e..ee82bbd 100644
--- a/src/pixi/InteractionManager.js
+++ b/src/pixi/InteractionManager.js
@@ -62,7 +62,6 @@
this.onTouchEnd = this.onTouchEnd.bind(this);
this.onTouchMove = this.onTouchMove.bind(this);
-
this.last = 0;
}
diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js
index 1a95d20..eef1059 100644
--- a/src/pixi/core/Ellipse.js
+++ b/src/pixi/core/Ellipse.js
@@ -78,7 +78,7 @@
return (normx + normy < 0.25);
}
-PIXI.Ellipse.getBounds = function()
+PIXI.Ellipse.prototype.getBounds = function()
{
return new PIXI.Rectangle(this.x, this.y, this.width, this.height);
}
diff --git a/tasks/karma.js b/tasks/karma.js
new file mode 100644
index 0000000..c340485
--- /dev/null
+++ b/tasks/karma.js
@@ -0,0 +1,27 @@
+'use strict';
+
+var path = require('path');
+var server = require('karma').server;
+
+module.exports = function (grunt) {
+ grunt.registerMultiTask('karma', 'run karma.', function() {
+ var done = this.async();
+ var options = this.options({
+ background: false
+ });
+ var data = this.data;
+
+ //merge options onto data, with data taking precedence
+ data = grunt.util._.merge(options, data);
+ data.configFile = path.resolve(data.configFile);
+ if (data.configFile) {
+ data.configFile = grunt.template.process(data.configFile);
+ }
+
+ server.start(
+ data,
+ function(code) {
+ done(!code);
+ });
+ });
+};
diff --git a/test/functional/example-1-basics/bunny.png b/test/functional/example-1-basics/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/functional/example-1-basics/bunny.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-30.png b/test/functional/example-1-basics/frame-30.png
new file mode 100644
index 0000000..96e3409
--- /dev/null
+++ b/test/functional/example-1-basics/frame-30.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-60.png b/test/functional/example-1-basics/frame-60.png
new file mode 100644
index 0000000..af3f4ce
--- /dev/null
+++ b/test/functional/example-1-basics/frame-60.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-90.png b/test/functional/example-1-basics/frame-90.png
new file mode 100644
index 0000000..099b823
--- /dev/null
+++ b/test/functional/example-1-basics/frame-90.png
Binary files differ
diff --git a/test/functional/example-1-basics/index.js b/test/functional/example-1-basics/index.js
new file mode 100644
index 0000000..7ae7a98
--- /dev/null
+++ b/test/functional/example-1-basics/index.js
@@ -0,0 +1,133 @@
+describe('Example 1 - Basics', function () {
+ 'use strict';
+
+ var baseUri = '/base/test/functional/example-1-basics';
+ var expect = chai.expect;
+ var currentFrame = 0;
+ var frameEvents = {};
+ var stage;
+ var renderer;
+ var bunny;
+
+ function onFrame(frame, callback) {
+ frameEvents[frame] = callback;
+ }
+
+ function animate() {
+ currentFrame += 1;
+
+ requestAnimFrame( animate );
+
+ // just for fun, lets rotate mr rabbit a little
+ bunny.rotation += 0.1;
+
+ // render the stage
+ renderer.render(stage);
+
+ if (frameEvents[currentFrame])
+ frameEvents[currentFrame](currentFrame);
+ }
+
+ function initScene() {
+ // create an new instance of a pixi stage
+ stage = new PIXI.Stage(0x66FF99);
+
+ // create a renderer instance
+ renderer = PIXI.autoDetectRenderer(400, 300);
+ console.log('Is PIXI.WebGLRenderer: ' + (renderer instanceof PIXI.WebGLRenderer));
+
+ // add the renderer view element to the DOM
+ document.body.appendChild(renderer.view);
+
+ requestAnimFrame( animate );
+
+ // create a texture from an image path
+ var texture = PIXI.Texture.fromImage(baseUri + "/bunny.png");
+ // create a new Sprite using the texture
+ bunny = new PIXI.Sprite(texture);
+
+ // center the sprites anchor point
+ bunny.anchor.x = 0.5;
+ bunny.anchor.y = 0.5;
+
+ // move the sprite t the center of the screen
+ bunny.position.x = 200;
+ bunny.position.y = 150;
+
+ stage.addChild(bunny);
+ }
+
+ it('assets loaded', function (done) {
+ var loader = new PIXI.AssetLoader([
+ baseUri + '/bunny.png',
+ baseUri + '/frame-30.png',
+ baseUri + '/frame-60.png',
+ baseUri + '/frame-90.png'
+ ]);
+ // loader.on('onProgress', function (event) {
+ // console.log(event.content);
+ // });
+ loader.on('onComplete', function (event) {
+ done();
+ initScene();
+ });
+ loader.load();
+ });
+
+ it('frame 30 should match', function (done) {
+ this.timeout(700);
+ onFrame(30, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-30.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 60 should match', function (done) {
+ this.timeout(1200);
+ onFrame(60, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-60.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 90 should match', function (done) {
+ this.timeout(1700);
+ onFrame(90, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-90.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ // it('capture something', function (done) {
+ // this.timeout(2000000);
+ // onFrame(30, function () {
+ // var img = new Image();
+ // img.src = renderer.view.toDataURL('image/png');
+ // document.body.appendChild(img);
+ // });
+ // });
+});
diff --git a/test/index.html b/test/index.html
deleted file mode 100644
index 9cbcac5..0000000
--- a/test/index.html
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
- Pixi.js Test Suite
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/test/karma.conf.js b/test/karma.conf.js
new file mode 100644
index 0000000..c66a696
--- /dev/null
+++ b/test/karma.conf.js
@@ -0,0 +1,82 @@
+module.exports = function(config) {
+ config.set({
+
+ // base path, that will be used to resolve files and exclude
+ basePath : '../',
+
+ frameworks : ['mocha'],
+
+ // list of files / patterns to load in the browser
+ files : [
+ 'node_modules/chai/chai.js',
+ 'bin/pixi.dev.js',
+ 'test/lib/**/*.js',
+ 'test/unit/**/*.js',
+ // 'test/functional/**/*.js',
+ {pattern: 'test/**/*.png', watched: false, included: false, served: true}
+ ],
+
+ // list of files to exclude
+ exclude : [],
+
+ // use dolts reporter, as travis terminal does not support escaping sequences
+ // possible values: 'dots', 'progress', 'junit', 'teamcity'
+ // CLI --reporters progress
+ reporters : ['progress'],
+
+ // web server port
+ // CLI --port 9876
+ port : 9876,
+
+ // cli runner port
+ // CLI --runner-port 9100
+ runnerPort : 9100,
+
+ // enable / disable colors in the output (reporters and logs)
+ // CLI --colors --no-colors
+ colors : true,
+
+ // level of logging
+ // possible values: karma.LOG_DISABLE || karma.LOG_ERROR || karma.LOG_WARN || karma.LOG_INFO || karma.LOG_DEBUG
+ // CLI --log-level debug
+ logLevel : config.LOG_DEBUG,
+
+ // enable / disable watching file and executing tests whenever any file changes
+ // CLI --auto-watch --no-auto-watch
+ autoWatch : false,
+
+ // Start these browsers, currently available:
+ // - Chrome
+ // - ChromeCanary
+ // - Firefox
+ // - Opera
+ // - Safari (only Mac)
+ // - PhantomJS
+ // - IE (only Windows)
+ // CLI --browsers Chrome,Firefox,Safari
+ browsers : ['Firefox'],
+
+ // If browser does not capture in given timeout [ms], kill it
+ // CLI --capture-timeout 5000
+ captureTimeout : 5000,
+
+ // Auto run tests on start (when browsers are captured) and exit
+ // CLI --single-run --no-single-run
+ singleRun : true,
+
+ // report which specs are slower than 500ms
+ // CLI --report-slower-than 500
+ reportSlowerThan : 1000,
+
+ preprocessors : {
+ // '**/client/js/*.js': 'coverage'
+ },
+
+ plugins : [
+ 'karma-mocha',
+ // 'karma-chrome-launcher',
+ 'karma-firefox-launcher',
+ // 'karma-phantomjs-launcher'
+ ]
+ });
+};
diff --git a/test/lib/pixi/core/Matrix.js b/test/lib/pixi/core/Matrix.js
new file mode 100644
index 0000000..d26386b
--- /dev/null
+++ b/test/lib/pixi/core/Matrix.js
@@ -0,0 +1,40 @@
+
+function pixi_core_Matrix_confirmNewMat3(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(1);
+ expect(matrix[5]).to.equal(0);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(1);
+}
+
+function pixi_core_Matrix_confirmNewMat4(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[0]).to.equal(1);
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(0);
+ expect(matrix[5]).to.equal(1);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(0);
+ expect(matrix[9]).to.equal(0);
+ expect(matrix[10]).to.equal(1);
+ expect(matrix[11]).to.equal(0);
+ expect(matrix[12]).to.equal(0);
+ expect(matrix[13]).to.equal(0);
+ expect(matrix[14]).to.equal(0);
+ expect(matrix[15]).to.equal(1);
+}
diff --git a/test/lib/pixi/core/Point.js b/test/lib/pixi/core/Point.js
new file mode 100644
index 0000000..e5df07b
--- /dev/null
+++ b/test/lib/pixi/core/Point.js
@@ -0,0 +1,10 @@
+
+function pixi_core_Point_confirm(obj, x, y) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Point);
+ expect(obj).to.respondTo('clone');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+}
diff --git a/test/lib/pixi/core/Rectangle.js b/test/lib/pixi/core/Rectangle.js
new file mode 100644
index 0000000..23f0d12
--- /dev/null
+++ b/test/lib/pixi/core/Rectangle.js
@@ -0,0 +1,13 @@
+
+function pixi_core_Rectangle_confirm(obj, x, y, width, height) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Rectangle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+ expect(obj).to.have.property('width', width);
+ expect(obj).to.have.property('height', height);
+}
diff --git a/test/lib/pixi/display/DisplayObject.js b/test/lib/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..1388a7f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObject.js
@@ -0,0 +1,43 @@
+
+function pixi_display_DisplayObject_confirmNew(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObject);
+ expect(obj).to.respondTo('setInteractive');
+ expect(obj).to.respondTo('addFilter');
+ expect(obj).to.respondTo('removeFilter');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.property('last', obj);
+ expect(obj).to.have.property('first', obj);
+
+ expect(obj).to.contain.property('position');
+ pixi_core_Point_confirm(obj.position, 0, 0);
+ expect(obj).to.contain.property('scale');
+ pixi_core_Point_confirm(obj.scale, 1, 1);
+ expect(obj).to.contain.property('pivot');
+ pixi_core_Point_confirm(obj.pivot, 0, 0);
+
+ expect(obj).to.have.property('rotation', 0);
+ expect(obj).to.have.property('alpha', 1);
+ expect(obj).to.have.property('visible', true);
+ expect(obj).to.have.property('buttonMode', false);
+ expect(obj).to.have.property('parent', null);
+ expect(obj).to.have.property('worldAlpha', 1);
+
+ expect(obj).to.have.property('hitArea');
+ expect(obj).to.have.property('interactive'); // TODO: Have a better default value
+ expect('mask' in obj).to.be.true; // TODO: Have a better default value
+ expect(obj.mask).to.be.undefined;
+
+ expect(obj).to.have.property('renderable');
+ expect(obj).to.have.property('stage');
+
+ expect(obj).to.have.deep.property('worldTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ expect(obj).to.have.deep.property('localTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.localTransform);
+
+ expect(obj).to.have.deep.property('color.length', 0);
+ expect(obj).to.have.property('dynamic', true);
+}
diff --git a/test/lib/pixi/display/DisplayObjectContainer.js b/test/lib/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..085c59f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,16 @@
+
+function pixi_display_DisplayObjectContainer_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObject_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObjectContainer);
+ expect(obj).to.respondTo('addChild');
+ expect(obj).to.respondTo('addChildAt');
+ expect(obj).to.respondTo('swapChildren');
+ expect(obj).to.respondTo('getChildAt');
+ expect(obj).to.respondTo('removeChild');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('children.length', 0);
+}
diff --git a/test/lib/pixi/display/Sprite.js b/test/lib/pixi/display/Sprite.js
new file mode 100644
index 0000000..cc7a2d6
--- /dev/null
+++ b/test/lib/pixi/display/Sprite.js
@@ -0,0 +1,28 @@
+
+function pixi_display_Sprite_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Sprite);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', true);
+ expect(obj).to.have.property('stage', null);
+
+ expect(obj).to.have.property('anchor');
+ pixi_core_Point_confirm(obj.anchor, 0, 0);
+
+ expect(obj).to.have.property('blendMode', PIXI.blendModes.NORMAL);
+ expect(obj).to.have.property('width', 1); // TODO: is 1 expected
+ expect(obj).to.have.property('height', 1); // TODO: is 1 expected
+
+ // FIXME: Just make this a boolean that is always there
+ expect(!!obj.updateFrame).to.equal(obj.texture.baseTexture.hasLoaded);
+
+ expect(obj).to.have.property('texture');
+ pixi_textures_Texture_confirmNew(obj.texture, done);
+}
diff --git a/test/lib/pixi/extras/Strip.js b/test/lib/pixi/extras/Strip.js
new file mode 100644
index 0000000..8927a8a
--- /dev/null
+++ b/test/lib/pixi/extras/Strip.js
@@ -0,0 +1,12 @@
+
+function pixi_extras_Strip_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Strip);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ // TODO: Test properties
+}
diff --git a/test/lib/pixi/textures/Texture.js b/test/lib/pixi/textures/Texture.js
new file mode 100644
index 0000000..d5867b6
--- /dev/null
+++ b/test/lib/pixi/textures/Texture.js
@@ -0,0 +1,31 @@
+
+function pixi_textures_Texture_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ function confirmFrameDone() {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, obj.baseTexture.width, obj.baseTexture.height);
+
+ expect(obj).to.have.property('width', obj.baseTexture.width);
+ expect(obj).to.have.property('height', obj.baseTexture.height);
+ done();
+ }
+
+ expect(obj).to.be.an.instanceof(PIXI.Texture);
+ pixi_utils_EventTarget_like(obj);
+
+ expect(obj).to.have.property('baseTexture')
+ .and.to.be.an.instanceof(PIXI.BaseTexture);
+
+ expect(obj).to.have.property('scope', obj);
+
+ expect(obj).to.have.property('trim');
+ pixi_core_Point_confirm(obj.trim, 0, 0);
+
+ expect(obj).to.have.property('frame');
+ if (obj.baseTexture.hasLoaded) {
+ confirmFrameDone();
+ } else {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, 1, 1);
+ obj.addEventListener('update', confirmFrameDone);
+ }
+}
diff --git a/test/lib/pixi/utils/EventTarget.js b/test/lib/pixi/utils/EventTarget.js
new file mode 100644
index 0000000..7b1dcfa
--- /dev/null
+++ b/test/lib/pixi/utils/EventTarget.js
@@ -0,0 +1,8 @@
+
+function pixi_utils_EventTarget_like(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.respondTo('addEventListener');
+ expect(obj).to.respondTo('dispatchEvent');
+ expect(obj).to.respondTo('removeEventListener');
+}
diff --git a/test/lib/qunit-1.11.0.css b/test/lib/qunit-1.11.0.css
deleted file mode 100644
index d7fc0c8..0000000
--- a/test/lib/qunit-1.11.0.css
+++ /dev/null
@@ -1,244 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-/** Font Family and Sizes */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
- font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
-}
-
-#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
-#qunit-tests { font-size: smaller; }
-
-
-/** Resets */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter {
- margin: 0;
- padding: 0;
-}
-
-
-/** Header */
-
-#qunit-header {
- padding: 0.5em 0 0.5em 1em;
-
- color: #8699a4;
- background-color: #0d3349;
-
- font-size: 1.5em;
- line-height: 1em;
- font-weight: normal;
-
- border-radius: 5px 5px 0 0;
- -moz-border-radius: 5px 5px 0 0;
- -webkit-border-top-right-radius: 5px;
- -webkit-border-top-left-radius: 5px;
-}
-
-#qunit-header a {
- text-decoration: none;
- color: #c2ccd1;
-}
-
-#qunit-header a:hover,
-#qunit-header a:focus {
- color: #fff;
-}
-
-#qunit-testrunner-toolbar label {
- display: inline-block;
- padding: 0 .5em 0 .1em;
-}
-
-#qunit-banner {
- height: 5px;
-}
-
-#qunit-testrunner-toolbar {
- padding: 0.5em 0 0.5em 2em;
- color: #5E740B;
- background-color: #eee;
- overflow: hidden;
-}
-
-#qunit-userAgent {
- padding: 0.5em 0 0.5em 2.5em;
- background-color: #2b81af;
- color: #fff;
- text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
-}
-
-#qunit-modulefilter-container {
- float: right;
-}
-
-/** Tests: Pass/Fail */
-
-#qunit-tests {
- list-style-position: inside;
-}
-
-#qunit-tests li {
- padding: 0.4em 0.5em 0.4em 2.5em;
- border-bottom: 1px solid #fff;
- list-style-position: inside;
-}
-
-#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running {
- display: none;
-}
-
-#qunit-tests li strong {
- cursor: pointer;
-}
-
-#qunit-tests li a {
- padding: 0.5em;
- color: #c2ccd1;
- text-decoration: none;
-}
-#qunit-tests li a:hover,
-#qunit-tests li a:focus {
- color: #000;
-}
-
-#qunit-tests li .runtime {
- float: right;
- font-size: smaller;
-}
-
-.qunit-assert-list {
- margin-top: 0.5em;
- padding: 0.5em;
-
- background-color: #fff;
-
- border-radius: 5px;
- -moz-border-radius: 5px;
- -webkit-border-radius: 5px;
-}
-
-.qunit-collapsed {
- display: none;
-}
-
-#qunit-tests table {
- border-collapse: collapse;
- margin-top: .2em;
-}
-
-#qunit-tests th {
- text-align: right;
- vertical-align: top;
- padding: 0 .5em 0 0;
-}
-
-#qunit-tests td {
- vertical-align: top;
-}
-
-#qunit-tests pre {
- margin: 0;
- white-space: pre-wrap;
- word-wrap: break-word;
-}
-
-#qunit-tests del {
- background-color: #e0f2be;
- color: #374e0c;
- text-decoration: none;
-}
-
-#qunit-tests ins {
- background-color: #ffcaca;
- color: #500;
- text-decoration: none;
-}
-
-/*** Test Counts */
-
-#qunit-tests b.counts { color: black; }
-#qunit-tests b.passed { color: #5E740B; }
-#qunit-tests b.failed { color: #710909; }
-
-#qunit-tests li li {
- padding: 5px;
- background-color: #fff;
- border-bottom: none;
- list-style-position: inside;
-}
-
-/*** Passing Styles */
-
-#qunit-tests li li.pass {
- color: #3c510c;
- background-color: #fff;
- border-left: 10px solid #C6E746;
-}
-
-#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
-#qunit-tests .pass .test-name { color: #366097; }
-
-#qunit-tests .pass .test-actual,
-#qunit-tests .pass .test-expected { color: #999999; }
-
-#qunit-banner.qunit-pass { background-color: #C6E746; }
-
-/*** Failing Styles */
-
-#qunit-tests li li.fail {
- color: #710909;
- background-color: #fff;
- border-left: 10px solid #EE5757;
- white-space: pre;
-}
-
-#qunit-tests > li:last-child {
- border-radius: 0 0 5px 5px;
- -moz-border-radius: 0 0 5px 5px;
- -webkit-border-bottom-right-radius: 5px;
- -webkit-border-bottom-left-radius: 5px;
-}
-
-#qunit-tests .fail { color: #000000; background-color: #EE5757; }
-#qunit-tests .fail .test-name,
-#qunit-tests .fail .module-name { color: #000000; }
-
-#qunit-tests .fail .test-actual { color: #EE5757; }
-#qunit-tests .fail .test-expected { color: green; }
-
-#qunit-banner.qunit-fail { background-color: #EE5757; }
-
-
-/** Result */
-
-#qunit-testresult {
- padding: 0.5em 0.5em 0.5em 2.5em;
-
- color: #2b81af;
- background-color: #D2E0E6;
-
- border-bottom: 1px solid white;
-}
-#qunit-testresult .module-name {
- font-weight: bold;
-}
-
-/** Fixture */
-
-#qunit-fixture {
- position: absolute;
- top: -10000px;
- left: -10000px;
- width: 1000px;
- height: 1000px;
-}
diff --git a/test/lib/qunit-1.11.0.js b/test/lib/qunit-1.11.0.js
deleted file mode 100644
index 302545f..0000000
--- a/test/lib/qunit-1.11.0.js
+++ /dev/null
@@ -1,2152 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-(function( window ) {
-
-var QUnit,
- assert,
- config,
- onErrorFnPrev,
- testId = 0,
- fileName = (sourceFromStacktrace( 0 ) || "" ).replace(/(:\d+)+\)?/, "").replace(/.+\//, ""),
- toString = Object.prototype.toString,
- hasOwn = Object.prototype.hasOwnProperty,
- // Keep a local reference to Date (GH-283)
- Date = window.Date,
- defined = {
- setTimeout: typeof window.setTimeout !== "undefined",
- sessionStorage: (function() {
- var x = "qunit-test-string";
- try {
- sessionStorage.setItem( x, x );
- sessionStorage.removeItem( x );
- return true;
- } catch( e ) {
- return false;
- }
- }())
- },
- /**
- * Provides a normalized error string, correcting an issue
- * with IE 7 (and prior) where Error.prototype.toString is
- * not properly implemented
- *
- * Based on http://es5.github.com/#x15.11.4.4
- *
- * @param {String|Error} error
- * @return {String} error message
- */
- errorString = function( error ) {
- var name, message,
- errorString = error.toString();
- if ( errorString.substring( 0, 7 ) === "[object" ) {
- name = error.name ? error.name.toString() : "Error";
- message = error.message ? error.message.toString() : "";
- if ( name && message ) {
- return name + ": " + message;
- } else if ( name ) {
- return name;
- } else if ( message ) {
- return message;
- } else {
- return "Error";
- }
- } else {
- return errorString;
- }
- },
- /**
- * Makes a clone of an object using only Array or Object as base,
- * and copies over the own enumerable properties.
- *
- * @param {Object} obj
- * @return {Object} New object with only the own properties (recursively).
- */
- objectValues = function( obj ) {
- // Grunt 0.3.x uses an older version of jshint that still has jshint/jshint#392.
- /*jshint newcap: false */
- var key, val,
- vals = QUnit.is( "array", obj ) ? [] : {};
- for ( key in obj ) {
- if ( hasOwn.call( obj, key ) ) {
- val = obj[key];
- vals[key] = val === Object(val) ? objectValues(val) : val;
- }
- }
- return vals;
- };
-
-function Test( settings ) {
- extend( this, settings );
- this.assertions = [];
- this.testNumber = ++Test.count;
-}
-
-Test.count = 0;
-
-Test.prototype = {
- init: function() {
- var a, b, li,
- tests = id( "qunit-tests" );
-
- if ( tests ) {
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml;
-
- // `a` initialized at top of scope
- a = document.createElement( "a" );
- a.innerHTML = "Rerun";
- a.href = QUnit.url({ testNumber: this.testNumber });
-
- li = document.createElement( "li" );
- li.appendChild( b );
- li.appendChild( a );
- li.className = "running";
- li.id = this.id = "qunit-test-output" + testId++;
-
- tests.appendChild( li );
- }
- },
- setup: function() {
- if ( this.module !== config.previousModule ) {
- if ( config.previousModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.previousModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
- config.previousModule = this.module;
- config.moduleStats = { all: 0, bad: 0 };
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- } else if ( config.autorun ) {
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- }
-
- config.current = this;
-
- this.testEnvironment = extend({
- setup: function() {},
- teardown: function() {}
- }, this.moduleTestEnvironment );
-
- this.started = +new Date();
- runLoggingCallbacks( "testStart", QUnit, {
- name: this.testName,
- module: this.module
- });
-
- // allow utility functions to access the current test environment
- // TODO why??
- QUnit.current_testEnvironment = this.testEnvironment;
-
- if ( !config.pollution ) {
- saveGlobal();
- }
- if ( config.notrycatch ) {
- this.testEnvironment.setup.call( this.testEnvironment );
- return;
- }
- try {
- this.testEnvironment.setup.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Setup failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- },
- run: function() {
- config.current = this;
-
- var running = id( "qunit-testresult" );
-
- if ( running ) {
- running.innerHTML = "Running:
" + this.nameHtml;
- }
-
- if ( this.async ) {
- QUnit.stop();
- }
-
- this.callbackStarted = +new Date();
-
- if ( config.notrycatch ) {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- return;
- }
-
- try {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- } catch( e ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
-
- QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + " " + this.stack + ": " + ( e.message || e ), extractStacktrace( e, 0 ) );
- // else next test will carry the responsibility
- saveGlobal();
-
- // Restart the tests if they're blocking
- if ( config.blocking ) {
- QUnit.start();
- }
- }
- },
- teardown: function() {
- config.current = this;
- if ( config.notrycatch ) {
- if ( typeof this.callbackRuntime === "undefined" ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
- }
- this.testEnvironment.teardown.call( this.testEnvironment );
- return;
- } else {
- try {
- this.testEnvironment.teardown.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Teardown failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- }
- checkPollution();
- },
- finish: function() {
- config.current = this;
- if ( config.requireExpects && this.expected === null ) {
- QUnit.pushFailure( "Expected number of assertions to be defined, but expect() was not called.", this.stack );
- } else if ( this.expected !== null && this.expected !== this.assertions.length ) {
- QUnit.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack );
- } else if ( this.expected === null && !this.assertions.length ) {
- QUnit.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions.", this.stack );
- }
-
- var i, assertion, a, b, time, li, ol,
- test = this,
- good = 0,
- bad = 0,
- tests = id( "qunit-tests" );
-
- this.runtime = +new Date() - this.started;
- config.stats.all += this.assertions.length;
- config.moduleStats.all += this.assertions.length;
-
- if ( tests ) {
- ol = document.createElement( "ol" );
- ol.className = "qunit-assert-list";
-
- for ( i = 0; i < this.assertions.length; i++ ) {
- assertion = this.assertions[i];
-
- li = document.createElement( "li" );
- li.className = assertion.result ? "pass" : "fail";
- li.innerHTML = assertion.message || ( assertion.result ? "okay" : "failed" );
- ol.appendChild( li );
-
- if ( assertion.result ) {
- good++;
- } else {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
-
- // store result when possible
- if ( QUnit.config.reorder && defined.sessionStorage ) {
- if ( bad ) {
- sessionStorage.setItem( "qunit-test-" + this.module + "-" + this.testName, bad );
- } else {
- sessionStorage.removeItem( "qunit-test-" + this.module + "-" + this.testName );
- }
- }
-
- if ( bad === 0 ) {
- addClass( ol, "qunit-collapsed" );
- }
-
- // `b` initialized at top of scope
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml + " (" + bad + ", " + good + ", " + this.assertions.length + ")";
-
- addEvent(b, "click", function() {
- var next = b.parentNode.lastChild,
- collapsed = hasClass( next, "qunit-collapsed" );
- ( collapsed ? removeClass : addClass )( next, "qunit-collapsed" );
- });
-
- addEvent(b, "dblclick", function( e ) {
- var target = e && e.target ? e.target : window.event.srcElement;
- if ( target.nodeName.toLowerCase() === "span" || target.nodeName.toLowerCase() === "b" ) {
- target = target.parentNode;
- }
- if ( window.location && target.nodeName.toLowerCase() === "strong" ) {
- window.location = QUnit.url({ testNumber: test.testNumber });
- }
- });
-
- // `time` initialized at top of scope
- time = document.createElement( "span" );
- time.className = "runtime";
- time.innerHTML = this.runtime + " ms";
-
- // `li` initialized at top of scope
- li = id( this.id );
- li.className = bad ? "fail" : "pass";
- li.removeChild( li.firstChild );
- a = li.firstChild;
- li.appendChild( b );
- li.appendChild( a );
- li.appendChild( time );
- li.appendChild( ol );
-
- } else {
- for ( i = 0; i < this.assertions.length; i++ ) {
- if ( !this.assertions[i].result ) {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
- }
-
- runLoggingCallbacks( "testDone", QUnit, {
- name: this.testName,
- module: this.module,
- failed: bad,
- passed: this.assertions.length - bad,
- total: this.assertions.length,
- duration: this.runtime
- });
-
- QUnit.reset();
-
- config.current = undefined;
- },
-
- queue: function() {
- var bad,
- test = this;
-
- synchronize(function() {
- test.init();
- });
- function run() {
- // each of these can by async
- synchronize(function() {
- test.setup();
- });
- synchronize(function() {
- test.run();
- });
- synchronize(function() {
- test.teardown();
- });
- synchronize(function() {
- test.finish();
- });
- }
-
- // `bad` initialized at top of scope
- // defer when previous test run passed, if storage is available
- bad = QUnit.config.reorder && defined.sessionStorage &&
- +sessionStorage.getItem( "qunit-test-" + this.module + "-" + this.testName );
-
- if ( bad ) {
- run();
- } else {
- synchronize( run, true );
- }
- }
-};
-
-// Root QUnit object.
-// `QUnit` initialized at top of scope
-QUnit = {
-
- // call on start of module test to prepend name to all tests
- module: function( name, testEnvironment ) {
- config.currentModule = name;
- config.currentModuleTestEnvironment = testEnvironment;
- config.modules[name] = true;
- },
-
- asyncTest: function( testName, expected, callback ) {
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- QUnit.test( testName, expected, callback, true );
- },
-
- test: function( testName, expected, callback, async ) {
- var test,
- nameHtml = "" + escapeText( testName ) + "";
-
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- if ( config.currentModule ) {
- nameHtml = "" + escapeText( config.currentModule ) + ": " + nameHtml;
- }
-
- test = new Test({
- nameHtml: nameHtml,
- testName: testName,
- expected: expected,
- async: async,
- callback: callback,
- module: config.currentModule,
- moduleTestEnvironment: config.currentModuleTestEnvironment,
- stack: sourceFromStacktrace( 2 )
- });
-
- if ( !validTest( test ) ) {
- return;
- }
-
- test.queue();
- },
-
- // Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through.
- expect: function( asserts ) {
- if (arguments.length === 1) {
- config.current.expected = asserts;
- } else {
- return config.current.expected;
- }
- },
-
- start: function( count ) {
- // QUnit hasn't been initialized yet.
- // Note: RequireJS (et al) may delay onLoad
- if ( config.semaphore === undefined ) {
- QUnit.begin(function() {
- // This is triggered at the top of QUnit.load, push start() to the event loop, to allow QUnit.load to finish first
- setTimeout(function() {
- QUnit.start( count );
- });
- });
- return;
- }
-
- config.semaphore -= count || 1;
- // don't start until equal number of stop-calls
- if ( config.semaphore > 0 ) {
- return;
- }
- // ignore if start is called more often then stop
- if ( config.semaphore < 0 ) {
- config.semaphore = 0;
- QUnit.pushFailure( "Called start() while already started (QUnit.config.semaphore was 0 already)", null, sourceFromStacktrace(2) );
- return;
- }
- // A slight delay, to avoid any current callbacks
- if ( defined.setTimeout ) {
- window.setTimeout(function() {
- if ( config.semaphore > 0 ) {
- return;
- }
- if ( config.timeout ) {
- clearTimeout( config.timeout );
- }
-
- config.blocking = false;
- process( true );
- }, 13);
- } else {
- config.blocking = false;
- process( true );
- }
- },
-
- stop: function( count ) {
- config.semaphore += count || 1;
- config.blocking = true;
-
- if ( config.testTimeout && defined.setTimeout ) {
- clearTimeout( config.timeout );
- config.timeout = window.setTimeout(function() {
- QUnit.ok( false, "Test timed out" );
- config.semaphore = 1;
- QUnit.start();
- }, config.testTimeout );
- }
- }
-};
-
-// `assert` initialized at top of scope
-// Asssert helpers
-// All of these must either call QUnit.push() or manually do:
-// - runLoggingCallbacks( "log", .. );
-// - config.current.assertions.push({ .. });
-// We attach it to the QUnit object *after* we expose the public API,
-// otherwise `assert` will become a global variable in browsers (#341).
-assert = {
- /**
- * Asserts rough true-ish result.
- * @name ok
- * @function
- * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" );
- */
- ok: function( result, msg ) {
- if ( !config.current ) {
- throw new Error( "ok() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
- result = !!result;
-
- var source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: msg
- };
-
- msg = escapeText( msg || (result ? "okay" : "failed" ) );
- msg = "" + msg + "";
-
- if ( !result ) {
- source = sourceFromStacktrace( 2 );
- if ( source ) {
- details.source = source;
- msg += "Source: | " + escapeText( source ) + " |
---|
";
- }
- }
- runLoggingCallbacks( "log", QUnit, details );
- config.current.assertions.push({
- result: result,
- message: msg
- });
- },
-
- /**
- * Assert that the first two arguments are equal, with an optional message.
- * Prints out both actual and expected values.
- * @name equal
- * @function
- * @example equal( format( "Received {0} bytes.", 2), "Received 2 bytes.", "format() replaces {0} with next argument" );
- */
- equal: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected == actual, actual, expected, message );
- },
-
- /**
- * @name notEqual
- * @function
- */
- notEqual: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected != actual, actual, expected, message );
- },
-
- /**
- * @name propEqual
- * @function
- */
- propEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notPropEqual
- * @function
- */
- notPropEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name deepEqual
- * @function
- */
- deepEqual: function( actual, expected, message ) {
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notDeepEqual
- * @function
- */
- notDeepEqual: function( actual, expected, message ) {
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name strictEqual
- * @function
- */
- strictEqual: function( actual, expected, message ) {
- QUnit.push( expected === actual, actual, expected, message );
- },
-
- /**
- * @name notStrictEqual
- * @function
- */
- notStrictEqual: function( actual, expected, message ) {
- QUnit.push( expected !== actual, actual, expected, message );
- },
-
- "throws": function( block, expected, message ) {
- var actual,
- expectedOutput = expected,
- ok = false;
-
- // 'expected' is optional
- if ( typeof expected === "string" ) {
- message = expected;
- expected = null;
- }
-
- config.current.ignoreGlobalErrors = true;
- try {
- block.call( config.current.testEnvironment );
- } catch (e) {
- actual = e;
- }
- config.current.ignoreGlobalErrors = false;
-
- if ( actual ) {
- // we don't want to validate thrown error
- if ( !expected ) {
- ok = true;
- expectedOutput = null;
- // expected is a regexp
- } else if ( QUnit.objectType( expected ) === "regexp" ) {
- ok = expected.test( errorString( actual ) );
- // expected is a constructor
- } else if ( actual instanceof expected ) {
- ok = true;
- // expected is a validation function which returns true is validation passed
- } else if ( expected.call( {}, actual ) === true ) {
- expectedOutput = null;
- ok = true;
- }
-
- QUnit.push( ok, actual, expectedOutput, message );
- } else {
- QUnit.pushFailure( message, null, 'No exception was thrown.' );
- }
- }
-};
-
-/**
- * @deprecate since 1.8.0
- * Kept assertion helpers in root for backwards compatibility.
- */
-extend( QUnit, assert );
-
-/**
- * @deprecated since 1.9.0
- * Kept root "raises()" for backwards compatibility.
- * (Note that we don't introduce assert.raises).
- */
-QUnit.raises = assert[ "throws" ];
-
-/**
- * @deprecated since 1.0.0, replaced with error pushes since 1.3.0
- * Kept to avoid TypeErrors for undefined methods.
- */
-QUnit.equals = function() {
- QUnit.push( false, false, false, "QUnit.equals has been deprecated since 2009 (e88049a0), use QUnit.equal instead" );
-};
-QUnit.same = function() {
- QUnit.push( false, false, false, "QUnit.same has been deprecated since 2009 (e88049a0), use QUnit.deepEqual instead" );
-};
-
-// We want access to the constructor's prototype
-(function() {
- function F() {}
- F.prototype = QUnit;
- QUnit = new F();
- // Make F QUnit's constructor so that we can add to the prototype later
- QUnit.constructor = F;
-}());
-
-/**
- * Config object: Maintain internal state
- * Later exposed as QUnit.config
- * `config` initialized at top of scope
- */
-config = {
- // The queue of tests to run
- queue: [],
-
- // block until document ready
- blocking: true,
-
- // when enabled, show only failing tests
- // gets persisted through sessionStorage and can be changed in UI via checkbox
- hidepassed: false,
-
- // by default, run previously failed tests first
- // very useful in combination with "Hide passed tests" checked
- reorder: true,
-
- // by default, modify document.title when suite is done
- altertitle: true,
-
- // when enabled, all tests must call expect()
- requireExpects: false,
-
- // add checkboxes that are persisted in the query-string
- // when enabled, the id is set to `true` as a `QUnit.config` property
- urlConfig: [
- {
- id: "noglobals",
- label: "Check for Globals",
- tooltip: "Enabling this will test if any test introduces new properties on the `window` object. Stored as query-strings."
- },
- {
- id: "notrycatch",
- label: "No try-catch",
- tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging exceptions in IE reasonable. Stored as query-strings."
- }
- ],
-
- // Set of all modules.
- modules: {},
-
- // logging callback queues
- begin: [],
- done: [],
- log: [],
- testStart: [],
- testDone: [],
- moduleStart: [],
- moduleDone: []
-};
-
-// Export global variables, unless an 'exports' object exists,
-// in that case we assume we're in CommonJS (dealt with on the bottom of the script)
-if ( typeof exports === "undefined" ) {
- extend( window, QUnit );
-
- // Expose QUnit object
- window.QUnit = QUnit;
-}
-
-// Initialize more QUnit.config and QUnit.urlParams
-(function() {
- var i,
- location = window.location || { search: "", protocol: "file:" },
- params = location.search.slice( 1 ).split( "&" ),
- length = params.length,
- urlParams = {},
- current;
-
- if ( params[ 0 ] ) {
- for ( i = 0; i < length; i++ ) {
- current = params[ i ].split( "=" );
- current[ 0 ] = decodeURIComponent( current[ 0 ] );
- // allow just a key to turn on a flag, e.g., test.html?noglobals
- current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true;
- urlParams[ current[ 0 ] ] = current[ 1 ];
- }
- }
-
- QUnit.urlParams = urlParams;
-
- // String search anywhere in moduleName+testName
- config.filter = urlParams.filter;
-
- // Exact match of the module name
- config.module = urlParams.module;
-
- config.testNumber = parseInt( urlParams.testNumber, 10 ) || null;
-
- // Figure out if we're running the tests from a server or not
- QUnit.isLocal = location.protocol === "file:";
-}());
-
-// Extend QUnit object,
-// these after set here because they should not be exposed as global functions
-extend( QUnit, {
- assert: assert,
-
- config: config,
-
- // Initialize the configuration options
- init: function() {
- extend( config, {
- stats: { all: 0, bad: 0 },
- moduleStats: { all: 0, bad: 0 },
- started: +new Date(),
- updateRate: 1000,
- blocking: false,
- autostart: true,
- autorun: false,
- filter: "",
- queue: [],
- semaphore: 1
- });
-
- var tests, banner, result,
- qunit = id( "qunit" );
-
- if ( qunit ) {
- qunit.innerHTML =
- "" +
- "" +
- "" +
- "" +
- "
";
- }
-
- tests = id( "qunit-tests" );
- banner = id( "qunit-banner" );
- result = id( "qunit-testresult" );
-
- if ( tests ) {
- tests.innerHTML = "";
- }
-
- if ( banner ) {
- banner.className = "";
- }
-
- if ( result ) {
- result.parentNode.removeChild( result );
- }
-
- if ( tests ) {
- result = document.createElement( "p" );
- result.id = "qunit-testresult";
- result.className = "result";
- tests.parentNode.insertBefore( result, tests );
- result.innerHTML = "Running...
";
- }
- },
-
- // Resets the test setup. Useful for tests that modify the DOM.
- reset: function() {
- var fixture = id( "qunit-fixture" );
- if ( fixture ) {
- fixture.innerHTML = config.fixture;
- }
- },
-
- // Trigger an event on an element.
- // @example triggerEvent( document.body, "click" );
- triggerEvent: function( elem, type, event ) {
- if ( document.createEvent ) {
- event = document.createEvent( "MouseEvents" );
- event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView,
- 0, 0, 0, 0, 0, false, false, false, false, 0, null);
-
- elem.dispatchEvent( event );
- } else if ( elem.fireEvent ) {
- elem.fireEvent( "on" + type );
- }
- },
-
- // Safe object type checking
- is: function( type, obj ) {
- return QUnit.objectType( obj ) === type;
- },
-
- objectType: function( obj ) {
- if ( typeof obj === "undefined" ) {
- return "undefined";
- // consider: typeof null === object
- }
- if ( obj === null ) {
- return "null";
- }
-
- var match = toString.call( obj ).match(/^\[object\s(.*)\]$/),
- type = match && match[1] || "";
-
- switch ( type ) {
- case "Number":
- if ( isNaN(obj) ) {
- return "nan";
- }
- return "number";
- case "String":
- case "Boolean":
- case "Array":
- case "Date":
- case "RegExp":
- case "Function":
- return type.toLowerCase();
- }
- if ( typeof obj === "object" ) {
- return "object";
- }
- return undefined;
- },
-
- push: function( result, actual, expected, message ) {
- if ( !config.current ) {
- throw new Error( "assertion outside test context, was " + sourceFromStacktrace() );
- }
-
- var output, source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: message,
- actual: actual,
- expected: expected
- };
-
- message = escapeText( message ) || ( result ? "okay" : "failed" );
- message = "" + message + "";
- output = message;
-
- if ( !result ) {
- expected = escapeText( QUnit.jsDump.parse(expected) );
- actual = escapeText( QUnit.jsDump.parse(actual) );
- output += "Expected: | " + expected + " |
";
-
- if ( actual !== expected ) {
- output += "Result: | " + actual + " |
";
- output += "Diff: | " + QUnit.diff( expected, actual ) + " |
";
- }
-
- source = sourceFromStacktrace();
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
- }
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: !!result,
- message: output
- });
- },
-
- pushFailure: function( message, source, actual ) {
- if ( !config.current ) {
- throw new Error( "pushFailure() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
-
- var output,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: false,
- message: message
- };
-
- message = escapeText( message ) || "error";
- message = "" + message + "";
- output = message;
-
- output += "";
-
- if ( actual ) {
- output += "Result: | " + escapeText( actual ) + " |
";
- }
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: false,
- message: output
- });
- },
-
- url: function( params ) {
- params = extend( extend( {}, QUnit.urlParams ), params );
- var key,
- querystring = "?";
-
- for ( key in params ) {
- if ( !hasOwn.call( params, key ) ) {
- continue;
- }
- querystring += encodeURIComponent( key ) + "=" +
- encodeURIComponent( params[ key ] ) + "&";
- }
- return window.location.protocol + "//" + window.location.host +
- window.location.pathname + querystring.slice( 0, -1 );
- },
-
- extend: extend,
- id: id,
- addEvent: addEvent
- // load, equiv, jsDump, diff: Attached later
-});
-
-/**
- * @deprecated: Created for backwards compatibility with test runner that set the hook function
- * into QUnit.{hook}, instead of invoking it and passing the hook function.
- * QUnit.constructor is set to the empty F() above so that we can add to it's prototype here.
- * Doing this allows us to tell if the following methods have been overwritten on the actual
- * QUnit object.
- */
-extend( QUnit.constructor.prototype, {
-
- // Logging callbacks; all receive a single argument with the listed properties
- // run test/logs.html for any related changes
- begin: registerLoggingCallback( "begin" ),
-
- // done: { failed, passed, total, runtime }
- done: registerLoggingCallback( "done" ),
-
- // log: { result, actual, expected, message }
- log: registerLoggingCallback( "log" ),
-
- // testStart: { name }
- testStart: registerLoggingCallback( "testStart" ),
-
- // testDone: { name, failed, passed, total, duration }
- testDone: registerLoggingCallback( "testDone" ),
-
- // moduleStart: { name }
- moduleStart: registerLoggingCallback( "moduleStart" ),
-
- // moduleDone: { name, failed, passed, total }
- moduleDone: registerLoggingCallback( "moduleDone" )
-});
-
-if ( typeof document === "undefined" || document.readyState === "complete" ) {
- config.autorun = true;
-}
-
-QUnit.load = function() {
- runLoggingCallbacks( "begin", QUnit, {} );
-
- // Initialize the config, saving the execution queue
- var banner, filter, i, label, len, main, ol, toolbar, userAgent, val,
- urlConfigCheckboxesContainer, urlConfigCheckboxes, moduleFilter,
- numModules = 0,
- moduleFilterHtml = "",
- urlConfigHtml = "",
- oldconfig = extend( {}, config );
-
- QUnit.init();
- extend(config, oldconfig);
-
- config.blocking = false;
-
- len = config.urlConfig.length;
-
- for ( i = 0; i < len; i++ ) {
- val = config.urlConfig[i];
- if ( typeof val === "string" ) {
- val = {
- id: val,
- label: val,
- tooltip: "[no tooltip available]"
- };
- }
- config[ val.id ] = QUnit.urlParams[ val.id ];
- urlConfigHtml += "";
- }
-
- moduleFilterHtml += "";
-
- // `userAgent` initialized at top of scope
- userAgent = id( "qunit-userAgent" );
- if ( userAgent ) {
- userAgent.innerHTML = navigator.userAgent;
- }
-
- // `banner` initialized at top of scope
- banner = id( "qunit-header" );
- if ( banner ) {
- banner.innerHTML = "" + banner.innerHTML + " ";
- }
-
- // `toolbar` initialized at top of scope
- toolbar = id( "qunit-testrunner-toolbar" );
- if ( toolbar ) {
- // `filter` initialized at top of scope
- filter = document.createElement( "input" );
- filter.type = "checkbox";
- filter.id = "qunit-filter-pass";
-
- addEvent( filter, "click", function() {
- var tmp,
- ol = document.getElementById( "qunit-tests" );
-
- if ( filter.checked ) {
- ol.className = ol.className + " hidepass";
- } else {
- tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " ";
- ol.className = tmp.replace( / hidepass /, " " );
- }
- if ( defined.sessionStorage ) {
- if (filter.checked) {
- sessionStorage.setItem( "qunit-filter-passed-tests", "true" );
- } else {
- sessionStorage.removeItem( "qunit-filter-passed-tests" );
- }
- }
- });
-
- if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem( "qunit-filter-passed-tests" ) ) {
- filter.checked = true;
- // `ol` initialized at top of scope
- ol = document.getElementById( "qunit-tests" );
- ol.className = ol.className + " hidepass";
- }
- toolbar.appendChild( filter );
-
- // `label` initialized at top of scope
- label = document.createElement( "label" );
- label.setAttribute( "for", "qunit-filter-pass" );
- label.setAttribute( "title", "Only show tests and assertons that fail. Stored in sessionStorage." );
- label.innerHTML = "Hide passed tests";
- toolbar.appendChild( label );
-
- urlConfigCheckboxesContainer = document.createElement("span");
- urlConfigCheckboxesContainer.innerHTML = urlConfigHtml;
- urlConfigCheckboxes = urlConfigCheckboxesContainer.getElementsByTagName("input");
- // For oldIE support:
- // * Add handlers to the individual elements instead of the container
- // * Use "click" instead of "change"
- // * Fallback from event.target to event.srcElement
- addEvents( urlConfigCheckboxes, "click", function( event ) {
- var params = {},
- target = event.target || event.srcElement;
- params[ target.name ] = target.checked ? true : undefined;
- window.location = QUnit.url( params );
- });
- toolbar.appendChild( urlConfigCheckboxesContainer );
-
- if (numModules > 1) {
- moduleFilter = document.createElement( 'span' );
- moduleFilter.setAttribute( 'id', 'qunit-modulefilter-container' );
- moduleFilter.innerHTML = moduleFilterHtml;
- addEvent( moduleFilter.lastChild, "change", function() {
- var selectBox = moduleFilter.getElementsByTagName("select")[0],
- selectedModule = decodeURIComponent(selectBox.options[selectBox.selectedIndex].value);
-
- window.location = QUnit.url( { module: ( selectedModule === "" ) ? undefined : selectedModule } );
- });
- toolbar.appendChild(moduleFilter);
- }
- }
-
- // `main` initialized at top of scope
- main = id( "qunit-fixture" );
- if ( main ) {
- config.fixture = main.innerHTML;
- }
-
- if ( config.autostart ) {
- QUnit.start();
- }
-};
-
-addEvent( window, "load", QUnit.load );
-
-// `onErrorFnPrev` initialized at top of scope
-// Preserve other handlers
-onErrorFnPrev = window.onerror;
-
-// Cover uncaught exceptions
-// Returning true will surpress the default browser handler,
-// returning false will let it run.
-window.onerror = function ( error, filePath, linerNr ) {
- var ret = false;
- if ( onErrorFnPrev ) {
- ret = onErrorFnPrev( error, filePath, linerNr );
- }
-
- // Treat return value as window.onerror itself does,
- // Only do our handling if not surpressed.
- if ( ret !== true ) {
- if ( QUnit.config.current ) {
- if ( QUnit.config.current.ignoreGlobalErrors ) {
- return true;
- }
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- } else {
- QUnit.test( "global failure", extend( function() {
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- }, { validTest: validTest } ) );
- }
- return false;
- }
-
- return ret;
-};
-
-function done() {
- config.autorun = true;
-
- // Log the last module results
- if ( config.currentModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.currentModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
-
- var i, key,
- banner = id( "qunit-banner" ),
- tests = id( "qunit-tests" ),
- runtime = +new Date() - config.started,
- passed = config.stats.all - config.stats.bad,
- html = [
- "Tests completed in ",
- runtime,
- " milliseconds.
",
- "",
- passed,
- " assertions of ",
- config.stats.all,
- " passed, ",
- config.stats.bad,
- " failed."
- ].join( "" );
-
- if ( banner ) {
- banner.className = ( config.stats.bad ? "qunit-fail" : "qunit-pass" );
- }
-
- if ( tests ) {
- id( "qunit-testresult" ).innerHTML = html;
- }
-
- if ( config.altertitle && typeof document !== "undefined" && document.title ) {
- // show ✖ for good, ✔ for bad suite result in title
- // use escape sequences in case file gets loaded with non-utf-8-charset
- document.title = [
- ( config.stats.bad ? "\u2716" : "\u2714" ),
- document.title.replace( /^[\u2714\u2716] /i, "" )
- ].join( " " );
- }
-
- // clear own sessionStorage items if all tests passed
- if ( config.reorder && defined.sessionStorage && config.stats.bad === 0 ) {
- // `key` & `i` initialized at top of scope
- for ( i = 0; i < sessionStorage.length; i++ ) {
- key = sessionStorage.key( i++ );
- if ( key.indexOf( "qunit-test-" ) === 0 ) {
- sessionStorage.removeItem( key );
- }
- }
- }
-
- // scroll back to top to show results
- if ( window.scrollTo ) {
- window.scrollTo(0, 0);
- }
-
- runLoggingCallbacks( "done", QUnit, {
- failed: config.stats.bad,
- passed: passed,
- total: config.stats.all,
- runtime: runtime
- });
-}
-
-/** @return Boolean: true if this test should be ran */
-function validTest( test ) {
- var include,
- filter = config.filter && config.filter.toLowerCase(),
- module = config.module && config.module.toLowerCase(),
- fullName = (test.module + ": " + test.testName).toLowerCase();
-
- // Internally-generated tests are always valid
- if ( test.callback && test.callback.validTest === validTest ) {
- delete test.callback.validTest;
- return true;
- }
-
- if ( config.testNumber ) {
- return test.testNumber === config.testNumber;
- }
-
- if ( module && ( !test.module || test.module.toLowerCase() !== module ) ) {
- return false;
- }
-
- if ( !filter ) {
- return true;
- }
-
- include = filter.charAt( 0 ) !== "!";
- if ( !include ) {
- filter = filter.slice( 1 );
- }
-
- // If the filter matches, we need to honour include
- if ( fullName.indexOf( filter ) !== -1 ) {
- return include;
- }
-
- // Otherwise, do the opposite
- return !include;
-}
-
-// so far supports only Firefox, Chrome and Opera (buggy), Safari (for real exceptions)
-// Later Safari and IE10 are supposed to support error.stack as well
-// See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack
-function extractStacktrace( e, offset ) {
- offset = offset === undefined ? 3 : offset;
-
- var stack, include, i;
-
- if ( e.stacktrace ) {
- // Opera
- return e.stacktrace.split( "\n" )[ offset + 3 ];
- } else if ( e.stack ) {
- // Firefox, Chrome
- stack = e.stack.split( "\n" );
- if (/^error$/i.test( stack[0] ) ) {
- stack.shift();
- }
- if ( fileName ) {
- include = [];
- for ( i = offset; i < stack.length; i++ ) {
- if ( stack[ i ].indexOf( fileName ) !== -1 ) {
- break;
- }
- include.push( stack[ i ] );
- }
- if ( include.length ) {
- return include.join( "\n" );
- }
- }
- return stack[ offset ];
- } else if ( e.sourceURL ) {
- // Safari, PhantomJS
- // hopefully one day Safari provides actual stacktraces
- // exclude useless self-reference for generated Error objects
- if ( /qunit.js$/.test( e.sourceURL ) ) {
- return;
- }
- // for actual exceptions, this is useful
- return e.sourceURL + ":" + e.line;
- }
-}
-function sourceFromStacktrace( offset ) {
- try {
- throw new Error();
- } catch ( e ) {
- return extractStacktrace( e, offset );
- }
-}
-
-/**
- * Escape text for attribute or text content.
- */
-function escapeText( s ) {
- if ( !s ) {
- return "";
- }
- s = s + "";
- // Both single quotes and double quotes (for attributes)
- return s.replace( /['"<>&]/g, function( s ) {
- switch( s ) {
- case '\'':
- return ''';
- case '"':
- return '"';
- case '<':
- return '<';
- case '>':
- return '>';
- case '&':
- return '&';
- }
- });
-}
-
-function synchronize( callback, last ) {
- config.queue.push( callback );
-
- if ( config.autorun && !config.blocking ) {
- process( last );
- }
-}
-
-function process( last ) {
- function next() {
- process( last );
- }
- var start = new Date().getTime();
- config.depth = config.depth ? config.depth + 1 : 1;
-
- while ( config.queue.length && !config.blocking ) {
- if ( !defined.setTimeout || config.updateRate <= 0 || ( ( new Date().getTime() - start ) < config.updateRate ) ) {
- config.queue.shift()();
- } else {
- window.setTimeout( next, 13 );
- break;
- }
- }
- config.depth--;
- if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) {
- done();
- }
-}
-
-function saveGlobal() {
- config.pollution = [];
-
- if ( config.noglobals ) {
- for ( var key in window ) {
- // in Opera sometimes DOM element ids show up here, ignore them
- if ( !hasOwn.call( window, key ) || /^qunit-test-output/.test( key ) ) {
- continue;
- }
- config.pollution.push( key );
- }
- }
-}
-
-function checkPollution() {
- var newGlobals,
- deletedGlobals,
- old = config.pollution;
-
- saveGlobal();
-
- newGlobals = diff( config.pollution, old );
- if ( newGlobals.length > 0 ) {
- QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join(", ") );
- }
-
- deletedGlobals = diff( old, config.pollution );
- if ( deletedGlobals.length > 0 ) {
- QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join(", ") );
- }
-}
-
-// returns a new Array with the elements that are in a but not in b
-function diff( a, b ) {
- var i, j,
- result = a.slice();
-
- for ( i = 0; i < result.length; i++ ) {
- for ( j = 0; j < b.length; j++ ) {
- if ( result[i] === b[j] ) {
- result.splice( i, 1 );
- i--;
- break;
- }
- }
- }
- return result;
-}
-
-function extend( a, b ) {
- for ( var prop in b ) {
- if ( b[ prop ] === undefined ) {
- delete a[ prop ];
-
- // Avoid "Member not found" error in IE8 caused by setting window.constructor
- } else if ( prop !== "constructor" || a !== window ) {
- a[ prop ] = b[ prop ];
- }
- }
-
- return a;
-}
-
-/**
- * @param {HTMLElement} elem
- * @param {string} type
- * @param {Function} fn
- */
-function addEvent( elem, type, fn ) {
- // Standards-based browsers
- if ( elem.addEventListener ) {
- elem.addEventListener( type, fn, false );
- // IE
- } else {
- elem.attachEvent( "on" + type, fn );
- }
-}
-
-/**
- * @param {Array|NodeList} elems
- * @param {string} type
- * @param {Function} fn
- */
-function addEvents( elems, type, fn ) {
- var i = elems.length;
- while ( i-- ) {
- addEvent( elems[i], type, fn );
- }
-}
-
-function hasClass( elem, name ) {
- return (" " + elem.className + " ").indexOf(" " + name + " ") > -1;
-}
-
-function addClass( elem, name ) {
- if ( !hasClass( elem, name ) ) {
- elem.className += (elem.className ? " " : "") + name;
- }
-}
-
-function removeClass( elem, name ) {
- var set = " " + elem.className + " ";
- // Class name may appear multiple times
- while ( set.indexOf(" " + name + " ") > -1 ) {
- set = set.replace(" " + name + " " , " ");
- }
- // If possible, trim it for prettiness, but not neccecarily
- elem.className = window.jQuery ? jQuery.trim( set ) : ( set.trim ? set.trim() : set );
-}
-
-function id( name ) {
- return !!( typeof document !== "undefined" && document && document.getElementById ) &&
- document.getElementById( name );
-}
-
-function registerLoggingCallback( key ) {
- return function( callback ) {
- config[key].push( callback );
- };
-}
-
-// Supports deprecated method of completely overwriting logging callbacks
-function runLoggingCallbacks( key, scope, args ) {
- var i, callbacks;
- if ( QUnit.hasOwnProperty( key ) ) {
- QUnit[ key ].call(scope, args );
- } else {
- callbacks = config[ key ];
- for ( i = 0; i < callbacks.length; i++ ) {
- callbacks[ i ].call( scope, args );
- }
- }
-}
-
-// Test for equality any JavaScript type.
-// Author: Philippe Rathé
-QUnit.equiv = (function() {
-
- // Call the o related callback with the given arguments.
- function bindCallbacks( o, callbacks, args ) {
- var prop = QUnit.objectType( o );
- if ( prop ) {
- if ( QUnit.objectType( callbacks[ prop ] ) === "function" ) {
- return callbacks[ prop ].apply( callbacks, args );
- } else {
- return callbacks[ prop ]; // or undefined
- }
- }
- }
-
- // the real equiv function
- var innerEquiv,
- // stack to decide between skip/abort functions
- callers = [],
- // stack to avoiding loops from circular referencing
- parents = [],
-
- getProto = Object.getPrototypeOf || function ( obj ) {
- return obj.__proto__;
- },
- callbacks = (function () {
-
- // for string, boolean, number and null
- function useStrictEquality( b, a ) {
- /*jshint eqeqeq:false */
- if ( b instanceof a.constructor || a instanceof b.constructor ) {
- // to catch short annotaion VS 'new' annotation of a
- // declaration
- // e.g. var i = 1;
- // var j = new Number(1);
- return a == b;
- } else {
- return a === b;
- }
- }
-
- return {
- "string": useStrictEquality,
- "boolean": useStrictEquality,
- "number": useStrictEquality,
- "null": useStrictEquality,
- "undefined": useStrictEquality,
-
- "nan": function( b ) {
- return isNaN( b );
- },
-
- "date": function( b, a ) {
- return QUnit.objectType( b ) === "date" && a.valueOf() === b.valueOf();
- },
-
- "regexp": function( b, a ) {
- return QUnit.objectType( b ) === "regexp" &&
- // the regex itself
- a.source === b.source &&
- // and its modifers
- a.global === b.global &&
- // (gmi) ...
- a.ignoreCase === b.ignoreCase &&
- a.multiline === b.multiline &&
- a.sticky === b.sticky;
- },
-
- // - skip when the property is a method of an instance (OOP)
- // - abort otherwise,
- // initial === would have catch identical references anyway
- "function": function() {
- var caller = callers[callers.length - 1];
- return caller !== Object && typeof caller !== "undefined";
- },
-
- "array": function( b, a ) {
- var i, j, len, loop;
-
- // b could be an object literal here
- if ( QUnit.objectType( b ) !== "array" ) {
- return false;
- }
-
- len = a.length;
- if ( len !== b.length ) {
- // safe and faster
- return false;
- }
-
- // track reference to avoid circular references
- parents.push( a );
- for ( i = 0; i < len; i++ ) {
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- loop = true;// dont rewalk array
- }
- }
- if ( !loop && !innerEquiv(a[i], b[i]) ) {
- parents.pop();
- return false;
- }
- }
- parents.pop();
- return true;
- },
-
- "object": function( b, a ) {
- var i, j, loop,
- // Default to true
- eq = true,
- aProperties = [],
- bProperties = [];
-
- // comparing constructors is more strict than using
- // instanceof
- if ( a.constructor !== b.constructor ) {
- // Allow objects with no prototype to be equivalent to
- // objects with Object as their constructor.
- if ( !(( getProto(a) === null && getProto(b) === Object.prototype ) ||
- ( getProto(b) === null && getProto(a) === Object.prototype ) ) ) {
- return false;
- }
- }
-
- // stack constructor before traversing properties
- callers.push( a.constructor );
- // track reference to avoid circular references
- parents.push( a );
-
- for ( i in a ) { // be strict: don't ensures hasOwnProperty
- // and go deep
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- // don't go down the same path twice
- loop = true;
- }
- }
- aProperties.push(i); // collect a's properties
-
- if (!loop && !innerEquiv( a[i], b[i] ) ) {
- eq = false;
- break;
- }
- }
-
- callers.pop(); // unstack, we are done
- parents.pop();
-
- for ( i in b ) {
- bProperties.push( i ); // collect b's properties
- }
-
- // Ensures identical properties name
- return eq && innerEquiv( aProperties.sort(), bProperties.sort() );
- }
- };
- }());
-
- innerEquiv = function() { // can take multiple arguments
- var args = [].slice.apply( arguments );
- if ( args.length < 2 ) {
- return true; // end transition
- }
-
- return (function( a, b ) {
- if ( a === b ) {
- return true; // catch the most you can
- } else if ( a === null || b === null || typeof a === "undefined" ||
- typeof b === "undefined" ||
- QUnit.objectType(a) !== QUnit.objectType(b) ) {
- return false; // don't lose time with error prone cases
- } else {
- return bindCallbacks(a, callbacks, [ b, a ]);
- }
-
- // apply transition with (1..n) arguments
- }( args[0], args[1] ) && arguments.callee.apply( this, args.splice(1, args.length - 1 )) );
- };
-
- return innerEquiv;
-}());
-
-/**
- * jsDump Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com |
- * http://flesler.blogspot.com Licensed under BSD
- * (http://www.opensource.org/licenses/bsd-license.php) Date: 5/15/2008
- *
- * @projectDescription Advanced and extensible data dumping for Javascript.
- * @version 1.0.0
- * @author Ariel Flesler
- * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html}
- */
-QUnit.jsDump = (function() {
- function quote( str ) {
- return '"' + str.toString().replace( /"/g, '\\"' ) + '"';
- }
- function literal( o ) {
- return o + "";
- }
- function join( pre, arr, post ) {
- var s = jsDump.separator(),
- base = jsDump.indent(),
- inner = jsDump.indent(1);
- if ( arr.join ) {
- arr = arr.join( "," + s + inner );
- }
- if ( !arr ) {
- return pre + post;
- }
- return [ pre, inner + arr, base + post ].join(s);
- }
- function array( arr, stack ) {
- var i = arr.length, ret = new Array(i);
- this.up();
- while ( i-- ) {
- ret[i] = this.parse( arr[i] , undefined , stack);
- }
- this.down();
- return join( "[", ret, "]" );
- }
-
- var reName = /^function (\w+)/,
- jsDump = {
- // type is used mostly internally, you can fix a (custom)type in advance
- parse: function( obj, type, stack ) {
- stack = stack || [ ];
- var inStack, res,
- parser = this.parsers[ type || this.typeOf(obj) ];
-
- type = typeof parser;
- inStack = inArray( obj, stack );
-
- if ( inStack !== -1 ) {
- return "recursion(" + (inStack - stack.length) + ")";
- }
- if ( type === "function" ) {
- stack.push( obj );
- res = parser.call( this, obj, stack );
- stack.pop();
- return res;
- }
- return ( type === "string" ) ? parser : this.parsers.error;
- },
- typeOf: function( obj ) {
- var type;
- if ( obj === null ) {
- type = "null";
- } else if ( typeof obj === "undefined" ) {
- type = "undefined";
- } else if ( QUnit.is( "regexp", obj) ) {
- type = "regexp";
- } else if ( QUnit.is( "date", obj) ) {
- type = "date";
- } else if ( QUnit.is( "function", obj) ) {
- type = "function";
- } else if ( typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined" ) {
- type = "window";
- } else if ( obj.nodeType === 9 ) {
- type = "document";
- } else if ( obj.nodeType ) {
- type = "node";
- } else if (
- // native arrays
- toString.call( obj ) === "[object Array]" ||
- // NodeList objects
- ( typeof obj.length === "number" && typeof obj.item !== "undefined" && ( obj.length ? obj.item(0) === obj[0] : ( obj.item( 0 ) === null && typeof obj[0] === "undefined" ) ) )
- ) {
- type = "array";
- } else if ( obj.constructor === Error.prototype.constructor ) {
- type = "error";
- } else {
- type = typeof obj;
- }
- return type;
- },
- separator: function() {
- return this.multiline ? this.HTML ? "
" : "\n" : this.HTML ? " " : " ";
- },
- // extra can be a number, shortcut for increasing-calling-decreasing
- indent: function( extra ) {
- if ( !this.multiline ) {
- return "";
- }
- var chr = this.indentChar;
- if ( this.HTML ) {
- chr = chr.replace( /\t/g, " " ).replace( / /g, " " );
- }
- return new Array( this._depth_ + (extra||0) ).join(chr);
- },
- up: function( a ) {
- this._depth_ += a || 1;
- },
- down: function( a ) {
- this._depth_ -= a || 1;
- },
- setParser: function( name, parser ) {
- this.parsers[name] = parser;
- },
- // The next 3 are exposed so you can use them
- quote: quote,
- literal: literal,
- join: join,
- //
- _depth_: 1,
- // This is the list of parsers, to modify them, use jsDump.setParser
- parsers: {
- window: "[Window]",
- document: "[Document]",
- error: function(error) {
- return "Error(\"" + error.message + "\")";
- },
- unknown: "[Unknown]",
- "null": "null",
- "undefined": "undefined",
- "function": function( fn ) {
- var ret = "function",
- // functions never have name in IE
- name = "name" in fn ? fn.name : (reName.exec(fn) || [])[1];
-
- if ( name ) {
- ret += " " + name;
- }
- ret += "( ";
-
- ret = [ ret, QUnit.jsDump.parse( fn, "functionArgs" ), "){" ].join( "" );
- return join( ret, QUnit.jsDump.parse(fn,"functionCode" ), "}" );
- },
- array: array,
- nodelist: array,
- "arguments": array,
- object: function( map, stack ) {
- var ret = [ ], keys, key, val, i;
- QUnit.jsDump.up();
- keys = [];
- for ( key in map ) {
- keys.push( key );
- }
- keys.sort();
- for ( i = 0; i < keys.length; i++ ) {
- key = keys[ i ];
- val = map[ key ];
- ret.push( QUnit.jsDump.parse( key, "key" ) + ": " + QUnit.jsDump.parse( val, undefined, stack ) );
- }
- QUnit.jsDump.down();
- return join( "{", ret, "}" );
- },
- node: function( node ) {
- var len, i, val,
- open = QUnit.jsDump.HTML ? "<" : "<",
- close = QUnit.jsDump.HTML ? ">" : ">",
- tag = node.nodeName.toLowerCase(),
- ret = open + tag,
- attrs = node.attributes;
-
- if ( attrs ) {
- for ( i = 0, len = attrs.length; i < len; i++ ) {
- val = attrs[i].nodeValue;
- // IE6 includes all attributes in .attributes, even ones not explicitly set.
- // Those have values like undefined, null, 0, false, "" or "inherit".
- if ( val && val !== "inherit" ) {
- ret += " " + attrs[i].nodeName + "=" + QUnit.jsDump.parse( val, "attribute" );
- }
- }
- }
- ret += close;
-
- // Show content of TextNode or CDATASection
- if ( node.nodeType === 3 || node.nodeType === 4 ) {
- ret += node.nodeValue;
- }
-
- return ret + open + "/" + tag + close;
- },
- // function calls it internally, it's the arguments part of the function
- functionArgs: function( fn ) {
- var args,
- l = fn.length;
-
- if ( !l ) {
- return "";
- }
-
- args = new Array(l);
- while ( l-- ) {
- // 97 is 'a'
- args[l] = String.fromCharCode(97+l);
- }
- return " " + args.join( ", " ) + " ";
- },
- // object calls it internally, the key part of an item in a map
- key: quote,
- // function calls it internally, it's the content of the function
- functionCode: "[code]",
- // node calls it internally, it's an html attribute value
- attribute: quote,
- string: quote,
- date: quote,
- regexp: literal,
- number: literal,
- "boolean": literal
- },
- // if true, entities are escaped ( <, >, \t, space and \n )
- HTML: false,
- // indentation unit
- indentChar: " ",
- // if true, items in a collection, are separated by a \n, else just a space.
- multiline: true
- };
-
- return jsDump;
-}());
-
-// from jquery.js
-function inArray( elem, array ) {
- if ( array.indexOf ) {
- return array.indexOf( elem );
- }
-
- for ( var i = 0, length = array.length; i < length; i++ ) {
- if ( array[ i ] === elem ) {
- return i;
- }
- }
-
- return -1;
-}
-
-/*
- * Javascript Diff Algorithm
- * By John Resig (http://ejohn.org/)
- * Modified by Chu Alan "sprite"
- *
- * Released under the MIT license.
- *
- * More Info:
- * http://ejohn.org/projects/javascript-diff-algorithm/
- *
- * Usage: QUnit.diff(expected, actual)
- *
- * QUnit.diff( "the quick brown fox jumped over", "the quick fox jumps over" ) == "the quick brown fox jumped jumps over"
- */
-QUnit.diff = (function() {
- /*jshint eqeqeq:false, eqnull:true */
- function diff( o, n ) {
- var i,
- ns = {},
- os = {};
-
- for ( i = 0; i < n.length; i++ ) {
- if ( !hasOwn.call( ns, n[i] ) ) {
- ns[ n[i] ] = {
- rows: [],
- o: null
- };
- }
- ns[ n[i] ].rows.push( i );
- }
-
- for ( i = 0; i < o.length; i++ ) {
- if ( !hasOwn.call( os, o[i] ) ) {
- os[ o[i] ] = {
- rows: [],
- n: null
- };
- }
- os[ o[i] ].rows.push( i );
- }
-
- for ( i in ns ) {
- if ( !hasOwn.call( ns, i ) ) {
- continue;
- }
- if ( ns[i].rows.length === 1 && hasOwn.call( os, i ) && os[i].rows.length === 1 ) {
- n[ ns[i].rows[0] ] = {
- text: n[ ns[i].rows[0] ],
- row: os[i].rows[0]
- };
- o[ os[i].rows[0] ] = {
- text: o[ os[i].rows[0] ],
- row: ns[i].rows[0]
- };
- }
- }
-
- for ( i = 0; i < n.length - 1; i++ ) {
- if ( n[i].text != null && n[ i + 1 ].text == null && n[i].row + 1 < o.length && o[ n[i].row + 1 ].text == null &&
- n[ i + 1 ] == o[ n[i].row + 1 ] ) {
-
- n[ i + 1 ] = {
- text: n[ i + 1 ],
- row: n[i].row + 1
- };
- o[ n[i].row + 1 ] = {
- text: o[ n[i].row + 1 ],
- row: i + 1
- };
- }
- }
-
- for ( i = n.length - 1; i > 0; i-- ) {
- if ( n[i].text != null && n[ i - 1 ].text == null && n[i].row > 0 && o[ n[i].row - 1 ].text == null &&
- n[ i - 1 ] == o[ n[i].row - 1 ]) {
-
- n[ i - 1 ] = {
- text: n[ i - 1 ],
- row: n[i].row - 1
- };
- o[ n[i].row - 1 ] = {
- text: o[ n[i].row - 1 ],
- row: i - 1
- };
- }
- }
-
- return {
- o: o,
- n: n
- };
- }
-
- return function( o, n ) {
- o = o.replace( /\s+$/, "" );
- n = n.replace( /\s+$/, "" );
-
- var i, pre,
- str = "",
- out = diff( o === "" ? [] : o.split(/\s+/), n === "" ? [] : n.split(/\s+/) ),
- oSpace = o.match(/\s+/g),
- nSpace = n.match(/\s+/g);
-
- if ( oSpace == null ) {
- oSpace = [ " " ];
- }
- else {
- oSpace.push( " " );
- }
-
- if ( nSpace == null ) {
- nSpace = [ " " ];
- }
- else {
- nSpace.push( " " );
- }
-
- if ( out.n.length === 0 ) {
- for ( i = 0; i < out.o.length; i++ ) {
- str += "" + out.o[i] + oSpace[i] + "";
- }
- }
- else {
- if ( out.n[0].text == null ) {
- for ( n = 0; n < out.o.length && out.o[n].text == null; n++ ) {
- str += "" + out.o[n] + oSpace[n] + "";
- }
- }
-
- for ( i = 0; i < out.n.length; i++ ) {
- if (out.n[i].text == null) {
- str += "" + out.n[i] + nSpace[i] + "";
- }
- else {
- // `pre` initialized at top of scope
- pre = "";
-
- for ( n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++ ) {
- pre += "" + out.o[n] + oSpace[n] + "";
- }
- str += " " + out.n[i].text + nSpace[i] + pre;
- }
- }
- }
-
- return str;
- };
-}());
-
-// for CommonJS enviroments, export everything
-if ( typeof exports !== "undefined" ) {
- extend( exports, QUnit );
-}
-
-// get at whatever the global object is, like window in browsers
-}( (function() {return this;}.call()) ));
diff --git a/test/lib/require.js b/test/lib/require.js
deleted file mode 100644
index 987f865..0000000
--- a/test/lib/require.js
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- RequireJS 2.1.5 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.
- Available via the MIT or new BSD license.
- see: http://github.com/jrburke/requirejs for details
-*/
-var requirejs,require,define;
-(function(aa){function I(b){return"[object Function]"===L.call(b)}function J(b){return"[object Array]"===L.call(b)}function y(b,c){if(b){var d;for(d=0;dthis.depCount&&!this.defined){if(I(n)){if(this.events.error)try{e=i.execCb(c,n,b,e)}catch(d){a=d}else e=i.execCb(c,n,b,e);this.map.isDefine&&((b=this.module)&&void 0!==b.exports&&b.exports!==this.exports?e=b.exports:void 0===e&&this.usingExports&&(e=this.exports));if(a)return a.requireMap=this.map,a.requireModules=[this.map.id],a.requireType="define",v(this.error=
-a)}else e=n;this.exports=e;if(this.map.isDefine&&!this.ignore&&(q[c]=e,l.onResourceLoad))l.onResourceLoad(i,this.map,this.depMaps);x(c);this.defined=!0}this.defining=!1;this.defined&&!this.defineEmitted&&(this.defineEmitted=!0,this.emit("defined",this.exports),this.defineEmitComplete=!0)}}else this.fetch()}},callPlugin:function(){var a=this.map,b=a.id,d=j(a.prefix);this.depMaps.push(d);t(d,"defined",u(this,function(e){var n,d;d=this.map.name;var g=this.map.parentMap?this.map.parentMap.name:null,h=
-i.makeRequire(a.parentMap,{enableBuildCallback:!0});if(this.map.unnormalized){if(e.normalize&&(d=e.normalize(d,function(a){return c(a,g,!0)})||""),e=j(a.prefix+"!"+d,this.map.parentMap),t(e,"defined",u(this,function(a){this.init([],function(){return a},null,{enabled:!0,ignore:!0})})),d=m(p,e.id)){this.depMaps.push(e);if(this.events.error)d.on("error",u(this,function(a){this.emit("error",a)}));d.enable()}}else n=u(this,function(a){this.init([],function(){return a},null,{enabled:!0})}),n.error=u(this,
-function(a){this.inited=!0;this.error=a;a.requireModules=[b];G(p,function(a){0===a.map.id.indexOf(b+"_unnormalized")&&x(a.map.id)});v(a)}),n.fromText=u(this,function(e,c){var d=a.name,g=j(d),C=O;c&&(e=c);C&&(O=!1);r(g);s(k.config,b)&&(k.config[d]=k.config[b]);try{l.exec(e)}catch(ca){return v(B("fromtexteval","fromText eval for "+b+" failed: "+ca,ca,[b]))}C&&(O=!0);this.depMaps.push(g);i.completeLoad(d);h([d],n)}),e.load(a.name,h,n,k)}));i.enable(d,this);this.pluginMaps[d.id]=d},enable:function(){V[this.map.id]=
-this;this.enabling=this.enabled=!0;y(this.depMaps,u(this,function(a,b){var c,e;if("string"===typeof a){a=j(a,this.map.isDefine?this.map:this.map.parentMap,!1,!this.skipMap);this.depMaps[b]=a;if(c=m(N,a.id)){this.depExports[b]=c(this);return}this.depCount+=1;t(a,"defined",u(this,function(a){this.defineDep(b,a);this.check()}));this.errback&&t(a,"error",this.errback)}c=a.id;e=p[c];!s(N,c)&&(e&&!e.enabled)&&i.enable(a,this)}));G(this.pluginMaps,u(this,function(a){var b=m(p,a.id);b&&!b.enabled&&i.enable(a,
-this)}));this.enabling=!1;this.check()},on:function(a,b){var c=this.events[a];c||(c=this.events[a]=[]);c.push(b)},emit:function(a,b){y(this.events[a],function(a){a(b)});"error"===a&&delete this.events[a]}};i={config:k,contextName:b,registry:p,defined:q,urlFetched:U,defQueue:H,Module:Z,makeModuleMap:j,nextTick:l.nextTick,onError:v,configure:function(a){a.baseUrl&&"/"!==a.baseUrl.charAt(a.baseUrl.length-1)&&(a.baseUrl+="/");var b=k.pkgs,c=k.shim,e={paths:!0,config:!0,map:!0};G(a,function(a,b){e[b]?
-"map"===b?(k.map||(k.map={}),R(k[b],a,!0,!0)):R(k[b],a,!0):k[b]=a});a.shim&&(G(a.shim,function(a,b){J(a)&&(a={deps:a});if((a.exports||a.init)&&!a.exportsFn)a.exportsFn=i.makeShimExports(a);c[b]=a}),k.shim=c);a.packages&&(y(a.packages,function(a){a="string"===typeof a?{name:a}:a;b[a.name]={name:a.name,location:a.location||a.name,main:(a.main||"main").replace(ja,"").replace(ea,"")}}),k.pkgs=b);G(p,function(a,b){!a.inited&&!a.map.unnormalized&&(a.map=j(b))});if(a.deps||a.callback)i.require(a.deps||[],
-a.callback)},makeShimExports:function(a){return function(){var b;a.init&&(b=a.init.apply(aa,arguments));return b||a.exports&&ba(a.exports)}},makeRequire:function(a,f){function d(e,c,h){var g,k;f.enableBuildCallback&&(c&&I(c))&&(c.__requireJsBuild=!0);if("string"===typeof e){if(I(c))return v(B("requireargs","Invalid require call"),h);if(a&&s(N,e))return N[e](p[a.id]);if(l.get)return l.get(i,e,a,d);g=j(e,a,!1,!0);g=g.id;return!s(q,g)?v(B("notloaded",'Module name "'+g+'" has not been loaded yet for context: '+
-b+(a?"":". Use require([])"))):q[g]}L();i.nextTick(function(){L();k=r(j(null,a));k.skipMap=f.skipMap;k.init(e,c,h,{enabled:!0});D()});return d}f=f||{};R(d,{isBrowser:A,toUrl:function(b){var d,f=b.lastIndexOf("."),g=b.split("/")[0];if(-1!==f&&(!("."===g||".."===g)||1h.attachEvent.toString().indexOf("[native code"))&&!Y?(O=!0,h.attachEvent("onreadystatechange",b.onScriptLoad)):(h.addEventListener("load",b.onScriptLoad,!1),h.addEventListener("error",b.onScriptError,!1)),h.src=d,K=h,D?x.insertBefore(h,D):x.appendChild(h),K=null,h;if(da)try{importScripts(d),b.completeLoad(c)}catch(j){b.onError(B("importscripts","importScripts failed for "+c+" at "+d,j,[c]))}};A&&M(document.getElementsByTagName("script"),function(b){x||(x=
-b.parentNode);if(t=b.getAttribute("data-main"))return r.baseUrl||(E=t.split("/"),Q=E.pop(),fa=E.length?E.join("/")+"/":"./",r.baseUrl=fa,t=Q),t=t.replace(ea,""),r.deps=r.deps?r.deps.concat(t):[t],!0});define=function(b,c,d){var l,h;"string"!==typeof b&&(d=c,c=b,b=null);J(c)||(d=c,c=[]);!c.length&&I(d)&&d.length&&(d.toString().replace(la,"").replace(ma,function(b,d){c.push(d)}),c=(1===d.length?["require"]:["require","exports","module"]).concat(c));if(O){if(!(l=K))P&&"interactive"===P.readyState||M(document.getElementsByTagName("script"),
-function(b){if("interactive"===b.readyState)return P=b}),l=P;l&&(b||(b=l.getAttribute("data-requiremodule")),h=F[l.getAttribute("data-requirecontext")])}(h?h.defQueue:T).push([b,c,d])};define.amd={jQuery:!0};l.exec=function(b){return eval(b)};l(r)}})(this);
diff --git a/test/lib/resemble.js b/test/lib/resemble.js
new file mode 100644
index 0000000..1cb8c29
--- /dev/null
+++ b/test/lib/resemble.js
@@ -0,0 +1,535 @@
+/*
+Author: James Cryer
+Company: Huddle
+Last updated date: 21 Feb 2013
+URL: https://github.com/Huddle/Resemble.js
+*/
+
+(function(_this){
+ 'use strict';
+
+ _this['resemble'] = function( fileData ){
+
+ var data = {};
+ var images = [];
+ var updateCallbackArray = [];
+
+ var tolerance = { // between 0 and 255
+ red: 16,
+ green: 16,
+ blue: 16,
+ minBrightness: 16,
+ maxBrightness: 240
+ };
+
+ var ignoreAntialiasing = false;
+ var ignoreColors = false;
+
+ function triggerDataUpdate(){
+ var len = updateCallbackArray.length;
+ var i;
+ for(i=0;i tolerance.maxBrightness;
+ }
+
+ function getHue(r,g,b){
+
+ r = r / 255;
+ g = g / 255;
+ b = b / 255;
+ var max = Math.max(r, g, b), min = Math.min(r, g, b);
+ var h;
+ var d;
+
+ if (max == min){
+ h = 0; // achromatic
+ } else{
+ d = max - min;
+ switch(max){
+ case r: h = (g - b) / d + (g < b ? 6 : 0); break;
+ case g: h = (b - r) / d + 2; break;
+ case b: h = (r - g) / d + 4; break;
+ }
+ h /= 6;
+ }
+
+ return h;
+ }
+
+ function isAntialiased(sourcePix, data, cacheSet, verticalPos, horizontalPos, width){
+ var offset;
+ var targetPix;
+ var distance = 1;
+ var i;
+ var j;
+ var hasHighContrastSibling = 0;
+ var hasSiblingWithDifferentHue = 0;
+ var hasEquivilantSibling = 0;
+
+ addHueInfo(sourcePix);
+
+ for (i = distance*-1; i <= distance; i++){
+ for (j = distance*-1; j <= distance; j++){
+
+ if(i===0 && j===0){
+ // ignore source pixel
+ } else {
+
+ offset = ((verticalPos+j)*width + (horizontalPos+i)) * 4;
+ targetPix = getPixelInfo(data, offset, cacheSet);
+
+ if(targetPix === null){
+ continue;
+ }
+
+ addBrightnessInfo(targetPix);
+ addHueInfo(targetPix);
+
+ if( isContrasting(sourcePix, targetPix) ){
+ hasHighContrastSibling++;
+ }
+
+ if( isRGBSame(sourcePix,targetPix) ){
+ hasEquivilantSibling++;
+ }
+
+ if( Math.abs(targetPix.h - sourcePix.h) > 0.3 ){
+ hasSiblingWithDifferentHue++;
+ }
+
+ if( hasSiblingWithDifferentHue > 1 || hasHighContrastSibling > 1){
+ return true;
+ }
+ }
+ }
+ }
+
+ if(hasEquivilantSibling < 2){
+ return true;
+ }
+
+ return false;
+ }
+
+ function errorPixel(px, offset){
+ px[offset] = 255; //r
+ px[offset + 1] = 0; //g
+ px[offset + 2] = 255; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyPixel(px, offset, data){
+ px[offset] = data.r; //r
+ px[offset + 1] = data.g; //g
+ px[offset + 2] = data.b; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyGrayScalePixel(px, offset, data){
+ px[offset] = data.brightness; //r
+ px[offset + 1] = data.brightness; //g
+ px[offset + 2] = data.brightness; //b
+ px[offset + 3] = 255; //a
+ }
+
+
+ function getPixelInfo(data, offset, cacheSet){
+ var r;
+ var g;
+ var b;
+ var d;
+
+ if(typeof data[offset] !== 'undefined'){
+ r = data[offset];
+ g = data[offset+1];
+ b = data[offset+2];
+ d = {
+ r: r,
+ g: g,
+ b: b
+ };
+
+ return d;
+ } else {
+ return null;
+ }
+ }
+
+ function addBrightnessInfo(data){
+ data.brightness = getBrightness(data.r,data.g,data.b); // 'corrected' lightness
+ }
+
+ function addHueInfo(data){
+ data.h = getHue(data.r,data.g,data.b);
+ }
+
+ function analyseImages(img1, img2, width, height){
+
+ var hiddenCanvas = document.createElement('canvas');
+
+ var data1 = img1.data;
+ var data2 = img2.data;
+
+ hiddenCanvas.width = width;
+ hiddenCanvas.height = height;
+
+ var context = hiddenCanvas.getContext('2d');
+ var imgd = context.createImageData(width,height);
+ var targetPix = imgd.data;
+
+ var mismatchCount = 0;
+
+ var time = Date.now();
+
+ var skip;
+
+ if( (width > 1200 || height > 1200) && ignoreAntialiasing){
+ skip = 6;
+ }
+
+ loop(height, width, function(verticalPos, horizontalPos){
+
+ if(skip){ // only skip if the image isn't small
+ if(verticalPos % skip === 0 || horizontalPos % skip === 0){
+ return;
+ }
+ }
+
+ var offset = (verticalPos*width + horizontalPos) * 4;
+ var pixel1 = getPixelInfo(data1, offset, 1);
+ var pixel2 = getPixelInfo(data2, offset, 2);
+
+ if(pixel1 === null || pixel2 === null){
+ return;
+ }
+
+ if (ignoreColors){
+
+ addBrightnessInfo(pixel1);
+ addBrightnessInfo(pixel2);
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ return;
+ }
+
+ if( isRGBSimilar(pixel1, pixel2) ){
+ copyPixel(targetPix, offset, pixel2);
+
+ } else if( ignoreAntialiasing && (
+ addBrightnessInfo(pixel1), // jit pixel info augmentation looks a little weird, sorry.
+ addBrightnessInfo(pixel2),
+ isAntialiased(pixel1, data1, 1, verticalPos, horizontalPos, width) ||
+ isAntialiased(pixel2, data2, 2, verticalPos, horizontalPos, width)
+ )){
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+
+ });
+
+ data.misMatchPercentage = (mismatchCount / (height*width) * 100).toFixed(2);
+ data.analysisTime = Date.now() - time;
+
+ data.getImageDataUrl = function(text){
+ var barHeight = 0;
+
+ if(text){
+ barHeight = addLabel(text,context,hiddenCanvas);
+ }
+
+ context.putImageData(imgd, 0, barHeight);
+
+ return hiddenCanvas.toDataURL("image/png");
+ };
+ }
+
+ function addLabel(text, context, hiddenCanvas){
+ var textPadding = 2;
+
+ context.font = '12px sans-serif';
+
+ var textWidth = context.measureText(text).width + textPadding*2;
+ var barHeight = 22;
+
+ if(textWidth > hiddenCanvas.width){
+ hiddenCanvas.width = textWidth;
+ }
+
+ hiddenCanvas.height += barHeight;
+
+ context.fillStyle = "#666";
+ context.fillRect(0,0,hiddenCanvas.width,barHeight -4);
+ context.fillStyle = "#fff";
+ context.fillRect(0,barHeight -4,hiddenCanvas.width, 4);
+
+ context.fillStyle = "#fff";
+ context.textBaseline = "top";
+ context.font = '12px sans-serif';
+ context.fillText(text, textPadding, 1);
+
+ return barHeight;
+ }
+
+ function normalise(img, w, h){
+ var c;
+ var context;
+
+ if(img.height < h || img.width < w){
+ c = document.createElement('canvas');
+ c.width = w;
+ c.height = h;
+ context = c.getContext('2d');
+ context.putImageData(img, 0, 0);
+ return context.getImageData(0, 0, w, h);
+ }
+
+ return img;
+ }
+
+ function compare(one, two){
+
+ function onceWeHaveBoth(){
+ var width;
+ var height;
+ if(images.length === 2){
+ width = images[0].width > images[1].width ? images[0].width : images[1].width;
+ height = images[0].height > images[1].height ? images[0].height : images[1].height;
+
+ if( (images[0].width === images[1].width) && (images[0].height === images[1].height) ){
+ data.isSameDimensions = true;
+ } else {
+ data.isSameDimensions = false;
+ }
+
+ analyseImages( normalise(images[0],width, height), normalise(images[1],width, height), width, height);
+
+ triggerDataUpdate();
+ }
+ }
+
+ images = [];
+ loadImageData(one, onceWeHaveBoth);
+ loadImageData(two, onceWeHaveBoth);
+ }
+
+ function getCompareApi(param){
+
+ var secondFileData,
+ hasMethod = typeof param === 'function';
+
+ if( !hasMethod ){
+ // assume it's file data
+ secondFileData = param;
+ }
+
+ var self = {
+ ignoreNothing: function(){
+
+ tolerance.red = 16;
+ tolerance.green = 16;
+ tolerance.blue = 16;
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreAntialiasing: function(){
+
+ tolerance.red = 32;
+ tolerance.green = 32;
+ tolerance.blue = 32;
+ tolerance.minBrightness = 64;
+ tolerance.maxBrightness = 96;
+
+ ignoreAntialiasing = true;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreColors: function(){
+
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = true;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ onComplete: function( callback ){
+
+ updateCallbackArray.push(callback);
+
+ var wrapper = function(){
+ compare(fileData, secondFileData);
+ };
+
+ wrapper();
+
+ return getCompareApi(wrapper);
+ }
+ };
+
+ return self;
+ }
+
+ return {
+ onComplete: function( callback ){
+ updateCallbackArray.push(callback);
+ loadImageData(fileData, function(imageData, width, height){
+ parseImage(imageData.data, width, height);
+ });
+ },
+ compareTo: function(secondFileData){
+ return getCompareApi(secondFileData);
+ }
+ };
+
+ };
+}(this));
\ No newline at end of file
diff --git a/test/testsuite.js b/test/testsuite.js
deleted file mode 100644
index b486acb..0000000
--- a/test/testsuite.js
+++ /dev/null
@@ -1,36 +0,0 @@
-requirejs.config({
- baseUrl: '/test/unit/'
-});
-
-define(function(require) {
- var testModules = [
- 'Pixi',
- 'Point',
- 'Rectangle',
- 'DisplayObject',
- 'DisplayObjectContainer',
- 'Sprite',
- 'MovieClip',
- 'InteractionManager',
- 'Stage',
- 'utils/Utils',
- 'utils/EventTarget',
- 'utils/Matrix',
- 'utils/Detector',
- 'renderers/WebGLShaders',
- 'renderers/WebGLRenderer',
- 'renderers/WebGLBatch',
- 'renderers/CanvasRenderer',
- 'extras/Strip',
- 'extras/Rope',
- 'textures/BaseTexture',
- 'textures/Texture',
- 'loaders/SpriteSheetLoader',
- 'loaders/AssetLoader'
- ];
-
- // Resolve all testModules and then start the Test Runner.
- require(testModules, function() {
- QUnit.start();
- });
-});
\ No newline at end of file
diff --git a/test/textures/SpriteSheet-Aliens.png b/test/textures/SpriteSheet-Aliens.png
new file mode 100644
index 0000000..210acb1
--- /dev/null
+++ b/test/textures/SpriteSheet-Aliens.png
Binary files differ
diff --git a/test/textures/SpriteSheet-Explosion.png b/test/textures/SpriteSheet-Explosion.png
new file mode 100755
index 0000000..79e1a69
--- /dev/null
+++ b/test/textures/SpriteSheet-Explosion.png
Binary files differ
diff --git a/test/textures/bunny.png b/test/textures/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/textures/bunny.png
Binary files differ
diff --git a/test/unit/DisplayObject.js b/test/unit/DisplayObject.js
deleted file mode 100644
index 5e7e72f..0000000
--- a/test/unit/DisplayObject.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObject');
-});
diff --git a/test/unit/DisplayObjectContainer.js b/test/unit/DisplayObjectContainer.js
deleted file mode 100644
index b323959..0000000
--- a/test/unit/DisplayObjectContainer.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObjectContainer');
-});
diff --git a/test/unit/InteractionManager.js b/test/unit/InteractionManager.js
deleted file mode 100644
index e751f52..0000000
--- a/test/unit/InteractionManager.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('InteractionManager');
-});
diff --git a/test/unit/MovieClip.js b/test/unit/MovieClip.js
deleted file mode 100644
index 37d9446..0000000
--- a/test/unit/MovieClip.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('MovieClip');
-});
diff --git a/test/unit/Pixi.js b/test/unit/Pixi.js
deleted file mode 100644
index 36eee73..0000000
--- a/test/unit/Pixi.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Pixi');
-});
diff --git a/test/unit/Point.js b/test/unit/Point.js
deleted file mode 100644
index 983ff6e..0000000
--- a/test/unit/Point.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Point');
-});
diff --git a/test/unit/Rectangle.js b/test/unit/Rectangle.js
deleted file mode 100644
index 3b439ba..0000000
--- a/test/unit/Rectangle.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Rectangle');
-});
diff --git a/test/unit/Sprite.js b/test/unit/Sprite.js
deleted file mode 100644
index ed4f596..0000000
--- a/test/unit/Sprite.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Sprite');
-});
diff --git a/test/unit/Stage.js b/test/unit/Stage.js
deleted file mode 100644
index 2d70291..0000000
--- a/test/unit/Stage.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Stage');
-});
diff --git a/test/unit/extras/Rope.js b/test/unit/extras/Rope.js
deleted file mode 100644
index 5606f14..0000000
--- a/test/unit/extras/Rope.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Rope');
-});
diff --git a/test/unit/extras/Strip.js b/test/unit/extras/Strip.js
deleted file mode 100644
index 0134d3a..0000000
--- a/test/unit/extras/Strip.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Strip');
-});
diff --git a/test/unit/loaders/AssetLoader.js b/test/unit/loaders/AssetLoader.js
deleted file mode 100644
index 13b8443..0000000
--- a/test/unit/loaders/AssetLoader.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('AssetLoader');
-});
diff --git a/test/unit/loaders/SpriteSheetLoader.js b/test/unit/loaders/SpriteSheetLoader.js
deleted file mode 100644
index 8bf0cb2..0000000
--- a/test/unit/loaders/SpriteSheetLoader.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('SpriteSheetLoader');
-});
diff --git a/test/unit/pixi/InteractionManager.js b/test/unit/pixi/InteractionManager.js
new file mode 100644
index 0000000..ed3001f
--- /dev/null
+++ b/test/unit/pixi/InteractionManager.js
@@ -0,0 +1,10 @@
+describe('pixi/InteractionManager', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var InteractionManager = PIXI.InteractionManager;
+
+ it('Module exists', function () {
+ expect(InteractionManager).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/Pixi.js b/test/unit/pixi/Pixi.js
new file mode 100644
index 0000000..27debc1
--- /dev/null
+++ b/test/unit/pixi/Pixi.js
@@ -0,0 +1,9 @@
+describe('pixi/Pixi', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+
+ it('Module exists', function () {
+ expect(global).to.have.property('PIXI').and.to.be.an('object');
+ });
+});
diff --git a/test/unit/pixi/core/Circle.js b/test/unit/pixi/core/Circle.js
new file mode 100644
index 0000000..93a4456
--- /dev/null
+++ b/test/unit/pixi/core/Circle.js
@@ -0,0 +1,22 @@
+describe('pixi/core/Circle', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Circle = PIXI.Circle;
+
+ it('Module exists', function () {
+ expect(Circle).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Circle();
+
+ expect(obj).to.be.an.instanceof(Circle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', 0);
+ expect(obj).to.have.property('y', 0);
+ expect(obj).to.have.property('radius', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Ellipse.js b/test/unit/pixi/core/Ellipse.js
new file mode 100644
index 0000000..026b56f
--- /dev/null
+++ b/test/unit/pixi/core/Ellipse.js
@@ -0,0 +1,24 @@
+describe('pixi/core/Ellipse', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Ellipse = PIXI.Ellipse;
+
+ it('Module exists', function () {
+ expect(Ellipse).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Ellipse();
+
+ expect(obj).to.be.an.instanceof(Ellipse);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+ expect(obj).to.respondTo('getBounds');
+
+ expect(obj).to.have.property('x', 0);
+ expect(obj).to.have.property('y', 0);
+ expect(obj).to.have.property('width', 0);
+ expect(obj).to.have.property('height', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Matrix.js b/test/unit/pixi/core/Matrix.js
new file mode 100644
index 0000000..b48989e
--- /dev/null
+++ b/test/unit/pixi/core/Matrix.js
@@ -0,0 +1,30 @@
+describe('pixi/core/Matrix', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var mat3 = PIXI.mat3;
+ var mat4 = PIXI.mat4;
+ var Matrix = PIXI.Matrix;
+
+ it('Ensure determineMatrixArrayType works', function () {
+ expect(Matrix).to.be.a('function');
+ });
+
+ it('mat3 exists', function () {
+ expect(mat3).to.be.an('object');
+ });
+
+ it('Confirm new mat3 matrix', function () {
+ var matrix = new mat3.create();
+ pixi_core_Matrix_confirmNewMat3(matrix);
+ });
+
+ it('mat3 exists', function () {
+ expect(mat4).to.be.an('object');
+ });
+
+ it('Confirm new mat4 matrix', function () {
+ var matrix = new mat4.create();
+ pixi_core_Matrix_confirmNewMat4(matrix);
+ });
+});
diff --git a/test/unit/pixi/core/Point.js b/test/unit/pixi/core/Point.js
new file mode 100644
index 0000000..c4d5163
--- /dev/null
+++ b/test/unit/pixi/core/Point.js
@@ -0,0 +1,15 @@
+describe('pixi/core/Point', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Point = PIXI.Point;
+
+ it('Module exists', function () {
+ expect(Point).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Point();
+ pixi_core_Point_confirm(obj, 0, 0);
+ });
+});
diff --git a/test/unit/pixi/core/Polygon.js b/test/unit/pixi/core/Polygon.js
new file mode 100644
index 0000000..dc8c918
--- /dev/null
+++ b/test/unit/pixi/core/Polygon.js
@@ -0,0 +1,20 @@
+describe('pixi/core/Polygon', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Polygon = PIXI.Polygon;
+
+ it('Module exists', function () {
+ expect(Polygon).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Polygon();
+
+ expect(obj).to.be.an.instanceof(Polygon);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.deep.property('points.length', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Rectangle.js b/test/unit/pixi/core/Rectangle.js
new file mode 100644
index 0000000..d43316e
--- /dev/null
+++ b/test/unit/pixi/core/Rectangle.js
@@ -0,0 +1,15 @@
+describe('pixi/core/Rectangle', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Rectangle = PIXI.Rectangle;
+
+ it('Module exists', function () {
+ expect(Rectangle).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var rect = new Rectangle();
+ pixi_core_Rectangle_confirm(rect, 0, 0, 0, 0);
+ });
+});
diff --git a/test/unit/pixi/display/DisplayObject.js b/test/unit/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..40c6fbc
--- /dev/null
+++ b/test/unit/pixi/display/DisplayObject.js
@@ -0,0 +1,21 @@
+describe('pixi/display/DisplayObject', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var DisplayObject = PIXI.DisplayObject;
+
+ it('Module exists', function () {
+ expect(DisplayObject).to.be.a('function');
+ expect(PIXI).to.have.property('visibleCount', 0);
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new DisplayObject();
+
+ pixi_display_DisplayObject_confirmNew(obj);
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', false);
+ expect(obj).to.have.property('stage', null);
+ });
+});
diff --git a/test/unit/pixi/display/DisplayObjectContainer.js b/test/unit/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..ce7f02f
--- /dev/null
+++ b/test/unit/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,20 @@
+describe('pixi/display/DisplayObjectContainer', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var DisplayObjectContainer = PIXI.DisplayObjectContainer;
+
+ it('Module exists', function () {
+ expect(DisplayObjectContainer).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new DisplayObjectContainer();
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', false);
+ expect(obj).to.have.property('stage', null);
+ });
+});
diff --git a/test/unit/pixi/display/MovieClip.js b/test/unit/pixi/display/MovieClip.js
new file mode 100644
index 0000000..f3c6c6a
--- /dev/null
+++ b/test/unit/pixi/display/MovieClip.js
@@ -0,0 +1,33 @@
+describe('pixi/display/MovieClip', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var MovieClip = PIXI.MovieClip;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(MovieClip).to.be.a('function');
+ });
+
+ it('Confirm new instance', function (done) {
+ var texture = Texture.fromImage('/base/test/textures/SpriteSheet-Explosion.png');
+ var obj = new MovieClip([texture]);
+
+ pixi_display_Sprite_confirmNew(obj, done);
+
+ expect(obj).to.be.an.instanceof(MovieClip);
+ expect(obj).to.respondTo('stop');
+ expect(obj).to.respondTo('play');
+ expect(obj).to.respondTo('gotoAndStop');
+ expect(obj).to.respondTo('gotoAndPlay');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('textures.length', 1);
+ expect(obj).to.have.deep.property('textures[0]', texture);
+ expect(obj).to.have.property('animationSpeed', 1);
+ expect(obj).to.have.property('loop', true);
+ expect(obj).to.have.property('onComplete', null);
+ expect(obj).to.have.property('currentFrame', 0);
+ expect(obj).to.have.property('playing', false);
+ });
+});
diff --git a/test/unit/pixi/display/Sprite.js b/test/unit/pixi/display/Sprite.js
new file mode 100644
index 0000000..54e914f
--- /dev/null
+++ b/test/unit/pixi/display/Sprite.js
@@ -0,0 +1,25 @@
+describe('pixi/display/Sprite', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Sprite = PIXI.Sprite;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(Sprite).to.be.a('function');
+ expect(PIXI).to.have.deep.property('blendModes.NORMAL', 0);
+ expect(PIXI).to.have.deep.property('blendModes.SCREEN', 1);
+ });
+
+ it('Members exist', function () {
+ expect(Sprite).itself.to.respondTo('fromImage');
+ expect(Sprite).itself.to.respondTo('fromFrame');
+ });
+
+ it('Confirm new instance', function (done) {
+ var texture = Texture.fromImage('/base/test/textures/SpriteSheet-Aliens.png');
+ var obj = new Sprite(texture);
+
+ pixi_display_Sprite_confirmNew(obj, done);
+ });
+});
diff --git a/test/unit/pixi/display/Stage.js b/test/unit/pixi/display/Stage.js
new file mode 100644
index 0000000..3cc2a4d
--- /dev/null
+++ b/test/unit/pixi/display/Stage.js
@@ -0,0 +1,49 @@
+describe('pixi/display/Stage', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Stage = PIXI.Stage;
+ var InteractionManager = PIXI.InteractionManager;
+ var Rectangle = PIXI.Rectangle;
+
+ it('Module exists', function () {
+ expect(Stage).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Stage(null, true);
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(Stage);
+ expect(obj).to.respondTo('updateTransform');
+ expect(obj).to.respondTo('setBackgroundColor');
+ expect(obj).to.respondTo('getMousePosition');
+
+ // FIXME: duplicate member in DisplayObject
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ // FIXME: convert arg to bool in constructor
+ expect(obj).to.have.property('interactive', true);
+
+ expect(obj).to.have.property('interactionManager')
+ .and.to.be.an.instanceof(InteractionManager)
+ .and.to.have.property('stage', obj);
+
+ expect(obj).to.have.property('dirty', true);
+
+ expect(obj).to.have.property('stage', obj);
+
+ expect(obj).to.have.property('hitArea')
+ .and.to.be.an.instanceof(Rectangle);
+ pixi_core_Rectangle_confirm(obj.hitArea, 0, 0, 100000, 100000);
+
+ expect(obj).to.have.property('backgroundColor', 0x000000);
+ expect(obj).to.have.deep.property('backgroundColorSplit.length', 3);
+ expect(obj).to.have.deep.property('backgroundColorSplit[0]', 0);
+ expect(obj).to.have.deep.property('backgroundColorSplit[1]', 0);
+ expect(obj).to.have.deep.property('backgroundColorSplit[2]', 0);
+ expect(obj).to.have.property('backgroundColorString', '#000000');
+
+ expect(obj).to.have.property('worldVisible', true);
+ });
+});
diff --git a/test/unit/pixi/extras/CustomRenderable.js b/test/unit/pixi/extras/CustomRenderable.js
new file mode 100644
index 0000000..8d83cf0
--- /dev/null
+++ b/test/unit/pixi/extras/CustomRenderable.js
@@ -0,0 +1,21 @@
+describe('pixi/extras/CustomRenderable', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var CustomRenderable = PIXI.CustomRenderable;
+
+ it('Module exists', function () {
+ expect(CustomRenderable).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new CustomRenderable();
+
+ pixi_display_DisplayObject_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(CustomRenderable);
+ expect(obj).to.respondTo('renderCanvas');
+ expect(obj).to.respondTo('initWebGL');
+ expect(obj).to.respondTo('renderWebGL');
+ });
+});
diff --git a/test/unit/pixi/extras/Rope.js b/test/unit/pixi/extras/Rope.js
new file mode 100644
index 0000000..6ddaf83
--- /dev/null
+++ b/test/unit/pixi/extras/Rope.js
@@ -0,0 +1,26 @@
+describe('pixi/extras/Rope', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Rope = PIXI.Rope;
+ var Texture = PIXI.Texture;
+ var Point = PIXI.Point;
+
+ it('Module exists', function () {
+ expect(Rope).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var texture = Texture.fromImage('/base/test/textures/bunny.png');
+ var obj = new Rope(texture, [new Point(), new Point(5, 10), new Point(10, 20)]);
+
+ pixi_extras_Strip_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(Rope);
+ expect(obj).to.respondTo('refresh');
+ expect(obj).to.respondTo('updateTransform');
+ expect(obj).to.respondTo('setTexture');
+
+ // TODO: Test properties
+ });
+});
diff --git a/test/unit/pixi/extras/Spine.js b/test/unit/pixi/extras/Spine.js
new file mode 100644
index 0000000..0708bc0
--- /dev/null
+++ b/test/unit/pixi/extras/Spine.js
@@ -0,0 +1,10 @@
+describe('pixi/extras/Spine', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Spine = PIXI.Spine;
+
+ it('Module exists', function () {
+ expect(Spine).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/extras/Strip.js b/test/unit/pixi/extras/Strip.js
new file mode 100644
index 0000000..8e564e1
--- /dev/null
+++ b/test/unit/pixi/extras/Strip.js
@@ -0,0 +1,18 @@
+describe('pixi/extras/Strip', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Strip = PIXI.Strip;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(Strip).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var texture = Texture.fromImage('/base/test/textures/bunny.png');
+ var obj = new Strip(texture, 20, 10000);
+
+ pixi_extras_Strip_confirmNew(obj);
+ });
+});
diff --git a/test/unit/pixi/extras/TilingSprite.js b/test/unit/pixi/extras/TilingSprite.js
new file mode 100644
index 0000000..56aea14
--- /dev/null
+++ b/test/unit/pixi/extras/TilingSprite.js
@@ -0,0 +1,24 @@
+describe('pixi/extras/TilingSprite', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var TilingSprite = PIXI.TilingSprite;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(TilingSprite).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var texture = Texture.fromImage('/base/test/textures/bunny.png');
+ var obj = new TilingSprite(texture, 6000, 12000);
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(TilingSprite);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ // TODO: Test properties
+ });
+});
diff --git a/test/unit/pixi/filters/FilterBlock.js b/test/unit/pixi/filters/FilterBlock.js
new file mode 100644
index 0000000..870cec0
--- /dev/null
+++ b/test/unit/pixi/filters/FilterBlock.js
@@ -0,0 +1,10 @@
+describe('pixi/filters/FilterBlock', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var FilterBlock = PIXI.FilterBlock;
+
+ it('Module exists', function () {
+ expect(FilterBlock).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/filters/MaskFilter.js b/test/unit/pixi/filters/MaskFilter.js
new file mode 100644
index 0000000..32d6a45
--- /dev/null
+++ b/test/unit/pixi/filters/MaskFilter.js
@@ -0,0 +1,10 @@
+describe('pixi/filters/MaskFilter', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ // var MaskFilter = PIXI.MaskFilter;
+
+ // it('Module exists', function () {
+ // expect(MaskFilter).to.be.a('function');
+ // });
+});
diff --git a/test/unit/pixi/loaders/AssetLoader.js b/test/unit/pixi/loaders/AssetLoader.js
new file mode 100644
index 0000000..a0aa0b5
--- /dev/null
+++ b/test/unit/pixi/loaders/AssetLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/AssetLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var AssetLoader = PIXI.AssetLoader;
+
+ it('Module exists', function () {
+ expect(AssetLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/BitmapFontLoader.js b/test/unit/pixi/loaders/BitmapFontLoader.js
new file mode 100644
index 0000000..6253c42
--- /dev/null
+++ b/test/unit/pixi/loaders/BitmapFontLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/BitmapFontLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var BitmapFontLoader = PIXI.BitmapFontLoader;
+
+ it('Module exists', function () {
+ expect(PIXI.BitmapFontLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/ImageLoader.js b/test/unit/pixi/loaders/ImageLoader.js
new file mode 100644
index 0000000..8b1f556
--- /dev/null
+++ b/test/unit/pixi/loaders/ImageLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/ImageLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var ImageLoader = PIXI.ImageLoader;
+
+ it('Module exists', function () {
+ expect(ImageLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/JsonLoader.js b/test/unit/pixi/loaders/JsonLoader.js
new file mode 100644
index 0000000..c577e83
--- /dev/null
+++ b/test/unit/pixi/loaders/JsonLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/JsonLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var JsonLoader = PIXI.JsonLoader;
+
+ it('Module exists', function () {
+ expect(JsonLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/SpineLoader.js b/test/unit/pixi/loaders/SpineLoader.js
new file mode 100644
index 0000000..fdcc0b8
--- /dev/null
+++ b/test/unit/pixi/loaders/SpineLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/SpineLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var SpineLoader = PIXI.SpineLoader;
+
+ it('Module exists', function () {
+ expect(SpineLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/SpriteSheetLoader.js b/test/unit/pixi/loaders/SpriteSheetLoader.js
new file mode 100644
index 0000000..57beb27
--- /dev/null
+++ b/test/unit/pixi/loaders/SpriteSheetLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/SpriteSheetLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var SpriteSheetLoader = PIXI.SpriteSheetLoader;
+
+ it('Module exists', function () {
+ expect(SpriteSheetLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/primitives/Graphics.js b/test/unit/pixi/primitives/Graphics.js
new file mode 100644
index 0000000..b8b3e5c
--- /dev/null
+++ b/test/unit/pixi/primitives/Graphics.js
@@ -0,0 +1,40 @@
+describe('pixi/primitives/Graphics', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Graphics = PIXI.Graphics;
+
+ it('Module exists', function () {
+ expect(Graphics).to.be.a('function');
+
+ expect(Graphics).itself.to.have.property('POLY', 0);
+ expect(Graphics).itself.to.have.property('RECT', 1);
+ expect(Graphics).itself.to.have.property('CIRC', 2);
+ expect(Graphics).itself.to.have.property('ELIP', 3);
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Graphics();
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(Graphics);
+ expect(obj).to.respondTo('lineStyle');
+ expect(obj).to.respondTo('lineStyle');
+ expect(obj).to.respondTo('moveTo');
+ expect(obj).to.respondTo('lineTo');
+ expect(obj).to.respondTo('beginFill');
+ expect(obj).to.respondTo('endFill');
+ expect(obj).to.respondTo('drawRect');
+ expect(obj).to.respondTo('drawCircle');
+ expect(obj).to.respondTo('drawElipse');
+ expect(obj).to.respondTo('clear');
+
+ expect(obj).to.have.property('renderable', true);
+ expect(obj).to.have.property('fillAlpha', 1);
+ expect(obj).to.have.property('lineWidth', 0);
+ expect(obj).to.have.property('lineColor', 'black');
+ expect(obj).to.have.deep.property('graphicsData.length', 0);
+ expect(obj).to.have.deep.property('currentPath.points.length', 0);
+ });
+});
diff --git a/test/unit/pixi/renderers/canvas/CanvasGraphics.js b/test/unit/pixi/renderers/canvas/CanvasGraphics.js
new file mode 100644
index 0000000..8f44472
--- /dev/null
+++ b/test/unit/pixi/renderers/canvas/CanvasGraphics.js
@@ -0,0 +1,15 @@
+describe('renders/canvas/CanvasGraphics', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var CanvasGraphics = PIXI.CanvasGraphics;
+
+ it('Module exists', function () {
+ expect(CanvasGraphics).to.be.a('function');
+ });
+
+ it('Members exist', function () {
+ expect(CanvasGraphics).itself.to.respondTo('renderGraphics');
+ expect(CanvasGraphics).itself.to.respondTo('renderGraphicsMask');
+ });
+});
diff --git a/test/unit/pixi/renderers/canvas/CanvasRenderer.js b/test/unit/pixi/renderers/canvas/CanvasRenderer.js
new file mode 100644
index 0000000..df3a12f
--- /dev/null
+++ b/test/unit/pixi/renderers/canvas/CanvasRenderer.js
@@ -0,0 +1,10 @@
+describe('renderers/canvas/CanvasRenderer', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var CanvasRenderer = PIXI.CanvasRenderer;
+
+ it('Module exists', function () {
+ expect(CanvasRenderer).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/renderers/webgl/WebGLBatch.js b/test/unit/pixi/renderers/webgl/WebGLBatch.js
new file mode 100644
index 0000000..75efd56
--- /dev/null
+++ b/test/unit/pixi/renderers/webgl/WebGLBatch.js
@@ -0,0 +1,10 @@
+describe('renderers/webgl/WebGLBatch', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var WebGLBatch = PIXI.WebGLBatch;
+
+ it('Module exists', function () {
+ expect(WebGLBatch).to.be.a('function');
+ });
+});
diff --git a/.gitignore b/.gitignore
index 12e1b62..0b88317 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
node_modules
.DS_Store
-.project
\ No newline at end of file
+.project
+*.log
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..63e4d7c
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,8 @@
+language: node_js
+node_js:
+ - 0.10
+
+before_script:
+ - npm install -g grunt-cli
+ - export DISPLAY=:99.0
+ - sh -e /etc/init.d/xvfb start
diff --git a/Gruntfile.js b/Gruntfile.js
index b083b49..103938c 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -1,10 +1,12 @@
+'use strict';
+
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-connect');
- grunt.loadNpmTasks('grunt-contrib-qunit');
grunt.loadNpmTasks('grunt-contrib-yuidoc');
+ grunt.loadTasks('tasks');
var root = 'src/pixi/',
debug = 'bin/pixi.dev.js',
@@ -79,7 +81,7 @@
},
files: {
srcBlob: '<%= dirs.src %>/**/*.js',
- testBlob: '<%= dirs.test %>/unit/**/*.js',
+ testBlob: '<%= dirs.test %>/{functional,lib/pixi,unit}/**/*.js',
build: '<%= dirs.build %>/pixi.dev.js',
buildMin: '<%= dirs.build %>/pixi.js'
},
@@ -94,7 +96,12 @@
},
jshint: {
beforeconcat: srcFiles,
- test: ['<%= files.testBlob %>'],
+ test: {
+ src: ['<%= files.testBlob %>'],
+ options: {
+ expr: true
+ }
+ },
options: {
asi: true,
smarttabs: true
@@ -128,12 +135,6 @@
]
},
connect: {
- qunit: {
- options: {
- port: grunt.option('port-test') || 9002,
- base: './'
- }
- },
test: {
options: {
port: grunt.option('port-test') || 9002,
@@ -142,13 +143,6 @@
}
}
},
- qunit: {
- all: {
- options: {
- urls: ['http://localhost:' + (grunt.option('port-test') || 9002) + '/test/index.html']
- }
- }
- },
yuidoc: {
compile: {
name: '<%= pkg.name %>',
@@ -161,6 +155,13 @@
outdir: '<%= dirs.docs %>'
}
}
+ },
+ karma: {
+ unit: {
+ configFile: 'test/karma.conf.js',
+ // browsers: ['Chrome'],
+ singleRun: true
+ }
}
});
@@ -182,9 +183,10 @@
}
)
- grunt.registerTask('default', ['concat', 'uglify', 'distribute']);
grunt.registerTask('build', ['concat', 'uglify', 'distribute']);
- grunt.registerTask('test', ['build', 'connect:qunit', 'qunit']);
+ grunt.registerTask('test', ['concat', 'jshint:test', 'karma']);
grunt.registerTask('docs', ['yuidoc']);
-
-}
\ No newline at end of file
+ grunt.registerTask('default', ['test', 'uglify', 'distribute']);
+ // Travis CI task.
+ grunt.registerTask('travis', ['test']);
+}
diff --git a/README.md b/README.md
index c62ef86..690cfe4 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,8 @@

+[](http://travis-ci.org/drkibitz/pixi.js)
+
#### JavaScript 2D Renderer ####
The aim of this project is to provide a fast lightweight 2D library that works
diff --git a/package.json b/package.json
index b373240..1246a68 100644
--- a/package.json
+++ b/package.json
@@ -18,14 +18,21 @@
"main": "bin/pixi.js",
+ "scripts": {
+ "test": "grunt travis --verbose"
+ },
+
"dependencies": {},
"devDependencies": {
"grunt": "~0.4.x",
- "grunt-contrib-jshint": "0.3.x",
+ "grunt-contrib-jshint": "0.6.x",
"grunt-contrib-uglify": "0.2.x",
- "grunt-contrib-connect": "0.2.x",
- "grunt-contrib-qunit": "0.2.x",
+ "grunt-contrib-connect": "0.3.x",
"grunt-contrib-yuidoc": "0.4.x",
- "grunt-contrib-concat": "0.1.x"
+ "grunt-contrib-concat": "0.3.x",
+ "chai": "~1.7.0",
+ "karma": "0.11.0",
+ "karma-firefox-launcher": "0.1.0",
+ "karma-mocha": "0.1.0"
}
}
diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js
index a7c520e..ee82bbd 100644
--- a/src/pixi/InteractionManager.js
+++ b/src/pixi/InteractionManager.js
@@ -62,7 +62,6 @@
this.onTouchEnd = this.onTouchEnd.bind(this);
this.onTouchMove = this.onTouchMove.bind(this);
-
this.last = 0;
}
diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js
index 1a95d20..eef1059 100644
--- a/src/pixi/core/Ellipse.js
+++ b/src/pixi/core/Ellipse.js
@@ -78,7 +78,7 @@
return (normx + normy < 0.25);
}
-PIXI.Ellipse.getBounds = function()
+PIXI.Ellipse.prototype.getBounds = function()
{
return new PIXI.Rectangle(this.x, this.y, this.width, this.height);
}
diff --git a/tasks/karma.js b/tasks/karma.js
new file mode 100644
index 0000000..c340485
--- /dev/null
+++ b/tasks/karma.js
@@ -0,0 +1,27 @@
+'use strict';
+
+var path = require('path');
+var server = require('karma').server;
+
+module.exports = function (grunt) {
+ grunt.registerMultiTask('karma', 'run karma.', function() {
+ var done = this.async();
+ var options = this.options({
+ background: false
+ });
+ var data = this.data;
+
+ //merge options onto data, with data taking precedence
+ data = grunt.util._.merge(options, data);
+ data.configFile = path.resolve(data.configFile);
+ if (data.configFile) {
+ data.configFile = grunt.template.process(data.configFile);
+ }
+
+ server.start(
+ data,
+ function(code) {
+ done(!code);
+ });
+ });
+};
diff --git a/test/functional/example-1-basics/bunny.png b/test/functional/example-1-basics/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/functional/example-1-basics/bunny.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-30.png b/test/functional/example-1-basics/frame-30.png
new file mode 100644
index 0000000..96e3409
--- /dev/null
+++ b/test/functional/example-1-basics/frame-30.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-60.png b/test/functional/example-1-basics/frame-60.png
new file mode 100644
index 0000000..af3f4ce
--- /dev/null
+++ b/test/functional/example-1-basics/frame-60.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-90.png b/test/functional/example-1-basics/frame-90.png
new file mode 100644
index 0000000..099b823
--- /dev/null
+++ b/test/functional/example-1-basics/frame-90.png
Binary files differ
diff --git a/test/functional/example-1-basics/index.js b/test/functional/example-1-basics/index.js
new file mode 100644
index 0000000..7ae7a98
--- /dev/null
+++ b/test/functional/example-1-basics/index.js
@@ -0,0 +1,133 @@
+describe('Example 1 - Basics', function () {
+ 'use strict';
+
+ var baseUri = '/base/test/functional/example-1-basics';
+ var expect = chai.expect;
+ var currentFrame = 0;
+ var frameEvents = {};
+ var stage;
+ var renderer;
+ var bunny;
+
+ function onFrame(frame, callback) {
+ frameEvents[frame] = callback;
+ }
+
+ function animate() {
+ currentFrame += 1;
+
+ requestAnimFrame( animate );
+
+ // just for fun, lets rotate mr rabbit a little
+ bunny.rotation += 0.1;
+
+ // render the stage
+ renderer.render(stage);
+
+ if (frameEvents[currentFrame])
+ frameEvents[currentFrame](currentFrame);
+ }
+
+ function initScene() {
+ // create an new instance of a pixi stage
+ stage = new PIXI.Stage(0x66FF99);
+
+ // create a renderer instance
+ renderer = PIXI.autoDetectRenderer(400, 300);
+ console.log('Is PIXI.WebGLRenderer: ' + (renderer instanceof PIXI.WebGLRenderer));
+
+ // add the renderer view element to the DOM
+ document.body.appendChild(renderer.view);
+
+ requestAnimFrame( animate );
+
+ // create a texture from an image path
+ var texture = PIXI.Texture.fromImage(baseUri + "/bunny.png");
+ // create a new Sprite using the texture
+ bunny = new PIXI.Sprite(texture);
+
+ // center the sprites anchor point
+ bunny.anchor.x = 0.5;
+ bunny.anchor.y = 0.5;
+
+ // move the sprite t the center of the screen
+ bunny.position.x = 200;
+ bunny.position.y = 150;
+
+ stage.addChild(bunny);
+ }
+
+ it('assets loaded', function (done) {
+ var loader = new PIXI.AssetLoader([
+ baseUri + '/bunny.png',
+ baseUri + '/frame-30.png',
+ baseUri + '/frame-60.png',
+ baseUri + '/frame-90.png'
+ ]);
+ // loader.on('onProgress', function (event) {
+ // console.log(event.content);
+ // });
+ loader.on('onComplete', function (event) {
+ done();
+ initScene();
+ });
+ loader.load();
+ });
+
+ it('frame 30 should match', function (done) {
+ this.timeout(700);
+ onFrame(30, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-30.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 60 should match', function (done) {
+ this.timeout(1200);
+ onFrame(60, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-60.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 90 should match', function (done) {
+ this.timeout(1700);
+ onFrame(90, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-90.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ // it('capture something', function (done) {
+ // this.timeout(2000000);
+ // onFrame(30, function () {
+ // var img = new Image();
+ // img.src = renderer.view.toDataURL('image/png');
+ // document.body.appendChild(img);
+ // });
+ // });
+});
diff --git a/test/index.html b/test/index.html
deleted file mode 100644
index 9cbcac5..0000000
--- a/test/index.html
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
- Pixi.js Test Suite
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/test/karma.conf.js b/test/karma.conf.js
new file mode 100644
index 0000000..c66a696
--- /dev/null
+++ b/test/karma.conf.js
@@ -0,0 +1,82 @@
+module.exports = function(config) {
+ config.set({
+
+ // base path, that will be used to resolve files and exclude
+ basePath : '../',
+
+ frameworks : ['mocha'],
+
+ // list of files / patterns to load in the browser
+ files : [
+ 'node_modules/chai/chai.js',
+ 'bin/pixi.dev.js',
+ 'test/lib/**/*.js',
+ 'test/unit/**/*.js',
+ // 'test/functional/**/*.js',
+ {pattern: 'test/**/*.png', watched: false, included: false, served: true}
+ ],
+
+ // list of files to exclude
+ exclude : [],
+
+ // use dolts reporter, as travis terminal does not support escaping sequences
+ // possible values: 'dots', 'progress', 'junit', 'teamcity'
+ // CLI --reporters progress
+ reporters : ['progress'],
+
+ // web server port
+ // CLI --port 9876
+ port : 9876,
+
+ // cli runner port
+ // CLI --runner-port 9100
+ runnerPort : 9100,
+
+ // enable / disable colors in the output (reporters and logs)
+ // CLI --colors --no-colors
+ colors : true,
+
+ // level of logging
+ // possible values: karma.LOG_DISABLE || karma.LOG_ERROR || karma.LOG_WARN || karma.LOG_INFO || karma.LOG_DEBUG
+ // CLI --log-level debug
+ logLevel : config.LOG_DEBUG,
+
+ // enable / disable watching file and executing tests whenever any file changes
+ // CLI --auto-watch --no-auto-watch
+ autoWatch : false,
+
+ // Start these browsers, currently available:
+ // - Chrome
+ // - ChromeCanary
+ // - Firefox
+ // - Opera
+ // - Safari (only Mac)
+ // - PhantomJS
+ // - IE (only Windows)
+ // CLI --browsers Chrome,Firefox,Safari
+ browsers : ['Firefox'],
+
+ // If browser does not capture in given timeout [ms], kill it
+ // CLI --capture-timeout 5000
+ captureTimeout : 5000,
+
+ // Auto run tests on start (when browsers are captured) and exit
+ // CLI --single-run --no-single-run
+ singleRun : true,
+
+ // report which specs are slower than 500ms
+ // CLI --report-slower-than 500
+ reportSlowerThan : 1000,
+
+ preprocessors : {
+ // '**/client/js/*.js': 'coverage'
+ },
+
+ plugins : [
+ 'karma-mocha',
+ // 'karma-chrome-launcher',
+ 'karma-firefox-launcher',
+ // 'karma-phantomjs-launcher'
+ ]
+ });
+};
diff --git a/test/lib/pixi/core/Matrix.js b/test/lib/pixi/core/Matrix.js
new file mode 100644
index 0000000..d26386b
--- /dev/null
+++ b/test/lib/pixi/core/Matrix.js
@@ -0,0 +1,40 @@
+
+function pixi_core_Matrix_confirmNewMat3(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(1);
+ expect(matrix[5]).to.equal(0);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(1);
+}
+
+function pixi_core_Matrix_confirmNewMat4(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[0]).to.equal(1);
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(0);
+ expect(matrix[5]).to.equal(1);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(0);
+ expect(matrix[9]).to.equal(0);
+ expect(matrix[10]).to.equal(1);
+ expect(matrix[11]).to.equal(0);
+ expect(matrix[12]).to.equal(0);
+ expect(matrix[13]).to.equal(0);
+ expect(matrix[14]).to.equal(0);
+ expect(matrix[15]).to.equal(1);
+}
diff --git a/test/lib/pixi/core/Point.js b/test/lib/pixi/core/Point.js
new file mode 100644
index 0000000..e5df07b
--- /dev/null
+++ b/test/lib/pixi/core/Point.js
@@ -0,0 +1,10 @@
+
+function pixi_core_Point_confirm(obj, x, y) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Point);
+ expect(obj).to.respondTo('clone');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+}
diff --git a/test/lib/pixi/core/Rectangle.js b/test/lib/pixi/core/Rectangle.js
new file mode 100644
index 0000000..23f0d12
--- /dev/null
+++ b/test/lib/pixi/core/Rectangle.js
@@ -0,0 +1,13 @@
+
+function pixi_core_Rectangle_confirm(obj, x, y, width, height) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Rectangle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+ expect(obj).to.have.property('width', width);
+ expect(obj).to.have.property('height', height);
+}
diff --git a/test/lib/pixi/display/DisplayObject.js b/test/lib/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..1388a7f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObject.js
@@ -0,0 +1,43 @@
+
+function pixi_display_DisplayObject_confirmNew(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObject);
+ expect(obj).to.respondTo('setInteractive');
+ expect(obj).to.respondTo('addFilter');
+ expect(obj).to.respondTo('removeFilter');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.property('last', obj);
+ expect(obj).to.have.property('first', obj);
+
+ expect(obj).to.contain.property('position');
+ pixi_core_Point_confirm(obj.position, 0, 0);
+ expect(obj).to.contain.property('scale');
+ pixi_core_Point_confirm(obj.scale, 1, 1);
+ expect(obj).to.contain.property('pivot');
+ pixi_core_Point_confirm(obj.pivot, 0, 0);
+
+ expect(obj).to.have.property('rotation', 0);
+ expect(obj).to.have.property('alpha', 1);
+ expect(obj).to.have.property('visible', true);
+ expect(obj).to.have.property('buttonMode', false);
+ expect(obj).to.have.property('parent', null);
+ expect(obj).to.have.property('worldAlpha', 1);
+
+ expect(obj).to.have.property('hitArea');
+ expect(obj).to.have.property('interactive'); // TODO: Have a better default value
+ expect('mask' in obj).to.be.true; // TODO: Have a better default value
+ expect(obj.mask).to.be.undefined;
+
+ expect(obj).to.have.property('renderable');
+ expect(obj).to.have.property('stage');
+
+ expect(obj).to.have.deep.property('worldTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ expect(obj).to.have.deep.property('localTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.localTransform);
+
+ expect(obj).to.have.deep.property('color.length', 0);
+ expect(obj).to.have.property('dynamic', true);
+}
diff --git a/test/lib/pixi/display/DisplayObjectContainer.js b/test/lib/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..085c59f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,16 @@
+
+function pixi_display_DisplayObjectContainer_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObject_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObjectContainer);
+ expect(obj).to.respondTo('addChild');
+ expect(obj).to.respondTo('addChildAt');
+ expect(obj).to.respondTo('swapChildren');
+ expect(obj).to.respondTo('getChildAt');
+ expect(obj).to.respondTo('removeChild');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('children.length', 0);
+}
diff --git a/test/lib/pixi/display/Sprite.js b/test/lib/pixi/display/Sprite.js
new file mode 100644
index 0000000..cc7a2d6
--- /dev/null
+++ b/test/lib/pixi/display/Sprite.js
@@ -0,0 +1,28 @@
+
+function pixi_display_Sprite_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Sprite);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', true);
+ expect(obj).to.have.property('stage', null);
+
+ expect(obj).to.have.property('anchor');
+ pixi_core_Point_confirm(obj.anchor, 0, 0);
+
+ expect(obj).to.have.property('blendMode', PIXI.blendModes.NORMAL);
+ expect(obj).to.have.property('width', 1); // TODO: is 1 expected
+ expect(obj).to.have.property('height', 1); // TODO: is 1 expected
+
+ // FIXME: Just make this a boolean that is always there
+ expect(!!obj.updateFrame).to.equal(obj.texture.baseTexture.hasLoaded);
+
+ expect(obj).to.have.property('texture');
+ pixi_textures_Texture_confirmNew(obj.texture, done);
+}
diff --git a/test/lib/pixi/extras/Strip.js b/test/lib/pixi/extras/Strip.js
new file mode 100644
index 0000000..8927a8a
--- /dev/null
+++ b/test/lib/pixi/extras/Strip.js
@@ -0,0 +1,12 @@
+
+function pixi_extras_Strip_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Strip);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ // TODO: Test properties
+}
diff --git a/test/lib/pixi/textures/Texture.js b/test/lib/pixi/textures/Texture.js
new file mode 100644
index 0000000..d5867b6
--- /dev/null
+++ b/test/lib/pixi/textures/Texture.js
@@ -0,0 +1,31 @@
+
+function pixi_textures_Texture_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ function confirmFrameDone() {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, obj.baseTexture.width, obj.baseTexture.height);
+
+ expect(obj).to.have.property('width', obj.baseTexture.width);
+ expect(obj).to.have.property('height', obj.baseTexture.height);
+ done();
+ }
+
+ expect(obj).to.be.an.instanceof(PIXI.Texture);
+ pixi_utils_EventTarget_like(obj);
+
+ expect(obj).to.have.property('baseTexture')
+ .and.to.be.an.instanceof(PIXI.BaseTexture);
+
+ expect(obj).to.have.property('scope', obj);
+
+ expect(obj).to.have.property('trim');
+ pixi_core_Point_confirm(obj.trim, 0, 0);
+
+ expect(obj).to.have.property('frame');
+ if (obj.baseTexture.hasLoaded) {
+ confirmFrameDone();
+ } else {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, 1, 1);
+ obj.addEventListener('update', confirmFrameDone);
+ }
+}
diff --git a/test/lib/pixi/utils/EventTarget.js b/test/lib/pixi/utils/EventTarget.js
new file mode 100644
index 0000000..7b1dcfa
--- /dev/null
+++ b/test/lib/pixi/utils/EventTarget.js
@@ -0,0 +1,8 @@
+
+function pixi_utils_EventTarget_like(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.respondTo('addEventListener');
+ expect(obj).to.respondTo('dispatchEvent');
+ expect(obj).to.respondTo('removeEventListener');
+}
diff --git a/test/lib/qunit-1.11.0.css b/test/lib/qunit-1.11.0.css
deleted file mode 100644
index d7fc0c8..0000000
--- a/test/lib/qunit-1.11.0.css
+++ /dev/null
@@ -1,244 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-/** Font Family and Sizes */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
- font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
-}
-
-#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
-#qunit-tests { font-size: smaller; }
-
-
-/** Resets */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter {
- margin: 0;
- padding: 0;
-}
-
-
-/** Header */
-
-#qunit-header {
- padding: 0.5em 0 0.5em 1em;
-
- color: #8699a4;
- background-color: #0d3349;
-
- font-size: 1.5em;
- line-height: 1em;
- font-weight: normal;
-
- border-radius: 5px 5px 0 0;
- -moz-border-radius: 5px 5px 0 0;
- -webkit-border-top-right-radius: 5px;
- -webkit-border-top-left-radius: 5px;
-}
-
-#qunit-header a {
- text-decoration: none;
- color: #c2ccd1;
-}
-
-#qunit-header a:hover,
-#qunit-header a:focus {
- color: #fff;
-}
-
-#qunit-testrunner-toolbar label {
- display: inline-block;
- padding: 0 .5em 0 .1em;
-}
-
-#qunit-banner {
- height: 5px;
-}
-
-#qunit-testrunner-toolbar {
- padding: 0.5em 0 0.5em 2em;
- color: #5E740B;
- background-color: #eee;
- overflow: hidden;
-}
-
-#qunit-userAgent {
- padding: 0.5em 0 0.5em 2.5em;
- background-color: #2b81af;
- color: #fff;
- text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
-}
-
-#qunit-modulefilter-container {
- float: right;
-}
-
-/** Tests: Pass/Fail */
-
-#qunit-tests {
- list-style-position: inside;
-}
-
-#qunit-tests li {
- padding: 0.4em 0.5em 0.4em 2.5em;
- border-bottom: 1px solid #fff;
- list-style-position: inside;
-}
-
-#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running {
- display: none;
-}
-
-#qunit-tests li strong {
- cursor: pointer;
-}
-
-#qunit-tests li a {
- padding: 0.5em;
- color: #c2ccd1;
- text-decoration: none;
-}
-#qunit-tests li a:hover,
-#qunit-tests li a:focus {
- color: #000;
-}
-
-#qunit-tests li .runtime {
- float: right;
- font-size: smaller;
-}
-
-.qunit-assert-list {
- margin-top: 0.5em;
- padding: 0.5em;
-
- background-color: #fff;
-
- border-radius: 5px;
- -moz-border-radius: 5px;
- -webkit-border-radius: 5px;
-}
-
-.qunit-collapsed {
- display: none;
-}
-
-#qunit-tests table {
- border-collapse: collapse;
- margin-top: .2em;
-}
-
-#qunit-tests th {
- text-align: right;
- vertical-align: top;
- padding: 0 .5em 0 0;
-}
-
-#qunit-tests td {
- vertical-align: top;
-}
-
-#qunit-tests pre {
- margin: 0;
- white-space: pre-wrap;
- word-wrap: break-word;
-}
-
-#qunit-tests del {
- background-color: #e0f2be;
- color: #374e0c;
- text-decoration: none;
-}
-
-#qunit-tests ins {
- background-color: #ffcaca;
- color: #500;
- text-decoration: none;
-}
-
-/*** Test Counts */
-
-#qunit-tests b.counts { color: black; }
-#qunit-tests b.passed { color: #5E740B; }
-#qunit-tests b.failed { color: #710909; }
-
-#qunit-tests li li {
- padding: 5px;
- background-color: #fff;
- border-bottom: none;
- list-style-position: inside;
-}
-
-/*** Passing Styles */
-
-#qunit-tests li li.pass {
- color: #3c510c;
- background-color: #fff;
- border-left: 10px solid #C6E746;
-}
-
-#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
-#qunit-tests .pass .test-name { color: #366097; }
-
-#qunit-tests .pass .test-actual,
-#qunit-tests .pass .test-expected { color: #999999; }
-
-#qunit-banner.qunit-pass { background-color: #C6E746; }
-
-/*** Failing Styles */
-
-#qunit-tests li li.fail {
- color: #710909;
- background-color: #fff;
- border-left: 10px solid #EE5757;
- white-space: pre;
-}
-
-#qunit-tests > li:last-child {
- border-radius: 0 0 5px 5px;
- -moz-border-radius: 0 0 5px 5px;
- -webkit-border-bottom-right-radius: 5px;
- -webkit-border-bottom-left-radius: 5px;
-}
-
-#qunit-tests .fail { color: #000000; background-color: #EE5757; }
-#qunit-tests .fail .test-name,
-#qunit-tests .fail .module-name { color: #000000; }
-
-#qunit-tests .fail .test-actual { color: #EE5757; }
-#qunit-tests .fail .test-expected { color: green; }
-
-#qunit-banner.qunit-fail { background-color: #EE5757; }
-
-
-/** Result */
-
-#qunit-testresult {
- padding: 0.5em 0.5em 0.5em 2.5em;
-
- color: #2b81af;
- background-color: #D2E0E6;
-
- border-bottom: 1px solid white;
-}
-#qunit-testresult .module-name {
- font-weight: bold;
-}
-
-/** Fixture */
-
-#qunit-fixture {
- position: absolute;
- top: -10000px;
- left: -10000px;
- width: 1000px;
- height: 1000px;
-}
diff --git a/test/lib/qunit-1.11.0.js b/test/lib/qunit-1.11.0.js
deleted file mode 100644
index 302545f..0000000
--- a/test/lib/qunit-1.11.0.js
+++ /dev/null
@@ -1,2152 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-(function( window ) {
-
-var QUnit,
- assert,
- config,
- onErrorFnPrev,
- testId = 0,
- fileName = (sourceFromStacktrace( 0 ) || "" ).replace(/(:\d+)+\)?/, "").replace(/.+\//, ""),
- toString = Object.prototype.toString,
- hasOwn = Object.prototype.hasOwnProperty,
- // Keep a local reference to Date (GH-283)
- Date = window.Date,
- defined = {
- setTimeout: typeof window.setTimeout !== "undefined",
- sessionStorage: (function() {
- var x = "qunit-test-string";
- try {
- sessionStorage.setItem( x, x );
- sessionStorage.removeItem( x );
- return true;
- } catch( e ) {
- return false;
- }
- }())
- },
- /**
- * Provides a normalized error string, correcting an issue
- * with IE 7 (and prior) where Error.prototype.toString is
- * not properly implemented
- *
- * Based on http://es5.github.com/#x15.11.4.4
- *
- * @param {String|Error} error
- * @return {String} error message
- */
- errorString = function( error ) {
- var name, message,
- errorString = error.toString();
- if ( errorString.substring( 0, 7 ) === "[object" ) {
- name = error.name ? error.name.toString() : "Error";
- message = error.message ? error.message.toString() : "";
- if ( name && message ) {
- return name + ": " + message;
- } else if ( name ) {
- return name;
- } else if ( message ) {
- return message;
- } else {
- return "Error";
- }
- } else {
- return errorString;
- }
- },
- /**
- * Makes a clone of an object using only Array or Object as base,
- * and copies over the own enumerable properties.
- *
- * @param {Object} obj
- * @return {Object} New object with only the own properties (recursively).
- */
- objectValues = function( obj ) {
- // Grunt 0.3.x uses an older version of jshint that still has jshint/jshint#392.
- /*jshint newcap: false */
- var key, val,
- vals = QUnit.is( "array", obj ) ? [] : {};
- for ( key in obj ) {
- if ( hasOwn.call( obj, key ) ) {
- val = obj[key];
- vals[key] = val === Object(val) ? objectValues(val) : val;
- }
- }
- return vals;
- };
-
-function Test( settings ) {
- extend( this, settings );
- this.assertions = [];
- this.testNumber = ++Test.count;
-}
-
-Test.count = 0;
-
-Test.prototype = {
- init: function() {
- var a, b, li,
- tests = id( "qunit-tests" );
-
- if ( tests ) {
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml;
-
- // `a` initialized at top of scope
- a = document.createElement( "a" );
- a.innerHTML = "Rerun";
- a.href = QUnit.url({ testNumber: this.testNumber });
-
- li = document.createElement( "li" );
- li.appendChild( b );
- li.appendChild( a );
- li.className = "running";
- li.id = this.id = "qunit-test-output" + testId++;
-
- tests.appendChild( li );
- }
- },
- setup: function() {
- if ( this.module !== config.previousModule ) {
- if ( config.previousModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.previousModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
- config.previousModule = this.module;
- config.moduleStats = { all: 0, bad: 0 };
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- } else if ( config.autorun ) {
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- }
-
- config.current = this;
-
- this.testEnvironment = extend({
- setup: function() {},
- teardown: function() {}
- }, this.moduleTestEnvironment );
-
- this.started = +new Date();
- runLoggingCallbacks( "testStart", QUnit, {
- name: this.testName,
- module: this.module
- });
-
- // allow utility functions to access the current test environment
- // TODO why??
- QUnit.current_testEnvironment = this.testEnvironment;
-
- if ( !config.pollution ) {
- saveGlobal();
- }
- if ( config.notrycatch ) {
- this.testEnvironment.setup.call( this.testEnvironment );
- return;
- }
- try {
- this.testEnvironment.setup.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Setup failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- },
- run: function() {
- config.current = this;
-
- var running = id( "qunit-testresult" );
-
- if ( running ) {
- running.innerHTML = "Running:
" + this.nameHtml;
- }
-
- if ( this.async ) {
- QUnit.stop();
- }
-
- this.callbackStarted = +new Date();
-
- if ( config.notrycatch ) {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- return;
- }
-
- try {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- } catch( e ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
-
- QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + " " + this.stack + ": " + ( e.message || e ), extractStacktrace( e, 0 ) );
- // else next test will carry the responsibility
- saveGlobal();
-
- // Restart the tests if they're blocking
- if ( config.blocking ) {
- QUnit.start();
- }
- }
- },
- teardown: function() {
- config.current = this;
- if ( config.notrycatch ) {
- if ( typeof this.callbackRuntime === "undefined" ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
- }
- this.testEnvironment.teardown.call( this.testEnvironment );
- return;
- } else {
- try {
- this.testEnvironment.teardown.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Teardown failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- }
- checkPollution();
- },
- finish: function() {
- config.current = this;
- if ( config.requireExpects && this.expected === null ) {
- QUnit.pushFailure( "Expected number of assertions to be defined, but expect() was not called.", this.stack );
- } else if ( this.expected !== null && this.expected !== this.assertions.length ) {
- QUnit.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack );
- } else if ( this.expected === null && !this.assertions.length ) {
- QUnit.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions.", this.stack );
- }
-
- var i, assertion, a, b, time, li, ol,
- test = this,
- good = 0,
- bad = 0,
- tests = id( "qunit-tests" );
-
- this.runtime = +new Date() - this.started;
- config.stats.all += this.assertions.length;
- config.moduleStats.all += this.assertions.length;
-
- if ( tests ) {
- ol = document.createElement( "ol" );
- ol.className = "qunit-assert-list";
-
- for ( i = 0; i < this.assertions.length; i++ ) {
- assertion = this.assertions[i];
-
- li = document.createElement( "li" );
- li.className = assertion.result ? "pass" : "fail";
- li.innerHTML = assertion.message || ( assertion.result ? "okay" : "failed" );
- ol.appendChild( li );
-
- if ( assertion.result ) {
- good++;
- } else {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
-
- // store result when possible
- if ( QUnit.config.reorder && defined.sessionStorage ) {
- if ( bad ) {
- sessionStorage.setItem( "qunit-test-" + this.module + "-" + this.testName, bad );
- } else {
- sessionStorage.removeItem( "qunit-test-" + this.module + "-" + this.testName );
- }
- }
-
- if ( bad === 0 ) {
- addClass( ol, "qunit-collapsed" );
- }
-
- // `b` initialized at top of scope
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml + " (" + bad + ", " + good + ", " + this.assertions.length + ")";
-
- addEvent(b, "click", function() {
- var next = b.parentNode.lastChild,
- collapsed = hasClass( next, "qunit-collapsed" );
- ( collapsed ? removeClass : addClass )( next, "qunit-collapsed" );
- });
-
- addEvent(b, "dblclick", function( e ) {
- var target = e && e.target ? e.target : window.event.srcElement;
- if ( target.nodeName.toLowerCase() === "span" || target.nodeName.toLowerCase() === "b" ) {
- target = target.parentNode;
- }
- if ( window.location && target.nodeName.toLowerCase() === "strong" ) {
- window.location = QUnit.url({ testNumber: test.testNumber });
- }
- });
-
- // `time` initialized at top of scope
- time = document.createElement( "span" );
- time.className = "runtime";
- time.innerHTML = this.runtime + " ms";
-
- // `li` initialized at top of scope
- li = id( this.id );
- li.className = bad ? "fail" : "pass";
- li.removeChild( li.firstChild );
- a = li.firstChild;
- li.appendChild( b );
- li.appendChild( a );
- li.appendChild( time );
- li.appendChild( ol );
-
- } else {
- for ( i = 0; i < this.assertions.length; i++ ) {
- if ( !this.assertions[i].result ) {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
- }
-
- runLoggingCallbacks( "testDone", QUnit, {
- name: this.testName,
- module: this.module,
- failed: bad,
- passed: this.assertions.length - bad,
- total: this.assertions.length,
- duration: this.runtime
- });
-
- QUnit.reset();
-
- config.current = undefined;
- },
-
- queue: function() {
- var bad,
- test = this;
-
- synchronize(function() {
- test.init();
- });
- function run() {
- // each of these can by async
- synchronize(function() {
- test.setup();
- });
- synchronize(function() {
- test.run();
- });
- synchronize(function() {
- test.teardown();
- });
- synchronize(function() {
- test.finish();
- });
- }
-
- // `bad` initialized at top of scope
- // defer when previous test run passed, if storage is available
- bad = QUnit.config.reorder && defined.sessionStorage &&
- +sessionStorage.getItem( "qunit-test-" + this.module + "-" + this.testName );
-
- if ( bad ) {
- run();
- } else {
- synchronize( run, true );
- }
- }
-};
-
-// Root QUnit object.
-// `QUnit` initialized at top of scope
-QUnit = {
-
- // call on start of module test to prepend name to all tests
- module: function( name, testEnvironment ) {
- config.currentModule = name;
- config.currentModuleTestEnvironment = testEnvironment;
- config.modules[name] = true;
- },
-
- asyncTest: function( testName, expected, callback ) {
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- QUnit.test( testName, expected, callback, true );
- },
-
- test: function( testName, expected, callback, async ) {
- var test,
- nameHtml = "" + escapeText( testName ) + "";
-
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- if ( config.currentModule ) {
- nameHtml = "" + escapeText( config.currentModule ) + ": " + nameHtml;
- }
-
- test = new Test({
- nameHtml: nameHtml,
- testName: testName,
- expected: expected,
- async: async,
- callback: callback,
- module: config.currentModule,
- moduleTestEnvironment: config.currentModuleTestEnvironment,
- stack: sourceFromStacktrace( 2 )
- });
-
- if ( !validTest( test ) ) {
- return;
- }
-
- test.queue();
- },
-
- // Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through.
- expect: function( asserts ) {
- if (arguments.length === 1) {
- config.current.expected = asserts;
- } else {
- return config.current.expected;
- }
- },
-
- start: function( count ) {
- // QUnit hasn't been initialized yet.
- // Note: RequireJS (et al) may delay onLoad
- if ( config.semaphore === undefined ) {
- QUnit.begin(function() {
- // This is triggered at the top of QUnit.load, push start() to the event loop, to allow QUnit.load to finish first
- setTimeout(function() {
- QUnit.start( count );
- });
- });
- return;
- }
-
- config.semaphore -= count || 1;
- // don't start until equal number of stop-calls
- if ( config.semaphore > 0 ) {
- return;
- }
- // ignore if start is called more often then stop
- if ( config.semaphore < 0 ) {
- config.semaphore = 0;
- QUnit.pushFailure( "Called start() while already started (QUnit.config.semaphore was 0 already)", null, sourceFromStacktrace(2) );
- return;
- }
- // A slight delay, to avoid any current callbacks
- if ( defined.setTimeout ) {
- window.setTimeout(function() {
- if ( config.semaphore > 0 ) {
- return;
- }
- if ( config.timeout ) {
- clearTimeout( config.timeout );
- }
-
- config.blocking = false;
- process( true );
- }, 13);
- } else {
- config.blocking = false;
- process( true );
- }
- },
-
- stop: function( count ) {
- config.semaphore += count || 1;
- config.blocking = true;
-
- if ( config.testTimeout && defined.setTimeout ) {
- clearTimeout( config.timeout );
- config.timeout = window.setTimeout(function() {
- QUnit.ok( false, "Test timed out" );
- config.semaphore = 1;
- QUnit.start();
- }, config.testTimeout );
- }
- }
-};
-
-// `assert` initialized at top of scope
-// Asssert helpers
-// All of these must either call QUnit.push() or manually do:
-// - runLoggingCallbacks( "log", .. );
-// - config.current.assertions.push({ .. });
-// We attach it to the QUnit object *after* we expose the public API,
-// otherwise `assert` will become a global variable in browsers (#341).
-assert = {
- /**
- * Asserts rough true-ish result.
- * @name ok
- * @function
- * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" );
- */
- ok: function( result, msg ) {
- if ( !config.current ) {
- throw new Error( "ok() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
- result = !!result;
-
- var source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: msg
- };
-
- msg = escapeText( msg || (result ? "okay" : "failed" ) );
- msg = "" + msg + "";
-
- if ( !result ) {
- source = sourceFromStacktrace( 2 );
- if ( source ) {
- details.source = source;
- msg += "Source: | " + escapeText( source ) + " |
---|
";
- }
- }
- runLoggingCallbacks( "log", QUnit, details );
- config.current.assertions.push({
- result: result,
- message: msg
- });
- },
-
- /**
- * Assert that the first two arguments are equal, with an optional message.
- * Prints out both actual and expected values.
- * @name equal
- * @function
- * @example equal( format( "Received {0} bytes.", 2), "Received 2 bytes.", "format() replaces {0} with next argument" );
- */
- equal: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected == actual, actual, expected, message );
- },
-
- /**
- * @name notEqual
- * @function
- */
- notEqual: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected != actual, actual, expected, message );
- },
-
- /**
- * @name propEqual
- * @function
- */
- propEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notPropEqual
- * @function
- */
- notPropEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name deepEqual
- * @function
- */
- deepEqual: function( actual, expected, message ) {
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notDeepEqual
- * @function
- */
- notDeepEqual: function( actual, expected, message ) {
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name strictEqual
- * @function
- */
- strictEqual: function( actual, expected, message ) {
- QUnit.push( expected === actual, actual, expected, message );
- },
-
- /**
- * @name notStrictEqual
- * @function
- */
- notStrictEqual: function( actual, expected, message ) {
- QUnit.push( expected !== actual, actual, expected, message );
- },
-
- "throws": function( block, expected, message ) {
- var actual,
- expectedOutput = expected,
- ok = false;
-
- // 'expected' is optional
- if ( typeof expected === "string" ) {
- message = expected;
- expected = null;
- }
-
- config.current.ignoreGlobalErrors = true;
- try {
- block.call( config.current.testEnvironment );
- } catch (e) {
- actual = e;
- }
- config.current.ignoreGlobalErrors = false;
-
- if ( actual ) {
- // we don't want to validate thrown error
- if ( !expected ) {
- ok = true;
- expectedOutput = null;
- // expected is a regexp
- } else if ( QUnit.objectType( expected ) === "regexp" ) {
- ok = expected.test( errorString( actual ) );
- // expected is a constructor
- } else if ( actual instanceof expected ) {
- ok = true;
- // expected is a validation function which returns true is validation passed
- } else if ( expected.call( {}, actual ) === true ) {
- expectedOutput = null;
- ok = true;
- }
-
- QUnit.push( ok, actual, expectedOutput, message );
- } else {
- QUnit.pushFailure( message, null, 'No exception was thrown.' );
- }
- }
-};
-
-/**
- * @deprecate since 1.8.0
- * Kept assertion helpers in root for backwards compatibility.
- */
-extend( QUnit, assert );
-
-/**
- * @deprecated since 1.9.0
- * Kept root "raises()" for backwards compatibility.
- * (Note that we don't introduce assert.raises).
- */
-QUnit.raises = assert[ "throws" ];
-
-/**
- * @deprecated since 1.0.0, replaced with error pushes since 1.3.0
- * Kept to avoid TypeErrors for undefined methods.
- */
-QUnit.equals = function() {
- QUnit.push( false, false, false, "QUnit.equals has been deprecated since 2009 (e88049a0), use QUnit.equal instead" );
-};
-QUnit.same = function() {
- QUnit.push( false, false, false, "QUnit.same has been deprecated since 2009 (e88049a0), use QUnit.deepEqual instead" );
-};
-
-// We want access to the constructor's prototype
-(function() {
- function F() {}
- F.prototype = QUnit;
- QUnit = new F();
- // Make F QUnit's constructor so that we can add to the prototype later
- QUnit.constructor = F;
-}());
-
-/**
- * Config object: Maintain internal state
- * Later exposed as QUnit.config
- * `config` initialized at top of scope
- */
-config = {
- // The queue of tests to run
- queue: [],
-
- // block until document ready
- blocking: true,
-
- // when enabled, show only failing tests
- // gets persisted through sessionStorage and can be changed in UI via checkbox
- hidepassed: false,
-
- // by default, run previously failed tests first
- // very useful in combination with "Hide passed tests" checked
- reorder: true,
-
- // by default, modify document.title when suite is done
- altertitle: true,
-
- // when enabled, all tests must call expect()
- requireExpects: false,
-
- // add checkboxes that are persisted in the query-string
- // when enabled, the id is set to `true` as a `QUnit.config` property
- urlConfig: [
- {
- id: "noglobals",
- label: "Check for Globals",
- tooltip: "Enabling this will test if any test introduces new properties on the `window` object. Stored as query-strings."
- },
- {
- id: "notrycatch",
- label: "No try-catch",
- tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging exceptions in IE reasonable. Stored as query-strings."
- }
- ],
-
- // Set of all modules.
- modules: {},
-
- // logging callback queues
- begin: [],
- done: [],
- log: [],
- testStart: [],
- testDone: [],
- moduleStart: [],
- moduleDone: []
-};
-
-// Export global variables, unless an 'exports' object exists,
-// in that case we assume we're in CommonJS (dealt with on the bottom of the script)
-if ( typeof exports === "undefined" ) {
- extend( window, QUnit );
-
- // Expose QUnit object
- window.QUnit = QUnit;
-}
-
-// Initialize more QUnit.config and QUnit.urlParams
-(function() {
- var i,
- location = window.location || { search: "", protocol: "file:" },
- params = location.search.slice( 1 ).split( "&" ),
- length = params.length,
- urlParams = {},
- current;
-
- if ( params[ 0 ] ) {
- for ( i = 0; i < length; i++ ) {
- current = params[ i ].split( "=" );
- current[ 0 ] = decodeURIComponent( current[ 0 ] );
- // allow just a key to turn on a flag, e.g., test.html?noglobals
- current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true;
- urlParams[ current[ 0 ] ] = current[ 1 ];
- }
- }
-
- QUnit.urlParams = urlParams;
-
- // String search anywhere in moduleName+testName
- config.filter = urlParams.filter;
-
- // Exact match of the module name
- config.module = urlParams.module;
-
- config.testNumber = parseInt( urlParams.testNumber, 10 ) || null;
-
- // Figure out if we're running the tests from a server or not
- QUnit.isLocal = location.protocol === "file:";
-}());
-
-// Extend QUnit object,
-// these after set here because they should not be exposed as global functions
-extend( QUnit, {
- assert: assert,
-
- config: config,
-
- // Initialize the configuration options
- init: function() {
- extend( config, {
- stats: { all: 0, bad: 0 },
- moduleStats: { all: 0, bad: 0 },
- started: +new Date(),
- updateRate: 1000,
- blocking: false,
- autostart: true,
- autorun: false,
- filter: "",
- queue: [],
- semaphore: 1
- });
-
- var tests, banner, result,
- qunit = id( "qunit" );
-
- if ( qunit ) {
- qunit.innerHTML =
- "" +
- "" +
- "" +
- "" +
- "
";
- }
-
- tests = id( "qunit-tests" );
- banner = id( "qunit-banner" );
- result = id( "qunit-testresult" );
-
- if ( tests ) {
- tests.innerHTML = "";
- }
-
- if ( banner ) {
- banner.className = "";
- }
-
- if ( result ) {
- result.parentNode.removeChild( result );
- }
-
- if ( tests ) {
- result = document.createElement( "p" );
- result.id = "qunit-testresult";
- result.className = "result";
- tests.parentNode.insertBefore( result, tests );
- result.innerHTML = "Running...
";
- }
- },
-
- // Resets the test setup. Useful for tests that modify the DOM.
- reset: function() {
- var fixture = id( "qunit-fixture" );
- if ( fixture ) {
- fixture.innerHTML = config.fixture;
- }
- },
-
- // Trigger an event on an element.
- // @example triggerEvent( document.body, "click" );
- triggerEvent: function( elem, type, event ) {
- if ( document.createEvent ) {
- event = document.createEvent( "MouseEvents" );
- event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView,
- 0, 0, 0, 0, 0, false, false, false, false, 0, null);
-
- elem.dispatchEvent( event );
- } else if ( elem.fireEvent ) {
- elem.fireEvent( "on" + type );
- }
- },
-
- // Safe object type checking
- is: function( type, obj ) {
- return QUnit.objectType( obj ) === type;
- },
-
- objectType: function( obj ) {
- if ( typeof obj === "undefined" ) {
- return "undefined";
- // consider: typeof null === object
- }
- if ( obj === null ) {
- return "null";
- }
-
- var match = toString.call( obj ).match(/^\[object\s(.*)\]$/),
- type = match && match[1] || "";
-
- switch ( type ) {
- case "Number":
- if ( isNaN(obj) ) {
- return "nan";
- }
- return "number";
- case "String":
- case "Boolean":
- case "Array":
- case "Date":
- case "RegExp":
- case "Function":
- return type.toLowerCase();
- }
- if ( typeof obj === "object" ) {
- return "object";
- }
- return undefined;
- },
-
- push: function( result, actual, expected, message ) {
- if ( !config.current ) {
- throw new Error( "assertion outside test context, was " + sourceFromStacktrace() );
- }
-
- var output, source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: message,
- actual: actual,
- expected: expected
- };
-
- message = escapeText( message ) || ( result ? "okay" : "failed" );
- message = "" + message + "";
- output = message;
-
- if ( !result ) {
- expected = escapeText( QUnit.jsDump.parse(expected) );
- actual = escapeText( QUnit.jsDump.parse(actual) );
- output += "Expected: | " + expected + " |
";
-
- if ( actual !== expected ) {
- output += "Result: | " + actual + " |
";
- output += "Diff: | " + QUnit.diff( expected, actual ) + " |
";
- }
-
- source = sourceFromStacktrace();
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
- }
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: !!result,
- message: output
- });
- },
-
- pushFailure: function( message, source, actual ) {
- if ( !config.current ) {
- throw new Error( "pushFailure() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
-
- var output,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: false,
- message: message
- };
-
- message = escapeText( message ) || "error";
- message = "" + message + "";
- output = message;
-
- output += "";
-
- if ( actual ) {
- output += "Result: | " + escapeText( actual ) + " |
";
- }
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: false,
- message: output
- });
- },
-
- url: function( params ) {
- params = extend( extend( {}, QUnit.urlParams ), params );
- var key,
- querystring = "?";
-
- for ( key in params ) {
- if ( !hasOwn.call( params, key ) ) {
- continue;
- }
- querystring += encodeURIComponent( key ) + "=" +
- encodeURIComponent( params[ key ] ) + "&";
- }
- return window.location.protocol + "//" + window.location.host +
- window.location.pathname + querystring.slice( 0, -1 );
- },
-
- extend: extend,
- id: id,
- addEvent: addEvent
- // load, equiv, jsDump, diff: Attached later
-});
-
-/**
- * @deprecated: Created for backwards compatibility with test runner that set the hook function
- * into QUnit.{hook}, instead of invoking it and passing the hook function.
- * QUnit.constructor is set to the empty F() above so that we can add to it's prototype here.
- * Doing this allows us to tell if the following methods have been overwritten on the actual
- * QUnit object.
- */
-extend( QUnit.constructor.prototype, {
-
- // Logging callbacks; all receive a single argument with the listed properties
- // run test/logs.html for any related changes
- begin: registerLoggingCallback( "begin" ),
-
- // done: { failed, passed, total, runtime }
- done: registerLoggingCallback( "done" ),
-
- // log: { result, actual, expected, message }
- log: registerLoggingCallback( "log" ),
-
- // testStart: { name }
- testStart: registerLoggingCallback( "testStart" ),
-
- // testDone: { name, failed, passed, total, duration }
- testDone: registerLoggingCallback( "testDone" ),
-
- // moduleStart: { name }
- moduleStart: registerLoggingCallback( "moduleStart" ),
-
- // moduleDone: { name, failed, passed, total }
- moduleDone: registerLoggingCallback( "moduleDone" )
-});
-
-if ( typeof document === "undefined" || document.readyState === "complete" ) {
- config.autorun = true;
-}
-
-QUnit.load = function() {
- runLoggingCallbacks( "begin", QUnit, {} );
-
- // Initialize the config, saving the execution queue
- var banner, filter, i, label, len, main, ol, toolbar, userAgent, val,
- urlConfigCheckboxesContainer, urlConfigCheckboxes, moduleFilter,
- numModules = 0,
- moduleFilterHtml = "",
- urlConfigHtml = "",
- oldconfig = extend( {}, config );
-
- QUnit.init();
- extend(config, oldconfig);
-
- config.blocking = false;
-
- len = config.urlConfig.length;
-
- for ( i = 0; i < len; i++ ) {
- val = config.urlConfig[i];
- if ( typeof val === "string" ) {
- val = {
- id: val,
- label: val,
- tooltip: "[no tooltip available]"
- };
- }
- config[ val.id ] = QUnit.urlParams[ val.id ];
- urlConfigHtml += "";
- }
-
- moduleFilterHtml += "";
-
- // `userAgent` initialized at top of scope
- userAgent = id( "qunit-userAgent" );
- if ( userAgent ) {
- userAgent.innerHTML = navigator.userAgent;
- }
-
- // `banner` initialized at top of scope
- banner = id( "qunit-header" );
- if ( banner ) {
- banner.innerHTML = "" + banner.innerHTML + " ";
- }
-
- // `toolbar` initialized at top of scope
- toolbar = id( "qunit-testrunner-toolbar" );
- if ( toolbar ) {
- // `filter` initialized at top of scope
- filter = document.createElement( "input" );
- filter.type = "checkbox";
- filter.id = "qunit-filter-pass";
-
- addEvent( filter, "click", function() {
- var tmp,
- ol = document.getElementById( "qunit-tests" );
-
- if ( filter.checked ) {
- ol.className = ol.className + " hidepass";
- } else {
- tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " ";
- ol.className = tmp.replace( / hidepass /, " " );
- }
- if ( defined.sessionStorage ) {
- if (filter.checked) {
- sessionStorage.setItem( "qunit-filter-passed-tests", "true" );
- } else {
- sessionStorage.removeItem( "qunit-filter-passed-tests" );
- }
- }
- });
-
- if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem( "qunit-filter-passed-tests" ) ) {
- filter.checked = true;
- // `ol` initialized at top of scope
- ol = document.getElementById( "qunit-tests" );
- ol.className = ol.className + " hidepass";
- }
- toolbar.appendChild( filter );
-
- // `label` initialized at top of scope
- label = document.createElement( "label" );
- label.setAttribute( "for", "qunit-filter-pass" );
- label.setAttribute( "title", "Only show tests and assertons that fail. Stored in sessionStorage." );
- label.innerHTML = "Hide passed tests";
- toolbar.appendChild( label );
-
- urlConfigCheckboxesContainer = document.createElement("span");
- urlConfigCheckboxesContainer.innerHTML = urlConfigHtml;
- urlConfigCheckboxes = urlConfigCheckboxesContainer.getElementsByTagName("input");
- // For oldIE support:
- // * Add handlers to the individual elements instead of the container
- // * Use "click" instead of "change"
- // * Fallback from event.target to event.srcElement
- addEvents( urlConfigCheckboxes, "click", function( event ) {
- var params = {},
- target = event.target || event.srcElement;
- params[ target.name ] = target.checked ? true : undefined;
- window.location = QUnit.url( params );
- });
- toolbar.appendChild( urlConfigCheckboxesContainer );
-
- if (numModules > 1) {
- moduleFilter = document.createElement( 'span' );
- moduleFilter.setAttribute( 'id', 'qunit-modulefilter-container' );
- moduleFilter.innerHTML = moduleFilterHtml;
- addEvent( moduleFilter.lastChild, "change", function() {
- var selectBox = moduleFilter.getElementsByTagName("select")[0],
- selectedModule = decodeURIComponent(selectBox.options[selectBox.selectedIndex].value);
-
- window.location = QUnit.url( { module: ( selectedModule === "" ) ? undefined : selectedModule } );
- });
- toolbar.appendChild(moduleFilter);
- }
- }
-
- // `main` initialized at top of scope
- main = id( "qunit-fixture" );
- if ( main ) {
- config.fixture = main.innerHTML;
- }
-
- if ( config.autostart ) {
- QUnit.start();
- }
-};
-
-addEvent( window, "load", QUnit.load );
-
-// `onErrorFnPrev` initialized at top of scope
-// Preserve other handlers
-onErrorFnPrev = window.onerror;
-
-// Cover uncaught exceptions
-// Returning true will surpress the default browser handler,
-// returning false will let it run.
-window.onerror = function ( error, filePath, linerNr ) {
- var ret = false;
- if ( onErrorFnPrev ) {
- ret = onErrorFnPrev( error, filePath, linerNr );
- }
-
- // Treat return value as window.onerror itself does,
- // Only do our handling if not surpressed.
- if ( ret !== true ) {
- if ( QUnit.config.current ) {
- if ( QUnit.config.current.ignoreGlobalErrors ) {
- return true;
- }
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- } else {
- QUnit.test( "global failure", extend( function() {
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- }, { validTest: validTest } ) );
- }
- return false;
- }
-
- return ret;
-};
-
-function done() {
- config.autorun = true;
-
- // Log the last module results
- if ( config.currentModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.currentModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
-
- var i, key,
- banner = id( "qunit-banner" ),
- tests = id( "qunit-tests" ),
- runtime = +new Date() - config.started,
- passed = config.stats.all - config.stats.bad,
- html = [
- "Tests completed in ",
- runtime,
- " milliseconds.
",
- "",
- passed,
- " assertions of ",
- config.stats.all,
- " passed, ",
- config.stats.bad,
- " failed."
- ].join( "" );
-
- if ( banner ) {
- banner.className = ( config.stats.bad ? "qunit-fail" : "qunit-pass" );
- }
-
- if ( tests ) {
- id( "qunit-testresult" ).innerHTML = html;
- }
-
- if ( config.altertitle && typeof document !== "undefined" && document.title ) {
- // show ✖ for good, ✔ for bad suite result in title
- // use escape sequences in case file gets loaded with non-utf-8-charset
- document.title = [
- ( config.stats.bad ? "\u2716" : "\u2714" ),
- document.title.replace( /^[\u2714\u2716] /i, "" )
- ].join( " " );
- }
-
- // clear own sessionStorage items if all tests passed
- if ( config.reorder && defined.sessionStorage && config.stats.bad === 0 ) {
- // `key` & `i` initialized at top of scope
- for ( i = 0; i < sessionStorage.length; i++ ) {
- key = sessionStorage.key( i++ );
- if ( key.indexOf( "qunit-test-" ) === 0 ) {
- sessionStorage.removeItem( key );
- }
- }
- }
-
- // scroll back to top to show results
- if ( window.scrollTo ) {
- window.scrollTo(0, 0);
- }
-
- runLoggingCallbacks( "done", QUnit, {
- failed: config.stats.bad,
- passed: passed,
- total: config.stats.all,
- runtime: runtime
- });
-}
-
-/** @return Boolean: true if this test should be ran */
-function validTest( test ) {
- var include,
- filter = config.filter && config.filter.toLowerCase(),
- module = config.module && config.module.toLowerCase(),
- fullName = (test.module + ": " + test.testName).toLowerCase();
-
- // Internally-generated tests are always valid
- if ( test.callback && test.callback.validTest === validTest ) {
- delete test.callback.validTest;
- return true;
- }
-
- if ( config.testNumber ) {
- return test.testNumber === config.testNumber;
- }
-
- if ( module && ( !test.module || test.module.toLowerCase() !== module ) ) {
- return false;
- }
-
- if ( !filter ) {
- return true;
- }
-
- include = filter.charAt( 0 ) !== "!";
- if ( !include ) {
- filter = filter.slice( 1 );
- }
-
- // If the filter matches, we need to honour include
- if ( fullName.indexOf( filter ) !== -1 ) {
- return include;
- }
-
- // Otherwise, do the opposite
- return !include;
-}
-
-// so far supports only Firefox, Chrome and Opera (buggy), Safari (for real exceptions)
-// Later Safari and IE10 are supposed to support error.stack as well
-// See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack
-function extractStacktrace( e, offset ) {
- offset = offset === undefined ? 3 : offset;
-
- var stack, include, i;
-
- if ( e.stacktrace ) {
- // Opera
- return e.stacktrace.split( "\n" )[ offset + 3 ];
- } else if ( e.stack ) {
- // Firefox, Chrome
- stack = e.stack.split( "\n" );
- if (/^error$/i.test( stack[0] ) ) {
- stack.shift();
- }
- if ( fileName ) {
- include = [];
- for ( i = offset; i < stack.length; i++ ) {
- if ( stack[ i ].indexOf( fileName ) !== -1 ) {
- break;
- }
- include.push( stack[ i ] );
- }
- if ( include.length ) {
- return include.join( "\n" );
- }
- }
- return stack[ offset ];
- } else if ( e.sourceURL ) {
- // Safari, PhantomJS
- // hopefully one day Safari provides actual stacktraces
- // exclude useless self-reference for generated Error objects
- if ( /qunit.js$/.test( e.sourceURL ) ) {
- return;
- }
- // for actual exceptions, this is useful
- return e.sourceURL + ":" + e.line;
- }
-}
-function sourceFromStacktrace( offset ) {
- try {
- throw new Error();
- } catch ( e ) {
- return extractStacktrace( e, offset );
- }
-}
-
-/**
- * Escape text for attribute or text content.
- */
-function escapeText( s ) {
- if ( !s ) {
- return "";
- }
- s = s + "";
- // Both single quotes and double quotes (for attributes)
- return s.replace( /['"<>&]/g, function( s ) {
- switch( s ) {
- case '\'':
- return ''';
- case '"':
- return '"';
- case '<':
- return '<';
- case '>':
- return '>';
- case '&':
- return '&';
- }
- });
-}
-
-function synchronize( callback, last ) {
- config.queue.push( callback );
-
- if ( config.autorun && !config.blocking ) {
- process( last );
- }
-}
-
-function process( last ) {
- function next() {
- process( last );
- }
- var start = new Date().getTime();
- config.depth = config.depth ? config.depth + 1 : 1;
-
- while ( config.queue.length && !config.blocking ) {
- if ( !defined.setTimeout || config.updateRate <= 0 || ( ( new Date().getTime() - start ) < config.updateRate ) ) {
- config.queue.shift()();
- } else {
- window.setTimeout( next, 13 );
- break;
- }
- }
- config.depth--;
- if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) {
- done();
- }
-}
-
-function saveGlobal() {
- config.pollution = [];
-
- if ( config.noglobals ) {
- for ( var key in window ) {
- // in Opera sometimes DOM element ids show up here, ignore them
- if ( !hasOwn.call( window, key ) || /^qunit-test-output/.test( key ) ) {
- continue;
- }
- config.pollution.push( key );
- }
- }
-}
-
-function checkPollution() {
- var newGlobals,
- deletedGlobals,
- old = config.pollution;
-
- saveGlobal();
-
- newGlobals = diff( config.pollution, old );
- if ( newGlobals.length > 0 ) {
- QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join(", ") );
- }
-
- deletedGlobals = diff( old, config.pollution );
- if ( deletedGlobals.length > 0 ) {
- QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join(", ") );
- }
-}
-
-// returns a new Array with the elements that are in a but not in b
-function diff( a, b ) {
- var i, j,
- result = a.slice();
-
- for ( i = 0; i < result.length; i++ ) {
- for ( j = 0; j < b.length; j++ ) {
- if ( result[i] === b[j] ) {
- result.splice( i, 1 );
- i--;
- break;
- }
- }
- }
- return result;
-}
-
-function extend( a, b ) {
- for ( var prop in b ) {
- if ( b[ prop ] === undefined ) {
- delete a[ prop ];
-
- // Avoid "Member not found" error in IE8 caused by setting window.constructor
- } else if ( prop !== "constructor" || a !== window ) {
- a[ prop ] = b[ prop ];
- }
- }
-
- return a;
-}
-
-/**
- * @param {HTMLElement} elem
- * @param {string} type
- * @param {Function} fn
- */
-function addEvent( elem, type, fn ) {
- // Standards-based browsers
- if ( elem.addEventListener ) {
- elem.addEventListener( type, fn, false );
- // IE
- } else {
- elem.attachEvent( "on" + type, fn );
- }
-}
-
-/**
- * @param {Array|NodeList} elems
- * @param {string} type
- * @param {Function} fn
- */
-function addEvents( elems, type, fn ) {
- var i = elems.length;
- while ( i-- ) {
- addEvent( elems[i], type, fn );
- }
-}
-
-function hasClass( elem, name ) {
- return (" " + elem.className + " ").indexOf(" " + name + " ") > -1;
-}
-
-function addClass( elem, name ) {
- if ( !hasClass( elem, name ) ) {
- elem.className += (elem.className ? " " : "") + name;
- }
-}
-
-function removeClass( elem, name ) {
- var set = " " + elem.className + " ";
- // Class name may appear multiple times
- while ( set.indexOf(" " + name + " ") > -1 ) {
- set = set.replace(" " + name + " " , " ");
- }
- // If possible, trim it for prettiness, but not neccecarily
- elem.className = window.jQuery ? jQuery.trim( set ) : ( set.trim ? set.trim() : set );
-}
-
-function id( name ) {
- return !!( typeof document !== "undefined" && document && document.getElementById ) &&
- document.getElementById( name );
-}
-
-function registerLoggingCallback( key ) {
- return function( callback ) {
- config[key].push( callback );
- };
-}
-
-// Supports deprecated method of completely overwriting logging callbacks
-function runLoggingCallbacks( key, scope, args ) {
- var i, callbacks;
- if ( QUnit.hasOwnProperty( key ) ) {
- QUnit[ key ].call(scope, args );
- } else {
- callbacks = config[ key ];
- for ( i = 0; i < callbacks.length; i++ ) {
- callbacks[ i ].call( scope, args );
- }
- }
-}
-
-// Test for equality any JavaScript type.
-// Author: Philippe Rathé
-QUnit.equiv = (function() {
-
- // Call the o related callback with the given arguments.
- function bindCallbacks( o, callbacks, args ) {
- var prop = QUnit.objectType( o );
- if ( prop ) {
- if ( QUnit.objectType( callbacks[ prop ] ) === "function" ) {
- return callbacks[ prop ].apply( callbacks, args );
- } else {
- return callbacks[ prop ]; // or undefined
- }
- }
- }
-
- // the real equiv function
- var innerEquiv,
- // stack to decide between skip/abort functions
- callers = [],
- // stack to avoiding loops from circular referencing
- parents = [],
-
- getProto = Object.getPrototypeOf || function ( obj ) {
- return obj.__proto__;
- },
- callbacks = (function () {
-
- // for string, boolean, number and null
- function useStrictEquality( b, a ) {
- /*jshint eqeqeq:false */
- if ( b instanceof a.constructor || a instanceof b.constructor ) {
- // to catch short annotaion VS 'new' annotation of a
- // declaration
- // e.g. var i = 1;
- // var j = new Number(1);
- return a == b;
- } else {
- return a === b;
- }
- }
-
- return {
- "string": useStrictEquality,
- "boolean": useStrictEquality,
- "number": useStrictEquality,
- "null": useStrictEquality,
- "undefined": useStrictEquality,
-
- "nan": function( b ) {
- return isNaN( b );
- },
-
- "date": function( b, a ) {
- return QUnit.objectType( b ) === "date" && a.valueOf() === b.valueOf();
- },
-
- "regexp": function( b, a ) {
- return QUnit.objectType( b ) === "regexp" &&
- // the regex itself
- a.source === b.source &&
- // and its modifers
- a.global === b.global &&
- // (gmi) ...
- a.ignoreCase === b.ignoreCase &&
- a.multiline === b.multiline &&
- a.sticky === b.sticky;
- },
-
- // - skip when the property is a method of an instance (OOP)
- // - abort otherwise,
- // initial === would have catch identical references anyway
- "function": function() {
- var caller = callers[callers.length - 1];
- return caller !== Object && typeof caller !== "undefined";
- },
-
- "array": function( b, a ) {
- var i, j, len, loop;
-
- // b could be an object literal here
- if ( QUnit.objectType( b ) !== "array" ) {
- return false;
- }
-
- len = a.length;
- if ( len !== b.length ) {
- // safe and faster
- return false;
- }
-
- // track reference to avoid circular references
- parents.push( a );
- for ( i = 0; i < len; i++ ) {
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- loop = true;// dont rewalk array
- }
- }
- if ( !loop && !innerEquiv(a[i], b[i]) ) {
- parents.pop();
- return false;
- }
- }
- parents.pop();
- return true;
- },
-
- "object": function( b, a ) {
- var i, j, loop,
- // Default to true
- eq = true,
- aProperties = [],
- bProperties = [];
-
- // comparing constructors is more strict than using
- // instanceof
- if ( a.constructor !== b.constructor ) {
- // Allow objects with no prototype to be equivalent to
- // objects with Object as their constructor.
- if ( !(( getProto(a) === null && getProto(b) === Object.prototype ) ||
- ( getProto(b) === null && getProto(a) === Object.prototype ) ) ) {
- return false;
- }
- }
-
- // stack constructor before traversing properties
- callers.push( a.constructor );
- // track reference to avoid circular references
- parents.push( a );
-
- for ( i in a ) { // be strict: don't ensures hasOwnProperty
- // and go deep
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- // don't go down the same path twice
- loop = true;
- }
- }
- aProperties.push(i); // collect a's properties
-
- if (!loop && !innerEquiv( a[i], b[i] ) ) {
- eq = false;
- break;
- }
- }
-
- callers.pop(); // unstack, we are done
- parents.pop();
-
- for ( i in b ) {
- bProperties.push( i ); // collect b's properties
- }
-
- // Ensures identical properties name
- return eq && innerEquiv( aProperties.sort(), bProperties.sort() );
- }
- };
- }());
-
- innerEquiv = function() { // can take multiple arguments
- var args = [].slice.apply( arguments );
- if ( args.length < 2 ) {
- return true; // end transition
- }
-
- return (function( a, b ) {
- if ( a === b ) {
- return true; // catch the most you can
- } else if ( a === null || b === null || typeof a === "undefined" ||
- typeof b === "undefined" ||
- QUnit.objectType(a) !== QUnit.objectType(b) ) {
- return false; // don't lose time with error prone cases
- } else {
- return bindCallbacks(a, callbacks, [ b, a ]);
- }
-
- // apply transition with (1..n) arguments
- }( args[0], args[1] ) && arguments.callee.apply( this, args.splice(1, args.length - 1 )) );
- };
-
- return innerEquiv;
-}());
-
-/**
- * jsDump Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com |
- * http://flesler.blogspot.com Licensed under BSD
- * (http://www.opensource.org/licenses/bsd-license.php) Date: 5/15/2008
- *
- * @projectDescription Advanced and extensible data dumping for Javascript.
- * @version 1.0.0
- * @author Ariel Flesler
- * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html}
- */
-QUnit.jsDump = (function() {
- function quote( str ) {
- return '"' + str.toString().replace( /"/g, '\\"' ) + '"';
- }
- function literal( o ) {
- return o + "";
- }
- function join( pre, arr, post ) {
- var s = jsDump.separator(),
- base = jsDump.indent(),
- inner = jsDump.indent(1);
- if ( arr.join ) {
- arr = arr.join( "," + s + inner );
- }
- if ( !arr ) {
- return pre + post;
- }
- return [ pre, inner + arr, base + post ].join(s);
- }
- function array( arr, stack ) {
- var i = arr.length, ret = new Array(i);
- this.up();
- while ( i-- ) {
- ret[i] = this.parse( arr[i] , undefined , stack);
- }
- this.down();
- return join( "[", ret, "]" );
- }
-
- var reName = /^function (\w+)/,
- jsDump = {
- // type is used mostly internally, you can fix a (custom)type in advance
- parse: function( obj, type, stack ) {
- stack = stack || [ ];
- var inStack, res,
- parser = this.parsers[ type || this.typeOf(obj) ];
-
- type = typeof parser;
- inStack = inArray( obj, stack );
-
- if ( inStack !== -1 ) {
- return "recursion(" + (inStack - stack.length) + ")";
- }
- if ( type === "function" ) {
- stack.push( obj );
- res = parser.call( this, obj, stack );
- stack.pop();
- return res;
- }
- return ( type === "string" ) ? parser : this.parsers.error;
- },
- typeOf: function( obj ) {
- var type;
- if ( obj === null ) {
- type = "null";
- } else if ( typeof obj === "undefined" ) {
- type = "undefined";
- } else if ( QUnit.is( "regexp", obj) ) {
- type = "regexp";
- } else if ( QUnit.is( "date", obj) ) {
- type = "date";
- } else if ( QUnit.is( "function", obj) ) {
- type = "function";
- } else if ( typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined" ) {
- type = "window";
- } else if ( obj.nodeType === 9 ) {
- type = "document";
- } else if ( obj.nodeType ) {
- type = "node";
- } else if (
- // native arrays
- toString.call( obj ) === "[object Array]" ||
- // NodeList objects
- ( typeof obj.length === "number" && typeof obj.item !== "undefined" && ( obj.length ? obj.item(0) === obj[0] : ( obj.item( 0 ) === null && typeof obj[0] === "undefined" ) ) )
- ) {
- type = "array";
- } else if ( obj.constructor === Error.prototype.constructor ) {
- type = "error";
- } else {
- type = typeof obj;
- }
- return type;
- },
- separator: function() {
- return this.multiline ? this.HTML ? "
" : "\n" : this.HTML ? " " : " ";
- },
- // extra can be a number, shortcut for increasing-calling-decreasing
- indent: function( extra ) {
- if ( !this.multiline ) {
- return "";
- }
- var chr = this.indentChar;
- if ( this.HTML ) {
- chr = chr.replace( /\t/g, " " ).replace( / /g, " " );
- }
- return new Array( this._depth_ + (extra||0) ).join(chr);
- },
- up: function( a ) {
- this._depth_ += a || 1;
- },
- down: function( a ) {
- this._depth_ -= a || 1;
- },
- setParser: function( name, parser ) {
- this.parsers[name] = parser;
- },
- // The next 3 are exposed so you can use them
- quote: quote,
- literal: literal,
- join: join,
- //
- _depth_: 1,
- // This is the list of parsers, to modify them, use jsDump.setParser
- parsers: {
- window: "[Window]",
- document: "[Document]",
- error: function(error) {
- return "Error(\"" + error.message + "\")";
- },
- unknown: "[Unknown]",
- "null": "null",
- "undefined": "undefined",
- "function": function( fn ) {
- var ret = "function",
- // functions never have name in IE
- name = "name" in fn ? fn.name : (reName.exec(fn) || [])[1];
-
- if ( name ) {
- ret += " " + name;
- }
- ret += "( ";
-
- ret = [ ret, QUnit.jsDump.parse( fn, "functionArgs" ), "){" ].join( "" );
- return join( ret, QUnit.jsDump.parse(fn,"functionCode" ), "}" );
- },
- array: array,
- nodelist: array,
- "arguments": array,
- object: function( map, stack ) {
- var ret = [ ], keys, key, val, i;
- QUnit.jsDump.up();
- keys = [];
- for ( key in map ) {
- keys.push( key );
- }
- keys.sort();
- for ( i = 0; i < keys.length; i++ ) {
- key = keys[ i ];
- val = map[ key ];
- ret.push( QUnit.jsDump.parse( key, "key" ) + ": " + QUnit.jsDump.parse( val, undefined, stack ) );
- }
- QUnit.jsDump.down();
- return join( "{", ret, "}" );
- },
- node: function( node ) {
- var len, i, val,
- open = QUnit.jsDump.HTML ? "<" : "<",
- close = QUnit.jsDump.HTML ? ">" : ">",
- tag = node.nodeName.toLowerCase(),
- ret = open + tag,
- attrs = node.attributes;
-
- if ( attrs ) {
- for ( i = 0, len = attrs.length; i < len; i++ ) {
- val = attrs[i].nodeValue;
- // IE6 includes all attributes in .attributes, even ones not explicitly set.
- // Those have values like undefined, null, 0, false, "" or "inherit".
- if ( val && val !== "inherit" ) {
- ret += " " + attrs[i].nodeName + "=" + QUnit.jsDump.parse( val, "attribute" );
- }
- }
- }
- ret += close;
-
- // Show content of TextNode or CDATASection
- if ( node.nodeType === 3 || node.nodeType === 4 ) {
- ret += node.nodeValue;
- }
-
- return ret + open + "/" + tag + close;
- },
- // function calls it internally, it's the arguments part of the function
- functionArgs: function( fn ) {
- var args,
- l = fn.length;
-
- if ( !l ) {
- return "";
- }
-
- args = new Array(l);
- while ( l-- ) {
- // 97 is 'a'
- args[l] = String.fromCharCode(97+l);
- }
- return " " + args.join( ", " ) + " ";
- },
- // object calls it internally, the key part of an item in a map
- key: quote,
- // function calls it internally, it's the content of the function
- functionCode: "[code]",
- // node calls it internally, it's an html attribute value
- attribute: quote,
- string: quote,
- date: quote,
- regexp: literal,
- number: literal,
- "boolean": literal
- },
- // if true, entities are escaped ( <, >, \t, space and \n )
- HTML: false,
- // indentation unit
- indentChar: " ",
- // if true, items in a collection, are separated by a \n, else just a space.
- multiline: true
- };
-
- return jsDump;
-}());
-
-// from jquery.js
-function inArray( elem, array ) {
- if ( array.indexOf ) {
- return array.indexOf( elem );
- }
-
- for ( var i = 0, length = array.length; i < length; i++ ) {
- if ( array[ i ] === elem ) {
- return i;
- }
- }
-
- return -1;
-}
-
-/*
- * Javascript Diff Algorithm
- * By John Resig (http://ejohn.org/)
- * Modified by Chu Alan "sprite"
- *
- * Released under the MIT license.
- *
- * More Info:
- * http://ejohn.org/projects/javascript-diff-algorithm/
- *
- * Usage: QUnit.diff(expected, actual)
- *
- * QUnit.diff( "the quick brown fox jumped over", "the quick fox jumps over" ) == "the quick brown fox jumped jumps over"
- */
-QUnit.diff = (function() {
- /*jshint eqeqeq:false, eqnull:true */
- function diff( o, n ) {
- var i,
- ns = {},
- os = {};
-
- for ( i = 0; i < n.length; i++ ) {
- if ( !hasOwn.call( ns, n[i] ) ) {
- ns[ n[i] ] = {
- rows: [],
- o: null
- };
- }
- ns[ n[i] ].rows.push( i );
- }
-
- for ( i = 0; i < o.length; i++ ) {
- if ( !hasOwn.call( os, o[i] ) ) {
- os[ o[i] ] = {
- rows: [],
- n: null
- };
- }
- os[ o[i] ].rows.push( i );
- }
-
- for ( i in ns ) {
- if ( !hasOwn.call( ns, i ) ) {
- continue;
- }
- if ( ns[i].rows.length === 1 && hasOwn.call( os, i ) && os[i].rows.length === 1 ) {
- n[ ns[i].rows[0] ] = {
- text: n[ ns[i].rows[0] ],
- row: os[i].rows[0]
- };
- o[ os[i].rows[0] ] = {
- text: o[ os[i].rows[0] ],
- row: ns[i].rows[0]
- };
- }
- }
-
- for ( i = 0; i < n.length - 1; i++ ) {
- if ( n[i].text != null && n[ i + 1 ].text == null && n[i].row + 1 < o.length && o[ n[i].row + 1 ].text == null &&
- n[ i + 1 ] == o[ n[i].row + 1 ] ) {
-
- n[ i + 1 ] = {
- text: n[ i + 1 ],
- row: n[i].row + 1
- };
- o[ n[i].row + 1 ] = {
- text: o[ n[i].row + 1 ],
- row: i + 1
- };
- }
- }
-
- for ( i = n.length - 1; i > 0; i-- ) {
- if ( n[i].text != null && n[ i - 1 ].text == null && n[i].row > 0 && o[ n[i].row - 1 ].text == null &&
- n[ i - 1 ] == o[ n[i].row - 1 ]) {
-
- n[ i - 1 ] = {
- text: n[ i - 1 ],
- row: n[i].row - 1
- };
- o[ n[i].row - 1 ] = {
- text: o[ n[i].row - 1 ],
- row: i - 1
- };
- }
- }
-
- return {
- o: o,
- n: n
- };
- }
-
- return function( o, n ) {
- o = o.replace( /\s+$/, "" );
- n = n.replace( /\s+$/, "" );
-
- var i, pre,
- str = "",
- out = diff( o === "" ? [] : o.split(/\s+/), n === "" ? [] : n.split(/\s+/) ),
- oSpace = o.match(/\s+/g),
- nSpace = n.match(/\s+/g);
-
- if ( oSpace == null ) {
- oSpace = [ " " ];
- }
- else {
- oSpace.push( " " );
- }
-
- if ( nSpace == null ) {
- nSpace = [ " " ];
- }
- else {
- nSpace.push( " " );
- }
-
- if ( out.n.length === 0 ) {
- for ( i = 0; i < out.o.length; i++ ) {
- str += "" + out.o[i] + oSpace[i] + "";
- }
- }
- else {
- if ( out.n[0].text == null ) {
- for ( n = 0; n < out.o.length && out.o[n].text == null; n++ ) {
- str += "" + out.o[n] + oSpace[n] + "";
- }
- }
-
- for ( i = 0; i < out.n.length; i++ ) {
- if (out.n[i].text == null) {
- str += "" + out.n[i] + nSpace[i] + "";
- }
- else {
- // `pre` initialized at top of scope
- pre = "";
-
- for ( n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++ ) {
- pre += "" + out.o[n] + oSpace[n] + "";
- }
- str += " " + out.n[i].text + nSpace[i] + pre;
- }
- }
- }
-
- return str;
- };
-}());
-
-// for CommonJS enviroments, export everything
-if ( typeof exports !== "undefined" ) {
- extend( exports, QUnit );
-}
-
-// get at whatever the global object is, like window in browsers
-}( (function() {return this;}.call()) ));
diff --git a/test/lib/require.js b/test/lib/require.js
deleted file mode 100644
index 987f865..0000000
--- a/test/lib/require.js
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- RequireJS 2.1.5 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.
- Available via the MIT or new BSD license.
- see: http://github.com/jrburke/requirejs for details
-*/
-var requirejs,require,define;
-(function(aa){function I(b){return"[object Function]"===L.call(b)}function J(b){return"[object Array]"===L.call(b)}function y(b,c){if(b){var d;for(d=0;dthis.depCount&&!this.defined){if(I(n)){if(this.events.error)try{e=i.execCb(c,n,b,e)}catch(d){a=d}else e=i.execCb(c,n,b,e);this.map.isDefine&&((b=this.module)&&void 0!==b.exports&&b.exports!==this.exports?e=b.exports:void 0===e&&this.usingExports&&(e=this.exports));if(a)return a.requireMap=this.map,a.requireModules=[this.map.id],a.requireType="define",v(this.error=
-a)}else e=n;this.exports=e;if(this.map.isDefine&&!this.ignore&&(q[c]=e,l.onResourceLoad))l.onResourceLoad(i,this.map,this.depMaps);x(c);this.defined=!0}this.defining=!1;this.defined&&!this.defineEmitted&&(this.defineEmitted=!0,this.emit("defined",this.exports),this.defineEmitComplete=!0)}}else this.fetch()}},callPlugin:function(){var a=this.map,b=a.id,d=j(a.prefix);this.depMaps.push(d);t(d,"defined",u(this,function(e){var n,d;d=this.map.name;var g=this.map.parentMap?this.map.parentMap.name:null,h=
-i.makeRequire(a.parentMap,{enableBuildCallback:!0});if(this.map.unnormalized){if(e.normalize&&(d=e.normalize(d,function(a){return c(a,g,!0)})||""),e=j(a.prefix+"!"+d,this.map.parentMap),t(e,"defined",u(this,function(a){this.init([],function(){return a},null,{enabled:!0,ignore:!0})})),d=m(p,e.id)){this.depMaps.push(e);if(this.events.error)d.on("error",u(this,function(a){this.emit("error",a)}));d.enable()}}else n=u(this,function(a){this.init([],function(){return a},null,{enabled:!0})}),n.error=u(this,
-function(a){this.inited=!0;this.error=a;a.requireModules=[b];G(p,function(a){0===a.map.id.indexOf(b+"_unnormalized")&&x(a.map.id)});v(a)}),n.fromText=u(this,function(e,c){var d=a.name,g=j(d),C=O;c&&(e=c);C&&(O=!1);r(g);s(k.config,b)&&(k.config[d]=k.config[b]);try{l.exec(e)}catch(ca){return v(B("fromtexteval","fromText eval for "+b+" failed: "+ca,ca,[b]))}C&&(O=!0);this.depMaps.push(g);i.completeLoad(d);h([d],n)}),e.load(a.name,h,n,k)}));i.enable(d,this);this.pluginMaps[d.id]=d},enable:function(){V[this.map.id]=
-this;this.enabling=this.enabled=!0;y(this.depMaps,u(this,function(a,b){var c,e;if("string"===typeof a){a=j(a,this.map.isDefine?this.map:this.map.parentMap,!1,!this.skipMap);this.depMaps[b]=a;if(c=m(N,a.id)){this.depExports[b]=c(this);return}this.depCount+=1;t(a,"defined",u(this,function(a){this.defineDep(b,a);this.check()}));this.errback&&t(a,"error",this.errback)}c=a.id;e=p[c];!s(N,c)&&(e&&!e.enabled)&&i.enable(a,this)}));G(this.pluginMaps,u(this,function(a){var b=m(p,a.id);b&&!b.enabled&&i.enable(a,
-this)}));this.enabling=!1;this.check()},on:function(a,b){var c=this.events[a];c||(c=this.events[a]=[]);c.push(b)},emit:function(a,b){y(this.events[a],function(a){a(b)});"error"===a&&delete this.events[a]}};i={config:k,contextName:b,registry:p,defined:q,urlFetched:U,defQueue:H,Module:Z,makeModuleMap:j,nextTick:l.nextTick,onError:v,configure:function(a){a.baseUrl&&"/"!==a.baseUrl.charAt(a.baseUrl.length-1)&&(a.baseUrl+="/");var b=k.pkgs,c=k.shim,e={paths:!0,config:!0,map:!0};G(a,function(a,b){e[b]?
-"map"===b?(k.map||(k.map={}),R(k[b],a,!0,!0)):R(k[b],a,!0):k[b]=a});a.shim&&(G(a.shim,function(a,b){J(a)&&(a={deps:a});if((a.exports||a.init)&&!a.exportsFn)a.exportsFn=i.makeShimExports(a);c[b]=a}),k.shim=c);a.packages&&(y(a.packages,function(a){a="string"===typeof a?{name:a}:a;b[a.name]={name:a.name,location:a.location||a.name,main:(a.main||"main").replace(ja,"").replace(ea,"")}}),k.pkgs=b);G(p,function(a,b){!a.inited&&!a.map.unnormalized&&(a.map=j(b))});if(a.deps||a.callback)i.require(a.deps||[],
-a.callback)},makeShimExports:function(a){return function(){var b;a.init&&(b=a.init.apply(aa,arguments));return b||a.exports&&ba(a.exports)}},makeRequire:function(a,f){function d(e,c,h){var g,k;f.enableBuildCallback&&(c&&I(c))&&(c.__requireJsBuild=!0);if("string"===typeof e){if(I(c))return v(B("requireargs","Invalid require call"),h);if(a&&s(N,e))return N[e](p[a.id]);if(l.get)return l.get(i,e,a,d);g=j(e,a,!1,!0);g=g.id;return!s(q,g)?v(B("notloaded",'Module name "'+g+'" has not been loaded yet for context: '+
-b+(a?"":". Use require([])"))):q[g]}L();i.nextTick(function(){L();k=r(j(null,a));k.skipMap=f.skipMap;k.init(e,c,h,{enabled:!0});D()});return d}f=f||{};R(d,{isBrowser:A,toUrl:function(b){var d,f=b.lastIndexOf("."),g=b.split("/")[0];if(-1!==f&&(!("."===g||".."===g)||1h.attachEvent.toString().indexOf("[native code"))&&!Y?(O=!0,h.attachEvent("onreadystatechange",b.onScriptLoad)):(h.addEventListener("load",b.onScriptLoad,!1),h.addEventListener("error",b.onScriptError,!1)),h.src=d,K=h,D?x.insertBefore(h,D):x.appendChild(h),K=null,h;if(da)try{importScripts(d),b.completeLoad(c)}catch(j){b.onError(B("importscripts","importScripts failed for "+c+" at "+d,j,[c]))}};A&&M(document.getElementsByTagName("script"),function(b){x||(x=
-b.parentNode);if(t=b.getAttribute("data-main"))return r.baseUrl||(E=t.split("/"),Q=E.pop(),fa=E.length?E.join("/")+"/":"./",r.baseUrl=fa,t=Q),t=t.replace(ea,""),r.deps=r.deps?r.deps.concat(t):[t],!0});define=function(b,c,d){var l,h;"string"!==typeof b&&(d=c,c=b,b=null);J(c)||(d=c,c=[]);!c.length&&I(d)&&d.length&&(d.toString().replace(la,"").replace(ma,function(b,d){c.push(d)}),c=(1===d.length?["require"]:["require","exports","module"]).concat(c));if(O){if(!(l=K))P&&"interactive"===P.readyState||M(document.getElementsByTagName("script"),
-function(b){if("interactive"===b.readyState)return P=b}),l=P;l&&(b||(b=l.getAttribute("data-requiremodule")),h=F[l.getAttribute("data-requirecontext")])}(h?h.defQueue:T).push([b,c,d])};define.amd={jQuery:!0};l.exec=function(b){return eval(b)};l(r)}})(this);
diff --git a/test/lib/resemble.js b/test/lib/resemble.js
new file mode 100644
index 0000000..1cb8c29
--- /dev/null
+++ b/test/lib/resemble.js
@@ -0,0 +1,535 @@
+/*
+Author: James Cryer
+Company: Huddle
+Last updated date: 21 Feb 2013
+URL: https://github.com/Huddle/Resemble.js
+*/
+
+(function(_this){
+ 'use strict';
+
+ _this['resemble'] = function( fileData ){
+
+ var data = {};
+ var images = [];
+ var updateCallbackArray = [];
+
+ var tolerance = { // between 0 and 255
+ red: 16,
+ green: 16,
+ blue: 16,
+ minBrightness: 16,
+ maxBrightness: 240
+ };
+
+ var ignoreAntialiasing = false;
+ var ignoreColors = false;
+
+ function triggerDataUpdate(){
+ var len = updateCallbackArray.length;
+ var i;
+ for(i=0;i tolerance.maxBrightness;
+ }
+
+ function getHue(r,g,b){
+
+ r = r / 255;
+ g = g / 255;
+ b = b / 255;
+ var max = Math.max(r, g, b), min = Math.min(r, g, b);
+ var h;
+ var d;
+
+ if (max == min){
+ h = 0; // achromatic
+ } else{
+ d = max - min;
+ switch(max){
+ case r: h = (g - b) / d + (g < b ? 6 : 0); break;
+ case g: h = (b - r) / d + 2; break;
+ case b: h = (r - g) / d + 4; break;
+ }
+ h /= 6;
+ }
+
+ return h;
+ }
+
+ function isAntialiased(sourcePix, data, cacheSet, verticalPos, horizontalPos, width){
+ var offset;
+ var targetPix;
+ var distance = 1;
+ var i;
+ var j;
+ var hasHighContrastSibling = 0;
+ var hasSiblingWithDifferentHue = 0;
+ var hasEquivilantSibling = 0;
+
+ addHueInfo(sourcePix);
+
+ for (i = distance*-1; i <= distance; i++){
+ for (j = distance*-1; j <= distance; j++){
+
+ if(i===0 && j===0){
+ // ignore source pixel
+ } else {
+
+ offset = ((verticalPos+j)*width + (horizontalPos+i)) * 4;
+ targetPix = getPixelInfo(data, offset, cacheSet);
+
+ if(targetPix === null){
+ continue;
+ }
+
+ addBrightnessInfo(targetPix);
+ addHueInfo(targetPix);
+
+ if( isContrasting(sourcePix, targetPix) ){
+ hasHighContrastSibling++;
+ }
+
+ if( isRGBSame(sourcePix,targetPix) ){
+ hasEquivilantSibling++;
+ }
+
+ if( Math.abs(targetPix.h - sourcePix.h) > 0.3 ){
+ hasSiblingWithDifferentHue++;
+ }
+
+ if( hasSiblingWithDifferentHue > 1 || hasHighContrastSibling > 1){
+ return true;
+ }
+ }
+ }
+ }
+
+ if(hasEquivilantSibling < 2){
+ return true;
+ }
+
+ return false;
+ }
+
+ function errorPixel(px, offset){
+ px[offset] = 255; //r
+ px[offset + 1] = 0; //g
+ px[offset + 2] = 255; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyPixel(px, offset, data){
+ px[offset] = data.r; //r
+ px[offset + 1] = data.g; //g
+ px[offset + 2] = data.b; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyGrayScalePixel(px, offset, data){
+ px[offset] = data.brightness; //r
+ px[offset + 1] = data.brightness; //g
+ px[offset + 2] = data.brightness; //b
+ px[offset + 3] = 255; //a
+ }
+
+
+ function getPixelInfo(data, offset, cacheSet){
+ var r;
+ var g;
+ var b;
+ var d;
+
+ if(typeof data[offset] !== 'undefined'){
+ r = data[offset];
+ g = data[offset+1];
+ b = data[offset+2];
+ d = {
+ r: r,
+ g: g,
+ b: b
+ };
+
+ return d;
+ } else {
+ return null;
+ }
+ }
+
+ function addBrightnessInfo(data){
+ data.brightness = getBrightness(data.r,data.g,data.b); // 'corrected' lightness
+ }
+
+ function addHueInfo(data){
+ data.h = getHue(data.r,data.g,data.b);
+ }
+
+ function analyseImages(img1, img2, width, height){
+
+ var hiddenCanvas = document.createElement('canvas');
+
+ var data1 = img1.data;
+ var data2 = img2.data;
+
+ hiddenCanvas.width = width;
+ hiddenCanvas.height = height;
+
+ var context = hiddenCanvas.getContext('2d');
+ var imgd = context.createImageData(width,height);
+ var targetPix = imgd.data;
+
+ var mismatchCount = 0;
+
+ var time = Date.now();
+
+ var skip;
+
+ if( (width > 1200 || height > 1200) && ignoreAntialiasing){
+ skip = 6;
+ }
+
+ loop(height, width, function(verticalPos, horizontalPos){
+
+ if(skip){ // only skip if the image isn't small
+ if(verticalPos % skip === 0 || horizontalPos % skip === 0){
+ return;
+ }
+ }
+
+ var offset = (verticalPos*width + horizontalPos) * 4;
+ var pixel1 = getPixelInfo(data1, offset, 1);
+ var pixel2 = getPixelInfo(data2, offset, 2);
+
+ if(pixel1 === null || pixel2 === null){
+ return;
+ }
+
+ if (ignoreColors){
+
+ addBrightnessInfo(pixel1);
+ addBrightnessInfo(pixel2);
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ return;
+ }
+
+ if( isRGBSimilar(pixel1, pixel2) ){
+ copyPixel(targetPix, offset, pixel2);
+
+ } else if( ignoreAntialiasing && (
+ addBrightnessInfo(pixel1), // jit pixel info augmentation looks a little weird, sorry.
+ addBrightnessInfo(pixel2),
+ isAntialiased(pixel1, data1, 1, verticalPos, horizontalPos, width) ||
+ isAntialiased(pixel2, data2, 2, verticalPos, horizontalPos, width)
+ )){
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+
+ });
+
+ data.misMatchPercentage = (mismatchCount / (height*width) * 100).toFixed(2);
+ data.analysisTime = Date.now() - time;
+
+ data.getImageDataUrl = function(text){
+ var barHeight = 0;
+
+ if(text){
+ barHeight = addLabel(text,context,hiddenCanvas);
+ }
+
+ context.putImageData(imgd, 0, barHeight);
+
+ return hiddenCanvas.toDataURL("image/png");
+ };
+ }
+
+ function addLabel(text, context, hiddenCanvas){
+ var textPadding = 2;
+
+ context.font = '12px sans-serif';
+
+ var textWidth = context.measureText(text).width + textPadding*2;
+ var barHeight = 22;
+
+ if(textWidth > hiddenCanvas.width){
+ hiddenCanvas.width = textWidth;
+ }
+
+ hiddenCanvas.height += barHeight;
+
+ context.fillStyle = "#666";
+ context.fillRect(0,0,hiddenCanvas.width,barHeight -4);
+ context.fillStyle = "#fff";
+ context.fillRect(0,barHeight -4,hiddenCanvas.width, 4);
+
+ context.fillStyle = "#fff";
+ context.textBaseline = "top";
+ context.font = '12px sans-serif';
+ context.fillText(text, textPadding, 1);
+
+ return barHeight;
+ }
+
+ function normalise(img, w, h){
+ var c;
+ var context;
+
+ if(img.height < h || img.width < w){
+ c = document.createElement('canvas');
+ c.width = w;
+ c.height = h;
+ context = c.getContext('2d');
+ context.putImageData(img, 0, 0);
+ return context.getImageData(0, 0, w, h);
+ }
+
+ return img;
+ }
+
+ function compare(one, two){
+
+ function onceWeHaveBoth(){
+ var width;
+ var height;
+ if(images.length === 2){
+ width = images[0].width > images[1].width ? images[0].width : images[1].width;
+ height = images[0].height > images[1].height ? images[0].height : images[1].height;
+
+ if( (images[0].width === images[1].width) && (images[0].height === images[1].height) ){
+ data.isSameDimensions = true;
+ } else {
+ data.isSameDimensions = false;
+ }
+
+ analyseImages( normalise(images[0],width, height), normalise(images[1],width, height), width, height);
+
+ triggerDataUpdate();
+ }
+ }
+
+ images = [];
+ loadImageData(one, onceWeHaveBoth);
+ loadImageData(two, onceWeHaveBoth);
+ }
+
+ function getCompareApi(param){
+
+ var secondFileData,
+ hasMethod = typeof param === 'function';
+
+ if( !hasMethod ){
+ // assume it's file data
+ secondFileData = param;
+ }
+
+ var self = {
+ ignoreNothing: function(){
+
+ tolerance.red = 16;
+ tolerance.green = 16;
+ tolerance.blue = 16;
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreAntialiasing: function(){
+
+ tolerance.red = 32;
+ tolerance.green = 32;
+ tolerance.blue = 32;
+ tolerance.minBrightness = 64;
+ tolerance.maxBrightness = 96;
+
+ ignoreAntialiasing = true;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreColors: function(){
+
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = true;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ onComplete: function( callback ){
+
+ updateCallbackArray.push(callback);
+
+ var wrapper = function(){
+ compare(fileData, secondFileData);
+ };
+
+ wrapper();
+
+ return getCompareApi(wrapper);
+ }
+ };
+
+ return self;
+ }
+
+ return {
+ onComplete: function( callback ){
+ updateCallbackArray.push(callback);
+ loadImageData(fileData, function(imageData, width, height){
+ parseImage(imageData.data, width, height);
+ });
+ },
+ compareTo: function(secondFileData){
+ return getCompareApi(secondFileData);
+ }
+ };
+
+ };
+}(this));
\ No newline at end of file
diff --git a/test/testsuite.js b/test/testsuite.js
deleted file mode 100644
index b486acb..0000000
--- a/test/testsuite.js
+++ /dev/null
@@ -1,36 +0,0 @@
-requirejs.config({
- baseUrl: '/test/unit/'
-});
-
-define(function(require) {
- var testModules = [
- 'Pixi',
- 'Point',
- 'Rectangle',
- 'DisplayObject',
- 'DisplayObjectContainer',
- 'Sprite',
- 'MovieClip',
- 'InteractionManager',
- 'Stage',
- 'utils/Utils',
- 'utils/EventTarget',
- 'utils/Matrix',
- 'utils/Detector',
- 'renderers/WebGLShaders',
- 'renderers/WebGLRenderer',
- 'renderers/WebGLBatch',
- 'renderers/CanvasRenderer',
- 'extras/Strip',
- 'extras/Rope',
- 'textures/BaseTexture',
- 'textures/Texture',
- 'loaders/SpriteSheetLoader',
- 'loaders/AssetLoader'
- ];
-
- // Resolve all testModules and then start the Test Runner.
- require(testModules, function() {
- QUnit.start();
- });
-});
\ No newline at end of file
diff --git a/test/textures/SpriteSheet-Aliens.png b/test/textures/SpriteSheet-Aliens.png
new file mode 100644
index 0000000..210acb1
--- /dev/null
+++ b/test/textures/SpriteSheet-Aliens.png
Binary files differ
diff --git a/test/textures/SpriteSheet-Explosion.png b/test/textures/SpriteSheet-Explosion.png
new file mode 100755
index 0000000..79e1a69
--- /dev/null
+++ b/test/textures/SpriteSheet-Explosion.png
Binary files differ
diff --git a/test/textures/bunny.png b/test/textures/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/textures/bunny.png
Binary files differ
diff --git a/test/unit/DisplayObject.js b/test/unit/DisplayObject.js
deleted file mode 100644
index 5e7e72f..0000000
--- a/test/unit/DisplayObject.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObject');
-});
diff --git a/test/unit/DisplayObjectContainer.js b/test/unit/DisplayObjectContainer.js
deleted file mode 100644
index b323959..0000000
--- a/test/unit/DisplayObjectContainer.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObjectContainer');
-});
diff --git a/test/unit/InteractionManager.js b/test/unit/InteractionManager.js
deleted file mode 100644
index e751f52..0000000
--- a/test/unit/InteractionManager.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('InteractionManager');
-});
diff --git a/test/unit/MovieClip.js b/test/unit/MovieClip.js
deleted file mode 100644
index 37d9446..0000000
--- a/test/unit/MovieClip.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('MovieClip');
-});
diff --git a/test/unit/Pixi.js b/test/unit/Pixi.js
deleted file mode 100644
index 36eee73..0000000
--- a/test/unit/Pixi.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Pixi');
-});
diff --git a/test/unit/Point.js b/test/unit/Point.js
deleted file mode 100644
index 983ff6e..0000000
--- a/test/unit/Point.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Point');
-});
diff --git a/test/unit/Rectangle.js b/test/unit/Rectangle.js
deleted file mode 100644
index 3b439ba..0000000
--- a/test/unit/Rectangle.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Rectangle');
-});
diff --git a/test/unit/Sprite.js b/test/unit/Sprite.js
deleted file mode 100644
index ed4f596..0000000
--- a/test/unit/Sprite.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Sprite');
-});
diff --git a/test/unit/Stage.js b/test/unit/Stage.js
deleted file mode 100644
index 2d70291..0000000
--- a/test/unit/Stage.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Stage');
-});
diff --git a/test/unit/extras/Rope.js b/test/unit/extras/Rope.js
deleted file mode 100644
index 5606f14..0000000
--- a/test/unit/extras/Rope.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Rope');
-});
diff --git a/test/unit/extras/Strip.js b/test/unit/extras/Strip.js
deleted file mode 100644
index 0134d3a..0000000
--- a/test/unit/extras/Strip.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Strip');
-});
diff --git a/test/unit/loaders/AssetLoader.js b/test/unit/loaders/AssetLoader.js
deleted file mode 100644
index 13b8443..0000000
--- a/test/unit/loaders/AssetLoader.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('AssetLoader');
-});
diff --git a/test/unit/loaders/SpriteSheetLoader.js b/test/unit/loaders/SpriteSheetLoader.js
deleted file mode 100644
index 8bf0cb2..0000000
--- a/test/unit/loaders/SpriteSheetLoader.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('SpriteSheetLoader');
-});
diff --git a/test/unit/pixi/InteractionManager.js b/test/unit/pixi/InteractionManager.js
new file mode 100644
index 0000000..ed3001f
--- /dev/null
+++ b/test/unit/pixi/InteractionManager.js
@@ -0,0 +1,10 @@
+describe('pixi/InteractionManager', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var InteractionManager = PIXI.InteractionManager;
+
+ it('Module exists', function () {
+ expect(InteractionManager).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/Pixi.js b/test/unit/pixi/Pixi.js
new file mode 100644
index 0000000..27debc1
--- /dev/null
+++ b/test/unit/pixi/Pixi.js
@@ -0,0 +1,9 @@
+describe('pixi/Pixi', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+
+ it('Module exists', function () {
+ expect(global).to.have.property('PIXI').and.to.be.an('object');
+ });
+});
diff --git a/test/unit/pixi/core/Circle.js b/test/unit/pixi/core/Circle.js
new file mode 100644
index 0000000..93a4456
--- /dev/null
+++ b/test/unit/pixi/core/Circle.js
@@ -0,0 +1,22 @@
+describe('pixi/core/Circle', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Circle = PIXI.Circle;
+
+ it('Module exists', function () {
+ expect(Circle).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Circle();
+
+ expect(obj).to.be.an.instanceof(Circle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', 0);
+ expect(obj).to.have.property('y', 0);
+ expect(obj).to.have.property('radius', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Ellipse.js b/test/unit/pixi/core/Ellipse.js
new file mode 100644
index 0000000..026b56f
--- /dev/null
+++ b/test/unit/pixi/core/Ellipse.js
@@ -0,0 +1,24 @@
+describe('pixi/core/Ellipse', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Ellipse = PIXI.Ellipse;
+
+ it('Module exists', function () {
+ expect(Ellipse).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Ellipse();
+
+ expect(obj).to.be.an.instanceof(Ellipse);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+ expect(obj).to.respondTo('getBounds');
+
+ expect(obj).to.have.property('x', 0);
+ expect(obj).to.have.property('y', 0);
+ expect(obj).to.have.property('width', 0);
+ expect(obj).to.have.property('height', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Matrix.js b/test/unit/pixi/core/Matrix.js
new file mode 100644
index 0000000..b48989e
--- /dev/null
+++ b/test/unit/pixi/core/Matrix.js
@@ -0,0 +1,30 @@
+describe('pixi/core/Matrix', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var mat3 = PIXI.mat3;
+ var mat4 = PIXI.mat4;
+ var Matrix = PIXI.Matrix;
+
+ it('Ensure determineMatrixArrayType works', function () {
+ expect(Matrix).to.be.a('function');
+ });
+
+ it('mat3 exists', function () {
+ expect(mat3).to.be.an('object');
+ });
+
+ it('Confirm new mat3 matrix', function () {
+ var matrix = new mat3.create();
+ pixi_core_Matrix_confirmNewMat3(matrix);
+ });
+
+ it('mat3 exists', function () {
+ expect(mat4).to.be.an('object');
+ });
+
+ it('Confirm new mat4 matrix', function () {
+ var matrix = new mat4.create();
+ pixi_core_Matrix_confirmNewMat4(matrix);
+ });
+});
diff --git a/test/unit/pixi/core/Point.js b/test/unit/pixi/core/Point.js
new file mode 100644
index 0000000..c4d5163
--- /dev/null
+++ b/test/unit/pixi/core/Point.js
@@ -0,0 +1,15 @@
+describe('pixi/core/Point', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Point = PIXI.Point;
+
+ it('Module exists', function () {
+ expect(Point).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Point();
+ pixi_core_Point_confirm(obj, 0, 0);
+ });
+});
diff --git a/test/unit/pixi/core/Polygon.js b/test/unit/pixi/core/Polygon.js
new file mode 100644
index 0000000..dc8c918
--- /dev/null
+++ b/test/unit/pixi/core/Polygon.js
@@ -0,0 +1,20 @@
+describe('pixi/core/Polygon', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Polygon = PIXI.Polygon;
+
+ it('Module exists', function () {
+ expect(Polygon).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Polygon();
+
+ expect(obj).to.be.an.instanceof(Polygon);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.deep.property('points.length', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Rectangle.js b/test/unit/pixi/core/Rectangle.js
new file mode 100644
index 0000000..d43316e
--- /dev/null
+++ b/test/unit/pixi/core/Rectangle.js
@@ -0,0 +1,15 @@
+describe('pixi/core/Rectangle', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Rectangle = PIXI.Rectangle;
+
+ it('Module exists', function () {
+ expect(Rectangle).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var rect = new Rectangle();
+ pixi_core_Rectangle_confirm(rect, 0, 0, 0, 0);
+ });
+});
diff --git a/test/unit/pixi/display/DisplayObject.js b/test/unit/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..40c6fbc
--- /dev/null
+++ b/test/unit/pixi/display/DisplayObject.js
@@ -0,0 +1,21 @@
+describe('pixi/display/DisplayObject', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var DisplayObject = PIXI.DisplayObject;
+
+ it('Module exists', function () {
+ expect(DisplayObject).to.be.a('function');
+ expect(PIXI).to.have.property('visibleCount', 0);
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new DisplayObject();
+
+ pixi_display_DisplayObject_confirmNew(obj);
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', false);
+ expect(obj).to.have.property('stage', null);
+ });
+});
diff --git a/test/unit/pixi/display/DisplayObjectContainer.js b/test/unit/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..ce7f02f
--- /dev/null
+++ b/test/unit/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,20 @@
+describe('pixi/display/DisplayObjectContainer', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var DisplayObjectContainer = PIXI.DisplayObjectContainer;
+
+ it('Module exists', function () {
+ expect(DisplayObjectContainer).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new DisplayObjectContainer();
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', false);
+ expect(obj).to.have.property('stage', null);
+ });
+});
diff --git a/test/unit/pixi/display/MovieClip.js b/test/unit/pixi/display/MovieClip.js
new file mode 100644
index 0000000..f3c6c6a
--- /dev/null
+++ b/test/unit/pixi/display/MovieClip.js
@@ -0,0 +1,33 @@
+describe('pixi/display/MovieClip', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var MovieClip = PIXI.MovieClip;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(MovieClip).to.be.a('function');
+ });
+
+ it('Confirm new instance', function (done) {
+ var texture = Texture.fromImage('/base/test/textures/SpriteSheet-Explosion.png');
+ var obj = new MovieClip([texture]);
+
+ pixi_display_Sprite_confirmNew(obj, done);
+
+ expect(obj).to.be.an.instanceof(MovieClip);
+ expect(obj).to.respondTo('stop');
+ expect(obj).to.respondTo('play');
+ expect(obj).to.respondTo('gotoAndStop');
+ expect(obj).to.respondTo('gotoAndPlay');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('textures.length', 1);
+ expect(obj).to.have.deep.property('textures[0]', texture);
+ expect(obj).to.have.property('animationSpeed', 1);
+ expect(obj).to.have.property('loop', true);
+ expect(obj).to.have.property('onComplete', null);
+ expect(obj).to.have.property('currentFrame', 0);
+ expect(obj).to.have.property('playing', false);
+ });
+});
diff --git a/test/unit/pixi/display/Sprite.js b/test/unit/pixi/display/Sprite.js
new file mode 100644
index 0000000..54e914f
--- /dev/null
+++ b/test/unit/pixi/display/Sprite.js
@@ -0,0 +1,25 @@
+describe('pixi/display/Sprite', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Sprite = PIXI.Sprite;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(Sprite).to.be.a('function');
+ expect(PIXI).to.have.deep.property('blendModes.NORMAL', 0);
+ expect(PIXI).to.have.deep.property('blendModes.SCREEN', 1);
+ });
+
+ it('Members exist', function () {
+ expect(Sprite).itself.to.respondTo('fromImage');
+ expect(Sprite).itself.to.respondTo('fromFrame');
+ });
+
+ it('Confirm new instance', function (done) {
+ var texture = Texture.fromImage('/base/test/textures/SpriteSheet-Aliens.png');
+ var obj = new Sprite(texture);
+
+ pixi_display_Sprite_confirmNew(obj, done);
+ });
+});
diff --git a/test/unit/pixi/display/Stage.js b/test/unit/pixi/display/Stage.js
new file mode 100644
index 0000000..3cc2a4d
--- /dev/null
+++ b/test/unit/pixi/display/Stage.js
@@ -0,0 +1,49 @@
+describe('pixi/display/Stage', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Stage = PIXI.Stage;
+ var InteractionManager = PIXI.InteractionManager;
+ var Rectangle = PIXI.Rectangle;
+
+ it('Module exists', function () {
+ expect(Stage).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Stage(null, true);
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(Stage);
+ expect(obj).to.respondTo('updateTransform');
+ expect(obj).to.respondTo('setBackgroundColor');
+ expect(obj).to.respondTo('getMousePosition');
+
+ // FIXME: duplicate member in DisplayObject
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ // FIXME: convert arg to bool in constructor
+ expect(obj).to.have.property('interactive', true);
+
+ expect(obj).to.have.property('interactionManager')
+ .and.to.be.an.instanceof(InteractionManager)
+ .and.to.have.property('stage', obj);
+
+ expect(obj).to.have.property('dirty', true);
+
+ expect(obj).to.have.property('stage', obj);
+
+ expect(obj).to.have.property('hitArea')
+ .and.to.be.an.instanceof(Rectangle);
+ pixi_core_Rectangle_confirm(obj.hitArea, 0, 0, 100000, 100000);
+
+ expect(obj).to.have.property('backgroundColor', 0x000000);
+ expect(obj).to.have.deep.property('backgroundColorSplit.length', 3);
+ expect(obj).to.have.deep.property('backgroundColorSplit[0]', 0);
+ expect(obj).to.have.deep.property('backgroundColorSplit[1]', 0);
+ expect(obj).to.have.deep.property('backgroundColorSplit[2]', 0);
+ expect(obj).to.have.property('backgroundColorString', '#000000');
+
+ expect(obj).to.have.property('worldVisible', true);
+ });
+});
diff --git a/test/unit/pixi/extras/CustomRenderable.js b/test/unit/pixi/extras/CustomRenderable.js
new file mode 100644
index 0000000..8d83cf0
--- /dev/null
+++ b/test/unit/pixi/extras/CustomRenderable.js
@@ -0,0 +1,21 @@
+describe('pixi/extras/CustomRenderable', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var CustomRenderable = PIXI.CustomRenderable;
+
+ it('Module exists', function () {
+ expect(CustomRenderable).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new CustomRenderable();
+
+ pixi_display_DisplayObject_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(CustomRenderable);
+ expect(obj).to.respondTo('renderCanvas');
+ expect(obj).to.respondTo('initWebGL');
+ expect(obj).to.respondTo('renderWebGL');
+ });
+});
diff --git a/test/unit/pixi/extras/Rope.js b/test/unit/pixi/extras/Rope.js
new file mode 100644
index 0000000..6ddaf83
--- /dev/null
+++ b/test/unit/pixi/extras/Rope.js
@@ -0,0 +1,26 @@
+describe('pixi/extras/Rope', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Rope = PIXI.Rope;
+ var Texture = PIXI.Texture;
+ var Point = PIXI.Point;
+
+ it('Module exists', function () {
+ expect(Rope).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var texture = Texture.fromImage('/base/test/textures/bunny.png');
+ var obj = new Rope(texture, [new Point(), new Point(5, 10), new Point(10, 20)]);
+
+ pixi_extras_Strip_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(Rope);
+ expect(obj).to.respondTo('refresh');
+ expect(obj).to.respondTo('updateTransform');
+ expect(obj).to.respondTo('setTexture');
+
+ // TODO: Test properties
+ });
+});
diff --git a/test/unit/pixi/extras/Spine.js b/test/unit/pixi/extras/Spine.js
new file mode 100644
index 0000000..0708bc0
--- /dev/null
+++ b/test/unit/pixi/extras/Spine.js
@@ -0,0 +1,10 @@
+describe('pixi/extras/Spine', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Spine = PIXI.Spine;
+
+ it('Module exists', function () {
+ expect(Spine).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/extras/Strip.js b/test/unit/pixi/extras/Strip.js
new file mode 100644
index 0000000..8e564e1
--- /dev/null
+++ b/test/unit/pixi/extras/Strip.js
@@ -0,0 +1,18 @@
+describe('pixi/extras/Strip', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Strip = PIXI.Strip;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(Strip).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var texture = Texture.fromImage('/base/test/textures/bunny.png');
+ var obj = new Strip(texture, 20, 10000);
+
+ pixi_extras_Strip_confirmNew(obj);
+ });
+});
diff --git a/test/unit/pixi/extras/TilingSprite.js b/test/unit/pixi/extras/TilingSprite.js
new file mode 100644
index 0000000..56aea14
--- /dev/null
+++ b/test/unit/pixi/extras/TilingSprite.js
@@ -0,0 +1,24 @@
+describe('pixi/extras/TilingSprite', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var TilingSprite = PIXI.TilingSprite;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(TilingSprite).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var texture = Texture.fromImage('/base/test/textures/bunny.png');
+ var obj = new TilingSprite(texture, 6000, 12000);
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(TilingSprite);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ // TODO: Test properties
+ });
+});
diff --git a/test/unit/pixi/filters/FilterBlock.js b/test/unit/pixi/filters/FilterBlock.js
new file mode 100644
index 0000000..870cec0
--- /dev/null
+++ b/test/unit/pixi/filters/FilterBlock.js
@@ -0,0 +1,10 @@
+describe('pixi/filters/FilterBlock', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var FilterBlock = PIXI.FilterBlock;
+
+ it('Module exists', function () {
+ expect(FilterBlock).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/filters/MaskFilter.js b/test/unit/pixi/filters/MaskFilter.js
new file mode 100644
index 0000000..32d6a45
--- /dev/null
+++ b/test/unit/pixi/filters/MaskFilter.js
@@ -0,0 +1,10 @@
+describe('pixi/filters/MaskFilter', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ // var MaskFilter = PIXI.MaskFilter;
+
+ // it('Module exists', function () {
+ // expect(MaskFilter).to.be.a('function');
+ // });
+});
diff --git a/test/unit/pixi/loaders/AssetLoader.js b/test/unit/pixi/loaders/AssetLoader.js
new file mode 100644
index 0000000..a0aa0b5
--- /dev/null
+++ b/test/unit/pixi/loaders/AssetLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/AssetLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var AssetLoader = PIXI.AssetLoader;
+
+ it('Module exists', function () {
+ expect(AssetLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/BitmapFontLoader.js b/test/unit/pixi/loaders/BitmapFontLoader.js
new file mode 100644
index 0000000..6253c42
--- /dev/null
+++ b/test/unit/pixi/loaders/BitmapFontLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/BitmapFontLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var BitmapFontLoader = PIXI.BitmapFontLoader;
+
+ it('Module exists', function () {
+ expect(PIXI.BitmapFontLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/ImageLoader.js b/test/unit/pixi/loaders/ImageLoader.js
new file mode 100644
index 0000000..8b1f556
--- /dev/null
+++ b/test/unit/pixi/loaders/ImageLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/ImageLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var ImageLoader = PIXI.ImageLoader;
+
+ it('Module exists', function () {
+ expect(ImageLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/JsonLoader.js b/test/unit/pixi/loaders/JsonLoader.js
new file mode 100644
index 0000000..c577e83
--- /dev/null
+++ b/test/unit/pixi/loaders/JsonLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/JsonLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var JsonLoader = PIXI.JsonLoader;
+
+ it('Module exists', function () {
+ expect(JsonLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/SpineLoader.js b/test/unit/pixi/loaders/SpineLoader.js
new file mode 100644
index 0000000..fdcc0b8
--- /dev/null
+++ b/test/unit/pixi/loaders/SpineLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/SpineLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var SpineLoader = PIXI.SpineLoader;
+
+ it('Module exists', function () {
+ expect(SpineLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/SpriteSheetLoader.js b/test/unit/pixi/loaders/SpriteSheetLoader.js
new file mode 100644
index 0000000..57beb27
--- /dev/null
+++ b/test/unit/pixi/loaders/SpriteSheetLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/SpriteSheetLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var SpriteSheetLoader = PIXI.SpriteSheetLoader;
+
+ it('Module exists', function () {
+ expect(SpriteSheetLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/primitives/Graphics.js b/test/unit/pixi/primitives/Graphics.js
new file mode 100644
index 0000000..b8b3e5c
--- /dev/null
+++ b/test/unit/pixi/primitives/Graphics.js
@@ -0,0 +1,40 @@
+describe('pixi/primitives/Graphics', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Graphics = PIXI.Graphics;
+
+ it('Module exists', function () {
+ expect(Graphics).to.be.a('function');
+
+ expect(Graphics).itself.to.have.property('POLY', 0);
+ expect(Graphics).itself.to.have.property('RECT', 1);
+ expect(Graphics).itself.to.have.property('CIRC', 2);
+ expect(Graphics).itself.to.have.property('ELIP', 3);
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Graphics();
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(Graphics);
+ expect(obj).to.respondTo('lineStyle');
+ expect(obj).to.respondTo('lineStyle');
+ expect(obj).to.respondTo('moveTo');
+ expect(obj).to.respondTo('lineTo');
+ expect(obj).to.respondTo('beginFill');
+ expect(obj).to.respondTo('endFill');
+ expect(obj).to.respondTo('drawRect');
+ expect(obj).to.respondTo('drawCircle');
+ expect(obj).to.respondTo('drawElipse');
+ expect(obj).to.respondTo('clear');
+
+ expect(obj).to.have.property('renderable', true);
+ expect(obj).to.have.property('fillAlpha', 1);
+ expect(obj).to.have.property('lineWidth', 0);
+ expect(obj).to.have.property('lineColor', 'black');
+ expect(obj).to.have.deep.property('graphicsData.length', 0);
+ expect(obj).to.have.deep.property('currentPath.points.length', 0);
+ });
+});
diff --git a/test/unit/pixi/renderers/canvas/CanvasGraphics.js b/test/unit/pixi/renderers/canvas/CanvasGraphics.js
new file mode 100644
index 0000000..8f44472
--- /dev/null
+++ b/test/unit/pixi/renderers/canvas/CanvasGraphics.js
@@ -0,0 +1,15 @@
+describe('renders/canvas/CanvasGraphics', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var CanvasGraphics = PIXI.CanvasGraphics;
+
+ it('Module exists', function () {
+ expect(CanvasGraphics).to.be.a('function');
+ });
+
+ it('Members exist', function () {
+ expect(CanvasGraphics).itself.to.respondTo('renderGraphics');
+ expect(CanvasGraphics).itself.to.respondTo('renderGraphicsMask');
+ });
+});
diff --git a/test/unit/pixi/renderers/canvas/CanvasRenderer.js b/test/unit/pixi/renderers/canvas/CanvasRenderer.js
new file mode 100644
index 0000000..df3a12f
--- /dev/null
+++ b/test/unit/pixi/renderers/canvas/CanvasRenderer.js
@@ -0,0 +1,10 @@
+describe('renderers/canvas/CanvasRenderer', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var CanvasRenderer = PIXI.CanvasRenderer;
+
+ it('Module exists', function () {
+ expect(CanvasRenderer).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/renderers/webgl/WebGLBatch.js b/test/unit/pixi/renderers/webgl/WebGLBatch.js
new file mode 100644
index 0000000..75efd56
--- /dev/null
+++ b/test/unit/pixi/renderers/webgl/WebGLBatch.js
@@ -0,0 +1,10 @@
+describe('renderers/webgl/WebGLBatch', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var WebGLBatch = PIXI.WebGLBatch;
+
+ it('Module exists', function () {
+ expect(WebGLBatch).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/renderers/webgl/WebGLGraphics.js b/test/unit/pixi/renderers/webgl/WebGLGraphics.js
new file mode 100644
index 0000000..41bf941
--- /dev/null
+++ b/test/unit/pixi/renderers/webgl/WebGLGraphics.js
@@ -0,0 +1,19 @@
+describe('renderers/wegbl/WebGLGraphics', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var WebGLGraphics = PIXI.WebGLGraphics;
+
+ it('Module exists', function () {
+ expect(WebGLGraphics).to.be.a('function');
+ });
+
+ it('Members exist', function () {
+ expect(WebGLGraphics).itself.to.respondTo('renderGraphics');
+ expect(WebGLGraphics).itself.to.respondTo('updateGraphics');
+ expect(WebGLGraphics).itself.to.respondTo('buildRectangle');
+ expect(WebGLGraphics).itself.to.respondTo('buildCircle');
+ expect(WebGLGraphics).itself.to.respondTo('buildLine');
+ expect(WebGLGraphics).itself.to.respondTo('buildPoly');
+ });
+});
diff --git a/.gitignore b/.gitignore
index 12e1b62..0b88317 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
node_modules
.DS_Store
-.project
\ No newline at end of file
+.project
+*.log
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..63e4d7c
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,8 @@
+language: node_js
+node_js:
+ - 0.10
+
+before_script:
+ - npm install -g grunt-cli
+ - export DISPLAY=:99.0
+ - sh -e /etc/init.d/xvfb start
diff --git a/Gruntfile.js b/Gruntfile.js
index b083b49..103938c 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -1,10 +1,12 @@
+'use strict';
+
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-connect');
- grunt.loadNpmTasks('grunt-contrib-qunit');
grunt.loadNpmTasks('grunt-contrib-yuidoc');
+ grunt.loadTasks('tasks');
var root = 'src/pixi/',
debug = 'bin/pixi.dev.js',
@@ -79,7 +81,7 @@
},
files: {
srcBlob: '<%= dirs.src %>/**/*.js',
- testBlob: '<%= dirs.test %>/unit/**/*.js',
+ testBlob: '<%= dirs.test %>/{functional,lib/pixi,unit}/**/*.js',
build: '<%= dirs.build %>/pixi.dev.js',
buildMin: '<%= dirs.build %>/pixi.js'
},
@@ -94,7 +96,12 @@
},
jshint: {
beforeconcat: srcFiles,
- test: ['<%= files.testBlob %>'],
+ test: {
+ src: ['<%= files.testBlob %>'],
+ options: {
+ expr: true
+ }
+ },
options: {
asi: true,
smarttabs: true
@@ -128,12 +135,6 @@
]
},
connect: {
- qunit: {
- options: {
- port: grunt.option('port-test') || 9002,
- base: './'
- }
- },
test: {
options: {
port: grunt.option('port-test') || 9002,
@@ -142,13 +143,6 @@
}
}
},
- qunit: {
- all: {
- options: {
- urls: ['http://localhost:' + (grunt.option('port-test') || 9002) + '/test/index.html']
- }
- }
- },
yuidoc: {
compile: {
name: '<%= pkg.name %>',
@@ -161,6 +155,13 @@
outdir: '<%= dirs.docs %>'
}
}
+ },
+ karma: {
+ unit: {
+ configFile: 'test/karma.conf.js',
+ // browsers: ['Chrome'],
+ singleRun: true
+ }
}
});
@@ -182,9 +183,10 @@
}
)
- grunt.registerTask('default', ['concat', 'uglify', 'distribute']);
grunt.registerTask('build', ['concat', 'uglify', 'distribute']);
- grunt.registerTask('test', ['build', 'connect:qunit', 'qunit']);
+ grunt.registerTask('test', ['concat', 'jshint:test', 'karma']);
grunt.registerTask('docs', ['yuidoc']);
-
-}
\ No newline at end of file
+ grunt.registerTask('default', ['test', 'uglify', 'distribute']);
+ // Travis CI task.
+ grunt.registerTask('travis', ['test']);
+}
diff --git a/README.md b/README.md
index c62ef86..690cfe4 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,8 @@

+[](http://travis-ci.org/drkibitz/pixi.js)
+
#### JavaScript 2D Renderer ####
The aim of this project is to provide a fast lightweight 2D library that works
diff --git a/package.json b/package.json
index b373240..1246a68 100644
--- a/package.json
+++ b/package.json
@@ -18,14 +18,21 @@
"main": "bin/pixi.js",
+ "scripts": {
+ "test": "grunt travis --verbose"
+ },
+
"dependencies": {},
"devDependencies": {
"grunt": "~0.4.x",
- "grunt-contrib-jshint": "0.3.x",
+ "grunt-contrib-jshint": "0.6.x",
"grunt-contrib-uglify": "0.2.x",
- "grunt-contrib-connect": "0.2.x",
- "grunt-contrib-qunit": "0.2.x",
+ "grunt-contrib-connect": "0.3.x",
"grunt-contrib-yuidoc": "0.4.x",
- "grunt-contrib-concat": "0.1.x"
+ "grunt-contrib-concat": "0.3.x",
+ "chai": "~1.7.0",
+ "karma": "0.11.0",
+ "karma-firefox-launcher": "0.1.0",
+ "karma-mocha": "0.1.0"
}
}
diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js
index a7c520e..ee82bbd 100644
--- a/src/pixi/InteractionManager.js
+++ b/src/pixi/InteractionManager.js
@@ -62,7 +62,6 @@
this.onTouchEnd = this.onTouchEnd.bind(this);
this.onTouchMove = this.onTouchMove.bind(this);
-
this.last = 0;
}
diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js
index 1a95d20..eef1059 100644
--- a/src/pixi/core/Ellipse.js
+++ b/src/pixi/core/Ellipse.js
@@ -78,7 +78,7 @@
return (normx + normy < 0.25);
}
-PIXI.Ellipse.getBounds = function()
+PIXI.Ellipse.prototype.getBounds = function()
{
return new PIXI.Rectangle(this.x, this.y, this.width, this.height);
}
diff --git a/tasks/karma.js b/tasks/karma.js
new file mode 100644
index 0000000..c340485
--- /dev/null
+++ b/tasks/karma.js
@@ -0,0 +1,27 @@
+'use strict';
+
+var path = require('path');
+var server = require('karma').server;
+
+module.exports = function (grunt) {
+ grunt.registerMultiTask('karma', 'run karma.', function() {
+ var done = this.async();
+ var options = this.options({
+ background: false
+ });
+ var data = this.data;
+
+ //merge options onto data, with data taking precedence
+ data = grunt.util._.merge(options, data);
+ data.configFile = path.resolve(data.configFile);
+ if (data.configFile) {
+ data.configFile = grunt.template.process(data.configFile);
+ }
+
+ server.start(
+ data,
+ function(code) {
+ done(!code);
+ });
+ });
+};
diff --git a/test/functional/example-1-basics/bunny.png b/test/functional/example-1-basics/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/functional/example-1-basics/bunny.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-30.png b/test/functional/example-1-basics/frame-30.png
new file mode 100644
index 0000000..96e3409
--- /dev/null
+++ b/test/functional/example-1-basics/frame-30.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-60.png b/test/functional/example-1-basics/frame-60.png
new file mode 100644
index 0000000..af3f4ce
--- /dev/null
+++ b/test/functional/example-1-basics/frame-60.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-90.png b/test/functional/example-1-basics/frame-90.png
new file mode 100644
index 0000000..099b823
--- /dev/null
+++ b/test/functional/example-1-basics/frame-90.png
Binary files differ
diff --git a/test/functional/example-1-basics/index.js b/test/functional/example-1-basics/index.js
new file mode 100644
index 0000000..7ae7a98
--- /dev/null
+++ b/test/functional/example-1-basics/index.js
@@ -0,0 +1,133 @@
+describe('Example 1 - Basics', function () {
+ 'use strict';
+
+ var baseUri = '/base/test/functional/example-1-basics';
+ var expect = chai.expect;
+ var currentFrame = 0;
+ var frameEvents = {};
+ var stage;
+ var renderer;
+ var bunny;
+
+ function onFrame(frame, callback) {
+ frameEvents[frame] = callback;
+ }
+
+ function animate() {
+ currentFrame += 1;
+
+ requestAnimFrame( animate );
+
+ // just for fun, lets rotate mr rabbit a little
+ bunny.rotation += 0.1;
+
+ // render the stage
+ renderer.render(stage);
+
+ if (frameEvents[currentFrame])
+ frameEvents[currentFrame](currentFrame);
+ }
+
+ function initScene() {
+ // create an new instance of a pixi stage
+ stage = new PIXI.Stage(0x66FF99);
+
+ // create a renderer instance
+ renderer = PIXI.autoDetectRenderer(400, 300);
+ console.log('Is PIXI.WebGLRenderer: ' + (renderer instanceof PIXI.WebGLRenderer));
+
+ // add the renderer view element to the DOM
+ document.body.appendChild(renderer.view);
+
+ requestAnimFrame( animate );
+
+ // create a texture from an image path
+ var texture = PIXI.Texture.fromImage(baseUri + "/bunny.png");
+ // create a new Sprite using the texture
+ bunny = new PIXI.Sprite(texture);
+
+ // center the sprites anchor point
+ bunny.anchor.x = 0.5;
+ bunny.anchor.y = 0.5;
+
+ // move the sprite t the center of the screen
+ bunny.position.x = 200;
+ bunny.position.y = 150;
+
+ stage.addChild(bunny);
+ }
+
+ it('assets loaded', function (done) {
+ var loader = new PIXI.AssetLoader([
+ baseUri + '/bunny.png',
+ baseUri + '/frame-30.png',
+ baseUri + '/frame-60.png',
+ baseUri + '/frame-90.png'
+ ]);
+ // loader.on('onProgress', function (event) {
+ // console.log(event.content);
+ // });
+ loader.on('onComplete', function (event) {
+ done();
+ initScene();
+ });
+ loader.load();
+ });
+
+ it('frame 30 should match', function (done) {
+ this.timeout(700);
+ onFrame(30, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-30.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 60 should match', function (done) {
+ this.timeout(1200);
+ onFrame(60, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-60.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 90 should match', function (done) {
+ this.timeout(1700);
+ onFrame(90, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-90.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ // it('capture something', function (done) {
+ // this.timeout(2000000);
+ // onFrame(30, function () {
+ // var img = new Image();
+ // img.src = renderer.view.toDataURL('image/png');
+ // document.body.appendChild(img);
+ // });
+ // });
+});
diff --git a/test/index.html b/test/index.html
deleted file mode 100644
index 9cbcac5..0000000
--- a/test/index.html
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
- Pixi.js Test Suite
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/test/karma.conf.js b/test/karma.conf.js
new file mode 100644
index 0000000..c66a696
--- /dev/null
+++ b/test/karma.conf.js
@@ -0,0 +1,82 @@
+module.exports = function(config) {
+ config.set({
+
+ // base path, that will be used to resolve files and exclude
+ basePath : '../',
+
+ frameworks : ['mocha'],
+
+ // list of files / patterns to load in the browser
+ files : [
+ 'node_modules/chai/chai.js',
+ 'bin/pixi.dev.js',
+ 'test/lib/**/*.js',
+ 'test/unit/**/*.js',
+ // 'test/functional/**/*.js',
+ {pattern: 'test/**/*.png', watched: false, included: false, served: true}
+ ],
+
+ // list of files to exclude
+ exclude : [],
+
+ // use dolts reporter, as travis terminal does not support escaping sequences
+ // possible values: 'dots', 'progress', 'junit', 'teamcity'
+ // CLI --reporters progress
+ reporters : ['progress'],
+
+ // web server port
+ // CLI --port 9876
+ port : 9876,
+
+ // cli runner port
+ // CLI --runner-port 9100
+ runnerPort : 9100,
+
+ // enable / disable colors in the output (reporters and logs)
+ // CLI --colors --no-colors
+ colors : true,
+
+ // level of logging
+ // possible values: karma.LOG_DISABLE || karma.LOG_ERROR || karma.LOG_WARN || karma.LOG_INFO || karma.LOG_DEBUG
+ // CLI --log-level debug
+ logLevel : config.LOG_DEBUG,
+
+ // enable / disable watching file and executing tests whenever any file changes
+ // CLI --auto-watch --no-auto-watch
+ autoWatch : false,
+
+ // Start these browsers, currently available:
+ // - Chrome
+ // - ChromeCanary
+ // - Firefox
+ // - Opera
+ // - Safari (only Mac)
+ // - PhantomJS
+ // - IE (only Windows)
+ // CLI --browsers Chrome,Firefox,Safari
+ browsers : ['Firefox'],
+
+ // If browser does not capture in given timeout [ms], kill it
+ // CLI --capture-timeout 5000
+ captureTimeout : 5000,
+
+ // Auto run tests on start (when browsers are captured) and exit
+ // CLI --single-run --no-single-run
+ singleRun : true,
+
+ // report which specs are slower than 500ms
+ // CLI --report-slower-than 500
+ reportSlowerThan : 1000,
+
+ preprocessors : {
+ // '**/client/js/*.js': 'coverage'
+ },
+
+ plugins : [
+ 'karma-mocha',
+ // 'karma-chrome-launcher',
+ 'karma-firefox-launcher',
+ // 'karma-phantomjs-launcher'
+ ]
+ });
+};
diff --git a/test/lib/pixi/core/Matrix.js b/test/lib/pixi/core/Matrix.js
new file mode 100644
index 0000000..d26386b
--- /dev/null
+++ b/test/lib/pixi/core/Matrix.js
@@ -0,0 +1,40 @@
+
+function pixi_core_Matrix_confirmNewMat3(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(1);
+ expect(matrix[5]).to.equal(0);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(1);
+}
+
+function pixi_core_Matrix_confirmNewMat4(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[0]).to.equal(1);
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(0);
+ expect(matrix[5]).to.equal(1);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(0);
+ expect(matrix[9]).to.equal(0);
+ expect(matrix[10]).to.equal(1);
+ expect(matrix[11]).to.equal(0);
+ expect(matrix[12]).to.equal(0);
+ expect(matrix[13]).to.equal(0);
+ expect(matrix[14]).to.equal(0);
+ expect(matrix[15]).to.equal(1);
+}
diff --git a/test/lib/pixi/core/Point.js b/test/lib/pixi/core/Point.js
new file mode 100644
index 0000000..e5df07b
--- /dev/null
+++ b/test/lib/pixi/core/Point.js
@@ -0,0 +1,10 @@
+
+function pixi_core_Point_confirm(obj, x, y) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Point);
+ expect(obj).to.respondTo('clone');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+}
diff --git a/test/lib/pixi/core/Rectangle.js b/test/lib/pixi/core/Rectangle.js
new file mode 100644
index 0000000..23f0d12
--- /dev/null
+++ b/test/lib/pixi/core/Rectangle.js
@@ -0,0 +1,13 @@
+
+function pixi_core_Rectangle_confirm(obj, x, y, width, height) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Rectangle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+ expect(obj).to.have.property('width', width);
+ expect(obj).to.have.property('height', height);
+}
diff --git a/test/lib/pixi/display/DisplayObject.js b/test/lib/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..1388a7f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObject.js
@@ -0,0 +1,43 @@
+
+function pixi_display_DisplayObject_confirmNew(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObject);
+ expect(obj).to.respondTo('setInteractive');
+ expect(obj).to.respondTo('addFilter');
+ expect(obj).to.respondTo('removeFilter');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.property('last', obj);
+ expect(obj).to.have.property('first', obj);
+
+ expect(obj).to.contain.property('position');
+ pixi_core_Point_confirm(obj.position, 0, 0);
+ expect(obj).to.contain.property('scale');
+ pixi_core_Point_confirm(obj.scale, 1, 1);
+ expect(obj).to.contain.property('pivot');
+ pixi_core_Point_confirm(obj.pivot, 0, 0);
+
+ expect(obj).to.have.property('rotation', 0);
+ expect(obj).to.have.property('alpha', 1);
+ expect(obj).to.have.property('visible', true);
+ expect(obj).to.have.property('buttonMode', false);
+ expect(obj).to.have.property('parent', null);
+ expect(obj).to.have.property('worldAlpha', 1);
+
+ expect(obj).to.have.property('hitArea');
+ expect(obj).to.have.property('interactive'); // TODO: Have a better default value
+ expect('mask' in obj).to.be.true; // TODO: Have a better default value
+ expect(obj.mask).to.be.undefined;
+
+ expect(obj).to.have.property('renderable');
+ expect(obj).to.have.property('stage');
+
+ expect(obj).to.have.deep.property('worldTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ expect(obj).to.have.deep.property('localTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.localTransform);
+
+ expect(obj).to.have.deep.property('color.length', 0);
+ expect(obj).to.have.property('dynamic', true);
+}
diff --git a/test/lib/pixi/display/DisplayObjectContainer.js b/test/lib/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..085c59f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,16 @@
+
+function pixi_display_DisplayObjectContainer_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObject_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObjectContainer);
+ expect(obj).to.respondTo('addChild');
+ expect(obj).to.respondTo('addChildAt');
+ expect(obj).to.respondTo('swapChildren');
+ expect(obj).to.respondTo('getChildAt');
+ expect(obj).to.respondTo('removeChild');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('children.length', 0);
+}
diff --git a/test/lib/pixi/display/Sprite.js b/test/lib/pixi/display/Sprite.js
new file mode 100644
index 0000000..cc7a2d6
--- /dev/null
+++ b/test/lib/pixi/display/Sprite.js
@@ -0,0 +1,28 @@
+
+function pixi_display_Sprite_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Sprite);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', true);
+ expect(obj).to.have.property('stage', null);
+
+ expect(obj).to.have.property('anchor');
+ pixi_core_Point_confirm(obj.anchor, 0, 0);
+
+ expect(obj).to.have.property('blendMode', PIXI.blendModes.NORMAL);
+ expect(obj).to.have.property('width', 1); // TODO: is 1 expected
+ expect(obj).to.have.property('height', 1); // TODO: is 1 expected
+
+ // FIXME: Just make this a boolean that is always there
+ expect(!!obj.updateFrame).to.equal(obj.texture.baseTexture.hasLoaded);
+
+ expect(obj).to.have.property('texture');
+ pixi_textures_Texture_confirmNew(obj.texture, done);
+}
diff --git a/test/lib/pixi/extras/Strip.js b/test/lib/pixi/extras/Strip.js
new file mode 100644
index 0000000..8927a8a
--- /dev/null
+++ b/test/lib/pixi/extras/Strip.js
@@ -0,0 +1,12 @@
+
+function pixi_extras_Strip_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Strip);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ // TODO: Test properties
+}
diff --git a/test/lib/pixi/textures/Texture.js b/test/lib/pixi/textures/Texture.js
new file mode 100644
index 0000000..d5867b6
--- /dev/null
+++ b/test/lib/pixi/textures/Texture.js
@@ -0,0 +1,31 @@
+
+function pixi_textures_Texture_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ function confirmFrameDone() {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, obj.baseTexture.width, obj.baseTexture.height);
+
+ expect(obj).to.have.property('width', obj.baseTexture.width);
+ expect(obj).to.have.property('height', obj.baseTexture.height);
+ done();
+ }
+
+ expect(obj).to.be.an.instanceof(PIXI.Texture);
+ pixi_utils_EventTarget_like(obj);
+
+ expect(obj).to.have.property('baseTexture')
+ .and.to.be.an.instanceof(PIXI.BaseTexture);
+
+ expect(obj).to.have.property('scope', obj);
+
+ expect(obj).to.have.property('trim');
+ pixi_core_Point_confirm(obj.trim, 0, 0);
+
+ expect(obj).to.have.property('frame');
+ if (obj.baseTexture.hasLoaded) {
+ confirmFrameDone();
+ } else {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, 1, 1);
+ obj.addEventListener('update', confirmFrameDone);
+ }
+}
diff --git a/test/lib/pixi/utils/EventTarget.js b/test/lib/pixi/utils/EventTarget.js
new file mode 100644
index 0000000..7b1dcfa
--- /dev/null
+++ b/test/lib/pixi/utils/EventTarget.js
@@ -0,0 +1,8 @@
+
+function pixi_utils_EventTarget_like(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.respondTo('addEventListener');
+ expect(obj).to.respondTo('dispatchEvent');
+ expect(obj).to.respondTo('removeEventListener');
+}
diff --git a/test/lib/qunit-1.11.0.css b/test/lib/qunit-1.11.0.css
deleted file mode 100644
index d7fc0c8..0000000
--- a/test/lib/qunit-1.11.0.css
+++ /dev/null
@@ -1,244 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-/** Font Family and Sizes */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
- font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
-}
-
-#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
-#qunit-tests { font-size: smaller; }
-
-
-/** Resets */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter {
- margin: 0;
- padding: 0;
-}
-
-
-/** Header */
-
-#qunit-header {
- padding: 0.5em 0 0.5em 1em;
-
- color: #8699a4;
- background-color: #0d3349;
-
- font-size: 1.5em;
- line-height: 1em;
- font-weight: normal;
-
- border-radius: 5px 5px 0 0;
- -moz-border-radius: 5px 5px 0 0;
- -webkit-border-top-right-radius: 5px;
- -webkit-border-top-left-radius: 5px;
-}
-
-#qunit-header a {
- text-decoration: none;
- color: #c2ccd1;
-}
-
-#qunit-header a:hover,
-#qunit-header a:focus {
- color: #fff;
-}
-
-#qunit-testrunner-toolbar label {
- display: inline-block;
- padding: 0 .5em 0 .1em;
-}
-
-#qunit-banner {
- height: 5px;
-}
-
-#qunit-testrunner-toolbar {
- padding: 0.5em 0 0.5em 2em;
- color: #5E740B;
- background-color: #eee;
- overflow: hidden;
-}
-
-#qunit-userAgent {
- padding: 0.5em 0 0.5em 2.5em;
- background-color: #2b81af;
- color: #fff;
- text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
-}
-
-#qunit-modulefilter-container {
- float: right;
-}
-
-/** Tests: Pass/Fail */
-
-#qunit-tests {
- list-style-position: inside;
-}
-
-#qunit-tests li {
- padding: 0.4em 0.5em 0.4em 2.5em;
- border-bottom: 1px solid #fff;
- list-style-position: inside;
-}
-
-#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running {
- display: none;
-}
-
-#qunit-tests li strong {
- cursor: pointer;
-}
-
-#qunit-tests li a {
- padding: 0.5em;
- color: #c2ccd1;
- text-decoration: none;
-}
-#qunit-tests li a:hover,
-#qunit-tests li a:focus {
- color: #000;
-}
-
-#qunit-tests li .runtime {
- float: right;
- font-size: smaller;
-}
-
-.qunit-assert-list {
- margin-top: 0.5em;
- padding: 0.5em;
-
- background-color: #fff;
-
- border-radius: 5px;
- -moz-border-radius: 5px;
- -webkit-border-radius: 5px;
-}
-
-.qunit-collapsed {
- display: none;
-}
-
-#qunit-tests table {
- border-collapse: collapse;
- margin-top: .2em;
-}
-
-#qunit-tests th {
- text-align: right;
- vertical-align: top;
- padding: 0 .5em 0 0;
-}
-
-#qunit-tests td {
- vertical-align: top;
-}
-
-#qunit-tests pre {
- margin: 0;
- white-space: pre-wrap;
- word-wrap: break-word;
-}
-
-#qunit-tests del {
- background-color: #e0f2be;
- color: #374e0c;
- text-decoration: none;
-}
-
-#qunit-tests ins {
- background-color: #ffcaca;
- color: #500;
- text-decoration: none;
-}
-
-/*** Test Counts */
-
-#qunit-tests b.counts { color: black; }
-#qunit-tests b.passed { color: #5E740B; }
-#qunit-tests b.failed { color: #710909; }
-
-#qunit-tests li li {
- padding: 5px;
- background-color: #fff;
- border-bottom: none;
- list-style-position: inside;
-}
-
-/*** Passing Styles */
-
-#qunit-tests li li.pass {
- color: #3c510c;
- background-color: #fff;
- border-left: 10px solid #C6E746;
-}
-
-#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
-#qunit-tests .pass .test-name { color: #366097; }
-
-#qunit-tests .pass .test-actual,
-#qunit-tests .pass .test-expected { color: #999999; }
-
-#qunit-banner.qunit-pass { background-color: #C6E746; }
-
-/*** Failing Styles */
-
-#qunit-tests li li.fail {
- color: #710909;
- background-color: #fff;
- border-left: 10px solid #EE5757;
- white-space: pre;
-}
-
-#qunit-tests > li:last-child {
- border-radius: 0 0 5px 5px;
- -moz-border-radius: 0 0 5px 5px;
- -webkit-border-bottom-right-radius: 5px;
- -webkit-border-bottom-left-radius: 5px;
-}
-
-#qunit-tests .fail { color: #000000; background-color: #EE5757; }
-#qunit-tests .fail .test-name,
-#qunit-tests .fail .module-name { color: #000000; }
-
-#qunit-tests .fail .test-actual { color: #EE5757; }
-#qunit-tests .fail .test-expected { color: green; }
-
-#qunit-banner.qunit-fail { background-color: #EE5757; }
-
-
-/** Result */
-
-#qunit-testresult {
- padding: 0.5em 0.5em 0.5em 2.5em;
-
- color: #2b81af;
- background-color: #D2E0E6;
-
- border-bottom: 1px solid white;
-}
-#qunit-testresult .module-name {
- font-weight: bold;
-}
-
-/** Fixture */
-
-#qunit-fixture {
- position: absolute;
- top: -10000px;
- left: -10000px;
- width: 1000px;
- height: 1000px;
-}
diff --git a/test/lib/qunit-1.11.0.js b/test/lib/qunit-1.11.0.js
deleted file mode 100644
index 302545f..0000000
--- a/test/lib/qunit-1.11.0.js
+++ /dev/null
@@ -1,2152 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-(function( window ) {
-
-var QUnit,
- assert,
- config,
- onErrorFnPrev,
- testId = 0,
- fileName = (sourceFromStacktrace( 0 ) || "" ).replace(/(:\d+)+\)?/, "").replace(/.+\//, ""),
- toString = Object.prototype.toString,
- hasOwn = Object.prototype.hasOwnProperty,
- // Keep a local reference to Date (GH-283)
- Date = window.Date,
- defined = {
- setTimeout: typeof window.setTimeout !== "undefined",
- sessionStorage: (function() {
- var x = "qunit-test-string";
- try {
- sessionStorage.setItem( x, x );
- sessionStorage.removeItem( x );
- return true;
- } catch( e ) {
- return false;
- }
- }())
- },
- /**
- * Provides a normalized error string, correcting an issue
- * with IE 7 (and prior) where Error.prototype.toString is
- * not properly implemented
- *
- * Based on http://es5.github.com/#x15.11.4.4
- *
- * @param {String|Error} error
- * @return {String} error message
- */
- errorString = function( error ) {
- var name, message,
- errorString = error.toString();
- if ( errorString.substring( 0, 7 ) === "[object" ) {
- name = error.name ? error.name.toString() : "Error";
- message = error.message ? error.message.toString() : "";
- if ( name && message ) {
- return name + ": " + message;
- } else if ( name ) {
- return name;
- } else if ( message ) {
- return message;
- } else {
- return "Error";
- }
- } else {
- return errorString;
- }
- },
- /**
- * Makes a clone of an object using only Array or Object as base,
- * and copies over the own enumerable properties.
- *
- * @param {Object} obj
- * @return {Object} New object with only the own properties (recursively).
- */
- objectValues = function( obj ) {
- // Grunt 0.3.x uses an older version of jshint that still has jshint/jshint#392.
- /*jshint newcap: false */
- var key, val,
- vals = QUnit.is( "array", obj ) ? [] : {};
- for ( key in obj ) {
- if ( hasOwn.call( obj, key ) ) {
- val = obj[key];
- vals[key] = val === Object(val) ? objectValues(val) : val;
- }
- }
- return vals;
- };
-
-function Test( settings ) {
- extend( this, settings );
- this.assertions = [];
- this.testNumber = ++Test.count;
-}
-
-Test.count = 0;
-
-Test.prototype = {
- init: function() {
- var a, b, li,
- tests = id( "qunit-tests" );
-
- if ( tests ) {
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml;
-
- // `a` initialized at top of scope
- a = document.createElement( "a" );
- a.innerHTML = "Rerun";
- a.href = QUnit.url({ testNumber: this.testNumber });
-
- li = document.createElement( "li" );
- li.appendChild( b );
- li.appendChild( a );
- li.className = "running";
- li.id = this.id = "qunit-test-output" + testId++;
-
- tests.appendChild( li );
- }
- },
- setup: function() {
- if ( this.module !== config.previousModule ) {
- if ( config.previousModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.previousModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
- config.previousModule = this.module;
- config.moduleStats = { all: 0, bad: 0 };
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- } else if ( config.autorun ) {
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- }
-
- config.current = this;
-
- this.testEnvironment = extend({
- setup: function() {},
- teardown: function() {}
- }, this.moduleTestEnvironment );
-
- this.started = +new Date();
- runLoggingCallbacks( "testStart", QUnit, {
- name: this.testName,
- module: this.module
- });
-
- // allow utility functions to access the current test environment
- // TODO why??
- QUnit.current_testEnvironment = this.testEnvironment;
-
- if ( !config.pollution ) {
- saveGlobal();
- }
- if ( config.notrycatch ) {
- this.testEnvironment.setup.call( this.testEnvironment );
- return;
- }
- try {
- this.testEnvironment.setup.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Setup failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- },
- run: function() {
- config.current = this;
-
- var running = id( "qunit-testresult" );
-
- if ( running ) {
- running.innerHTML = "Running:
" + this.nameHtml;
- }
-
- if ( this.async ) {
- QUnit.stop();
- }
-
- this.callbackStarted = +new Date();
-
- if ( config.notrycatch ) {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- return;
- }
-
- try {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- } catch( e ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
-
- QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + " " + this.stack + ": " + ( e.message || e ), extractStacktrace( e, 0 ) );
- // else next test will carry the responsibility
- saveGlobal();
-
- // Restart the tests if they're blocking
- if ( config.blocking ) {
- QUnit.start();
- }
- }
- },
- teardown: function() {
- config.current = this;
- if ( config.notrycatch ) {
- if ( typeof this.callbackRuntime === "undefined" ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
- }
- this.testEnvironment.teardown.call( this.testEnvironment );
- return;
- } else {
- try {
- this.testEnvironment.teardown.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Teardown failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- }
- checkPollution();
- },
- finish: function() {
- config.current = this;
- if ( config.requireExpects && this.expected === null ) {
- QUnit.pushFailure( "Expected number of assertions to be defined, but expect() was not called.", this.stack );
- } else if ( this.expected !== null && this.expected !== this.assertions.length ) {
- QUnit.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack );
- } else if ( this.expected === null && !this.assertions.length ) {
- QUnit.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions.", this.stack );
- }
-
- var i, assertion, a, b, time, li, ol,
- test = this,
- good = 0,
- bad = 0,
- tests = id( "qunit-tests" );
-
- this.runtime = +new Date() - this.started;
- config.stats.all += this.assertions.length;
- config.moduleStats.all += this.assertions.length;
-
- if ( tests ) {
- ol = document.createElement( "ol" );
- ol.className = "qunit-assert-list";
-
- for ( i = 0; i < this.assertions.length; i++ ) {
- assertion = this.assertions[i];
-
- li = document.createElement( "li" );
- li.className = assertion.result ? "pass" : "fail";
- li.innerHTML = assertion.message || ( assertion.result ? "okay" : "failed" );
- ol.appendChild( li );
-
- if ( assertion.result ) {
- good++;
- } else {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
-
- // store result when possible
- if ( QUnit.config.reorder && defined.sessionStorage ) {
- if ( bad ) {
- sessionStorage.setItem( "qunit-test-" + this.module + "-" + this.testName, bad );
- } else {
- sessionStorage.removeItem( "qunit-test-" + this.module + "-" + this.testName );
- }
- }
-
- if ( bad === 0 ) {
- addClass( ol, "qunit-collapsed" );
- }
-
- // `b` initialized at top of scope
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml + " (" + bad + ", " + good + ", " + this.assertions.length + ")";
-
- addEvent(b, "click", function() {
- var next = b.parentNode.lastChild,
- collapsed = hasClass( next, "qunit-collapsed" );
- ( collapsed ? removeClass : addClass )( next, "qunit-collapsed" );
- });
-
- addEvent(b, "dblclick", function( e ) {
- var target = e && e.target ? e.target : window.event.srcElement;
- if ( target.nodeName.toLowerCase() === "span" || target.nodeName.toLowerCase() === "b" ) {
- target = target.parentNode;
- }
- if ( window.location && target.nodeName.toLowerCase() === "strong" ) {
- window.location = QUnit.url({ testNumber: test.testNumber });
- }
- });
-
- // `time` initialized at top of scope
- time = document.createElement( "span" );
- time.className = "runtime";
- time.innerHTML = this.runtime + " ms";
-
- // `li` initialized at top of scope
- li = id( this.id );
- li.className = bad ? "fail" : "pass";
- li.removeChild( li.firstChild );
- a = li.firstChild;
- li.appendChild( b );
- li.appendChild( a );
- li.appendChild( time );
- li.appendChild( ol );
-
- } else {
- for ( i = 0; i < this.assertions.length; i++ ) {
- if ( !this.assertions[i].result ) {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
- }
-
- runLoggingCallbacks( "testDone", QUnit, {
- name: this.testName,
- module: this.module,
- failed: bad,
- passed: this.assertions.length - bad,
- total: this.assertions.length,
- duration: this.runtime
- });
-
- QUnit.reset();
-
- config.current = undefined;
- },
-
- queue: function() {
- var bad,
- test = this;
-
- synchronize(function() {
- test.init();
- });
- function run() {
- // each of these can by async
- synchronize(function() {
- test.setup();
- });
- synchronize(function() {
- test.run();
- });
- synchronize(function() {
- test.teardown();
- });
- synchronize(function() {
- test.finish();
- });
- }
-
- // `bad` initialized at top of scope
- // defer when previous test run passed, if storage is available
- bad = QUnit.config.reorder && defined.sessionStorage &&
- +sessionStorage.getItem( "qunit-test-" + this.module + "-" + this.testName );
-
- if ( bad ) {
- run();
- } else {
- synchronize( run, true );
- }
- }
-};
-
-// Root QUnit object.
-// `QUnit` initialized at top of scope
-QUnit = {
-
- // call on start of module test to prepend name to all tests
- module: function( name, testEnvironment ) {
- config.currentModule = name;
- config.currentModuleTestEnvironment = testEnvironment;
- config.modules[name] = true;
- },
-
- asyncTest: function( testName, expected, callback ) {
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- QUnit.test( testName, expected, callback, true );
- },
-
- test: function( testName, expected, callback, async ) {
- var test,
- nameHtml = "" + escapeText( testName ) + "";
-
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- if ( config.currentModule ) {
- nameHtml = "" + escapeText( config.currentModule ) + ": " + nameHtml;
- }
-
- test = new Test({
- nameHtml: nameHtml,
- testName: testName,
- expected: expected,
- async: async,
- callback: callback,
- module: config.currentModule,
- moduleTestEnvironment: config.currentModuleTestEnvironment,
- stack: sourceFromStacktrace( 2 )
- });
-
- if ( !validTest( test ) ) {
- return;
- }
-
- test.queue();
- },
-
- // Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through.
- expect: function( asserts ) {
- if (arguments.length === 1) {
- config.current.expected = asserts;
- } else {
- return config.current.expected;
- }
- },
-
- start: function( count ) {
- // QUnit hasn't been initialized yet.
- // Note: RequireJS (et al) may delay onLoad
- if ( config.semaphore === undefined ) {
- QUnit.begin(function() {
- // This is triggered at the top of QUnit.load, push start() to the event loop, to allow QUnit.load to finish first
- setTimeout(function() {
- QUnit.start( count );
- });
- });
- return;
- }
-
- config.semaphore -= count || 1;
- // don't start until equal number of stop-calls
- if ( config.semaphore > 0 ) {
- return;
- }
- // ignore if start is called more often then stop
- if ( config.semaphore < 0 ) {
- config.semaphore = 0;
- QUnit.pushFailure( "Called start() while already started (QUnit.config.semaphore was 0 already)", null, sourceFromStacktrace(2) );
- return;
- }
- // A slight delay, to avoid any current callbacks
- if ( defined.setTimeout ) {
- window.setTimeout(function() {
- if ( config.semaphore > 0 ) {
- return;
- }
- if ( config.timeout ) {
- clearTimeout( config.timeout );
- }
-
- config.blocking = false;
- process( true );
- }, 13);
- } else {
- config.blocking = false;
- process( true );
- }
- },
-
- stop: function( count ) {
- config.semaphore += count || 1;
- config.blocking = true;
-
- if ( config.testTimeout && defined.setTimeout ) {
- clearTimeout( config.timeout );
- config.timeout = window.setTimeout(function() {
- QUnit.ok( false, "Test timed out" );
- config.semaphore = 1;
- QUnit.start();
- }, config.testTimeout );
- }
- }
-};
-
-// `assert` initialized at top of scope
-// Asssert helpers
-// All of these must either call QUnit.push() or manually do:
-// - runLoggingCallbacks( "log", .. );
-// - config.current.assertions.push({ .. });
-// We attach it to the QUnit object *after* we expose the public API,
-// otherwise `assert` will become a global variable in browsers (#341).
-assert = {
- /**
- * Asserts rough true-ish result.
- * @name ok
- * @function
- * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" );
- */
- ok: function( result, msg ) {
- if ( !config.current ) {
- throw new Error( "ok() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
- result = !!result;
-
- var source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: msg
- };
-
- msg = escapeText( msg || (result ? "okay" : "failed" ) );
- msg = "" + msg + "";
-
- if ( !result ) {
- source = sourceFromStacktrace( 2 );
- if ( source ) {
- details.source = source;
- msg += "Source: | " + escapeText( source ) + " |
---|
";
- }
- }
- runLoggingCallbacks( "log", QUnit, details );
- config.current.assertions.push({
- result: result,
- message: msg
- });
- },
-
- /**
- * Assert that the first two arguments are equal, with an optional message.
- * Prints out both actual and expected values.
- * @name equal
- * @function
- * @example equal( format( "Received {0} bytes.", 2), "Received 2 bytes.", "format() replaces {0} with next argument" );
- */
- equal: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected == actual, actual, expected, message );
- },
-
- /**
- * @name notEqual
- * @function
- */
- notEqual: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected != actual, actual, expected, message );
- },
-
- /**
- * @name propEqual
- * @function
- */
- propEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notPropEqual
- * @function
- */
- notPropEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name deepEqual
- * @function
- */
- deepEqual: function( actual, expected, message ) {
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notDeepEqual
- * @function
- */
- notDeepEqual: function( actual, expected, message ) {
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name strictEqual
- * @function
- */
- strictEqual: function( actual, expected, message ) {
- QUnit.push( expected === actual, actual, expected, message );
- },
-
- /**
- * @name notStrictEqual
- * @function
- */
- notStrictEqual: function( actual, expected, message ) {
- QUnit.push( expected !== actual, actual, expected, message );
- },
-
- "throws": function( block, expected, message ) {
- var actual,
- expectedOutput = expected,
- ok = false;
-
- // 'expected' is optional
- if ( typeof expected === "string" ) {
- message = expected;
- expected = null;
- }
-
- config.current.ignoreGlobalErrors = true;
- try {
- block.call( config.current.testEnvironment );
- } catch (e) {
- actual = e;
- }
- config.current.ignoreGlobalErrors = false;
-
- if ( actual ) {
- // we don't want to validate thrown error
- if ( !expected ) {
- ok = true;
- expectedOutput = null;
- // expected is a regexp
- } else if ( QUnit.objectType( expected ) === "regexp" ) {
- ok = expected.test( errorString( actual ) );
- // expected is a constructor
- } else if ( actual instanceof expected ) {
- ok = true;
- // expected is a validation function which returns true is validation passed
- } else if ( expected.call( {}, actual ) === true ) {
- expectedOutput = null;
- ok = true;
- }
-
- QUnit.push( ok, actual, expectedOutput, message );
- } else {
- QUnit.pushFailure( message, null, 'No exception was thrown.' );
- }
- }
-};
-
-/**
- * @deprecate since 1.8.0
- * Kept assertion helpers in root for backwards compatibility.
- */
-extend( QUnit, assert );
-
-/**
- * @deprecated since 1.9.0
- * Kept root "raises()" for backwards compatibility.
- * (Note that we don't introduce assert.raises).
- */
-QUnit.raises = assert[ "throws" ];
-
-/**
- * @deprecated since 1.0.0, replaced with error pushes since 1.3.0
- * Kept to avoid TypeErrors for undefined methods.
- */
-QUnit.equals = function() {
- QUnit.push( false, false, false, "QUnit.equals has been deprecated since 2009 (e88049a0), use QUnit.equal instead" );
-};
-QUnit.same = function() {
- QUnit.push( false, false, false, "QUnit.same has been deprecated since 2009 (e88049a0), use QUnit.deepEqual instead" );
-};
-
-// We want access to the constructor's prototype
-(function() {
- function F() {}
- F.prototype = QUnit;
- QUnit = new F();
- // Make F QUnit's constructor so that we can add to the prototype later
- QUnit.constructor = F;
-}());
-
-/**
- * Config object: Maintain internal state
- * Later exposed as QUnit.config
- * `config` initialized at top of scope
- */
-config = {
- // The queue of tests to run
- queue: [],
-
- // block until document ready
- blocking: true,
-
- // when enabled, show only failing tests
- // gets persisted through sessionStorage and can be changed in UI via checkbox
- hidepassed: false,
-
- // by default, run previously failed tests first
- // very useful in combination with "Hide passed tests" checked
- reorder: true,
-
- // by default, modify document.title when suite is done
- altertitle: true,
-
- // when enabled, all tests must call expect()
- requireExpects: false,
-
- // add checkboxes that are persisted in the query-string
- // when enabled, the id is set to `true` as a `QUnit.config` property
- urlConfig: [
- {
- id: "noglobals",
- label: "Check for Globals",
- tooltip: "Enabling this will test if any test introduces new properties on the `window` object. Stored as query-strings."
- },
- {
- id: "notrycatch",
- label: "No try-catch",
- tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging exceptions in IE reasonable. Stored as query-strings."
- }
- ],
-
- // Set of all modules.
- modules: {},
-
- // logging callback queues
- begin: [],
- done: [],
- log: [],
- testStart: [],
- testDone: [],
- moduleStart: [],
- moduleDone: []
-};
-
-// Export global variables, unless an 'exports' object exists,
-// in that case we assume we're in CommonJS (dealt with on the bottom of the script)
-if ( typeof exports === "undefined" ) {
- extend( window, QUnit );
-
- // Expose QUnit object
- window.QUnit = QUnit;
-}
-
-// Initialize more QUnit.config and QUnit.urlParams
-(function() {
- var i,
- location = window.location || { search: "", protocol: "file:" },
- params = location.search.slice( 1 ).split( "&" ),
- length = params.length,
- urlParams = {},
- current;
-
- if ( params[ 0 ] ) {
- for ( i = 0; i < length; i++ ) {
- current = params[ i ].split( "=" );
- current[ 0 ] = decodeURIComponent( current[ 0 ] );
- // allow just a key to turn on a flag, e.g., test.html?noglobals
- current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true;
- urlParams[ current[ 0 ] ] = current[ 1 ];
- }
- }
-
- QUnit.urlParams = urlParams;
-
- // String search anywhere in moduleName+testName
- config.filter = urlParams.filter;
-
- // Exact match of the module name
- config.module = urlParams.module;
-
- config.testNumber = parseInt( urlParams.testNumber, 10 ) || null;
-
- // Figure out if we're running the tests from a server or not
- QUnit.isLocal = location.protocol === "file:";
-}());
-
-// Extend QUnit object,
-// these after set here because they should not be exposed as global functions
-extend( QUnit, {
- assert: assert,
-
- config: config,
-
- // Initialize the configuration options
- init: function() {
- extend( config, {
- stats: { all: 0, bad: 0 },
- moduleStats: { all: 0, bad: 0 },
- started: +new Date(),
- updateRate: 1000,
- blocking: false,
- autostart: true,
- autorun: false,
- filter: "",
- queue: [],
- semaphore: 1
- });
-
- var tests, banner, result,
- qunit = id( "qunit" );
-
- if ( qunit ) {
- qunit.innerHTML =
- "" +
- "" +
- "" +
- "" +
- "
";
- }
-
- tests = id( "qunit-tests" );
- banner = id( "qunit-banner" );
- result = id( "qunit-testresult" );
-
- if ( tests ) {
- tests.innerHTML = "";
- }
-
- if ( banner ) {
- banner.className = "";
- }
-
- if ( result ) {
- result.parentNode.removeChild( result );
- }
-
- if ( tests ) {
- result = document.createElement( "p" );
- result.id = "qunit-testresult";
- result.className = "result";
- tests.parentNode.insertBefore( result, tests );
- result.innerHTML = "Running...
";
- }
- },
-
- // Resets the test setup. Useful for tests that modify the DOM.
- reset: function() {
- var fixture = id( "qunit-fixture" );
- if ( fixture ) {
- fixture.innerHTML = config.fixture;
- }
- },
-
- // Trigger an event on an element.
- // @example triggerEvent( document.body, "click" );
- triggerEvent: function( elem, type, event ) {
- if ( document.createEvent ) {
- event = document.createEvent( "MouseEvents" );
- event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView,
- 0, 0, 0, 0, 0, false, false, false, false, 0, null);
-
- elem.dispatchEvent( event );
- } else if ( elem.fireEvent ) {
- elem.fireEvent( "on" + type );
- }
- },
-
- // Safe object type checking
- is: function( type, obj ) {
- return QUnit.objectType( obj ) === type;
- },
-
- objectType: function( obj ) {
- if ( typeof obj === "undefined" ) {
- return "undefined";
- // consider: typeof null === object
- }
- if ( obj === null ) {
- return "null";
- }
-
- var match = toString.call( obj ).match(/^\[object\s(.*)\]$/),
- type = match && match[1] || "";
-
- switch ( type ) {
- case "Number":
- if ( isNaN(obj) ) {
- return "nan";
- }
- return "number";
- case "String":
- case "Boolean":
- case "Array":
- case "Date":
- case "RegExp":
- case "Function":
- return type.toLowerCase();
- }
- if ( typeof obj === "object" ) {
- return "object";
- }
- return undefined;
- },
-
- push: function( result, actual, expected, message ) {
- if ( !config.current ) {
- throw new Error( "assertion outside test context, was " + sourceFromStacktrace() );
- }
-
- var output, source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: message,
- actual: actual,
- expected: expected
- };
-
- message = escapeText( message ) || ( result ? "okay" : "failed" );
- message = "" + message + "";
- output = message;
-
- if ( !result ) {
- expected = escapeText( QUnit.jsDump.parse(expected) );
- actual = escapeText( QUnit.jsDump.parse(actual) );
- output += "Expected: | " + expected + " |
";
-
- if ( actual !== expected ) {
- output += "Result: | " + actual + " |
";
- output += "Diff: | " + QUnit.diff( expected, actual ) + " |
";
- }
-
- source = sourceFromStacktrace();
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
- }
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: !!result,
- message: output
- });
- },
-
- pushFailure: function( message, source, actual ) {
- if ( !config.current ) {
- throw new Error( "pushFailure() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
-
- var output,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: false,
- message: message
- };
-
- message = escapeText( message ) || "error";
- message = "" + message + "";
- output = message;
-
- output += "";
-
- if ( actual ) {
- output += "Result: | " + escapeText( actual ) + " |
";
- }
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: false,
- message: output
- });
- },
-
- url: function( params ) {
- params = extend( extend( {}, QUnit.urlParams ), params );
- var key,
- querystring = "?";
-
- for ( key in params ) {
- if ( !hasOwn.call( params, key ) ) {
- continue;
- }
- querystring += encodeURIComponent( key ) + "=" +
- encodeURIComponent( params[ key ] ) + "&";
- }
- return window.location.protocol + "//" + window.location.host +
- window.location.pathname + querystring.slice( 0, -1 );
- },
-
- extend: extend,
- id: id,
- addEvent: addEvent
- // load, equiv, jsDump, diff: Attached later
-});
-
-/**
- * @deprecated: Created for backwards compatibility with test runner that set the hook function
- * into QUnit.{hook}, instead of invoking it and passing the hook function.
- * QUnit.constructor is set to the empty F() above so that we can add to it's prototype here.
- * Doing this allows us to tell if the following methods have been overwritten on the actual
- * QUnit object.
- */
-extend( QUnit.constructor.prototype, {
-
- // Logging callbacks; all receive a single argument with the listed properties
- // run test/logs.html for any related changes
- begin: registerLoggingCallback( "begin" ),
-
- // done: { failed, passed, total, runtime }
- done: registerLoggingCallback( "done" ),
-
- // log: { result, actual, expected, message }
- log: registerLoggingCallback( "log" ),
-
- // testStart: { name }
- testStart: registerLoggingCallback( "testStart" ),
-
- // testDone: { name, failed, passed, total, duration }
- testDone: registerLoggingCallback( "testDone" ),
-
- // moduleStart: { name }
- moduleStart: registerLoggingCallback( "moduleStart" ),
-
- // moduleDone: { name, failed, passed, total }
- moduleDone: registerLoggingCallback( "moduleDone" )
-});
-
-if ( typeof document === "undefined" || document.readyState === "complete" ) {
- config.autorun = true;
-}
-
-QUnit.load = function() {
- runLoggingCallbacks( "begin", QUnit, {} );
-
- // Initialize the config, saving the execution queue
- var banner, filter, i, label, len, main, ol, toolbar, userAgent, val,
- urlConfigCheckboxesContainer, urlConfigCheckboxes, moduleFilter,
- numModules = 0,
- moduleFilterHtml = "",
- urlConfigHtml = "",
- oldconfig = extend( {}, config );
-
- QUnit.init();
- extend(config, oldconfig);
-
- config.blocking = false;
-
- len = config.urlConfig.length;
-
- for ( i = 0; i < len; i++ ) {
- val = config.urlConfig[i];
- if ( typeof val === "string" ) {
- val = {
- id: val,
- label: val,
- tooltip: "[no tooltip available]"
- };
- }
- config[ val.id ] = QUnit.urlParams[ val.id ];
- urlConfigHtml += "";
- }
-
- moduleFilterHtml += "";
-
- // `userAgent` initialized at top of scope
- userAgent = id( "qunit-userAgent" );
- if ( userAgent ) {
- userAgent.innerHTML = navigator.userAgent;
- }
-
- // `banner` initialized at top of scope
- banner = id( "qunit-header" );
- if ( banner ) {
- banner.innerHTML = "" + banner.innerHTML + " ";
- }
-
- // `toolbar` initialized at top of scope
- toolbar = id( "qunit-testrunner-toolbar" );
- if ( toolbar ) {
- // `filter` initialized at top of scope
- filter = document.createElement( "input" );
- filter.type = "checkbox";
- filter.id = "qunit-filter-pass";
-
- addEvent( filter, "click", function() {
- var tmp,
- ol = document.getElementById( "qunit-tests" );
-
- if ( filter.checked ) {
- ol.className = ol.className + " hidepass";
- } else {
- tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " ";
- ol.className = tmp.replace( / hidepass /, " " );
- }
- if ( defined.sessionStorage ) {
- if (filter.checked) {
- sessionStorage.setItem( "qunit-filter-passed-tests", "true" );
- } else {
- sessionStorage.removeItem( "qunit-filter-passed-tests" );
- }
- }
- });
-
- if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem( "qunit-filter-passed-tests" ) ) {
- filter.checked = true;
- // `ol` initialized at top of scope
- ol = document.getElementById( "qunit-tests" );
- ol.className = ol.className + " hidepass";
- }
- toolbar.appendChild( filter );
-
- // `label` initialized at top of scope
- label = document.createElement( "label" );
- label.setAttribute( "for", "qunit-filter-pass" );
- label.setAttribute( "title", "Only show tests and assertons that fail. Stored in sessionStorage." );
- label.innerHTML = "Hide passed tests";
- toolbar.appendChild( label );
-
- urlConfigCheckboxesContainer = document.createElement("span");
- urlConfigCheckboxesContainer.innerHTML = urlConfigHtml;
- urlConfigCheckboxes = urlConfigCheckboxesContainer.getElementsByTagName("input");
- // For oldIE support:
- // * Add handlers to the individual elements instead of the container
- // * Use "click" instead of "change"
- // * Fallback from event.target to event.srcElement
- addEvents( urlConfigCheckboxes, "click", function( event ) {
- var params = {},
- target = event.target || event.srcElement;
- params[ target.name ] = target.checked ? true : undefined;
- window.location = QUnit.url( params );
- });
- toolbar.appendChild( urlConfigCheckboxesContainer );
-
- if (numModules > 1) {
- moduleFilter = document.createElement( 'span' );
- moduleFilter.setAttribute( 'id', 'qunit-modulefilter-container' );
- moduleFilter.innerHTML = moduleFilterHtml;
- addEvent( moduleFilter.lastChild, "change", function() {
- var selectBox = moduleFilter.getElementsByTagName("select")[0],
- selectedModule = decodeURIComponent(selectBox.options[selectBox.selectedIndex].value);
-
- window.location = QUnit.url( { module: ( selectedModule === "" ) ? undefined : selectedModule } );
- });
- toolbar.appendChild(moduleFilter);
- }
- }
-
- // `main` initialized at top of scope
- main = id( "qunit-fixture" );
- if ( main ) {
- config.fixture = main.innerHTML;
- }
-
- if ( config.autostart ) {
- QUnit.start();
- }
-};
-
-addEvent( window, "load", QUnit.load );
-
-// `onErrorFnPrev` initialized at top of scope
-// Preserve other handlers
-onErrorFnPrev = window.onerror;
-
-// Cover uncaught exceptions
-// Returning true will surpress the default browser handler,
-// returning false will let it run.
-window.onerror = function ( error, filePath, linerNr ) {
- var ret = false;
- if ( onErrorFnPrev ) {
- ret = onErrorFnPrev( error, filePath, linerNr );
- }
-
- // Treat return value as window.onerror itself does,
- // Only do our handling if not surpressed.
- if ( ret !== true ) {
- if ( QUnit.config.current ) {
- if ( QUnit.config.current.ignoreGlobalErrors ) {
- return true;
- }
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- } else {
- QUnit.test( "global failure", extend( function() {
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- }, { validTest: validTest } ) );
- }
- return false;
- }
-
- return ret;
-};
-
-function done() {
- config.autorun = true;
-
- // Log the last module results
- if ( config.currentModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.currentModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
-
- var i, key,
- banner = id( "qunit-banner" ),
- tests = id( "qunit-tests" ),
- runtime = +new Date() - config.started,
- passed = config.stats.all - config.stats.bad,
- html = [
- "Tests completed in ",
- runtime,
- " milliseconds.
",
- "",
- passed,
- " assertions of ",
- config.stats.all,
- " passed, ",
- config.stats.bad,
- " failed."
- ].join( "" );
-
- if ( banner ) {
- banner.className = ( config.stats.bad ? "qunit-fail" : "qunit-pass" );
- }
-
- if ( tests ) {
- id( "qunit-testresult" ).innerHTML = html;
- }
-
- if ( config.altertitle && typeof document !== "undefined" && document.title ) {
- // show ✖ for good, ✔ for bad suite result in title
- // use escape sequences in case file gets loaded with non-utf-8-charset
- document.title = [
- ( config.stats.bad ? "\u2716" : "\u2714" ),
- document.title.replace( /^[\u2714\u2716] /i, "" )
- ].join( " " );
- }
-
- // clear own sessionStorage items if all tests passed
- if ( config.reorder && defined.sessionStorage && config.stats.bad === 0 ) {
- // `key` & `i` initialized at top of scope
- for ( i = 0; i < sessionStorage.length; i++ ) {
- key = sessionStorage.key( i++ );
- if ( key.indexOf( "qunit-test-" ) === 0 ) {
- sessionStorage.removeItem( key );
- }
- }
- }
-
- // scroll back to top to show results
- if ( window.scrollTo ) {
- window.scrollTo(0, 0);
- }
-
- runLoggingCallbacks( "done", QUnit, {
- failed: config.stats.bad,
- passed: passed,
- total: config.stats.all,
- runtime: runtime
- });
-}
-
-/** @return Boolean: true if this test should be ran */
-function validTest( test ) {
- var include,
- filter = config.filter && config.filter.toLowerCase(),
- module = config.module && config.module.toLowerCase(),
- fullName = (test.module + ": " + test.testName).toLowerCase();
-
- // Internally-generated tests are always valid
- if ( test.callback && test.callback.validTest === validTest ) {
- delete test.callback.validTest;
- return true;
- }
-
- if ( config.testNumber ) {
- return test.testNumber === config.testNumber;
- }
-
- if ( module && ( !test.module || test.module.toLowerCase() !== module ) ) {
- return false;
- }
-
- if ( !filter ) {
- return true;
- }
-
- include = filter.charAt( 0 ) !== "!";
- if ( !include ) {
- filter = filter.slice( 1 );
- }
-
- // If the filter matches, we need to honour include
- if ( fullName.indexOf( filter ) !== -1 ) {
- return include;
- }
-
- // Otherwise, do the opposite
- return !include;
-}
-
-// so far supports only Firefox, Chrome and Opera (buggy), Safari (for real exceptions)
-// Later Safari and IE10 are supposed to support error.stack as well
-// See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack
-function extractStacktrace( e, offset ) {
- offset = offset === undefined ? 3 : offset;
-
- var stack, include, i;
-
- if ( e.stacktrace ) {
- // Opera
- return e.stacktrace.split( "\n" )[ offset + 3 ];
- } else if ( e.stack ) {
- // Firefox, Chrome
- stack = e.stack.split( "\n" );
- if (/^error$/i.test( stack[0] ) ) {
- stack.shift();
- }
- if ( fileName ) {
- include = [];
- for ( i = offset; i < stack.length; i++ ) {
- if ( stack[ i ].indexOf( fileName ) !== -1 ) {
- break;
- }
- include.push( stack[ i ] );
- }
- if ( include.length ) {
- return include.join( "\n" );
- }
- }
- return stack[ offset ];
- } else if ( e.sourceURL ) {
- // Safari, PhantomJS
- // hopefully one day Safari provides actual stacktraces
- // exclude useless self-reference for generated Error objects
- if ( /qunit.js$/.test( e.sourceURL ) ) {
- return;
- }
- // for actual exceptions, this is useful
- return e.sourceURL + ":" + e.line;
- }
-}
-function sourceFromStacktrace( offset ) {
- try {
- throw new Error();
- } catch ( e ) {
- return extractStacktrace( e, offset );
- }
-}
-
-/**
- * Escape text for attribute or text content.
- */
-function escapeText( s ) {
- if ( !s ) {
- return "";
- }
- s = s + "";
- // Both single quotes and double quotes (for attributes)
- return s.replace( /['"<>&]/g, function( s ) {
- switch( s ) {
- case '\'':
- return ''';
- case '"':
- return '"';
- case '<':
- return '<';
- case '>':
- return '>';
- case '&':
- return '&';
- }
- });
-}
-
-function synchronize( callback, last ) {
- config.queue.push( callback );
-
- if ( config.autorun && !config.blocking ) {
- process( last );
- }
-}
-
-function process( last ) {
- function next() {
- process( last );
- }
- var start = new Date().getTime();
- config.depth = config.depth ? config.depth + 1 : 1;
-
- while ( config.queue.length && !config.blocking ) {
- if ( !defined.setTimeout || config.updateRate <= 0 || ( ( new Date().getTime() - start ) < config.updateRate ) ) {
- config.queue.shift()();
- } else {
- window.setTimeout( next, 13 );
- break;
- }
- }
- config.depth--;
- if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) {
- done();
- }
-}
-
-function saveGlobal() {
- config.pollution = [];
-
- if ( config.noglobals ) {
- for ( var key in window ) {
- // in Opera sometimes DOM element ids show up here, ignore them
- if ( !hasOwn.call( window, key ) || /^qunit-test-output/.test( key ) ) {
- continue;
- }
- config.pollution.push( key );
- }
- }
-}
-
-function checkPollution() {
- var newGlobals,
- deletedGlobals,
- old = config.pollution;
-
- saveGlobal();
-
- newGlobals = diff( config.pollution, old );
- if ( newGlobals.length > 0 ) {
- QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join(", ") );
- }
-
- deletedGlobals = diff( old, config.pollution );
- if ( deletedGlobals.length > 0 ) {
- QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join(", ") );
- }
-}
-
-// returns a new Array with the elements that are in a but not in b
-function diff( a, b ) {
- var i, j,
- result = a.slice();
-
- for ( i = 0; i < result.length; i++ ) {
- for ( j = 0; j < b.length; j++ ) {
- if ( result[i] === b[j] ) {
- result.splice( i, 1 );
- i--;
- break;
- }
- }
- }
- return result;
-}
-
-function extend( a, b ) {
- for ( var prop in b ) {
- if ( b[ prop ] === undefined ) {
- delete a[ prop ];
-
- // Avoid "Member not found" error in IE8 caused by setting window.constructor
- } else if ( prop !== "constructor" || a !== window ) {
- a[ prop ] = b[ prop ];
- }
- }
-
- return a;
-}
-
-/**
- * @param {HTMLElement} elem
- * @param {string} type
- * @param {Function} fn
- */
-function addEvent( elem, type, fn ) {
- // Standards-based browsers
- if ( elem.addEventListener ) {
- elem.addEventListener( type, fn, false );
- // IE
- } else {
- elem.attachEvent( "on" + type, fn );
- }
-}
-
-/**
- * @param {Array|NodeList} elems
- * @param {string} type
- * @param {Function} fn
- */
-function addEvents( elems, type, fn ) {
- var i = elems.length;
- while ( i-- ) {
- addEvent( elems[i], type, fn );
- }
-}
-
-function hasClass( elem, name ) {
- return (" " + elem.className + " ").indexOf(" " + name + " ") > -1;
-}
-
-function addClass( elem, name ) {
- if ( !hasClass( elem, name ) ) {
- elem.className += (elem.className ? " " : "") + name;
- }
-}
-
-function removeClass( elem, name ) {
- var set = " " + elem.className + " ";
- // Class name may appear multiple times
- while ( set.indexOf(" " + name + " ") > -1 ) {
- set = set.replace(" " + name + " " , " ");
- }
- // If possible, trim it for prettiness, but not neccecarily
- elem.className = window.jQuery ? jQuery.trim( set ) : ( set.trim ? set.trim() : set );
-}
-
-function id( name ) {
- return !!( typeof document !== "undefined" && document && document.getElementById ) &&
- document.getElementById( name );
-}
-
-function registerLoggingCallback( key ) {
- return function( callback ) {
- config[key].push( callback );
- };
-}
-
-// Supports deprecated method of completely overwriting logging callbacks
-function runLoggingCallbacks( key, scope, args ) {
- var i, callbacks;
- if ( QUnit.hasOwnProperty( key ) ) {
- QUnit[ key ].call(scope, args );
- } else {
- callbacks = config[ key ];
- for ( i = 0; i < callbacks.length; i++ ) {
- callbacks[ i ].call( scope, args );
- }
- }
-}
-
-// Test for equality any JavaScript type.
-// Author: Philippe Rathé
-QUnit.equiv = (function() {
-
- // Call the o related callback with the given arguments.
- function bindCallbacks( o, callbacks, args ) {
- var prop = QUnit.objectType( o );
- if ( prop ) {
- if ( QUnit.objectType( callbacks[ prop ] ) === "function" ) {
- return callbacks[ prop ].apply( callbacks, args );
- } else {
- return callbacks[ prop ]; // or undefined
- }
- }
- }
-
- // the real equiv function
- var innerEquiv,
- // stack to decide between skip/abort functions
- callers = [],
- // stack to avoiding loops from circular referencing
- parents = [],
-
- getProto = Object.getPrototypeOf || function ( obj ) {
- return obj.__proto__;
- },
- callbacks = (function () {
-
- // for string, boolean, number and null
- function useStrictEquality( b, a ) {
- /*jshint eqeqeq:false */
- if ( b instanceof a.constructor || a instanceof b.constructor ) {
- // to catch short annotaion VS 'new' annotation of a
- // declaration
- // e.g. var i = 1;
- // var j = new Number(1);
- return a == b;
- } else {
- return a === b;
- }
- }
-
- return {
- "string": useStrictEquality,
- "boolean": useStrictEquality,
- "number": useStrictEquality,
- "null": useStrictEquality,
- "undefined": useStrictEquality,
-
- "nan": function( b ) {
- return isNaN( b );
- },
-
- "date": function( b, a ) {
- return QUnit.objectType( b ) === "date" && a.valueOf() === b.valueOf();
- },
-
- "regexp": function( b, a ) {
- return QUnit.objectType( b ) === "regexp" &&
- // the regex itself
- a.source === b.source &&
- // and its modifers
- a.global === b.global &&
- // (gmi) ...
- a.ignoreCase === b.ignoreCase &&
- a.multiline === b.multiline &&
- a.sticky === b.sticky;
- },
-
- // - skip when the property is a method of an instance (OOP)
- // - abort otherwise,
- // initial === would have catch identical references anyway
- "function": function() {
- var caller = callers[callers.length - 1];
- return caller !== Object && typeof caller !== "undefined";
- },
-
- "array": function( b, a ) {
- var i, j, len, loop;
-
- // b could be an object literal here
- if ( QUnit.objectType( b ) !== "array" ) {
- return false;
- }
-
- len = a.length;
- if ( len !== b.length ) {
- // safe and faster
- return false;
- }
-
- // track reference to avoid circular references
- parents.push( a );
- for ( i = 0; i < len; i++ ) {
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- loop = true;// dont rewalk array
- }
- }
- if ( !loop && !innerEquiv(a[i], b[i]) ) {
- parents.pop();
- return false;
- }
- }
- parents.pop();
- return true;
- },
-
- "object": function( b, a ) {
- var i, j, loop,
- // Default to true
- eq = true,
- aProperties = [],
- bProperties = [];
-
- // comparing constructors is more strict than using
- // instanceof
- if ( a.constructor !== b.constructor ) {
- // Allow objects with no prototype to be equivalent to
- // objects with Object as their constructor.
- if ( !(( getProto(a) === null && getProto(b) === Object.prototype ) ||
- ( getProto(b) === null && getProto(a) === Object.prototype ) ) ) {
- return false;
- }
- }
-
- // stack constructor before traversing properties
- callers.push( a.constructor );
- // track reference to avoid circular references
- parents.push( a );
-
- for ( i in a ) { // be strict: don't ensures hasOwnProperty
- // and go deep
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- // don't go down the same path twice
- loop = true;
- }
- }
- aProperties.push(i); // collect a's properties
-
- if (!loop && !innerEquiv( a[i], b[i] ) ) {
- eq = false;
- break;
- }
- }
-
- callers.pop(); // unstack, we are done
- parents.pop();
-
- for ( i in b ) {
- bProperties.push( i ); // collect b's properties
- }
-
- // Ensures identical properties name
- return eq && innerEquiv( aProperties.sort(), bProperties.sort() );
- }
- };
- }());
-
- innerEquiv = function() { // can take multiple arguments
- var args = [].slice.apply( arguments );
- if ( args.length < 2 ) {
- return true; // end transition
- }
-
- return (function( a, b ) {
- if ( a === b ) {
- return true; // catch the most you can
- } else if ( a === null || b === null || typeof a === "undefined" ||
- typeof b === "undefined" ||
- QUnit.objectType(a) !== QUnit.objectType(b) ) {
- return false; // don't lose time with error prone cases
- } else {
- return bindCallbacks(a, callbacks, [ b, a ]);
- }
-
- // apply transition with (1..n) arguments
- }( args[0], args[1] ) && arguments.callee.apply( this, args.splice(1, args.length - 1 )) );
- };
-
- return innerEquiv;
-}());
-
-/**
- * jsDump Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com |
- * http://flesler.blogspot.com Licensed under BSD
- * (http://www.opensource.org/licenses/bsd-license.php) Date: 5/15/2008
- *
- * @projectDescription Advanced and extensible data dumping for Javascript.
- * @version 1.0.0
- * @author Ariel Flesler
- * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html}
- */
-QUnit.jsDump = (function() {
- function quote( str ) {
- return '"' + str.toString().replace( /"/g, '\\"' ) + '"';
- }
- function literal( o ) {
- return o + "";
- }
- function join( pre, arr, post ) {
- var s = jsDump.separator(),
- base = jsDump.indent(),
- inner = jsDump.indent(1);
- if ( arr.join ) {
- arr = arr.join( "," + s + inner );
- }
- if ( !arr ) {
- return pre + post;
- }
- return [ pre, inner + arr, base + post ].join(s);
- }
- function array( arr, stack ) {
- var i = arr.length, ret = new Array(i);
- this.up();
- while ( i-- ) {
- ret[i] = this.parse( arr[i] , undefined , stack);
- }
- this.down();
- return join( "[", ret, "]" );
- }
-
- var reName = /^function (\w+)/,
- jsDump = {
- // type is used mostly internally, you can fix a (custom)type in advance
- parse: function( obj, type, stack ) {
- stack = stack || [ ];
- var inStack, res,
- parser = this.parsers[ type || this.typeOf(obj) ];
-
- type = typeof parser;
- inStack = inArray( obj, stack );
-
- if ( inStack !== -1 ) {
- return "recursion(" + (inStack - stack.length) + ")";
- }
- if ( type === "function" ) {
- stack.push( obj );
- res = parser.call( this, obj, stack );
- stack.pop();
- return res;
- }
- return ( type === "string" ) ? parser : this.parsers.error;
- },
- typeOf: function( obj ) {
- var type;
- if ( obj === null ) {
- type = "null";
- } else if ( typeof obj === "undefined" ) {
- type = "undefined";
- } else if ( QUnit.is( "regexp", obj) ) {
- type = "regexp";
- } else if ( QUnit.is( "date", obj) ) {
- type = "date";
- } else if ( QUnit.is( "function", obj) ) {
- type = "function";
- } else if ( typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined" ) {
- type = "window";
- } else if ( obj.nodeType === 9 ) {
- type = "document";
- } else if ( obj.nodeType ) {
- type = "node";
- } else if (
- // native arrays
- toString.call( obj ) === "[object Array]" ||
- // NodeList objects
- ( typeof obj.length === "number" && typeof obj.item !== "undefined" && ( obj.length ? obj.item(0) === obj[0] : ( obj.item( 0 ) === null && typeof obj[0] === "undefined" ) ) )
- ) {
- type = "array";
- } else if ( obj.constructor === Error.prototype.constructor ) {
- type = "error";
- } else {
- type = typeof obj;
- }
- return type;
- },
- separator: function() {
- return this.multiline ? this.HTML ? "
" : "\n" : this.HTML ? " " : " ";
- },
- // extra can be a number, shortcut for increasing-calling-decreasing
- indent: function( extra ) {
- if ( !this.multiline ) {
- return "";
- }
- var chr = this.indentChar;
- if ( this.HTML ) {
- chr = chr.replace( /\t/g, " " ).replace( / /g, " " );
- }
- return new Array( this._depth_ + (extra||0) ).join(chr);
- },
- up: function( a ) {
- this._depth_ += a || 1;
- },
- down: function( a ) {
- this._depth_ -= a || 1;
- },
- setParser: function( name, parser ) {
- this.parsers[name] = parser;
- },
- // The next 3 are exposed so you can use them
- quote: quote,
- literal: literal,
- join: join,
- //
- _depth_: 1,
- // This is the list of parsers, to modify them, use jsDump.setParser
- parsers: {
- window: "[Window]",
- document: "[Document]",
- error: function(error) {
- return "Error(\"" + error.message + "\")";
- },
- unknown: "[Unknown]",
- "null": "null",
- "undefined": "undefined",
- "function": function( fn ) {
- var ret = "function",
- // functions never have name in IE
- name = "name" in fn ? fn.name : (reName.exec(fn) || [])[1];
-
- if ( name ) {
- ret += " " + name;
- }
- ret += "( ";
-
- ret = [ ret, QUnit.jsDump.parse( fn, "functionArgs" ), "){" ].join( "" );
- return join( ret, QUnit.jsDump.parse(fn,"functionCode" ), "}" );
- },
- array: array,
- nodelist: array,
- "arguments": array,
- object: function( map, stack ) {
- var ret = [ ], keys, key, val, i;
- QUnit.jsDump.up();
- keys = [];
- for ( key in map ) {
- keys.push( key );
- }
- keys.sort();
- for ( i = 0; i < keys.length; i++ ) {
- key = keys[ i ];
- val = map[ key ];
- ret.push( QUnit.jsDump.parse( key, "key" ) + ": " + QUnit.jsDump.parse( val, undefined, stack ) );
- }
- QUnit.jsDump.down();
- return join( "{", ret, "}" );
- },
- node: function( node ) {
- var len, i, val,
- open = QUnit.jsDump.HTML ? "<" : "<",
- close = QUnit.jsDump.HTML ? ">" : ">",
- tag = node.nodeName.toLowerCase(),
- ret = open + tag,
- attrs = node.attributes;
-
- if ( attrs ) {
- for ( i = 0, len = attrs.length; i < len; i++ ) {
- val = attrs[i].nodeValue;
- // IE6 includes all attributes in .attributes, even ones not explicitly set.
- // Those have values like undefined, null, 0, false, "" or "inherit".
- if ( val && val !== "inherit" ) {
- ret += " " + attrs[i].nodeName + "=" + QUnit.jsDump.parse( val, "attribute" );
- }
- }
- }
- ret += close;
-
- // Show content of TextNode or CDATASection
- if ( node.nodeType === 3 || node.nodeType === 4 ) {
- ret += node.nodeValue;
- }
-
- return ret + open + "/" + tag + close;
- },
- // function calls it internally, it's the arguments part of the function
- functionArgs: function( fn ) {
- var args,
- l = fn.length;
-
- if ( !l ) {
- return "";
- }
-
- args = new Array(l);
- while ( l-- ) {
- // 97 is 'a'
- args[l] = String.fromCharCode(97+l);
- }
- return " " + args.join( ", " ) + " ";
- },
- // object calls it internally, the key part of an item in a map
- key: quote,
- // function calls it internally, it's the content of the function
- functionCode: "[code]",
- // node calls it internally, it's an html attribute value
- attribute: quote,
- string: quote,
- date: quote,
- regexp: literal,
- number: literal,
- "boolean": literal
- },
- // if true, entities are escaped ( <, >, \t, space and \n )
- HTML: false,
- // indentation unit
- indentChar: " ",
- // if true, items in a collection, are separated by a \n, else just a space.
- multiline: true
- };
-
- return jsDump;
-}());
-
-// from jquery.js
-function inArray( elem, array ) {
- if ( array.indexOf ) {
- return array.indexOf( elem );
- }
-
- for ( var i = 0, length = array.length; i < length; i++ ) {
- if ( array[ i ] === elem ) {
- return i;
- }
- }
-
- return -1;
-}
-
-/*
- * Javascript Diff Algorithm
- * By John Resig (http://ejohn.org/)
- * Modified by Chu Alan "sprite"
- *
- * Released under the MIT license.
- *
- * More Info:
- * http://ejohn.org/projects/javascript-diff-algorithm/
- *
- * Usage: QUnit.diff(expected, actual)
- *
- * QUnit.diff( "the quick brown fox jumped over", "the quick fox jumps over" ) == "the quick brown fox jumped jumps over"
- */
-QUnit.diff = (function() {
- /*jshint eqeqeq:false, eqnull:true */
- function diff( o, n ) {
- var i,
- ns = {},
- os = {};
-
- for ( i = 0; i < n.length; i++ ) {
- if ( !hasOwn.call( ns, n[i] ) ) {
- ns[ n[i] ] = {
- rows: [],
- o: null
- };
- }
- ns[ n[i] ].rows.push( i );
- }
-
- for ( i = 0; i < o.length; i++ ) {
- if ( !hasOwn.call( os, o[i] ) ) {
- os[ o[i] ] = {
- rows: [],
- n: null
- };
- }
- os[ o[i] ].rows.push( i );
- }
-
- for ( i in ns ) {
- if ( !hasOwn.call( ns, i ) ) {
- continue;
- }
- if ( ns[i].rows.length === 1 && hasOwn.call( os, i ) && os[i].rows.length === 1 ) {
- n[ ns[i].rows[0] ] = {
- text: n[ ns[i].rows[0] ],
- row: os[i].rows[0]
- };
- o[ os[i].rows[0] ] = {
- text: o[ os[i].rows[0] ],
- row: ns[i].rows[0]
- };
- }
- }
-
- for ( i = 0; i < n.length - 1; i++ ) {
- if ( n[i].text != null && n[ i + 1 ].text == null && n[i].row + 1 < o.length && o[ n[i].row + 1 ].text == null &&
- n[ i + 1 ] == o[ n[i].row + 1 ] ) {
-
- n[ i + 1 ] = {
- text: n[ i + 1 ],
- row: n[i].row + 1
- };
- o[ n[i].row + 1 ] = {
- text: o[ n[i].row + 1 ],
- row: i + 1
- };
- }
- }
-
- for ( i = n.length - 1; i > 0; i-- ) {
- if ( n[i].text != null && n[ i - 1 ].text == null && n[i].row > 0 && o[ n[i].row - 1 ].text == null &&
- n[ i - 1 ] == o[ n[i].row - 1 ]) {
-
- n[ i - 1 ] = {
- text: n[ i - 1 ],
- row: n[i].row - 1
- };
- o[ n[i].row - 1 ] = {
- text: o[ n[i].row - 1 ],
- row: i - 1
- };
- }
- }
-
- return {
- o: o,
- n: n
- };
- }
-
- return function( o, n ) {
- o = o.replace( /\s+$/, "" );
- n = n.replace( /\s+$/, "" );
-
- var i, pre,
- str = "",
- out = diff( o === "" ? [] : o.split(/\s+/), n === "" ? [] : n.split(/\s+/) ),
- oSpace = o.match(/\s+/g),
- nSpace = n.match(/\s+/g);
-
- if ( oSpace == null ) {
- oSpace = [ " " ];
- }
- else {
- oSpace.push( " " );
- }
-
- if ( nSpace == null ) {
- nSpace = [ " " ];
- }
- else {
- nSpace.push( " " );
- }
-
- if ( out.n.length === 0 ) {
- for ( i = 0; i < out.o.length; i++ ) {
- str += "" + out.o[i] + oSpace[i] + "";
- }
- }
- else {
- if ( out.n[0].text == null ) {
- for ( n = 0; n < out.o.length && out.o[n].text == null; n++ ) {
- str += "" + out.o[n] + oSpace[n] + "";
- }
- }
-
- for ( i = 0; i < out.n.length; i++ ) {
- if (out.n[i].text == null) {
- str += "" + out.n[i] + nSpace[i] + "";
- }
- else {
- // `pre` initialized at top of scope
- pre = "";
-
- for ( n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++ ) {
- pre += "" + out.o[n] + oSpace[n] + "";
- }
- str += " " + out.n[i].text + nSpace[i] + pre;
- }
- }
- }
-
- return str;
- };
-}());
-
-// for CommonJS enviroments, export everything
-if ( typeof exports !== "undefined" ) {
- extend( exports, QUnit );
-}
-
-// get at whatever the global object is, like window in browsers
-}( (function() {return this;}.call()) ));
diff --git a/test/lib/require.js b/test/lib/require.js
deleted file mode 100644
index 987f865..0000000
--- a/test/lib/require.js
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- RequireJS 2.1.5 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.
- Available via the MIT or new BSD license.
- see: http://github.com/jrburke/requirejs for details
-*/
-var requirejs,require,define;
-(function(aa){function I(b){return"[object Function]"===L.call(b)}function J(b){return"[object Array]"===L.call(b)}function y(b,c){if(b){var d;for(d=0;dthis.depCount&&!this.defined){if(I(n)){if(this.events.error)try{e=i.execCb(c,n,b,e)}catch(d){a=d}else e=i.execCb(c,n,b,e);this.map.isDefine&&((b=this.module)&&void 0!==b.exports&&b.exports!==this.exports?e=b.exports:void 0===e&&this.usingExports&&(e=this.exports));if(a)return a.requireMap=this.map,a.requireModules=[this.map.id],a.requireType="define",v(this.error=
-a)}else e=n;this.exports=e;if(this.map.isDefine&&!this.ignore&&(q[c]=e,l.onResourceLoad))l.onResourceLoad(i,this.map,this.depMaps);x(c);this.defined=!0}this.defining=!1;this.defined&&!this.defineEmitted&&(this.defineEmitted=!0,this.emit("defined",this.exports),this.defineEmitComplete=!0)}}else this.fetch()}},callPlugin:function(){var a=this.map,b=a.id,d=j(a.prefix);this.depMaps.push(d);t(d,"defined",u(this,function(e){var n,d;d=this.map.name;var g=this.map.parentMap?this.map.parentMap.name:null,h=
-i.makeRequire(a.parentMap,{enableBuildCallback:!0});if(this.map.unnormalized){if(e.normalize&&(d=e.normalize(d,function(a){return c(a,g,!0)})||""),e=j(a.prefix+"!"+d,this.map.parentMap),t(e,"defined",u(this,function(a){this.init([],function(){return a},null,{enabled:!0,ignore:!0})})),d=m(p,e.id)){this.depMaps.push(e);if(this.events.error)d.on("error",u(this,function(a){this.emit("error",a)}));d.enable()}}else n=u(this,function(a){this.init([],function(){return a},null,{enabled:!0})}),n.error=u(this,
-function(a){this.inited=!0;this.error=a;a.requireModules=[b];G(p,function(a){0===a.map.id.indexOf(b+"_unnormalized")&&x(a.map.id)});v(a)}),n.fromText=u(this,function(e,c){var d=a.name,g=j(d),C=O;c&&(e=c);C&&(O=!1);r(g);s(k.config,b)&&(k.config[d]=k.config[b]);try{l.exec(e)}catch(ca){return v(B("fromtexteval","fromText eval for "+b+" failed: "+ca,ca,[b]))}C&&(O=!0);this.depMaps.push(g);i.completeLoad(d);h([d],n)}),e.load(a.name,h,n,k)}));i.enable(d,this);this.pluginMaps[d.id]=d},enable:function(){V[this.map.id]=
-this;this.enabling=this.enabled=!0;y(this.depMaps,u(this,function(a,b){var c,e;if("string"===typeof a){a=j(a,this.map.isDefine?this.map:this.map.parentMap,!1,!this.skipMap);this.depMaps[b]=a;if(c=m(N,a.id)){this.depExports[b]=c(this);return}this.depCount+=1;t(a,"defined",u(this,function(a){this.defineDep(b,a);this.check()}));this.errback&&t(a,"error",this.errback)}c=a.id;e=p[c];!s(N,c)&&(e&&!e.enabled)&&i.enable(a,this)}));G(this.pluginMaps,u(this,function(a){var b=m(p,a.id);b&&!b.enabled&&i.enable(a,
-this)}));this.enabling=!1;this.check()},on:function(a,b){var c=this.events[a];c||(c=this.events[a]=[]);c.push(b)},emit:function(a,b){y(this.events[a],function(a){a(b)});"error"===a&&delete this.events[a]}};i={config:k,contextName:b,registry:p,defined:q,urlFetched:U,defQueue:H,Module:Z,makeModuleMap:j,nextTick:l.nextTick,onError:v,configure:function(a){a.baseUrl&&"/"!==a.baseUrl.charAt(a.baseUrl.length-1)&&(a.baseUrl+="/");var b=k.pkgs,c=k.shim,e={paths:!0,config:!0,map:!0};G(a,function(a,b){e[b]?
-"map"===b?(k.map||(k.map={}),R(k[b],a,!0,!0)):R(k[b],a,!0):k[b]=a});a.shim&&(G(a.shim,function(a,b){J(a)&&(a={deps:a});if((a.exports||a.init)&&!a.exportsFn)a.exportsFn=i.makeShimExports(a);c[b]=a}),k.shim=c);a.packages&&(y(a.packages,function(a){a="string"===typeof a?{name:a}:a;b[a.name]={name:a.name,location:a.location||a.name,main:(a.main||"main").replace(ja,"").replace(ea,"")}}),k.pkgs=b);G(p,function(a,b){!a.inited&&!a.map.unnormalized&&(a.map=j(b))});if(a.deps||a.callback)i.require(a.deps||[],
-a.callback)},makeShimExports:function(a){return function(){var b;a.init&&(b=a.init.apply(aa,arguments));return b||a.exports&&ba(a.exports)}},makeRequire:function(a,f){function d(e,c,h){var g,k;f.enableBuildCallback&&(c&&I(c))&&(c.__requireJsBuild=!0);if("string"===typeof e){if(I(c))return v(B("requireargs","Invalid require call"),h);if(a&&s(N,e))return N[e](p[a.id]);if(l.get)return l.get(i,e,a,d);g=j(e,a,!1,!0);g=g.id;return!s(q,g)?v(B("notloaded",'Module name "'+g+'" has not been loaded yet for context: '+
-b+(a?"":". Use require([])"))):q[g]}L();i.nextTick(function(){L();k=r(j(null,a));k.skipMap=f.skipMap;k.init(e,c,h,{enabled:!0});D()});return d}f=f||{};R(d,{isBrowser:A,toUrl:function(b){var d,f=b.lastIndexOf("."),g=b.split("/")[0];if(-1!==f&&(!("."===g||".."===g)||1h.attachEvent.toString().indexOf("[native code"))&&!Y?(O=!0,h.attachEvent("onreadystatechange",b.onScriptLoad)):(h.addEventListener("load",b.onScriptLoad,!1),h.addEventListener("error",b.onScriptError,!1)),h.src=d,K=h,D?x.insertBefore(h,D):x.appendChild(h),K=null,h;if(da)try{importScripts(d),b.completeLoad(c)}catch(j){b.onError(B("importscripts","importScripts failed for "+c+" at "+d,j,[c]))}};A&&M(document.getElementsByTagName("script"),function(b){x||(x=
-b.parentNode);if(t=b.getAttribute("data-main"))return r.baseUrl||(E=t.split("/"),Q=E.pop(),fa=E.length?E.join("/")+"/":"./",r.baseUrl=fa,t=Q),t=t.replace(ea,""),r.deps=r.deps?r.deps.concat(t):[t],!0});define=function(b,c,d){var l,h;"string"!==typeof b&&(d=c,c=b,b=null);J(c)||(d=c,c=[]);!c.length&&I(d)&&d.length&&(d.toString().replace(la,"").replace(ma,function(b,d){c.push(d)}),c=(1===d.length?["require"]:["require","exports","module"]).concat(c));if(O){if(!(l=K))P&&"interactive"===P.readyState||M(document.getElementsByTagName("script"),
-function(b){if("interactive"===b.readyState)return P=b}),l=P;l&&(b||(b=l.getAttribute("data-requiremodule")),h=F[l.getAttribute("data-requirecontext")])}(h?h.defQueue:T).push([b,c,d])};define.amd={jQuery:!0};l.exec=function(b){return eval(b)};l(r)}})(this);
diff --git a/test/lib/resemble.js b/test/lib/resemble.js
new file mode 100644
index 0000000..1cb8c29
--- /dev/null
+++ b/test/lib/resemble.js
@@ -0,0 +1,535 @@
+/*
+Author: James Cryer
+Company: Huddle
+Last updated date: 21 Feb 2013
+URL: https://github.com/Huddle/Resemble.js
+*/
+
+(function(_this){
+ 'use strict';
+
+ _this['resemble'] = function( fileData ){
+
+ var data = {};
+ var images = [];
+ var updateCallbackArray = [];
+
+ var tolerance = { // between 0 and 255
+ red: 16,
+ green: 16,
+ blue: 16,
+ minBrightness: 16,
+ maxBrightness: 240
+ };
+
+ var ignoreAntialiasing = false;
+ var ignoreColors = false;
+
+ function triggerDataUpdate(){
+ var len = updateCallbackArray.length;
+ var i;
+ for(i=0;i tolerance.maxBrightness;
+ }
+
+ function getHue(r,g,b){
+
+ r = r / 255;
+ g = g / 255;
+ b = b / 255;
+ var max = Math.max(r, g, b), min = Math.min(r, g, b);
+ var h;
+ var d;
+
+ if (max == min){
+ h = 0; // achromatic
+ } else{
+ d = max - min;
+ switch(max){
+ case r: h = (g - b) / d + (g < b ? 6 : 0); break;
+ case g: h = (b - r) / d + 2; break;
+ case b: h = (r - g) / d + 4; break;
+ }
+ h /= 6;
+ }
+
+ return h;
+ }
+
+ function isAntialiased(sourcePix, data, cacheSet, verticalPos, horizontalPos, width){
+ var offset;
+ var targetPix;
+ var distance = 1;
+ var i;
+ var j;
+ var hasHighContrastSibling = 0;
+ var hasSiblingWithDifferentHue = 0;
+ var hasEquivilantSibling = 0;
+
+ addHueInfo(sourcePix);
+
+ for (i = distance*-1; i <= distance; i++){
+ for (j = distance*-1; j <= distance; j++){
+
+ if(i===0 && j===0){
+ // ignore source pixel
+ } else {
+
+ offset = ((verticalPos+j)*width + (horizontalPos+i)) * 4;
+ targetPix = getPixelInfo(data, offset, cacheSet);
+
+ if(targetPix === null){
+ continue;
+ }
+
+ addBrightnessInfo(targetPix);
+ addHueInfo(targetPix);
+
+ if( isContrasting(sourcePix, targetPix) ){
+ hasHighContrastSibling++;
+ }
+
+ if( isRGBSame(sourcePix,targetPix) ){
+ hasEquivilantSibling++;
+ }
+
+ if( Math.abs(targetPix.h - sourcePix.h) > 0.3 ){
+ hasSiblingWithDifferentHue++;
+ }
+
+ if( hasSiblingWithDifferentHue > 1 || hasHighContrastSibling > 1){
+ return true;
+ }
+ }
+ }
+ }
+
+ if(hasEquivilantSibling < 2){
+ return true;
+ }
+
+ return false;
+ }
+
+ function errorPixel(px, offset){
+ px[offset] = 255; //r
+ px[offset + 1] = 0; //g
+ px[offset + 2] = 255; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyPixel(px, offset, data){
+ px[offset] = data.r; //r
+ px[offset + 1] = data.g; //g
+ px[offset + 2] = data.b; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyGrayScalePixel(px, offset, data){
+ px[offset] = data.brightness; //r
+ px[offset + 1] = data.brightness; //g
+ px[offset + 2] = data.brightness; //b
+ px[offset + 3] = 255; //a
+ }
+
+
+ function getPixelInfo(data, offset, cacheSet){
+ var r;
+ var g;
+ var b;
+ var d;
+
+ if(typeof data[offset] !== 'undefined'){
+ r = data[offset];
+ g = data[offset+1];
+ b = data[offset+2];
+ d = {
+ r: r,
+ g: g,
+ b: b
+ };
+
+ return d;
+ } else {
+ return null;
+ }
+ }
+
+ function addBrightnessInfo(data){
+ data.brightness = getBrightness(data.r,data.g,data.b); // 'corrected' lightness
+ }
+
+ function addHueInfo(data){
+ data.h = getHue(data.r,data.g,data.b);
+ }
+
+ function analyseImages(img1, img2, width, height){
+
+ var hiddenCanvas = document.createElement('canvas');
+
+ var data1 = img1.data;
+ var data2 = img2.data;
+
+ hiddenCanvas.width = width;
+ hiddenCanvas.height = height;
+
+ var context = hiddenCanvas.getContext('2d');
+ var imgd = context.createImageData(width,height);
+ var targetPix = imgd.data;
+
+ var mismatchCount = 0;
+
+ var time = Date.now();
+
+ var skip;
+
+ if( (width > 1200 || height > 1200) && ignoreAntialiasing){
+ skip = 6;
+ }
+
+ loop(height, width, function(verticalPos, horizontalPos){
+
+ if(skip){ // only skip if the image isn't small
+ if(verticalPos % skip === 0 || horizontalPos % skip === 0){
+ return;
+ }
+ }
+
+ var offset = (verticalPos*width + horizontalPos) * 4;
+ var pixel1 = getPixelInfo(data1, offset, 1);
+ var pixel2 = getPixelInfo(data2, offset, 2);
+
+ if(pixel1 === null || pixel2 === null){
+ return;
+ }
+
+ if (ignoreColors){
+
+ addBrightnessInfo(pixel1);
+ addBrightnessInfo(pixel2);
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ return;
+ }
+
+ if( isRGBSimilar(pixel1, pixel2) ){
+ copyPixel(targetPix, offset, pixel2);
+
+ } else if( ignoreAntialiasing && (
+ addBrightnessInfo(pixel1), // jit pixel info augmentation looks a little weird, sorry.
+ addBrightnessInfo(pixel2),
+ isAntialiased(pixel1, data1, 1, verticalPos, horizontalPos, width) ||
+ isAntialiased(pixel2, data2, 2, verticalPos, horizontalPos, width)
+ )){
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+
+ });
+
+ data.misMatchPercentage = (mismatchCount / (height*width) * 100).toFixed(2);
+ data.analysisTime = Date.now() - time;
+
+ data.getImageDataUrl = function(text){
+ var barHeight = 0;
+
+ if(text){
+ barHeight = addLabel(text,context,hiddenCanvas);
+ }
+
+ context.putImageData(imgd, 0, barHeight);
+
+ return hiddenCanvas.toDataURL("image/png");
+ };
+ }
+
+ function addLabel(text, context, hiddenCanvas){
+ var textPadding = 2;
+
+ context.font = '12px sans-serif';
+
+ var textWidth = context.measureText(text).width + textPadding*2;
+ var barHeight = 22;
+
+ if(textWidth > hiddenCanvas.width){
+ hiddenCanvas.width = textWidth;
+ }
+
+ hiddenCanvas.height += barHeight;
+
+ context.fillStyle = "#666";
+ context.fillRect(0,0,hiddenCanvas.width,barHeight -4);
+ context.fillStyle = "#fff";
+ context.fillRect(0,barHeight -4,hiddenCanvas.width, 4);
+
+ context.fillStyle = "#fff";
+ context.textBaseline = "top";
+ context.font = '12px sans-serif';
+ context.fillText(text, textPadding, 1);
+
+ return barHeight;
+ }
+
+ function normalise(img, w, h){
+ var c;
+ var context;
+
+ if(img.height < h || img.width < w){
+ c = document.createElement('canvas');
+ c.width = w;
+ c.height = h;
+ context = c.getContext('2d');
+ context.putImageData(img, 0, 0);
+ return context.getImageData(0, 0, w, h);
+ }
+
+ return img;
+ }
+
+ function compare(one, two){
+
+ function onceWeHaveBoth(){
+ var width;
+ var height;
+ if(images.length === 2){
+ width = images[0].width > images[1].width ? images[0].width : images[1].width;
+ height = images[0].height > images[1].height ? images[0].height : images[1].height;
+
+ if( (images[0].width === images[1].width) && (images[0].height === images[1].height) ){
+ data.isSameDimensions = true;
+ } else {
+ data.isSameDimensions = false;
+ }
+
+ analyseImages( normalise(images[0],width, height), normalise(images[1],width, height), width, height);
+
+ triggerDataUpdate();
+ }
+ }
+
+ images = [];
+ loadImageData(one, onceWeHaveBoth);
+ loadImageData(two, onceWeHaveBoth);
+ }
+
+ function getCompareApi(param){
+
+ var secondFileData,
+ hasMethod = typeof param === 'function';
+
+ if( !hasMethod ){
+ // assume it's file data
+ secondFileData = param;
+ }
+
+ var self = {
+ ignoreNothing: function(){
+
+ tolerance.red = 16;
+ tolerance.green = 16;
+ tolerance.blue = 16;
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreAntialiasing: function(){
+
+ tolerance.red = 32;
+ tolerance.green = 32;
+ tolerance.blue = 32;
+ tolerance.minBrightness = 64;
+ tolerance.maxBrightness = 96;
+
+ ignoreAntialiasing = true;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreColors: function(){
+
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = true;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ onComplete: function( callback ){
+
+ updateCallbackArray.push(callback);
+
+ var wrapper = function(){
+ compare(fileData, secondFileData);
+ };
+
+ wrapper();
+
+ return getCompareApi(wrapper);
+ }
+ };
+
+ return self;
+ }
+
+ return {
+ onComplete: function( callback ){
+ updateCallbackArray.push(callback);
+ loadImageData(fileData, function(imageData, width, height){
+ parseImage(imageData.data, width, height);
+ });
+ },
+ compareTo: function(secondFileData){
+ return getCompareApi(secondFileData);
+ }
+ };
+
+ };
+}(this));
\ No newline at end of file
diff --git a/test/testsuite.js b/test/testsuite.js
deleted file mode 100644
index b486acb..0000000
--- a/test/testsuite.js
+++ /dev/null
@@ -1,36 +0,0 @@
-requirejs.config({
- baseUrl: '/test/unit/'
-});
-
-define(function(require) {
- var testModules = [
- 'Pixi',
- 'Point',
- 'Rectangle',
- 'DisplayObject',
- 'DisplayObjectContainer',
- 'Sprite',
- 'MovieClip',
- 'InteractionManager',
- 'Stage',
- 'utils/Utils',
- 'utils/EventTarget',
- 'utils/Matrix',
- 'utils/Detector',
- 'renderers/WebGLShaders',
- 'renderers/WebGLRenderer',
- 'renderers/WebGLBatch',
- 'renderers/CanvasRenderer',
- 'extras/Strip',
- 'extras/Rope',
- 'textures/BaseTexture',
- 'textures/Texture',
- 'loaders/SpriteSheetLoader',
- 'loaders/AssetLoader'
- ];
-
- // Resolve all testModules and then start the Test Runner.
- require(testModules, function() {
- QUnit.start();
- });
-});
\ No newline at end of file
diff --git a/test/textures/SpriteSheet-Aliens.png b/test/textures/SpriteSheet-Aliens.png
new file mode 100644
index 0000000..210acb1
--- /dev/null
+++ b/test/textures/SpriteSheet-Aliens.png
Binary files differ
diff --git a/test/textures/SpriteSheet-Explosion.png b/test/textures/SpriteSheet-Explosion.png
new file mode 100755
index 0000000..79e1a69
--- /dev/null
+++ b/test/textures/SpriteSheet-Explosion.png
Binary files differ
diff --git a/test/textures/bunny.png b/test/textures/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/textures/bunny.png
Binary files differ
diff --git a/test/unit/DisplayObject.js b/test/unit/DisplayObject.js
deleted file mode 100644
index 5e7e72f..0000000
--- a/test/unit/DisplayObject.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObject');
-});
diff --git a/test/unit/DisplayObjectContainer.js b/test/unit/DisplayObjectContainer.js
deleted file mode 100644
index b323959..0000000
--- a/test/unit/DisplayObjectContainer.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObjectContainer');
-});
diff --git a/test/unit/InteractionManager.js b/test/unit/InteractionManager.js
deleted file mode 100644
index e751f52..0000000
--- a/test/unit/InteractionManager.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('InteractionManager');
-});
diff --git a/test/unit/MovieClip.js b/test/unit/MovieClip.js
deleted file mode 100644
index 37d9446..0000000
--- a/test/unit/MovieClip.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('MovieClip');
-});
diff --git a/test/unit/Pixi.js b/test/unit/Pixi.js
deleted file mode 100644
index 36eee73..0000000
--- a/test/unit/Pixi.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Pixi');
-});
diff --git a/test/unit/Point.js b/test/unit/Point.js
deleted file mode 100644
index 983ff6e..0000000
--- a/test/unit/Point.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Point');
-});
diff --git a/test/unit/Rectangle.js b/test/unit/Rectangle.js
deleted file mode 100644
index 3b439ba..0000000
--- a/test/unit/Rectangle.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Rectangle');
-});
diff --git a/test/unit/Sprite.js b/test/unit/Sprite.js
deleted file mode 100644
index ed4f596..0000000
--- a/test/unit/Sprite.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Sprite');
-});
diff --git a/test/unit/Stage.js b/test/unit/Stage.js
deleted file mode 100644
index 2d70291..0000000
--- a/test/unit/Stage.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Stage');
-});
diff --git a/test/unit/extras/Rope.js b/test/unit/extras/Rope.js
deleted file mode 100644
index 5606f14..0000000
--- a/test/unit/extras/Rope.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Rope');
-});
diff --git a/test/unit/extras/Strip.js b/test/unit/extras/Strip.js
deleted file mode 100644
index 0134d3a..0000000
--- a/test/unit/extras/Strip.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Strip');
-});
diff --git a/test/unit/loaders/AssetLoader.js b/test/unit/loaders/AssetLoader.js
deleted file mode 100644
index 13b8443..0000000
--- a/test/unit/loaders/AssetLoader.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('AssetLoader');
-});
diff --git a/test/unit/loaders/SpriteSheetLoader.js b/test/unit/loaders/SpriteSheetLoader.js
deleted file mode 100644
index 8bf0cb2..0000000
--- a/test/unit/loaders/SpriteSheetLoader.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('SpriteSheetLoader');
-});
diff --git a/test/unit/pixi/InteractionManager.js b/test/unit/pixi/InteractionManager.js
new file mode 100644
index 0000000..ed3001f
--- /dev/null
+++ b/test/unit/pixi/InteractionManager.js
@@ -0,0 +1,10 @@
+describe('pixi/InteractionManager', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var InteractionManager = PIXI.InteractionManager;
+
+ it('Module exists', function () {
+ expect(InteractionManager).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/Pixi.js b/test/unit/pixi/Pixi.js
new file mode 100644
index 0000000..27debc1
--- /dev/null
+++ b/test/unit/pixi/Pixi.js
@@ -0,0 +1,9 @@
+describe('pixi/Pixi', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+
+ it('Module exists', function () {
+ expect(global).to.have.property('PIXI').and.to.be.an('object');
+ });
+});
diff --git a/test/unit/pixi/core/Circle.js b/test/unit/pixi/core/Circle.js
new file mode 100644
index 0000000..93a4456
--- /dev/null
+++ b/test/unit/pixi/core/Circle.js
@@ -0,0 +1,22 @@
+describe('pixi/core/Circle', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Circle = PIXI.Circle;
+
+ it('Module exists', function () {
+ expect(Circle).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Circle();
+
+ expect(obj).to.be.an.instanceof(Circle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', 0);
+ expect(obj).to.have.property('y', 0);
+ expect(obj).to.have.property('radius', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Ellipse.js b/test/unit/pixi/core/Ellipse.js
new file mode 100644
index 0000000..026b56f
--- /dev/null
+++ b/test/unit/pixi/core/Ellipse.js
@@ -0,0 +1,24 @@
+describe('pixi/core/Ellipse', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Ellipse = PIXI.Ellipse;
+
+ it('Module exists', function () {
+ expect(Ellipse).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Ellipse();
+
+ expect(obj).to.be.an.instanceof(Ellipse);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+ expect(obj).to.respondTo('getBounds');
+
+ expect(obj).to.have.property('x', 0);
+ expect(obj).to.have.property('y', 0);
+ expect(obj).to.have.property('width', 0);
+ expect(obj).to.have.property('height', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Matrix.js b/test/unit/pixi/core/Matrix.js
new file mode 100644
index 0000000..b48989e
--- /dev/null
+++ b/test/unit/pixi/core/Matrix.js
@@ -0,0 +1,30 @@
+describe('pixi/core/Matrix', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var mat3 = PIXI.mat3;
+ var mat4 = PIXI.mat4;
+ var Matrix = PIXI.Matrix;
+
+ it('Ensure determineMatrixArrayType works', function () {
+ expect(Matrix).to.be.a('function');
+ });
+
+ it('mat3 exists', function () {
+ expect(mat3).to.be.an('object');
+ });
+
+ it('Confirm new mat3 matrix', function () {
+ var matrix = new mat3.create();
+ pixi_core_Matrix_confirmNewMat3(matrix);
+ });
+
+ it('mat3 exists', function () {
+ expect(mat4).to.be.an('object');
+ });
+
+ it('Confirm new mat4 matrix', function () {
+ var matrix = new mat4.create();
+ pixi_core_Matrix_confirmNewMat4(matrix);
+ });
+});
diff --git a/test/unit/pixi/core/Point.js b/test/unit/pixi/core/Point.js
new file mode 100644
index 0000000..c4d5163
--- /dev/null
+++ b/test/unit/pixi/core/Point.js
@@ -0,0 +1,15 @@
+describe('pixi/core/Point', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Point = PIXI.Point;
+
+ it('Module exists', function () {
+ expect(Point).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Point();
+ pixi_core_Point_confirm(obj, 0, 0);
+ });
+});
diff --git a/test/unit/pixi/core/Polygon.js b/test/unit/pixi/core/Polygon.js
new file mode 100644
index 0000000..dc8c918
--- /dev/null
+++ b/test/unit/pixi/core/Polygon.js
@@ -0,0 +1,20 @@
+describe('pixi/core/Polygon', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Polygon = PIXI.Polygon;
+
+ it('Module exists', function () {
+ expect(Polygon).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Polygon();
+
+ expect(obj).to.be.an.instanceof(Polygon);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.deep.property('points.length', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Rectangle.js b/test/unit/pixi/core/Rectangle.js
new file mode 100644
index 0000000..d43316e
--- /dev/null
+++ b/test/unit/pixi/core/Rectangle.js
@@ -0,0 +1,15 @@
+describe('pixi/core/Rectangle', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Rectangle = PIXI.Rectangle;
+
+ it('Module exists', function () {
+ expect(Rectangle).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var rect = new Rectangle();
+ pixi_core_Rectangle_confirm(rect, 0, 0, 0, 0);
+ });
+});
diff --git a/test/unit/pixi/display/DisplayObject.js b/test/unit/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..40c6fbc
--- /dev/null
+++ b/test/unit/pixi/display/DisplayObject.js
@@ -0,0 +1,21 @@
+describe('pixi/display/DisplayObject', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var DisplayObject = PIXI.DisplayObject;
+
+ it('Module exists', function () {
+ expect(DisplayObject).to.be.a('function');
+ expect(PIXI).to.have.property('visibleCount', 0);
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new DisplayObject();
+
+ pixi_display_DisplayObject_confirmNew(obj);
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', false);
+ expect(obj).to.have.property('stage', null);
+ });
+});
diff --git a/test/unit/pixi/display/DisplayObjectContainer.js b/test/unit/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..ce7f02f
--- /dev/null
+++ b/test/unit/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,20 @@
+describe('pixi/display/DisplayObjectContainer', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var DisplayObjectContainer = PIXI.DisplayObjectContainer;
+
+ it('Module exists', function () {
+ expect(DisplayObjectContainer).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new DisplayObjectContainer();
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', false);
+ expect(obj).to.have.property('stage', null);
+ });
+});
diff --git a/test/unit/pixi/display/MovieClip.js b/test/unit/pixi/display/MovieClip.js
new file mode 100644
index 0000000..f3c6c6a
--- /dev/null
+++ b/test/unit/pixi/display/MovieClip.js
@@ -0,0 +1,33 @@
+describe('pixi/display/MovieClip', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var MovieClip = PIXI.MovieClip;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(MovieClip).to.be.a('function');
+ });
+
+ it('Confirm new instance', function (done) {
+ var texture = Texture.fromImage('/base/test/textures/SpriteSheet-Explosion.png');
+ var obj = new MovieClip([texture]);
+
+ pixi_display_Sprite_confirmNew(obj, done);
+
+ expect(obj).to.be.an.instanceof(MovieClip);
+ expect(obj).to.respondTo('stop');
+ expect(obj).to.respondTo('play');
+ expect(obj).to.respondTo('gotoAndStop');
+ expect(obj).to.respondTo('gotoAndPlay');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('textures.length', 1);
+ expect(obj).to.have.deep.property('textures[0]', texture);
+ expect(obj).to.have.property('animationSpeed', 1);
+ expect(obj).to.have.property('loop', true);
+ expect(obj).to.have.property('onComplete', null);
+ expect(obj).to.have.property('currentFrame', 0);
+ expect(obj).to.have.property('playing', false);
+ });
+});
diff --git a/test/unit/pixi/display/Sprite.js b/test/unit/pixi/display/Sprite.js
new file mode 100644
index 0000000..54e914f
--- /dev/null
+++ b/test/unit/pixi/display/Sprite.js
@@ -0,0 +1,25 @@
+describe('pixi/display/Sprite', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Sprite = PIXI.Sprite;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(Sprite).to.be.a('function');
+ expect(PIXI).to.have.deep.property('blendModes.NORMAL', 0);
+ expect(PIXI).to.have.deep.property('blendModes.SCREEN', 1);
+ });
+
+ it('Members exist', function () {
+ expect(Sprite).itself.to.respondTo('fromImage');
+ expect(Sprite).itself.to.respondTo('fromFrame');
+ });
+
+ it('Confirm new instance', function (done) {
+ var texture = Texture.fromImage('/base/test/textures/SpriteSheet-Aliens.png');
+ var obj = new Sprite(texture);
+
+ pixi_display_Sprite_confirmNew(obj, done);
+ });
+});
diff --git a/test/unit/pixi/display/Stage.js b/test/unit/pixi/display/Stage.js
new file mode 100644
index 0000000..3cc2a4d
--- /dev/null
+++ b/test/unit/pixi/display/Stage.js
@@ -0,0 +1,49 @@
+describe('pixi/display/Stage', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Stage = PIXI.Stage;
+ var InteractionManager = PIXI.InteractionManager;
+ var Rectangle = PIXI.Rectangle;
+
+ it('Module exists', function () {
+ expect(Stage).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Stage(null, true);
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(Stage);
+ expect(obj).to.respondTo('updateTransform');
+ expect(obj).to.respondTo('setBackgroundColor');
+ expect(obj).to.respondTo('getMousePosition');
+
+ // FIXME: duplicate member in DisplayObject
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ // FIXME: convert arg to bool in constructor
+ expect(obj).to.have.property('interactive', true);
+
+ expect(obj).to.have.property('interactionManager')
+ .and.to.be.an.instanceof(InteractionManager)
+ .and.to.have.property('stage', obj);
+
+ expect(obj).to.have.property('dirty', true);
+
+ expect(obj).to.have.property('stage', obj);
+
+ expect(obj).to.have.property('hitArea')
+ .and.to.be.an.instanceof(Rectangle);
+ pixi_core_Rectangle_confirm(obj.hitArea, 0, 0, 100000, 100000);
+
+ expect(obj).to.have.property('backgroundColor', 0x000000);
+ expect(obj).to.have.deep.property('backgroundColorSplit.length', 3);
+ expect(obj).to.have.deep.property('backgroundColorSplit[0]', 0);
+ expect(obj).to.have.deep.property('backgroundColorSplit[1]', 0);
+ expect(obj).to.have.deep.property('backgroundColorSplit[2]', 0);
+ expect(obj).to.have.property('backgroundColorString', '#000000');
+
+ expect(obj).to.have.property('worldVisible', true);
+ });
+});
diff --git a/test/unit/pixi/extras/CustomRenderable.js b/test/unit/pixi/extras/CustomRenderable.js
new file mode 100644
index 0000000..8d83cf0
--- /dev/null
+++ b/test/unit/pixi/extras/CustomRenderable.js
@@ -0,0 +1,21 @@
+describe('pixi/extras/CustomRenderable', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var CustomRenderable = PIXI.CustomRenderable;
+
+ it('Module exists', function () {
+ expect(CustomRenderable).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new CustomRenderable();
+
+ pixi_display_DisplayObject_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(CustomRenderable);
+ expect(obj).to.respondTo('renderCanvas');
+ expect(obj).to.respondTo('initWebGL');
+ expect(obj).to.respondTo('renderWebGL');
+ });
+});
diff --git a/test/unit/pixi/extras/Rope.js b/test/unit/pixi/extras/Rope.js
new file mode 100644
index 0000000..6ddaf83
--- /dev/null
+++ b/test/unit/pixi/extras/Rope.js
@@ -0,0 +1,26 @@
+describe('pixi/extras/Rope', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Rope = PIXI.Rope;
+ var Texture = PIXI.Texture;
+ var Point = PIXI.Point;
+
+ it('Module exists', function () {
+ expect(Rope).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var texture = Texture.fromImage('/base/test/textures/bunny.png');
+ var obj = new Rope(texture, [new Point(), new Point(5, 10), new Point(10, 20)]);
+
+ pixi_extras_Strip_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(Rope);
+ expect(obj).to.respondTo('refresh');
+ expect(obj).to.respondTo('updateTransform');
+ expect(obj).to.respondTo('setTexture');
+
+ // TODO: Test properties
+ });
+});
diff --git a/test/unit/pixi/extras/Spine.js b/test/unit/pixi/extras/Spine.js
new file mode 100644
index 0000000..0708bc0
--- /dev/null
+++ b/test/unit/pixi/extras/Spine.js
@@ -0,0 +1,10 @@
+describe('pixi/extras/Spine', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Spine = PIXI.Spine;
+
+ it('Module exists', function () {
+ expect(Spine).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/extras/Strip.js b/test/unit/pixi/extras/Strip.js
new file mode 100644
index 0000000..8e564e1
--- /dev/null
+++ b/test/unit/pixi/extras/Strip.js
@@ -0,0 +1,18 @@
+describe('pixi/extras/Strip', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Strip = PIXI.Strip;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(Strip).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var texture = Texture.fromImage('/base/test/textures/bunny.png');
+ var obj = new Strip(texture, 20, 10000);
+
+ pixi_extras_Strip_confirmNew(obj);
+ });
+});
diff --git a/test/unit/pixi/extras/TilingSprite.js b/test/unit/pixi/extras/TilingSprite.js
new file mode 100644
index 0000000..56aea14
--- /dev/null
+++ b/test/unit/pixi/extras/TilingSprite.js
@@ -0,0 +1,24 @@
+describe('pixi/extras/TilingSprite', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var TilingSprite = PIXI.TilingSprite;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(TilingSprite).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var texture = Texture.fromImage('/base/test/textures/bunny.png');
+ var obj = new TilingSprite(texture, 6000, 12000);
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(TilingSprite);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ // TODO: Test properties
+ });
+});
diff --git a/test/unit/pixi/filters/FilterBlock.js b/test/unit/pixi/filters/FilterBlock.js
new file mode 100644
index 0000000..870cec0
--- /dev/null
+++ b/test/unit/pixi/filters/FilterBlock.js
@@ -0,0 +1,10 @@
+describe('pixi/filters/FilterBlock', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var FilterBlock = PIXI.FilterBlock;
+
+ it('Module exists', function () {
+ expect(FilterBlock).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/filters/MaskFilter.js b/test/unit/pixi/filters/MaskFilter.js
new file mode 100644
index 0000000..32d6a45
--- /dev/null
+++ b/test/unit/pixi/filters/MaskFilter.js
@@ -0,0 +1,10 @@
+describe('pixi/filters/MaskFilter', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ // var MaskFilter = PIXI.MaskFilter;
+
+ // it('Module exists', function () {
+ // expect(MaskFilter).to.be.a('function');
+ // });
+});
diff --git a/test/unit/pixi/loaders/AssetLoader.js b/test/unit/pixi/loaders/AssetLoader.js
new file mode 100644
index 0000000..a0aa0b5
--- /dev/null
+++ b/test/unit/pixi/loaders/AssetLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/AssetLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var AssetLoader = PIXI.AssetLoader;
+
+ it('Module exists', function () {
+ expect(AssetLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/BitmapFontLoader.js b/test/unit/pixi/loaders/BitmapFontLoader.js
new file mode 100644
index 0000000..6253c42
--- /dev/null
+++ b/test/unit/pixi/loaders/BitmapFontLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/BitmapFontLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var BitmapFontLoader = PIXI.BitmapFontLoader;
+
+ it('Module exists', function () {
+ expect(PIXI.BitmapFontLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/ImageLoader.js b/test/unit/pixi/loaders/ImageLoader.js
new file mode 100644
index 0000000..8b1f556
--- /dev/null
+++ b/test/unit/pixi/loaders/ImageLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/ImageLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var ImageLoader = PIXI.ImageLoader;
+
+ it('Module exists', function () {
+ expect(ImageLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/JsonLoader.js b/test/unit/pixi/loaders/JsonLoader.js
new file mode 100644
index 0000000..c577e83
--- /dev/null
+++ b/test/unit/pixi/loaders/JsonLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/JsonLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var JsonLoader = PIXI.JsonLoader;
+
+ it('Module exists', function () {
+ expect(JsonLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/SpineLoader.js b/test/unit/pixi/loaders/SpineLoader.js
new file mode 100644
index 0000000..fdcc0b8
--- /dev/null
+++ b/test/unit/pixi/loaders/SpineLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/SpineLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var SpineLoader = PIXI.SpineLoader;
+
+ it('Module exists', function () {
+ expect(SpineLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/SpriteSheetLoader.js b/test/unit/pixi/loaders/SpriteSheetLoader.js
new file mode 100644
index 0000000..57beb27
--- /dev/null
+++ b/test/unit/pixi/loaders/SpriteSheetLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/SpriteSheetLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var SpriteSheetLoader = PIXI.SpriteSheetLoader;
+
+ it('Module exists', function () {
+ expect(SpriteSheetLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/primitives/Graphics.js b/test/unit/pixi/primitives/Graphics.js
new file mode 100644
index 0000000..b8b3e5c
--- /dev/null
+++ b/test/unit/pixi/primitives/Graphics.js
@@ -0,0 +1,40 @@
+describe('pixi/primitives/Graphics', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Graphics = PIXI.Graphics;
+
+ it('Module exists', function () {
+ expect(Graphics).to.be.a('function');
+
+ expect(Graphics).itself.to.have.property('POLY', 0);
+ expect(Graphics).itself.to.have.property('RECT', 1);
+ expect(Graphics).itself.to.have.property('CIRC', 2);
+ expect(Graphics).itself.to.have.property('ELIP', 3);
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Graphics();
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(Graphics);
+ expect(obj).to.respondTo('lineStyle');
+ expect(obj).to.respondTo('lineStyle');
+ expect(obj).to.respondTo('moveTo');
+ expect(obj).to.respondTo('lineTo');
+ expect(obj).to.respondTo('beginFill');
+ expect(obj).to.respondTo('endFill');
+ expect(obj).to.respondTo('drawRect');
+ expect(obj).to.respondTo('drawCircle');
+ expect(obj).to.respondTo('drawElipse');
+ expect(obj).to.respondTo('clear');
+
+ expect(obj).to.have.property('renderable', true);
+ expect(obj).to.have.property('fillAlpha', 1);
+ expect(obj).to.have.property('lineWidth', 0);
+ expect(obj).to.have.property('lineColor', 'black');
+ expect(obj).to.have.deep.property('graphicsData.length', 0);
+ expect(obj).to.have.deep.property('currentPath.points.length', 0);
+ });
+});
diff --git a/test/unit/pixi/renderers/canvas/CanvasGraphics.js b/test/unit/pixi/renderers/canvas/CanvasGraphics.js
new file mode 100644
index 0000000..8f44472
--- /dev/null
+++ b/test/unit/pixi/renderers/canvas/CanvasGraphics.js
@@ -0,0 +1,15 @@
+describe('renders/canvas/CanvasGraphics', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var CanvasGraphics = PIXI.CanvasGraphics;
+
+ it('Module exists', function () {
+ expect(CanvasGraphics).to.be.a('function');
+ });
+
+ it('Members exist', function () {
+ expect(CanvasGraphics).itself.to.respondTo('renderGraphics');
+ expect(CanvasGraphics).itself.to.respondTo('renderGraphicsMask');
+ });
+});
diff --git a/test/unit/pixi/renderers/canvas/CanvasRenderer.js b/test/unit/pixi/renderers/canvas/CanvasRenderer.js
new file mode 100644
index 0000000..df3a12f
--- /dev/null
+++ b/test/unit/pixi/renderers/canvas/CanvasRenderer.js
@@ -0,0 +1,10 @@
+describe('renderers/canvas/CanvasRenderer', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var CanvasRenderer = PIXI.CanvasRenderer;
+
+ it('Module exists', function () {
+ expect(CanvasRenderer).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/renderers/webgl/WebGLBatch.js b/test/unit/pixi/renderers/webgl/WebGLBatch.js
new file mode 100644
index 0000000..75efd56
--- /dev/null
+++ b/test/unit/pixi/renderers/webgl/WebGLBatch.js
@@ -0,0 +1,10 @@
+describe('renderers/webgl/WebGLBatch', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var WebGLBatch = PIXI.WebGLBatch;
+
+ it('Module exists', function () {
+ expect(WebGLBatch).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/renderers/webgl/WebGLGraphics.js b/test/unit/pixi/renderers/webgl/WebGLGraphics.js
new file mode 100644
index 0000000..41bf941
--- /dev/null
+++ b/test/unit/pixi/renderers/webgl/WebGLGraphics.js
@@ -0,0 +1,19 @@
+describe('renderers/wegbl/WebGLGraphics', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var WebGLGraphics = PIXI.WebGLGraphics;
+
+ it('Module exists', function () {
+ expect(WebGLGraphics).to.be.a('function');
+ });
+
+ it('Members exist', function () {
+ expect(WebGLGraphics).itself.to.respondTo('renderGraphics');
+ expect(WebGLGraphics).itself.to.respondTo('updateGraphics');
+ expect(WebGLGraphics).itself.to.respondTo('buildRectangle');
+ expect(WebGLGraphics).itself.to.respondTo('buildCircle');
+ expect(WebGLGraphics).itself.to.respondTo('buildLine');
+ expect(WebGLGraphics).itself.to.respondTo('buildPoly');
+ });
+});
diff --git a/test/unit/pixi/renderers/webgl/WebGLRenderGroup.js b/test/unit/pixi/renderers/webgl/WebGLRenderGroup.js
new file mode 100644
index 0000000..f4ee366
--- /dev/null
+++ b/test/unit/pixi/renderers/webgl/WebGLRenderGroup.js
@@ -0,0 +1,10 @@
+describe('renderers/webgl/WebGLRenderGroup', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var WebGLRenderGroup = PIXI.WebGLRenderGroup;
+
+ it('Module exists', function () {
+ expect(WebGLRenderGroup).to.be.a('function');
+ });
+});
diff --git a/.gitignore b/.gitignore
index 12e1b62..0b88317 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
node_modules
.DS_Store
-.project
\ No newline at end of file
+.project
+*.log
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..63e4d7c
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,8 @@
+language: node_js
+node_js:
+ - 0.10
+
+before_script:
+ - npm install -g grunt-cli
+ - export DISPLAY=:99.0
+ - sh -e /etc/init.d/xvfb start
diff --git a/Gruntfile.js b/Gruntfile.js
index b083b49..103938c 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -1,10 +1,12 @@
+'use strict';
+
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-connect');
- grunt.loadNpmTasks('grunt-contrib-qunit');
grunt.loadNpmTasks('grunt-contrib-yuidoc');
+ grunt.loadTasks('tasks');
var root = 'src/pixi/',
debug = 'bin/pixi.dev.js',
@@ -79,7 +81,7 @@
},
files: {
srcBlob: '<%= dirs.src %>/**/*.js',
- testBlob: '<%= dirs.test %>/unit/**/*.js',
+ testBlob: '<%= dirs.test %>/{functional,lib/pixi,unit}/**/*.js',
build: '<%= dirs.build %>/pixi.dev.js',
buildMin: '<%= dirs.build %>/pixi.js'
},
@@ -94,7 +96,12 @@
},
jshint: {
beforeconcat: srcFiles,
- test: ['<%= files.testBlob %>'],
+ test: {
+ src: ['<%= files.testBlob %>'],
+ options: {
+ expr: true
+ }
+ },
options: {
asi: true,
smarttabs: true
@@ -128,12 +135,6 @@
]
},
connect: {
- qunit: {
- options: {
- port: grunt.option('port-test') || 9002,
- base: './'
- }
- },
test: {
options: {
port: grunt.option('port-test') || 9002,
@@ -142,13 +143,6 @@
}
}
},
- qunit: {
- all: {
- options: {
- urls: ['http://localhost:' + (grunt.option('port-test') || 9002) + '/test/index.html']
- }
- }
- },
yuidoc: {
compile: {
name: '<%= pkg.name %>',
@@ -161,6 +155,13 @@
outdir: '<%= dirs.docs %>'
}
}
+ },
+ karma: {
+ unit: {
+ configFile: 'test/karma.conf.js',
+ // browsers: ['Chrome'],
+ singleRun: true
+ }
}
});
@@ -182,9 +183,10 @@
}
)
- grunt.registerTask('default', ['concat', 'uglify', 'distribute']);
grunt.registerTask('build', ['concat', 'uglify', 'distribute']);
- grunt.registerTask('test', ['build', 'connect:qunit', 'qunit']);
+ grunt.registerTask('test', ['concat', 'jshint:test', 'karma']);
grunt.registerTask('docs', ['yuidoc']);
-
-}
\ No newline at end of file
+ grunt.registerTask('default', ['test', 'uglify', 'distribute']);
+ // Travis CI task.
+ grunt.registerTask('travis', ['test']);
+}
diff --git a/README.md b/README.md
index c62ef86..690cfe4 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,8 @@

+[](http://travis-ci.org/drkibitz/pixi.js)
+
#### JavaScript 2D Renderer ####
The aim of this project is to provide a fast lightweight 2D library that works
diff --git a/package.json b/package.json
index b373240..1246a68 100644
--- a/package.json
+++ b/package.json
@@ -18,14 +18,21 @@
"main": "bin/pixi.js",
+ "scripts": {
+ "test": "grunt travis --verbose"
+ },
+
"dependencies": {},
"devDependencies": {
"grunt": "~0.4.x",
- "grunt-contrib-jshint": "0.3.x",
+ "grunt-contrib-jshint": "0.6.x",
"grunt-contrib-uglify": "0.2.x",
- "grunt-contrib-connect": "0.2.x",
- "grunt-contrib-qunit": "0.2.x",
+ "grunt-contrib-connect": "0.3.x",
"grunt-contrib-yuidoc": "0.4.x",
- "grunt-contrib-concat": "0.1.x"
+ "grunt-contrib-concat": "0.3.x",
+ "chai": "~1.7.0",
+ "karma": "0.11.0",
+ "karma-firefox-launcher": "0.1.0",
+ "karma-mocha": "0.1.0"
}
}
diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js
index a7c520e..ee82bbd 100644
--- a/src/pixi/InteractionManager.js
+++ b/src/pixi/InteractionManager.js
@@ -62,7 +62,6 @@
this.onTouchEnd = this.onTouchEnd.bind(this);
this.onTouchMove = this.onTouchMove.bind(this);
-
this.last = 0;
}
diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js
index 1a95d20..eef1059 100644
--- a/src/pixi/core/Ellipse.js
+++ b/src/pixi/core/Ellipse.js
@@ -78,7 +78,7 @@
return (normx + normy < 0.25);
}
-PIXI.Ellipse.getBounds = function()
+PIXI.Ellipse.prototype.getBounds = function()
{
return new PIXI.Rectangle(this.x, this.y, this.width, this.height);
}
diff --git a/tasks/karma.js b/tasks/karma.js
new file mode 100644
index 0000000..c340485
--- /dev/null
+++ b/tasks/karma.js
@@ -0,0 +1,27 @@
+'use strict';
+
+var path = require('path');
+var server = require('karma').server;
+
+module.exports = function (grunt) {
+ grunt.registerMultiTask('karma', 'run karma.', function() {
+ var done = this.async();
+ var options = this.options({
+ background: false
+ });
+ var data = this.data;
+
+ //merge options onto data, with data taking precedence
+ data = grunt.util._.merge(options, data);
+ data.configFile = path.resolve(data.configFile);
+ if (data.configFile) {
+ data.configFile = grunt.template.process(data.configFile);
+ }
+
+ server.start(
+ data,
+ function(code) {
+ done(!code);
+ });
+ });
+};
diff --git a/test/functional/example-1-basics/bunny.png b/test/functional/example-1-basics/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/functional/example-1-basics/bunny.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-30.png b/test/functional/example-1-basics/frame-30.png
new file mode 100644
index 0000000..96e3409
--- /dev/null
+++ b/test/functional/example-1-basics/frame-30.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-60.png b/test/functional/example-1-basics/frame-60.png
new file mode 100644
index 0000000..af3f4ce
--- /dev/null
+++ b/test/functional/example-1-basics/frame-60.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-90.png b/test/functional/example-1-basics/frame-90.png
new file mode 100644
index 0000000..099b823
--- /dev/null
+++ b/test/functional/example-1-basics/frame-90.png
Binary files differ
diff --git a/test/functional/example-1-basics/index.js b/test/functional/example-1-basics/index.js
new file mode 100644
index 0000000..7ae7a98
--- /dev/null
+++ b/test/functional/example-1-basics/index.js
@@ -0,0 +1,133 @@
+describe('Example 1 - Basics', function () {
+ 'use strict';
+
+ var baseUri = '/base/test/functional/example-1-basics';
+ var expect = chai.expect;
+ var currentFrame = 0;
+ var frameEvents = {};
+ var stage;
+ var renderer;
+ var bunny;
+
+ function onFrame(frame, callback) {
+ frameEvents[frame] = callback;
+ }
+
+ function animate() {
+ currentFrame += 1;
+
+ requestAnimFrame( animate );
+
+ // just for fun, lets rotate mr rabbit a little
+ bunny.rotation += 0.1;
+
+ // render the stage
+ renderer.render(stage);
+
+ if (frameEvents[currentFrame])
+ frameEvents[currentFrame](currentFrame);
+ }
+
+ function initScene() {
+ // create an new instance of a pixi stage
+ stage = new PIXI.Stage(0x66FF99);
+
+ // create a renderer instance
+ renderer = PIXI.autoDetectRenderer(400, 300);
+ console.log('Is PIXI.WebGLRenderer: ' + (renderer instanceof PIXI.WebGLRenderer));
+
+ // add the renderer view element to the DOM
+ document.body.appendChild(renderer.view);
+
+ requestAnimFrame( animate );
+
+ // create a texture from an image path
+ var texture = PIXI.Texture.fromImage(baseUri + "/bunny.png");
+ // create a new Sprite using the texture
+ bunny = new PIXI.Sprite(texture);
+
+ // center the sprites anchor point
+ bunny.anchor.x = 0.5;
+ bunny.anchor.y = 0.5;
+
+ // move the sprite t the center of the screen
+ bunny.position.x = 200;
+ bunny.position.y = 150;
+
+ stage.addChild(bunny);
+ }
+
+ it('assets loaded', function (done) {
+ var loader = new PIXI.AssetLoader([
+ baseUri + '/bunny.png',
+ baseUri + '/frame-30.png',
+ baseUri + '/frame-60.png',
+ baseUri + '/frame-90.png'
+ ]);
+ // loader.on('onProgress', function (event) {
+ // console.log(event.content);
+ // });
+ loader.on('onComplete', function (event) {
+ done();
+ initScene();
+ });
+ loader.load();
+ });
+
+ it('frame 30 should match', function (done) {
+ this.timeout(700);
+ onFrame(30, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-30.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 60 should match', function (done) {
+ this.timeout(1200);
+ onFrame(60, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-60.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 90 should match', function (done) {
+ this.timeout(1700);
+ onFrame(90, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-90.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ // it('capture something', function (done) {
+ // this.timeout(2000000);
+ // onFrame(30, function () {
+ // var img = new Image();
+ // img.src = renderer.view.toDataURL('image/png');
+ // document.body.appendChild(img);
+ // });
+ // });
+});
diff --git a/test/index.html b/test/index.html
deleted file mode 100644
index 9cbcac5..0000000
--- a/test/index.html
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
- Pixi.js Test Suite
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/test/karma.conf.js b/test/karma.conf.js
new file mode 100644
index 0000000..c66a696
--- /dev/null
+++ b/test/karma.conf.js
@@ -0,0 +1,82 @@
+module.exports = function(config) {
+ config.set({
+
+ // base path, that will be used to resolve files and exclude
+ basePath : '../',
+
+ frameworks : ['mocha'],
+
+ // list of files / patterns to load in the browser
+ files : [
+ 'node_modules/chai/chai.js',
+ 'bin/pixi.dev.js',
+ 'test/lib/**/*.js',
+ 'test/unit/**/*.js',
+ // 'test/functional/**/*.js',
+ {pattern: 'test/**/*.png', watched: false, included: false, served: true}
+ ],
+
+ // list of files to exclude
+ exclude : [],
+
+ // use dolts reporter, as travis terminal does not support escaping sequences
+ // possible values: 'dots', 'progress', 'junit', 'teamcity'
+ // CLI --reporters progress
+ reporters : ['progress'],
+
+ // web server port
+ // CLI --port 9876
+ port : 9876,
+
+ // cli runner port
+ // CLI --runner-port 9100
+ runnerPort : 9100,
+
+ // enable / disable colors in the output (reporters and logs)
+ // CLI --colors --no-colors
+ colors : true,
+
+ // level of logging
+ // possible values: karma.LOG_DISABLE || karma.LOG_ERROR || karma.LOG_WARN || karma.LOG_INFO || karma.LOG_DEBUG
+ // CLI --log-level debug
+ logLevel : config.LOG_DEBUG,
+
+ // enable / disable watching file and executing tests whenever any file changes
+ // CLI --auto-watch --no-auto-watch
+ autoWatch : false,
+
+ // Start these browsers, currently available:
+ // - Chrome
+ // - ChromeCanary
+ // - Firefox
+ // - Opera
+ // - Safari (only Mac)
+ // - PhantomJS
+ // - IE (only Windows)
+ // CLI --browsers Chrome,Firefox,Safari
+ browsers : ['Firefox'],
+
+ // If browser does not capture in given timeout [ms], kill it
+ // CLI --capture-timeout 5000
+ captureTimeout : 5000,
+
+ // Auto run tests on start (when browsers are captured) and exit
+ // CLI --single-run --no-single-run
+ singleRun : true,
+
+ // report which specs are slower than 500ms
+ // CLI --report-slower-than 500
+ reportSlowerThan : 1000,
+
+ preprocessors : {
+ // '**/client/js/*.js': 'coverage'
+ },
+
+ plugins : [
+ 'karma-mocha',
+ // 'karma-chrome-launcher',
+ 'karma-firefox-launcher',
+ // 'karma-phantomjs-launcher'
+ ]
+ });
+};
diff --git a/test/lib/pixi/core/Matrix.js b/test/lib/pixi/core/Matrix.js
new file mode 100644
index 0000000..d26386b
--- /dev/null
+++ b/test/lib/pixi/core/Matrix.js
@@ -0,0 +1,40 @@
+
+function pixi_core_Matrix_confirmNewMat3(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(1);
+ expect(matrix[5]).to.equal(0);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(1);
+}
+
+function pixi_core_Matrix_confirmNewMat4(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[0]).to.equal(1);
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(0);
+ expect(matrix[5]).to.equal(1);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(0);
+ expect(matrix[9]).to.equal(0);
+ expect(matrix[10]).to.equal(1);
+ expect(matrix[11]).to.equal(0);
+ expect(matrix[12]).to.equal(0);
+ expect(matrix[13]).to.equal(0);
+ expect(matrix[14]).to.equal(0);
+ expect(matrix[15]).to.equal(1);
+}
diff --git a/test/lib/pixi/core/Point.js b/test/lib/pixi/core/Point.js
new file mode 100644
index 0000000..e5df07b
--- /dev/null
+++ b/test/lib/pixi/core/Point.js
@@ -0,0 +1,10 @@
+
+function pixi_core_Point_confirm(obj, x, y) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Point);
+ expect(obj).to.respondTo('clone');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+}
diff --git a/test/lib/pixi/core/Rectangle.js b/test/lib/pixi/core/Rectangle.js
new file mode 100644
index 0000000..23f0d12
--- /dev/null
+++ b/test/lib/pixi/core/Rectangle.js
@@ -0,0 +1,13 @@
+
+function pixi_core_Rectangle_confirm(obj, x, y, width, height) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Rectangle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+ expect(obj).to.have.property('width', width);
+ expect(obj).to.have.property('height', height);
+}
diff --git a/test/lib/pixi/display/DisplayObject.js b/test/lib/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..1388a7f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObject.js
@@ -0,0 +1,43 @@
+
+function pixi_display_DisplayObject_confirmNew(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObject);
+ expect(obj).to.respondTo('setInteractive');
+ expect(obj).to.respondTo('addFilter');
+ expect(obj).to.respondTo('removeFilter');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.property('last', obj);
+ expect(obj).to.have.property('first', obj);
+
+ expect(obj).to.contain.property('position');
+ pixi_core_Point_confirm(obj.position, 0, 0);
+ expect(obj).to.contain.property('scale');
+ pixi_core_Point_confirm(obj.scale, 1, 1);
+ expect(obj).to.contain.property('pivot');
+ pixi_core_Point_confirm(obj.pivot, 0, 0);
+
+ expect(obj).to.have.property('rotation', 0);
+ expect(obj).to.have.property('alpha', 1);
+ expect(obj).to.have.property('visible', true);
+ expect(obj).to.have.property('buttonMode', false);
+ expect(obj).to.have.property('parent', null);
+ expect(obj).to.have.property('worldAlpha', 1);
+
+ expect(obj).to.have.property('hitArea');
+ expect(obj).to.have.property('interactive'); // TODO: Have a better default value
+ expect('mask' in obj).to.be.true; // TODO: Have a better default value
+ expect(obj.mask).to.be.undefined;
+
+ expect(obj).to.have.property('renderable');
+ expect(obj).to.have.property('stage');
+
+ expect(obj).to.have.deep.property('worldTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ expect(obj).to.have.deep.property('localTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.localTransform);
+
+ expect(obj).to.have.deep.property('color.length', 0);
+ expect(obj).to.have.property('dynamic', true);
+}
diff --git a/test/lib/pixi/display/DisplayObjectContainer.js b/test/lib/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..085c59f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,16 @@
+
+function pixi_display_DisplayObjectContainer_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObject_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObjectContainer);
+ expect(obj).to.respondTo('addChild');
+ expect(obj).to.respondTo('addChildAt');
+ expect(obj).to.respondTo('swapChildren');
+ expect(obj).to.respondTo('getChildAt');
+ expect(obj).to.respondTo('removeChild');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('children.length', 0);
+}
diff --git a/test/lib/pixi/display/Sprite.js b/test/lib/pixi/display/Sprite.js
new file mode 100644
index 0000000..cc7a2d6
--- /dev/null
+++ b/test/lib/pixi/display/Sprite.js
@@ -0,0 +1,28 @@
+
+function pixi_display_Sprite_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Sprite);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', true);
+ expect(obj).to.have.property('stage', null);
+
+ expect(obj).to.have.property('anchor');
+ pixi_core_Point_confirm(obj.anchor, 0, 0);
+
+ expect(obj).to.have.property('blendMode', PIXI.blendModes.NORMAL);
+ expect(obj).to.have.property('width', 1); // TODO: is 1 expected
+ expect(obj).to.have.property('height', 1); // TODO: is 1 expected
+
+ // FIXME: Just make this a boolean that is always there
+ expect(!!obj.updateFrame).to.equal(obj.texture.baseTexture.hasLoaded);
+
+ expect(obj).to.have.property('texture');
+ pixi_textures_Texture_confirmNew(obj.texture, done);
+}
diff --git a/test/lib/pixi/extras/Strip.js b/test/lib/pixi/extras/Strip.js
new file mode 100644
index 0000000..8927a8a
--- /dev/null
+++ b/test/lib/pixi/extras/Strip.js
@@ -0,0 +1,12 @@
+
+function pixi_extras_Strip_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Strip);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ // TODO: Test properties
+}
diff --git a/test/lib/pixi/textures/Texture.js b/test/lib/pixi/textures/Texture.js
new file mode 100644
index 0000000..d5867b6
--- /dev/null
+++ b/test/lib/pixi/textures/Texture.js
@@ -0,0 +1,31 @@
+
+function pixi_textures_Texture_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ function confirmFrameDone() {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, obj.baseTexture.width, obj.baseTexture.height);
+
+ expect(obj).to.have.property('width', obj.baseTexture.width);
+ expect(obj).to.have.property('height', obj.baseTexture.height);
+ done();
+ }
+
+ expect(obj).to.be.an.instanceof(PIXI.Texture);
+ pixi_utils_EventTarget_like(obj);
+
+ expect(obj).to.have.property('baseTexture')
+ .and.to.be.an.instanceof(PIXI.BaseTexture);
+
+ expect(obj).to.have.property('scope', obj);
+
+ expect(obj).to.have.property('trim');
+ pixi_core_Point_confirm(obj.trim, 0, 0);
+
+ expect(obj).to.have.property('frame');
+ if (obj.baseTexture.hasLoaded) {
+ confirmFrameDone();
+ } else {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, 1, 1);
+ obj.addEventListener('update', confirmFrameDone);
+ }
+}
diff --git a/test/lib/pixi/utils/EventTarget.js b/test/lib/pixi/utils/EventTarget.js
new file mode 100644
index 0000000..7b1dcfa
--- /dev/null
+++ b/test/lib/pixi/utils/EventTarget.js
@@ -0,0 +1,8 @@
+
+function pixi_utils_EventTarget_like(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.respondTo('addEventListener');
+ expect(obj).to.respondTo('dispatchEvent');
+ expect(obj).to.respondTo('removeEventListener');
+}
diff --git a/test/lib/qunit-1.11.0.css b/test/lib/qunit-1.11.0.css
deleted file mode 100644
index d7fc0c8..0000000
--- a/test/lib/qunit-1.11.0.css
+++ /dev/null
@@ -1,244 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-/** Font Family and Sizes */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
- font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
-}
-
-#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
-#qunit-tests { font-size: smaller; }
-
-
-/** Resets */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter {
- margin: 0;
- padding: 0;
-}
-
-
-/** Header */
-
-#qunit-header {
- padding: 0.5em 0 0.5em 1em;
-
- color: #8699a4;
- background-color: #0d3349;
-
- font-size: 1.5em;
- line-height: 1em;
- font-weight: normal;
-
- border-radius: 5px 5px 0 0;
- -moz-border-radius: 5px 5px 0 0;
- -webkit-border-top-right-radius: 5px;
- -webkit-border-top-left-radius: 5px;
-}
-
-#qunit-header a {
- text-decoration: none;
- color: #c2ccd1;
-}
-
-#qunit-header a:hover,
-#qunit-header a:focus {
- color: #fff;
-}
-
-#qunit-testrunner-toolbar label {
- display: inline-block;
- padding: 0 .5em 0 .1em;
-}
-
-#qunit-banner {
- height: 5px;
-}
-
-#qunit-testrunner-toolbar {
- padding: 0.5em 0 0.5em 2em;
- color: #5E740B;
- background-color: #eee;
- overflow: hidden;
-}
-
-#qunit-userAgent {
- padding: 0.5em 0 0.5em 2.5em;
- background-color: #2b81af;
- color: #fff;
- text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
-}
-
-#qunit-modulefilter-container {
- float: right;
-}
-
-/** Tests: Pass/Fail */
-
-#qunit-tests {
- list-style-position: inside;
-}
-
-#qunit-tests li {
- padding: 0.4em 0.5em 0.4em 2.5em;
- border-bottom: 1px solid #fff;
- list-style-position: inside;
-}
-
-#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running {
- display: none;
-}
-
-#qunit-tests li strong {
- cursor: pointer;
-}
-
-#qunit-tests li a {
- padding: 0.5em;
- color: #c2ccd1;
- text-decoration: none;
-}
-#qunit-tests li a:hover,
-#qunit-tests li a:focus {
- color: #000;
-}
-
-#qunit-tests li .runtime {
- float: right;
- font-size: smaller;
-}
-
-.qunit-assert-list {
- margin-top: 0.5em;
- padding: 0.5em;
-
- background-color: #fff;
-
- border-radius: 5px;
- -moz-border-radius: 5px;
- -webkit-border-radius: 5px;
-}
-
-.qunit-collapsed {
- display: none;
-}
-
-#qunit-tests table {
- border-collapse: collapse;
- margin-top: .2em;
-}
-
-#qunit-tests th {
- text-align: right;
- vertical-align: top;
- padding: 0 .5em 0 0;
-}
-
-#qunit-tests td {
- vertical-align: top;
-}
-
-#qunit-tests pre {
- margin: 0;
- white-space: pre-wrap;
- word-wrap: break-word;
-}
-
-#qunit-tests del {
- background-color: #e0f2be;
- color: #374e0c;
- text-decoration: none;
-}
-
-#qunit-tests ins {
- background-color: #ffcaca;
- color: #500;
- text-decoration: none;
-}
-
-/*** Test Counts */
-
-#qunit-tests b.counts { color: black; }
-#qunit-tests b.passed { color: #5E740B; }
-#qunit-tests b.failed { color: #710909; }
-
-#qunit-tests li li {
- padding: 5px;
- background-color: #fff;
- border-bottom: none;
- list-style-position: inside;
-}
-
-/*** Passing Styles */
-
-#qunit-tests li li.pass {
- color: #3c510c;
- background-color: #fff;
- border-left: 10px solid #C6E746;
-}
-
-#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
-#qunit-tests .pass .test-name { color: #366097; }
-
-#qunit-tests .pass .test-actual,
-#qunit-tests .pass .test-expected { color: #999999; }
-
-#qunit-banner.qunit-pass { background-color: #C6E746; }
-
-/*** Failing Styles */
-
-#qunit-tests li li.fail {
- color: #710909;
- background-color: #fff;
- border-left: 10px solid #EE5757;
- white-space: pre;
-}
-
-#qunit-tests > li:last-child {
- border-radius: 0 0 5px 5px;
- -moz-border-radius: 0 0 5px 5px;
- -webkit-border-bottom-right-radius: 5px;
- -webkit-border-bottom-left-radius: 5px;
-}
-
-#qunit-tests .fail { color: #000000; background-color: #EE5757; }
-#qunit-tests .fail .test-name,
-#qunit-tests .fail .module-name { color: #000000; }
-
-#qunit-tests .fail .test-actual { color: #EE5757; }
-#qunit-tests .fail .test-expected { color: green; }
-
-#qunit-banner.qunit-fail { background-color: #EE5757; }
-
-
-/** Result */
-
-#qunit-testresult {
- padding: 0.5em 0.5em 0.5em 2.5em;
-
- color: #2b81af;
- background-color: #D2E0E6;
-
- border-bottom: 1px solid white;
-}
-#qunit-testresult .module-name {
- font-weight: bold;
-}
-
-/** Fixture */
-
-#qunit-fixture {
- position: absolute;
- top: -10000px;
- left: -10000px;
- width: 1000px;
- height: 1000px;
-}
diff --git a/test/lib/qunit-1.11.0.js b/test/lib/qunit-1.11.0.js
deleted file mode 100644
index 302545f..0000000
--- a/test/lib/qunit-1.11.0.js
+++ /dev/null
@@ -1,2152 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-(function( window ) {
-
-var QUnit,
- assert,
- config,
- onErrorFnPrev,
- testId = 0,
- fileName = (sourceFromStacktrace( 0 ) || "" ).replace(/(:\d+)+\)?/, "").replace(/.+\//, ""),
- toString = Object.prototype.toString,
- hasOwn = Object.prototype.hasOwnProperty,
- // Keep a local reference to Date (GH-283)
- Date = window.Date,
- defined = {
- setTimeout: typeof window.setTimeout !== "undefined",
- sessionStorage: (function() {
- var x = "qunit-test-string";
- try {
- sessionStorage.setItem( x, x );
- sessionStorage.removeItem( x );
- return true;
- } catch( e ) {
- return false;
- }
- }())
- },
- /**
- * Provides a normalized error string, correcting an issue
- * with IE 7 (and prior) where Error.prototype.toString is
- * not properly implemented
- *
- * Based on http://es5.github.com/#x15.11.4.4
- *
- * @param {String|Error} error
- * @return {String} error message
- */
- errorString = function( error ) {
- var name, message,
- errorString = error.toString();
- if ( errorString.substring( 0, 7 ) === "[object" ) {
- name = error.name ? error.name.toString() : "Error";
- message = error.message ? error.message.toString() : "";
- if ( name && message ) {
- return name + ": " + message;
- } else if ( name ) {
- return name;
- } else if ( message ) {
- return message;
- } else {
- return "Error";
- }
- } else {
- return errorString;
- }
- },
- /**
- * Makes a clone of an object using only Array or Object as base,
- * and copies over the own enumerable properties.
- *
- * @param {Object} obj
- * @return {Object} New object with only the own properties (recursively).
- */
- objectValues = function( obj ) {
- // Grunt 0.3.x uses an older version of jshint that still has jshint/jshint#392.
- /*jshint newcap: false */
- var key, val,
- vals = QUnit.is( "array", obj ) ? [] : {};
- for ( key in obj ) {
- if ( hasOwn.call( obj, key ) ) {
- val = obj[key];
- vals[key] = val === Object(val) ? objectValues(val) : val;
- }
- }
- return vals;
- };
-
-function Test( settings ) {
- extend( this, settings );
- this.assertions = [];
- this.testNumber = ++Test.count;
-}
-
-Test.count = 0;
-
-Test.prototype = {
- init: function() {
- var a, b, li,
- tests = id( "qunit-tests" );
-
- if ( tests ) {
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml;
-
- // `a` initialized at top of scope
- a = document.createElement( "a" );
- a.innerHTML = "Rerun";
- a.href = QUnit.url({ testNumber: this.testNumber });
-
- li = document.createElement( "li" );
- li.appendChild( b );
- li.appendChild( a );
- li.className = "running";
- li.id = this.id = "qunit-test-output" + testId++;
-
- tests.appendChild( li );
- }
- },
- setup: function() {
- if ( this.module !== config.previousModule ) {
- if ( config.previousModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.previousModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
- config.previousModule = this.module;
- config.moduleStats = { all: 0, bad: 0 };
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- } else if ( config.autorun ) {
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- }
-
- config.current = this;
-
- this.testEnvironment = extend({
- setup: function() {},
- teardown: function() {}
- }, this.moduleTestEnvironment );
-
- this.started = +new Date();
- runLoggingCallbacks( "testStart", QUnit, {
- name: this.testName,
- module: this.module
- });
-
- // allow utility functions to access the current test environment
- // TODO why??
- QUnit.current_testEnvironment = this.testEnvironment;
-
- if ( !config.pollution ) {
- saveGlobal();
- }
- if ( config.notrycatch ) {
- this.testEnvironment.setup.call( this.testEnvironment );
- return;
- }
- try {
- this.testEnvironment.setup.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Setup failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- },
- run: function() {
- config.current = this;
-
- var running = id( "qunit-testresult" );
-
- if ( running ) {
- running.innerHTML = "Running:
" + this.nameHtml;
- }
-
- if ( this.async ) {
- QUnit.stop();
- }
-
- this.callbackStarted = +new Date();
-
- if ( config.notrycatch ) {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- return;
- }
-
- try {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- } catch( e ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
-
- QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + " " + this.stack + ": " + ( e.message || e ), extractStacktrace( e, 0 ) );
- // else next test will carry the responsibility
- saveGlobal();
-
- // Restart the tests if they're blocking
- if ( config.blocking ) {
- QUnit.start();
- }
- }
- },
- teardown: function() {
- config.current = this;
- if ( config.notrycatch ) {
- if ( typeof this.callbackRuntime === "undefined" ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
- }
- this.testEnvironment.teardown.call( this.testEnvironment );
- return;
- } else {
- try {
- this.testEnvironment.teardown.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Teardown failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- }
- checkPollution();
- },
- finish: function() {
- config.current = this;
- if ( config.requireExpects && this.expected === null ) {
- QUnit.pushFailure( "Expected number of assertions to be defined, but expect() was not called.", this.stack );
- } else if ( this.expected !== null && this.expected !== this.assertions.length ) {
- QUnit.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack );
- } else if ( this.expected === null && !this.assertions.length ) {
- QUnit.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions.", this.stack );
- }
-
- var i, assertion, a, b, time, li, ol,
- test = this,
- good = 0,
- bad = 0,
- tests = id( "qunit-tests" );
-
- this.runtime = +new Date() - this.started;
- config.stats.all += this.assertions.length;
- config.moduleStats.all += this.assertions.length;
-
- if ( tests ) {
- ol = document.createElement( "ol" );
- ol.className = "qunit-assert-list";
-
- for ( i = 0; i < this.assertions.length; i++ ) {
- assertion = this.assertions[i];
-
- li = document.createElement( "li" );
- li.className = assertion.result ? "pass" : "fail";
- li.innerHTML = assertion.message || ( assertion.result ? "okay" : "failed" );
- ol.appendChild( li );
-
- if ( assertion.result ) {
- good++;
- } else {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
-
- // store result when possible
- if ( QUnit.config.reorder && defined.sessionStorage ) {
- if ( bad ) {
- sessionStorage.setItem( "qunit-test-" + this.module + "-" + this.testName, bad );
- } else {
- sessionStorage.removeItem( "qunit-test-" + this.module + "-" + this.testName );
- }
- }
-
- if ( bad === 0 ) {
- addClass( ol, "qunit-collapsed" );
- }
-
- // `b` initialized at top of scope
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml + " (" + bad + ", " + good + ", " + this.assertions.length + ")";
-
- addEvent(b, "click", function() {
- var next = b.parentNode.lastChild,
- collapsed = hasClass( next, "qunit-collapsed" );
- ( collapsed ? removeClass : addClass )( next, "qunit-collapsed" );
- });
-
- addEvent(b, "dblclick", function( e ) {
- var target = e && e.target ? e.target : window.event.srcElement;
- if ( target.nodeName.toLowerCase() === "span" || target.nodeName.toLowerCase() === "b" ) {
- target = target.parentNode;
- }
- if ( window.location && target.nodeName.toLowerCase() === "strong" ) {
- window.location = QUnit.url({ testNumber: test.testNumber });
- }
- });
-
- // `time` initialized at top of scope
- time = document.createElement( "span" );
- time.className = "runtime";
- time.innerHTML = this.runtime + " ms";
-
- // `li` initialized at top of scope
- li = id( this.id );
- li.className = bad ? "fail" : "pass";
- li.removeChild( li.firstChild );
- a = li.firstChild;
- li.appendChild( b );
- li.appendChild( a );
- li.appendChild( time );
- li.appendChild( ol );
-
- } else {
- for ( i = 0; i < this.assertions.length; i++ ) {
- if ( !this.assertions[i].result ) {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
- }
-
- runLoggingCallbacks( "testDone", QUnit, {
- name: this.testName,
- module: this.module,
- failed: bad,
- passed: this.assertions.length - bad,
- total: this.assertions.length,
- duration: this.runtime
- });
-
- QUnit.reset();
-
- config.current = undefined;
- },
-
- queue: function() {
- var bad,
- test = this;
-
- synchronize(function() {
- test.init();
- });
- function run() {
- // each of these can by async
- synchronize(function() {
- test.setup();
- });
- synchronize(function() {
- test.run();
- });
- synchronize(function() {
- test.teardown();
- });
- synchronize(function() {
- test.finish();
- });
- }
-
- // `bad` initialized at top of scope
- // defer when previous test run passed, if storage is available
- bad = QUnit.config.reorder && defined.sessionStorage &&
- +sessionStorage.getItem( "qunit-test-" + this.module + "-" + this.testName );
-
- if ( bad ) {
- run();
- } else {
- synchronize( run, true );
- }
- }
-};
-
-// Root QUnit object.
-// `QUnit` initialized at top of scope
-QUnit = {
-
- // call on start of module test to prepend name to all tests
- module: function( name, testEnvironment ) {
- config.currentModule = name;
- config.currentModuleTestEnvironment = testEnvironment;
- config.modules[name] = true;
- },
-
- asyncTest: function( testName, expected, callback ) {
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- QUnit.test( testName, expected, callback, true );
- },
-
- test: function( testName, expected, callback, async ) {
- var test,
- nameHtml = "" + escapeText( testName ) + "";
-
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- if ( config.currentModule ) {
- nameHtml = "" + escapeText( config.currentModule ) + ": " + nameHtml;
- }
-
- test = new Test({
- nameHtml: nameHtml,
- testName: testName,
- expected: expected,
- async: async,
- callback: callback,
- module: config.currentModule,
- moduleTestEnvironment: config.currentModuleTestEnvironment,
- stack: sourceFromStacktrace( 2 )
- });
-
- if ( !validTest( test ) ) {
- return;
- }
-
- test.queue();
- },
-
- // Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through.
- expect: function( asserts ) {
- if (arguments.length === 1) {
- config.current.expected = asserts;
- } else {
- return config.current.expected;
- }
- },
-
- start: function( count ) {
- // QUnit hasn't been initialized yet.
- // Note: RequireJS (et al) may delay onLoad
- if ( config.semaphore === undefined ) {
- QUnit.begin(function() {
- // This is triggered at the top of QUnit.load, push start() to the event loop, to allow QUnit.load to finish first
- setTimeout(function() {
- QUnit.start( count );
- });
- });
- return;
- }
-
- config.semaphore -= count || 1;
- // don't start until equal number of stop-calls
- if ( config.semaphore > 0 ) {
- return;
- }
- // ignore if start is called more often then stop
- if ( config.semaphore < 0 ) {
- config.semaphore = 0;
- QUnit.pushFailure( "Called start() while already started (QUnit.config.semaphore was 0 already)", null, sourceFromStacktrace(2) );
- return;
- }
- // A slight delay, to avoid any current callbacks
- if ( defined.setTimeout ) {
- window.setTimeout(function() {
- if ( config.semaphore > 0 ) {
- return;
- }
- if ( config.timeout ) {
- clearTimeout( config.timeout );
- }
-
- config.blocking = false;
- process( true );
- }, 13);
- } else {
- config.blocking = false;
- process( true );
- }
- },
-
- stop: function( count ) {
- config.semaphore += count || 1;
- config.blocking = true;
-
- if ( config.testTimeout && defined.setTimeout ) {
- clearTimeout( config.timeout );
- config.timeout = window.setTimeout(function() {
- QUnit.ok( false, "Test timed out" );
- config.semaphore = 1;
- QUnit.start();
- }, config.testTimeout );
- }
- }
-};
-
-// `assert` initialized at top of scope
-// Asssert helpers
-// All of these must either call QUnit.push() or manually do:
-// - runLoggingCallbacks( "log", .. );
-// - config.current.assertions.push({ .. });
-// We attach it to the QUnit object *after* we expose the public API,
-// otherwise `assert` will become a global variable in browsers (#341).
-assert = {
- /**
- * Asserts rough true-ish result.
- * @name ok
- * @function
- * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" );
- */
- ok: function( result, msg ) {
- if ( !config.current ) {
- throw new Error( "ok() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
- result = !!result;
-
- var source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: msg
- };
-
- msg = escapeText( msg || (result ? "okay" : "failed" ) );
- msg = "" + msg + "";
-
- if ( !result ) {
- source = sourceFromStacktrace( 2 );
- if ( source ) {
- details.source = source;
- msg += "Source: | " + escapeText( source ) + " |
---|
";
- }
- }
- runLoggingCallbacks( "log", QUnit, details );
- config.current.assertions.push({
- result: result,
- message: msg
- });
- },
-
- /**
- * Assert that the first two arguments are equal, with an optional message.
- * Prints out both actual and expected values.
- * @name equal
- * @function
- * @example equal( format( "Received {0} bytes.", 2), "Received 2 bytes.", "format() replaces {0} with next argument" );
- */
- equal: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected == actual, actual, expected, message );
- },
-
- /**
- * @name notEqual
- * @function
- */
- notEqual: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected != actual, actual, expected, message );
- },
-
- /**
- * @name propEqual
- * @function
- */
- propEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notPropEqual
- * @function
- */
- notPropEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name deepEqual
- * @function
- */
- deepEqual: function( actual, expected, message ) {
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notDeepEqual
- * @function
- */
- notDeepEqual: function( actual, expected, message ) {
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name strictEqual
- * @function
- */
- strictEqual: function( actual, expected, message ) {
- QUnit.push( expected === actual, actual, expected, message );
- },
-
- /**
- * @name notStrictEqual
- * @function
- */
- notStrictEqual: function( actual, expected, message ) {
- QUnit.push( expected !== actual, actual, expected, message );
- },
-
- "throws": function( block, expected, message ) {
- var actual,
- expectedOutput = expected,
- ok = false;
-
- // 'expected' is optional
- if ( typeof expected === "string" ) {
- message = expected;
- expected = null;
- }
-
- config.current.ignoreGlobalErrors = true;
- try {
- block.call( config.current.testEnvironment );
- } catch (e) {
- actual = e;
- }
- config.current.ignoreGlobalErrors = false;
-
- if ( actual ) {
- // we don't want to validate thrown error
- if ( !expected ) {
- ok = true;
- expectedOutput = null;
- // expected is a regexp
- } else if ( QUnit.objectType( expected ) === "regexp" ) {
- ok = expected.test( errorString( actual ) );
- // expected is a constructor
- } else if ( actual instanceof expected ) {
- ok = true;
- // expected is a validation function which returns true is validation passed
- } else if ( expected.call( {}, actual ) === true ) {
- expectedOutput = null;
- ok = true;
- }
-
- QUnit.push( ok, actual, expectedOutput, message );
- } else {
- QUnit.pushFailure( message, null, 'No exception was thrown.' );
- }
- }
-};
-
-/**
- * @deprecate since 1.8.0
- * Kept assertion helpers in root for backwards compatibility.
- */
-extend( QUnit, assert );
-
-/**
- * @deprecated since 1.9.0
- * Kept root "raises()" for backwards compatibility.
- * (Note that we don't introduce assert.raises).
- */
-QUnit.raises = assert[ "throws" ];
-
-/**
- * @deprecated since 1.0.0, replaced with error pushes since 1.3.0
- * Kept to avoid TypeErrors for undefined methods.
- */
-QUnit.equals = function() {
- QUnit.push( false, false, false, "QUnit.equals has been deprecated since 2009 (e88049a0), use QUnit.equal instead" );
-};
-QUnit.same = function() {
- QUnit.push( false, false, false, "QUnit.same has been deprecated since 2009 (e88049a0), use QUnit.deepEqual instead" );
-};
-
-// We want access to the constructor's prototype
-(function() {
- function F() {}
- F.prototype = QUnit;
- QUnit = new F();
- // Make F QUnit's constructor so that we can add to the prototype later
- QUnit.constructor = F;
-}());
-
-/**
- * Config object: Maintain internal state
- * Later exposed as QUnit.config
- * `config` initialized at top of scope
- */
-config = {
- // The queue of tests to run
- queue: [],
-
- // block until document ready
- blocking: true,
-
- // when enabled, show only failing tests
- // gets persisted through sessionStorage and can be changed in UI via checkbox
- hidepassed: false,
-
- // by default, run previously failed tests first
- // very useful in combination with "Hide passed tests" checked
- reorder: true,
-
- // by default, modify document.title when suite is done
- altertitle: true,
-
- // when enabled, all tests must call expect()
- requireExpects: false,
-
- // add checkboxes that are persisted in the query-string
- // when enabled, the id is set to `true` as a `QUnit.config` property
- urlConfig: [
- {
- id: "noglobals",
- label: "Check for Globals",
- tooltip: "Enabling this will test if any test introduces new properties on the `window` object. Stored as query-strings."
- },
- {
- id: "notrycatch",
- label: "No try-catch",
- tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging exceptions in IE reasonable. Stored as query-strings."
- }
- ],
-
- // Set of all modules.
- modules: {},
-
- // logging callback queues
- begin: [],
- done: [],
- log: [],
- testStart: [],
- testDone: [],
- moduleStart: [],
- moduleDone: []
-};
-
-// Export global variables, unless an 'exports' object exists,
-// in that case we assume we're in CommonJS (dealt with on the bottom of the script)
-if ( typeof exports === "undefined" ) {
- extend( window, QUnit );
-
- // Expose QUnit object
- window.QUnit = QUnit;
-}
-
-// Initialize more QUnit.config and QUnit.urlParams
-(function() {
- var i,
- location = window.location || { search: "", protocol: "file:" },
- params = location.search.slice( 1 ).split( "&" ),
- length = params.length,
- urlParams = {},
- current;
-
- if ( params[ 0 ] ) {
- for ( i = 0; i < length; i++ ) {
- current = params[ i ].split( "=" );
- current[ 0 ] = decodeURIComponent( current[ 0 ] );
- // allow just a key to turn on a flag, e.g., test.html?noglobals
- current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true;
- urlParams[ current[ 0 ] ] = current[ 1 ];
- }
- }
-
- QUnit.urlParams = urlParams;
-
- // String search anywhere in moduleName+testName
- config.filter = urlParams.filter;
-
- // Exact match of the module name
- config.module = urlParams.module;
-
- config.testNumber = parseInt( urlParams.testNumber, 10 ) || null;
-
- // Figure out if we're running the tests from a server or not
- QUnit.isLocal = location.protocol === "file:";
-}());
-
-// Extend QUnit object,
-// these after set here because they should not be exposed as global functions
-extend( QUnit, {
- assert: assert,
-
- config: config,
-
- // Initialize the configuration options
- init: function() {
- extend( config, {
- stats: { all: 0, bad: 0 },
- moduleStats: { all: 0, bad: 0 },
- started: +new Date(),
- updateRate: 1000,
- blocking: false,
- autostart: true,
- autorun: false,
- filter: "",
- queue: [],
- semaphore: 1
- });
-
- var tests, banner, result,
- qunit = id( "qunit" );
-
- if ( qunit ) {
- qunit.innerHTML =
- "" +
- "" +
- "" +
- "" +
- "
";
- }
-
- tests = id( "qunit-tests" );
- banner = id( "qunit-banner" );
- result = id( "qunit-testresult" );
-
- if ( tests ) {
- tests.innerHTML = "";
- }
-
- if ( banner ) {
- banner.className = "";
- }
-
- if ( result ) {
- result.parentNode.removeChild( result );
- }
-
- if ( tests ) {
- result = document.createElement( "p" );
- result.id = "qunit-testresult";
- result.className = "result";
- tests.parentNode.insertBefore( result, tests );
- result.innerHTML = "Running...
";
- }
- },
-
- // Resets the test setup. Useful for tests that modify the DOM.
- reset: function() {
- var fixture = id( "qunit-fixture" );
- if ( fixture ) {
- fixture.innerHTML = config.fixture;
- }
- },
-
- // Trigger an event on an element.
- // @example triggerEvent( document.body, "click" );
- triggerEvent: function( elem, type, event ) {
- if ( document.createEvent ) {
- event = document.createEvent( "MouseEvents" );
- event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView,
- 0, 0, 0, 0, 0, false, false, false, false, 0, null);
-
- elem.dispatchEvent( event );
- } else if ( elem.fireEvent ) {
- elem.fireEvent( "on" + type );
- }
- },
-
- // Safe object type checking
- is: function( type, obj ) {
- return QUnit.objectType( obj ) === type;
- },
-
- objectType: function( obj ) {
- if ( typeof obj === "undefined" ) {
- return "undefined";
- // consider: typeof null === object
- }
- if ( obj === null ) {
- return "null";
- }
-
- var match = toString.call( obj ).match(/^\[object\s(.*)\]$/),
- type = match && match[1] || "";
-
- switch ( type ) {
- case "Number":
- if ( isNaN(obj) ) {
- return "nan";
- }
- return "number";
- case "String":
- case "Boolean":
- case "Array":
- case "Date":
- case "RegExp":
- case "Function":
- return type.toLowerCase();
- }
- if ( typeof obj === "object" ) {
- return "object";
- }
- return undefined;
- },
-
- push: function( result, actual, expected, message ) {
- if ( !config.current ) {
- throw new Error( "assertion outside test context, was " + sourceFromStacktrace() );
- }
-
- var output, source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: message,
- actual: actual,
- expected: expected
- };
-
- message = escapeText( message ) || ( result ? "okay" : "failed" );
- message = "" + message + "";
- output = message;
-
- if ( !result ) {
- expected = escapeText( QUnit.jsDump.parse(expected) );
- actual = escapeText( QUnit.jsDump.parse(actual) );
- output += "Expected: | " + expected + " |
";
-
- if ( actual !== expected ) {
- output += "Result: | " + actual + " |
";
- output += "Diff: | " + QUnit.diff( expected, actual ) + " |
";
- }
-
- source = sourceFromStacktrace();
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
- }
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: !!result,
- message: output
- });
- },
-
- pushFailure: function( message, source, actual ) {
- if ( !config.current ) {
- throw new Error( "pushFailure() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
-
- var output,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: false,
- message: message
- };
-
- message = escapeText( message ) || "error";
- message = "" + message + "";
- output = message;
-
- output += "";
-
- if ( actual ) {
- output += "Result: | " + escapeText( actual ) + " |
";
- }
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: false,
- message: output
- });
- },
-
- url: function( params ) {
- params = extend( extend( {}, QUnit.urlParams ), params );
- var key,
- querystring = "?";
-
- for ( key in params ) {
- if ( !hasOwn.call( params, key ) ) {
- continue;
- }
- querystring += encodeURIComponent( key ) + "=" +
- encodeURIComponent( params[ key ] ) + "&";
- }
- return window.location.protocol + "//" + window.location.host +
- window.location.pathname + querystring.slice( 0, -1 );
- },
-
- extend: extend,
- id: id,
- addEvent: addEvent
- // load, equiv, jsDump, diff: Attached later
-});
-
-/**
- * @deprecated: Created for backwards compatibility with test runner that set the hook function
- * into QUnit.{hook}, instead of invoking it and passing the hook function.
- * QUnit.constructor is set to the empty F() above so that we can add to it's prototype here.
- * Doing this allows us to tell if the following methods have been overwritten on the actual
- * QUnit object.
- */
-extend( QUnit.constructor.prototype, {
-
- // Logging callbacks; all receive a single argument with the listed properties
- // run test/logs.html for any related changes
- begin: registerLoggingCallback( "begin" ),
-
- // done: { failed, passed, total, runtime }
- done: registerLoggingCallback( "done" ),
-
- // log: { result, actual, expected, message }
- log: registerLoggingCallback( "log" ),
-
- // testStart: { name }
- testStart: registerLoggingCallback( "testStart" ),
-
- // testDone: { name, failed, passed, total, duration }
- testDone: registerLoggingCallback( "testDone" ),
-
- // moduleStart: { name }
- moduleStart: registerLoggingCallback( "moduleStart" ),
-
- // moduleDone: { name, failed, passed, total }
- moduleDone: registerLoggingCallback( "moduleDone" )
-});
-
-if ( typeof document === "undefined" || document.readyState === "complete" ) {
- config.autorun = true;
-}
-
-QUnit.load = function() {
- runLoggingCallbacks( "begin", QUnit, {} );
-
- // Initialize the config, saving the execution queue
- var banner, filter, i, label, len, main, ol, toolbar, userAgent, val,
- urlConfigCheckboxesContainer, urlConfigCheckboxes, moduleFilter,
- numModules = 0,
- moduleFilterHtml = "",
- urlConfigHtml = "",
- oldconfig = extend( {}, config );
-
- QUnit.init();
- extend(config, oldconfig);
-
- config.blocking = false;
-
- len = config.urlConfig.length;
-
- for ( i = 0; i < len; i++ ) {
- val = config.urlConfig[i];
- if ( typeof val === "string" ) {
- val = {
- id: val,
- label: val,
- tooltip: "[no tooltip available]"
- };
- }
- config[ val.id ] = QUnit.urlParams[ val.id ];
- urlConfigHtml += "";
- }
-
- moduleFilterHtml += "";
-
- // `userAgent` initialized at top of scope
- userAgent = id( "qunit-userAgent" );
- if ( userAgent ) {
- userAgent.innerHTML = navigator.userAgent;
- }
-
- // `banner` initialized at top of scope
- banner = id( "qunit-header" );
- if ( banner ) {
- banner.innerHTML = "" + banner.innerHTML + " ";
- }
-
- // `toolbar` initialized at top of scope
- toolbar = id( "qunit-testrunner-toolbar" );
- if ( toolbar ) {
- // `filter` initialized at top of scope
- filter = document.createElement( "input" );
- filter.type = "checkbox";
- filter.id = "qunit-filter-pass";
-
- addEvent( filter, "click", function() {
- var tmp,
- ol = document.getElementById( "qunit-tests" );
-
- if ( filter.checked ) {
- ol.className = ol.className + " hidepass";
- } else {
- tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " ";
- ol.className = tmp.replace( / hidepass /, " " );
- }
- if ( defined.sessionStorage ) {
- if (filter.checked) {
- sessionStorage.setItem( "qunit-filter-passed-tests", "true" );
- } else {
- sessionStorage.removeItem( "qunit-filter-passed-tests" );
- }
- }
- });
-
- if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem( "qunit-filter-passed-tests" ) ) {
- filter.checked = true;
- // `ol` initialized at top of scope
- ol = document.getElementById( "qunit-tests" );
- ol.className = ol.className + " hidepass";
- }
- toolbar.appendChild( filter );
-
- // `label` initialized at top of scope
- label = document.createElement( "label" );
- label.setAttribute( "for", "qunit-filter-pass" );
- label.setAttribute( "title", "Only show tests and assertons that fail. Stored in sessionStorage." );
- label.innerHTML = "Hide passed tests";
- toolbar.appendChild( label );
-
- urlConfigCheckboxesContainer = document.createElement("span");
- urlConfigCheckboxesContainer.innerHTML = urlConfigHtml;
- urlConfigCheckboxes = urlConfigCheckboxesContainer.getElementsByTagName("input");
- // For oldIE support:
- // * Add handlers to the individual elements instead of the container
- // * Use "click" instead of "change"
- // * Fallback from event.target to event.srcElement
- addEvents( urlConfigCheckboxes, "click", function( event ) {
- var params = {},
- target = event.target || event.srcElement;
- params[ target.name ] = target.checked ? true : undefined;
- window.location = QUnit.url( params );
- });
- toolbar.appendChild( urlConfigCheckboxesContainer );
-
- if (numModules > 1) {
- moduleFilter = document.createElement( 'span' );
- moduleFilter.setAttribute( 'id', 'qunit-modulefilter-container' );
- moduleFilter.innerHTML = moduleFilterHtml;
- addEvent( moduleFilter.lastChild, "change", function() {
- var selectBox = moduleFilter.getElementsByTagName("select")[0],
- selectedModule = decodeURIComponent(selectBox.options[selectBox.selectedIndex].value);
-
- window.location = QUnit.url( { module: ( selectedModule === "" ) ? undefined : selectedModule } );
- });
- toolbar.appendChild(moduleFilter);
- }
- }
-
- // `main` initialized at top of scope
- main = id( "qunit-fixture" );
- if ( main ) {
- config.fixture = main.innerHTML;
- }
-
- if ( config.autostart ) {
- QUnit.start();
- }
-};
-
-addEvent( window, "load", QUnit.load );
-
-// `onErrorFnPrev` initialized at top of scope
-// Preserve other handlers
-onErrorFnPrev = window.onerror;
-
-// Cover uncaught exceptions
-// Returning true will surpress the default browser handler,
-// returning false will let it run.
-window.onerror = function ( error, filePath, linerNr ) {
- var ret = false;
- if ( onErrorFnPrev ) {
- ret = onErrorFnPrev( error, filePath, linerNr );
- }
-
- // Treat return value as window.onerror itself does,
- // Only do our handling if not surpressed.
- if ( ret !== true ) {
- if ( QUnit.config.current ) {
- if ( QUnit.config.current.ignoreGlobalErrors ) {
- return true;
- }
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- } else {
- QUnit.test( "global failure", extend( function() {
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- }, { validTest: validTest } ) );
- }
- return false;
- }
-
- return ret;
-};
-
-function done() {
- config.autorun = true;
-
- // Log the last module results
- if ( config.currentModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.currentModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
-
- var i, key,
- banner = id( "qunit-banner" ),
- tests = id( "qunit-tests" ),
- runtime = +new Date() - config.started,
- passed = config.stats.all - config.stats.bad,
- html = [
- "Tests completed in ",
- runtime,
- " milliseconds.
",
- "",
- passed,
- " assertions of ",
- config.stats.all,
- " passed, ",
- config.stats.bad,
- " failed."
- ].join( "" );
-
- if ( banner ) {
- banner.className = ( config.stats.bad ? "qunit-fail" : "qunit-pass" );
- }
-
- if ( tests ) {
- id( "qunit-testresult" ).innerHTML = html;
- }
-
- if ( config.altertitle && typeof document !== "undefined" && document.title ) {
- // show ✖ for good, ✔ for bad suite result in title
- // use escape sequences in case file gets loaded with non-utf-8-charset
- document.title = [
- ( config.stats.bad ? "\u2716" : "\u2714" ),
- document.title.replace( /^[\u2714\u2716] /i, "" )
- ].join( " " );
- }
-
- // clear own sessionStorage items if all tests passed
- if ( config.reorder && defined.sessionStorage && config.stats.bad === 0 ) {
- // `key` & `i` initialized at top of scope
- for ( i = 0; i < sessionStorage.length; i++ ) {
- key = sessionStorage.key( i++ );
- if ( key.indexOf( "qunit-test-" ) === 0 ) {
- sessionStorage.removeItem( key );
- }
- }
- }
-
- // scroll back to top to show results
- if ( window.scrollTo ) {
- window.scrollTo(0, 0);
- }
-
- runLoggingCallbacks( "done", QUnit, {
- failed: config.stats.bad,
- passed: passed,
- total: config.stats.all,
- runtime: runtime
- });
-}
-
-/** @return Boolean: true if this test should be ran */
-function validTest( test ) {
- var include,
- filter = config.filter && config.filter.toLowerCase(),
- module = config.module && config.module.toLowerCase(),
- fullName = (test.module + ": " + test.testName).toLowerCase();
-
- // Internally-generated tests are always valid
- if ( test.callback && test.callback.validTest === validTest ) {
- delete test.callback.validTest;
- return true;
- }
-
- if ( config.testNumber ) {
- return test.testNumber === config.testNumber;
- }
-
- if ( module && ( !test.module || test.module.toLowerCase() !== module ) ) {
- return false;
- }
-
- if ( !filter ) {
- return true;
- }
-
- include = filter.charAt( 0 ) !== "!";
- if ( !include ) {
- filter = filter.slice( 1 );
- }
-
- // If the filter matches, we need to honour include
- if ( fullName.indexOf( filter ) !== -1 ) {
- return include;
- }
-
- // Otherwise, do the opposite
- return !include;
-}
-
-// so far supports only Firefox, Chrome and Opera (buggy), Safari (for real exceptions)
-// Later Safari and IE10 are supposed to support error.stack as well
-// See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack
-function extractStacktrace( e, offset ) {
- offset = offset === undefined ? 3 : offset;
-
- var stack, include, i;
-
- if ( e.stacktrace ) {
- // Opera
- return e.stacktrace.split( "\n" )[ offset + 3 ];
- } else if ( e.stack ) {
- // Firefox, Chrome
- stack = e.stack.split( "\n" );
- if (/^error$/i.test( stack[0] ) ) {
- stack.shift();
- }
- if ( fileName ) {
- include = [];
- for ( i = offset; i < stack.length; i++ ) {
- if ( stack[ i ].indexOf( fileName ) !== -1 ) {
- break;
- }
- include.push( stack[ i ] );
- }
- if ( include.length ) {
- return include.join( "\n" );
- }
- }
- return stack[ offset ];
- } else if ( e.sourceURL ) {
- // Safari, PhantomJS
- // hopefully one day Safari provides actual stacktraces
- // exclude useless self-reference for generated Error objects
- if ( /qunit.js$/.test( e.sourceURL ) ) {
- return;
- }
- // for actual exceptions, this is useful
- return e.sourceURL + ":" + e.line;
- }
-}
-function sourceFromStacktrace( offset ) {
- try {
- throw new Error();
- } catch ( e ) {
- return extractStacktrace( e, offset );
- }
-}
-
-/**
- * Escape text for attribute or text content.
- */
-function escapeText( s ) {
- if ( !s ) {
- return "";
- }
- s = s + "";
- // Both single quotes and double quotes (for attributes)
- return s.replace( /['"<>&]/g, function( s ) {
- switch( s ) {
- case '\'':
- return ''';
- case '"':
- return '"';
- case '<':
- return '<';
- case '>':
- return '>';
- case '&':
- return '&';
- }
- });
-}
-
-function synchronize( callback, last ) {
- config.queue.push( callback );
-
- if ( config.autorun && !config.blocking ) {
- process( last );
- }
-}
-
-function process( last ) {
- function next() {
- process( last );
- }
- var start = new Date().getTime();
- config.depth = config.depth ? config.depth + 1 : 1;
-
- while ( config.queue.length && !config.blocking ) {
- if ( !defined.setTimeout || config.updateRate <= 0 || ( ( new Date().getTime() - start ) < config.updateRate ) ) {
- config.queue.shift()();
- } else {
- window.setTimeout( next, 13 );
- break;
- }
- }
- config.depth--;
- if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) {
- done();
- }
-}
-
-function saveGlobal() {
- config.pollution = [];
-
- if ( config.noglobals ) {
- for ( var key in window ) {
- // in Opera sometimes DOM element ids show up here, ignore them
- if ( !hasOwn.call( window, key ) || /^qunit-test-output/.test( key ) ) {
- continue;
- }
- config.pollution.push( key );
- }
- }
-}
-
-function checkPollution() {
- var newGlobals,
- deletedGlobals,
- old = config.pollution;
-
- saveGlobal();
-
- newGlobals = diff( config.pollution, old );
- if ( newGlobals.length > 0 ) {
- QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join(", ") );
- }
-
- deletedGlobals = diff( old, config.pollution );
- if ( deletedGlobals.length > 0 ) {
- QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join(", ") );
- }
-}
-
-// returns a new Array with the elements that are in a but not in b
-function diff( a, b ) {
- var i, j,
- result = a.slice();
-
- for ( i = 0; i < result.length; i++ ) {
- for ( j = 0; j < b.length; j++ ) {
- if ( result[i] === b[j] ) {
- result.splice( i, 1 );
- i--;
- break;
- }
- }
- }
- return result;
-}
-
-function extend( a, b ) {
- for ( var prop in b ) {
- if ( b[ prop ] === undefined ) {
- delete a[ prop ];
-
- // Avoid "Member not found" error in IE8 caused by setting window.constructor
- } else if ( prop !== "constructor" || a !== window ) {
- a[ prop ] = b[ prop ];
- }
- }
-
- return a;
-}
-
-/**
- * @param {HTMLElement} elem
- * @param {string} type
- * @param {Function} fn
- */
-function addEvent( elem, type, fn ) {
- // Standards-based browsers
- if ( elem.addEventListener ) {
- elem.addEventListener( type, fn, false );
- // IE
- } else {
- elem.attachEvent( "on" + type, fn );
- }
-}
-
-/**
- * @param {Array|NodeList} elems
- * @param {string} type
- * @param {Function} fn
- */
-function addEvents( elems, type, fn ) {
- var i = elems.length;
- while ( i-- ) {
- addEvent( elems[i], type, fn );
- }
-}
-
-function hasClass( elem, name ) {
- return (" " + elem.className + " ").indexOf(" " + name + " ") > -1;
-}
-
-function addClass( elem, name ) {
- if ( !hasClass( elem, name ) ) {
- elem.className += (elem.className ? " " : "") + name;
- }
-}
-
-function removeClass( elem, name ) {
- var set = " " + elem.className + " ";
- // Class name may appear multiple times
- while ( set.indexOf(" " + name + " ") > -1 ) {
- set = set.replace(" " + name + " " , " ");
- }
- // If possible, trim it for prettiness, but not neccecarily
- elem.className = window.jQuery ? jQuery.trim( set ) : ( set.trim ? set.trim() : set );
-}
-
-function id( name ) {
- return !!( typeof document !== "undefined" && document && document.getElementById ) &&
- document.getElementById( name );
-}
-
-function registerLoggingCallback( key ) {
- return function( callback ) {
- config[key].push( callback );
- };
-}
-
-// Supports deprecated method of completely overwriting logging callbacks
-function runLoggingCallbacks( key, scope, args ) {
- var i, callbacks;
- if ( QUnit.hasOwnProperty( key ) ) {
- QUnit[ key ].call(scope, args );
- } else {
- callbacks = config[ key ];
- for ( i = 0; i < callbacks.length; i++ ) {
- callbacks[ i ].call( scope, args );
- }
- }
-}
-
-// Test for equality any JavaScript type.
-// Author: Philippe Rathé
-QUnit.equiv = (function() {
-
- // Call the o related callback with the given arguments.
- function bindCallbacks( o, callbacks, args ) {
- var prop = QUnit.objectType( o );
- if ( prop ) {
- if ( QUnit.objectType( callbacks[ prop ] ) === "function" ) {
- return callbacks[ prop ].apply( callbacks, args );
- } else {
- return callbacks[ prop ]; // or undefined
- }
- }
- }
-
- // the real equiv function
- var innerEquiv,
- // stack to decide between skip/abort functions
- callers = [],
- // stack to avoiding loops from circular referencing
- parents = [],
-
- getProto = Object.getPrototypeOf || function ( obj ) {
- return obj.__proto__;
- },
- callbacks = (function () {
-
- // for string, boolean, number and null
- function useStrictEquality( b, a ) {
- /*jshint eqeqeq:false */
- if ( b instanceof a.constructor || a instanceof b.constructor ) {
- // to catch short annotaion VS 'new' annotation of a
- // declaration
- // e.g. var i = 1;
- // var j = new Number(1);
- return a == b;
- } else {
- return a === b;
- }
- }
-
- return {
- "string": useStrictEquality,
- "boolean": useStrictEquality,
- "number": useStrictEquality,
- "null": useStrictEquality,
- "undefined": useStrictEquality,
-
- "nan": function( b ) {
- return isNaN( b );
- },
-
- "date": function( b, a ) {
- return QUnit.objectType( b ) === "date" && a.valueOf() === b.valueOf();
- },
-
- "regexp": function( b, a ) {
- return QUnit.objectType( b ) === "regexp" &&
- // the regex itself
- a.source === b.source &&
- // and its modifers
- a.global === b.global &&
- // (gmi) ...
- a.ignoreCase === b.ignoreCase &&
- a.multiline === b.multiline &&
- a.sticky === b.sticky;
- },
-
- // - skip when the property is a method of an instance (OOP)
- // - abort otherwise,
- // initial === would have catch identical references anyway
- "function": function() {
- var caller = callers[callers.length - 1];
- return caller !== Object && typeof caller !== "undefined";
- },
-
- "array": function( b, a ) {
- var i, j, len, loop;
-
- // b could be an object literal here
- if ( QUnit.objectType( b ) !== "array" ) {
- return false;
- }
-
- len = a.length;
- if ( len !== b.length ) {
- // safe and faster
- return false;
- }
-
- // track reference to avoid circular references
- parents.push( a );
- for ( i = 0; i < len; i++ ) {
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- loop = true;// dont rewalk array
- }
- }
- if ( !loop && !innerEquiv(a[i], b[i]) ) {
- parents.pop();
- return false;
- }
- }
- parents.pop();
- return true;
- },
-
- "object": function( b, a ) {
- var i, j, loop,
- // Default to true
- eq = true,
- aProperties = [],
- bProperties = [];
-
- // comparing constructors is more strict than using
- // instanceof
- if ( a.constructor !== b.constructor ) {
- // Allow objects with no prototype to be equivalent to
- // objects with Object as their constructor.
- if ( !(( getProto(a) === null && getProto(b) === Object.prototype ) ||
- ( getProto(b) === null && getProto(a) === Object.prototype ) ) ) {
- return false;
- }
- }
-
- // stack constructor before traversing properties
- callers.push( a.constructor );
- // track reference to avoid circular references
- parents.push( a );
-
- for ( i in a ) { // be strict: don't ensures hasOwnProperty
- // and go deep
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- // don't go down the same path twice
- loop = true;
- }
- }
- aProperties.push(i); // collect a's properties
-
- if (!loop && !innerEquiv( a[i], b[i] ) ) {
- eq = false;
- break;
- }
- }
-
- callers.pop(); // unstack, we are done
- parents.pop();
-
- for ( i in b ) {
- bProperties.push( i ); // collect b's properties
- }
-
- // Ensures identical properties name
- return eq && innerEquiv( aProperties.sort(), bProperties.sort() );
- }
- };
- }());
-
- innerEquiv = function() { // can take multiple arguments
- var args = [].slice.apply( arguments );
- if ( args.length < 2 ) {
- return true; // end transition
- }
-
- return (function( a, b ) {
- if ( a === b ) {
- return true; // catch the most you can
- } else if ( a === null || b === null || typeof a === "undefined" ||
- typeof b === "undefined" ||
- QUnit.objectType(a) !== QUnit.objectType(b) ) {
- return false; // don't lose time with error prone cases
- } else {
- return bindCallbacks(a, callbacks, [ b, a ]);
- }
-
- // apply transition with (1..n) arguments
- }( args[0], args[1] ) && arguments.callee.apply( this, args.splice(1, args.length - 1 )) );
- };
-
- return innerEquiv;
-}());
-
-/**
- * jsDump Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com |
- * http://flesler.blogspot.com Licensed under BSD
- * (http://www.opensource.org/licenses/bsd-license.php) Date: 5/15/2008
- *
- * @projectDescription Advanced and extensible data dumping for Javascript.
- * @version 1.0.0
- * @author Ariel Flesler
- * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html}
- */
-QUnit.jsDump = (function() {
- function quote( str ) {
- return '"' + str.toString().replace( /"/g, '\\"' ) + '"';
- }
- function literal( o ) {
- return o + "";
- }
- function join( pre, arr, post ) {
- var s = jsDump.separator(),
- base = jsDump.indent(),
- inner = jsDump.indent(1);
- if ( arr.join ) {
- arr = arr.join( "," + s + inner );
- }
- if ( !arr ) {
- return pre + post;
- }
- return [ pre, inner + arr, base + post ].join(s);
- }
- function array( arr, stack ) {
- var i = arr.length, ret = new Array(i);
- this.up();
- while ( i-- ) {
- ret[i] = this.parse( arr[i] , undefined , stack);
- }
- this.down();
- return join( "[", ret, "]" );
- }
-
- var reName = /^function (\w+)/,
- jsDump = {
- // type is used mostly internally, you can fix a (custom)type in advance
- parse: function( obj, type, stack ) {
- stack = stack || [ ];
- var inStack, res,
- parser = this.parsers[ type || this.typeOf(obj) ];
-
- type = typeof parser;
- inStack = inArray( obj, stack );
-
- if ( inStack !== -1 ) {
- return "recursion(" + (inStack - stack.length) + ")";
- }
- if ( type === "function" ) {
- stack.push( obj );
- res = parser.call( this, obj, stack );
- stack.pop();
- return res;
- }
- return ( type === "string" ) ? parser : this.parsers.error;
- },
- typeOf: function( obj ) {
- var type;
- if ( obj === null ) {
- type = "null";
- } else if ( typeof obj === "undefined" ) {
- type = "undefined";
- } else if ( QUnit.is( "regexp", obj) ) {
- type = "regexp";
- } else if ( QUnit.is( "date", obj) ) {
- type = "date";
- } else if ( QUnit.is( "function", obj) ) {
- type = "function";
- } else if ( typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined" ) {
- type = "window";
- } else if ( obj.nodeType === 9 ) {
- type = "document";
- } else if ( obj.nodeType ) {
- type = "node";
- } else if (
- // native arrays
- toString.call( obj ) === "[object Array]" ||
- // NodeList objects
- ( typeof obj.length === "number" && typeof obj.item !== "undefined" && ( obj.length ? obj.item(0) === obj[0] : ( obj.item( 0 ) === null && typeof obj[0] === "undefined" ) ) )
- ) {
- type = "array";
- } else if ( obj.constructor === Error.prototype.constructor ) {
- type = "error";
- } else {
- type = typeof obj;
- }
- return type;
- },
- separator: function() {
- return this.multiline ? this.HTML ? "
" : "\n" : this.HTML ? " " : " ";
- },
- // extra can be a number, shortcut for increasing-calling-decreasing
- indent: function( extra ) {
- if ( !this.multiline ) {
- return "";
- }
- var chr = this.indentChar;
- if ( this.HTML ) {
- chr = chr.replace( /\t/g, " " ).replace( / /g, " " );
- }
- return new Array( this._depth_ + (extra||0) ).join(chr);
- },
- up: function( a ) {
- this._depth_ += a || 1;
- },
- down: function( a ) {
- this._depth_ -= a || 1;
- },
- setParser: function( name, parser ) {
- this.parsers[name] = parser;
- },
- // The next 3 are exposed so you can use them
- quote: quote,
- literal: literal,
- join: join,
- //
- _depth_: 1,
- // This is the list of parsers, to modify them, use jsDump.setParser
- parsers: {
- window: "[Window]",
- document: "[Document]",
- error: function(error) {
- return "Error(\"" + error.message + "\")";
- },
- unknown: "[Unknown]",
- "null": "null",
- "undefined": "undefined",
- "function": function( fn ) {
- var ret = "function",
- // functions never have name in IE
- name = "name" in fn ? fn.name : (reName.exec(fn) || [])[1];
-
- if ( name ) {
- ret += " " + name;
- }
- ret += "( ";
-
- ret = [ ret, QUnit.jsDump.parse( fn, "functionArgs" ), "){" ].join( "" );
- return join( ret, QUnit.jsDump.parse(fn,"functionCode" ), "}" );
- },
- array: array,
- nodelist: array,
- "arguments": array,
- object: function( map, stack ) {
- var ret = [ ], keys, key, val, i;
- QUnit.jsDump.up();
- keys = [];
- for ( key in map ) {
- keys.push( key );
- }
- keys.sort();
- for ( i = 0; i < keys.length; i++ ) {
- key = keys[ i ];
- val = map[ key ];
- ret.push( QUnit.jsDump.parse( key, "key" ) + ": " + QUnit.jsDump.parse( val, undefined, stack ) );
- }
- QUnit.jsDump.down();
- return join( "{", ret, "}" );
- },
- node: function( node ) {
- var len, i, val,
- open = QUnit.jsDump.HTML ? "<" : "<",
- close = QUnit.jsDump.HTML ? ">" : ">",
- tag = node.nodeName.toLowerCase(),
- ret = open + tag,
- attrs = node.attributes;
-
- if ( attrs ) {
- for ( i = 0, len = attrs.length; i < len; i++ ) {
- val = attrs[i].nodeValue;
- // IE6 includes all attributes in .attributes, even ones not explicitly set.
- // Those have values like undefined, null, 0, false, "" or "inherit".
- if ( val && val !== "inherit" ) {
- ret += " " + attrs[i].nodeName + "=" + QUnit.jsDump.parse( val, "attribute" );
- }
- }
- }
- ret += close;
-
- // Show content of TextNode or CDATASection
- if ( node.nodeType === 3 || node.nodeType === 4 ) {
- ret += node.nodeValue;
- }
-
- return ret + open + "/" + tag + close;
- },
- // function calls it internally, it's the arguments part of the function
- functionArgs: function( fn ) {
- var args,
- l = fn.length;
-
- if ( !l ) {
- return "";
- }
-
- args = new Array(l);
- while ( l-- ) {
- // 97 is 'a'
- args[l] = String.fromCharCode(97+l);
- }
- return " " + args.join( ", " ) + " ";
- },
- // object calls it internally, the key part of an item in a map
- key: quote,
- // function calls it internally, it's the content of the function
- functionCode: "[code]",
- // node calls it internally, it's an html attribute value
- attribute: quote,
- string: quote,
- date: quote,
- regexp: literal,
- number: literal,
- "boolean": literal
- },
- // if true, entities are escaped ( <, >, \t, space and \n )
- HTML: false,
- // indentation unit
- indentChar: " ",
- // if true, items in a collection, are separated by a \n, else just a space.
- multiline: true
- };
-
- return jsDump;
-}());
-
-// from jquery.js
-function inArray( elem, array ) {
- if ( array.indexOf ) {
- return array.indexOf( elem );
- }
-
- for ( var i = 0, length = array.length; i < length; i++ ) {
- if ( array[ i ] === elem ) {
- return i;
- }
- }
-
- return -1;
-}
-
-/*
- * Javascript Diff Algorithm
- * By John Resig (http://ejohn.org/)
- * Modified by Chu Alan "sprite"
- *
- * Released under the MIT license.
- *
- * More Info:
- * http://ejohn.org/projects/javascript-diff-algorithm/
- *
- * Usage: QUnit.diff(expected, actual)
- *
- * QUnit.diff( "the quick brown fox jumped over", "the quick fox jumps over" ) == "the quick brown fox jumped jumps over"
- */
-QUnit.diff = (function() {
- /*jshint eqeqeq:false, eqnull:true */
- function diff( o, n ) {
- var i,
- ns = {},
- os = {};
-
- for ( i = 0; i < n.length; i++ ) {
- if ( !hasOwn.call( ns, n[i] ) ) {
- ns[ n[i] ] = {
- rows: [],
- o: null
- };
- }
- ns[ n[i] ].rows.push( i );
- }
-
- for ( i = 0; i < o.length; i++ ) {
- if ( !hasOwn.call( os, o[i] ) ) {
- os[ o[i] ] = {
- rows: [],
- n: null
- };
- }
- os[ o[i] ].rows.push( i );
- }
-
- for ( i in ns ) {
- if ( !hasOwn.call( ns, i ) ) {
- continue;
- }
- if ( ns[i].rows.length === 1 && hasOwn.call( os, i ) && os[i].rows.length === 1 ) {
- n[ ns[i].rows[0] ] = {
- text: n[ ns[i].rows[0] ],
- row: os[i].rows[0]
- };
- o[ os[i].rows[0] ] = {
- text: o[ os[i].rows[0] ],
- row: ns[i].rows[0]
- };
- }
- }
-
- for ( i = 0; i < n.length - 1; i++ ) {
- if ( n[i].text != null && n[ i + 1 ].text == null && n[i].row + 1 < o.length && o[ n[i].row + 1 ].text == null &&
- n[ i + 1 ] == o[ n[i].row + 1 ] ) {
-
- n[ i + 1 ] = {
- text: n[ i + 1 ],
- row: n[i].row + 1
- };
- o[ n[i].row + 1 ] = {
- text: o[ n[i].row + 1 ],
- row: i + 1
- };
- }
- }
-
- for ( i = n.length - 1; i > 0; i-- ) {
- if ( n[i].text != null && n[ i - 1 ].text == null && n[i].row > 0 && o[ n[i].row - 1 ].text == null &&
- n[ i - 1 ] == o[ n[i].row - 1 ]) {
-
- n[ i - 1 ] = {
- text: n[ i - 1 ],
- row: n[i].row - 1
- };
- o[ n[i].row - 1 ] = {
- text: o[ n[i].row - 1 ],
- row: i - 1
- };
- }
- }
-
- return {
- o: o,
- n: n
- };
- }
-
- return function( o, n ) {
- o = o.replace( /\s+$/, "" );
- n = n.replace( /\s+$/, "" );
-
- var i, pre,
- str = "",
- out = diff( o === "" ? [] : o.split(/\s+/), n === "" ? [] : n.split(/\s+/) ),
- oSpace = o.match(/\s+/g),
- nSpace = n.match(/\s+/g);
-
- if ( oSpace == null ) {
- oSpace = [ " " ];
- }
- else {
- oSpace.push( " " );
- }
-
- if ( nSpace == null ) {
- nSpace = [ " " ];
- }
- else {
- nSpace.push( " " );
- }
-
- if ( out.n.length === 0 ) {
- for ( i = 0; i < out.o.length; i++ ) {
- str += "" + out.o[i] + oSpace[i] + "";
- }
- }
- else {
- if ( out.n[0].text == null ) {
- for ( n = 0; n < out.o.length && out.o[n].text == null; n++ ) {
- str += "" + out.o[n] + oSpace[n] + "";
- }
- }
-
- for ( i = 0; i < out.n.length; i++ ) {
- if (out.n[i].text == null) {
- str += "" + out.n[i] + nSpace[i] + "";
- }
- else {
- // `pre` initialized at top of scope
- pre = "";
-
- for ( n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++ ) {
- pre += "" + out.o[n] + oSpace[n] + "";
- }
- str += " " + out.n[i].text + nSpace[i] + pre;
- }
- }
- }
-
- return str;
- };
-}());
-
-// for CommonJS enviroments, export everything
-if ( typeof exports !== "undefined" ) {
- extend( exports, QUnit );
-}
-
-// get at whatever the global object is, like window in browsers
-}( (function() {return this;}.call()) ));
diff --git a/test/lib/require.js b/test/lib/require.js
deleted file mode 100644
index 987f865..0000000
--- a/test/lib/require.js
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- RequireJS 2.1.5 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.
- Available via the MIT or new BSD license.
- see: http://github.com/jrburke/requirejs for details
-*/
-var requirejs,require,define;
-(function(aa){function I(b){return"[object Function]"===L.call(b)}function J(b){return"[object Array]"===L.call(b)}function y(b,c){if(b){var d;for(d=0;dthis.depCount&&!this.defined){if(I(n)){if(this.events.error)try{e=i.execCb(c,n,b,e)}catch(d){a=d}else e=i.execCb(c,n,b,e);this.map.isDefine&&((b=this.module)&&void 0!==b.exports&&b.exports!==this.exports?e=b.exports:void 0===e&&this.usingExports&&(e=this.exports));if(a)return a.requireMap=this.map,a.requireModules=[this.map.id],a.requireType="define",v(this.error=
-a)}else e=n;this.exports=e;if(this.map.isDefine&&!this.ignore&&(q[c]=e,l.onResourceLoad))l.onResourceLoad(i,this.map,this.depMaps);x(c);this.defined=!0}this.defining=!1;this.defined&&!this.defineEmitted&&(this.defineEmitted=!0,this.emit("defined",this.exports),this.defineEmitComplete=!0)}}else this.fetch()}},callPlugin:function(){var a=this.map,b=a.id,d=j(a.prefix);this.depMaps.push(d);t(d,"defined",u(this,function(e){var n,d;d=this.map.name;var g=this.map.parentMap?this.map.parentMap.name:null,h=
-i.makeRequire(a.parentMap,{enableBuildCallback:!0});if(this.map.unnormalized){if(e.normalize&&(d=e.normalize(d,function(a){return c(a,g,!0)})||""),e=j(a.prefix+"!"+d,this.map.parentMap),t(e,"defined",u(this,function(a){this.init([],function(){return a},null,{enabled:!0,ignore:!0})})),d=m(p,e.id)){this.depMaps.push(e);if(this.events.error)d.on("error",u(this,function(a){this.emit("error",a)}));d.enable()}}else n=u(this,function(a){this.init([],function(){return a},null,{enabled:!0})}),n.error=u(this,
-function(a){this.inited=!0;this.error=a;a.requireModules=[b];G(p,function(a){0===a.map.id.indexOf(b+"_unnormalized")&&x(a.map.id)});v(a)}),n.fromText=u(this,function(e,c){var d=a.name,g=j(d),C=O;c&&(e=c);C&&(O=!1);r(g);s(k.config,b)&&(k.config[d]=k.config[b]);try{l.exec(e)}catch(ca){return v(B("fromtexteval","fromText eval for "+b+" failed: "+ca,ca,[b]))}C&&(O=!0);this.depMaps.push(g);i.completeLoad(d);h([d],n)}),e.load(a.name,h,n,k)}));i.enable(d,this);this.pluginMaps[d.id]=d},enable:function(){V[this.map.id]=
-this;this.enabling=this.enabled=!0;y(this.depMaps,u(this,function(a,b){var c,e;if("string"===typeof a){a=j(a,this.map.isDefine?this.map:this.map.parentMap,!1,!this.skipMap);this.depMaps[b]=a;if(c=m(N,a.id)){this.depExports[b]=c(this);return}this.depCount+=1;t(a,"defined",u(this,function(a){this.defineDep(b,a);this.check()}));this.errback&&t(a,"error",this.errback)}c=a.id;e=p[c];!s(N,c)&&(e&&!e.enabled)&&i.enable(a,this)}));G(this.pluginMaps,u(this,function(a){var b=m(p,a.id);b&&!b.enabled&&i.enable(a,
-this)}));this.enabling=!1;this.check()},on:function(a,b){var c=this.events[a];c||(c=this.events[a]=[]);c.push(b)},emit:function(a,b){y(this.events[a],function(a){a(b)});"error"===a&&delete this.events[a]}};i={config:k,contextName:b,registry:p,defined:q,urlFetched:U,defQueue:H,Module:Z,makeModuleMap:j,nextTick:l.nextTick,onError:v,configure:function(a){a.baseUrl&&"/"!==a.baseUrl.charAt(a.baseUrl.length-1)&&(a.baseUrl+="/");var b=k.pkgs,c=k.shim,e={paths:!0,config:!0,map:!0};G(a,function(a,b){e[b]?
-"map"===b?(k.map||(k.map={}),R(k[b],a,!0,!0)):R(k[b],a,!0):k[b]=a});a.shim&&(G(a.shim,function(a,b){J(a)&&(a={deps:a});if((a.exports||a.init)&&!a.exportsFn)a.exportsFn=i.makeShimExports(a);c[b]=a}),k.shim=c);a.packages&&(y(a.packages,function(a){a="string"===typeof a?{name:a}:a;b[a.name]={name:a.name,location:a.location||a.name,main:(a.main||"main").replace(ja,"").replace(ea,"")}}),k.pkgs=b);G(p,function(a,b){!a.inited&&!a.map.unnormalized&&(a.map=j(b))});if(a.deps||a.callback)i.require(a.deps||[],
-a.callback)},makeShimExports:function(a){return function(){var b;a.init&&(b=a.init.apply(aa,arguments));return b||a.exports&&ba(a.exports)}},makeRequire:function(a,f){function d(e,c,h){var g,k;f.enableBuildCallback&&(c&&I(c))&&(c.__requireJsBuild=!0);if("string"===typeof e){if(I(c))return v(B("requireargs","Invalid require call"),h);if(a&&s(N,e))return N[e](p[a.id]);if(l.get)return l.get(i,e,a,d);g=j(e,a,!1,!0);g=g.id;return!s(q,g)?v(B("notloaded",'Module name "'+g+'" has not been loaded yet for context: '+
-b+(a?"":". Use require([])"))):q[g]}L();i.nextTick(function(){L();k=r(j(null,a));k.skipMap=f.skipMap;k.init(e,c,h,{enabled:!0});D()});return d}f=f||{};R(d,{isBrowser:A,toUrl:function(b){var d,f=b.lastIndexOf("."),g=b.split("/")[0];if(-1!==f&&(!("."===g||".."===g)||1h.attachEvent.toString().indexOf("[native code"))&&!Y?(O=!0,h.attachEvent("onreadystatechange",b.onScriptLoad)):(h.addEventListener("load",b.onScriptLoad,!1),h.addEventListener("error",b.onScriptError,!1)),h.src=d,K=h,D?x.insertBefore(h,D):x.appendChild(h),K=null,h;if(da)try{importScripts(d),b.completeLoad(c)}catch(j){b.onError(B("importscripts","importScripts failed for "+c+" at "+d,j,[c]))}};A&&M(document.getElementsByTagName("script"),function(b){x||(x=
-b.parentNode);if(t=b.getAttribute("data-main"))return r.baseUrl||(E=t.split("/"),Q=E.pop(),fa=E.length?E.join("/")+"/":"./",r.baseUrl=fa,t=Q),t=t.replace(ea,""),r.deps=r.deps?r.deps.concat(t):[t],!0});define=function(b,c,d){var l,h;"string"!==typeof b&&(d=c,c=b,b=null);J(c)||(d=c,c=[]);!c.length&&I(d)&&d.length&&(d.toString().replace(la,"").replace(ma,function(b,d){c.push(d)}),c=(1===d.length?["require"]:["require","exports","module"]).concat(c));if(O){if(!(l=K))P&&"interactive"===P.readyState||M(document.getElementsByTagName("script"),
-function(b){if("interactive"===b.readyState)return P=b}),l=P;l&&(b||(b=l.getAttribute("data-requiremodule")),h=F[l.getAttribute("data-requirecontext")])}(h?h.defQueue:T).push([b,c,d])};define.amd={jQuery:!0};l.exec=function(b){return eval(b)};l(r)}})(this);
diff --git a/test/lib/resemble.js b/test/lib/resemble.js
new file mode 100644
index 0000000..1cb8c29
--- /dev/null
+++ b/test/lib/resemble.js
@@ -0,0 +1,535 @@
+/*
+Author: James Cryer
+Company: Huddle
+Last updated date: 21 Feb 2013
+URL: https://github.com/Huddle/Resemble.js
+*/
+
+(function(_this){
+ 'use strict';
+
+ _this['resemble'] = function( fileData ){
+
+ var data = {};
+ var images = [];
+ var updateCallbackArray = [];
+
+ var tolerance = { // between 0 and 255
+ red: 16,
+ green: 16,
+ blue: 16,
+ minBrightness: 16,
+ maxBrightness: 240
+ };
+
+ var ignoreAntialiasing = false;
+ var ignoreColors = false;
+
+ function triggerDataUpdate(){
+ var len = updateCallbackArray.length;
+ var i;
+ for(i=0;i tolerance.maxBrightness;
+ }
+
+ function getHue(r,g,b){
+
+ r = r / 255;
+ g = g / 255;
+ b = b / 255;
+ var max = Math.max(r, g, b), min = Math.min(r, g, b);
+ var h;
+ var d;
+
+ if (max == min){
+ h = 0; // achromatic
+ } else{
+ d = max - min;
+ switch(max){
+ case r: h = (g - b) / d + (g < b ? 6 : 0); break;
+ case g: h = (b - r) / d + 2; break;
+ case b: h = (r - g) / d + 4; break;
+ }
+ h /= 6;
+ }
+
+ return h;
+ }
+
+ function isAntialiased(sourcePix, data, cacheSet, verticalPos, horizontalPos, width){
+ var offset;
+ var targetPix;
+ var distance = 1;
+ var i;
+ var j;
+ var hasHighContrastSibling = 0;
+ var hasSiblingWithDifferentHue = 0;
+ var hasEquivilantSibling = 0;
+
+ addHueInfo(sourcePix);
+
+ for (i = distance*-1; i <= distance; i++){
+ for (j = distance*-1; j <= distance; j++){
+
+ if(i===0 && j===0){
+ // ignore source pixel
+ } else {
+
+ offset = ((verticalPos+j)*width + (horizontalPos+i)) * 4;
+ targetPix = getPixelInfo(data, offset, cacheSet);
+
+ if(targetPix === null){
+ continue;
+ }
+
+ addBrightnessInfo(targetPix);
+ addHueInfo(targetPix);
+
+ if( isContrasting(sourcePix, targetPix) ){
+ hasHighContrastSibling++;
+ }
+
+ if( isRGBSame(sourcePix,targetPix) ){
+ hasEquivilantSibling++;
+ }
+
+ if( Math.abs(targetPix.h - sourcePix.h) > 0.3 ){
+ hasSiblingWithDifferentHue++;
+ }
+
+ if( hasSiblingWithDifferentHue > 1 || hasHighContrastSibling > 1){
+ return true;
+ }
+ }
+ }
+ }
+
+ if(hasEquivilantSibling < 2){
+ return true;
+ }
+
+ return false;
+ }
+
+ function errorPixel(px, offset){
+ px[offset] = 255; //r
+ px[offset + 1] = 0; //g
+ px[offset + 2] = 255; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyPixel(px, offset, data){
+ px[offset] = data.r; //r
+ px[offset + 1] = data.g; //g
+ px[offset + 2] = data.b; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyGrayScalePixel(px, offset, data){
+ px[offset] = data.brightness; //r
+ px[offset + 1] = data.brightness; //g
+ px[offset + 2] = data.brightness; //b
+ px[offset + 3] = 255; //a
+ }
+
+
+ function getPixelInfo(data, offset, cacheSet){
+ var r;
+ var g;
+ var b;
+ var d;
+
+ if(typeof data[offset] !== 'undefined'){
+ r = data[offset];
+ g = data[offset+1];
+ b = data[offset+2];
+ d = {
+ r: r,
+ g: g,
+ b: b
+ };
+
+ return d;
+ } else {
+ return null;
+ }
+ }
+
+ function addBrightnessInfo(data){
+ data.brightness = getBrightness(data.r,data.g,data.b); // 'corrected' lightness
+ }
+
+ function addHueInfo(data){
+ data.h = getHue(data.r,data.g,data.b);
+ }
+
+ function analyseImages(img1, img2, width, height){
+
+ var hiddenCanvas = document.createElement('canvas');
+
+ var data1 = img1.data;
+ var data2 = img2.data;
+
+ hiddenCanvas.width = width;
+ hiddenCanvas.height = height;
+
+ var context = hiddenCanvas.getContext('2d');
+ var imgd = context.createImageData(width,height);
+ var targetPix = imgd.data;
+
+ var mismatchCount = 0;
+
+ var time = Date.now();
+
+ var skip;
+
+ if( (width > 1200 || height > 1200) && ignoreAntialiasing){
+ skip = 6;
+ }
+
+ loop(height, width, function(verticalPos, horizontalPos){
+
+ if(skip){ // only skip if the image isn't small
+ if(verticalPos % skip === 0 || horizontalPos % skip === 0){
+ return;
+ }
+ }
+
+ var offset = (verticalPos*width + horizontalPos) * 4;
+ var pixel1 = getPixelInfo(data1, offset, 1);
+ var pixel2 = getPixelInfo(data2, offset, 2);
+
+ if(pixel1 === null || pixel2 === null){
+ return;
+ }
+
+ if (ignoreColors){
+
+ addBrightnessInfo(pixel1);
+ addBrightnessInfo(pixel2);
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ return;
+ }
+
+ if( isRGBSimilar(pixel1, pixel2) ){
+ copyPixel(targetPix, offset, pixel2);
+
+ } else if( ignoreAntialiasing && (
+ addBrightnessInfo(pixel1), // jit pixel info augmentation looks a little weird, sorry.
+ addBrightnessInfo(pixel2),
+ isAntialiased(pixel1, data1, 1, verticalPos, horizontalPos, width) ||
+ isAntialiased(pixel2, data2, 2, verticalPos, horizontalPos, width)
+ )){
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+
+ });
+
+ data.misMatchPercentage = (mismatchCount / (height*width) * 100).toFixed(2);
+ data.analysisTime = Date.now() - time;
+
+ data.getImageDataUrl = function(text){
+ var barHeight = 0;
+
+ if(text){
+ barHeight = addLabel(text,context,hiddenCanvas);
+ }
+
+ context.putImageData(imgd, 0, barHeight);
+
+ return hiddenCanvas.toDataURL("image/png");
+ };
+ }
+
+ function addLabel(text, context, hiddenCanvas){
+ var textPadding = 2;
+
+ context.font = '12px sans-serif';
+
+ var textWidth = context.measureText(text).width + textPadding*2;
+ var barHeight = 22;
+
+ if(textWidth > hiddenCanvas.width){
+ hiddenCanvas.width = textWidth;
+ }
+
+ hiddenCanvas.height += barHeight;
+
+ context.fillStyle = "#666";
+ context.fillRect(0,0,hiddenCanvas.width,barHeight -4);
+ context.fillStyle = "#fff";
+ context.fillRect(0,barHeight -4,hiddenCanvas.width, 4);
+
+ context.fillStyle = "#fff";
+ context.textBaseline = "top";
+ context.font = '12px sans-serif';
+ context.fillText(text, textPadding, 1);
+
+ return barHeight;
+ }
+
+ function normalise(img, w, h){
+ var c;
+ var context;
+
+ if(img.height < h || img.width < w){
+ c = document.createElement('canvas');
+ c.width = w;
+ c.height = h;
+ context = c.getContext('2d');
+ context.putImageData(img, 0, 0);
+ return context.getImageData(0, 0, w, h);
+ }
+
+ return img;
+ }
+
+ function compare(one, two){
+
+ function onceWeHaveBoth(){
+ var width;
+ var height;
+ if(images.length === 2){
+ width = images[0].width > images[1].width ? images[0].width : images[1].width;
+ height = images[0].height > images[1].height ? images[0].height : images[1].height;
+
+ if( (images[0].width === images[1].width) && (images[0].height === images[1].height) ){
+ data.isSameDimensions = true;
+ } else {
+ data.isSameDimensions = false;
+ }
+
+ analyseImages( normalise(images[0],width, height), normalise(images[1],width, height), width, height);
+
+ triggerDataUpdate();
+ }
+ }
+
+ images = [];
+ loadImageData(one, onceWeHaveBoth);
+ loadImageData(two, onceWeHaveBoth);
+ }
+
+ function getCompareApi(param){
+
+ var secondFileData,
+ hasMethod = typeof param === 'function';
+
+ if( !hasMethod ){
+ // assume it's file data
+ secondFileData = param;
+ }
+
+ var self = {
+ ignoreNothing: function(){
+
+ tolerance.red = 16;
+ tolerance.green = 16;
+ tolerance.blue = 16;
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreAntialiasing: function(){
+
+ tolerance.red = 32;
+ tolerance.green = 32;
+ tolerance.blue = 32;
+ tolerance.minBrightness = 64;
+ tolerance.maxBrightness = 96;
+
+ ignoreAntialiasing = true;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreColors: function(){
+
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = true;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ onComplete: function( callback ){
+
+ updateCallbackArray.push(callback);
+
+ var wrapper = function(){
+ compare(fileData, secondFileData);
+ };
+
+ wrapper();
+
+ return getCompareApi(wrapper);
+ }
+ };
+
+ return self;
+ }
+
+ return {
+ onComplete: function( callback ){
+ updateCallbackArray.push(callback);
+ loadImageData(fileData, function(imageData, width, height){
+ parseImage(imageData.data, width, height);
+ });
+ },
+ compareTo: function(secondFileData){
+ return getCompareApi(secondFileData);
+ }
+ };
+
+ };
+}(this));
\ No newline at end of file
diff --git a/test/testsuite.js b/test/testsuite.js
deleted file mode 100644
index b486acb..0000000
--- a/test/testsuite.js
+++ /dev/null
@@ -1,36 +0,0 @@
-requirejs.config({
- baseUrl: '/test/unit/'
-});
-
-define(function(require) {
- var testModules = [
- 'Pixi',
- 'Point',
- 'Rectangle',
- 'DisplayObject',
- 'DisplayObjectContainer',
- 'Sprite',
- 'MovieClip',
- 'InteractionManager',
- 'Stage',
- 'utils/Utils',
- 'utils/EventTarget',
- 'utils/Matrix',
- 'utils/Detector',
- 'renderers/WebGLShaders',
- 'renderers/WebGLRenderer',
- 'renderers/WebGLBatch',
- 'renderers/CanvasRenderer',
- 'extras/Strip',
- 'extras/Rope',
- 'textures/BaseTexture',
- 'textures/Texture',
- 'loaders/SpriteSheetLoader',
- 'loaders/AssetLoader'
- ];
-
- // Resolve all testModules and then start the Test Runner.
- require(testModules, function() {
- QUnit.start();
- });
-});
\ No newline at end of file
diff --git a/test/textures/SpriteSheet-Aliens.png b/test/textures/SpriteSheet-Aliens.png
new file mode 100644
index 0000000..210acb1
--- /dev/null
+++ b/test/textures/SpriteSheet-Aliens.png
Binary files differ
diff --git a/test/textures/SpriteSheet-Explosion.png b/test/textures/SpriteSheet-Explosion.png
new file mode 100755
index 0000000..79e1a69
--- /dev/null
+++ b/test/textures/SpriteSheet-Explosion.png
Binary files differ
diff --git a/test/textures/bunny.png b/test/textures/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/textures/bunny.png
Binary files differ
diff --git a/test/unit/DisplayObject.js b/test/unit/DisplayObject.js
deleted file mode 100644
index 5e7e72f..0000000
--- a/test/unit/DisplayObject.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObject');
-});
diff --git a/test/unit/DisplayObjectContainer.js b/test/unit/DisplayObjectContainer.js
deleted file mode 100644
index b323959..0000000
--- a/test/unit/DisplayObjectContainer.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObjectContainer');
-});
diff --git a/test/unit/InteractionManager.js b/test/unit/InteractionManager.js
deleted file mode 100644
index e751f52..0000000
--- a/test/unit/InteractionManager.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('InteractionManager');
-});
diff --git a/test/unit/MovieClip.js b/test/unit/MovieClip.js
deleted file mode 100644
index 37d9446..0000000
--- a/test/unit/MovieClip.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('MovieClip');
-});
diff --git a/test/unit/Pixi.js b/test/unit/Pixi.js
deleted file mode 100644
index 36eee73..0000000
--- a/test/unit/Pixi.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Pixi');
-});
diff --git a/test/unit/Point.js b/test/unit/Point.js
deleted file mode 100644
index 983ff6e..0000000
--- a/test/unit/Point.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Point');
-});
diff --git a/test/unit/Rectangle.js b/test/unit/Rectangle.js
deleted file mode 100644
index 3b439ba..0000000
--- a/test/unit/Rectangle.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Rectangle');
-});
diff --git a/test/unit/Sprite.js b/test/unit/Sprite.js
deleted file mode 100644
index ed4f596..0000000
--- a/test/unit/Sprite.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Sprite');
-});
diff --git a/test/unit/Stage.js b/test/unit/Stage.js
deleted file mode 100644
index 2d70291..0000000
--- a/test/unit/Stage.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Stage');
-});
diff --git a/test/unit/extras/Rope.js b/test/unit/extras/Rope.js
deleted file mode 100644
index 5606f14..0000000
--- a/test/unit/extras/Rope.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Rope');
-});
diff --git a/test/unit/extras/Strip.js b/test/unit/extras/Strip.js
deleted file mode 100644
index 0134d3a..0000000
--- a/test/unit/extras/Strip.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Strip');
-});
diff --git a/test/unit/loaders/AssetLoader.js b/test/unit/loaders/AssetLoader.js
deleted file mode 100644
index 13b8443..0000000
--- a/test/unit/loaders/AssetLoader.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('AssetLoader');
-});
diff --git a/test/unit/loaders/SpriteSheetLoader.js b/test/unit/loaders/SpriteSheetLoader.js
deleted file mode 100644
index 8bf0cb2..0000000
--- a/test/unit/loaders/SpriteSheetLoader.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('SpriteSheetLoader');
-});
diff --git a/test/unit/pixi/InteractionManager.js b/test/unit/pixi/InteractionManager.js
new file mode 100644
index 0000000..ed3001f
--- /dev/null
+++ b/test/unit/pixi/InteractionManager.js
@@ -0,0 +1,10 @@
+describe('pixi/InteractionManager', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var InteractionManager = PIXI.InteractionManager;
+
+ it('Module exists', function () {
+ expect(InteractionManager).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/Pixi.js b/test/unit/pixi/Pixi.js
new file mode 100644
index 0000000..27debc1
--- /dev/null
+++ b/test/unit/pixi/Pixi.js
@@ -0,0 +1,9 @@
+describe('pixi/Pixi', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+
+ it('Module exists', function () {
+ expect(global).to.have.property('PIXI').and.to.be.an('object');
+ });
+});
diff --git a/test/unit/pixi/core/Circle.js b/test/unit/pixi/core/Circle.js
new file mode 100644
index 0000000..93a4456
--- /dev/null
+++ b/test/unit/pixi/core/Circle.js
@@ -0,0 +1,22 @@
+describe('pixi/core/Circle', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Circle = PIXI.Circle;
+
+ it('Module exists', function () {
+ expect(Circle).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Circle();
+
+ expect(obj).to.be.an.instanceof(Circle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', 0);
+ expect(obj).to.have.property('y', 0);
+ expect(obj).to.have.property('radius', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Ellipse.js b/test/unit/pixi/core/Ellipse.js
new file mode 100644
index 0000000..026b56f
--- /dev/null
+++ b/test/unit/pixi/core/Ellipse.js
@@ -0,0 +1,24 @@
+describe('pixi/core/Ellipse', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Ellipse = PIXI.Ellipse;
+
+ it('Module exists', function () {
+ expect(Ellipse).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Ellipse();
+
+ expect(obj).to.be.an.instanceof(Ellipse);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+ expect(obj).to.respondTo('getBounds');
+
+ expect(obj).to.have.property('x', 0);
+ expect(obj).to.have.property('y', 0);
+ expect(obj).to.have.property('width', 0);
+ expect(obj).to.have.property('height', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Matrix.js b/test/unit/pixi/core/Matrix.js
new file mode 100644
index 0000000..b48989e
--- /dev/null
+++ b/test/unit/pixi/core/Matrix.js
@@ -0,0 +1,30 @@
+describe('pixi/core/Matrix', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var mat3 = PIXI.mat3;
+ var mat4 = PIXI.mat4;
+ var Matrix = PIXI.Matrix;
+
+ it('Ensure determineMatrixArrayType works', function () {
+ expect(Matrix).to.be.a('function');
+ });
+
+ it('mat3 exists', function () {
+ expect(mat3).to.be.an('object');
+ });
+
+ it('Confirm new mat3 matrix', function () {
+ var matrix = new mat3.create();
+ pixi_core_Matrix_confirmNewMat3(matrix);
+ });
+
+ it('mat3 exists', function () {
+ expect(mat4).to.be.an('object');
+ });
+
+ it('Confirm new mat4 matrix', function () {
+ var matrix = new mat4.create();
+ pixi_core_Matrix_confirmNewMat4(matrix);
+ });
+});
diff --git a/test/unit/pixi/core/Point.js b/test/unit/pixi/core/Point.js
new file mode 100644
index 0000000..c4d5163
--- /dev/null
+++ b/test/unit/pixi/core/Point.js
@@ -0,0 +1,15 @@
+describe('pixi/core/Point', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Point = PIXI.Point;
+
+ it('Module exists', function () {
+ expect(Point).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Point();
+ pixi_core_Point_confirm(obj, 0, 0);
+ });
+});
diff --git a/test/unit/pixi/core/Polygon.js b/test/unit/pixi/core/Polygon.js
new file mode 100644
index 0000000..dc8c918
--- /dev/null
+++ b/test/unit/pixi/core/Polygon.js
@@ -0,0 +1,20 @@
+describe('pixi/core/Polygon', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Polygon = PIXI.Polygon;
+
+ it('Module exists', function () {
+ expect(Polygon).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Polygon();
+
+ expect(obj).to.be.an.instanceof(Polygon);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.deep.property('points.length', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Rectangle.js b/test/unit/pixi/core/Rectangle.js
new file mode 100644
index 0000000..d43316e
--- /dev/null
+++ b/test/unit/pixi/core/Rectangle.js
@@ -0,0 +1,15 @@
+describe('pixi/core/Rectangle', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Rectangle = PIXI.Rectangle;
+
+ it('Module exists', function () {
+ expect(Rectangle).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var rect = new Rectangle();
+ pixi_core_Rectangle_confirm(rect, 0, 0, 0, 0);
+ });
+});
diff --git a/test/unit/pixi/display/DisplayObject.js b/test/unit/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..40c6fbc
--- /dev/null
+++ b/test/unit/pixi/display/DisplayObject.js
@@ -0,0 +1,21 @@
+describe('pixi/display/DisplayObject', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var DisplayObject = PIXI.DisplayObject;
+
+ it('Module exists', function () {
+ expect(DisplayObject).to.be.a('function');
+ expect(PIXI).to.have.property('visibleCount', 0);
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new DisplayObject();
+
+ pixi_display_DisplayObject_confirmNew(obj);
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', false);
+ expect(obj).to.have.property('stage', null);
+ });
+});
diff --git a/test/unit/pixi/display/DisplayObjectContainer.js b/test/unit/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..ce7f02f
--- /dev/null
+++ b/test/unit/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,20 @@
+describe('pixi/display/DisplayObjectContainer', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var DisplayObjectContainer = PIXI.DisplayObjectContainer;
+
+ it('Module exists', function () {
+ expect(DisplayObjectContainer).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new DisplayObjectContainer();
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', false);
+ expect(obj).to.have.property('stage', null);
+ });
+});
diff --git a/test/unit/pixi/display/MovieClip.js b/test/unit/pixi/display/MovieClip.js
new file mode 100644
index 0000000..f3c6c6a
--- /dev/null
+++ b/test/unit/pixi/display/MovieClip.js
@@ -0,0 +1,33 @@
+describe('pixi/display/MovieClip', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var MovieClip = PIXI.MovieClip;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(MovieClip).to.be.a('function');
+ });
+
+ it('Confirm new instance', function (done) {
+ var texture = Texture.fromImage('/base/test/textures/SpriteSheet-Explosion.png');
+ var obj = new MovieClip([texture]);
+
+ pixi_display_Sprite_confirmNew(obj, done);
+
+ expect(obj).to.be.an.instanceof(MovieClip);
+ expect(obj).to.respondTo('stop');
+ expect(obj).to.respondTo('play');
+ expect(obj).to.respondTo('gotoAndStop');
+ expect(obj).to.respondTo('gotoAndPlay');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('textures.length', 1);
+ expect(obj).to.have.deep.property('textures[0]', texture);
+ expect(obj).to.have.property('animationSpeed', 1);
+ expect(obj).to.have.property('loop', true);
+ expect(obj).to.have.property('onComplete', null);
+ expect(obj).to.have.property('currentFrame', 0);
+ expect(obj).to.have.property('playing', false);
+ });
+});
diff --git a/test/unit/pixi/display/Sprite.js b/test/unit/pixi/display/Sprite.js
new file mode 100644
index 0000000..54e914f
--- /dev/null
+++ b/test/unit/pixi/display/Sprite.js
@@ -0,0 +1,25 @@
+describe('pixi/display/Sprite', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Sprite = PIXI.Sprite;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(Sprite).to.be.a('function');
+ expect(PIXI).to.have.deep.property('blendModes.NORMAL', 0);
+ expect(PIXI).to.have.deep.property('blendModes.SCREEN', 1);
+ });
+
+ it('Members exist', function () {
+ expect(Sprite).itself.to.respondTo('fromImage');
+ expect(Sprite).itself.to.respondTo('fromFrame');
+ });
+
+ it('Confirm new instance', function (done) {
+ var texture = Texture.fromImage('/base/test/textures/SpriteSheet-Aliens.png');
+ var obj = new Sprite(texture);
+
+ pixi_display_Sprite_confirmNew(obj, done);
+ });
+});
diff --git a/test/unit/pixi/display/Stage.js b/test/unit/pixi/display/Stage.js
new file mode 100644
index 0000000..3cc2a4d
--- /dev/null
+++ b/test/unit/pixi/display/Stage.js
@@ -0,0 +1,49 @@
+describe('pixi/display/Stage', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Stage = PIXI.Stage;
+ var InteractionManager = PIXI.InteractionManager;
+ var Rectangle = PIXI.Rectangle;
+
+ it('Module exists', function () {
+ expect(Stage).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Stage(null, true);
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(Stage);
+ expect(obj).to.respondTo('updateTransform');
+ expect(obj).to.respondTo('setBackgroundColor');
+ expect(obj).to.respondTo('getMousePosition');
+
+ // FIXME: duplicate member in DisplayObject
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ // FIXME: convert arg to bool in constructor
+ expect(obj).to.have.property('interactive', true);
+
+ expect(obj).to.have.property('interactionManager')
+ .and.to.be.an.instanceof(InteractionManager)
+ .and.to.have.property('stage', obj);
+
+ expect(obj).to.have.property('dirty', true);
+
+ expect(obj).to.have.property('stage', obj);
+
+ expect(obj).to.have.property('hitArea')
+ .and.to.be.an.instanceof(Rectangle);
+ pixi_core_Rectangle_confirm(obj.hitArea, 0, 0, 100000, 100000);
+
+ expect(obj).to.have.property('backgroundColor', 0x000000);
+ expect(obj).to.have.deep.property('backgroundColorSplit.length', 3);
+ expect(obj).to.have.deep.property('backgroundColorSplit[0]', 0);
+ expect(obj).to.have.deep.property('backgroundColorSplit[1]', 0);
+ expect(obj).to.have.deep.property('backgroundColorSplit[2]', 0);
+ expect(obj).to.have.property('backgroundColorString', '#000000');
+
+ expect(obj).to.have.property('worldVisible', true);
+ });
+});
diff --git a/test/unit/pixi/extras/CustomRenderable.js b/test/unit/pixi/extras/CustomRenderable.js
new file mode 100644
index 0000000..8d83cf0
--- /dev/null
+++ b/test/unit/pixi/extras/CustomRenderable.js
@@ -0,0 +1,21 @@
+describe('pixi/extras/CustomRenderable', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var CustomRenderable = PIXI.CustomRenderable;
+
+ it('Module exists', function () {
+ expect(CustomRenderable).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new CustomRenderable();
+
+ pixi_display_DisplayObject_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(CustomRenderable);
+ expect(obj).to.respondTo('renderCanvas');
+ expect(obj).to.respondTo('initWebGL');
+ expect(obj).to.respondTo('renderWebGL');
+ });
+});
diff --git a/test/unit/pixi/extras/Rope.js b/test/unit/pixi/extras/Rope.js
new file mode 100644
index 0000000..6ddaf83
--- /dev/null
+++ b/test/unit/pixi/extras/Rope.js
@@ -0,0 +1,26 @@
+describe('pixi/extras/Rope', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Rope = PIXI.Rope;
+ var Texture = PIXI.Texture;
+ var Point = PIXI.Point;
+
+ it('Module exists', function () {
+ expect(Rope).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var texture = Texture.fromImage('/base/test/textures/bunny.png');
+ var obj = new Rope(texture, [new Point(), new Point(5, 10), new Point(10, 20)]);
+
+ pixi_extras_Strip_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(Rope);
+ expect(obj).to.respondTo('refresh');
+ expect(obj).to.respondTo('updateTransform');
+ expect(obj).to.respondTo('setTexture');
+
+ // TODO: Test properties
+ });
+});
diff --git a/test/unit/pixi/extras/Spine.js b/test/unit/pixi/extras/Spine.js
new file mode 100644
index 0000000..0708bc0
--- /dev/null
+++ b/test/unit/pixi/extras/Spine.js
@@ -0,0 +1,10 @@
+describe('pixi/extras/Spine', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Spine = PIXI.Spine;
+
+ it('Module exists', function () {
+ expect(Spine).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/extras/Strip.js b/test/unit/pixi/extras/Strip.js
new file mode 100644
index 0000000..8e564e1
--- /dev/null
+++ b/test/unit/pixi/extras/Strip.js
@@ -0,0 +1,18 @@
+describe('pixi/extras/Strip', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Strip = PIXI.Strip;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(Strip).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var texture = Texture.fromImage('/base/test/textures/bunny.png');
+ var obj = new Strip(texture, 20, 10000);
+
+ pixi_extras_Strip_confirmNew(obj);
+ });
+});
diff --git a/test/unit/pixi/extras/TilingSprite.js b/test/unit/pixi/extras/TilingSprite.js
new file mode 100644
index 0000000..56aea14
--- /dev/null
+++ b/test/unit/pixi/extras/TilingSprite.js
@@ -0,0 +1,24 @@
+describe('pixi/extras/TilingSprite', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var TilingSprite = PIXI.TilingSprite;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(TilingSprite).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var texture = Texture.fromImage('/base/test/textures/bunny.png');
+ var obj = new TilingSprite(texture, 6000, 12000);
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(TilingSprite);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ // TODO: Test properties
+ });
+});
diff --git a/test/unit/pixi/filters/FilterBlock.js b/test/unit/pixi/filters/FilterBlock.js
new file mode 100644
index 0000000..870cec0
--- /dev/null
+++ b/test/unit/pixi/filters/FilterBlock.js
@@ -0,0 +1,10 @@
+describe('pixi/filters/FilterBlock', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var FilterBlock = PIXI.FilterBlock;
+
+ it('Module exists', function () {
+ expect(FilterBlock).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/filters/MaskFilter.js b/test/unit/pixi/filters/MaskFilter.js
new file mode 100644
index 0000000..32d6a45
--- /dev/null
+++ b/test/unit/pixi/filters/MaskFilter.js
@@ -0,0 +1,10 @@
+describe('pixi/filters/MaskFilter', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ // var MaskFilter = PIXI.MaskFilter;
+
+ // it('Module exists', function () {
+ // expect(MaskFilter).to.be.a('function');
+ // });
+});
diff --git a/test/unit/pixi/loaders/AssetLoader.js b/test/unit/pixi/loaders/AssetLoader.js
new file mode 100644
index 0000000..a0aa0b5
--- /dev/null
+++ b/test/unit/pixi/loaders/AssetLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/AssetLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var AssetLoader = PIXI.AssetLoader;
+
+ it('Module exists', function () {
+ expect(AssetLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/BitmapFontLoader.js b/test/unit/pixi/loaders/BitmapFontLoader.js
new file mode 100644
index 0000000..6253c42
--- /dev/null
+++ b/test/unit/pixi/loaders/BitmapFontLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/BitmapFontLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var BitmapFontLoader = PIXI.BitmapFontLoader;
+
+ it('Module exists', function () {
+ expect(PIXI.BitmapFontLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/ImageLoader.js b/test/unit/pixi/loaders/ImageLoader.js
new file mode 100644
index 0000000..8b1f556
--- /dev/null
+++ b/test/unit/pixi/loaders/ImageLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/ImageLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var ImageLoader = PIXI.ImageLoader;
+
+ it('Module exists', function () {
+ expect(ImageLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/JsonLoader.js b/test/unit/pixi/loaders/JsonLoader.js
new file mode 100644
index 0000000..c577e83
--- /dev/null
+++ b/test/unit/pixi/loaders/JsonLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/JsonLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var JsonLoader = PIXI.JsonLoader;
+
+ it('Module exists', function () {
+ expect(JsonLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/SpineLoader.js b/test/unit/pixi/loaders/SpineLoader.js
new file mode 100644
index 0000000..fdcc0b8
--- /dev/null
+++ b/test/unit/pixi/loaders/SpineLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/SpineLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var SpineLoader = PIXI.SpineLoader;
+
+ it('Module exists', function () {
+ expect(SpineLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/SpriteSheetLoader.js b/test/unit/pixi/loaders/SpriteSheetLoader.js
new file mode 100644
index 0000000..57beb27
--- /dev/null
+++ b/test/unit/pixi/loaders/SpriteSheetLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/SpriteSheetLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var SpriteSheetLoader = PIXI.SpriteSheetLoader;
+
+ it('Module exists', function () {
+ expect(SpriteSheetLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/primitives/Graphics.js b/test/unit/pixi/primitives/Graphics.js
new file mode 100644
index 0000000..b8b3e5c
--- /dev/null
+++ b/test/unit/pixi/primitives/Graphics.js
@@ -0,0 +1,40 @@
+describe('pixi/primitives/Graphics', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Graphics = PIXI.Graphics;
+
+ it('Module exists', function () {
+ expect(Graphics).to.be.a('function');
+
+ expect(Graphics).itself.to.have.property('POLY', 0);
+ expect(Graphics).itself.to.have.property('RECT', 1);
+ expect(Graphics).itself.to.have.property('CIRC', 2);
+ expect(Graphics).itself.to.have.property('ELIP', 3);
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Graphics();
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(Graphics);
+ expect(obj).to.respondTo('lineStyle');
+ expect(obj).to.respondTo('lineStyle');
+ expect(obj).to.respondTo('moveTo');
+ expect(obj).to.respondTo('lineTo');
+ expect(obj).to.respondTo('beginFill');
+ expect(obj).to.respondTo('endFill');
+ expect(obj).to.respondTo('drawRect');
+ expect(obj).to.respondTo('drawCircle');
+ expect(obj).to.respondTo('drawElipse');
+ expect(obj).to.respondTo('clear');
+
+ expect(obj).to.have.property('renderable', true);
+ expect(obj).to.have.property('fillAlpha', 1);
+ expect(obj).to.have.property('lineWidth', 0);
+ expect(obj).to.have.property('lineColor', 'black');
+ expect(obj).to.have.deep.property('graphicsData.length', 0);
+ expect(obj).to.have.deep.property('currentPath.points.length', 0);
+ });
+});
diff --git a/test/unit/pixi/renderers/canvas/CanvasGraphics.js b/test/unit/pixi/renderers/canvas/CanvasGraphics.js
new file mode 100644
index 0000000..8f44472
--- /dev/null
+++ b/test/unit/pixi/renderers/canvas/CanvasGraphics.js
@@ -0,0 +1,15 @@
+describe('renders/canvas/CanvasGraphics', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var CanvasGraphics = PIXI.CanvasGraphics;
+
+ it('Module exists', function () {
+ expect(CanvasGraphics).to.be.a('function');
+ });
+
+ it('Members exist', function () {
+ expect(CanvasGraphics).itself.to.respondTo('renderGraphics');
+ expect(CanvasGraphics).itself.to.respondTo('renderGraphicsMask');
+ });
+});
diff --git a/test/unit/pixi/renderers/canvas/CanvasRenderer.js b/test/unit/pixi/renderers/canvas/CanvasRenderer.js
new file mode 100644
index 0000000..df3a12f
--- /dev/null
+++ b/test/unit/pixi/renderers/canvas/CanvasRenderer.js
@@ -0,0 +1,10 @@
+describe('renderers/canvas/CanvasRenderer', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var CanvasRenderer = PIXI.CanvasRenderer;
+
+ it('Module exists', function () {
+ expect(CanvasRenderer).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/renderers/webgl/WebGLBatch.js b/test/unit/pixi/renderers/webgl/WebGLBatch.js
new file mode 100644
index 0000000..75efd56
--- /dev/null
+++ b/test/unit/pixi/renderers/webgl/WebGLBatch.js
@@ -0,0 +1,10 @@
+describe('renderers/webgl/WebGLBatch', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var WebGLBatch = PIXI.WebGLBatch;
+
+ it('Module exists', function () {
+ expect(WebGLBatch).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/renderers/webgl/WebGLGraphics.js b/test/unit/pixi/renderers/webgl/WebGLGraphics.js
new file mode 100644
index 0000000..41bf941
--- /dev/null
+++ b/test/unit/pixi/renderers/webgl/WebGLGraphics.js
@@ -0,0 +1,19 @@
+describe('renderers/wegbl/WebGLGraphics', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var WebGLGraphics = PIXI.WebGLGraphics;
+
+ it('Module exists', function () {
+ expect(WebGLGraphics).to.be.a('function');
+ });
+
+ it('Members exist', function () {
+ expect(WebGLGraphics).itself.to.respondTo('renderGraphics');
+ expect(WebGLGraphics).itself.to.respondTo('updateGraphics');
+ expect(WebGLGraphics).itself.to.respondTo('buildRectangle');
+ expect(WebGLGraphics).itself.to.respondTo('buildCircle');
+ expect(WebGLGraphics).itself.to.respondTo('buildLine');
+ expect(WebGLGraphics).itself.to.respondTo('buildPoly');
+ });
+});
diff --git a/test/unit/pixi/renderers/webgl/WebGLRenderGroup.js b/test/unit/pixi/renderers/webgl/WebGLRenderGroup.js
new file mode 100644
index 0000000..f4ee366
--- /dev/null
+++ b/test/unit/pixi/renderers/webgl/WebGLRenderGroup.js
@@ -0,0 +1,10 @@
+describe('renderers/webgl/WebGLRenderGroup', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var WebGLRenderGroup = PIXI.WebGLRenderGroup;
+
+ it('Module exists', function () {
+ expect(WebGLRenderGroup).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/renderers/webgl/WebGLRenderer.js b/test/unit/pixi/renderers/webgl/WebGLRenderer.js
new file mode 100644
index 0000000..86533eb
--- /dev/null
+++ b/test/unit/pixi/renderers/webgl/WebGLRenderer.js
@@ -0,0 +1,10 @@
+describe('renderers/webgl/WebGLRenderer', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var WebGLRenderer = PIXI.WebGLRenderer;
+
+ it('Module exists', function () {
+ expect(WebGLRenderer).to.be.a('function');
+ });
+});
diff --git a/.gitignore b/.gitignore
index 12e1b62..0b88317 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
node_modules
.DS_Store
-.project
\ No newline at end of file
+.project
+*.log
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..63e4d7c
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,8 @@
+language: node_js
+node_js:
+ - 0.10
+
+before_script:
+ - npm install -g grunt-cli
+ - export DISPLAY=:99.0
+ - sh -e /etc/init.d/xvfb start
diff --git a/Gruntfile.js b/Gruntfile.js
index b083b49..103938c 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -1,10 +1,12 @@
+'use strict';
+
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-connect');
- grunt.loadNpmTasks('grunt-contrib-qunit');
grunt.loadNpmTasks('grunt-contrib-yuidoc');
+ grunt.loadTasks('tasks');
var root = 'src/pixi/',
debug = 'bin/pixi.dev.js',
@@ -79,7 +81,7 @@
},
files: {
srcBlob: '<%= dirs.src %>/**/*.js',
- testBlob: '<%= dirs.test %>/unit/**/*.js',
+ testBlob: '<%= dirs.test %>/{functional,lib/pixi,unit}/**/*.js',
build: '<%= dirs.build %>/pixi.dev.js',
buildMin: '<%= dirs.build %>/pixi.js'
},
@@ -94,7 +96,12 @@
},
jshint: {
beforeconcat: srcFiles,
- test: ['<%= files.testBlob %>'],
+ test: {
+ src: ['<%= files.testBlob %>'],
+ options: {
+ expr: true
+ }
+ },
options: {
asi: true,
smarttabs: true
@@ -128,12 +135,6 @@
]
},
connect: {
- qunit: {
- options: {
- port: grunt.option('port-test') || 9002,
- base: './'
- }
- },
test: {
options: {
port: grunt.option('port-test') || 9002,
@@ -142,13 +143,6 @@
}
}
},
- qunit: {
- all: {
- options: {
- urls: ['http://localhost:' + (grunt.option('port-test') || 9002) + '/test/index.html']
- }
- }
- },
yuidoc: {
compile: {
name: '<%= pkg.name %>',
@@ -161,6 +155,13 @@
outdir: '<%= dirs.docs %>'
}
}
+ },
+ karma: {
+ unit: {
+ configFile: 'test/karma.conf.js',
+ // browsers: ['Chrome'],
+ singleRun: true
+ }
}
});
@@ -182,9 +183,10 @@
}
)
- grunt.registerTask('default', ['concat', 'uglify', 'distribute']);
grunt.registerTask('build', ['concat', 'uglify', 'distribute']);
- grunt.registerTask('test', ['build', 'connect:qunit', 'qunit']);
+ grunt.registerTask('test', ['concat', 'jshint:test', 'karma']);
grunt.registerTask('docs', ['yuidoc']);
-
-}
\ No newline at end of file
+ grunt.registerTask('default', ['test', 'uglify', 'distribute']);
+ // Travis CI task.
+ grunt.registerTask('travis', ['test']);
+}
diff --git a/README.md b/README.md
index c62ef86..690cfe4 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,8 @@

+[](http://travis-ci.org/drkibitz/pixi.js)
+
#### JavaScript 2D Renderer ####
The aim of this project is to provide a fast lightweight 2D library that works
diff --git a/package.json b/package.json
index b373240..1246a68 100644
--- a/package.json
+++ b/package.json
@@ -18,14 +18,21 @@
"main": "bin/pixi.js",
+ "scripts": {
+ "test": "grunt travis --verbose"
+ },
+
"dependencies": {},
"devDependencies": {
"grunt": "~0.4.x",
- "grunt-contrib-jshint": "0.3.x",
+ "grunt-contrib-jshint": "0.6.x",
"grunt-contrib-uglify": "0.2.x",
- "grunt-contrib-connect": "0.2.x",
- "grunt-contrib-qunit": "0.2.x",
+ "grunt-contrib-connect": "0.3.x",
"grunt-contrib-yuidoc": "0.4.x",
- "grunt-contrib-concat": "0.1.x"
+ "grunt-contrib-concat": "0.3.x",
+ "chai": "~1.7.0",
+ "karma": "0.11.0",
+ "karma-firefox-launcher": "0.1.0",
+ "karma-mocha": "0.1.0"
}
}
diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js
index a7c520e..ee82bbd 100644
--- a/src/pixi/InteractionManager.js
+++ b/src/pixi/InteractionManager.js
@@ -62,7 +62,6 @@
this.onTouchEnd = this.onTouchEnd.bind(this);
this.onTouchMove = this.onTouchMove.bind(this);
-
this.last = 0;
}
diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js
index 1a95d20..eef1059 100644
--- a/src/pixi/core/Ellipse.js
+++ b/src/pixi/core/Ellipse.js
@@ -78,7 +78,7 @@
return (normx + normy < 0.25);
}
-PIXI.Ellipse.getBounds = function()
+PIXI.Ellipse.prototype.getBounds = function()
{
return new PIXI.Rectangle(this.x, this.y, this.width, this.height);
}
diff --git a/tasks/karma.js b/tasks/karma.js
new file mode 100644
index 0000000..c340485
--- /dev/null
+++ b/tasks/karma.js
@@ -0,0 +1,27 @@
+'use strict';
+
+var path = require('path');
+var server = require('karma').server;
+
+module.exports = function (grunt) {
+ grunt.registerMultiTask('karma', 'run karma.', function() {
+ var done = this.async();
+ var options = this.options({
+ background: false
+ });
+ var data = this.data;
+
+ //merge options onto data, with data taking precedence
+ data = grunt.util._.merge(options, data);
+ data.configFile = path.resolve(data.configFile);
+ if (data.configFile) {
+ data.configFile = grunt.template.process(data.configFile);
+ }
+
+ server.start(
+ data,
+ function(code) {
+ done(!code);
+ });
+ });
+};
diff --git a/test/functional/example-1-basics/bunny.png b/test/functional/example-1-basics/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/functional/example-1-basics/bunny.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-30.png b/test/functional/example-1-basics/frame-30.png
new file mode 100644
index 0000000..96e3409
--- /dev/null
+++ b/test/functional/example-1-basics/frame-30.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-60.png b/test/functional/example-1-basics/frame-60.png
new file mode 100644
index 0000000..af3f4ce
--- /dev/null
+++ b/test/functional/example-1-basics/frame-60.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-90.png b/test/functional/example-1-basics/frame-90.png
new file mode 100644
index 0000000..099b823
--- /dev/null
+++ b/test/functional/example-1-basics/frame-90.png
Binary files differ
diff --git a/test/functional/example-1-basics/index.js b/test/functional/example-1-basics/index.js
new file mode 100644
index 0000000..7ae7a98
--- /dev/null
+++ b/test/functional/example-1-basics/index.js
@@ -0,0 +1,133 @@
+describe('Example 1 - Basics', function () {
+ 'use strict';
+
+ var baseUri = '/base/test/functional/example-1-basics';
+ var expect = chai.expect;
+ var currentFrame = 0;
+ var frameEvents = {};
+ var stage;
+ var renderer;
+ var bunny;
+
+ function onFrame(frame, callback) {
+ frameEvents[frame] = callback;
+ }
+
+ function animate() {
+ currentFrame += 1;
+
+ requestAnimFrame( animate );
+
+ // just for fun, lets rotate mr rabbit a little
+ bunny.rotation += 0.1;
+
+ // render the stage
+ renderer.render(stage);
+
+ if (frameEvents[currentFrame])
+ frameEvents[currentFrame](currentFrame);
+ }
+
+ function initScene() {
+ // create an new instance of a pixi stage
+ stage = new PIXI.Stage(0x66FF99);
+
+ // create a renderer instance
+ renderer = PIXI.autoDetectRenderer(400, 300);
+ console.log('Is PIXI.WebGLRenderer: ' + (renderer instanceof PIXI.WebGLRenderer));
+
+ // add the renderer view element to the DOM
+ document.body.appendChild(renderer.view);
+
+ requestAnimFrame( animate );
+
+ // create a texture from an image path
+ var texture = PIXI.Texture.fromImage(baseUri + "/bunny.png");
+ // create a new Sprite using the texture
+ bunny = new PIXI.Sprite(texture);
+
+ // center the sprites anchor point
+ bunny.anchor.x = 0.5;
+ bunny.anchor.y = 0.5;
+
+ // move the sprite t the center of the screen
+ bunny.position.x = 200;
+ bunny.position.y = 150;
+
+ stage.addChild(bunny);
+ }
+
+ it('assets loaded', function (done) {
+ var loader = new PIXI.AssetLoader([
+ baseUri + '/bunny.png',
+ baseUri + '/frame-30.png',
+ baseUri + '/frame-60.png',
+ baseUri + '/frame-90.png'
+ ]);
+ // loader.on('onProgress', function (event) {
+ // console.log(event.content);
+ // });
+ loader.on('onComplete', function (event) {
+ done();
+ initScene();
+ });
+ loader.load();
+ });
+
+ it('frame 30 should match', function (done) {
+ this.timeout(700);
+ onFrame(30, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-30.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 60 should match', function (done) {
+ this.timeout(1200);
+ onFrame(60, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-60.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 90 should match', function (done) {
+ this.timeout(1700);
+ onFrame(90, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-90.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ // it('capture something', function (done) {
+ // this.timeout(2000000);
+ // onFrame(30, function () {
+ // var img = new Image();
+ // img.src = renderer.view.toDataURL('image/png');
+ // document.body.appendChild(img);
+ // });
+ // });
+});
diff --git a/test/index.html b/test/index.html
deleted file mode 100644
index 9cbcac5..0000000
--- a/test/index.html
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
- Pixi.js Test Suite
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/test/karma.conf.js b/test/karma.conf.js
new file mode 100644
index 0000000..c66a696
--- /dev/null
+++ b/test/karma.conf.js
@@ -0,0 +1,82 @@
+module.exports = function(config) {
+ config.set({
+
+ // base path, that will be used to resolve files and exclude
+ basePath : '../',
+
+ frameworks : ['mocha'],
+
+ // list of files / patterns to load in the browser
+ files : [
+ 'node_modules/chai/chai.js',
+ 'bin/pixi.dev.js',
+ 'test/lib/**/*.js',
+ 'test/unit/**/*.js',
+ // 'test/functional/**/*.js',
+ {pattern: 'test/**/*.png', watched: false, included: false, served: true}
+ ],
+
+ // list of files to exclude
+ exclude : [],
+
+ // use dolts reporter, as travis terminal does not support escaping sequences
+ // possible values: 'dots', 'progress', 'junit', 'teamcity'
+ // CLI --reporters progress
+ reporters : ['progress'],
+
+ // web server port
+ // CLI --port 9876
+ port : 9876,
+
+ // cli runner port
+ // CLI --runner-port 9100
+ runnerPort : 9100,
+
+ // enable / disable colors in the output (reporters and logs)
+ // CLI --colors --no-colors
+ colors : true,
+
+ // level of logging
+ // possible values: karma.LOG_DISABLE || karma.LOG_ERROR || karma.LOG_WARN || karma.LOG_INFO || karma.LOG_DEBUG
+ // CLI --log-level debug
+ logLevel : config.LOG_DEBUG,
+
+ // enable / disable watching file and executing tests whenever any file changes
+ // CLI --auto-watch --no-auto-watch
+ autoWatch : false,
+
+ // Start these browsers, currently available:
+ // - Chrome
+ // - ChromeCanary
+ // - Firefox
+ // - Opera
+ // - Safari (only Mac)
+ // - PhantomJS
+ // - IE (only Windows)
+ // CLI --browsers Chrome,Firefox,Safari
+ browsers : ['Firefox'],
+
+ // If browser does not capture in given timeout [ms], kill it
+ // CLI --capture-timeout 5000
+ captureTimeout : 5000,
+
+ // Auto run tests on start (when browsers are captured) and exit
+ // CLI --single-run --no-single-run
+ singleRun : true,
+
+ // report which specs are slower than 500ms
+ // CLI --report-slower-than 500
+ reportSlowerThan : 1000,
+
+ preprocessors : {
+ // '**/client/js/*.js': 'coverage'
+ },
+
+ plugins : [
+ 'karma-mocha',
+ // 'karma-chrome-launcher',
+ 'karma-firefox-launcher',
+ // 'karma-phantomjs-launcher'
+ ]
+ });
+};
diff --git a/test/lib/pixi/core/Matrix.js b/test/lib/pixi/core/Matrix.js
new file mode 100644
index 0000000..d26386b
--- /dev/null
+++ b/test/lib/pixi/core/Matrix.js
@@ -0,0 +1,40 @@
+
+function pixi_core_Matrix_confirmNewMat3(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(1);
+ expect(matrix[5]).to.equal(0);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(1);
+}
+
+function pixi_core_Matrix_confirmNewMat4(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[0]).to.equal(1);
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(0);
+ expect(matrix[5]).to.equal(1);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(0);
+ expect(matrix[9]).to.equal(0);
+ expect(matrix[10]).to.equal(1);
+ expect(matrix[11]).to.equal(0);
+ expect(matrix[12]).to.equal(0);
+ expect(matrix[13]).to.equal(0);
+ expect(matrix[14]).to.equal(0);
+ expect(matrix[15]).to.equal(1);
+}
diff --git a/test/lib/pixi/core/Point.js b/test/lib/pixi/core/Point.js
new file mode 100644
index 0000000..e5df07b
--- /dev/null
+++ b/test/lib/pixi/core/Point.js
@@ -0,0 +1,10 @@
+
+function pixi_core_Point_confirm(obj, x, y) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Point);
+ expect(obj).to.respondTo('clone');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+}
diff --git a/test/lib/pixi/core/Rectangle.js b/test/lib/pixi/core/Rectangle.js
new file mode 100644
index 0000000..23f0d12
--- /dev/null
+++ b/test/lib/pixi/core/Rectangle.js
@@ -0,0 +1,13 @@
+
+function pixi_core_Rectangle_confirm(obj, x, y, width, height) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Rectangle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+ expect(obj).to.have.property('width', width);
+ expect(obj).to.have.property('height', height);
+}
diff --git a/test/lib/pixi/display/DisplayObject.js b/test/lib/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..1388a7f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObject.js
@@ -0,0 +1,43 @@
+
+function pixi_display_DisplayObject_confirmNew(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObject);
+ expect(obj).to.respondTo('setInteractive');
+ expect(obj).to.respondTo('addFilter');
+ expect(obj).to.respondTo('removeFilter');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.property('last', obj);
+ expect(obj).to.have.property('first', obj);
+
+ expect(obj).to.contain.property('position');
+ pixi_core_Point_confirm(obj.position, 0, 0);
+ expect(obj).to.contain.property('scale');
+ pixi_core_Point_confirm(obj.scale, 1, 1);
+ expect(obj).to.contain.property('pivot');
+ pixi_core_Point_confirm(obj.pivot, 0, 0);
+
+ expect(obj).to.have.property('rotation', 0);
+ expect(obj).to.have.property('alpha', 1);
+ expect(obj).to.have.property('visible', true);
+ expect(obj).to.have.property('buttonMode', false);
+ expect(obj).to.have.property('parent', null);
+ expect(obj).to.have.property('worldAlpha', 1);
+
+ expect(obj).to.have.property('hitArea');
+ expect(obj).to.have.property('interactive'); // TODO: Have a better default value
+ expect('mask' in obj).to.be.true; // TODO: Have a better default value
+ expect(obj.mask).to.be.undefined;
+
+ expect(obj).to.have.property('renderable');
+ expect(obj).to.have.property('stage');
+
+ expect(obj).to.have.deep.property('worldTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ expect(obj).to.have.deep.property('localTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.localTransform);
+
+ expect(obj).to.have.deep.property('color.length', 0);
+ expect(obj).to.have.property('dynamic', true);
+}
diff --git a/test/lib/pixi/display/DisplayObjectContainer.js b/test/lib/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..085c59f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,16 @@
+
+function pixi_display_DisplayObjectContainer_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObject_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObjectContainer);
+ expect(obj).to.respondTo('addChild');
+ expect(obj).to.respondTo('addChildAt');
+ expect(obj).to.respondTo('swapChildren');
+ expect(obj).to.respondTo('getChildAt');
+ expect(obj).to.respondTo('removeChild');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('children.length', 0);
+}
diff --git a/test/lib/pixi/display/Sprite.js b/test/lib/pixi/display/Sprite.js
new file mode 100644
index 0000000..cc7a2d6
--- /dev/null
+++ b/test/lib/pixi/display/Sprite.js
@@ -0,0 +1,28 @@
+
+function pixi_display_Sprite_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Sprite);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', true);
+ expect(obj).to.have.property('stage', null);
+
+ expect(obj).to.have.property('anchor');
+ pixi_core_Point_confirm(obj.anchor, 0, 0);
+
+ expect(obj).to.have.property('blendMode', PIXI.blendModes.NORMAL);
+ expect(obj).to.have.property('width', 1); // TODO: is 1 expected
+ expect(obj).to.have.property('height', 1); // TODO: is 1 expected
+
+ // FIXME: Just make this a boolean that is always there
+ expect(!!obj.updateFrame).to.equal(obj.texture.baseTexture.hasLoaded);
+
+ expect(obj).to.have.property('texture');
+ pixi_textures_Texture_confirmNew(obj.texture, done);
+}
diff --git a/test/lib/pixi/extras/Strip.js b/test/lib/pixi/extras/Strip.js
new file mode 100644
index 0000000..8927a8a
--- /dev/null
+++ b/test/lib/pixi/extras/Strip.js
@@ -0,0 +1,12 @@
+
+function pixi_extras_Strip_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Strip);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ // TODO: Test properties
+}
diff --git a/test/lib/pixi/textures/Texture.js b/test/lib/pixi/textures/Texture.js
new file mode 100644
index 0000000..d5867b6
--- /dev/null
+++ b/test/lib/pixi/textures/Texture.js
@@ -0,0 +1,31 @@
+
+function pixi_textures_Texture_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ function confirmFrameDone() {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, obj.baseTexture.width, obj.baseTexture.height);
+
+ expect(obj).to.have.property('width', obj.baseTexture.width);
+ expect(obj).to.have.property('height', obj.baseTexture.height);
+ done();
+ }
+
+ expect(obj).to.be.an.instanceof(PIXI.Texture);
+ pixi_utils_EventTarget_like(obj);
+
+ expect(obj).to.have.property('baseTexture')
+ .and.to.be.an.instanceof(PIXI.BaseTexture);
+
+ expect(obj).to.have.property('scope', obj);
+
+ expect(obj).to.have.property('trim');
+ pixi_core_Point_confirm(obj.trim, 0, 0);
+
+ expect(obj).to.have.property('frame');
+ if (obj.baseTexture.hasLoaded) {
+ confirmFrameDone();
+ } else {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, 1, 1);
+ obj.addEventListener('update', confirmFrameDone);
+ }
+}
diff --git a/test/lib/pixi/utils/EventTarget.js b/test/lib/pixi/utils/EventTarget.js
new file mode 100644
index 0000000..7b1dcfa
--- /dev/null
+++ b/test/lib/pixi/utils/EventTarget.js
@@ -0,0 +1,8 @@
+
+function pixi_utils_EventTarget_like(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.respondTo('addEventListener');
+ expect(obj).to.respondTo('dispatchEvent');
+ expect(obj).to.respondTo('removeEventListener');
+}
diff --git a/test/lib/qunit-1.11.0.css b/test/lib/qunit-1.11.0.css
deleted file mode 100644
index d7fc0c8..0000000
--- a/test/lib/qunit-1.11.0.css
+++ /dev/null
@@ -1,244 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-/** Font Family and Sizes */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
- font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
-}
-
-#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
-#qunit-tests { font-size: smaller; }
-
-
-/** Resets */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter {
- margin: 0;
- padding: 0;
-}
-
-
-/** Header */
-
-#qunit-header {
- padding: 0.5em 0 0.5em 1em;
-
- color: #8699a4;
- background-color: #0d3349;
-
- font-size: 1.5em;
- line-height: 1em;
- font-weight: normal;
-
- border-radius: 5px 5px 0 0;
- -moz-border-radius: 5px 5px 0 0;
- -webkit-border-top-right-radius: 5px;
- -webkit-border-top-left-radius: 5px;
-}
-
-#qunit-header a {
- text-decoration: none;
- color: #c2ccd1;
-}
-
-#qunit-header a:hover,
-#qunit-header a:focus {
- color: #fff;
-}
-
-#qunit-testrunner-toolbar label {
- display: inline-block;
- padding: 0 .5em 0 .1em;
-}
-
-#qunit-banner {
- height: 5px;
-}
-
-#qunit-testrunner-toolbar {
- padding: 0.5em 0 0.5em 2em;
- color: #5E740B;
- background-color: #eee;
- overflow: hidden;
-}
-
-#qunit-userAgent {
- padding: 0.5em 0 0.5em 2.5em;
- background-color: #2b81af;
- color: #fff;
- text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
-}
-
-#qunit-modulefilter-container {
- float: right;
-}
-
-/** Tests: Pass/Fail */
-
-#qunit-tests {
- list-style-position: inside;
-}
-
-#qunit-tests li {
- padding: 0.4em 0.5em 0.4em 2.5em;
- border-bottom: 1px solid #fff;
- list-style-position: inside;
-}
-
-#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running {
- display: none;
-}
-
-#qunit-tests li strong {
- cursor: pointer;
-}
-
-#qunit-tests li a {
- padding: 0.5em;
- color: #c2ccd1;
- text-decoration: none;
-}
-#qunit-tests li a:hover,
-#qunit-tests li a:focus {
- color: #000;
-}
-
-#qunit-tests li .runtime {
- float: right;
- font-size: smaller;
-}
-
-.qunit-assert-list {
- margin-top: 0.5em;
- padding: 0.5em;
-
- background-color: #fff;
-
- border-radius: 5px;
- -moz-border-radius: 5px;
- -webkit-border-radius: 5px;
-}
-
-.qunit-collapsed {
- display: none;
-}
-
-#qunit-tests table {
- border-collapse: collapse;
- margin-top: .2em;
-}
-
-#qunit-tests th {
- text-align: right;
- vertical-align: top;
- padding: 0 .5em 0 0;
-}
-
-#qunit-tests td {
- vertical-align: top;
-}
-
-#qunit-tests pre {
- margin: 0;
- white-space: pre-wrap;
- word-wrap: break-word;
-}
-
-#qunit-tests del {
- background-color: #e0f2be;
- color: #374e0c;
- text-decoration: none;
-}
-
-#qunit-tests ins {
- background-color: #ffcaca;
- color: #500;
- text-decoration: none;
-}
-
-/*** Test Counts */
-
-#qunit-tests b.counts { color: black; }
-#qunit-tests b.passed { color: #5E740B; }
-#qunit-tests b.failed { color: #710909; }
-
-#qunit-tests li li {
- padding: 5px;
- background-color: #fff;
- border-bottom: none;
- list-style-position: inside;
-}
-
-/*** Passing Styles */
-
-#qunit-tests li li.pass {
- color: #3c510c;
- background-color: #fff;
- border-left: 10px solid #C6E746;
-}
-
-#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
-#qunit-tests .pass .test-name { color: #366097; }
-
-#qunit-tests .pass .test-actual,
-#qunit-tests .pass .test-expected { color: #999999; }
-
-#qunit-banner.qunit-pass { background-color: #C6E746; }
-
-/*** Failing Styles */
-
-#qunit-tests li li.fail {
- color: #710909;
- background-color: #fff;
- border-left: 10px solid #EE5757;
- white-space: pre;
-}
-
-#qunit-tests > li:last-child {
- border-radius: 0 0 5px 5px;
- -moz-border-radius: 0 0 5px 5px;
- -webkit-border-bottom-right-radius: 5px;
- -webkit-border-bottom-left-radius: 5px;
-}
-
-#qunit-tests .fail { color: #000000; background-color: #EE5757; }
-#qunit-tests .fail .test-name,
-#qunit-tests .fail .module-name { color: #000000; }
-
-#qunit-tests .fail .test-actual { color: #EE5757; }
-#qunit-tests .fail .test-expected { color: green; }
-
-#qunit-banner.qunit-fail { background-color: #EE5757; }
-
-
-/** Result */
-
-#qunit-testresult {
- padding: 0.5em 0.5em 0.5em 2.5em;
-
- color: #2b81af;
- background-color: #D2E0E6;
-
- border-bottom: 1px solid white;
-}
-#qunit-testresult .module-name {
- font-weight: bold;
-}
-
-/** Fixture */
-
-#qunit-fixture {
- position: absolute;
- top: -10000px;
- left: -10000px;
- width: 1000px;
- height: 1000px;
-}
diff --git a/test/lib/qunit-1.11.0.js b/test/lib/qunit-1.11.0.js
deleted file mode 100644
index 302545f..0000000
--- a/test/lib/qunit-1.11.0.js
+++ /dev/null
@@ -1,2152 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-(function( window ) {
-
-var QUnit,
- assert,
- config,
- onErrorFnPrev,
- testId = 0,
- fileName = (sourceFromStacktrace( 0 ) || "" ).replace(/(:\d+)+\)?/, "").replace(/.+\//, ""),
- toString = Object.prototype.toString,
- hasOwn = Object.prototype.hasOwnProperty,
- // Keep a local reference to Date (GH-283)
- Date = window.Date,
- defined = {
- setTimeout: typeof window.setTimeout !== "undefined",
- sessionStorage: (function() {
- var x = "qunit-test-string";
- try {
- sessionStorage.setItem( x, x );
- sessionStorage.removeItem( x );
- return true;
- } catch( e ) {
- return false;
- }
- }())
- },
- /**
- * Provides a normalized error string, correcting an issue
- * with IE 7 (and prior) where Error.prototype.toString is
- * not properly implemented
- *
- * Based on http://es5.github.com/#x15.11.4.4
- *
- * @param {String|Error} error
- * @return {String} error message
- */
- errorString = function( error ) {
- var name, message,
- errorString = error.toString();
- if ( errorString.substring( 0, 7 ) === "[object" ) {
- name = error.name ? error.name.toString() : "Error";
- message = error.message ? error.message.toString() : "";
- if ( name && message ) {
- return name + ": " + message;
- } else if ( name ) {
- return name;
- } else if ( message ) {
- return message;
- } else {
- return "Error";
- }
- } else {
- return errorString;
- }
- },
- /**
- * Makes a clone of an object using only Array or Object as base,
- * and copies over the own enumerable properties.
- *
- * @param {Object} obj
- * @return {Object} New object with only the own properties (recursively).
- */
- objectValues = function( obj ) {
- // Grunt 0.3.x uses an older version of jshint that still has jshint/jshint#392.
- /*jshint newcap: false */
- var key, val,
- vals = QUnit.is( "array", obj ) ? [] : {};
- for ( key in obj ) {
- if ( hasOwn.call( obj, key ) ) {
- val = obj[key];
- vals[key] = val === Object(val) ? objectValues(val) : val;
- }
- }
- return vals;
- };
-
-function Test( settings ) {
- extend( this, settings );
- this.assertions = [];
- this.testNumber = ++Test.count;
-}
-
-Test.count = 0;
-
-Test.prototype = {
- init: function() {
- var a, b, li,
- tests = id( "qunit-tests" );
-
- if ( tests ) {
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml;
-
- // `a` initialized at top of scope
- a = document.createElement( "a" );
- a.innerHTML = "Rerun";
- a.href = QUnit.url({ testNumber: this.testNumber });
-
- li = document.createElement( "li" );
- li.appendChild( b );
- li.appendChild( a );
- li.className = "running";
- li.id = this.id = "qunit-test-output" + testId++;
-
- tests.appendChild( li );
- }
- },
- setup: function() {
- if ( this.module !== config.previousModule ) {
- if ( config.previousModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.previousModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
- config.previousModule = this.module;
- config.moduleStats = { all: 0, bad: 0 };
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- } else if ( config.autorun ) {
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- }
-
- config.current = this;
-
- this.testEnvironment = extend({
- setup: function() {},
- teardown: function() {}
- }, this.moduleTestEnvironment );
-
- this.started = +new Date();
- runLoggingCallbacks( "testStart", QUnit, {
- name: this.testName,
- module: this.module
- });
-
- // allow utility functions to access the current test environment
- // TODO why??
- QUnit.current_testEnvironment = this.testEnvironment;
-
- if ( !config.pollution ) {
- saveGlobal();
- }
- if ( config.notrycatch ) {
- this.testEnvironment.setup.call( this.testEnvironment );
- return;
- }
- try {
- this.testEnvironment.setup.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Setup failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- },
- run: function() {
- config.current = this;
-
- var running = id( "qunit-testresult" );
-
- if ( running ) {
- running.innerHTML = "Running:
" + this.nameHtml;
- }
-
- if ( this.async ) {
- QUnit.stop();
- }
-
- this.callbackStarted = +new Date();
-
- if ( config.notrycatch ) {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- return;
- }
-
- try {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- } catch( e ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
-
- QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + " " + this.stack + ": " + ( e.message || e ), extractStacktrace( e, 0 ) );
- // else next test will carry the responsibility
- saveGlobal();
-
- // Restart the tests if they're blocking
- if ( config.blocking ) {
- QUnit.start();
- }
- }
- },
- teardown: function() {
- config.current = this;
- if ( config.notrycatch ) {
- if ( typeof this.callbackRuntime === "undefined" ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
- }
- this.testEnvironment.teardown.call( this.testEnvironment );
- return;
- } else {
- try {
- this.testEnvironment.teardown.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Teardown failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- }
- checkPollution();
- },
- finish: function() {
- config.current = this;
- if ( config.requireExpects && this.expected === null ) {
- QUnit.pushFailure( "Expected number of assertions to be defined, but expect() was not called.", this.stack );
- } else if ( this.expected !== null && this.expected !== this.assertions.length ) {
- QUnit.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack );
- } else if ( this.expected === null && !this.assertions.length ) {
- QUnit.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions.", this.stack );
- }
-
- var i, assertion, a, b, time, li, ol,
- test = this,
- good = 0,
- bad = 0,
- tests = id( "qunit-tests" );
-
- this.runtime = +new Date() - this.started;
- config.stats.all += this.assertions.length;
- config.moduleStats.all += this.assertions.length;
-
- if ( tests ) {
- ol = document.createElement( "ol" );
- ol.className = "qunit-assert-list";
-
- for ( i = 0; i < this.assertions.length; i++ ) {
- assertion = this.assertions[i];
-
- li = document.createElement( "li" );
- li.className = assertion.result ? "pass" : "fail";
- li.innerHTML = assertion.message || ( assertion.result ? "okay" : "failed" );
- ol.appendChild( li );
-
- if ( assertion.result ) {
- good++;
- } else {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
-
- // store result when possible
- if ( QUnit.config.reorder && defined.sessionStorage ) {
- if ( bad ) {
- sessionStorage.setItem( "qunit-test-" + this.module + "-" + this.testName, bad );
- } else {
- sessionStorage.removeItem( "qunit-test-" + this.module + "-" + this.testName );
- }
- }
-
- if ( bad === 0 ) {
- addClass( ol, "qunit-collapsed" );
- }
-
- // `b` initialized at top of scope
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml + " (" + bad + ", " + good + ", " + this.assertions.length + ")";
-
- addEvent(b, "click", function() {
- var next = b.parentNode.lastChild,
- collapsed = hasClass( next, "qunit-collapsed" );
- ( collapsed ? removeClass : addClass )( next, "qunit-collapsed" );
- });
-
- addEvent(b, "dblclick", function( e ) {
- var target = e && e.target ? e.target : window.event.srcElement;
- if ( target.nodeName.toLowerCase() === "span" || target.nodeName.toLowerCase() === "b" ) {
- target = target.parentNode;
- }
- if ( window.location && target.nodeName.toLowerCase() === "strong" ) {
- window.location = QUnit.url({ testNumber: test.testNumber });
- }
- });
-
- // `time` initialized at top of scope
- time = document.createElement( "span" );
- time.className = "runtime";
- time.innerHTML = this.runtime + " ms";
-
- // `li` initialized at top of scope
- li = id( this.id );
- li.className = bad ? "fail" : "pass";
- li.removeChild( li.firstChild );
- a = li.firstChild;
- li.appendChild( b );
- li.appendChild( a );
- li.appendChild( time );
- li.appendChild( ol );
-
- } else {
- for ( i = 0; i < this.assertions.length; i++ ) {
- if ( !this.assertions[i].result ) {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
- }
-
- runLoggingCallbacks( "testDone", QUnit, {
- name: this.testName,
- module: this.module,
- failed: bad,
- passed: this.assertions.length - bad,
- total: this.assertions.length,
- duration: this.runtime
- });
-
- QUnit.reset();
-
- config.current = undefined;
- },
-
- queue: function() {
- var bad,
- test = this;
-
- synchronize(function() {
- test.init();
- });
- function run() {
- // each of these can by async
- synchronize(function() {
- test.setup();
- });
- synchronize(function() {
- test.run();
- });
- synchronize(function() {
- test.teardown();
- });
- synchronize(function() {
- test.finish();
- });
- }
-
- // `bad` initialized at top of scope
- // defer when previous test run passed, if storage is available
- bad = QUnit.config.reorder && defined.sessionStorage &&
- +sessionStorage.getItem( "qunit-test-" + this.module + "-" + this.testName );
-
- if ( bad ) {
- run();
- } else {
- synchronize( run, true );
- }
- }
-};
-
-// Root QUnit object.
-// `QUnit` initialized at top of scope
-QUnit = {
-
- // call on start of module test to prepend name to all tests
- module: function( name, testEnvironment ) {
- config.currentModule = name;
- config.currentModuleTestEnvironment = testEnvironment;
- config.modules[name] = true;
- },
-
- asyncTest: function( testName, expected, callback ) {
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- QUnit.test( testName, expected, callback, true );
- },
-
- test: function( testName, expected, callback, async ) {
- var test,
- nameHtml = "" + escapeText( testName ) + "";
-
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- if ( config.currentModule ) {
- nameHtml = "" + escapeText( config.currentModule ) + ": " + nameHtml;
- }
-
- test = new Test({
- nameHtml: nameHtml,
- testName: testName,
- expected: expected,
- async: async,
- callback: callback,
- module: config.currentModule,
- moduleTestEnvironment: config.currentModuleTestEnvironment,
- stack: sourceFromStacktrace( 2 )
- });
-
- if ( !validTest( test ) ) {
- return;
- }
-
- test.queue();
- },
-
- // Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through.
- expect: function( asserts ) {
- if (arguments.length === 1) {
- config.current.expected = asserts;
- } else {
- return config.current.expected;
- }
- },
-
- start: function( count ) {
- // QUnit hasn't been initialized yet.
- // Note: RequireJS (et al) may delay onLoad
- if ( config.semaphore === undefined ) {
- QUnit.begin(function() {
- // This is triggered at the top of QUnit.load, push start() to the event loop, to allow QUnit.load to finish first
- setTimeout(function() {
- QUnit.start( count );
- });
- });
- return;
- }
-
- config.semaphore -= count || 1;
- // don't start until equal number of stop-calls
- if ( config.semaphore > 0 ) {
- return;
- }
- // ignore if start is called more often then stop
- if ( config.semaphore < 0 ) {
- config.semaphore = 0;
- QUnit.pushFailure( "Called start() while already started (QUnit.config.semaphore was 0 already)", null, sourceFromStacktrace(2) );
- return;
- }
- // A slight delay, to avoid any current callbacks
- if ( defined.setTimeout ) {
- window.setTimeout(function() {
- if ( config.semaphore > 0 ) {
- return;
- }
- if ( config.timeout ) {
- clearTimeout( config.timeout );
- }
-
- config.blocking = false;
- process( true );
- }, 13);
- } else {
- config.blocking = false;
- process( true );
- }
- },
-
- stop: function( count ) {
- config.semaphore += count || 1;
- config.blocking = true;
-
- if ( config.testTimeout && defined.setTimeout ) {
- clearTimeout( config.timeout );
- config.timeout = window.setTimeout(function() {
- QUnit.ok( false, "Test timed out" );
- config.semaphore = 1;
- QUnit.start();
- }, config.testTimeout );
- }
- }
-};
-
-// `assert` initialized at top of scope
-// Asssert helpers
-// All of these must either call QUnit.push() or manually do:
-// - runLoggingCallbacks( "log", .. );
-// - config.current.assertions.push({ .. });
-// We attach it to the QUnit object *after* we expose the public API,
-// otherwise `assert` will become a global variable in browsers (#341).
-assert = {
- /**
- * Asserts rough true-ish result.
- * @name ok
- * @function
- * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" );
- */
- ok: function( result, msg ) {
- if ( !config.current ) {
- throw new Error( "ok() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
- result = !!result;
-
- var source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: msg
- };
-
- msg = escapeText( msg || (result ? "okay" : "failed" ) );
- msg = "" + msg + "";
-
- if ( !result ) {
- source = sourceFromStacktrace( 2 );
- if ( source ) {
- details.source = source;
- msg += "Source: | " + escapeText( source ) + " |
---|
";
- }
- }
- runLoggingCallbacks( "log", QUnit, details );
- config.current.assertions.push({
- result: result,
- message: msg
- });
- },
-
- /**
- * Assert that the first two arguments are equal, with an optional message.
- * Prints out both actual and expected values.
- * @name equal
- * @function
- * @example equal( format( "Received {0} bytes.", 2), "Received 2 bytes.", "format() replaces {0} with next argument" );
- */
- equal: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected == actual, actual, expected, message );
- },
-
- /**
- * @name notEqual
- * @function
- */
- notEqual: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected != actual, actual, expected, message );
- },
-
- /**
- * @name propEqual
- * @function
- */
- propEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notPropEqual
- * @function
- */
- notPropEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name deepEqual
- * @function
- */
- deepEqual: function( actual, expected, message ) {
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notDeepEqual
- * @function
- */
- notDeepEqual: function( actual, expected, message ) {
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name strictEqual
- * @function
- */
- strictEqual: function( actual, expected, message ) {
- QUnit.push( expected === actual, actual, expected, message );
- },
-
- /**
- * @name notStrictEqual
- * @function
- */
- notStrictEqual: function( actual, expected, message ) {
- QUnit.push( expected !== actual, actual, expected, message );
- },
-
- "throws": function( block, expected, message ) {
- var actual,
- expectedOutput = expected,
- ok = false;
-
- // 'expected' is optional
- if ( typeof expected === "string" ) {
- message = expected;
- expected = null;
- }
-
- config.current.ignoreGlobalErrors = true;
- try {
- block.call( config.current.testEnvironment );
- } catch (e) {
- actual = e;
- }
- config.current.ignoreGlobalErrors = false;
-
- if ( actual ) {
- // we don't want to validate thrown error
- if ( !expected ) {
- ok = true;
- expectedOutput = null;
- // expected is a regexp
- } else if ( QUnit.objectType( expected ) === "regexp" ) {
- ok = expected.test( errorString( actual ) );
- // expected is a constructor
- } else if ( actual instanceof expected ) {
- ok = true;
- // expected is a validation function which returns true is validation passed
- } else if ( expected.call( {}, actual ) === true ) {
- expectedOutput = null;
- ok = true;
- }
-
- QUnit.push( ok, actual, expectedOutput, message );
- } else {
- QUnit.pushFailure( message, null, 'No exception was thrown.' );
- }
- }
-};
-
-/**
- * @deprecate since 1.8.0
- * Kept assertion helpers in root for backwards compatibility.
- */
-extend( QUnit, assert );
-
-/**
- * @deprecated since 1.9.0
- * Kept root "raises()" for backwards compatibility.
- * (Note that we don't introduce assert.raises).
- */
-QUnit.raises = assert[ "throws" ];
-
-/**
- * @deprecated since 1.0.0, replaced with error pushes since 1.3.0
- * Kept to avoid TypeErrors for undefined methods.
- */
-QUnit.equals = function() {
- QUnit.push( false, false, false, "QUnit.equals has been deprecated since 2009 (e88049a0), use QUnit.equal instead" );
-};
-QUnit.same = function() {
- QUnit.push( false, false, false, "QUnit.same has been deprecated since 2009 (e88049a0), use QUnit.deepEqual instead" );
-};
-
-// We want access to the constructor's prototype
-(function() {
- function F() {}
- F.prototype = QUnit;
- QUnit = new F();
- // Make F QUnit's constructor so that we can add to the prototype later
- QUnit.constructor = F;
-}());
-
-/**
- * Config object: Maintain internal state
- * Later exposed as QUnit.config
- * `config` initialized at top of scope
- */
-config = {
- // The queue of tests to run
- queue: [],
-
- // block until document ready
- blocking: true,
-
- // when enabled, show only failing tests
- // gets persisted through sessionStorage and can be changed in UI via checkbox
- hidepassed: false,
-
- // by default, run previously failed tests first
- // very useful in combination with "Hide passed tests" checked
- reorder: true,
-
- // by default, modify document.title when suite is done
- altertitle: true,
-
- // when enabled, all tests must call expect()
- requireExpects: false,
-
- // add checkboxes that are persisted in the query-string
- // when enabled, the id is set to `true` as a `QUnit.config` property
- urlConfig: [
- {
- id: "noglobals",
- label: "Check for Globals",
- tooltip: "Enabling this will test if any test introduces new properties on the `window` object. Stored as query-strings."
- },
- {
- id: "notrycatch",
- label: "No try-catch",
- tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging exceptions in IE reasonable. Stored as query-strings."
- }
- ],
-
- // Set of all modules.
- modules: {},
-
- // logging callback queues
- begin: [],
- done: [],
- log: [],
- testStart: [],
- testDone: [],
- moduleStart: [],
- moduleDone: []
-};
-
-// Export global variables, unless an 'exports' object exists,
-// in that case we assume we're in CommonJS (dealt with on the bottom of the script)
-if ( typeof exports === "undefined" ) {
- extend( window, QUnit );
-
- // Expose QUnit object
- window.QUnit = QUnit;
-}
-
-// Initialize more QUnit.config and QUnit.urlParams
-(function() {
- var i,
- location = window.location || { search: "", protocol: "file:" },
- params = location.search.slice( 1 ).split( "&" ),
- length = params.length,
- urlParams = {},
- current;
-
- if ( params[ 0 ] ) {
- for ( i = 0; i < length; i++ ) {
- current = params[ i ].split( "=" );
- current[ 0 ] = decodeURIComponent( current[ 0 ] );
- // allow just a key to turn on a flag, e.g., test.html?noglobals
- current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true;
- urlParams[ current[ 0 ] ] = current[ 1 ];
- }
- }
-
- QUnit.urlParams = urlParams;
-
- // String search anywhere in moduleName+testName
- config.filter = urlParams.filter;
-
- // Exact match of the module name
- config.module = urlParams.module;
-
- config.testNumber = parseInt( urlParams.testNumber, 10 ) || null;
-
- // Figure out if we're running the tests from a server or not
- QUnit.isLocal = location.protocol === "file:";
-}());
-
-// Extend QUnit object,
-// these after set here because they should not be exposed as global functions
-extend( QUnit, {
- assert: assert,
-
- config: config,
-
- // Initialize the configuration options
- init: function() {
- extend( config, {
- stats: { all: 0, bad: 0 },
- moduleStats: { all: 0, bad: 0 },
- started: +new Date(),
- updateRate: 1000,
- blocking: false,
- autostart: true,
- autorun: false,
- filter: "",
- queue: [],
- semaphore: 1
- });
-
- var tests, banner, result,
- qunit = id( "qunit" );
-
- if ( qunit ) {
- qunit.innerHTML =
- "" +
- "" +
- "" +
- "" +
- "
";
- }
-
- tests = id( "qunit-tests" );
- banner = id( "qunit-banner" );
- result = id( "qunit-testresult" );
-
- if ( tests ) {
- tests.innerHTML = "";
- }
-
- if ( banner ) {
- banner.className = "";
- }
-
- if ( result ) {
- result.parentNode.removeChild( result );
- }
-
- if ( tests ) {
- result = document.createElement( "p" );
- result.id = "qunit-testresult";
- result.className = "result";
- tests.parentNode.insertBefore( result, tests );
- result.innerHTML = "Running...
";
- }
- },
-
- // Resets the test setup. Useful for tests that modify the DOM.
- reset: function() {
- var fixture = id( "qunit-fixture" );
- if ( fixture ) {
- fixture.innerHTML = config.fixture;
- }
- },
-
- // Trigger an event on an element.
- // @example triggerEvent( document.body, "click" );
- triggerEvent: function( elem, type, event ) {
- if ( document.createEvent ) {
- event = document.createEvent( "MouseEvents" );
- event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView,
- 0, 0, 0, 0, 0, false, false, false, false, 0, null);
-
- elem.dispatchEvent( event );
- } else if ( elem.fireEvent ) {
- elem.fireEvent( "on" + type );
- }
- },
-
- // Safe object type checking
- is: function( type, obj ) {
- return QUnit.objectType( obj ) === type;
- },
-
- objectType: function( obj ) {
- if ( typeof obj === "undefined" ) {
- return "undefined";
- // consider: typeof null === object
- }
- if ( obj === null ) {
- return "null";
- }
-
- var match = toString.call( obj ).match(/^\[object\s(.*)\]$/),
- type = match && match[1] || "";
-
- switch ( type ) {
- case "Number":
- if ( isNaN(obj) ) {
- return "nan";
- }
- return "number";
- case "String":
- case "Boolean":
- case "Array":
- case "Date":
- case "RegExp":
- case "Function":
- return type.toLowerCase();
- }
- if ( typeof obj === "object" ) {
- return "object";
- }
- return undefined;
- },
-
- push: function( result, actual, expected, message ) {
- if ( !config.current ) {
- throw new Error( "assertion outside test context, was " + sourceFromStacktrace() );
- }
-
- var output, source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: message,
- actual: actual,
- expected: expected
- };
-
- message = escapeText( message ) || ( result ? "okay" : "failed" );
- message = "" + message + "";
- output = message;
-
- if ( !result ) {
- expected = escapeText( QUnit.jsDump.parse(expected) );
- actual = escapeText( QUnit.jsDump.parse(actual) );
- output += "Expected: | " + expected + " |
";
-
- if ( actual !== expected ) {
- output += "Result: | " + actual + " |
";
- output += "Diff: | " + QUnit.diff( expected, actual ) + " |
";
- }
-
- source = sourceFromStacktrace();
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
- }
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: !!result,
- message: output
- });
- },
-
- pushFailure: function( message, source, actual ) {
- if ( !config.current ) {
- throw new Error( "pushFailure() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
-
- var output,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: false,
- message: message
- };
-
- message = escapeText( message ) || "error";
- message = "" + message + "";
- output = message;
-
- output += "";
-
- if ( actual ) {
- output += "Result: | " + escapeText( actual ) + " |
";
- }
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: false,
- message: output
- });
- },
-
- url: function( params ) {
- params = extend( extend( {}, QUnit.urlParams ), params );
- var key,
- querystring = "?";
-
- for ( key in params ) {
- if ( !hasOwn.call( params, key ) ) {
- continue;
- }
- querystring += encodeURIComponent( key ) + "=" +
- encodeURIComponent( params[ key ] ) + "&";
- }
- return window.location.protocol + "//" + window.location.host +
- window.location.pathname + querystring.slice( 0, -1 );
- },
-
- extend: extend,
- id: id,
- addEvent: addEvent
- // load, equiv, jsDump, diff: Attached later
-});
-
-/**
- * @deprecated: Created for backwards compatibility with test runner that set the hook function
- * into QUnit.{hook}, instead of invoking it and passing the hook function.
- * QUnit.constructor is set to the empty F() above so that we can add to it's prototype here.
- * Doing this allows us to tell if the following methods have been overwritten on the actual
- * QUnit object.
- */
-extend( QUnit.constructor.prototype, {
-
- // Logging callbacks; all receive a single argument with the listed properties
- // run test/logs.html for any related changes
- begin: registerLoggingCallback( "begin" ),
-
- // done: { failed, passed, total, runtime }
- done: registerLoggingCallback( "done" ),
-
- // log: { result, actual, expected, message }
- log: registerLoggingCallback( "log" ),
-
- // testStart: { name }
- testStart: registerLoggingCallback( "testStart" ),
-
- // testDone: { name, failed, passed, total, duration }
- testDone: registerLoggingCallback( "testDone" ),
-
- // moduleStart: { name }
- moduleStart: registerLoggingCallback( "moduleStart" ),
-
- // moduleDone: { name, failed, passed, total }
- moduleDone: registerLoggingCallback( "moduleDone" )
-});
-
-if ( typeof document === "undefined" || document.readyState === "complete" ) {
- config.autorun = true;
-}
-
-QUnit.load = function() {
- runLoggingCallbacks( "begin", QUnit, {} );
-
- // Initialize the config, saving the execution queue
- var banner, filter, i, label, len, main, ol, toolbar, userAgent, val,
- urlConfigCheckboxesContainer, urlConfigCheckboxes, moduleFilter,
- numModules = 0,
- moduleFilterHtml = "",
- urlConfigHtml = "",
- oldconfig = extend( {}, config );
-
- QUnit.init();
- extend(config, oldconfig);
-
- config.blocking = false;
-
- len = config.urlConfig.length;
-
- for ( i = 0; i < len; i++ ) {
- val = config.urlConfig[i];
- if ( typeof val === "string" ) {
- val = {
- id: val,
- label: val,
- tooltip: "[no tooltip available]"
- };
- }
- config[ val.id ] = QUnit.urlParams[ val.id ];
- urlConfigHtml += "";
- }
-
- moduleFilterHtml += "";
-
- // `userAgent` initialized at top of scope
- userAgent = id( "qunit-userAgent" );
- if ( userAgent ) {
- userAgent.innerHTML = navigator.userAgent;
- }
-
- // `banner` initialized at top of scope
- banner = id( "qunit-header" );
- if ( banner ) {
- banner.innerHTML = "" + banner.innerHTML + " ";
- }
-
- // `toolbar` initialized at top of scope
- toolbar = id( "qunit-testrunner-toolbar" );
- if ( toolbar ) {
- // `filter` initialized at top of scope
- filter = document.createElement( "input" );
- filter.type = "checkbox";
- filter.id = "qunit-filter-pass";
-
- addEvent( filter, "click", function() {
- var tmp,
- ol = document.getElementById( "qunit-tests" );
-
- if ( filter.checked ) {
- ol.className = ol.className + " hidepass";
- } else {
- tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " ";
- ol.className = tmp.replace( / hidepass /, " " );
- }
- if ( defined.sessionStorage ) {
- if (filter.checked) {
- sessionStorage.setItem( "qunit-filter-passed-tests", "true" );
- } else {
- sessionStorage.removeItem( "qunit-filter-passed-tests" );
- }
- }
- });
-
- if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem( "qunit-filter-passed-tests" ) ) {
- filter.checked = true;
- // `ol` initialized at top of scope
- ol = document.getElementById( "qunit-tests" );
- ol.className = ol.className + " hidepass";
- }
- toolbar.appendChild( filter );
-
- // `label` initialized at top of scope
- label = document.createElement( "label" );
- label.setAttribute( "for", "qunit-filter-pass" );
- label.setAttribute( "title", "Only show tests and assertons that fail. Stored in sessionStorage." );
- label.innerHTML = "Hide passed tests";
- toolbar.appendChild( label );
-
- urlConfigCheckboxesContainer = document.createElement("span");
- urlConfigCheckboxesContainer.innerHTML = urlConfigHtml;
- urlConfigCheckboxes = urlConfigCheckboxesContainer.getElementsByTagName("input");
- // For oldIE support:
- // * Add handlers to the individual elements instead of the container
- // * Use "click" instead of "change"
- // * Fallback from event.target to event.srcElement
- addEvents( urlConfigCheckboxes, "click", function( event ) {
- var params = {},
- target = event.target || event.srcElement;
- params[ target.name ] = target.checked ? true : undefined;
- window.location = QUnit.url( params );
- });
- toolbar.appendChild( urlConfigCheckboxesContainer );
-
- if (numModules > 1) {
- moduleFilter = document.createElement( 'span' );
- moduleFilter.setAttribute( 'id', 'qunit-modulefilter-container' );
- moduleFilter.innerHTML = moduleFilterHtml;
- addEvent( moduleFilter.lastChild, "change", function() {
- var selectBox = moduleFilter.getElementsByTagName("select")[0],
- selectedModule = decodeURIComponent(selectBox.options[selectBox.selectedIndex].value);
-
- window.location = QUnit.url( { module: ( selectedModule === "" ) ? undefined : selectedModule } );
- });
- toolbar.appendChild(moduleFilter);
- }
- }
-
- // `main` initialized at top of scope
- main = id( "qunit-fixture" );
- if ( main ) {
- config.fixture = main.innerHTML;
- }
-
- if ( config.autostart ) {
- QUnit.start();
- }
-};
-
-addEvent( window, "load", QUnit.load );
-
-// `onErrorFnPrev` initialized at top of scope
-// Preserve other handlers
-onErrorFnPrev = window.onerror;
-
-// Cover uncaught exceptions
-// Returning true will surpress the default browser handler,
-// returning false will let it run.
-window.onerror = function ( error, filePath, linerNr ) {
- var ret = false;
- if ( onErrorFnPrev ) {
- ret = onErrorFnPrev( error, filePath, linerNr );
- }
-
- // Treat return value as window.onerror itself does,
- // Only do our handling if not surpressed.
- if ( ret !== true ) {
- if ( QUnit.config.current ) {
- if ( QUnit.config.current.ignoreGlobalErrors ) {
- return true;
- }
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- } else {
- QUnit.test( "global failure", extend( function() {
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- }, { validTest: validTest } ) );
- }
- return false;
- }
-
- return ret;
-};
-
-function done() {
- config.autorun = true;
-
- // Log the last module results
- if ( config.currentModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.currentModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
-
- var i, key,
- banner = id( "qunit-banner" ),
- tests = id( "qunit-tests" ),
- runtime = +new Date() - config.started,
- passed = config.stats.all - config.stats.bad,
- html = [
- "Tests completed in ",
- runtime,
- " milliseconds.
",
- "",
- passed,
- " assertions of ",
- config.stats.all,
- " passed, ",
- config.stats.bad,
- " failed."
- ].join( "" );
-
- if ( banner ) {
- banner.className = ( config.stats.bad ? "qunit-fail" : "qunit-pass" );
- }
-
- if ( tests ) {
- id( "qunit-testresult" ).innerHTML = html;
- }
-
- if ( config.altertitle && typeof document !== "undefined" && document.title ) {
- // show ✖ for good, ✔ for bad suite result in title
- // use escape sequences in case file gets loaded with non-utf-8-charset
- document.title = [
- ( config.stats.bad ? "\u2716" : "\u2714" ),
- document.title.replace( /^[\u2714\u2716] /i, "" )
- ].join( " " );
- }
-
- // clear own sessionStorage items if all tests passed
- if ( config.reorder && defined.sessionStorage && config.stats.bad === 0 ) {
- // `key` & `i` initialized at top of scope
- for ( i = 0; i < sessionStorage.length; i++ ) {
- key = sessionStorage.key( i++ );
- if ( key.indexOf( "qunit-test-" ) === 0 ) {
- sessionStorage.removeItem( key );
- }
- }
- }
-
- // scroll back to top to show results
- if ( window.scrollTo ) {
- window.scrollTo(0, 0);
- }
-
- runLoggingCallbacks( "done", QUnit, {
- failed: config.stats.bad,
- passed: passed,
- total: config.stats.all,
- runtime: runtime
- });
-}
-
-/** @return Boolean: true if this test should be ran */
-function validTest( test ) {
- var include,
- filter = config.filter && config.filter.toLowerCase(),
- module = config.module && config.module.toLowerCase(),
- fullName = (test.module + ": " + test.testName).toLowerCase();
-
- // Internally-generated tests are always valid
- if ( test.callback && test.callback.validTest === validTest ) {
- delete test.callback.validTest;
- return true;
- }
-
- if ( config.testNumber ) {
- return test.testNumber === config.testNumber;
- }
-
- if ( module && ( !test.module || test.module.toLowerCase() !== module ) ) {
- return false;
- }
-
- if ( !filter ) {
- return true;
- }
-
- include = filter.charAt( 0 ) !== "!";
- if ( !include ) {
- filter = filter.slice( 1 );
- }
-
- // If the filter matches, we need to honour include
- if ( fullName.indexOf( filter ) !== -1 ) {
- return include;
- }
-
- // Otherwise, do the opposite
- return !include;
-}
-
-// so far supports only Firefox, Chrome and Opera (buggy), Safari (for real exceptions)
-// Later Safari and IE10 are supposed to support error.stack as well
-// See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack
-function extractStacktrace( e, offset ) {
- offset = offset === undefined ? 3 : offset;
-
- var stack, include, i;
-
- if ( e.stacktrace ) {
- // Opera
- return e.stacktrace.split( "\n" )[ offset + 3 ];
- } else if ( e.stack ) {
- // Firefox, Chrome
- stack = e.stack.split( "\n" );
- if (/^error$/i.test( stack[0] ) ) {
- stack.shift();
- }
- if ( fileName ) {
- include = [];
- for ( i = offset; i < stack.length; i++ ) {
- if ( stack[ i ].indexOf( fileName ) !== -1 ) {
- break;
- }
- include.push( stack[ i ] );
- }
- if ( include.length ) {
- return include.join( "\n" );
- }
- }
- return stack[ offset ];
- } else if ( e.sourceURL ) {
- // Safari, PhantomJS
- // hopefully one day Safari provides actual stacktraces
- // exclude useless self-reference for generated Error objects
- if ( /qunit.js$/.test( e.sourceURL ) ) {
- return;
- }
- // for actual exceptions, this is useful
- return e.sourceURL + ":" + e.line;
- }
-}
-function sourceFromStacktrace( offset ) {
- try {
- throw new Error();
- } catch ( e ) {
- return extractStacktrace( e, offset );
- }
-}
-
-/**
- * Escape text for attribute or text content.
- */
-function escapeText( s ) {
- if ( !s ) {
- return "";
- }
- s = s + "";
- // Both single quotes and double quotes (for attributes)
- return s.replace( /['"<>&]/g, function( s ) {
- switch( s ) {
- case '\'':
- return ''';
- case '"':
- return '"';
- case '<':
- return '<';
- case '>':
- return '>';
- case '&':
- return '&';
- }
- });
-}
-
-function synchronize( callback, last ) {
- config.queue.push( callback );
-
- if ( config.autorun && !config.blocking ) {
- process( last );
- }
-}
-
-function process( last ) {
- function next() {
- process( last );
- }
- var start = new Date().getTime();
- config.depth = config.depth ? config.depth + 1 : 1;
-
- while ( config.queue.length && !config.blocking ) {
- if ( !defined.setTimeout || config.updateRate <= 0 || ( ( new Date().getTime() - start ) < config.updateRate ) ) {
- config.queue.shift()();
- } else {
- window.setTimeout( next, 13 );
- break;
- }
- }
- config.depth--;
- if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) {
- done();
- }
-}
-
-function saveGlobal() {
- config.pollution = [];
-
- if ( config.noglobals ) {
- for ( var key in window ) {
- // in Opera sometimes DOM element ids show up here, ignore them
- if ( !hasOwn.call( window, key ) || /^qunit-test-output/.test( key ) ) {
- continue;
- }
- config.pollution.push( key );
- }
- }
-}
-
-function checkPollution() {
- var newGlobals,
- deletedGlobals,
- old = config.pollution;
-
- saveGlobal();
-
- newGlobals = diff( config.pollution, old );
- if ( newGlobals.length > 0 ) {
- QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join(", ") );
- }
-
- deletedGlobals = diff( old, config.pollution );
- if ( deletedGlobals.length > 0 ) {
- QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join(", ") );
- }
-}
-
-// returns a new Array with the elements that are in a but not in b
-function diff( a, b ) {
- var i, j,
- result = a.slice();
-
- for ( i = 0; i < result.length; i++ ) {
- for ( j = 0; j < b.length; j++ ) {
- if ( result[i] === b[j] ) {
- result.splice( i, 1 );
- i--;
- break;
- }
- }
- }
- return result;
-}
-
-function extend( a, b ) {
- for ( var prop in b ) {
- if ( b[ prop ] === undefined ) {
- delete a[ prop ];
-
- // Avoid "Member not found" error in IE8 caused by setting window.constructor
- } else if ( prop !== "constructor" || a !== window ) {
- a[ prop ] = b[ prop ];
- }
- }
-
- return a;
-}
-
-/**
- * @param {HTMLElement} elem
- * @param {string} type
- * @param {Function} fn
- */
-function addEvent( elem, type, fn ) {
- // Standards-based browsers
- if ( elem.addEventListener ) {
- elem.addEventListener( type, fn, false );
- // IE
- } else {
- elem.attachEvent( "on" + type, fn );
- }
-}
-
-/**
- * @param {Array|NodeList} elems
- * @param {string} type
- * @param {Function} fn
- */
-function addEvents( elems, type, fn ) {
- var i = elems.length;
- while ( i-- ) {
- addEvent( elems[i], type, fn );
- }
-}
-
-function hasClass( elem, name ) {
- return (" " + elem.className + " ").indexOf(" " + name + " ") > -1;
-}
-
-function addClass( elem, name ) {
- if ( !hasClass( elem, name ) ) {
- elem.className += (elem.className ? " " : "") + name;
- }
-}
-
-function removeClass( elem, name ) {
- var set = " " + elem.className + " ";
- // Class name may appear multiple times
- while ( set.indexOf(" " + name + " ") > -1 ) {
- set = set.replace(" " + name + " " , " ");
- }
- // If possible, trim it for prettiness, but not neccecarily
- elem.className = window.jQuery ? jQuery.trim( set ) : ( set.trim ? set.trim() : set );
-}
-
-function id( name ) {
- return !!( typeof document !== "undefined" && document && document.getElementById ) &&
- document.getElementById( name );
-}
-
-function registerLoggingCallback( key ) {
- return function( callback ) {
- config[key].push( callback );
- };
-}
-
-// Supports deprecated method of completely overwriting logging callbacks
-function runLoggingCallbacks( key, scope, args ) {
- var i, callbacks;
- if ( QUnit.hasOwnProperty( key ) ) {
- QUnit[ key ].call(scope, args );
- } else {
- callbacks = config[ key ];
- for ( i = 0; i < callbacks.length; i++ ) {
- callbacks[ i ].call( scope, args );
- }
- }
-}
-
-// Test for equality any JavaScript type.
-// Author: Philippe Rathé
-QUnit.equiv = (function() {
-
- // Call the o related callback with the given arguments.
- function bindCallbacks( o, callbacks, args ) {
- var prop = QUnit.objectType( o );
- if ( prop ) {
- if ( QUnit.objectType( callbacks[ prop ] ) === "function" ) {
- return callbacks[ prop ].apply( callbacks, args );
- } else {
- return callbacks[ prop ]; // or undefined
- }
- }
- }
-
- // the real equiv function
- var innerEquiv,
- // stack to decide between skip/abort functions
- callers = [],
- // stack to avoiding loops from circular referencing
- parents = [],
-
- getProto = Object.getPrototypeOf || function ( obj ) {
- return obj.__proto__;
- },
- callbacks = (function () {
-
- // for string, boolean, number and null
- function useStrictEquality( b, a ) {
- /*jshint eqeqeq:false */
- if ( b instanceof a.constructor || a instanceof b.constructor ) {
- // to catch short annotaion VS 'new' annotation of a
- // declaration
- // e.g. var i = 1;
- // var j = new Number(1);
- return a == b;
- } else {
- return a === b;
- }
- }
-
- return {
- "string": useStrictEquality,
- "boolean": useStrictEquality,
- "number": useStrictEquality,
- "null": useStrictEquality,
- "undefined": useStrictEquality,
-
- "nan": function( b ) {
- return isNaN( b );
- },
-
- "date": function( b, a ) {
- return QUnit.objectType( b ) === "date" && a.valueOf() === b.valueOf();
- },
-
- "regexp": function( b, a ) {
- return QUnit.objectType( b ) === "regexp" &&
- // the regex itself
- a.source === b.source &&
- // and its modifers
- a.global === b.global &&
- // (gmi) ...
- a.ignoreCase === b.ignoreCase &&
- a.multiline === b.multiline &&
- a.sticky === b.sticky;
- },
-
- // - skip when the property is a method of an instance (OOP)
- // - abort otherwise,
- // initial === would have catch identical references anyway
- "function": function() {
- var caller = callers[callers.length - 1];
- return caller !== Object && typeof caller !== "undefined";
- },
-
- "array": function( b, a ) {
- var i, j, len, loop;
-
- // b could be an object literal here
- if ( QUnit.objectType( b ) !== "array" ) {
- return false;
- }
-
- len = a.length;
- if ( len !== b.length ) {
- // safe and faster
- return false;
- }
-
- // track reference to avoid circular references
- parents.push( a );
- for ( i = 0; i < len; i++ ) {
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- loop = true;// dont rewalk array
- }
- }
- if ( !loop && !innerEquiv(a[i], b[i]) ) {
- parents.pop();
- return false;
- }
- }
- parents.pop();
- return true;
- },
-
- "object": function( b, a ) {
- var i, j, loop,
- // Default to true
- eq = true,
- aProperties = [],
- bProperties = [];
-
- // comparing constructors is more strict than using
- // instanceof
- if ( a.constructor !== b.constructor ) {
- // Allow objects with no prototype to be equivalent to
- // objects with Object as their constructor.
- if ( !(( getProto(a) === null && getProto(b) === Object.prototype ) ||
- ( getProto(b) === null && getProto(a) === Object.prototype ) ) ) {
- return false;
- }
- }
-
- // stack constructor before traversing properties
- callers.push( a.constructor );
- // track reference to avoid circular references
- parents.push( a );
-
- for ( i in a ) { // be strict: don't ensures hasOwnProperty
- // and go deep
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- // don't go down the same path twice
- loop = true;
- }
- }
- aProperties.push(i); // collect a's properties
-
- if (!loop && !innerEquiv( a[i], b[i] ) ) {
- eq = false;
- break;
- }
- }
-
- callers.pop(); // unstack, we are done
- parents.pop();
-
- for ( i in b ) {
- bProperties.push( i ); // collect b's properties
- }
-
- // Ensures identical properties name
- return eq && innerEquiv( aProperties.sort(), bProperties.sort() );
- }
- };
- }());
-
- innerEquiv = function() { // can take multiple arguments
- var args = [].slice.apply( arguments );
- if ( args.length < 2 ) {
- return true; // end transition
- }
-
- return (function( a, b ) {
- if ( a === b ) {
- return true; // catch the most you can
- } else if ( a === null || b === null || typeof a === "undefined" ||
- typeof b === "undefined" ||
- QUnit.objectType(a) !== QUnit.objectType(b) ) {
- return false; // don't lose time with error prone cases
- } else {
- return bindCallbacks(a, callbacks, [ b, a ]);
- }
-
- // apply transition with (1..n) arguments
- }( args[0], args[1] ) && arguments.callee.apply( this, args.splice(1, args.length - 1 )) );
- };
-
- return innerEquiv;
-}());
-
-/**
- * jsDump Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com |
- * http://flesler.blogspot.com Licensed under BSD
- * (http://www.opensource.org/licenses/bsd-license.php) Date: 5/15/2008
- *
- * @projectDescription Advanced and extensible data dumping for Javascript.
- * @version 1.0.0
- * @author Ariel Flesler
- * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html}
- */
-QUnit.jsDump = (function() {
- function quote( str ) {
- return '"' + str.toString().replace( /"/g, '\\"' ) + '"';
- }
- function literal( o ) {
- return o + "";
- }
- function join( pre, arr, post ) {
- var s = jsDump.separator(),
- base = jsDump.indent(),
- inner = jsDump.indent(1);
- if ( arr.join ) {
- arr = arr.join( "," + s + inner );
- }
- if ( !arr ) {
- return pre + post;
- }
- return [ pre, inner + arr, base + post ].join(s);
- }
- function array( arr, stack ) {
- var i = arr.length, ret = new Array(i);
- this.up();
- while ( i-- ) {
- ret[i] = this.parse( arr[i] , undefined , stack);
- }
- this.down();
- return join( "[", ret, "]" );
- }
-
- var reName = /^function (\w+)/,
- jsDump = {
- // type is used mostly internally, you can fix a (custom)type in advance
- parse: function( obj, type, stack ) {
- stack = stack || [ ];
- var inStack, res,
- parser = this.parsers[ type || this.typeOf(obj) ];
-
- type = typeof parser;
- inStack = inArray( obj, stack );
-
- if ( inStack !== -1 ) {
- return "recursion(" + (inStack - stack.length) + ")";
- }
- if ( type === "function" ) {
- stack.push( obj );
- res = parser.call( this, obj, stack );
- stack.pop();
- return res;
- }
- return ( type === "string" ) ? parser : this.parsers.error;
- },
- typeOf: function( obj ) {
- var type;
- if ( obj === null ) {
- type = "null";
- } else if ( typeof obj === "undefined" ) {
- type = "undefined";
- } else if ( QUnit.is( "regexp", obj) ) {
- type = "regexp";
- } else if ( QUnit.is( "date", obj) ) {
- type = "date";
- } else if ( QUnit.is( "function", obj) ) {
- type = "function";
- } else if ( typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined" ) {
- type = "window";
- } else if ( obj.nodeType === 9 ) {
- type = "document";
- } else if ( obj.nodeType ) {
- type = "node";
- } else if (
- // native arrays
- toString.call( obj ) === "[object Array]" ||
- // NodeList objects
- ( typeof obj.length === "number" && typeof obj.item !== "undefined" && ( obj.length ? obj.item(0) === obj[0] : ( obj.item( 0 ) === null && typeof obj[0] === "undefined" ) ) )
- ) {
- type = "array";
- } else if ( obj.constructor === Error.prototype.constructor ) {
- type = "error";
- } else {
- type = typeof obj;
- }
- return type;
- },
- separator: function() {
- return this.multiline ? this.HTML ? "
" : "\n" : this.HTML ? " " : " ";
- },
- // extra can be a number, shortcut for increasing-calling-decreasing
- indent: function( extra ) {
- if ( !this.multiline ) {
- return "";
- }
- var chr = this.indentChar;
- if ( this.HTML ) {
- chr = chr.replace( /\t/g, " " ).replace( / /g, " " );
- }
- return new Array( this._depth_ + (extra||0) ).join(chr);
- },
- up: function( a ) {
- this._depth_ += a || 1;
- },
- down: function( a ) {
- this._depth_ -= a || 1;
- },
- setParser: function( name, parser ) {
- this.parsers[name] = parser;
- },
- // The next 3 are exposed so you can use them
- quote: quote,
- literal: literal,
- join: join,
- //
- _depth_: 1,
- // This is the list of parsers, to modify them, use jsDump.setParser
- parsers: {
- window: "[Window]",
- document: "[Document]",
- error: function(error) {
- return "Error(\"" + error.message + "\")";
- },
- unknown: "[Unknown]",
- "null": "null",
- "undefined": "undefined",
- "function": function( fn ) {
- var ret = "function",
- // functions never have name in IE
- name = "name" in fn ? fn.name : (reName.exec(fn) || [])[1];
-
- if ( name ) {
- ret += " " + name;
- }
- ret += "( ";
-
- ret = [ ret, QUnit.jsDump.parse( fn, "functionArgs" ), "){" ].join( "" );
- return join( ret, QUnit.jsDump.parse(fn,"functionCode" ), "}" );
- },
- array: array,
- nodelist: array,
- "arguments": array,
- object: function( map, stack ) {
- var ret = [ ], keys, key, val, i;
- QUnit.jsDump.up();
- keys = [];
- for ( key in map ) {
- keys.push( key );
- }
- keys.sort();
- for ( i = 0; i < keys.length; i++ ) {
- key = keys[ i ];
- val = map[ key ];
- ret.push( QUnit.jsDump.parse( key, "key" ) + ": " + QUnit.jsDump.parse( val, undefined, stack ) );
- }
- QUnit.jsDump.down();
- return join( "{", ret, "}" );
- },
- node: function( node ) {
- var len, i, val,
- open = QUnit.jsDump.HTML ? "<" : "<",
- close = QUnit.jsDump.HTML ? ">" : ">",
- tag = node.nodeName.toLowerCase(),
- ret = open + tag,
- attrs = node.attributes;
-
- if ( attrs ) {
- for ( i = 0, len = attrs.length; i < len; i++ ) {
- val = attrs[i].nodeValue;
- // IE6 includes all attributes in .attributes, even ones not explicitly set.
- // Those have values like undefined, null, 0, false, "" or "inherit".
- if ( val && val !== "inherit" ) {
- ret += " " + attrs[i].nodeName + "=" + QUnit.jsDump.parse( val, "attribute" );
- }
- }
- }
- ret += close;
-
- // Show content of TextNode or CDATASection
- if ( node.nodeType === 3 || node.nodeType === 4 ) {
- ret += node.nodeValue;
- }
-
- return ret + open + "/" + tag + close;
- },
- // function calls it internally, it's the arguments part of the function
- functionArgs: function( fn ) {
- var args,
- l = fn.length;
-
- if ( !l ) {
- return "";
- }
-
- args = new Array(l);
- while ( l-- ) {
- // 97 is 'a'
- args[l] = String.fromCharCode(97+l);
- }
- return " " + args.join( ", " ) + " ";
- },
- // object calls it internally, the key part of an item in a map
- key: quote,
- // function calls it internally, it's the content of the function
- functionCode: "[code]",
- // node calls it internally, it's an html attribute value
- attribute: quote,
- string: quote,
- date: quote,
- regexp: literal,
- number: literal,
- "boolean": literal
- },
- // if true, entities are escaped ( <, >, \t, space and \n )
- HTML: false,
- // indentation unit
- indentChar: " ",
- // if true, items in a collection, are separated by a \n, else just a space.
- multiline: true
- };
-
- return jsDump;
-}());
-
-// from jquery.js
-function inArray( elem, array ) {
- if ( array.indexOf ) {
- return array.indexOf( elem );
- }
-
- for ( var i = 0, length = array.length; i < length; i++ ) {
- if ( array[ i ] === elem ) {
- return i;
- }
- }
-
- return -1;
-}
-
-/*
- * Javascript Diff Algorithm
- * By John Resig (http://ejohn.org/)
- * Modified by Chu Alan "sprite"
- *
- * Released under the MIT license.
- *
- * More Info:
- * http://ejohn.org/projects/javascript-diff-algorithm/
- *
- * Usage: QUnit.diff(expected, actual)
- *
- * QUnit.diff( "the quick brown fox jumped over", "the quick fox jumps over" ) == "the quick brown fox jumped jumps over"
- */
-QUnit.diff = (function() {
- /*jshint eqeqeq:false, eqnull:true */
- function diff( o, n ) {
- var i,
- ns = {},
- os = {};
-
- for ( i = 0; i < n.length; i++ ) {
- if ( !hasOwn.call( ns, n[i] ) ) {
- ns[ n[i] ] = {
- rows: [],
- o: null
- };
- }
- ns[ n[i] ].rows.push( i );
- }
-
- for ( i = 0; i < o.length; i++ ) {
- if ( !hasOwn.call( os, o[i] ) ) {
- os[ o[i] ] = {
- rows: [],
- n: null
- };
- }
- os[ o[i] ].rows.push( i );
- }
-
- for ( i in ns ) {
- if ( !hasOwn.call( ns, i ) ) {
- continue;
- }
- if ( ns[i].rows.length === 1 && hasOwn.call( os, i ) && os[i].rows.length === 1 ) {
- n[ ns[i].rows[0] ] = {
- text: n[ ns[i].rows[0] ],
- row: os[i].rows[0]
- };
- o[ os[i].rows[0] ] = {
- text: o[ os[i].rows[0] ],
- row: ns[i].rows[0]
- };
- }
- }
-
- for ( i = 0; i < n.length - 1; i++ ) {
- if ( n[i].text != null && n[ i + 1 ].text == null && n[i].row + 1 < o.length && o[ n[i].row + 1 ].text == null &&
- n[ i + 1 ] == o[ n[i].row + 1 ] ) {
-
- n[ i + 1 ] = {
- text: n[ i + 1 ],
- row: n[i].row + 1
- };
- o[ n[i].row + 1 ] = {
- text: o[ n[i].row + 1 ],
- row: i + 1
- };
- }
- }
-
- for ( i = n.length - 1; i > 0; i-- ) {
- if ( n[i].text != null && n[ i - 1 ].text == null && n[i].row > 0 && o[ n[i].row - 1 ].text == null &&
- n[ i - 1 ] == o[ n[i].row - 1 ]) {
-
- n[ i - 1 ] = {
- text: n[ i - 1 ],
- row: n[i].row - 1
- };
- o[ n[i].row - 1 ] = {
- text: o[ n[i].row - 1 ],
- row: i - 1
- };
- }
- }
-
- return {
- o: o,
- n: n
- };
- }
-
- return function( o, n ) {
- o = o.replace( /\s+$/, "" );
- n = n.replace( /\s+$/, "" );
-
- var i, pre,
- str = "",
- out = diff( o === "" ? [] : o.split(/\s+/), n === "" ? [] : n.split(/\s+/) ),
- oSpace = o.match(/\s+/g),
- nSpace = n.match(/\s+/g);
-
- if ( oSpace == null ) {
- oSpace = [ " " ];
- }
- else {
- oSpace.push( " " );
- }
-
- if ( nSpace == null ) {
- nSpace = [ " " ];
- }
- else {
- nSpace.push( " " );
- }
-
- if ( out.n.length === 0 ) {
- for ( i = 0; i < out.o.length; i++ ) {
- str += "" + out.o[i] + oSpace[i] + "";
- }
- }
- else {
- if ( out.n[0].text == null ) {
- for ( n = 0; n < out.o.length && out.o[n].text == null; n++ ) {
- str += "" + out.o[n] + oSpace[n] + "";
- }
- }
-
- for ( i = 0; i < out.n.length; i++ ) {
- if (out.n[i].text == null) {
- str += "" + out.n[i] + nSpace[i] + "";
- }
- else {
- // `pre` initialized at top of scope
- pre = "";
-
- for ( n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++ ) {
- pre += "" + out.o[n] + oSpace[n] + "";
- }
- str += " " + out.n[i].text + nSpace[i] + pre;
- }
- }
- }
-
- return str;
- };
-}());
-
-// for CommonJS enviroments, export everything
-if ( typeof exports !== "undefined" ) {
- extend( exports, QUnit );
-}
-
-// get at whatever the global object is, like window in browsers
-}( (function() {return this;}.call()) ));
diff --git a/test/lib/require.js b/test/lib/require.js
deleted file mode 100644
index 987f865..0000000
--- a/test/lib/require.js
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- RequireJS 2.1.5 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.
- Available via the MIT or new BSD license.
- see: http://github.com/jrburke/requirejs for details
-*/
-var requirejs,require,define;
-(function(aa){function I(b){return"[object Function]"===L.call(b)}function J(b){return"[object Array]"===L.call(b)}function y(b,c){if(b){var d;for(d=0;dthis.depCount&&!this.defined){if(I(n)){if(this.events.error)try{e=i.execCb(c,n,b,e)}catch(d){a=d}else e=i.execCb(c,n,b,e);this.map.isDefine&&((b=this.module)&&void 0!==b.exports&&b.exports!==this.exports?e=b.exports:void 0===e&&this.usingExports&&(e=this.exports));if(a)return a.requireMap=this.map,a.requireModules=[this.map.id],a.requireType="define",v(this.error=
-a)}else e=n;this.exports=e;if(this.map.isDefine&&!this.ignore&&(q[c]=e,l.onResourceLoad))l.onResourceLoad(i,this.map,this.depMaps);x(c);this.defined=!0}this.defining=!1;this.defined&&!this.defineEmitted&&(this.defineEmitted=!0,this.emit("defined",this.exports),this.defineEmitComplete=!0)}}else this.fetch()}},callPlugin:function(){var a=this.map,b=a.id,d=j(a.prefix);this.depMaps.push(d);t(d,"defined",u(this,function(e){var n,d;d=this.map.name;var g=this.map.parentMap?this.map.parentMap.name:null,h=
-i.makeRequire(a.parentMap,{enableBuildCallback:!0});if(this.map.unnormalized){if(e.normalize&&(d=e.normalize(d,function(a){return c(a,g,!0)})||""),e=j(a.prefix+"!"+d,this.map.parentMap),t(e,"defined",u(this,function(a){this.init([],function(){return a},null,{enabled:!0,ignore:!0})})),d=m(p,e.id)){this.depMaps.push(e);if(this.events.error)d.on("error",u(this,function(a){this.emit("error",a)}));d.enable()}}else n=u(this,function(a){this.init([],function(){return a},null,{enabled:!0})}),n.error=u(this,
-function(a){this.inited=!0;this.error=a;a.requireModules=[b];G(p,function(a){0===a.map.id.indexOf(b+"_unnormalized")&&x(a.map.id)});v(a)}),n.fromText=u(this,function(e,c){var d=a.name,g=j(d),C=O;c&&(e=c);C&&(O=!1);r(g);s(k.config,b)&&(k.config[d]=k.config[b]);try{l.exec(e)}catch(ca){return v(B("fromtexteval","fromText eval for "+b+" failed: "+ca,ca,[b]))}C&&(O=!0);this.depMaps.push(g);i.completeLoad(d);h([d],n)}),e.load(a.name,h,n,k)}));i.enable(d,this);this.pluginMaps[d.id]=d},enable:function(){V[this.map.id]=
-this;this.enabling=this.enabled=!0;y(this.depMaps,u(this,function(a,b){var c,e;if("string"===typeof a){a=j(a,this.map.isDefine?this.map:this.map.parentMap,!1,!this.skipMap);this.depMaps[b]=a;if(c=m(N,a.id)){this.depExports[b]=c(this);return}this.depCount+=1;t(a,"defined",u(this,function(a){this.defineDep(b,a);this.check()}));this.errback&&t(a,"error",this.errback)}c=a.id;e=p[c];!s(N,c)&&(e&&!e.enabled)&&i.enable(a,this)}));G(this.pluginMaps,u(this,function(a){var b=m(p,a.id);b&&!b.enabled&&i.enable(a,
-this)}));this.enabling=!1;this.check()},on:function(a,b){var c=this.events[a];c||(c=this.events[a]=[]);c.push(b)},emit:function(a,b){y(this.events[a],function(a){a(b)});"error"===a&&delete this.events[a]}};i={config:k,contextName:b,registry:p,defined:q,urlFetched:U,defQueue:H,Module:Z,makeModuleMap:j,nextTick:l.nextTick,onError:v,configure:function(a){a.baseUrl&&"/"!==a.baseUrl.charAt(a.baseUrl.length-1)&&(a.baseUrl+="/");var b=k.pkgs,c=k.shim,e={paths:!0,config:!0,map:!0};G(a,function(a,b){e[b]?
-"map"===b?(k.map||(k.map={}),R(k[b],a,!0,!0)):R(k[b],a,!0):k[b]=a});a.shim&&(G(a.shim,function(a,b){J(a)&&(a={deps:a});if((a.exports||a.init)&&!a.exportsFn)a.exportsFn=i.makeShimExports(a);c[b]=a}),k.shim=c);a.packages&&(y(a.packages,function(a){a="string"===typeof a?{name:a}:a;b[a.name]={name:a.name,location:a.location||a.name,main:(a.main||"main").replace(ja,"").replace(ea,"")}}),k.pkgs=b);G(p,function(a,b){!a.inited&&!a.map.unnormalized&&(a.map=j(b))});if(a.deps||a.callback)i.require(a.deps||[],
-a.callback)},makeShimExports:function(a){return function(){var b;a.init&&(b=a.init.apply(aa,arguments));return b||a.exports&&ba(a.exports)}},makeRequire:function(a,f){function d(e,c,h){var g,k;f.enableBuildCallback&&(c&&I(c))&&(c.__requireJsBuild=!0);if("string"===typeof e){if(I(c))return v(B("requireargs","Invalid require call"),h);if(a&&s(N,e))return N[e](p[a.id]);if(l.get)return l.get(i,e,a,d);g=j(e,a,!1,!0);g=g.id;return!s(q,g)?v(B("notloaded",'Module name "'+g+'" has not been loaded yet for context: '+
-b+(a?"":". Use require([])"))):q[g]}L();i.nextTick(function(){L();k=r(j(null,a));k.skipMap=f.skipMap;k.init(e,c,h,{enabled:!0});D()});return d}f=f||{};R(d,{isBrowser:A,toUrl:function(b){var d,f=b.lastIndexOf("."),g=b.split("/")[0];if(-1!==f&&(!("."===g||".."===g)||1h.attachEvent.toString().indexOf("[native code"))&&!Y?(O=!0,h.attachEvent("onreadystatechange",b.onScriptLoad)):(h.addEventListener("load",b.onScriptLoad,!1),h.addEventListener("error",b.onScriptError,!1)),h.src=d,K=h,D?x.insertBefore(h,D):x.appendChild(h),K=null,h;if(da)try{importScripts(d),b.completeLoad(c)}catch(j){b.onError(B("importscripts","importScripts failed for "+c+" at "+d,j,[c]))}};A&&M(document.getElementsByTagName("script"),function(b){x||(x=
-b.parentNode);if(t=b.getAttribute("data-main"))return r.baseUrl||(E=t.split("/"),Q=E.pop(),fa=E.length?E.join("/")+"/":"./",r.baseUrl=fa,t=Q),t=t.replace(ea,""),r.deps=r.deps?r.deps.concat(t):[t],!0});define=function(b,c,d){var l,h;"string"!==typeof b&&(d=c,c=b,b=null);J(c)||(d=c,c=[]);!c.length&&I(d)&&d.length&&(d.toString().replace(la,"").replace(ma,function(b,d){c.push(d)}),c=(1===d.length?["require"]:["require","exports","module"]).concat(c));if(O){if(!(l=K))P&&"interactive"===P.readyState||M(document.getElementsByTagName("script"),
-function(b){if("interactive"===b.readyState)return P=b}),l=P;l&&(b||(b=l.getAttribute("data-requiremodule")),h=F[l.getAttribute("data-requirecontext")])}(h?h.defQueue:T).push([b,c,d])};define.amd={jQuery:!0};l.exec=function(b){return eval(b)};l(r)}})(this);
diff --git a/test/lib/resemble.js b/test/lib/resemble.js
new file mode 100644
index 0000000..1cb8c29
--- /dev/null
+++ b/test/lib/resemble.js
@@ -0,0 +1,535 @@
+/*
+Author: James Cryer
+Company: Huddle
+Last updated date: 21 Feb 2013
+URL: https://github.com/Huddle/Resemble.js
+*/
+
+(function(_this){
+ 'use strict';
+
+ _this['resemble'] = function( fileData ){
+
+ var data = {};
+ var images = [];
+ var updateCallbackArray = [];
+
+ var tolerance = { // between 0 and 255
+ red: 16,
+ green: 16,
+ blue: 16,
+ minBrightness: 16,
+ maxBrightness: 240
+ };
+
+ var ignoreAntialiasing = false;
+ var ignoreColors = false;
+
+ function triggerDataUpdate(){
+ var len = updateCallbackArray.length;
+ var i;
+ for(i=0;i tolerance.maxBrightness;
+ }
+
+ function getHue(r,g,b){
+
+ r = r / 255;
+ g = g / 255;
+ b = b / 255;
+ var max = Math.max(r, g, b), min = Math.min(r, g, b);
+ var h;
+ var d;
+
+ if (max == min){
+ h = 0; // achromatic
+ } else{
+ d = max - min;
+ switch(max){
+ case r: h = (g - b) / d + (g < b ? 6 : 0); break;
+ case g: h = (b - r) / d + 2; break;
+ case b: h = (r - g) / d + 4; break;
+ }
+ h /= 6;
+ }
+
+ return h;
+ }
+
+ function isAntialiased(sourcePix, data, cacheSet, verticalPos, horizontalPos, width){
+ var offset;
+ var targetPix;
+ var distance = 1;
+ var i;
+ var j;
+ var hasHighContrastSibling = 0;
+ var hasSiblingWithDifferentHue = 0;
+ var hasEquivilantSibling = 0;
+
+ addHueInfo(sourcePix);
+
+ for (i = distance*-1; i <= distance; i++){
+ for (j = distance*-1; j <= distance; j++){
+
+ if(i===0 && j===0){
+ // ignore source pixel
+ } else {
+
+ offset = ((verticalPos+j)*width + (horizontalPos+i)) * 4;
+ targetPix = getPixelInfo(data, offset, cacheSet);
+
+ if(targetPix === null){
+ continue;
+ }
+
+ addBrightnessInfo(targetPix);
+ addHueInfo(targetPix);
+
+ if( isContrasting(sourcePix, targetPix) ){
+ hasHighContrastSibling++;
+ }
+
+ if( isRGBSame(sourcePix,targetPix) ){
+ hasEquivilantSibling++;
+ }
+
+ if( Math.abs(targetPix.h - sourcePix.h) > 0.3 ){
+ hasSiblingWithDifferentHue++;
+ }
+
+ if( hasSiblingWithDifferentHue > 1 || hasHighContrastSibling > 1){
+ return true;
+ }
+ }
+ }
+ }
+
+ if(hasEquivilantSibling < 2){
+ return true;
+ }
+
+ return false;
+ }
+
+ function errorPixel(px, offset){
+ px[offset] = 255; //r
+ px[offset + 1] = 0; //g
+ px[offset + 2] = 255; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyPixel(px, offset, data){
+ px[offset] = data.r; //r
+ px[offset + 1] = data.g; //g
+ px[offset + 2] = data.b; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyGrayScalePixel(px, offset, data){
+ px[offset] = data.brightness; //r
+ px[offset + 1] = data.brightness; //g
+ px[offset + 2] = data.brightness; //b
+ px[offset + 3] = 255; //a
+ }
+
+
+ function getPixelInfo(data, offset, cacheSet){
+ var r;
+ var g;
+ var b;
+ var d;
+
+ if(typeof data[offset] !== 'undefined'){
+ r = data[offset];
+ g = data[offset+1];
+ b = data[offset+2];
+ d = {
+ r: r,
+ g: g,
+ b: b
+ };
+
+ return d;
+ } else {
+ return null;
+ }
+ }
+
+ function addBrightnessInfo(data){
+ data.brightness = getBrightness(data.r,data.g,data.b); // 'corrected' lightness
+ }
+
+ function addHueInfo(data){
+ data.h = getHue(data.r,data.g,data.b);
+ }
+
+ function analyseImages(img1, img2, width, height){
+
+ var hiddenCanvas = document.createElement('canvas');
+
+ var data1 = img1.data;
+ var data2 = img2.data;
+
+ hiddenCanvas.width = width;
+ hiddenCanvas.height = height;
+
+ var context = hiddenCanvas.getContext('2d');
+ var imgd = context.createImageData(width,height);
+ var targetPix = imgd.data;
+
+ var mismatchCount = 0;
+
+ var time = Date.now();
+
+ var skip;
+
+ if( (width > 1200 || height > 1200) && ignoreAntialiasing){
+ skip = 6;
+ }
+
+ loop(height, width, function(verticalPos, horizontalPos){
+
+ if(skip){ // only skip if the image isn't small
+ if(verticalPos % skip === 0 || horizontalPos % skip === 0){
+ return;
+ }
+ }
+
+ var offset = (verticalPos*width + horizontalPos) * 4;
+ var pixel1 = getPixelInfo(data1, offset, 1);
+ var pixel2 = getPixelInfo(data2, offset, 2);
+
+ if(pixel1 === null || pixel2 === null){
+ return;
+ }
+
+ if (ignoreColors){
+
+ addBrightnessInfo(pixel1);
+ addBrightnessInfo(pixel2);
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ return;
+ }
+
+ if( isRGBSimilar(pixel1, pixel2) ){
+ copyPixel(targetPix, offset, pixel2);
+
+ } else if( ignoreAntialiasing && (
+ addBrightnessInfo(pixel1), // jit pixel info augmentation looks a little weird, sorry.
+ addBrightnessInfo(pixel2),
+ isAntialiased(pixel1, data1, 1, verticalPos, horizontalPos, width) ||
+ isAntialiased(pixel2, data2, 2, verticalPos, horizontalPos, width)
+ )){
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+
+ });
+
+ data.misMatchPercentage = (mismatchCount / (height*width) * 100).toFixed(2);
+ data.analysisTime = Date.now() - time;
+
+ data.getImageDataUrl = function(text){
+ var barHeight = 0;
+
+ if(text){
+ barHeight = addLabel(text,context,hiddenCanvas);
+ }
+
+ context.putImageData(imgd, 0, barHeight);
+
+ return hiddenCanvas.toDataURL("image/png");
+ };
+ }
+
+ function addLabel(text, context, hiddenCanvas){
+ var textPadding = 2;
+
+ context.font = '12px sans-serif';
+
+ var textWidth = context.measureText(text).width + textPadding*2;
+ var barHeight = 22;
+
+ if(textWidth > hiddenCanvas.width){
+ hiddenCanvas.width = textWidth;
+ }
+
+ hiddenCanvas.height += barHeight;
+
+ context.fillStyle = "#666";
+ context.fillRect(0,0,hiddenCanvas.width,barHeight -4);
+ context.fillStyle = "#fff";
+ context.fillRect(0,barHeight -4,hiddenCanvas.width, 4);
+
+ context.fillStyle = "#fff";
+ context.textBaseline = "top";
+ context.font = '12px sans-serif';
+ context.fillText(text, textPadding, 1);
+
+ return barHeight;
+ }
+
+ function normalise(img, w, h){
+ var c;
+ var context;
+
+ if(img.height < h || img.width < w){
+ c = document.createElement('canvas');
+ c.width = w;
+ c.height = h;
+ context = c.getContext('2d');
+ context.putImageData(img, 0, 0);
+ return context.getImageData(0, 0, w, h);
+ }
+
+ return img;
+ }
+
+ function compare(one, two){
+
+ function onceWeHaveBoth(){
+ var width;
+ var height;
+ if(images.length === 2){
+ width = images[0].width > images[1].width ? images[0].width : images[1].width;
+ height = images[0].height > images[1].height ? images[0].height : images[1].height;
+
+ if( (images[0].width === images[1].width) && (images[0].height === images[1].height) ){
+ data.isSameDimensions = true;
+ } else {
+ data.isSameDimensions = false;
+ }
+
+ analyseImages( normalise(images[0],width, height), normalise(images[1],width, height), width, height);
+
+ triggerDataUpdate();
+ }
+ }
+
+ images = [];
+ loadImageData(one, onceWeHaveBoth);
+ loadImageData(two, onceWeHaveBoth);
+ }
+
+ function getCompareApi(param){
+
+ var secondFileData,
+ hasMethod = typeof param === 'function';
+
+ if( !hasMethod ){
+ // assume it's file data
+ secondFileData = param;
+ }
+
+ var self = {
+ ignoreNothing: function(){
+
+ tolerance.red = 16;
+ tolerance.green = 16;
+ tolerance.blue = 16;
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreAntialiasing: function(){
+
+ tolerance.red = 32;
+ tolerance.green = 32;
+ tolerance.blue = 32;
+ tolerance.minBrightness = 64;
+ tolerance.maxBrightness = 96;
+
+ ignoreAntialiasing = true;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreColors: function(){
+
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = true;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ onComplete: function( callback ){
+
+ updateCallbackArray.push(callback);
+
+ var wrapper = function(){
+ compare(fileData, secondFileData);
+ };
+
+ wrapper();
+
+ return getCompareApi(wrapper);
+ }
+ };
+
+ return self;
+ }
+
+ return {
+ onComplete: function( callback ){
+ updateCallbackArray.push(callback);
+ loadImageData(fileData, function(imageData, width, height){
+ parseImage(imageData.data, width, height);
+ });
+ },
+ compareTo: function(secondFileData){
+ return getCompareApi(secondFileData);
+ }
+ };
+
+ };
+}(this));
\ No newline at end of file
diff --git a/test/testsuite.js b/test/testsuite.js
deleted file mode 100644
index b486acb..0000000
--- a/test/testsuite.js
+++ /dev/null
@@ -1,36 +0,0 @@
-requirejs.config({
- baseUrl: '/test/unit/'
-});
-
-define(function(require) {
- var testModules = [
- 'Pixi',
- 'Point',
- 'Rectangle',
- 'DisplayObject',
- 'DisplayObjectContainer',
- 'Sprite',
- 'MovieClip',
- 'InteractionManager',
- 'Stage',
- 'utils/Utils',
- 'utils/EventTarget',
- 'utils/Matrix',
- 'utils/Detector',
- 'renderers/WebGLShaders',
- 'renderers/WebGLRenderer',
- 'renderers/WebGLBatch',
- 'renderers/CanvasRenderer',
- 'extras/Strip',
- 'extras/Rope',
- 'textures/BaseTexture',
- 'textures/Texture',
- 'loaders/SpriteSheetLoader',
- 'loaders/AssetLoader'
- ];
-
- // Resolve all testModules and then start the Test Runner.
- require(testModules, function() {
- QUnit.start();
- });
-});
\ No newline at end of file
diff --git a/test/textures/SpriteSheet-Aliens.png b/test/textures/SpriteSheet-Aliens.png
new file mode 100644
index 0000000..210acb1
--- /dev/null
+++ b/test/textures/SpriteSheet-Aliens.png
Binary files differ
diff --git a/test/textures/SpriteSheet-Explosion.png b/test/textures/SpriteSheet-Explosion.png
new file mode 100755
index 0000000..79e1a69
--- /dev/null
+++ b/test/textures/SpriteSheet-Explosion.png
Binary files differ
diff --git a/test/textures/bunny.png b/test/textures/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/textures/bunny.png
Binary files differ
diff --git a/test/unit/DisplayObject.js b/test/unit/DisplayObject.js
deleted file mode 100644
index 5e7e72f..0000000
--- a/test/unit/DisplayObject.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObject');
-});
diff --git a/test/unit/DisplayObjectContainer.js b/test/unit/DisplayObjectContainer.js
deleted file mode 100644
index b323959..0000000
--- a/test/unit/DisplayObjectContainer.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObjectContainer');
-});
diff --git a/test/unit/InteractionManager.js b/test/unit/InteractionManager.js
deleted file mode 100644
index e751f52..0000000
--- a/test/unit/InteractionManager.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('InteractionManager');
-});
diff --git a/test/unit/MovieClip.js b/test/unit/MovieClip.js
deleted file mode 100644
index 37d9446..0000000
--- a/test/unit/MovieClip.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('MovieClip');
-});
diff --git a/test/unit/Pixi.js b/test/unit/Pixi.js
deleted file mode 100644
index 36eee73..0000000
--- a/test/unit/Pixi.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Pixi');
-});
diff --git a/test/unit/Point.js b/test/unit/Point.js
deleted file mode 100644
index 983ff6e..0000000
--- a/test/unit/Point.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Point');
-});
diff --git a/test/unit/Rectangle.js b/test/unit/Rectangle.js
deleted file mode 100644
index 3b439ba..0000000
--- a/test/unit/Rectangle.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Rectangle');
-});
diff --git a/test/unit/Sprite.js b/test/unit/Sprite.js
deleted file mode 100644
index ed4f596..0000000
--- a/test/unit/Sprite.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Sprite');
-});
diff --git a/test/unit/Stage.js b/test/unit/Stage.js
deleted file mode 100644
index 2d70291..0000000
--- a/test/unit/Stage.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Stage');
-});
diff --git a/test/unit/extras/Rope.js b/test/unit/extras/Rope.js
deleted file mode 100644
index 5606f14..0000000
--- a/test/unit/extras/Rope.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Rope');
-});
diff --git a/test/unit/extras/Strip.js b/test/unit/extras/Strip.js
deleted file mode 100644
index 0134d3a..0000000
--- a/test/unit/extras/Strip.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Strip');
-});
diff --git a/test/unit/loaders/AssetLoader.js b/test/unit/loaders/AssetLoader.js
deleted file mode 100644
index 13b8443..0000000
--- a/test/unit/loaders/AssetLoader.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('AssetLoader');
-});
diff --git a/test/unit/loaders/SpriteSheetLoader.js b/test/unit/loaders/SpriteSheetLoader.js
deleted file mode 100644
index 8bf0cb2..0000000
--- a/test/unit/loaders/SpriteSheetLoader.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('SpriteSheetLoader');
-});
diff --git a/test/unit/pixi/InteractionManager.js b/test/unit/pixi/InteractionManager.js
new file mode 100644
index 0000000..ed3001f
--- /dev/null
+++ b/test/unit/pixi/InteractionManager.js
@@ -0,0 +1,10 @@
+describe('pixi/InteractionManager', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var InteractionManager = PIXI.InteractionManager;
+
+ it('Module exists', function () {
+ expect(InteractionManager).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/Pixi.js b/test/unit/pixi/Pixi.js
new file mode 100644
index 0000000..27debc1
--- /dev/null
+++ b/test/unit/pixi/Pixi.js
@@ -0,0 +1,9 @@
+describe('pixi/Pixi', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+
+ it('Module exists', function () {
+ expect(global).to.have.property('PIXI').and.to.be.an('object');
+ });
+});
diff --git a/test/unit/pixi/core/Circle.js b/test/unit/pixi/core/Circle.js
new file mode 100644
index 0000000..93a4456
--- /dev/null
+++ b/test/unit/pixi/core/Circle.js
@@ -0,0 +1,22 @@
+describe('pixi/core/Circle', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Circle = PIXI.Circle;
+
+ it('Module exists', function () {
+ expect(Circle).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Circle();
+
+ expect(obj).to.be.an.instanceof(Circle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', 0);
+ expect(obj).to.have.property('y', 0);
+ expect(obj).to.have.property('radius', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Ellipse.js b/test/unit/pixi/core/Ellipse.js
new file mode 100644
index 0000000..026b56f
--- /dev/null
+++ b/test/unit/pixi/core/Ellipse.js
@@ -0,0 +1,24 @@
+describe('pixi/core/Ellipse', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Ellipse = PIXI.Ellipse;
+
+ it('Module exists', function () {
+ expect(Ellipse).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Ellipse();
+
+ expect(obj).to.be.an.instanceof(Ellipse);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+ expect(obj).to.respondTo('getBounds');
+
+ expect(obj).to.have.property('x', 0);
+ expect(obj).to.have.property('y', 0);
+ expect(obj).to.have.property('width', 0);
+ expect(obj).to.have.property('height', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Matrix.js b/test/unit/pixi/core/Matrix.js
new file mode 100644
index 0000000..b48989e
--- /dev/null
+++ b/test/unit/pixi/core/Matrix.js
@@ -0,0 +1,30 @@
+describe('pixi/core/Matrix', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var mat3 = PIXI.mat3;
+ var mat4 = PIXI.mat4;
+ var Matrix = PIXI.Matrix;
+
+ it('Ensure determineMatrixArrayType works', function () {
+ expect(Matrix).to.be.a('function');
+ });
+
+ it('mat3 exists', function () {
+ expect(mat3).to.be.an('object');
+ });
+
+ it('Confirm new mat3 matrix', function () {
+ var matrix = new mat3.create();
+ pixi_core_Matrix_confirmNewMat3(matrix);
+ });
+
+ it('mat3 exists', function () {
+ expect(mat4).to.be.an('object');
+ });
+
+ it('Confirm new mat4 matrix', function () {
+ var matrix = new mat4.create();
+ pixi_core_Matrix_confirmNewMat4(matrix);
+ });
+});
diff --git a/test/unit/pixi/core/Point.js b/test/unit/pixi/core/Point.js
new file mode 100644
index 0000000..c4d5163
--- /dev/null
+++ b/test/unit/pixi/core/Point.js
@@ -0,0 +1,15 @@
+describe('pixi/core/Point', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Point = PIXI.Point;
+
+ it('Module exists', function () {
+ expect(Point).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Point();
+ pixi_core_Point_confirm(obj, 0, 0);
+ });
+});
diff --git a/test/unit/pixi/core/Polygon.js b/test/unit/pixi/core/Polygon.js
new file mode 100644
index 0000000..dc8c918
--- /dev/null
+++ b/test/unit/pixi/core/Polygon.js
@@ -0,0 +1,20 @@
+describe('pixi/core/Polygon', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Polygon = PIXI.Polygon;
+
+ it('Module exists', function () {
+ expect(Polygon).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Polygon();
+
+ expect(obj).to.be.an.instanceof(Polygon);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.deep.property('points.length', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Rectangle.js b/test/unit/pixi/core/Rectangle.js
new file mode 100644
index 0000000..d43316e
--- /dev/null
+++ b/test/unit/pixi/core/Rectangle.js
@@ -0,0 +1,15 @@
+describe('pixi/core/Rectangle', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Rectangle = PIXI.Rectangle;
+
+ it('Module exists', function () {
+ expect(Rectangle).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var rect = new Rectangle();
+ pixi_core_Rectangle_confirm(rect, 0, 0, 0, 0);
+ });
+});
diff --git a/test/unit/pixi/display/DisplayObject.js b/test/unit/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..40c6fbc
--- /dev/null
+++ b/test/unit/pixi/display/DisplayObject.js
@@ -0,0 +1,21 @@
+describe('pixi/display/DisplayObject', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var DisplayObject = PIXI.DisplayObject;
+
+ it('Module exists', function () {
+ expect(DisplayObject).to.be.a('function');
+ expect(PIXI).to.have.property('visibleCount', 0);
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new DisplayObject();
+
+ pixi_display_DisplayObject_confirmNew(obj);
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', false);
+ expect(obj).to.have.property('stage', null);
+ });
+});
diff --git a/test/unit/pixi/display/DisplayObjectContainer.js b/test/unit/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..ce7f02f
--- /dev/null
+++ b/test/unit/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,20 @@
+describe('pixi/display/DisplayObjectContainer', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var DisplayObjectContainer = PIXI.DisplayObjectContainer;
+
+ it('Module exists', function () {
+ expect(DisplayObjectContainer).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new DisplayObjectContainer();
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', false);
+ expect(obj).to.have.property('stage', null);
+ });
+});
diff --git a/test/unit/pixi/display/MovieClip.js b/test/unit/pixi/display/MovieClip.js
new file mode 100644
index 0000000..f3c6c6a
--- /dev/null
+++ b/test/unit/pixi/display/MovieClip.js
@@ -0,0 +1,33 @@
+describe('pixi/display/MovieClip', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var MovieClip = PIXI.MovieClip;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(MovieClip).to.be.a('function');
+ });
+
+ it('Confirm new instance', function (done) {
+ var texture = Texture.fromImage('/base/test/textures/SpriteSheet-Explosion.png');
+ var obj = new MovieClip([texture]);
+
+ pixi_display_Sprite_confirmNew(obj, done);
+
+ expect(obj).to.be.an.instanceof(MovieClip);
+ expect(obj).to.respondTo('stop');
+ expect(obj).to.respondTo('play');
+ expect(obj).to.respondTo('gotoAndStop');
+ expect(obj).to.respondTo('gotoAndPlay');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('textures.length', 1);
+ expect(obj).to.have.deep.property('textures[0]', texture);
+ expect(obj).to.have.property('animationSpeed', 1);
+ expect(obj).to.have.property('loop', true);
+ expect(obj).to.have.property('onComplete', null);
+ expect(obj).to.have.property('currentFrame', 0);
+ expect(obj).to.have.property('playing', false);
+ });
+});
diff --git a/test/unit/pixi/display/Sprite.js b/test/unit/pixi/display/Sprite.js
new file mode 100644
index 0000000..54e914f
--- /dev/null
+++ b/test/unit/pixi/display/Sprite.js
@@ -0,0 +1,25 @@
+describe('pixi/display/Sprite', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Sprite = PIXI.Sprite;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(Sprite).to.be.a('function');
+ expect(PIXI).to.have.deep.property('blendModes.NORMAL', 0);
+ expect(PIXI).to.have.deep.property('blendModes.SCREEN', 1);
+ });
+
+ it('Members exist', function () {
+ expect(Sprite).itself.to.respondTo('fromImage');
+ expect(Sprite).itself.to.respondTo('fromFrame');
+ });
+
+ it('Confirm new instance', function (done) {
+ var texture = Texture.fromImage('/base/test/textures/SpriteSheet-Aliens.png');
+ var obj = new Sprite(texture);
+
+ pixi_display_Sprite_confirmNew(obj, done);
+ });
+});
diff --git a/test/unit/pixi/display/Stage.js b/test/unit/pixi/display/Stage.js
new file mode 100644
index 0000000..3cc2a4d
--- /dev/null
+++ b/test/unit/pixi/display/Stage.js
@@ -0,0 +1,49 @@
+describe('pixi/display/Stage', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Stage = PIXI.Stage;
+ var InteractionManager = PIXI.InteractionManager;
+ var Rectangle = PIXI.Rectangle;
+
+ it('Module exists', function () {
+ expect(Stage).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Stage(null, true);
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(Stage);
+ expect(obj).to.respondTo('updateTransform');
+ expect(obj).to.respondTo('setBackgroundColor');
+ expect(obj).to.respondTo('getMousePosition');
+
+ // FIXME: duplicate member in DisplayObject
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ // FIXME: convert arg to bool in constructor
+ expect(obj).to.have.property('interactive', true);
+
+ expect(obj).to.have.property('interactionManager')
+ .and.to.be.an.instanceof(InteractionManager)
+ .and.to.have.property('stage', obj);
+
+ expect(obj).to.have.property('dirty', true);
+
+ expect(obj).to.have.property('stage', obj);
+
+ expect(obj).to.have.property('hitArea')
+ .and.to.be.an.instanceof(Rectangle);
+ pixi_core_Rectangle_confirm(obj.hitArea, 0, 0, 100000, 100000);
+
+ expect(obj).to.have.property('backgroundColor', 0x000000);
+ expect(obj).to.have.deep.property('backgroundColorSplit.length', 3);
+ expect(obj).to.have.deep.property('backgroundColorSplit[0]', 0);
+ expect(obj).to.have.deep.property('backgroundColorSplit[1]', 0);
+ expect(obj).to.have.deep.property('backgroundColorSplit[2]', 0);
+ expect(obj).to.have.property('backgroundColorString', '#000000');
+
+ expect(obj).to.have.property('worldVisible', true);
+ });
+});
diff --git a/test/unit/pixi/extras/CustomRenderable.js b/test/unit/pixi/extras/CustomRenderable.js
new file mode 100644
index 0000000..8d83cf0
--- /dev/null
+++ b/test/unit/pixi/extras/CustomRenderable.js
@@ -0,0 +1,21 @@
+describe('pixi/extras/CustomRenderable', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var CustomRenderable = PIXI.CustomRenderable;
+
+ it('Module exists', function () {
+ expect(CustomRenderable).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new CustomRenderable();
+
+ pixi_display_DisplayObject_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(CustomRenderable);
+ expect(obj).to.respondTo('renderCanvas');
+ expect(obj).to.respondTo('initWebGL');
+ expect(obj).to.respondTo('renderWebGL');
+ });
+});
diff --git a/test/unit/pixi/extras/Rope.js b/test/unit/pixi/extras/Rope.js
new file mode 100644
index 0000000..6ddaf83
--- /dev/null
+++ b/test/unit/pixi/extras/Rope.js
@@ -0,0 +1,26 @@
+describe('pixi/extras/Rope', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Rope = PIXI.Rope;
+ var Texture = PIXI.Texture;
+ var Point = PIXI.Point;
+
+ it('Module exists', function () {
+ expect(Rope).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var texture = Texture.fromImage('/base/test/textures/bunny.png');
+ var obj = new Rope(texture, [new Point(), new Point(5, 10), new Point(10, 20)]);
+
+ pixi_extras_Strip_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(Rope);
+ expect(obj).to.respondTo('refresh');
+ expect(obj).to.respondTo('updateTransform');
+ expect(obj).to.respondTo('setTexture');
+
+ // TODO: Test properties
+ });
+});
diff --git a/test/unit/pixi/extras/Spine.js b/test/unit/pixi/extras/Spine.js
new file mode 100644
index 0000000..0708bc0
--- /dev/null
+++ b/test/unit/pixi/extras/Spine.js
@@ -0,0 +1,10 @@
+describe('pixi/extras/Spine', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Spine = PIXI.Spine;
+
+ it('Module exists', function () {
+ expect(Spine).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/extras/Strip.js b/test/unit/pixi/extras/Strip.js
new file mode 100644
index 0000000..8e564e1
--- /dev/null
+++ b/test/unit/pixi/extras/Strip.js
@@ -0,0 +1,18 @@
+describe('pixi/extras/Strip', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Strip = PIXI.Strip;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(Strip).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var texture = Texture.fromImage('/base/test/textures/bunny.png');
+ var obj = new Strip(texture, 20, 10000);
+
+ pixi_extras_Strip_confirmNew(obj);
+ });
+});
diff --git a/test/unit/pixi/extras/TilingSprite.js b/test/unit/pixi/extras/TilingSprite.js
new file mode 100644
index 0000000..56aea14
--- /dev/null
+++ b/test/unit/pixi/extras/TilingSprite.js
@@ -0,0 +1,24 @@
+describe('pixi/extras/TilingSprite', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var TilingSprite = PIXI.TilingSprite;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(TilingSprite).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var texture = Texture.fromImage('/base/test/textures/bunny.png');
+ var obj = new TilingSprite(texture, 6000, 12000);
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(TilingSprite);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ // TODO: Test properties
+ });
+});
diff --git a/test/unit/pixi/filters/FilterBlock.js b/test/unit/pixi/filters/FilterBlock.js
new file mode 100644
index 0000000..870cec0
--- /dev/null
+++ b/test/unit/pixi/filters/FilterBlock.js
@@ -0,0 +1,10 @@
+describe('pixi/filters/FilterBlock', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var FilterBlock = PIXI.FilterBlock;
+
+ it('Module exists', function () {
+ expect(FilterBlock).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/filters/MaskFilter.js b/test/unit/pixi/filters/MaskFilter.js
new file mode 100644
index 0000000..32d6a45
--- /dev/null
+++ b/test/unit/pixi/filters/MaskFilter.js
@@ -0,0 +1,10 @@
+describe('pixi/filters/MaskFilter', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ // var MaskFilter = PIXI.MaskFilter;
+
+ // it('Module exists', function () {
+ // expect(MaskFilter).to.be.a('function');
+ // });
+});
diff --git a/test/unit/pixi/loaders/AssetLoader.js b/test/unit/pixi/loaders/AssetLoader.js
new file mode 100644
index 0000000..a0aa0b5
--- /dev/null
+++ b/test/unit/pixi/loaders/AssetLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/AssetLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var AssetLoader = PIXI.AssetLoader;
+
+ it('Module exists', function () {
+ expect(AssetLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/BitmapFontLoader.js b/test/unit/pixi/loaders/BitmapFontLoader.js
new file mode 100644
index 0000000..6253c42
--- /dev/null
+++ b/test/unit/pixi/loaders/BitmapFontLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/BitmapFontLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var BitmapFontLoader = PIXI.BitmapFontLoader;
+
+ it('Module exists', function () {
+ expect(PIXI.BitmapFontLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/ImageLoader.js b/test/unit/pixi/loaders/ImageLoader.js
new file mode 100644
index 0000000..8b1f556
--- /dev/null
+++ b/test/unit/pixi/loaders/ImageLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/ImageLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var ImageLoader = PIXI.ImageLoader;
+
+ it('Module exists', function () {
+ expect(ImageLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/JsonLoader.js b/test/unit/pixi/loaders/JsonLoader.js
new file mode 100644
index 0000000..c577e83
--- /dev/null
+++ b/test/unit/pixi/loaders/JsonLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/JsonLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var JsonLoader = PIXI.JsonLoader;
+
+ it('Module exists', function () {
+ expect(JsonLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/SpineLoader.js b/test/unit/pixi/loaders/SpineLoader.js
new file mode 100644
index 0000000..fdcc0b8
--- /dev/null
+++ b/test/unit/pixi/loaders/SpineLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/SpineLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var SpineLoader = PIXI.SpineLoader;
+
+ it('Module exists', function () {
+ expect(SpineLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/SpriteSheetLoader.js b/test/unit/pixi/loaders/SpriteSheetLoader.js
new file mode 100644
index 0000000..57beb27
--- /dev/null
+++ b/test/unit/pixi/loaders/SpriteSheetLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/SpriteSheetLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var SpriteSheetLoader = PIXI.SpriteSheetLoader;
+
+ it('Module exists', function () {
+ expect(SpriteSheetLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/primitives/Graphics.js b/test/unit/pixi/primitives/Graphics.js
new file mode 100644
index 0000000..b8b3e5c
--- /dev/null
+++ b/test/unit/pixi/primitives/Graphics.js
@@ -0,0 +1,40 @@
+describe('pixi/primitives/Graphics', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Graphics = PIXI.Graphics;
+
+ it('Module exists', function () {
+ expect(Graphics).to.be.a('function');
+
+ expect(Graphics).itself.to.have.property('POLY', 0);
+ expect(Graphics).itself.to.have.property('RECT', 1);
+ expect(Graphics).itself.to.have.property('CIRC', 2);
+ expect(Graphics).itself.to.have.property('ELIP', 3);
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Graphics();
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(Graphics);
+ expect(obj).to.respondTo('lineStyle');
+ expect(obj).to.respondTo('lineStyle');
+ expect(obj).to.respondTo('moveTo');
+ expect(obj).to.respondTo('lineTo');
+ expect(obj).to.respondTo('beginFill');
+ expect(obj).to.respondTo('endFill');
+ expect(obj).to.respondTo('drawRect');
+ expect(obj).to.respondTo('drawCircle');
+ expect(obj).to.respondTo('drawElipse');
+ expect(obj).to.respondTo('clear');
+
+ expect(obj).to.have.property('renderable', true);
+ expect(obj).to.have.property('fillAlpha', 1);
+ expect(obj).to.have.property('lineWidth', 0);
+ expect(obj).to.have.property('lineColor', 'black');
+ expect(obj).to.have.deep.property('graphicsData.length', 0);
+ expect(obj).to.have.deep.property('currentPath.points.length', 0);
+ });
+});
diff --git a/test/unit/pixi/renderers/canvas/CanvasGraphics.js b/test/unit/pixi/renderers/canvas/CanvasGraphics.js
new file mode 100644
index 0000000..8f44472
--- /dev/null
+++ b/test/unit/pixi/renderers/canvas/CanvasGraphics.js
@@ -0,0 +1,15 @@
+describe('renders/canvas/CanvasGraphics', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var CanvasGraphics = PIXI.CanvasGraphics;
+
+ it('Module exists', function () {
+ expect(CanvasGraphics).to.be.a('function');
+ });
+
+ it('Members exist', function () {
+ expect(CanvasGraphics).itself.to.respondTo('renderGraphics');
+ expect(CanvasGraphics).itself.to.respondTo('renderGraphicsMask');
+ });
+});
diff --git a/test/unit/pixi/renderers/canvas/CanvasRenderer.js b/test/unit/pixi/renderers/canvas/CanvasRenderer.js
new file mode 100644
index 0000000..df3a12f
--- /dev/null
+++ b/test/unit/pixi/renderers/canvas/CanvasRenderer.js
@@ -0,0 +1,10 @@
+describe('renderers/canvas/CanvasRenderer', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var CanvasRenderer = PIXI.CanvasRenderer;
+
+ it('Module exists', function () {
+ expect(CanvasRenderer).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/renderers/webgl/WebGLBatch.js b/test/unit/pixi/renderers/webgl/WebGLBatch.js
new file mode 100644
index 0000000..75efd56
--- /dev/null
+++ b/test/unit/pixi/renderers/webgl/WebGLBatch.js
@@ -0,0 +1,10 @@
+describe('renderers/webgl/WebGLBatch', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var WebGLBatch = PIXI.WebGLBatch;
+
+ it('Module exists', function () {
+ expect(WebGLBatch).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/renderers/webgl/WebGLGraphics.js b/test/unit/pixi/renderers/webgl/WebGLGraphics.js
new file mode 100644
index 0000000..41bf941
--- /dev/null
+++ b/test/unit/pixi/renderers/webgl/WebGLGraphics.js
@@ -0,0 +1,19 @@
+describe('renderers/wegbl/WebGLGraphics', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var WebGLGraphics = PIXI.WebGLGraphics;
+
+ it('Module exists', function () {
+ expect(WebGLGraphics).to.be.a('function');
+ });
+
+ it('Members exist', function () {
+ expect(WebGLGraphics).itself.to.respondTo('renderGraphics');
+ expect(WebGLGraphics).itself.to.respondTo('updateGraphics');
+ expect(WebGLGraphics).itself.to.respondTo('buildRectangle');
+ expect(WebGLGraphics).itself.to.respondTo('buildCircle');
+ expect(WebGLGraphics).itself.to.respondTo('buildLine');
+ expect(WebGLGraphics).itself.to.respondTo('buildPoly');
+ });
+});
diff --git a/test/unit/pixi/renderers/webgl/WebGLRenderGroup.js b/test/unit/pixi/renderers/webgl/WebGLRenderGroup.js
new file mode 100644
index 0000000..f4ee366
--- /dev/null
+++ b/test/unit/pixi/renderers/webgl/WebGLRenderGroup.js
@@ -0,0 +1,10 @@
+describe('renderers/webgl/WebGLRenderGroup', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var WebGLRenderGroup = PIXI.WebGLRenderGroup;
+
+ it('Module exists', function () {
+ expect(WebGLRenderGroup).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/renderers/webgl/WebGLRenderer.js b/test/unit/pixi/renderers/webgl/WebGLRenderer.js
new file mode 100644
index 0000000..86533eb
--- /dev/null
+++ b/test/unit/pixi/renderers/webgl/WebGLRenderer.js
@@ -0,0 +1,10 @@
+describe('renderers/webgl/WebGLRenderer', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var WebGLRenderer = PIXI.WebGLRenderer;
+
+ it('Module exists', function () {
+ expect(WebGLRenderer).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/renderers/webgl/WebGLShaders.js b/test/unit/pixi/renderers/webgl/WebGLShaders.js
new file mode 100644
index 0000000..2872de8
--- /dev/null
+++ b/test/unit/pixi/renderers/webgl/WebGLShaders.js
@@ -0,0 +1,13 @@
+describe('renderers/webgl/WebGLShaders', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+
+ it('Module members exist', function () {
+ expect(PIXI).to.respondTo('initPrimitiveShader');
+ expect(PIXI).to.respondTo('initDefaultShader');
+ expect(PIXI).to.respondTo('initDefaultStripShader');
+ expect(PIXI).to.respondTo('activateDefaultShader');
+ expect(PIXI).to.respondTo('activatePrimitiveShader');
+ });
+});
diff --git a/.gitignore b/.gitignore
index 12e1b62..0b88317 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
node_modules
.DS_Store
-.project
\ No newline at end of file
+.project
+*.log
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..63e4d7c
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,8 @@
+language: node_js
+node_js:
+ - 0.10
+
+before_script:
+ - npm install -g grunt-cli
+ - export DISPLAY=:99.0
+ - sh -e /etc/init.d/xvfb start
diff --git a/Gruntfile.js b/Gruntfile.js
index b083b49..103938c 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -1,10 +1,12 @@
+'use strict';
+
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-connect');
- grunt.loadNpmTasks('grunt-contrib-qunit');
grunt.loadNpmTasks('grunt-contrib-yuidoc');
+ grunt.loadTasks('tasks');
var root = 'src/pixi/',
debug = 'bin/pixi.dev.js',
@@ -79,7 +81,7 @@
},
files: {
srcBlob: '<%= dirs.src %>/**/*.js',
- testBlob: '<%= dirs.test %>/unit/**/*.js',
+ testBlob: '<%= dirs.test %>/{functional,lib/pixi,unit}/**/*.js',
build: '<%= dirs.build %>/pixi.dev.js',
buildMin: '<%= dirs.build %>/pixi.js'
},
@@ -94,7 +96,12 @@
},
jshint: {
beforeconcat: srcFiles,
- test: ['<%= files.testBlob %>'],
+ test: {
+ src: ['<%= files.testBlob %>'],
+ options: {
+ expr: true
+ }
+ },
options: {
asi: true,
smarttabs: true
@@ -128,12 +135,6 @@
]
},
connect: {
- qunit: {
- options: {
- port: grunt.option('port-test') || 9002,
- base: './'
- }
- },
test: {
options: {
port: grunt.option('port-test') || 9002,
@@ -142,13 +143,6 @@
}
}
},
- qunit: {
- all: {
- options: {
- urls: ['http://localhost:' + (grunt.option('port-test') || 9002) + '/test/index.html']
- }
- }
- },
yuidoc: {
compile: {
name: '<%= pkg.name %>',
@@ -161,6 +155,13 @@
outdir: '<%= dirs.docs %>'
}
}
+ },
+ karma: {
+ unit: {
+ configFile: 'test/karma.conf.js',
+ // browsers: ['Chrome'],
+ singleRun: true
+ }
}
});
@@ -182,9 +183,10 @@
}
)
- grunt.registerTask('default', ['concat', 'uglify', 'distribute']);
grunt.registerTask('build', ['concat', 'uglify', 'distribute']);
- grunt.registerTask('test', ['build', 'connect:qunit', 'qunit']);
+ grunt.registerTask('test', ['concat', 'jshint:test', 'karma']);
grunt.registerTask('docs', ['yuidoc']);
-
-}
\ No newline at end of file
+ grunt.registerTask('default', ['test', 'uglify', 'distribute']);
+ // Travis CI task.
+ grunt.registerTask('travis', ['test']);
+}
diff --git a/README.md b/README.md
index c62ef86..690cfe4 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,8 @@

+[](http://travis-ci.org/drkibitz/pixi.js)
+
#### JavaScript 2D Renderer ####
The aim of this project is to provide a fast lightweight 2D library that works
diff --git a/package.json b/package.json
index b373240..1246a68 100644
--- a/package.json
+++ b/package.json
@@ -18,14 +18,21 @@
"main": "bin/pixi.js",
+ "scripts": {
+ "test": "grunt travis --verbose"
+ },
+
"dependencies": {},
"devDependencies": {
"grunt": "~0.4.x",
- "grunt-contrib-jshint": "0.3.x",
+ "grunt-contrib-jshint": "0.6.x",
"grunt-contrib-uglify": "0.2.x",
- "grunt-contrib-connect": "0.2.x",
- "grunt-contrib-qunit": "0.2.x",
+ "grunt-contrib-connect": "0.3.x",
"grunt-contrib-yuidoc": "0.4.x",
- "grunt-contrib-concat": "0.1.x"
+ "grunt-contrib-concat": "0.3.x",
+ "chai": "~1.7.0",
+ "karma": "0.11.0",
+ "karma-firefox-launcher": "0.1.0",
+ "karma-mocha": "0.1.0"
}
}
diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js
index a7c520e..ee82bbd 100644
--- a/src/pixi/InteractionManager.js
+++ b/src/pixi/InteractionManager.js
@@ -62,7 +62,6 @@
this.onTouchEnd = this.onTouchEnd.bind(this);
this.onTouchMove = this.onTouchMove.bind(this);
-
this.last = 0;
}
diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js
index 1a95d20..eef1059 100644
--- a/src/pixi/core/Ellipse.js
+++ b/src/pixi/core/Ellipse.js
@@ -78,7 +78,7 @@
return (normx + normy < 0.25);
}
-PIXI.Ellipse.getBounds = function()
+PIXI.Ellipse.prototype.getBounds = function()
{
return new PIXI.Rectangle(this.x, this.y, this.width, this.height);
}
diff --git a/tasks/karma.js b/tasks/karma.js
new file mode 100644
index 0000000..c340485
--- /dev/null
+++ b/tasks/karma.js
@@ -0,0 +1,27 @@
+'use strict';
+
+var path = require('path');
+var server = require('karma').server;
+
+module.exports = function (grunt) {
+ grunt.registerMultiTask('karma', 'run karma.', function() {
+ var done = this.async();
+ var options = this.options({
+ background: false
+ });
+ var data = this.data;
+
+ //merge options onto data, with data taking precedence
+ data = grunt.util._.merge(options, data);
+ data.configFile = path.resolve(data.configFile);
+ if (data.configFile) {
+ data.configFile = grunt.template.process(data.configFile);
+ }
+
+ server.start(
+ data,
+ function(code) {
+ done(!code);
+ });
+ });
+};
diff --git a/test/functional/example-1-basics/bunny.png b/test/functional/example-1-basics/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/functional/example-1-basics/bunny.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-30.png b/test/functional/example-1-basics/frame-30.png
new file mode 100644
index 0000000..96e3409
--- /dev/null
+++ b/test/functional/example-1-basics/frame-30.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-60.png b/test/functional/example-1-basics/frame-60.png
new file mode 100644
index 0000000..af3f4ce
--- /dev/null
+++ b/test/functional/example-1-basics/frame-60.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-90.png b/test/functional/example-1-basics/frame-90.png
new file mode 100644
index 0000000..099b823
--- /dev/null
+++ b/test/functional/example-1-basics/frame-90.png
Binary files differ
diff --git a/test/functional/example-1-basics/index.js b/test/functional/example-1-basics/index.js
new file mode 100644
index 0000000..7ae7a98
--- /dev/null
+++ b/test/functional/example-1-basics/index.js
@@ -0,0 +1,133 @@
+describe('Example 1 - Basics', function () {
+ 'use strict';
+
+ var baseUri = '/base/test/functional/example-1-basics';
+ var expect = chai.expect;
+ var currentFrame = 0;
+ var frameEvents = {};
+ var stage;
+ var renderer;
+ var bunny;
+
+ function onFrame(frame, callback) {
+ frameEvents[frame] = callback;
+ }
+
+ function animate() {
+ currentFrame += 1;
+
+ requestAnimFrame( animate );
+
+ // just for fun, lets rotate mr rabbit a little
+ bunny.rotation += 0.1;
+
+ // render the stage
+ renderer.render(stage);
+
+ if (frameEvents[currentFrame])
+ frameEvents[currentFrame](currentFrame);
+ }
+
+ function initScene() {
+ // create an new instance of a pixi stage
+ stage = new PIXI.Stage(0x66FF99);
+
+ // create a renderer instance
+ renderer = PIXI.autoDetectRenderer(400, 300);
+ console.log('Is PIXI.WebGLRenderer: ' + (renderer instanceof PIXI.WebGLRenderer));
+
+ // add the renderer view element to the DOM
+ document.body.appendChild(renderer.view);
+
+ requestAnimFrame( animate );
+
+ // create a texture from an image path
+ var texture = PIXI.Texture.fromImage(baseUri + "/bunny.png");
+ // create a new Sprite using the texture
+ bunny = new PIXI.Sprite(texture);
+
+ // center the sprites anchor point
+ bunny.anchor.x = 0.5;
+ bunny.anchor.y = 0.5;
+
+ // move the sprite t the center of the screen
+ bunny.position.x = 200;
+ bunny.position.y = 150;
+
+ stage.addChild(bunny);
+ }
+
+ it('assets loaded', function (done) {
+ var loader = new PIXI.AssetLoader([
+ baseUri + '/bunny.png',
+ baseUri + '/frame-30.png',
+ baseUri + '/frame-60.png',
+ baseUri + '/frame-90.png'
+ ]);
+ // loader.on('onProgress', function (event) {
+ // console.log(event.content);
+ // });
+ loader.on('onComplete', function (event) {
+ done();
+ initScene();
+ });
+ loader.load();
+ });
+
+ it('frame 30 should match', function (done) {
+ this.timeout(700);
+ onFrame(30, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-30.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 60 should match', function (done) {
+ this.timeout(1200);
+ onFrame(60, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-60.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 90 should match', function (done) {
+ this.timeout(1700);
+ onFrame(90, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-90.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ // it('capture something', function (done) {
+ // this.timeout(2000000);
+ // onFrame(30, function () {
+ // var img = new Image();
+ // img.src = renderer.view.toDataURL('image/png');
+ // document.body.appendChild(img);
+ // });
+ // });
+});
diff --git a/test/index.html b/test/index.html
deleted file mode 100644
index 9cbcac5..0000000
--- a/test/index.html
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
- Pixi.js Test Suite
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/test/karma.conf.js b/test/karma.conf.js
new file mode 100644
index 0000000..c66a696
--- /dev/null
+++ b/test/karma.conf.js
@@ -0,0 +1,82 @@
+module.exports = function(config) {
+ config.set({
+
+ // base path, that will be used to resolve files and exclude
+ basePath : '../',
+
+ frameworks : ['mocha'],
+
+ // list of files / patterns to load in the browser
+ files : [
+ 'node_modules/chai/chai.js',
+ 'bin/pixi.dev.js',
+ 'test/lib/**/*.js',
+ 'test/unit/**/*.js',
+ // 'test/functional/**/*.js',
+ {pattern: 'test/**/*.png', watched: false, included: false, served: true}
+ ],
+
+ // list of files to exclude
+ exclude : [],
+
+ // use dolts reporter, as travis terminal does not support escaping sequences
+ // possible values: 'dots', 'progress', 'junit', 'teamcity'
+ // CLI --reporters progress
+ reporters : ['progress'],
+
+ // web server port
+ // CLI --port 9876
+ port : 9876,
+
+ // cli runner port
+ // CLI --runner-port 9100
+ runnerPort : 9100,
+
+ // enable / disable colors in the output (reporters and logs)
+ // CLI --colors --no-colors
+ colors : true,
+
+ // level of logging
+ // possible values: karma.LOG_DISABLE || karma.LOG_ERROR || karma.LOG_WARN || karma.LOG_INFO || karma.LOG_DEBUG
+ // CLI --log-level debug
+ logLevel : config.LOG_DEBUG,
+
+ // enable / disable watching file and executing tests whenever any file changes
+ // CLI --auto-watch --no-auto-watch
+ autoWatch : false,
+
+ // Start these browsers, currently available:
+ // - Chrome
+ // - ChromeCanary
+ // - Firefox
+ // - Opera
+ // - Safari (only Mac)
+ // - PhantomJS
+ // - IE (only Windows)
+ // CLI --browsers Chrome,Firefox,Safari
+ browsers : ['Firefox'],
+
+ // If browser does not capture in given timeout [ms], kill it
+ // CLI --capture-timeout 5000
+ captureTimeout : 5000,
+
+ // Auto run tests on start (when browsers are captured) and exit
+ // CLI --single-run --no-single-run
+ singleRun : true,
+
+ // report which specs are slower than 500ms
+ // CLI --report-slower-than 500
+ reportSlowerThan : 1000,
+
+ preprocessors : {
+ // '**/client/js/*.js': 'coverage'
+ },
+
+ plugins : [
+ 'karma-mocha',
+ // 'karma-chrome-launcher',
+ 'karma-firefox-launcher',
+ // 'karma-phantomjs-launcher'
+ ]
+ });
+};
diff --git a/test/lib/pixi/core/Matrix.js b/test/lib/pixi/core/Matrix.js
new file mode 100644
index 0000000..d26386b
--- /dev/null
+++ b/test/lib/pixi/core/Matrix.js
@@ -0,0 +1,40 @@
+
+function pixi_core_Matrix_confirmNewMat3(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(1);
+ expect(matrix[5]).to.equal(0);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(1);
+}
+
+function pixi_core_Matrix_confirmNewMat4(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[0]).to.equal(1);
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(0);
+ expect(matrix[5]).to.equal(1);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(0);
+ expect(matrix[9]).to.equal(0);
+ expect(matrix[10]).to.equal(1);
+ expect(matrix[11]).to.equal(0);
+ expect(matrix[12]).to.equal(0);
+ expect(matrix[13]).to.equal(0);
+ expect(matrix[14]).to.equal(0);
+ expect(matrix[15]).to.equal(1);
+}
diff --git a/test/lib/pixi/core/Point.js b/test/lib/pixi/core/Point.js
new file mode 100644
index 0000000..e5df07b
--- /dev/null
+++ b/test/lib/pixi/core/Point.js
@@ -0,0 +1,10 @@
+
+function pixi_core_Point_confirm(obj, x, y) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Point);
+ expect(obj).to.respondTo('clone');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+}
diff --git a/test/lib/pixi/core/Rectangle.js b/test/lib/pixi/core/Rectangle.js
new file mode 100644
index 0000000..23f0d12
--- /dev/null
+++ b/test/lib/pixi/core/Rectangle.js
@@ -0,0 +1,13 @@
+
+function pixi_core_Rectangle_confirm(obj, x, y, width, height) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Rectangle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+ expect(obj).to.have.property('width', width);
+ expect(obj).to.have.property('height', height);
+}
diff --git a/test/lib/pixi/display/DisplayObject.js b/test/lib/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..1388a7f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObject.js
@@ -0,0 +1,43 @@
+
+function pixi_display_DisplayObject_confirmNew(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObject);
+ expect(obj).to.respondTo('setInteractive');
+ expect(obj).to.respondTo('addFilter');
+ expect(obj).to.respondTo('removeFilter');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.property('last', obj);
+ expect(obj).to.have.property('first', obj);
+
+ expect(obj).to.contain.property('position');
+ pixi_core_Point_confirm(obj.position, 0, 0);
+ expect(obj).to.contain.property('scale');
+ pixi_core_Point_confirm(obj.scale, 1, 1);
+ expect(obj).to.contain.property('pivot');
+ pixi_core_Point_confirm(obj.pivot, 0, 0);
+
+ expect(obj).to.have.property('rotation', 0);
+ expect(obj).to.have.property('alpha', 1);
+ expect(obj).to.have.property('visible', true);
+ expect(obj).to.have.property('buttonMode', false);
+ expect(obj).to.have.property('parent', null);
+ expect(obj).to.have.property('worldAlpha', 1);
+
+ expect(obj).to.have.property('hitArea');
+ expect(obj).to.have.property('interactive'); // TODO: Have a better default value
+ expect('mask' in obj).to.be.true; // TODO: Have a better default value
+ expect(obj.mask).to.be.undefined;
+
+ expect(obj).to.have.property('renderable');
+ expect(obj).to.have.property('stage');
+
+ expect(obj).to.have.deep.property('worldTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ expect(obj).to.have.deep.property('localTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.localTransform);
+
+ expect(obj).to.have.deep.property('color.length', 0);
+ expect(obj).to.have.property('dynamic', true);
+}
diff --git a/test/lib/pixi/display/DisplayObjectContainer.js b/test/lib/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..085c59f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,16 @@
+
+function pixi_display_DisplayObjectContainer_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObject_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObjectContainer);
+ expect(obj).to.respondTo('addChild');
+ expect(obj).to.respondTo('addChildAt');
+ expect(obj).to.respondTo('swapChildren');
+ expect(obj).to.respondTo('getChildAt');
+ expect(obj).to.respondTo('removeChild');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('children.length', 0);
+}
diff --git a/test/lib/pixi/display/Sprite.js b/test/lib/pixi/display/Sprite.js
new file mode 100644
index 0000000..cc7a2d6
--- /dev/null
+++ b/test/lib/pixi/display/Sprite.js
@@ -0,0 +1,28 @@
+
+function pixi_display_Sprite_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Sprite);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', true);
+ expect(obj).to.have.property('stage', null);
+
+ expect(obj).to.have.property('anchor');
+ pixi_core_Point_confirm(obj.anchor, 0, 0);
+
+ expect(obj).to.have.property('blendMode', PIXI.blendModes.NORMAL);
+ expect(obj).to.have.property('width', 1); // TODO: is 1 expected
+ expect(obj).to.have.property('height', 1); // TODO: is 1 expected
+
+ // FIXME: Just make this a boolean that is always there
+ expect(!!obj.updateFrame).to.equal(obj.texture.baseTexture.hasLoaded);
+
+ expect(obj).to.have.property('texture');
+ pixi_textures_Texture_confirmNew(obj.texture, done);
+}
diff --git a/test/lib/pixi/extras/Strip.js b/test/lib/pixi/extras/Strip.js
new file mode 100644
index 0000000..8927a8a
--- /dev/null
+++ b/test/lib/pixi/extras/Strip.js
@@ -0,0 +1,12 @@
+
+function pixi_extras_Strip_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Strip);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ // TODO: Test properties
+}
diff --git a/test/lib/pixi/textures/Texture.js b/test/lib/pixi/textures/Texture.js
new file mode 100644
index 0000000..d5867b6
--- /dev/null
+++ b/test/lib/pixi/textures/Texture.js
@@ -0,0 +1,31 @@
+
+function pixi_textures_Texture_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ function confirmFrameDone() {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, obj.baseTexture.width, obj.baseTexture.height);
+
+ expect(obj).to.have.property('width', obj.baseTexture.width);
+ expect(obj).to.have.property('height', obj.baseTexture.height);
+ done();
+ }
+
+ expect(obj).to.be.an.instanceof(PIXI.Texture);
+ pixi_utils_EventTarget_like(obj);
+
+ expect(obj).to.have.property('baseTexture')
+ .and.to.be.an.instanceof(PIXI.BaseTexture);
+
+ expect(obj).to.have.property('scope', obj);
+
+ expect(obj).to.have.property('trim');
+ pixi_core_Point_confirm(obj.trim, 0, 0);
+
+ expect(obj).to.have.property('frame');
+ if (obj.baseTexture.hasLoaded) {
+ confirmFrameDone();
+ } else {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, 1, 1);
+ obj.addEventListener('update', confirmFrameDone);
+ }
+}
diff --git a/test/lib/pixi/utils/EventTarget.js b/test/lib/pixi/utils/EventTarget.js
new file mode 100644
index 0000000..7b1dcfa
--- /dev/null
+++ b/test/lib/pixi/utils/EventTarget.js
@@ -0,0 +1,8 @@
+
+function pixi_utils_EventTarget_like(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.respondTo('addEventListener');
+ expect(obj).to.respondTo('dispatchEvent');
+ expect(obj).to.respondTo('removeEventListener');
+}
diff --git a/test/lib/qunit-1.11.0.css b/test/lib/qunit-1.11.0.css
deleted file mode 100644
index d7fc0c8..0000000
--- a/test/lib/qunit-1.11.0.css
+++ /dev/null
@@ -1,244 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-/** Font Family and Sizes */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
- font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
-}
-
-#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
-#qunit-tests { font-size: smaller; }
-
-
-/** Resets */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter {
- margin: 0;
- padding: 0;
-}
-
-
-/** Header */
-
-#qunit-header {
- padding: 0.5em 0 0.5em 1em;
-
- color: #8699a4;
- background-color: #0d3349;
-
- font-size: 1.5em;
- line-height: 1em;
- font-weight: normal;
-
- border-radius: 5px 5px 0 0;
- -moz-border-radius: 5px 5px 0 0;
- -webkit-border-top-right-radius: 5px;
- -webkit-border-top-left-radius: 5px;
-}
-
-#qunit-header a {
- text-decoration: none;
- color: #c2ccd1;
-}
-
-#qunit-header a:hover,
-#qunit-header a:focus {
- color: #fff;
-}
-
-#qunit-testrunner-toolbar label {
- display: inline-block;
- padding: 0 .5em 0 .1em;
-}
-
-#qunit-banner {
- height: 5px;
-}
-
-#qunit-testrunner-toolbar {
- padding: 0.5em 0 0.5em 2em;
- color: #5E740B;
- background-color: #eee;
- overflow: hidden;
-}
-
-#qunit-userAgent {
- padding: 0.5em 0 0.5em 2.5em;
- background-color: #2b81af;
- color: #fff;
- text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
-}
-
-#qunit-modulefilter-container {
- float: right;
-}
-
-/** Tests: Pass/Fail */
-
-#qunit-tests {
- list-style-position: inside;
-}
-
-#qunit-tests li {
- padding: 0.4em 0.5em 0.4em 2.5em;
- border-bottom: 1px solid #fff;
- list-style-position: inside;
-}
-
-#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running {
- display: none;
-}
-
-#qunit-tests li strong {
- cursor: pointer;
-}
-
-#qunit-tests li a {
- padding: 0.5em;
- color: #c2ccd1;
- text-decoration: none;
-}
-#qunit-tests li a:hover,
-#qunit-tests li a:focus {
- color: #000;
-}
-
-#qunit-tests li .runtime {
- float: right;
- font-size: smaller;
-}
-
-.qunit-assert-list {
- margin-top: 0.5em;
- padding: 0.5em;
-
- background-color: #fff;
-
- border-radius: 5px;
- -moz-border-radius: 5px;
- -webkit-border-radius: 5px;
-}
-
-.qunit-collapsed {
- display: none;
-}
-
-#qunit-tests table {
- border-collapse: collapse;
- margin-top: .2em;
-}
-
-#qunit-tests th {
- text-align: right;
- vertical-align: top;
- padding: 0 .5em 0 0;
-}
-
-#qunit-tests td {
- vertical-align: top;
-}
-
-#qunit-tests pre {
- margin: 0;
- white-space: pre-wrap;
- word-wrap: break-word;
-}
-
-#qunit-tests del {
- background-color: #e0f2be;
- color: #374e0c;
- text-decoration: none;
-}
-
-#qunit-tests ins {
- background-color: #ffcaca;
- color: #500;
- text-decoration: none;
-}
-
-/*** Test Counts */
-
-#qunit-tests b.counts { color: black; }
-#qunit-tests b.passed { color: #5E740B; }
-#qunit-tests b.failed { color: #710909; }
-
-#qunit-tests li li {
- padding: 5px;
- background-color: #fff;
- border-bottom: none;
- list-style-position: inside;
-}
-
-/*** Passing Styles */
-
-#qunit-tests li li.pass {
- color: #3c510c;
- background-color: #fff;
- border-left: 10px solid #C6E746;
-}
-
-#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
-#qunit-tests .pass .test-name { color: #366097; }
-
-#qunit-tests .pass .test-actual,
-#qunit-tests .pass .test-expected { color: #999999; }
-
-#qunit-banner.qunit-pass { background-color: #C6E746; }
-
-/*** Failing Styles */
-
-#qunit-tests li li.fail {
- color: #710909;
- background-color: #fff;
- border-left: 10px solid #EE5757;
- white-space: pre;
-}
-
-#qunit-tests > li:last-child {
- border-radius: 0 0 5px 5px;
- -moz-border-radius: 0 0 5px 5px;
- -webkit-border-bottom-right-radius: 5px;
- -webkit-border-bottom-left-radius: 5px;
-}
-
-#qunit-tests .fail { color: #000000; background-color: #EE5757; }
-#qunit-tests .fail .test-name,
-#qunit-tests .fail .module-name { color: #000000; }
-
-#qunit-tests .fail .test-actual { color: #EE5757; }
-#qunit-tests .fail .test-expected { color: green; }
-
-#qunit-banner.qunit-fail { background-color: #EE5757; }
-
-
-/** Result */
-
-#qunit-testresult {
- padding: 0.5em 0.5em 0.5em 2.5em;
-
- color: #2b81af;
- background-color: #D2E0E6;
-
- border-bottom: 1px solid white;
-}
-#qunit-testresult .module-name {
- font-weight: bold;
-}
-
-/** Fixture */
-
-#qunit-fixture {
- position: absolute;
- top: -10000px;
- left: -10000px;
- width: 1000px;
- height: 1000px;
-}
diff --git a/test/lib/qunit-1.11.0.js b/test/lib/qunit-1.11.0.js
deleted file mode 100644
index 302545f..0000000
--- a/test/lib/qunit-1.11.0.js
+++ /dev/null
@@ -1,2152 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-(function( window ) {
-
-var QUnit,
- assert,
- config,
- onErrorFnPrev,
- testId = 0,
- fileName = (sourceFromStacktrace( 0 ) || "" ).replace(/(:\d+)+\)?/, "").replace(/.+\//, ""),
- toString = Object.prototype.toString,
- hasOwn = Object.prototype.hasOwnProperty,
- // Keep a local reference to Date (GH-283)
- Date = window.Date,
- defined = {
- setTimeout: typeof window.setTimeout !== "undefined",
- sessionStorage: (function() {
- var x = "qunit-test-string";
- try {
- sessionStorage.setItem( x, x );
- sessionStorage.removeItem( x );
- return true;
- } catch( e ) {
- return false;
- }
- }())
- },
- /**
- * Provides a normalized error string, correcting an issue
- * with IE 7 (and prior) where Error.prototype.toString is
- * not properly implemented
- *
- * Based on http://es5.github.com/#x15.11.4.4
- *
- * @param {String|Error} error
- * @return {String} error message
- */
- errorString = function( error ) {
- var name, message,
- errorString = error.toString();
- if ( errorString.substring( 0, 7 ) === "[object" ) {
- name = error.name ? error.name.toString() : "Error";
- message = error.message ? error.message.toString() : "";
- if ( name && message ) {
- return name + ": " + message;
- } else if ( name ) {
- return name;
- } else if ( message ) {
- return message;
- } else {
- return "Error";
- }
- } else {
- return errorString;
- }
- },
- /**
- * Makes a clone of an object using only Array or Object as base,
- * and copies over the own enumerable properties.
- *
- * @param {Object} obj
- * @return {Object} New object with only the own properties (recursively).
- */
- objectValues = function( obj ) {
- // Grunt 0.3.x uses an older version of jshint that still has jshint/jshint#392.
- /*jshint newcap: false */
- var key, val,
- vals = QUnit.is( "array", obj ) ? [] : {};
- for ( key in obj ) {
- if ( hasOwn.call( obj, key ) ) {
- val = obj[key];
- vals[key] = val === Object(val) ? objectValues(val) : val;
- }
- }
- return vals;
- };
-
-function Test( settings ) {
- extend( this, settings );
- this.assertions = [];
- this.testNumber = ++Test.count;
-}
-
-Test.count = 0;
-
-Test.prototype = {
- init: function() {
- var a, b, li,
- tests = id( "qunit-tests" );
-
- if ( tests ) {
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml;
-
- // `a` initialized at top of scope
- a = document.createElement( "a" );
- a.innerHTML = "Rerun";
- a.href = QUnit.url({ testNumber: this.testNumber });
-
- li = document.createElement( "li" );
- li.appendChild( b );
- li.appendChild( a );
- li.className = "running";
- li.id = this.id = "qunit-test-output" + testId++;
-
- tests.appendChild( li );
- }
- },
- setup: function() {
- if ( this.module !== config.previousModule ) {
- if ( config.previousModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.previousModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
- config.previousModule = this.module;
- config.moduleStats = { all: 0, bad: 0 };
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- } else if ( config.autorun ) {
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- }
-
- config.current = this;
-
- this.testEnvironment = extend({
- setup: function() {},
- teardown: function() {}
- }, this.moduleTestEnvironment );
-
- this.started = +new Date();
- runLoggingCallbacks( "testStart", QUnit, {
- name: this.testName,
- module: this.module
- });
-
- // allow utility functions to access the current test environment
- // TODO why??
- QUnit.current_testEnvironment = this.testEnvironment;
-
- if ( !config.pollution ) {
- saveGlobal();
- }
- if ( config.notrycatch ) {
- this.testEnvironment.setup.call( this.testEnvironment );
- return;
- }
- try {
- this.testEnvironment.setup.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Setup failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- },
- run: function() {
- config.current = this;
-
- var running = id( "qunit-testresult" );
-
- if ( running ) {
- running.innerHTML = "Running:
" + this.nameHtml;
- }
-
- if ( this.async ) {
- QUnit.stop();
- }
-
- this.callbackStarted = +new Date();
-
- if ( config.notrycatch ) {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- return;
- }
-
- try {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- } catch( e ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
-
- QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + " " + this.stack + ": " + ( e.message || e ), extractStacktrace( e, 0 ) );
- // else next test will carry the responsibility
- saveGlobal();
-
- // Restart the tests if they're blocking
- if ( config.blocking ) {
- QUnit.start();
- }
- }
- },
- teardown: function() {
- config.current = this;
- if ( config.notrycatch ) {
- if ( typeof this.callbackRuntime === "undefined" ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
- }
- this.testEnvironment.teardown.call( this.testEnvironment );
- return;
- } else {
- try {
- this.testEnvironment.teardown.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Teardown failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- }
- checkPollution();
- },
- finish: function() {
- config.current = this;
- if ( config.requireExpects && this.expected === null ) {
- QUnit.pushFailure( "Expected number of assertions to be defined, but expect() was not called.", this.stack );
- } else if ( this.expected !== null && this.expected !== this.assertions.length ) {
- QUnit.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack );
- } else if ( this.expected === null && !this.assertions.length ) {
- QUnit.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions.", this.stack );
- }
-
- var i, assertion, a, b, time, li, ol,
- test = this,
- good = 0,
- bad = 0,
- tests = id( "qunit-tests" );
-
- this.runtime = +new Date() - this.started;
- config.stats.all += this.assertions.length;
- config.moduleStats.all += this.assertions.length;
-
- if ( tests ) {
- ol = document.createElement( "ol" );
- ol.className = "qunit-assert-list";
-
- for ( i = 0; i < this.assertions.length; i++ ) {
- assertion = this.assertions[i];
-
- li = document.createElement( "li" );
- li.className = assertion.result ? "pass" : "fail";
- li.innerHTML = assertion.message || ( assertion.result ? "okay" : "failed" );
- ol.appendChild( li );
-
- if ( assertion.result ) {
- good++;
- } else {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
-
- // store result when possible
- if ( QUnit.config.reorder && defined.sessionStorage ) {
- if ( bad ) {
- sessionStorage.setItem( "qunit-test-" + this.module + "-" + this.testName, bad );
- } else {
- sessionStorage.removeItem( "qunit-test-" + this.module + "-" + this.testName );
- }
- }
-
- if ( bad === 0 ) {
- addClass( ol, "qunit-collapsed" );
- }
-
- // `b` initialized at top of scope
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml + " (" + bad + ", " + good + ", " + this.assertions.length + ")";
-
- addEvent(b, "click", function() {
- var next = b.parentNode.lastChild,
- collapsed = hasClass( next, "qunit-collapsed" );
- ( collapsed ? removeClass : addClass )( next, "qunit-collapsed" );
- });
-
- addEvent(b, "dblclick", function( e ) {
- var target = e && e.target ? e.target : window.event.srcElement;
- if ( target.nodeName.toLowerCase() === "span" || target.nodeName.toLowerCase() === "b" ) {
- target = target.parentNode;
- }
- if ( window.location && target.nodeName.toLowerCase() === "strong" ) {
- window.location = QUnit.url({ testNumber: test.testNumber });
- }
- });
-
- // `time` initialized at top of scope
- time = document.createElement( "span" );
- time.className = "runtime";
- time.innerHTML = this.runtime + " ms";
-
- // `li` initialized at top of scope
- li = id( this.id );
- li.className = bad ? "fail" : "pass";
- li.removeChild( li.firstChild );
- a = li.firstChild;
- li.appendChild( b );
- li.appendChild( a );
- li.appendChild( time );
- li.appendChild( ol );
-
- } else {
- for ( i = 0; i < this.assertions.length; i++ ) {
- if ( !this.assertions[i].result ) {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
- }
-
- runLoggingCallbacks( "testDone", QUnit, {
- name: this.testName,
- module: this.module,
- failed: bad,
- passed: this.assertions.length - bad,
- total: this.assertions.length,
- duration: this.runtime
- });
-
- QUnit.reset();
-
- config.current = undefined;
- },
-
- queue: function() {
- var bad,
- test = this;
-
- synchronize(function() {
- test.init();
- });
- function run() {
- // each of these can by async
- synchronize(function() {
- test.setup();
- });
- synchronize(function() {
- test.run();
- });
- synchronize(function() {
- test.teardown();
- });
- synchronize(function() {
- test.finish();
- });
- }
-
- // `bad` initialized at top of scope
- // defer when previous test run passed, if storage is available
- bad = QUnit.config.reorder && defined.sessionStorage &&
- +sessionStorage.getItem( "qunit-test-" + this.module + "-" + this.testName );
-
- if ( bad ) {
- run();
- } else {
- synchronize( run, true );
- }
- }
-};
-
-// Root QUnit object.
-// `QUnit` initialized at top of scope
-QUnit = {
-
- // call on start of module test to prepend name to all tests
- module: function( name, testEnvironment ) {
- config.currentModule = name;
- config.currentModuleTestEnvironment = testEnvironment;
- config.modules[name] = true;
- },
-
- asyncTest: function( testName, expected, callback ) {
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- QUnit.test( testName, expected, callback, true );
- },
-
- test: function( testName, expected, callback, async ) {
- var test,
- nameHtml = "" + escapeText( testName ) + "";
-
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- if ( config.currentModule ) {
- nameHtml = "" + escapeText( config.currentModule ) + ": " + nameHtml;
- }
-
- test = new Test({
- nameHtml: nameHtml,
- testName: testName,
- expected: expected,
- async: async,
- callback: callback,
- module: config.currentModule,
- moduleTestEnvironment: config.currentModuleTestEnvironment,
- stack: sourceFromStacktrace( 2 )
- });
-
- if ( !validTest( test ) ) {
- return;
- }
-
- test.queue();
- },
-
- // Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through.
- expect: function( asserts ) {
- if (arguments.length === 1) {
- config.current.expected = asserts;
- } else {
- return config.current.expected;
- }
- },
-
- start: function( count ) {
- // QUnit hasn't been initialized yet.
- // Note: RequireJS (et al) may delay onLoad
- if ( config.semaphore === undefined ) {
- QUnit.begin(function() {
- // This is triggered at the top of QUnit.load, push start() to the event loop, to allow QUnit.load to finish first
- setTimeout(function() {
- QUnit.start( count );
- });
- });
- return;
- }
-
- config.semaphore -= count || 1;
- // don't start until equal number of stop-calls
- if ( config.semaphore > 0 ) {
- return;
- }
- // ignore if start is called more often then stop
- if ( config.semaphore < 0 ) {
- config.semaphore = 0;
- QUnit.pushFailure( "Called start() while already started (QUnit.config.semaphore was 0 already)", null, sourceFromStacktrace(2) );
- return;
- }
- // A slight delay, to avoid any current callbacks
- if ( defined.setTimeout ) {
- window.setTimeout(function() {
- if ( config.semaphore > 0 ) {
- return;
- }
- if ( config.timeout ) {
- clearTimeout( config.timeout );
- }
-
- config.blocking = false;
- process( true );
- }, 13);
- } else {
- config.blocking = false;
- process( true );
- }
- },
-
- stop: function( count ) {
- config.semaphore += count || 1;
- config.blocking = true;
-
- if ( config.testTimeout && defined.setTimeout ) {
- clearTimeout( config.timeout );
- config.timeout = window.setTimeout(function() {
- QUnit.ok( false, "Test timed out" );
- config.semaphore = 1;
- QUnit.start();
- }, config.testTimeout );
- }
- }
-};
-
-// `assert` initialized at top of scope
-// Asssert helpers
-// All of these must either call QUnit.push() or manually do:
-// - runLoggingCallbacks( "log", .. );
-// - config.current.assertions.push({ .. });
-// We attach it to the QUnit object *after* we expose the public API,
-// otherwise `assert` will become a global variable in browsers (#341).
-assert = {
- /**
- * Asserts rough true-ish result.
- * @name ok
- * @function
- * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" );
- */
- ok: function( result, msg ) {
- if ( !config.current ) {
- throw new Error( "ok() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
- result = !!result;
-
- var source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: msg
- };
-
- msg = escapeText( msg || (result ? "okay" : "failed" ) );
- msg = "" + msg + "";
-
- if ( !result ) {
- source = sourceFromStacktrace( 2 );
- if ( source ) {
- details.source = source;
- msg += "Source: | " + escapeText( source ) + " |
---|
";
- }
- }
- runLoggingCallbacks( "log", QUnit, details );
- config.current.assertions.push({
- result: result,
- message: msg
- });
- },
-
- /**
- * Assert that the first two arguments are equal, with an optional message.
- * Prints out both actual and expected values.
- * @name equal
- * @function
- * @example equal( format( "Received {0} bytes.", 2), "Received 2 bytes.", "format() replaces {0} with next argument" );
- */
- equal: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected == actual, actual, expected, message );
- },
-
- /**
- * @name notEqual
- * @function
- */
- notEqual: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected != actual, actual, expected, message );
- },
-
- /**
- * @name propEqual
- * @function
- */
- propEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notPropEqual
- * @function
- */
- notPropEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name deepEqual
- * @function
- */
- deepEqual: function( actual, expected, message ) {
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notDeepEqual
- * @function
- */
- notDeepEqual: function( actual, expected, message ) {
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name strictEqual
- * @function
- */
- strictEqual: function( actual, expected, message ) {
- QUnit.push( expected === actual, actual, expected, message );
- },
-
- /**
- * @name notStrictEqual
- * @function
- */
- notStrictEqual: function( actual, expected, message ) {
- QUnit.push( expected !== actual, actual, expected, message );
- },
-
- "throws": function( block, expected, message ) {
- var actual,
- expectedOutput = expected,
- ok = false;
-
- // 'expected' is optional
- if ( typeof expected === "string" ) {
- message = expected;
- expected = null;
- }
-
- config.current.ignoreGlobalErrors = true;
- try {
- block.call( config.current.testEnvironment );
- } catch (e) {
- actual = e;
- }
- config.current.ignoreGlobalErrors = false;
-
- if ( actual ) {
- // we don't want to validate thrown error
- if ( !expected ) {
- ok = true;
- expectedOutput = null;
- // expected is a regexp
- } else if ( QUnit.objectType( expected ) === "regexp" ) {
- ok = expected.test( errorString( actual ) );
- // expected is a constructor
- } else if ( actual instanceof expected ) {
- ok = true;
- // expected is a validation function which returns true is validation passed
- } else if ( expected.call( {}, actual ) === true ) {
- expectedOutput = null;
- ok = true;
- }
-
- QUnit.push( ok, actual, expectedOutput, message );
- } else {
- QUnit.pushFailure( message, null, 'No exception was thrown.' );
- }
- }
-};
-
-/**
- * @deprecate since 1.8.0
- * Kept assertion helpers in root for backwards compatibility.
- */
-extend( QUnit, assert );
-
-/**
- * @deprecated since 1.9.0
- * Kept root "raises()" for backwards compatibility.
- * (Note that we don't introduce assert.raises).
- */
-QUnit.raises = assert[ "throws" ];
-
-/**
- * @deprecated since 1.0.0, replaced with error pushes since 1.3.0
- * Kept to avoid TypeErrors for undefined methods.
- */
-QUnit.equals = function() {
- QUnit.push( false, false, false, "QUnit.equals has been deprecated since 2009 (e88049a0), use QUnit.equal instead" );
-};
-QUnit.same = function() {
- QUnit.push( false, false, false, "QUnit.same has been deprecated since 2009 (e88049a0), use QUnit.deepEqual instead" );
-};
-
-// We want access to the constructor's prototype
-(function() {
- function F() {}
- F.prototype = QUnit;
- QUnit = new F();
- // Make F QUnit's constructor so that we can add to the prototype later
- QUnit.constructor = F;
-}());
-
-/**
- * Config object: Maintain internal state
- * Later exposed as QUnit.config
- * `config` initialized at top of scope
- */
-config = {
- // The queue of tests to run
- queue: [],
-
- // block until document ready
- blocking: true,
-
- // when enabled, show only failing tests
- // gets persisted through sessionStorage and can be changed in UI via checkbox
- hidepassed: false,
-
- // by default, run previously failed tests first
- // very useful in combination with "Hide passed tests" checked
- reorder: true,
-
- // by default, modify document.title when suite is done
- altertitle: true,
-
- // when enabled, all tests must call expect()
- requireExpects: false,
-
- // add checkboxes that are persisted in the query-string
- // when enabled, the id is set to `true` as a `QUnit.config` property
- urlConfig: [
- {
- id: "noglobals",
- label: "Check for Globals",
- tooltip: "Enabling this will test if any test introduces new properties on the `window` object. Stored as query-strings."
- },
- {
- id: "notrycatch",
- label: "No try-catch",
- tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging exceptions in IE reasonable. Stored as query-strings."
- }
- ],
-
- // Set of all modules.
- modules: {},
-
- // logging callback queues
- begin: [],
- done: [],
- log: [],
- testStart: [],
- testDone: [],
- moduleStart: [],
- moduleDone: []
-};
-
-// Export global variables, unless an 'exports' object exists,
-// in that case we assume we're in CommonJS (dealt with on the bottom of the script)
-if ( typeof exports === "undefined" ) {
- extend( window, QUnit );
-
- // Expose QUnit object
- window.QUnit = QUnit;
-}
-
-// Initialize more QUnit.config and QUnit.urlParams
-(function() {
- var i,
- location = window.location || { search: "", protocol: "file:" },
- params = location.search.slice( 1 ).split( "&" ),
- length = params.length,
- urlParams = {},
- current;
-
- if ( params[ 0 ] ) {
- for ( i = 0; i < length; i++ ) {
- current = params[ i ].split( "=" );
- current[ 0 ] = decodeURIComponent( current[ 0 ] );
- // allow just a key to turn on a flag, e.g., test.html?noglobals
- current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true;
- urlParams[ current[ 0 ] ] = current[ 1 ];
- }
- }
-
- QUnit.urlParams = urlParams;
-
- // String search anywhere in moduleName+testName
- config.filter = urlParams.filter;
-
- // Exact match of the module name
- config.module = urlParams.module;
-
- config.testNumber = parseInt( urlParams.testNumber, 10 ) || null;
-
- // Figure out if we're running the tests from a server or not
- QUnit.isLocal = location.protocol === "file:";
-}());
-
-// Extend QUnit object,
-// these after set here because they should not be exposed as global functions
-extend( QUnit, {
- assert: assert,
-
- config: config,
-
- // Initialize the configuration options
- init: function() {
- extend( config, {
- stats: { all: 0, bad: 0 },
- moduleStats: { all: 0, bad: 0 },
- started: +new Date(),
- updateRate: 1000,
- blocking: false,
- autostart: true,
- autorun: false,
- filter: "",
- queue: [],
- semaphore: 1
- });
-
- var tests, banner, result,
- qunit = id( "qunit" );
-
- if ( qunit ) {
- qunit.innerHTML =
- "" +
- "" +
- "" +
- "" +
- "
";
- }
-
- tests = id( "qunit-tests" );
- banner = id( "qunit-banner" );
- result = id( "qunit-testresult" );
-
- if ( tests ) {
- tests.innerHTML = "";
- }
-
- if ( banner ) {
- banner.className = "";
- }
-
- if ( result ) {
- result.parentNode.removeChild( result );
- }
-
- if ( tests ) {
- result = document.createElement( "p" );
- result.id = "qunit-testresult";
- result.className = "result";
- tests.parentNode.insertBefore( result, tests );
- result.innerHTML = "Running...
";
- }
- },
-
- // Resets the test setup. Useful for tests that modify the DOM.
- reset: function() {
- var fixture = id( "qunit-fixture" );
- if ( fixture ) {
- fixture.innerHTML = config.fixture;
- }
- },
-
- // Trigger an event on an element.
- // @example triggerEvent( document.body, "click" );
- triggerEvent: function( elem, type, event ) {
- if ( document.createEvent ) {
- event = document.createEvent( "MouseEvents" );
- event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView,
- 0, 0, 0, 0, 0, false, false, false, false, 0, null);
-
- elem.dispatchEvent( event );
- } else if ( elem.fireEvent ) {
- elem.fireEvent( "on" + type );
- }
- },
-
- // Safe object type checking
- is: function( type, obj ) {
- return QUnit.objectType( obj ) === type;
- },
-
- objectType: function( obj ) {
- if ( typeof obj === "undefined" ) {
- return "undefined";
- // consider: typeof null === object
- }
- if ( obj === null ) {
- return "null";
- }
-
- var match = toString.call( obj ).match(/^\[object\s(.*)\]$/),
- type = match && match[1] || "";
-
- switch ( type ) {
- case "Number":
- if ( isNaN(obj) ) {
- return "nan";
- }
- return "number";
- case "String":
- case "Boolean":
- case "Array":
- case "Date":
- case "RegExp":
- case "Function":
- return type.toLowerCase();
- }
- if ( typeof obj === "object" ) {
- return "object";
- }
- return undefined;
- },
-
- push: function( result, actual, expected, message ) {
- if ( !config.current ) {
- throw new Error( "assertion outside test context, was " + sourceFromStacktrace() );
- }
-
- var output, source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: message,
- actual: actual,
- expected: expected
- };
-
- message = escapeText( message ) || ( result ? "okay" : "failed" );
- message = "" + message + "";
- output = message;
-
- if ( !result ) {
- expected = escapeText( QUnit.jsDump.parse(expected) );
- actual = escapeText( QUnit.jsDump.parse(actual) );
- output += "Expected: | " + expected + " |
";
-
- if ( actual !== expected ) {
- output += "Result: | " + actual + " |
";
- output += "Diff: | " + QUnit.diff( expected, actual ) + " |
";
- }
-
- source = sourceFromStacktrace();
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
- }
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: !!result,
- message: output
- });
- },
-
- pushFailure: function( message, source, actual ) {
- if ( !config.current ) {
- throw new Error( "pushFailure() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
-
- var output,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: false,
- message: message
- };
-
- message = escapeText( message ) || "error";
- message = "" + message + "";
- output = message;
-
- output += "";
-
- if ( actual ) {
- output += "Result: | " + escapeText( actual ) + " |
";
- }
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: false,
- message: output
- });
- },
-
- url: function( params ) {
- params = extend( extend( {}, QUnit.urlParams ), params );
- var key,
- querystring = "?";
-
- for ( key in params ) {
- if ( !hasOwn.call( params, key ) ) {
- continue;
- }
- querystring += encodeURIComponent( key ) + "=" +
- encodeURIComponent( params[ key ] ) + "&";
- }
- return window.location.protocol + "//" + window.location.host +
- window.location.pathname + querystring.slice( 0, -1 );
- },
-
- extend: extend,
- id: id,
- addEvent: addEvent
- // load, equiv, jsDump, diff: Attached later
-});
-
-/**
- * @deprecated: Created for backwards compatibility with test runner that set the hook function
- * into QUnit.{hook}, instead of invoking it and passing the hook function.
- * QUnit.constructor is set to the empty F() above so that we can add to it's prototype here.
- * Doing this allows us to tell if the following methods have been overwritten on the actual
- * QUnit object.
- */
-extend( QUnit.constructor.prototype, {
-
- // Logging callbacks; all receive a single argument with the listed properties
- // run test/logs.html for any related changes
- begin: registerLoggingCallback( "begin" ),
-
- // done: { failed, passed, total, runtime }
- done: registerLoggingCallback( "done" ),
-
- // log: { result, actual, expected, message }
- log: registerLoggingCallback( "log" ),
-
- // testStart: { name }
- testStart: registerLoggingCallback( "testStart" ),
-
- // testDone: { name, failed, passed, total, duration }
- testDone: registerLoggingCallback( "testDone" ),
-
- // moduleStart: { name }
- moduleStart: registerLoggingCallback( "moduleStart" ),
-
- // moduleDone: { name, failed, passed, total }
- moduleDone: registerLoggingCallback( "moduleDone" )
-});
-
-if ( typeof document === "undefined" || document.readyState === "complete" ) {
- config.autorun = true;
-}
-
-QUnit.load = function() {
- runLoggingCallbacks( "begin", QUnit, {} );
-
- // Initialize the config, saving the execution queue
- var banner, filter, i, label, len, main, ol, toolbar, userAgent, val,
- urlConfigCheckboxesContainer, urlConfigCheckboxes, moduleFilter,
- numModules = 0,
- moduleFilterHtml = "",
- urlConfigHtml = "",
- oldconfig = extend( {}, config );
-
- QUnit.init();
- extend(config, oldconfig);
-
- config.blocking = false;
-
- len = config.urlConfig.length;
-
- for ( i = 0; i < len; i++ ) {
- val = config.urlConfig[i];
- if ( typeof val === "string" ) {
- val = {
- id: val,
- label: val,
- tooltip: "[no tooltip available]"
- };
- }
- config[ val.id ] = QUnit.urlParams[ val.id ];
- urlConfigHtml += "";
- }
-
- moduleFilterHtml += "";
-
- // `userAgent` initialized at top of scope
- userAgent = id( "qunit-userAgent" );
- if ( userAgent ) {
- userAgent.innerHTML = navigator.userAgent;
- }
-
- // `banner` initialized at top of scope
- banner = id( "qunit-header" );
- if ( banner ) {
- banner.innerHTML = "" + banner.innerHTML + " ";
- }
-
- // `toolbar` initialized at top of scope
- toolbar = id( "qunit-testrunner-toolbar" );
- if ( toolbar ) {
- // `filter` initialized at top of scope
- filter = document.createElement( "input" );
- filter.type = "checkbox";
- filter.id = "qunit-filter-pass";
-
- addEvent( filter, "click", function() {
- var tmp,
- ol = document.getElementById( "qunit-tests" );
-
- if ( filter.checked ) {
- ol.className = ol.className + " hidepass";
- } else {
- tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " ";
- ol.className = tmp.replace( / hidepass /, " " );
- }
- if ( defined.sessionStorage ) {
- if (filter.checked) {
- sessionStorage.setItem( "qunit-filter-passed-tests", "true" );
- } else {
- sessionStorage.removeItem( "qunit-filter-passed-tests" );
- }
- }
- });
-
- if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem( "qunit-filter-passed-tests" ) ) {
- filter.checked = true;
- // `ol` initialized at top of scope
- ol = document.getElementById( "qunit-tests" );
- ol.className = ol.className + " hidepass";
- }
- toolbar.appendChild( filter );
-
- // `label` initialized at top of scope
- label = document.createElement( "label" );
- label.setAttribute( "for", "qunit-filter-pass" );
- label.setAttribute( "title", "Only show tests and assertons that fail. Stored in sessionStorage." );
- label.innerHTML = "Hide passed tests";
- toolbar.appendChild( label );
-
- urlConfigCheckboxesContainer = document.createElement("span");
- urlConfigCheckboxesContainer.innerHTML = urlConfigHtml;
- urlConfigCheckboxes = urlConfigCheckboxesContainer.getElementsByTagName("input");
- // For oldIE support:
- // * Add handlers to the individual elements instead of the container
- // * Use "click" instead of "change"
- // * Fallback from event.target to event.srcElement
- addEvents( urlConfigCheckboxes, "click", function( event ) {
- var params = {},
- target = event.target || event.srcElement;
- params[ target.name ] = target.checked ? true : undefined;
- window.location = QUnit.url( params );
- });
- toolbar.appendChild( urlConfigCheckboxesContainer );
-
- if (numModules > 1) {
- moduleFilter = document.createElement( 'span' );
- moduleFilter.setAttribute( 'id', 'qunit-modulefilter-container' );
- moduleFilter.innerHTML = moduleFilterHtml;
- addEvent( moduleFilter.lastChild, "change", function() {
- var selectBox = moduleFilter.getElementsByTagName("select")[0],
- selectedModule = decodeURIComponent(selectBox.options[selectBox.selectedIndex].value);
-
- window.location = QUnit.url( { module: ( selectedModule === "" ) ? undefined : selectedModule } );
- });
- toolbar.appendChild(moduleFilter);
- }
- }
-
- // `main` initialized at top of scope
- main = id( "qunit-fixture" );
- if ( main ) {
- config.fixture = main.innerHTML;
- }
-
- if ( config.autostart ) {
- QUnit.start();
- }
-};
-
-addEvent( window, "load", QUnit.load );
-
-// `onErrorFnPrev` initialized at top of scope
-// Preserve other handlers
-onErrorFnPrev = window.onerror;
-
-// Cover uncaught exceptions
-// Returning true will surpress the default browser handler,
-// returning false will let it run.
-window.onerror = function ( error, filePath, linerNr ) {
- var ret = false;
- if ( onErrorFnPrev ) {
- ret = onErrorFnPrev( error, filePath, linerNr );
- }
-
- // Treat return value as window.onerror itself does,
- // Only do our handling if not surpressed.
- if ( ret !== true ) {
- if ( QUnit.config.current ) {
- if ( QUnit.config.current.ignoreGlobalErrors ) {
- return true;
- }
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- } else {
- QUnit.test( "global failure", extend( function() {
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- }, { validTest: validTest } ) );
- }
- return false;
- }
-
- return ret;
-};
-
-function done() {
- config.autorun = true;
-
- // Log the last module results
- if ( config.currentModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.currentModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
-
- var i, key,
- banner = id( "qunit-banner" ),
- tests = id( "qunit-tests" ),
- runtime = +new Date() - config.started,
- passed = config.stats.all - config.stats.bad,
- html = [
- "Tests completed in ",
- runtime,
- " milliseconds.
",
- "",
- passed,
- " assertions of ",
- config.stats.all,
- " passed, ",
- config.stats.bad,
- " failed."
- ].join( "" );
-
- if ( banner ) {
- banner.className = ( config.stats.bad ? "qunit-fail" : "qunit-pass" );
- }
-
- if ( tests ) {
- id( "qunit-testresult" ).innerHTML = html;
- }
-
- if ( config.altertitle && typeof document !== "undefined" && document.title ) {
- // show ✖ for good, ✔ for bad suite result in title
- // use escape sequences in case file gets loaded with non-utf-8-charset
- document.title = [
- ( config.stats.bad ? "\u2716" : "\u2714" ),
- document.title.replace( /^[\u2714\u2716] /i, "" )
- ].join( " " );
- }
-
- // clear own sessionStorage items if all tests passed
- if ( config.reorder && defined.sessionStorage && config.stats.bad === 0 ) {
- // `key` & `i` initialized at top of scope
- for ( i = 0; i < sessionStorage.length; i++ ) {
- key = sessionStorage.key( i++ );
- if ( key.indexOf( "qunit-test-" ) === 0 ) {
- sessionStorage.removeItem( key );
- }
- }
- }
-
- // scroll back to top to show results
- if ( window.scrollTo ) {
- window.scrollTo(0, 0);
- }
-
- runLoggingCallbacks( "done", QUnit, {
- failed: config.stats.bad,
- passed: passed,
- total: config.stats.all,
- runtime: runtime
- });
-}
-
-/** @return Boolean: true if this test should be ran */
-function validTest( test ) {
- var include,
- filter = config.filter && config.filter.toLowerCase(),
- module = config.module && config.module.toLowerCase(),
- fullName = (test.module + ": " + test.testName).toLowerCase();
-
- // Internally-generated tests are always valid
- if ( test.callback && test.callback.validTest === validTest ) {
- delete test.callback.validTest;
- return true;
- }
-
- if ( config.testNumber ) {
- return test.testNumber === config.testNumber;
- }
-
- if ( module && ( !test.module || test.module.toLowerCase() !== module ) ) {
- return false;
- }
-
- if ( !filter ) {
- return true;
- }
-
- include = filter.charAt( 0 ) !== "!";
- if ( !include ) {
- filter = filter.slice( 1 );
- }
-
- // If the filter matches, we need to honour include
- if ( fullName.indexOf( filter ) !== -1 ) {
- return include;
- }
-
- // Otherwise, do the opposite
- return !include;
-}
-
-// so far supports only Firefox, Chrome and Opera (buggy), Safari (for real exceptions)
-// Later Safari and IE10 are supposed to support error.stack as well
-// See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack
-function extractStacktrace( e, offset ) {
- offset = offset === undefined ? 3 : offset;
-
- var stack, include, i;
-
- if ( e.stacktrace ) {
- // Opera
- return e.stacktrace.split( "\n" )[ offset + 3 ];
- } else if ( e.stack ) {
- // Firefox, Chrome
- stack = e.stack.split( "\n" );
- if (/^error$/i.test( stack[0] ) ) {
- stack.shift();
- }
- if ( fileName ) {
- include = [];
- for ( i = offset; i < stack.length; i++ ) {
- if ( stack[ i ].indexOf( fileName ) !== -1 ) {
- break;
- }
- include.push( stack[ i ] );
- }
- if ( include.length ) {
- return include.join( "\n" );
- }
- }
- return stack[ offset ];
- } else if ( e.sourceURL ) {
- // Safari, PhantomJS
- // hopefully one day Safari provides actual stacktraces
- // exclude useless self-reference for generated Error objects
- if ( /qunit.js$/.test( e.sourceURL ) ) {
- return;
- }
- // for actual exceptions, this is useful
- return e.sourceURL + ":" + e.line;
- }
-}
-function sourceFromStacktrace( offset ) {
- try {
- throw new Error();
- } catch ( e ) {
- return extractStacktrace( e, offset );
- }
-}
-
-/**
- * Escape text for attribute or text content.
- */
-function escapeText( s ) {
- if ( !s ) {
- return "";
- }
- s = s + "";
- // Both single quotes and double quotes (for attributes)
- return s.replace( /['"<>&]/g, function( s ) {
- switch( s ) {
- case '\'':
- return ''';
- case '"':
- return '"';
- case '<':
- return '<';
- case '>':
- return '>';
- case '&':
- return '&';
- }
- });
-}
-
-function synchronize( callback, last ) {
- config.queue.push( callback );
-
- if ( config.autorun && !config.blocking ) {
- process( last );
- }
-}
-
-function process( last ) {
- function next() {
- process( last );
- }
- var start = new Date().getTime();
- config.depth = config.depth ? config.depth + 1 : 1;
-
- while ( config.queue.length && !config.blocking ) {
- if ( !defined.setTimeout || config.updateRate <= 0 || ( ( new Date().getTime() - start ) < config.updateRate ) ) {
- config.queue.shift()();
- } else {
- window.setTimeout( next, 13 );
- break;
- }
- }
- config.depth--;
- if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) {
- done();
- }
-}
-
-function saveGlobal() {
- config.pollution = [];
-
- if ( config.noglobals ) {
- for ( var key in window ) {
- // in Opera sometimes DOM element ids show up here, ignore them
- if ( !hasOwn.call( window, key ) || /^qunit-test-output/.test( key ) ) {
- continue;
- }
- config.pollution.push( key );
- }
- }
-}
-
-function checkPollution() {
- var newGlobals,
- deletedGlobals,
- old = config.pollution;
-
- saveGlobal();
-
- newGlobals = diff( config.pollution, old );
- if ( newGlobals.length > 0 ) {
- QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join(", ") );
- }
-
- deletedGlobals = diff( old, config.pollution );
- if ( deletedGlobals.length > 0 ) {
- QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join(", ") );
- }
-}
-
-// returns a new Array with the elements that are in a but not in b
-function diff( a, b ) {
- var i, j,
- result = a.slice();
-
- for ( i = 0; i < result.length; i++ ) {
- for ( j = 0; j < b.length; j++ ) {
- if ( result[i] === b[j] ) {
- result.splice( i, 1 );
- i--;
- break;
- }
- }
- }
- return result;
-}
-
-function extend( a, b ) {
- for ( var prop in b ) {
- if ( b[ prop ] === undefined ) {
- delete a[ prop ];
-
- // Avoid "Member not found" error in IE8 caused by setting window.constructor
- } else if ( prop !== "constructor" || a !== window ) {
- a[ prop ] = b[ prop ];
- }
- }
-
- return a;
-}
-
-/**
- * @param {HTMLElement} elem
- * @param {string} type
- * @param {Function} fn
- */
-function addEvent( elem, type, fn ) {
- // Standards-based browsers
- if ( elem.addEventListener ) {
- elem.addEventListener( type, fn, false );
- // IE
- } else {
- elem.attachEvent( "on" + type, fn );
- }
-}
-
-/**
- * @param {Array|NodeList} elems
- * @param {string} type
- * @param {Function} fn
- */
-function addEvents( elems, type, fn ) {
- var i = elems.length;
- while ( i-- ) {
- addEvent( elems[i], type, fn );
- }
-}
-
-function hasClass( elem, name ) {
- return (" " + elem.className + " ").indexOf(" " + name + " ") > -1;
-}
-
-function addClass( elem, name ) {
- if ( !hasClass( elem, name ) ) {
- elem.className += (elem.className ? " " : "") + name;
- }
-}
-
-function removeClass( elem, name ) {
- var set = " " + elem.className + " ";
- // Class name may appear multiple times
- while ( set.indexOf(" " + name + " ") > -1 ) {
- set = set.replace(" " + name + " " , " ");
- }
- // If possible, trim it for prettiness, but not neccecarily
- elem.className = window.jQuery ? jQuery.trim( set ) : ( set.trim ? set.trim() : set );
-}
-
-function id( name ) {
- return !!( typeof document !== "undefined" && document && document.getElementById ) &&
- document.getElementById( name );
-}
-
-function registerLoggingCallback( key ) {
- return function( callback ) {
- config[key].push( callback );
- };
-}
-
-// Supports deprecated method of completely overwriting logging callbacks
-function runLoggingCallbacks( key, scope, args ) {
- var i, callbacks;
- if ( QUnit.hasOwnProperty( key ) ) {
- QUnit[ key ].call(scope, args );
- } else {
- callbacks = config[ key ];
- for ( i = 0; i < callbacks.length; i++ ) {
- callbacks[ i ].call( scope, args );
- }
- }
-}
-
-// Test for equality any JavaScript type.
-// Author: Philippe Rathé
-QUnit.equiv = (function() {
-
- // Call the o related callback with the given arguments.
- function bindCallbacks( o, callbacks, args ) {
- var prop = QUnit.objectType( o );
- if ( prop ) {
- if ( QUnit.objectType( callbacks[ prop ] ) === "function" ) {
- return callbacks[ prop ].apply( callbacks, args );
- } else {
- return callbacks[ prop ]; // or undefined
- }
- }
- }
-
- // the real equiv function
- var innerEquiv,
- // stack to decide between skip/abort functions
- callers = [],
- // stack to avoiding loops from circular referencing
- parents = [],
-
- getProto = Object.getPrototypeOf || function ( obj ) {
- return obj.__proto__;
- },
- callbacks = (function () {
-
- // for string, boolean, number and null
- function useStrictEquality( b, a ) {
- /*jshint eqeqeq:false */
- if ( b instanceof a.constructor || a instanceof b.constructor ) {
- // to catch short annotaion VS 'new' annotation of a
- // declaration
- // e.g. var i = 1;
- // var j = new Number(1);
- return a == b;
- } else {
- return a === b;
- }
- }
-
- return {
- "string": useStrictEquality,
- "boolean": useStrictEquality,
- "number": useStrictEquality,
- "null": useStrictEquality,
- "undefined": useStrictEquality,
-
- "nan": function( b ) {
- return isNaN( b );
- },
-
- "date": function( b, a ) {
- return QUnit.objectType( b ) === "date" && a.valueOf() === b.valueOf();
- },
-
- "regexp": function( b, a ) {
- return QUnit.objectType( b ) === "regexp" &&
- // the regex itself
- a.source === b.source &&
- // and its modifers
- a.global === b.global &&
- // (gmi) ...
- a.ignoreCase === b.ignoreCase &&
- a.multiline === b.multiline &&
- a.sticky === b.sticky;
- },
-
- // - skip when the property is a method of an instance (OOP)
- // - abort otherwise,
- // initial === would have catch identical references anyway
- "function": function() {
- var caller = callers[callers.length - 1];
- return caller !== Object && typeof caller !== "undefined";
- },
-
- "array": function( b, a ) {
- var i, j, len, loop;
-
- // b could be an object literal here
- if ( QUnit.objectType( b ) !== "array" ) {
- return false;
- }
-
- len = a.length;
- if ( len !== b.length ) {
- // safe and faster
- return false;
- }
-
- // track reference to avoid circular references
- parents.push( a );
- for ( i = 0; i < len; i++ ) {
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- loop = true;// dont rewalk array
- }
- }
- if ( !loop && !innerEquiv(a[i], b[i]) ) {
- parents.pop();
- return false;
- }
- }
- parents.pop();
- return true;
- },
-
- "object": function( b, a ) {
- var i, j, loop,
- // Default to true
- eq = true,
- aProperties = [],
- bProperties = [];
-
- // comparing constructors is more strict than using
- // instanceof
- if ( a.constructor !== b.constructor ) {
- // Allow objects with no prototype to be equivalent to
- // objects with Object as their constructor.
- if ( !(( getProto(a) === null && getProto(b) === Object.prototype ) ||
- ( getProto(b) === null && getProto(a) === Object.prototype ) ) ) {
- return false;
- }
- }
-
- // stack constructor before traversing properties
- callers.push( a.constructor );
- // track reference to avoid circular references
- parents.push( a );
-
- for ( i in a ) { // be strict: don't ensures hasOwnProperty
- // and go deep
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- // don't go down the same path twice
- loop = true;
- }
- }
- aProperties.push(i); // collect a's properties
-
- if (!loop && !innerEquiv( a[i], b[i] ) ) {
- eq = false;
- break;
- }
- }
-
- callers.pop(); // unstack, we are done
- parents.pop();
-
- for ( i in b ) {
- bProperties.push( i ); // collect b's properties
- }
-
- // Ensures identical properties name
- return eq && innerEquiv( aProperties.sort(), bProperties.sort() );
- }
- };
- }());
-
- innerEquiv = function() { // can take multiple arguments
- var args = [].slice.apply( arguments );
- if ( args.length < 2 ) {
- return true; // end transition
- }
-
- return (function( a, b ) {
- if ( a === b ) {
- return true; // catch the most you can
- } else if ( a === null || b === null || typeof a === "undefined" ||
- typeof b === "undefined" ||
- QUnit.objectType(a) !== QUnit.objectType(b) ) {
- return false; // don't lose time with error prone cases
- } else {
- return bindCallbacks(a, callbacks, [ b, a ]);
- }
-
- // apply transition with (1..n) arguments
- }( args[0], args[1] ) && arguments.callee.apply( this, args.splice(1, args.length - 1 )) );
- };
-
- return innerEquiv;
-}());
-
-/**
- * jsDump Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com |
- * http://flesler.blogspot.com Licensed under BSD
- * (http://www.opensource.org/licenses/bsd-license.php) Date: 5/15/2008
- *
- * @projectDescription Advanced and extensible data dumping for Javascript.
- * @version 1.0.0
- * @author Ariel Flesler
- * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html}
- */
-QUnit.jsDump = (function() {
- function quote( str ) {
- return '"' + str.toString().replace( /"/g, '\\"' ) + '"';
- }
- function literal( o ) {
- return o + "";
- }
- function join( pre, arr, post ) {
- var s = jsDump.separator(),
- base = jsDump.indent(),
- inner = jsDump.indent(1);
- if ( arr.join ) {
- arr = arr.join( "," + s + inner );
- }
- if ( !arr ) {
- return pre + post;
- }
- return [ pre, inner + arr, base + post ].join(s);
- }
- function array( arr, stack ) {
- var i = arr.length, ret = new Array(i);
- this.up();
- while ( i-- ) {
- ret[i] = this.parse( arr[i] , undefined , stack);
- }
- this.down();
- return join( "[", ret, "]" );
- }
-
- var reName = /^function (\w+)/,
- jsDump = {
- // type is used mostly internally, you can fix a (custom)type in advance
- parse: function( obj, type, stack ) {
- stack = stack || [ ];
- var inStack, res,
- parser = this.parsers[ type || this.typeOf(obj) ];
-
- type = typeof parser;
- inStack = inArray( obj, stack );
-
- if ( inStack !== -1 ) {
- return "recursion(" + (inStack - stack.length) + ")";
- }
- if ( type === "function" ) {
- stack.push( obj );
- res = parser.call( this, obj, stack );
- stack.pop();
- return res;
- }
- return ( type === "string" ) ? parser : this.parsers.error;
- },
- typeOf: function( obj ) {
- var type;
- if ( obj === null ) {
- type = "null";
- } else if ( typeof obj === "undefined" ) {
- type = "undefined";
- } else if ( QUnit.is( "regexp", obj) ) {
- type = "regexp";
- } else if ( QUnit.is( "date", obj) ) {
- type = "date";
- } else if ( QUnit.is( "function", obj) ) {
- type = "function";
- } else if ( typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined" ) {
- type = "window";
- } else if ( obj.nodeType === 9 ) {
- type = "document";
- } else if ( obj.nodeType ) {
- type = "node";
- } else if (
- // native arrays
- toString.call( obj ) === "[object Array]" ||
- // NodeList objects
- ( typeof obj.length === "number" && typeof obj.item !== "undefined" && ( obj.length ? obj.item(0) === obj[0] : ( obj.item( 0 ) === null && typeof obj[0] === "undefined" ) ) )
- ) {
- type = "array";
- } else if ( obj.constructor === Error.prototype.constructor ) {
- type = "error";
- } else {
- type = typeof obj;
- }
- return type;
- },
- separator: function() {
- return this.multiline ? this.HTML ? "
" : "\n" : this.HTML ? " " : " ";
- },
- // extra can be a number, shortcut for increasing-calling-decreasing
- indent: function( extra ) {
- if ( !this.multiline ) {
- return "";
- }
- var chr = this.indentChar;
- if ( this.HTML ) {
- chr = chr.replace( /\t/g, " " ).replace( / /g, " " );
- }
- return new Array( this._depth_ + (extra||0) ).join(chr);
- },
- up: function( a ) {
- this._depth_ += a || 1;
- },
- down: function( a ) {
- this._depth_ -= a || 1;
- },
- setParser: function( name, parser ) {
- this.parsers[name] = parser;
- },
- // The next 3 are exposed so you can use them
- quote: quote,
- literal: literal,
- join: join,
- //
- _depth_: 1,
- // This is the list of parsers, to modify them, use jsDump.setParser
- parsers: {
- window: "[Window]",
- document: "[Document]",
- error: function(error) {
- return "Error(\"" + error.message + "\")";
- },
- unknown: "[Unknown]",
- "null": "null",
- "undefined": "undefined",
- "function": function( fn ) {
- var ret = "function",
- // functions never have name in IE
- name = "name" in fn ? fn.name : (reName.exec(fn) || [])[1];
-
- if ( name ) {
- ret += " " + name;
- }
- ret += "( ";
-
- ret = [ ret, QUnit.jsDump.parse( fn, "functionArgs" ), "){" ].join( "" );
- return join( ret, QUnit.jsDump.parse(fn,"functionCode" ), "}" );
- },
- array: array,
- nodelist: array,
- "arguments": array,
- object: function( map, stack ) {
- var ret = [ ], keys, key, val, i;
- QUnit.jsDump.up();
- keys = [];
- for ( key in map ) {
- keys.push( key );
- }
- keys.sort();
- for ( i = 0; i < keys.length; i++ ) {
- key = keys[ i ];
- val = map[ key ];
- ret.push( QUnit.jsDump.parse( key, "key" ) + ": " + QUnit.jsDump.parse( val, undefined, stack ) );
- }
- QUnit.jsDump.down();
- return join( "{", ret, "}" );
- },
- node: function( node ) {
- var len, i, val,
- open = QUnit.jsDump.HTML ? "<" : "<",
- close = QUnit.jsDump.HTML ? ">" : ">",
- tag = node.nodeName.toLowerCase(),
- ret = open + tag,
- attrs = node.attributes;
-
- if ( attrs ) {
- for ( i = 0, len = attrs.length; i < len; i++ ) {
- val = attrs[i].nodeValue;
- // IE6 includes all attributes in .attributes, even ones not explicitly set.
- // Those have values like undefined, null, 0, false, "" or "inherit".
- if ( val && val !== "inherit" ) {
- ret += " " + attrs[i].nodeName + "=" + QUnit.jsDump.parse( val, "attribute" );
- }
- }
- }
- ret += close;
-
- // Show content of TextNode or CDATASection
- if ( node.nodeType === 3 || node.nodeType === 4 ) {
- ret += node.nodeValue;
- }
-
- return ret + open + "/" + tag + close;
- },
- // function calls it internally, it's the arguments part of the function
- functionArgs: function( fn ) {
- var args,
- l = fn.length;
-
- if ( !l ) {
- return "";
- }
-
- args = new Array(l);
- while ( l-- ) {
- // 97 is 'a'
- args[l] = String.fromCharCode(97+l);
- }
- return " " + args.join( ", " ) + " ";
- },
- // object calls it internally, the key part of an item in a map
- key: quote,
- // function calls it internally, it's the content of the function
- functionCode: "[code]",
- // node calls it internally, it's an html attribute value
- attribute: quote,
- string: quote,
- date: quote,
- regexp: literal,
- number: literal,
- "boolean": literal
- },
- // if true, entities are escaped ( <, >, \t, space and \n )
- HTML: false,
- // indentation unit
- indentChar: " ",
- // if true, items in a collection, are separated by a \n, else just a space.
- multiline: true
- };
-
- return jsDump;
-}());
-
-// from jquery.js
-function inArray( elem, array ) {
- if ( array.indexOf ) {
- return array.indexOf( elem );
- }
-
- for ( var i = 0, length = array.length; i < length; i++ ) {
- if ( array[ i ] === elem ) {
- return i;
- }
- }
-
- return -1;
-}
-
-/*
- * Javascript Diff Algorithm
- * By John Resig (http://ejohn.org/)
- * Modified by Chu Alan "sprite"
- *
- * Released under the MIT license.
- *
- * More Info:
- * http://ejohn.org/projects/javascript-diff-algorithm/
- *
- * Usage: QUnit.diff(expected, actual)
- *
- * QUnit.diff( "the quick brown fox jumped over", "the quick fox jumps over" ) == "the quick brown fox jumped jumps over"
- */
-QUnit.diff = (function() {
- /*jshint eqeqeq:false, eqnull:true */
- function diff( o, n ) {
- var i,
- ns = {},
- os = {};
-
- for ( i = 0; i < n.length; i++ ) {
- if ( !hasOwn.call( ns, n[i] ) ) {
- ns[ n[i] ] = {
- rows: [],
- o: null
- };
- }
- ns[ n[i] ].rows.push( i );
- }
-
- for ( i = 0; i < o.length; i++ ) {
- if ( !hasOwn.call( os, o[i] ) ) {
- os[ o[i] ] = {
- rows: [],
- n: null
- };
- }
- os[ o[i] ].rows.push( i );
- }
-
- for ( i in ns ) {
- if ( !hasOwn.call( ns, i ) ) {
- continue;
- }
- if ( ns[i].rows.length === 1 && hasOwn.call( os, i ) && os[i].rows.length === 1 ) {
- n[ ns[i].rows[0] ] = {
- text: n[ ns[i].rows[0] ],
- row: os[i].rows[0]
- };
- o[ os[i].rows[0] ] = {
- text: o[ os[i].rows[0] ],
- row: ns[i].rows[0]
- };
- }
- }
-
- for ( i = 0; i < n.length - 1; i++ ) {
- if ( n[i].text != null && n[ i + 1 ].text == null && n[i].row + 1 < o.length && o[ n[i].row + 1 ].text == null &&
- n[ i + 1 ] == o[ n[i].row + 1 ] ) {
-
- n[ i + 1 ] = {
- text: n[ i + 1 ],
- row: n[i].row + 1
- };
- o[ n[i].row + 1 ] = {
- text: o[ n[i].row + 1 ],
- row: i + 1
- };
- }
- }
-
- for ( i = n.length - 1; i > 0; i-- ) {
- if ( n[i].text != null && n[ i - 1 ].text == null && n[i].row > 0 && o[ n[i].row - 1 ].text == null &&
- n[ i - 1 ] == o[ n[i].row - 1 ]) {
-
- n[ i - 1 ] = {
- text: n[ i - 1 ],
- row: n[i].row - 1
- };
- o[ n[i].row - 1 ] = {
- text: o[ n[i].row - 1 ],
- row: i - 1
- };
- }
- }
-
- return {
- o: o,
- n: n
- };
- }
-
- return function( o, n ) {
- o = o.replace( /\s+$/, "" );
- n = n.replace( /\s+$/, "" );
-
- var i, pre,
- str = "",
- out = diff( o === "" ? [] : o.split(/\s+/), n === "" ? [] : n.split(/\s+/) ),
- oSpace = o.match(/\s+/g),
- nSpace = n.match(/\s+/g);
-
- if ( oSpace == null ) {
- oSpace = [ " " ];
- }
- else {
- oSpace.push( " " );
- }
-
- if ( nSpace == null ) {
- nSpace = [ " " ];
- }
- else {
- nSpace.push( " " );
- }
-
- if ( out.n.length === 0 ) {
- for ( i = 0; i < out.o.length; i++ ) {
- str += "" + out.o[i] + oSpace[i] + "";
- }
- }
- else {
- if ( out.n[0].text == null ) {
- for ( n = 0; n < out.o.length && out.o[n].text == null; n++ ) {
- str += "" + out.o[n] + oSpace[n] + "";
- }
- }
-
- for ( i = 0; i < out.n.length; i++ ) {
- if (out.n[i].text == null) {
- str += "" + out.n[i] + nSpace[i] + "";
- }
- else {
- // `pre` initialized at top of scope
- pre = "";
-
- for ( n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++ ) {
- pre += "" + out.o[n] + oSpace[n] + "";
- }
- str += " " + out.n[i].text + nSpace[i] + pre;
- }
- }
- }
-
- return str;
- };
-}());
-
-// for CommonJS enviroments, export everything
-if ( typeof exports !== "undefined" ) {
- extend( exports, QUnit );
-}
-
-// get at whatever the global object is, like window in browsers
-}( (function() {return this;}.call()) ));
diff --git a/test/lib/require.js b/test/lib/require.js
deleted file mode 100644
index 987f865..0000000
--- a/test/lib/require.js
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- RequireJS 2.1.5 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.
- Available via the MIT or new BSD license.
- see: http://github.com/jrburke/requirejs for details
-*/
-var requirejs,require,define;
-(function(aa){function I(b){return"[object Function]"===L.call(b)}function J(b){return"[object Array]"===L.call(b)}function y(b,c){if(b){var d;for(d=0;dthis.depCount&&!this.defined){if(I(n)){if(this.events.error)try{e=i.execCb(c,n,b,e)}catch(d){a=d}else e=i.execCb(c,n,b,e);this.map.isDefine&&((b=this.module)&&void 0!==b.exports&&b.exports!==this.exports?e=b.exports:void 0===e&&this.usingExports&&(e=this.exports));if(a)return a.requireMap=this.map,a.requireModules=[this.map.id],a.requireType="define",v(this.error=
-a)}else e=n;this.exports=e;if(this.map.isDefine&&!this.ignore&&(q[c]=e,l.onResourceLoad))l.onResourceLoad(i,this.map,this.depMaps);x(c);this.defined=!0}this.defining=!1;this.defined&&!this.defineEmitted&&(this.defineEmitted=!0,this.emit("defined",this.exports),this.defineEmitComplete=!0)}}else this.fetch()}},callPlugin:function(){var a=this.map,b=a.id,d=j(a.prefix);this.depMaps.push(d);t(d,"defined",u(this,function(e){var n,d;d=this.map.name;var g=this.map.parentMap?this.map.parentMap.name:null,h=
-i.makeRequire(a.parentMap,{enableBuildCallback:!0});if(this.map.unnormalized){if(e.normalize&&(d=e.normalize(d,function(a){return c(a,g,!0)})||""),e=j(a.prefix+"!"+d,this.map.parentMap),t(e,"defined",u(this,function(a){this.init([],function(){return a},null,{enabled:!0,ignore:!0})})),d=m(p,e.id)){this.depMaps.push(e);if(this.events.error)d.on("error",u(this,function(a){this.emit("error",a)}));d.enable()}}else n=u(this,function(a){this.init([],function(){return a},null,{enabled:!0})}),n.error=u(this,
-function(a){this.inited=!0;this.error=a;a.requireModules=[b];G(p,function(a){0===a.map.id.indexOf(b+"_unnormalized")&&x(a.map.id)});v(a)}),n.fromText=u(this,function(e,c){var d=a.name,g=j(d),C=O;c&&(e=c);C&&(O=!1);r(g);s(k.config,b)&&(k.config[d]=k.config[b]);try{l.exec(e)}catch(ca){return v(B("fromtexteval","fromText eval for "+b+" failed: "+ca,ca,[b]))}C&&(O=!0);this.depMaps.push(g);i.completeLoad(d);h([d],n)}),e.load(a.name,h,n,k)}));i.enable(d,this);this.pluginMaps[d.id]=d},enable:function(){V[this.map.id]=
-this;this.enabling=this.enabled=!0;y(this.depMaps,u(this,function(a,b){var c,e;if("string"===typeof a){a=j(a,this.map.isDefine?this.map:this.map.parentMap,!1,!this.skipMap);this.depMaps[b]=a;if(c=m(N,a.id)){this.depExports[b]=c(this);return}this.depCount+=1;t(a,"defined",u(this,function(a){this.defineDep(b,a);this.check()}));this.errback&&t(a,"error",this.errback)}c=a.id;e=p[c];!s(N,c)&&(e&&!e.enabled)&&i.enable(a,this)}));G(this.pluginMaps,u(this,function(a){var b=m(p,a.id);b&&!b.enabled&&i.enable(a,
-this)}));this.enabling=!1;this.check()},on:function(a,b){var c=this.events[a];c||(c=this.events[a]=[]);c.push(b)},emit:function(a,b){y(this.events[a],function(a){a(b)});"error"===a&&delete this.events[a]}};i={config:k,contextName:b,registry:p,defined:q,urlFetched:U,defQueue:H,Module:Z,makeModuleMap:j,nextTick:l.nextTick,onError:v,configure:function(a){a.baseUrl&&"/"!==a.baseUrl.charAt(a.baseUrl.length-1)&&(a.baseUrl+="/");var b=k.pkgs,c=k.shim,e={paths:!0,config:!0,map:!0};G(a,function(a,b){e[b]?
-"map"===b?(k.map||(k.map={}),R(k[b],a,!0,!0)):R(k[b],a,!0):k[b]=a});a.shim&&(G(a.shim,function(a,b){J(a)&&(a={deps:a});if((a.exports||a.init)&&!a.exportsFn)a.exportsFn=i.makeShimExports(a);c[b]=a}),k.shim=c);a.packages&&(y(a.packages,function(a){a="string"===typeof a?{name:a}:a;b[a.name]={name:a.name,location:a.location||a.name,main:(a.main||"main").replace(ja,"").replace(ea,"")}}),k.pkgs=b);G(p,function(a,b){!a.inited&&!a.map.unnormalized&&(a.map=j(b))});if(a.deps||a.callback)i.require(a.deps||[],
-a.callback)},makeShimExports:function(a){return function(){var b;a.init&&(b=a.init.apply(aa,arguments));return b||a.exports&&ba(a.exports)}},makeRequire:function(a,f){function d(e,c,h){var g,k;f.enableBuildCallback&&(c&&I(c))&&(c.__requireJsBuild=!0);if("string"===typeof e){if(I(c))return v(B("requireargs","Invalid require call"),h);if(a&&s(N,e))return N[e](p[a.id]);if(l.get)return l.get(i,e,a,d);g=j(e,a,!1,!0);g=g.id;return!s(q,g)?v(B("notloaded",'Module name "'+g+'" has not been loaded yet for context: '+
-b+(a?"":". Use require([])"))):q[g]}L();i.nextTick(function(){L();k=r(j(null,a));k.skipMap=f.skipMap;k.init(e,c,h,{enabled:!0});D()});return d}f=f||{};R(d,{isBrowser:A,toUrl:function(b){var d,f=b.lastIndexOf("."),g=b.split("/")[0];if(-1!==f&&(!("."===g||".."===g)||1h.attachEvent.toString().indexOf("[native code"))&&!Y?(O=!0,h.attachEvent("onreadystatechange",b.onScriptLoad)):(h.addEventListener("load",b.onScriptLoad,!1),h.addEventListener("error",b.onScriptError,!1)),h.src=d,K=h,D?x.insertBefore(h,D):x.appendChild(h),K=null,h;if(da)try{importScripts(d),b.completeLoad(c)}catch(j){b.onError(B("importscripts","importScripts failed for "+c+" at "+d,j,[c]))}};A&&M(document.getElementsByTagName("script"),function(b){x||(x=
-b.parentNode);if(t=b.getAttribute("data-main"))return r.baseUrl||(E=t.split("/"),Q=E.pop(),fa=E.length?E.join("/")+"/":"./",r.baseUrl=fa,t=Q),t=t.replace(ea,""),r.deps=r.deps?r.deps.concat(t):[t],!0});define=function(b,c,d){var l,h;"string"!==typeof b&&(d=c,c=b,b=null);J(c)||(d=c,c=[]);!c.length&&I(d)&&d.length&&(d.toString().replace(la,"").replace(ma,function(b,d){c.push(d)}),c=(1===d.length?["require"]:["require","exports","module"]).concat(c));if(O){if(!(l=K))P&&"interactive"===P.readyState||M(document.getElementsByTagName("script"),
-function(b){if("interactive"===b.readyState)return P=b}),l=P;l&&(b||(b=l.getAttribute("data-requiremodule")),h=F[l.getAttribute("data-requirecontext")])}(h?h.defQueue:T).push([b,c,d])};define.amd={jQuery:!0};l.exec=function(b){return eval(b)};l(r)}})(this);
diff --git a/test/lib/resemble.js b/test/lib/resemble.js
new file mode 100644
index 0000000..1cb8c29
--- /dev/null
+++ b/test/lib/resemble.js
@@ -0,0 +1,535 @@
+/*
+Author: James Cryer
+Company: Huddle
+Last updated date: 21 Feb 2013
+URL: https://github.com/Huddle/Resemble.js
+*/
+
+(function(_this){
+ 'use strict';
+
+ _this['resemble'] = function( fileData ){
+
+ var data = {};
+ var images = [];
+ var updateCallbackArray = [];
+
+ var tolerance = { // between 0 and 255
+ red: 16,
+ green: 16,
+ blue: 16,
+ minBrightness: 16,
+ maxBrightness: 240
+ };
+
+ var ignoreAntialiasing = false;
+ var ignoreColors = false;
+
+ function triggerDataUpdate(){
+ var len = updateCallbackArray.length;
+ var i;
+ for(i=0;i tolerance.maxBrightness;
+ }
+
+ function getHue(r,g,b){
+
+ r = r / 255;
+ g = g / 255;
+ b = b / 255;
+ var max = Math.max(r, g, b), min = Math.min(r, g, b);
+ var h;
+ var d;
+
+ if (max == min){
+ h = 0; // achromatic
+ } else{
+ d = max - min;
+ switch(max){
+ case r: h = (g - b) / d + (g < b ? 6 : 0); break;
+ case g: h = (b - r) / d + 2; break;
+ case b: h = (r - g) / d + 4; break;
+ }
+ h /= 6;
+ }
+
+ return h;
+ }
+
+ function isAntialiased(sourcePix, data, cacheSet, verticalPos, horizontalPos, width){
+ var offset;
+ var targetPix;
+ var distance = 1;
+ var i;
+ var j;
+ var hasHighContrastSibling = 0;
+ var hasSiblingWithDifferentHue = 0;
+ var hasEquivilantSibling = 0;
+
+ addHueInfo(sourcePix);
+
+ for (i = distance*-1; i <= distance; i++){
+ for (j = distance*-1; j <= distance; j++){
+
+ if(i===0 && j===0){
+ // ignore source pixel
+ } else {
+
+ offset = ((verticalPos+j)*width + (horizontalPos+i)) * 4;
+ targetPix = getPixelInfo(data, offset, cacheSet);
+
+ if(targetPix === null){
+ continue;
+ }
+
+ addBrightnessInfo(targetPix);
+ addHueInfo(targetPix);
+
+ if( isContrasting(sourcePix, targetPix) ){
+ hasHighContrastSibling++;
+ }
+
+ if( isRGBSame(sourcePix,targetPix) ){
+ hasEquivilantSibling++;
+ }
+
+ if( Math.abs(targetPix.h - sourcePix.h) > 0.3 ){
+ hasSiblingWithDifferentHue++;
+ }
+
+ if( hasSiblingWithDifferentHue > 1 || hasHighContrastSibling > 1){
+ return true;
+ }
+ }
+ }
+ }
+
+ if(hasEquivilantSibling < 2){
+ return true;
+ }
+
+ return false;
+ }
+
+ function errorPixel(px, offset){
+ px[offset] = 255; //r
+ px[offset + 1] = 0; //g
+ px[offset + 2] = 255; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyPixel(px, offset, data){
+ px[offset] = data.r; //r
+ px[offset + 1] = data.g; //g
+ px[offset + 2] = data.b; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyGrayScalePixel(px, offset, data){
+ px[offset] = data.brightness; //r
+ px[offset + 1] = data.brightness; //g
+ px[offset + 2] = data.brightness; //b
+ px[offset + 3] = 255; //a
+ }
+
+
+ function getPixelInfo(data, offset, cacheSet){
+ var r;
+ var g;
+ var b;
+ var d;
+
+ if(typeof data[offset] !== 'undefined'){
+ r = data[offset];
+ g = data[offset+1];
+ b = data[offset+2];
+ d = {
+ r: r,
+ g: g,
+ b: b
+ };
+
+ return d;
+ } else {
+ return null;
+ }
+ }
+
+ function addBrightnessInfo(data){
+ data.brightness = getBrightness(data.r,data.g,data.b); // 'corrected' lightness
+ }
+
+ function addHueInfo(data){
+ data.h = getHue(data.r,data.g,data.b);
+ }
+
+ function analyseImages(img1, img2, width, height){
+
+ var hiddenCanvas = document.createElement('canvas');
+
+ var data1 = img1.data;
+ var data2 = img2.data;
+
+ hiddenCanvas.width = width;
+ hiddenCanvas.height = height;
+
+ var context = hiddenCanvas.getContext('2d');
+ var imgd = context.createImageData(width,height);
+ var targetPix = imgd.data;
+
+ var mismatchCount = 0;
+
+ var time = Date.now();
+
+ var skip;
+
+ if( (width > 1200 || height > 1200) && ignoreAntialiasing){
+ skip = 6;
+ }
+
+ loop(height, width, function(verticalPos, horizontalPos){
+
+ if(skip){ // only skip if the image isn't small
+ if(verticalPos % skip === 0 || horizontalPos % skip === 0){
+ return;
+ }
+ }
+
+ var offset = (verticalPos*width + horizontalPos) * 4;
+ var pixel1 = getPixelInfo(data1, offset, 1);
+ var pixel2 = getPixelInfo(data2, offset, 2);
+
+ if(pixel1 === null || pixel2 === null){
+ return;
+ }
+
+ if (ignoreColors){
+
+ addBrightnessInfo(pixel1);
+ addBrightnessInfo(pixel2);
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ return;
+ }
+
+ if( isRGBSimilar(pixel1, pixel2) ){
+ copyPixel(targetPix, offset, pixel2);
+
+ } else if( ignoreAntialiasing && (
+ addBrightnessInfo(pixel1), // jit pixel info augmentation looks a little weird, sorry.
+ addBrightnessInfo(pixel2),
+ isAntialiased(pixel1, data1, 1, verticalPos, horizontalPos, width) ||
+ isAntialiased(pixel2, data2, 2, verticalPos, horizontalPos, width)
+ )){
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+
+ });
+
+ data.misMatchPercentage = (mismatchCount / (height*width) * 100).toFixed(2);
+ data.analysisTime = Date.now() - time;
+
+ data.getImageDataUrl = function(text){
+ var barHeight = 0;
+
+ if(text){
+ barHeight = addLabel(text,context,hiddenCanvas);
+ }
+
+ context.putImageData(imgd, 0, barHeight);
+
+ return hiddenCanvas.toDataURL("image/png");
+ };
+ }
+
+ function addLabel(text, context, hiddenCanvas){
+ var textPadding = 2;
+
+ context.font = '12px sans-serif';
+
+ var textWidth = context.measureText(text).width + textPadding*2;
+ var barHeight = 22;
+
+ if(textWidth > hiddenCanvas.width){
+ hiddenCanvas.width = textWidth;
+ }
+
+ hiddenCanvas.height += barHeight;
+
+ context.fillStyle = "#666";
+ context.fillRect(0,0,hiddenCanvas.width,barHeight -4);
+ context.fillStyle = "#fff";
+ context.fillRect(0,barHeight -4,hiddenCanvas.width, 4);
+
+ context.fillStyle = "#fff";
+ context.textBaseline = "top";
+ context.font = '12px sans-serif';
+ context.fillText(text, textPadding, 1);
+
+ return barHeight;
+ }
+
+ function normalise(img, w, h){
+ var c;
+ var context;
+
+ if(img.height < h || img.width < w){
+ c = document.createElement('canvas');
+ c.width = w;
+ c.height = h;
+ context = c.getContext('2d');
+ context.putImageData(img, 0, 0);
+ return context.getImageData(0, 0, w, h);
+ }
+
+ return img;
+ }
+
+ function compare(one, two){
+
+ function onceWeHaveBoth(){
+ var width;
+ var height;
+ if(images.length === 2){
+ width = images[0].width > images[1].width ? images[0].width : images[1].width;
+ height = images[0].height > images[1].height ? images[0].height : images[1].height;
+
+ if( (images[0].width === images[1].width) && (images[0].height === images[1].height) ){
+ data.isSameDimensions = true;
+ } else {
+ data.isSameDimensions = false;
+ }
+
+ analyseImages( normalise(images[0],width, height), normalise(images[1],width, height), width, height);
+
+ triggerDataUpdate();
+ }
+ }
+
+ images = [];
+ loadImageData(one, onceWeHaveBoth);
+ loadImageData(two, onceWeHaveBoth);
+ }
+
+ function getCompareApi(param){
+
+ var secondFileData,
+ hasMethod = typeof param === 'function';
+
+ if( !hasMethod ){
+ // assume it's file data
+ secondFileData = param;
+ }
+
+ var self = {
+ ignoreNothing: function(){
+
+ tolerance.red = 16;
+ tolerance.green = 16;
+ tolerance.blue = 16;
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreAntialiasing: function(){
+
+ tolerance.red = 32;
+ tolerance.green = 32;
+ tolerance.blue = 32;
+ tolerance.minBrightness = 64;
+ tolerance.maxBrightness = 96;
+
+ ignoreAntialiasing = true;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreColors: function(){
+
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = true;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ onComplete: function( callback ){
+
+ updateCallbackArray.push(callback);
+
+ var wrapper = function(){
+ compare(fileData, secondFileData);
+ };
+
+ wrapper();
+
+ return getCompareApi(wrapper);
+ }
+ };
+
+ return self;
+ }
+
+ return {
+ onComplete: function( callback ){
+ updateCallbackArray.push(callback);
+ loadImageData(fileData, function(imageData, width, height){
+ parseImage(imageData.data, width, height);
+ });
+ },
+ compareTo: function(secondFileData){
+ return getCompareApi(secondFileData);
+ }
+ };
+
+ };
+}(this));
\ No newline at end of file
diff --git a/test/testsuite.js b/test/testsuite.js
deleted file mode 100644
index b486acb..0000000
--- a/test/testsuite.js
+++ /dev/null
@@ -1,36 +0,0 @@
-requirejs.config({
- baseUrl: '/test/unit/'
-});
-
-define(function(require) {
- var testModules = [
- 'Pixi',
- 'Point',
- 'Rectangle',
- 'DisplayObject',
- 'DisplayObjectContainer',
- 'Sprite',
- 'MovieClip',
- 'InteractionManager',
- 'Stage',
- 'utils/Utils',
- 'utils/EventTarget',
- 'utils/Matrix',
- 'utils/Detector',
- 'renderers/WebGLShaders',
- 'renderers/WebGLRenderer',
- 'renderers/WebGLBatch',
- 'renderers/CanvasRenderer',
- 'extras/Strip',
- 'extras/Rope',
- 'textures/BaseTexture',
- 'textures/Texture',
- 'loaders/SpriteSheetLoader',
- 'loaders/AssetLoader'
- ];
-
- // Resolve all testModules and then start the Test Runner.
- require(testModules, function() {
- QUnit.start();
- });
-});
\ No newline at end of file
diff --git a/test/textures/SpriteSheet-Aliens.png b/test/textures/SpriteSheet-Aliens.png
new file mode 100644
index 0000000..210acb1
--- /dev/null
+++ b/test/textures/SpriteSheet-Aliens.png
Binary files differ
diff --git a/test/textures/SpriteSheet-Explosion.png b/test/textures/SpriteSheet-Explosion.png
new file mode 100755
index 0000000..79e1a69
--- /dev/null
+++ b/test/textures/SpriteSheet-Explosion.png
Binary files differ
diff --git a/test/textures/bunny.png b/test/textures/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/textures/bunny.png
Binary files differ
diff --git a/test/unit/DisplayObject.js b/test/unit/DisplayObject.js
deleted file mode 100644
index 5e7e72f..0000000
--- a/test/unit/DisplayObject.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObject');
-});
diff --git a/test/unit/DisplayObjectContainer.js b/test/unit/DisplayObjectContainer.js
deleted file mode 100644
index b323959..0000000
--- a/test/unit/DisplayObjectContainer.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObjectContainer');
-});
diff --git a/test/unit/InteractionManager.js b/test/unit/InteractionManager.js
deleted file mode 100644
index e751f52..0000000
--- a/test/unit/InteractionManager.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('InteractionManager');
-});
diff --git a/test/unit/MovieClip.js b/test/unit/MovieClip.js
deleted file mode 100644
index 37d9446..0000000
--- a/test/unit/MovieClip.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('MovieClip');
-});
diff --git a/test/unit/Pixi.js b/test/unit/Pixi.js
deleted file mode 100644
index 36eee73..0000000
--- a/test/unit/Pixi.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Pixi');
-});
diff --git a/test/unit/Point.js b/test/unit/Point.js
deleted file mode 100644
index 983ff6e..0000000
--- a/test/unit/Point.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Point');
-});
diff --git a/test/unit/Rectangle.js b/test/unit/Rectangle.js
deleted file mode 100644
index 3b439ba..0000000
--- a/test/unit/Rectangle.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Rectangle');
-});
diff --git a/test/unit/Sprite.js b/test/unit/Sprite.js
deleted file mode 100644
index ed4f596..0000000
--- a/test/unit/Sprite.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Sprite');
-});
diff --git a/test/unit/Stage.js b/test/unit/Stage.js
deleted file mode 100644
index 2d70291..0000000
--- a/test/unit/Stage.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Stage');
-});
diff --git a/test/unit/extras/Rope.js b/test/unit/extras/Rope.js
deleted file mode 100644
index 5606f14..0000000
--- a/test/unit/extras/Rope.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Rope');
-});
diff --git a/test/unit/extras/Strip.js b/test/unit/extras/Strip.js
deleted file mode 100644
index 0134d3a..0000000
--- a/test/unit/extras/Strip.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Strip');
-});
diff --git a/test/unit/loaders/AssetLoader.js b/test/unit/loaders/AssetLoader.js
deleted file mode 100644
index 13b8443..0000000
--- a/test/unit/loaders/AssetLoader.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('AssetLoader');
-});
diff --git a/test/unit/loaders/SpriteSheetLoader.js b/test/unit/loaders/SpriteSheetLoader.js
deleted file mode 100644
index 8bf0cb2..0000000
--- a/test/unit/loaders/SpriteSheetLoader.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('SpriteSheetLoader');
-});
diff --git a/test/unit/pixi/InteractionManager.js b/test/unit/pixi/InteractionManager.js
new file mode 100644
index 0000000..ed3001f
--- /dev/null
+++ b/test/unit/pixi/InteractionManager.js
@@ -0,0 +1,10 @@
+describe('pixi/InteractionManager', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var InteractionManager = PIXI.InteractionManager;
+
+ it('Module exists', function () {
+ expect(InteractionManager).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/Pixi.js b/test/unit/pixi/Pixi.js
new file mode 100644
index 0000000..27debc1
--- /dev/null
+++ b/test/unit/pixi/Pixi.js
@@ -0,0 +1,9 @@
+describe('pixi/Pixi', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+
+ it('Module exists', function () {
+ expect(global).to.have.property('PIXI').and.to.be.an('object');
+ });
+});
diff --git a/test/unit/pixi/core/Circle.js b/test/unit/pixi/core/Circle.js
new file mode 100644
index 0000000..93a4456
--- /dev/null
+++ b/test/unit/pixi/core/Circle.js
@@ -0,0 +1,22 @@
+describe('pixi/core/Circle', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Circle = PIXI.Circle;
+
+ it('Module exists', function () {
+ expect(Circle).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Circle();
+
+ expect(obj).to.be.an.instanceof(Circle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', 0);
+ expect(obj).to.have.property('y', 0);
+ expect(obj).to.have.property('radius', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Ellipse.js b/test/unit/pixi/core/Ellipse.js
new file mode 100644
index 0000000..026b56f
--- /dev/null
+++ b/test/unit/pixi/core/Ellipse.js
@@ -0,0 +1,24 @@
+describe('pixi/core/Ellipse', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Ellipse = PIXI.Ellipse;
+
+ it('Module exists', function () {
+ expect(Ellipse).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Ellipse();
+
+ expect(obj).to.be.an.instanceof(Ellipse);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+ expect(obj).to.respondTo('getBounds');
+
+ expect(obj).to.have.property('x', 0);
+ expect(obj).to.have.property('y', 0);
+ expect(obj).to.have.property('width', 0);
+ expect(obj).to.have.property('height', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Matrix.js b/test/unit/pixi/core/Matrix.js
new file mode 100644
index 0000000..b48989e
--- /dev/null
+++ b/test/unit/pixi/core/Matrix.js
@@ -0,0 +1,30 @@
+describe('pixi/core/Matrix', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var mat3 = PIXI.mat3;
+ var mat4 = PIXI.mat4;
+ var Matrix = PIXI.Matrix;
+
+ it('Ensure determineMatrixArrayType works', function () {
+ expect(Matrix).to.be.a('function');
+ });
+
+ it('mat3 exists', function () {
+ expect(mat3).to.be.an('object');
+ });
+
+ it('Confirm new mat3 matrix', function () {
+ var matrix = new mat3.create();
+ pixi_core_Matrix_confirmNewMat3(matrix);
+ });
+
+ it('mat3 exists', function () {
+ expect(mat4).to.be.an('object');
+ });
+
+ it('Confirm new mat4 matrix', function () {
+ var matrix = new mat4.create();
+ pixi_core_Matrix_confirmNewMat4(matrix);
+ });
+});
diff --git a/test/unit/pixi/core/Point.js b/test/unit/pixi/core/Point.js
new file mode 100644
index 0000000..c4d5163
--- /dev/null
+++ b/test/unit/pixi/core/Point.js
@@ -0,0 +1,15 @@
+describe('pixi/core/Point', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Point = PIXI.Point;
+
+ it('Module exists', function () {
+ expect(Point).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Point();
+ pixi_core_Point_confirm(obj, 0, 0);
+ });
+});
diff --git a/test/unit/pixi/core/Polygon.js b/test/unit/pixi/core/Polygon.js
new file mode 100644
index 0000000..dc8c918
--- /dev/null
+++ b/test/unit/pixi/core/Polygon.js
@@ -0,0 +1,20 @@
+describe('pixi/core/Polygon', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Polygon = PIXI.Polygon;
+
+ it('Module exists', function () {
+ expect(Polygon).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Polygon();
+
+ expect(obj).to.be.an.instanceof(Polygon);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.deep.property('points.length', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Rectangle.js b/test/unit/pixi/core/Rectangle.js
new file mode 100644
index 0000000..d43316e
--- /dev/null
+++ b/test/unit/pixi/core/Rectangle.js
@@ -0,0 +1,15 @@
+describe('pixi/core/Rectangle', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Rectangle = PIXI.Rectangle;
+
+ it('Module exists', function () {
+ expect(Rectangle).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var rect = new Rectangle();
+ pixi_core_Rectangle_confirm(rect, 0, 0, 0, 0);
+ });
+});
diff --git a/test/unit/pixi/display/DisplayObject.js b/test/unit/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..40c6fbc
--- /dev/null
+++ b/test/unit/pixi/display/DisplayObject.js
@@ -0,0 +1,21 @@
+describe('pixi/display/DisplayObject', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var DisplayObject = PIXI.DisplayObject;
+
+ it('Module exists', function () {
+ expect(DisplayObject).to.be.a('function');
+ expect(PIXI).to.have.property('visibleCount', 0);
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new DisplayObject();
+
+ pixi_display_DisplayObject_confirmNew(obj);
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', false);
+ expect(obj).to.have.property('stage', null);
+ });
+});
diff --git a/test/unit/pixi/display/DisplayObjectContainer.js b/test/unit/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..ce7f02f
--- /dev/null
+++ b/test/unit/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,20 @@
+describe('pixi/display/DisplayObjectContainer', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var DisplayObjectContainer = PIXI.DisplayObjectContainer;
+
+ it('Module exists', function () {
+ expect(DisplayObjectContainer).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new DisplayObjectContainer();
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', false);
+ expect(obj).to.have.property('stage', null);
+ });
+});
diff --git a/test/unit/pixi/display/MovieClip.js b/test/unit/pixi/display/MovieClip.js
new file mode 100644
index 0000000..f3c6c6a
--- /dev/null
+++ b/test/unit/pixi/display/MovieClip.js
@@ -0,0 +1,33 @@
+describe('pixi/display/MovieClip', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var MovieClip = PIXI.MovieClip;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(MovieClip).to.be.a('function');
+ });
+
+ it('Confirm new instance', function (done) {
+ var texture = Texture.fromImage('/base/test/textures/SpriteSheet-Explosion.png');
+ var obj = new MovieClip([texture]);
+
+ pixi_display_Sprite_confirmNew(obj, done);
+
+ expect(obj).to.be.an.instanceof(MovieClip);
+ expect(obj).to.respondTo('stop');
+ expect(obj).to.respondTo('play');
+ expect(obj).to.respondTo('gotoAndStop');
+ expect(obj).to.respondTo('gotoAndPlay');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('textures.length', 1);
+ expect(obj).to.have.deep.property('textures[0]', texture);
+ expect(obj).to.have.property('animationSpeed', 1);
+ expect(obj).to.have.property('loop', true);
+ expect(obj).to.have.property('onComplete', null);
+ expect(obj).to.have.property('currentFrame', 0);
+ expect(obj).to.have.property('playing', false);
+ });
+});
diff --git a/test/unit/pixi/display/Sprite.js b/test/unit/pixi/display/Sprite.js
new file mode 100644
index 0000000..54e914f
--- /dev/null
+++ b/test/unit/pixi/display/Sprite.js
@@ -0,0 +1,25 @@
+describe('pixi/display/Sprite', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Sprite = PIXI.Sprite;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(Sprite).to.be.a('function');
+ expect(PIXI).to.have.deep.property('blendModes.NORMAL', 0);
+ expect(PIXI).to.have.deep.property('blendModes.SCREEN', 1);
+ });
+
+ it('Members exist', function () {
+ expect(Sprite).itself.to.respondTo('fromImage');
+ expect(Sprite).itself.to.respondTo('fromFrame');
+ });
+
+ it('Confirm new instance', function (done) {
+ var texture = Texture.fromImage('/base/test/textures/SpriteSheet-Aliens.png');
+ var obj = new Sprite(texture);
+
+ pixi_display_Sprite_confirmNew(obj, done);
+ });
+});
diff --git a/test/unit/pixi/display/Stage.js b/test/unit/pixi/display/Stage.js
new file mode 100644
index 0000000..3cc2a4d
--- /dev/null
+++ b/test/unit/pixi/display/Stage.js
@@ -0,0 +1,49 @@
+describe('pixi/display/Stage', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Stage = PIXI.Stage;
+ var InteractionManager = PIXI.InteractionManager;
+ var Rectangle = PIXI.Rectangle;
+
+ it('Module exists', function () {
+ expect(Stage).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Stage(null, true);
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(Stage);
+ expect(obj).to.respondTo('updateTransform');
+ expect(obj).to.respondTo('setBackgroundColor');
+ expect(obj).to.respondTo('getMousePosition');
+
+ // FIXME: duplicate member in DisplayObject
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ // FIXME: convert arg to bool in constructor
+ expect(obj).to.have.property('interactive', true);
+
+ expect(obj).to.have.property('interactionManager')
+ .and.to.be.an.instanceof(InteractionManager)
+ .and.to.have.property('stage', obj);
+
+ expect(obj).to.have.property('dirty', true);
+
+ expect(obj).to.have.property('stage', obj);
+
+ expect(obj).to.have.property('hitArea')
+ .and.to.be.an.instanceof(Rectangle);
+ pixi_core_Rectangle_confirm(obj.hitArea, 0, 0, 100000, 100000);
+
+ expect(obj).to.have.property('backgroundColor', 0x000000);
+ expect(obj).to.have.deep.property('backgroundColorSplit.length', 3);
+ expect(obj).to.have.deep.property('backgroundColorSplit[0]', 0);
+ expect(obj).to.have.deep.property('backgroundColorSplit[1]', 0);
+ expect(obj).to.have.deep.property('backgroundColorSplit[2]', 0);
+ expect(obj).to.have.property('backgroundColorString', '#000000');
+
+ expect(obj).to.have.property('worldVisible', true);
+ });
+});
diff --git a/test/unit/pixi/extras/CustomRenderable.js b/test/unit/pixi/extras/CustomRenderable.js
new file mode 100644
index 0000000..8d83cf0
--- /dev/null
+++ b/test/unit/pixi/extras/CustomRenderable.js
@@ -0,0 +1,21 @@
+describe('pixi/extras/CustomRenderable', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var CustomRenderable = PIXI.CustomRenderable;
+
+ it('Module exists', function () {
+ expect(CustomRenderable).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new CustomRenderable();
+
+ pixi_display_DisplayObject_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(CustomRenderable);
+ expect(obj).to.respondTo('renderCanvas');
+ expect(obj).to.respondTo('initWebGL');
+ expect(obj).to.respondTo('renderWebGL');
+ });
+});
diff --git a/test/unit/pixi/extras/Rope.js b/test/unit/pixi/extras/Rope.js
new file mode 100644
index 0000000..6ddaf83
--- /dev/null
+++ b/test/unit/pixi/extras/Rope.js
@@ -0,0 +1,26 @@
+describe('pixi/extras/Rope', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Rope = PIXI.Rope;
+ var Texture = PIXI.Texture;
+ var Point = PIXI.Point;
+
+ it('Module exists', function () {
+ expect(Rope).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var texture = Texture.fromImage('/base/test/textures/bunny.png');
+ var obj = new Rope(texture, [new Point(), new Point(5, 10), new Point(10, 20)]);
+
+ pixi_extras_Strip_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(Rope);
+ expect(obj).to.respondTo('refresh');
+ expect(obj).to.respondTo('updateTransform');
+ expect(obj).to.respondTo('setTexture');
+
+ // TODO: Test properties
+ });
+});
diff --git a/test/unit/pixi/extras/Spine.js b/test/unit/pixi/extras/Spine.js
new file mode 100644
index 0000000..0708bc0
--- /dev/null
+++ b/test/unit/pixi/extras/Spine.js
@@ -0,0 +1,10 @@
+describe('pixi/extras/Spine', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Spine = PIXI.Spine;
+
+ it('Module exists', function () {
+ expect(Spine).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/extras/Strip.js b/test/unit/pixi/extras/Strip.js
new file mode 100644
index 0000000..8e564e1
--- /dev/null
+++ b/test/unit/pixi/extras/Strip.js
@@ -0,0 +1,18 @@
+describe('pixi/extras/Strip', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Strip = PIXI.Strip;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(Strip).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var texture = Texture.fromImage('/base/test/textures/bunny.png');
+ var obj = new Strip(texture, 20, 10000);
+
+ pixi_extras_Strip_confirmNew(obj);
+ });
+});
diff --git a/test/unit/pixi/extras/TilingSprite.js b/test/unit/pixi/extras/TilingSprite.js
new file mode 100644
index 0000000..56aea14
--- /dev/null
+++ b/test/unit/pixi/extras/TilingSprite.js
@@ -0,0 +1,24 @@
+describe('pixi/extras/TilingSprite', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var TilingSprite = PIXI.TilingSprite;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(TilingSprite).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var texture = Texture.fromImage('/base/test/textures/bunny.png');
+ var obj = new TilingSprite(texture, 6000, 12000);
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(TilingSprite);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ // TODO: Test properties
+ });
+});
diff --git a/test/unit/pixi/filters/FilterBlock.js b/test/unit/pixi/filters/FilterBlock.js
new file mode 100644
index 0000000..870cec0
--- /dev/null
+++ b/test/unit/pixi/filters/FilterBlock.js
@@ -0,0 +1,10 @@
+describe('pixi/filters/FilterBlock', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var FilterBlock = PIXI.FilterBlock;
+
+ it('Module exists', function () {
+ expect(FilterBlock).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/filters/MaskFilter.js b/test/unit/pixi/filters/MaskFilter.js
new file mode 100644
index 0000000..32d6a45
--- /dev/null
+++ b/test/unit/pixi/filters/MaskFilter.js
@@ -0,0 +1,10 @@
+describe('pixi/filters/MaskFilter', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ // var MaskFilter = PIXI.MaskFilter;
+
+ // it('Module exists', function () {
+ // expect(MaskFilter).to.be.a('function');
+ // });
+});
diff --git a/test/unit/pixi/loaders/AssetLoader.js b/test/unit/pixi/loaders/AssetLoader.js
new file mode 100644
index 0000000..a0aa0b5
--- /dev/null
+++ b/test/unit/pixi/loaders/AssetLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/AssetLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var AssetLoader = PIXI.AssetLoader;
+
+ it('Module exists', function () {
+ expect(AssetLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/BitmapFontLoader.js b/test/unit/pixi/loaders/BitmapFontLoader.js
new file mode 100644
index 0000000..6253c42
--- /dev/null
+++ b/test/unit/pixi/loaders/BitmapFontLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/BitmapFontLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var BitmapFontLoader = PIXI.BitmapFontLoader;
+
+ it('Module exists', function () {
+ expect(PIXI.BitmapFontLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/ImageLoader.js b/test/unit/pixi/loaders/ImageLoader.js
new file mode 100644
index 0000000..8b1f556
--- /dev/null
+++ b/test/unit/pixi/loaders/ImageLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/ImageLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var ImageLoader = PIXI.ImageLoader;
+
+ it('Module exists', function () {
+ expect(ImageLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/JsonLoader.js b/test/unit/pixi/loaders/JsonLoader.js
new file mode 100644
index 0000000..c577e83
--- /dev/null
+++ b/test/unit/pixi/loaders/JsonLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/JsonLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var JsonLoader = PIXI.JsonLoader;
+
+ it('Module exists', function () {
+ expect(JsonLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/SpineLoader.js b/test/unit/pixi/loaders/SpineLoader.js
new file mode 100644
index 0000000..fdcc0b8
--- /dev/null
+++ b/test/unit/pixi/loaders/SpineLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/SpineLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var SpineLoader = PIXI.SpineLoader;
+
+ it('Module exists', function () {
+ expect(SpineLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/SpriteSheetLoader.js b/test/unit/pixi/loaders/SpriteSheetLoader.js
new file mode 100644
index 0000000..57beb27
--- /dev/null
+++ b/test/unit/pixi/loaders/SpriteSheetLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/SpriteSheetLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var SpriteSheetLoader = PIXI.SpriteSheetLoader;
+
+ it('Module exists', function () {
+ expect(SpriteSheetLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/primitives/Graphics.js b/test/unit/pixi/primitives/Graphics.js
new file mode 100644
index 0000000..b8b3e5c
--- /dev/null
+++ b/test/unit/pixi/primitives/Graphics.js
@@ -0,0 +1,40 @@
+describe('pixi/primitives/Graphics', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Graphics = PIXI.Graphics;
+
+ it('Module exists', function () {
+ expect(Graphics).to.be.a('function');
+
+ expect(Graphics).itself.to.have.property('POLY', 0);
+ expect(Graphics).itself.to.have.property('RECT', 1);
+ expect(Graphics).itself.to.have.property('CIRC', 2);
+ expect(Graphics).itself.to.have.property('ELIP', 3);
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Graphics();
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(Graphics);
+ expect(obj).to.respondTo('lineStyle');
+ expect(obj).to.respondTo('lineStyle');
+ expect(obj).to.respondTo('moveTo');
+ expect(obj).to.respondTo('lineTo');
+ expect(obj).to.respondTo('beginFill');
+ expect(obj).to.respondTo('endFill');
+ expect(obj).to.respondTo('drawRect');
+ expect(obj).to.respondTo('drawCircle');
+ expect(obj).to.respondTo('drawElipse');
+ expect(obj).to.respondTo('clear');
+
+ expect(obj).to.have.property('renderable', true);
+ expect(obj).to.have.property('fillAlpha', 1);
+ expect(obj).to.have.property('lineWidth', 0);
+ expect(obj).to.have.property('lineColor', 'black');
+ expect(obj).to.have.deep.property('graphicsData.length', 0);
+ expect(obj).to.have.deep.property('currentPath.points.length', 0);
+ });
+});
diff --git a/test/unit/pixi/renderers/canvas/CanvasGraphics.js b/test/unit/pixi/renderers/canvas/CanvasGraphics.js
new file mode 100644
index 0000000..8f44472
--- /dev/null
+++ b/test/unit/pixi/renderers/canvas/CanvasGraphics.js
@@ -0,0 +1,15 @@
+describe('renders/canvas/CanvasGraphics', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var CanvasGraphics = PIXI.CanvasGraphics;
+
+ it('Module exists', function () {
+ expect(CanvasGraphics).to.be.a('function');
+ });
+
+ it('Members exist', function () {
+ expect(CanvasGraphics).itself.to.respondTo('renderGraphics');
+ expect(CanvasGraphics).itself.to.respondTo('renderGraphicsMask');
+ });
+});
diff --git a/test/unit/pixi/renderers/canvas/CanvasRenderer.js b/test/unit/pixi/renderers/canvas/CanvasRenderer.js
new file mode 100644
index 0000000..df3a12f
--- /dev/null
+++ b/test/unit/pixi/renderers/canvas/CanvasRenderer.js
@@ -0,0 +1,10 @@
+describe('renderers/canvas/CanvasRenderer', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var CanvasRenderer = PIXI.CanvasRenderer;
+
+ it('Module exists', function () {
+ expect(CanvasRenderer).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/renderers/webgl/WebGLBatch.js b/test/unit/pixi/renderers/webgl/WebGLBatch.js
new file mode 100644
index 0000000..75efd56
--- /dev/null
+++ b/test/unit/pixi/renderers/webgl/WebGLBatch.js
@@ -0,0 +1,10 @@
+describe('renderers/webgl/WebGLBatch', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var WebGLBatch = PIXI.WebGLBatch;
+
+ it('Module exists', function () {
+ expect(WebGLBatch).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/renderers/webgl/WebGLGraphics.js b/test/unit/pixi/renderers/webgl/WebGLGraphics.js
new file mode 100644
index 0000000..41bf941
--- /dev/null
+++ b/test/unit/pixi/renderers/webgl/WebGLGraphics.js
@@ -0,0 +1,19 @@
+describe('renderers/wegbl/WebGLGraphics', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var WebGLGraphics = PIXI.WebGLGraphics;
+
+ it('Module exists', function () {
+ expect(WebGLGraphics).to.be.a('function');
+ });
+
+ it('Members exist', function () {
+ expect(WebGLGraphics).itself.to.respondTo('renderGraphics');
+ expect(WebGLGraphics).itself.to.respondTo('updateGraphics');
+ expect(WebGLGraphics).itself.to.respondTo('buildRectangle');
+ expect(WebGLGraphics).itself.to.respondTo('buildCircle');
+ expect(WebGLGraphics).itself.to.respondTo('buildLine');
+ expect(WebGLGraphics).itself.to.respondTo('buildPoly');
+ });
+});
diff --git a/test/unit/pixi/renderers/webgl/WebGLRenderGroup.js b/test/unit/pixi/renderers/webgl/WebGLRenderGroup.js
new file mode 100644
index 0000000..f4ee366
--- /dev/null
+++ b/test/unit/pixi/renderers/webgl/WebGLRenderGroup.js
@@ -0,0 +1,10 @@
+describe('renderers/webgl/WebGLRenderGroup', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var WebGLRenderGroup = PIXI.WebGLRenderGroup;
+
+ it('Module exists', function () {
+ expect(WebGLRenderGroup).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/renderers/webgl/WebGLRenderer.js b/test/unit/pixi/renderers/webgl/WebGLRenderer.js
new file mode 100644
index 0000000..86533eb
--- /dev/null
+++ b/test/unit/pixi/renderers/webgl/WebGLRenderer.js
@@ -0,0 +1,10 @@
+describe('renderers/webgl/WebGLRenderer', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var WebGLRenderer = PIXI.WebGLRenderer;
+
+ it('Module exists', function () {
+ expect(WebGLRenderer).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/renderers/webgl/WebGLShaders.js b/test/unit/pixi/renderers/webgl/WebGLShaders.js
new file mode 100644
index 0000000..2872de8
--- /dev/null
+++ b/test/unit/pixi/renderers/webgl/WebGLShaders.js
@@ -0,0 +1,13 @@
+describe('renderers/webgl/WebGLShaders', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+
+ it('Module members exist', function () {
+ expect(PIXI).to.respondTo('initPrimitiveShader');
+ expect(PIXI).to.respondTo('initDefaultShader');
+ expect(PIXI).to.respondTo('initDefaultStripShader');
+ expect(PIXI).to.respondTo('activateDefaultShader');
+ expect(PIXI).to.respondTo('activatePrimitiveShader');
+ });
+});
diff --git a/test/unit/pixi/text/BitmapText.js b/test/unit/pixi/text/BitmapText.js
new file mode 100644
index 0000000..9388e3d
--- /dev/null
+++ b/test/unit/pixi/text/BitmapText.js
@@ -0,0 +1,10 @@
+describe('pixi/text/BitmapText', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var BitmapText = PIXI.BitmapText;
+
+ it('Module exists', function () {
+ expect(BitmapText).to.be.a('function');
+ });
+});
diff --git a/.gitignore b/.gitignore
index 12e1b62..0b88317 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
node_modules
.DS_Store
-.project
\ No newline at end of file
+.project
+*.log
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..63e4d7c
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,8 @@
+language: node_js
+node_js:
+ - 0.10
+
+before_script:
+ - npm install -g grunt-cli
+ - export DISPLAY=:99.0
+ - sh -e /etc/init.d/xvfb start
diff --git a/Gruntfile.js b/Gruntfile.js
index b083b49..103938c 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -1,10 +1,12 @@
+'use strict';
+
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-connect');
- grunt.loadNpmTasks('grunt-contrib-qunit');
grunt.loadNpmTasks('grunt-contrib-yuidoc');
+ grunt.loadTasks('tasks');
var root = 'src/pixi/',
debug = 'bin/pixi.dev.js',
@@ -79,7 +81,7 @@
},
files: {
srcBlob: '<%= dirs.src %>/**/*.js',
- testBlob: '<%= dirs.test %>/unit/**/*.js',
+ testBlob: '<%= dirs.test %>/{functional,lib/pixi,unit}/**/*.js',
build: '<%= dirs.build %>/pixi.dev.js',
buildMin: '<%= dirs.build %>/pixi.js'
},
@@ -94,7 +96,12 @@
},
jshint: {
beforeconcat: srcFiles,
- test: ['<%= files.testBlob %>'],
+ test: {
+ src: ['<%= files.testBlob %>'],
+ options: {
+ expr: true
+ }
+ },
options: {
asi: true,
smarttabs: true
@@ -128,12 +135,6 @@
]
},
connect: {
- qunit: {
- options: {
- port: grunt.option('port-test') || 9002,
- base: './'
- }
- },
test: {
options: {
port: grunt.option('port-test') || 9002,
@@ -142,13 +143,6 @@
}
}
},
- qunit: {
- all: {
- options: {
- urls: ['http://localhost:' + (grunt.option('port-test') || 9002) + '/test/index.html']
- }
- }
- },
yuidoc: {
compile: {
name: '<%= pkg.name %>',
@@ -161,6 +155,13 @@
outdir: '<%= dirs.docs %>'
}
}
+ },
+ karma: {
+ unit: {
+ configFile: 'test/karma.conf.js',
+ // browsers: ['Chrome'],
+ singleRun: true
+ }
}
});
@@ -182,9 +183,10 @@
}
)
- grunt.registerTask('default', ['concat', 'uglify', 'distribute']);
grunt.registerTask('build', ['concat', 'uglify', 'distribute']);
- grunt.registerTask('test', ['build', 'connect:qunit', 'qunit']);
+ grunt.registerTask('test', ['concat', 'jshint:test', 'karma']);
grunt.registerTask('docs', ['yuidoc']);
-
-}
\ No newline at end of file
+ grunt.registerTask('default', ['test', 'uglify', 'distribute']);
+ // Travis CI task.
+ grunt.registerTask('travis', ['test']);
+}
diff --git a/README.md b/README.md
index c62ef86..690cfe4 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,8 @@

+[](http://travis-ci.org/drkibitz/pixi.js)
+
#### JavaScript 2D Renderer ####
The aim of this project is to provide a fast lightweight 2D library that works
diff --git a/package.json b/package.json
index b373240..1246a68 100644
--- a/package.json
+++ b/package.json
@@ -18,14 +18,21 @@
"main": "bin/pixi.js",
+ "scripts": {
+ "test": "grunt travis --verbose"
+ },
+
"dependencies": {},
"devDependencies": {
"grunt": "~0.4.x",
- "grunt-contrib-jshint": "0.3.x",
+ "grunt-contrib-jshint": "0.6.x",
"grunt-contrib-uglify": "0.2.x",
- "grunt-contrib-connect": "0.2.x",
- "grunt-contrib-qunit": "0.2.x",
+ "grunt-contrib-connect": "0.3.x",
"grunt-contrib-yuidoc": "0.4.x",
- "grunt-contrib-concat": "0.1.x"
+ "grunt-contrib-concat": "0.3.x",
+ "chai": "~1.7.0",
+ "karma": "0.11.0",
+ "karma-firefox-launcher": "0.1.0",
+ "karma-mocha": "0.1.0"
}
}
diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js
index a7c520e..ee82bbd 100644
--- a/src/pixi/InteractionManager.js
+++ b/src/pixi/InteractionManager.js
@@ -62,7 +62,6 @@
this.onTouchEnd = this.onTouchEnd.bind(this);
this.onTouchMove = this.onTouchMove.bind(this);
-
this.last = 0;
}
diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js
index 1a95d20..eef1059 100644
--- a/src/pixi/core/Ellipse.js
+++ b/src/pixi/core/Ellipse.js
@@ -78,7 +78,7 @@
return (normx + normy < 0.25);
}
-PIXI.Ellipse.getBounds = function()
+PIXI.Ellipse.prototype.getBounds = function()
{
return new PIXI.Rectangle(this.x, this.y, this.width, this.height);
}
diff --git a/tasks/karma.js b/tasks/karma.js
new file mode 100644
index 0000000..c340485
--- /dev/null
+++ b/tasks/karma.js
@@ -0,0 +1,27 @@
+'use strict';
+
+var path = require('path');
+var server = require('karma').server;
+
+module.exports = function (grunt) {
+ grunt.registerMultiTask('karma', 'run karma.', function() {
+ var done = this.async();
+ var options = this.options({
+ background: false
+ });
+ var data = this.data;
+
+ //merge options onto data, with data taking precedence
+ data = grunt.util._.merge(options, data);
+ data.configFile = path.resolve(data.configFile);
+ if (data.configFile) {
+ data.configFile = grunt.template.process(data.configFile);
+ }
+
+ server.start(
+ data,
+ function(code) {
+ done(!code);
+ });
+ });
+};
diff --git a/test/functional/example-1-basics/bunny.png b/test/functional/example-1-basics/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/functional/example-1-basics/bunny.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-30.png b/test/functional/example-1-basics/frame-30.png
new file mode 100644
index 0000000..96e3409
--- /dev/null
+++ b/test/functional/example-1-basics/frame-30.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-60.png b/test/functional/example-1-basics/frame-60.png
new file mode 100644
index 0000000..af3f4ce
--- /dev/null
+++ b/test/functional/example-1-basics/frame-60.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-90.png b/test/functional/example-1-basics/frame-90.png
new file mode 100644
index 0000000..099b823
--- /dev/null
+++ b/test/functional/example-1-basics/frame-90.png
Binary files differ
diff --git a/test/functional/example-1-basics/index.js b/test/functional/example-1-basics/index.js
new file mode 100644
index 0000000..7ae7a98
--- /dev/null
+++ b/test/functional/example-1-basics/index.js
@@ -0,0 +1,133 @@
+describe('Example 1 - Basics', function () {
+ 'use strict';
+
+ var baseUri = '/base/test/functional/example-1-basics';
+ var expect = chai.expect;
+ var currentFrame = 0;
+ var frameEvents = {};
+ var stage;
+ var renderer;
+ var bunny;
+
+ function onFrame(frame, callback) {
+ frameEvents[frame] = callback;
+ }
+
+ function animate() {
+ currentFrame += 1;
+
+ requestAnimFrame( animate );
+
+ // just for fun, lets rotate mr rabbit a little
+ bunny.rotation += 0.1;
+
+ // render the stage
+ renderer.render(stage);
+
+ if (frameEvents[currentFrame])
+ frameEvents[currentFrame](currentFrame);
+ }
+
+ function initScene() {
+ // create an new instance of a pixi stage
+ stage = new PIXI.Stage(0x66FF99);
+
+ // create a renderer instance
+ renderer = PIXI.autoDetectRenderer(400, 300);
+ console.log('Is PIXI.WebGLRenderer: ' + (renderer instanceof PIXI.WebGLRenderer));
+
+ // add the renderer view element to the DOM
+ document.body.appendChild(renderer.view);
+
+ requestAnimFrame( animate );
+
+ // create a texture from an image path
+ var texture = PIXI.Texture.fromImage(baseUri + "/bunny.png");
+ // create a new Sprite using the texture
+ bunny = new PIXI.Sprite(texture);
+
+ // center the sprites anchor point
+ bunny.anchor.x = 0.5;
+ bunny.anchor.y = 0.5;
+
+ // move the sprite t the center of the screen
+ bunny.position.x = 200;
+ bunny.position.y = 150;
+
+ stage.addChild(bunny);
+ }
+
+ it('assets loaded', function (done) {
+ var loader = new PIXI.AssetLoader([
+ baseUri + '/bunny.png',
+ baseUri + '/frame-30.png',
+ baseUri + '/frame-60.png',
+ baseUri + '/frame-90.png'
+ ]);
+ // loader.on('onProgress', function (event) {
+ // console.log(event.content);
+ // });
+ loader.on('onComplete', function (event) {
+ done();
+ initScene();
+ });
+ loader.load();
+ });
+
+ it('frame 30 should match', function (done) {
+ this.timeout(700);
+ onFrame(30, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-30.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 60 should match', function (done) {
+ this.timeout(1200);
+ onFrame(60, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-60.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 90 should match', function (done) {
+ this.timeout(1700);
+ onFrame(90, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-90.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ // it('capture something', function (done) {
+ // this.timeout(2000000);
+ // onFrame(30, function () {
+ // var img = new Image();
+ // img.src = renderer.view.toDataURL('image/png');
+ // document.body.appendChild(img);
+ // });
+ // });
+});
diff --git a/test/index.html b/test/index.html
deleted file mode 100644
index 9cbcac5..0000000
--- a/test/index.html
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
- Pixi.js Test Suite
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/test/karma.conf.js b/test/karma.conf.js
new file mode 100644
index 0000000..c66a696
--- /dev/null
+++ b/test/karma.conf.js
@@ -0,0 +1,82 @@
+module.exports = function(config) {
+ config.set({
+
+ // base path, that will be used to resolve files and exclude
+ basePath : '../',
+
+ frameworks : ['mocha'],
+
+ // list of files / patterns to load in the browser
+ files : [
+ 'node_modules/chai/chai.js',
+ 'bin/pixi.dev.js',
+ 'test/lib/**/*.js',
+ 'test/unit/**/*.js',
+ // 'test/functional/**/*.js',
+ {pattern: 'test/**/*.png', watched: false, included: false, served: true}
+ ],
+
+ // list of files to exclude
+ exclude : [],
+
+ // use dolts reporter, as travis terminal does not support escaping sequences
+ // possible values: 'dots', 'progress', 'junit', 'teamcity'
+ // CLI --reporters progress
+ reporters : ['progress'],
+
+ // web server port
+ // CLI --port 9876
+ port : 9876,
+
+ // cli runner port
+ // CLI --runner-port 9100
+ runnerPort : 9100,
+
+ // enable / disable colors in the output (reporters and logs)
+ // CLI --colors --no-colors
+ colors : true,
+
+ // level of logging
+ // possible values: karma.LOG_DISABLE || karma.LOG_ERROR || karma.LOG_WARN || karma.LOG_INFO || karma.LOG_DEBUG
+ // CLI --log-level debug
+ logLevel : config.LOG_DEBUG,
+
+ // enable / disable watching file and executing tests whenever any file changes
+ // CLI --auto-watch --no-auto-watch
+ autoWatch : false,
+
+ // Start these browsers, currently available:
+ // - Chrome
+ // - ChromeCanary
+ // - Firefox
+ // - Opera
+ // - Safari (only Mac)
+ // - PhantomJS
+ // - IE (only Windows)
+ // CLI --browsers Chrome,Firefox,Safari
+ browsers : ['Firefox'],
+
+ // If browser does not capture in given timeout [ms], kill it
+ // CLI --capture-timeout 5000
+ captureTimeout : 5000,
+
+ // Auto run tests on start (when browsers are captured) and exit
+ // CLI --single-run --no-single-run
+ singleRun : true,
+
+ // report which specs are slower than 500ms
+ // CLI --report-slower-than 500
+ reportSlowerThan : 1000,
+
+ preprocessors : {
+ // '**/client/js/*.js': 'coverage'
+ },
+
+ plugins : [
+ 'karma-mocha',
+ // 'karma-chrome-launcher',
+ 'karma-firefox-launcher',
+ // 'karma-phantomjs-launcher'
+ ]
+ });
+};
diff --git a/test/lib/pixi/core/Matrix.js b/test/lib/pixi/core/Matrix.js
new file mode 100644
index 0000000..d26386b
--- /dev/null
+++ b/test/lib/pixi/core/Matrix.js
@@ -0,0 +1,40 @@
+
+function pixi_core_Matrix_confirmNewMat3(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(1);
+ expect(matrix[5]).to.equal(0);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(1);
+}
+
+function pixi_core_Matrix_confirmNewMat4(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[0]).to.equal(1);
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(0);
+ expect(matrix[5]).to.equal(1);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(0);
+ expect(matrix[9]).to.equal(0);
+ expect(matrix[10]).to.equal(1);
+ expect(matrix[11]).to.equal(0);
+ expect(matrix[12]).to.equal(0);
+ expect(matrix[13]).to.equal(0);
+ expect(matrix[14]).to.equal(0);
+ expect(matrix[15]).to.equal(1);
+}
diff --git a/test/lib/pixi/core/Point.js b/test/lib/pixi/core/Point.js
new file mode 100644
index 0000000..e5df07b
--- /dev/null
+++ b/test/lib/pixi/core/Point.js
@@ -0,0 +1,10 @@
+
+function pixi_core_Point_confirm(obj, x, y) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Point);
+ expect(obj).to.respondTo('clone');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+}
diff --git a/test/lib/pixi/core/Rectangle.js b/test/lib/pixi/core/Rectangle.js
new file mode 100644
index 0000000..23f0d12
--- /dev/null
+++ b/test/lib/pixi/core/Rectangle.js
@@ -0,0 +1,13 @@
+
+function pixi_core_Rectangle_confirm(obj, x, y, width, height) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Rectangle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+ expect(obj).to.have.property('width', width);
+ expect(obj).to.have.property('height', height);
+}
diff --git a/test/lib/pixi/display/DisplayObject.js b/test/lib/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..1388a7f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObject.js
@@ -0,0 +1,43 @@
+
+function pixi_display_DisplayObject_confirmNew(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObject);
+ expect(obj).to.respondTo('setInteractive');
+ expect(obj).to.respondTo('addFilter');
+ expect(obj).to.respondTo('removeFilter');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.property('last', obj);
+ expect(obj).to.have.property('first', obj);
+
+ expect(obj).to.contain.property('position');
+ pixi_core_Point_confirm(obj.position, 0, 0);
+ expect(obj).to.contain.property('scale');
+ pixi_core_Point_confirm(obj.scale, 1, 1);
+ expect(obj).to.contain.property('pivot');
+ pixi_core_Point_confirm(obj.pivot, 0, 0);
+
+ expect(obj).to.have.property('rotation', 0);
+ expect(obj).to.have.property('alpha', 1);
+ expect(obj).to.have.property('visible', true);
+ expect(obj).to.have.property('buttonMode', false);
+ expect(obj).to.have.property('parent', null);
+ expect(obj).to.have.property('worldAlpha', 1);
+
+ expect(obj).to.have.property('hitArea');
+ expect(obj).to.have.property('interactive'); // TODO: Have a better default value
+ expect('mask' in obj).to.be.true; // TODO: Have a better default value
+ expect(obj.mask).to.be.undefined;
+
+ expect(obj).to.have.property('renderable');
+ expect(obj).to.have.property('stage');
+
+ expect(obj).to.have.deep.property('worldTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ expect(obj).to.have.deep.property('localTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.localTransform);
+
+ expect(obj).to.have.deep.property('color.length', 0);
+ expect(obj).to.have.property('dynamic', true);
+}
diff --git a/test/lib/pixi/display/DisplayObjectContainer.js b/test/lib/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..085c59f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,16 @@
+
+function pixi_display_DisplayObjectContainer_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObject_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObjectContainer);
+ expect(obj).to.respondTo('addChild');
+ expect(obj).to.respondTo('addChildAt');
+ expect(obj).to.respondTo('swapChildren');
+ expect(obj).to.respondTo('getChildAt');
+ expect(obj).to.respondTo('removeChild');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('children.length', 0);
+}
diff --git a/test/lib/pixi/display/Sprite.js b/test/lib/pixi/display/Sprite.js
new file mode 100644
index 0000000..cc7a2d6
--- /dev/null
+++ b/test/lib/pixi/display/Sprite.js
@@ -0,0 +1,28 @@
+
+function pixi_display_Sprite_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Sprite);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', true);
+ expect(obj).to.have.property('stage', null);
+
+ expect(obj).to.have.property('anchor');
+ pixi_core_Point_confirm(obj.anchor, 0, 0);
+
+ expect(obj).to.have.property('blendMode', PIXI.blendModes.NORMAL);
+ expect(obj).to.have.property('width', 1); // TODO: is 1 expected
+ expect(obj).to.have.property('height', 1); // TODO: is 1 expected
+
+ // FIXME: Just make this a boolean that is always there
+ expect(!!obj.updateFrame).to.equal(obj.texture.baseTexture.hasLoaded);
+
+ expect(obj).to.have.property('texture');
+ pixi_textures_Texture_confirmNew(obj.texture, done);
+}
diff --git a/test/lib/pixi/extras/Strip.js b/test/lib/pixi/extras/Strip.js
new file mode 100644
index 0000000..8927a8a
--- /dev/null
+++ b/test/lib/pixi/extras/Strip.js
@@ -0,0 +1,12 @@
+
+function pixi_extras_Strip_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Strip);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ // TODO: Test properties
+}
diff --git a/test/lib/pixi/textures/Texture.js b/test/lib/pixi/textures/Texture.js
new file mode 100644
index 0000000..d5867b6
--- /dev/null
+++ b/test/lib/pixi/textures/Texture.js
@@ -0,0 +1,31 @@
+
+function pixi_textures_Texture_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ function confirmFrameDone() {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, obj.baseTexture.width, obj.baseTexture.height);
+
+ expect(obj).to.have.property('width', obj.baseTexture.width);
+ expect(obj).to.have.property('height', obj.baseTexture.height);
+ done();
+ }
+
+ expect(obj).to.be.an.instanceof(PIXI.Texture);
+ pixi_utils_EventTarget_like(obj);
+
+ expect(obj).to.have.property('baseTexture')
+ .and.to.be.an.instanceof(PIXI.BaseTexture);
+
+ expect(obj).to.have.property('scope', obj);
+
+ expect(obj).to.have.property('trim');
+ pixi_core_Point_confirm(obj.trim, 0, 0);
+
+ expect(obj).to.have.property('frame');
+ if (obj.baseTexture.hasLoaded) {
+ confirmFrameDone();
+ } else {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, 1, 1);
+ obj.addEventListener('update', confirmFrameDone);
+ }
+}
diff --git a/test/lib/pixi/utils/EventTarget.js b/test/lib/pixi/utils/EventTarget.js
new file mode 100644
index 0000000..7b1dcfa
--- /dev/null
+++ b/test/lib/pixi/utils/EventTarget.js
@@ -0,0 +1,8 @@
+
+function pixi_utils_EventTarget_like(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.respondTo('addEventListener');
+ expect(obj).to.respondTo('dispatchEvent');
+ expect(obj).to.respondTo('removeEventListener');
+}
diff --git a/test/lib/qunit-1.11.0.css b/test/lib/qunit-1.11.0.css
deleted file mode 100644
index d7fc0c8..0000000
--- a/test/lib/qunit-1.11.0.css
+++ /dev/null
@@ -1,244 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-/** Font Family and Sizes */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
- font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
-}
-
-#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
-#qunit-tests { font-size: smaller; }
-
-
-/** Resets */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter {
- margin: 0;
- padding: 0;
-}
-
-
-/** Header */
-
-#qunit-header {
- padding: 0.5em 0 0.5em 1em;
-
- color: #8699a4;
- background-color: #0d3349;
-
- font-size: 1.5em;
- line-height: 1em;
- font-weight: normal;
-
- border-radius: 5px 5px 0 0;
- -moz-border-radius: 5px 5px 0 0;
- -webkit-border-top-right-radius: 5px;
- -webkit-border-top-left-radius: 5px;
-}
-
-#qunit-header a {
- text-decoration: none;
- color: #c2ccd1;
-}
-
-#qunit-header a:hover,
-#qunit-header a:focus {
- color: #fff;
-}
-
-#qunit-testrunner-toolbar label {
- display: inline-block;
- padding: 0 .5em 0 .1em;
-}
-
-#qunit-banner {
- height: 5px;
-}
-
-#qunit-testrunner-toolbar {
- padding: 0.5em 0 0.5em 2em;
- color: #5E740B;
- background-color: #eee;
- overflow: hidden;
-}
-
-#qunit-userAgent {
- padding: 0.5em 0 0.5em 2.5em;
- background-color: #2b81af;
- color: #fff;
- text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
-}
-
-#qunit-modulefilter-container {
- float: right;
-}
-
-/** Tests: Pass/Fail */
-
-#qunit-tests {
- list-style-position: inside;
-}
-
-#qunit-tests li {
- padding: 0.4em 0.5em 0.4em 2.5em;
- border-bottom: 1px solid #fff;
- list-style-position: inside;
-}
-
-#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running {
- display: none;
-}
-
-#qunit-tests li strong {
- cursor: pointer;
-}
-
-#qunit-tests li a {
- padding: 0.5em;
- color: #c2ccd1;
- text-decoration: none;
-}
-#qunit-tests li a:hover,
-#qunit-tests li a:focus {
- color: #000;
-}
-
-#qunit-tests li .runtime {
- float: right;
- font-size: smaller;
-}
-
-.qunit-assert-list {
- margin-top: 0.5em;
- padding: 0.5em;
-
- background-color: #fff;
-
- border-radius: 5px;
- -moz-border-radius: 5px;
- -webkit-border-radius: 5px;
-}
-
-.qunit-collapsed {
- display: none;
-}
-
-#qunit-tests table {
- border-collapse: collapse;
- margin-top: .2em;
-}
-
-#qunit-tests th {
- text-align: right;
- vertical-align: top;
- padding: 0 .5em 0 0;
-}
-
-#qunit-tests td {
- vertical-align: top;
-}
-
-#qunit-tests pre {
- margin: 0;
- white-space: pre-wrap;
- word-wrap: break-word;
-}
-
-#qunit-tests del {
- background-color: #e0f2be;
- color: #374e0c;
- text-decoration: none;
-}
-
-#qunit-tests ins {
- background-color: #ffcaca;
- color: #500;
- text-decoration: none;
-}
-
-/*** Test Counts */
-
-#qunit-tests b.counts { color: black; }
-#qunit-tests b.passed { color: #5E740B; }
-#qunit-tests b.failed { color: #710909; }
-
-#qunit-tests li li {
- padding: 5px;
- background-color: #fff;
- border-bottom: none;
- list-style-position: inside;
-}
-
-/*** Passing Styles */
-
-#qunit-tests li li.pass {
- color: #3c510c;
- background-color: #fff;
- border-left: 10px solid #C6E746;
-}
-
-#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
-#qunit-tests .pass .test-name { color: #366097; }
-
-#qunit-tests .pass .test-actual,
-#qunit-tests .pass .test-expected { color: #999999; }
-
-#qunit-banner.qunit-pass { background-color: #C6E746; }
-
-/*** Failing Styles */
-
-#qunit-tests li li.fail {
- color: #710909;
- background-color: #fff;
- border-left: 10px solid #EE5757;
- white-space: pre;
-}
-
-#qunit-tests > li:last-child {
- border-radius: 0 0 5px 5px;
- -moz-border-radius: 0 0 5px 5px;
- -webkit-border-bottom-right-radius: 5px;
- -webkit-border-bottom-left-radius: 5px;
-}
-
-#qunit-tests .fail { color: #000000; background-color: #EE5757; }
-#qunit-tests .fail .test-name,
-#qunit-tests .fail .module-name { color: #000000; }
-
-#qunit-tests .fail .test-actual { color: #EE5757; }
-#qunit-tests .fail .test-expected { color: green; }
-
-#qunit-banner.qunit-fail { background-color: #EE5757; }
-
-
-/** Result */
-
-#qunit-testresult {
- padding: 0.5em 0.5em 0.5em 2.5em;
-
- color: #2b81af;
- background-color: #D2E0E6;
-
- border-bottom: 1px solid white;
-}
-#qunit-testresult .module-name {
- font-weight: bold;
-}
-
-/** Fixture */
-
-#qunit-fixture {
- position: absolute;
- top: -10000px;
- left: -10000px;
- width: 1000px;
- height: 1000px;
-}
diff --git a/test/lib/qunit-1.11.0.js b/test/lib/qunit-1.11.0.js
deleted file mode 100644
index 302545f..0000000
--- a/test/lib/qunit-1.11.0.js
+++ /dev/null
@@ -1,2152 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-(function( window ) {
-
-var QUnit,
- assert,
- config,
- onErrorFnPrev,
- testId = 0,
- fileName = (sourceFromStacktrace( 0 ) || "" ).replace(/(:\d+)+\)?/, "").replace(/.+\//, ""),
- toString = Object.prototype.toString,
- hasOwn = Object.prototype.hasOwnProperty,
- // Keep a local reference to Date (GH-283)
- Date = window.Date,
- defined = {
- setTimeout: typeof window.setTimeout !== "undefined",
- sessionStorage: (function() {
- var x = "qunit-test-string";
- try {
- sessionStorage.setItem( x, x );
- sessionStorage.removeItem( x );
- return true;
- } catch( e ) {
- return false;
- }
- }())
- },
- /**
- * Provides a normalized error string, correcting an issue
- * with IE 7 (and prior) where Error.prototype.toString is
- * not properly implemented
- *
- * Based on http://es5.github.com/#x15.11.4.4
- *
- * @param {String|Error} error
- * @return {String} error message
- */
- errorString = function( error ) {
- var name, message,
- errorString = error.toString();
- if ( errorString.substring( 0, 7 ) === "[object" ) {
- name = error.name ? error.name.toString() : "Error";
- message = error.message ? error.message.toString() : "";
- if ( name && message ) {
- return name + ": " + message;
- } else if ( name ) {
- return name;
- } else if ( message ) {
- return message;
- } else {
- return "Error";
- }
- } else {
- return errorString;
- }
- },
- /**
- * Makes a clone of an object using only Array or Object as base,
- * and copies over the own enumerable properties.
- *
- * @param {Object} obj
- * @return {Object} New object with only the own properties (recursively).
- */
- objectValues = function( obj ) {
- // Grunt 0.3.x uses an older version of jshint that still has jshint/jshint#392.
- /*jshint newcap: false */
- var key, val,
- vals = QUnit.is( "array", obj ) ? [] : {};
- for ( key in obj ) {
- if ( hasOwn.call( obj, key ) ) {
- val = obj[key];
- vals[key] = val === Object(val) ? objectValues(val) : val;
- }
- }
- return vals;
- };
-
-function Test( settings ) {
- extend( this, settings );
- this.assertions = [];
- this.testNumber = ++Test.count;
-}
-
-Test.count = 0;
-
-Test.prototype = {
- init: function() {
- var a, b, li,
- tests = id( "qunit-tests" );
-
- if ( tests ) {
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml;
-
- // `a` initialized at top of scope
- a = document.createElement( "a" );
- a.innerHTML = "Rerun";
- a.href = QUnit.url({ testNumber: this.testNumber });
-
- li = document.createElement( "li" );
- li.appendChild( b );
- li.appendChild( a );
- li.className = "running";
- li.id = this.id = "qunit-test-output" + testId++;
-
- tests.appendChild( li );
- }
- },
- setup: function() {
- if ( this.module !== config.previousModule ) {
- if ( config.previousModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.previousModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
- config.previousModule = this.module;
- config.moduleStats = { all: 0, bad: 0 };
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- } else if ( config.autorun ) {
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- }
-
- config.current = this;
-
- this.testEnvironment = extend({
- setup: function() {},
- teardown: function() {}
- }, this.moduleTestEnvironment );
-
- this.started = +new Date();
- runLoggingCallbacks( "testStart", QUnit, {
- name: this.testName,
- module: this.module
- });
-
- // allow utility functions to access the current test environment
- // TODO why??
- QUnit.current_testEnvironment = this.testEnvironment;
-
- if ( !config.pollution ) {
- saveGlobal();
- }
- if ( config.notrycatch ) {
- this.testEnvironment.setup.call( this.testEnvironment );
- return;
- }
- try {
- this.testEnvironment.setup.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Setup failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- },
- run: function() {
- config.current = this;
-
- var running = id( "qunit-testresult" );
-
- if ( running ) {
- running.innerHTML = "Running:
" + this.nameHtml;
- }
-
- if ( this.async ) {
- QUnit.stop();
- }
-
- this.callbackStarted = +new Date();
-
- if ( config.notrycatch ) {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- return;
- }
-
- try {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- } catch( e ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
-
- QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + " " + this.stack + ": " + ( e.message || e ), extractStacktrace( e, 0 ) );
- // else next test will carry the responsibility
- saveGlobal();
-
- // Restart the tests if they're blocking
- if ( config.blocking ) {
- QUnit.start();
- }
- }
- },
- teardown: function() {
- config.current = this;
- if ( config.notrycatch ) {
- if ( typeof this.callbackRuntime === "undefined" ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
- }
- this.testEnvironment.teardown.call( this.testEnvironment );
- return;
- } else {
- try {
- this.testEnvironment.teardown.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Teardown failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- }
- checkPollution();
- },
- finish: function() {
- config.current = this;
- if ( config.requireExpects && this.expected === null ) {
- QUnit.pushFailure( "Expected number of assertions to be defined, but expect() was not called.", this.stack );
- } else if ( this.expected !== null && this.expected !== this.assertions.length ) {
- QUnit.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack );
- } else if ( this.expected === null && !this.assertions.length ) {
- QUnit.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions.", this.stack );
- }
-
- var i, assertion, a, b, time, li, ol,
- test = this,
- good = 0,
- bad = 0,
- tests = id( "qunit-tests" );
-
- this.runtime = +new Date() - this.started;
- config.stats.all += this.assertions.length;
- config.moduleStats.all += this.assertions.length;
-
- if ( tests ) {
- ol = document.createElement( "ol" );
- ol.className = "qunit-assert-list";
-
- for ( i = 0; i < this.assertions.length; i++ ) {
- assertion = this.assertions[i];
-
- li = document.createElement( "li" );
- li.className = assertion.result ? "pass" : "fail";
- li.innerHTML = assertion.message || ( assertion.result ? "okay" : "failed" );
- ol.appendChild( li );
-
- if ( assertion.result ) {
- good++;
- } else {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
-
- // store result when possible
- if ( QUnit.config.reorder && defined.sessionStorage ) {
- if ( bad ) {
- sessionStorage.setItem( "qunit-test-" + this.module + "-" + this.testName, bad );
- } else {
- sessionStorage.removeItem( "qunit-test-" + this.module + "-" + this.testName );
- }
- }
-
- if ( bad === 0 ) {
- addClass( ol, "qunit-collapsed" );
- }
-
- // `b` initialized at top of scope
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml + " (" + bad + ", " + good + ", " + this.assertions.length + ")";
-
- addEvent(b, "click", function() {
- var next = b.parentNode.lastChild,
- collapsed = hasClass( next, "qunit-collapsed" );
- ( collapsed ? removeClass : addClass )( next, "qunit-collapsed" );
- });
-
- addEvent(b, "dblclick", function( e ) {
- var target = e && e.target ? e.target : window.event.srcElement;
- if ( target.nodeName.toLowerCase() === "span" || target.nodeName.toLowerCase() === "b" ) {
- target = target.parentNode;
- }
- if ( window.location && target.nodeName.toLowerCase() === "strong" ) {
- window.location = QUnit.url({ testNumber: test.testNumber });
- }
- });
-
- // `time` initialized at top of scope
- time = document.createElement( "span" );
- time.className = "runtime";
- time.innerHTML = this.runtime + " ms";
-
- // `li` initialized at top of scope
- li = id( this.id );
- li.className = bad ? "fail" : "pass";
- li.removeChild( li.firstChild );
- a = li.firstChild;
- li.appendChild( b );
- li.appendChild( a );
- li.appendChild( time );
- li.appendChild( ol );
-
- } else {
- for ( i = 0; i < this.assertions.length; i++ ) {
- if ( !this.assertions[i].result ) {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
- }
-
- runLoggingCallbacks( "testDone", QUnit, {
- name: this.testName,
- module: this.module,
- failed: bad,
- passed: this.assertions.length - bad,
- total: this.assertions.length,
- duration: this.runtime
- });
-
- QUnit.reset();
-
- config.current = undefined;
- },
-
- queue: function() {
- var bad,
- test = this;
-
- synchronize(function() {
- test.init();
- });
- function run() {
- // each of these can by async
- synchronize(function() {
- test.setup();
- });
- synchronize(function() {
- test.run();
- });
- synchronize(function() {
- test.teardown();
- });
- synchronize(function() {
- test.finish();
- });
- }
-
- // `bad` initialized at top of scope
- // defer when previous test run passed, if storage is available
- bad = QUnit.config.reorder && defined.sessionStorage &&
- +sessionStorage.getItem( "qunit-test-" + this.module + "-" + this.testName );
-
- if ( bad ) {
- run();
- } else {
- synchronize( run, true );
- }
- }
-};
-
-// Root QUnit object.
-// `QUnit` initialized at top of scope
-QUnit = {
-
- // call on start of module test to prepend name to all tests
- module: function( name, testEnvironment ) {
- config.currentModule = name;
- config.currentModuleTestEnvironment = testEnvironment;
- config.modules[name] = true;
- },
-
- asyncTest: function( testName, expected, callback ) {
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- QUnit.test( testName, expected, callback, true );
- },
-
- test: function( testName, expected, callback, async ) {
- var test,
- nameHtml = "" + escapeText( testName ) + "";
-
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- if ( config.currentModule ) {
- nameHtml = "" + escapeText( config.currentModule ) + ": " + nameHtml;
- }
-
- test = new Test({
- nameHtml: nameHtml,
- testName: testName,
- expected: expected,
- async: async,
- callback: callback,
- module: config.currentModule,
- moduleTestEnvironment: config.currentModuleTestEnvironment,
- stack: sourceFromStacktrace( 2 )
- });
-
- if ( !validTest( test ) ) {
- return;
- }
-
- test.queue();
- },
-
- // Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through.
- expect: function( asserts ) {
- if (arguments.length === 1) {
- config.current.expected = asserts;
- } else {
- return config.current.expected;
- }
- },
-
- start: function( count ) {
- // QUnit hasn't been initialized yet.
- // Note: RequireJS (et al) may delay onLoad
- if ( config.semaphore === undefined ) {
- QUnit.begin(function() {
- // This is triggered at the top of QUnit.load, push start() to the event loop, to allow QUnit.load to finish first
- setTimeout(function() {
- QUnit.start( count );
- });
- });
- return;
- }
-
- config.semaphore -= count || 1;
- // don't start until equal number of stop-calls
- if ( config.semaphore > 0 ) {
- return;
- }
- // ignore if start is called more often then stop
- if ( config.semaphore < 0 ) {
- config.semaphore = 0;
- QUnit.pushFailure( "Called start() while already started (QUnit.config.semaphore was 0 already)", null, sourceFromStacktrace(2) );
- return;
- }
- // A slight delay, to avoid any current callbacks
- if ( defined.setTimeout ) {
- window.setTimeout(function() {
- if ( config.semaphore > 0 ) {
- return;
- }
- if ( config.timeout ) {
- clearTimeout( config.timeout );
- }
-
- config.blocking = false;
- process( true );
- }, 13);
- } else {
- config.blocking = false;
- process( true );
- }
- },
-
- stop: function( count ) {
- config.semaphore += count || 1;
- config.blocking = true;
-
- if ( config.testTimeout && defined.setTimeout ) {
- clearTimeout( config.timeout );
- config.timeout = window.setTimeout(function() {
- QUnit.ok( false, "Test timed out" );
- config.semaphore = 1;
- QUnit.start();
- }, config.testTimeout );
- }
- }
-};
-
-// `assert` initialized at top of scope
-// Asssert helpers
-// All of these must either call QUnit.push() or manually do:
-// - runLoggingCallbacks( "log", .. );
-// - config.current.assertions.push({ .. });
-// We attach it to the QUnit object *after* we expose the public API,
-// otherwise `assert` will become a global variable in browsers (#341).
-assert = {
- /**
- * Asserts rough true-ish result.
- * @name ok
- * @function
- * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" );
- */
- ok: function( result, msg ) {
- if ( !config.current ) {
- throw new Error( "ok() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
- result = !!result;
-
- var source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: msg
- };
-
- msg = escapeText( msg || (result ? "okay" : "failed" ) );
- msg = "" + msg + "";
-
- if ( !result ) {
- source = sourceFromStacktrace( 2 );
- if ( source ) {
- details.source = source;
- msg += "Source: | " + escapeText( source ) + " |
---|
";
- }
- }
- runLoggingCallbacks( "log", QUnit, details );
- config.current.assertions.push({
- result: result,
- message: msg
- });
- },
-
- /**
- * Assert that the first two arguments are equal, with an optional message.
- * Prints out both actual and expected values.
- * @name equal
- * @function
- * @example equal( format( "Received {0} bytes.", 2), "Received 2 bytes.", "format() replaces {0} with next argument" );
- */
- equal: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected == actual, actual, expected, message );
- },
-
- /**
- * @name notEqual
- * @function
- */
- notEqual: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected != actual, actual, expected, message );
- },
-
- /**
- * @name propEqual
- * @function
- */
- propEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notPropEqual
- * @function
- */
- notPropEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name deepEqual
- * @function
- */
- deepEqual: function( actual, expected, message ) {
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notDeepEqual
- * @function
- */
- notDeepEqual: function( actual, expected, message ) {
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name strictEqual
- * @function
- */
- strictEqual: function( actual, expected, message ) {
- QUnit.push( expected === actual, actual, expected, message );
- },
-
- /**
- * @name notStrictEqual
- * @function
- */
- notStrictEqual: function( actual, expected, message ) {
- QUnit.push( expected !== actual, actual, expected, message );
- },
-
- "throws": function( block, expected, message ) {
- var actual,
- expectedOutput = expected,
- ok = false;
-
- // 'expected' is optional
- if ( typeof expected === "string" ) {
- message = expected;
- expected = null;
- }
-
- config.current.ignoreGlobalErrors = true;
- try {
- block.call( config.current.testEnvironment );
- } catch (e) {
- actual = e;
- }
- config.current.ignoreGlobalErrors = false;
-
- if ( actual ) {
- // we don't want to validate thrown error
- if ( !expected ) {
- ok = true;
- expectedOutput = null;
- // expected is a regexp
- } else if ( QUnit.objectType( expected ) === "regexp" ) {
- ok = expected.test( errorString( actual ) );
- // expected is a constructor
- } else if ( actual instanceof expected ) {
- ok = true;
- // expected is a validation function which returns true is validation passed
- } else if ( expected.call( {}, actual ) === true ) {
- expectedOutput = null;
- ok = true;
- }
-
- QUnit.push( ok, actual, expectedOutput, message );
- } else {
- QUnit.pushFailure( message, null, 'No exception was thrown.' );
- }
- }
-};
-
-/**
- * @deprecate since 1.8.0
- * Kept assertion helpers in root for backwards compatibility.
- */
-extend( QUnit, assert );
-
-/**
- * @deprecated since 1.9.0
- * Kept root "raises()" for backwards compatibility.
- * (Note that we don't introduce assert.raises).
- */
-QUnit.raises = assert[ "throws" ];
-
-/**
- * @deprecated since 1.0.0, replaced with error pushes since 1.3.0
- * Kept to avoid TypeErrors for undefined methods.
- */
-QUnit.equals = function() {
- QUnit.push( false, false, false, "QUnit.equals has been deprecated since 2009 (e88049a0), use QUnit.equal instead" );
-};
-QUnit.same = function() {
- QUnit.push( false, false, false, "QUnit.same has been deprecated since 2009 (e88049a0), use QUnit.deepEqual instead" );
-};
-
-// We want access to the constructor's prototype
-(function() {
- function F() {}
- F.prototype = QUnit;
- QUnit = new F();
- // Make F QUnit's constructor so that we can add to the prototype later
- QUnit.constructor = F;
-}());
-
-/**
- * Config object: Maintain internal state
- * Later exposed as QUnit.config
- * `config` initialized at top of scope
- */
-config = {
- // The queue of tests to run
- queue: [],
-
- // block until document ready
- blocking: true,
-
- // when enabled, show only failing tests
- // gets persisted through sessionStorage and can be changed in UI via checkbox
- hidepassed: false,
-
- // by default, run previously failed tests first
- // very useful in combination with "Hide passed tests" checked
- reorder: true,
-
- // by default, modify document.title when suite is done
- altertitle: true,
-
- // when enabled, all tests must call expect()
- requireExpects: false,
-
- // add checkboxes that are persisted in the query-string
- // when enabled, the id is set to `true` as a `QUnit.config` property
- urlConfig: [
- {
- id: "noglobals",
- label: "Check for Globals",
- tooltip: "Enabling this will test if any test introduces new properties on the `window` object. Stored as query-strings."
- },
- {
- id: "notrycatch",
- label: "No try-catch",
- tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging exceptions in IE reasonable. Stored as query-strings."
- }
- ],
-
- // Set of all modules.
- modules: {},
-
- // logging callback queues
- begin: [],
- done: [],
- log: [],
- testStart: [],
- testDone: [],
- moduleStart: [],
- moduleDone: []
-};
-
-// Export global variables, unless an 'exports' object exists,
-// in that case we assume we're in CommonJS (dealt with on the bottom of the script)
-if ( typeof exports === "undefined" ) {
- extend( window, QUnit );
-
- // Expose QUnit object
- window.QUnit = QUnit;
-}
-
-// Initialize more QUnit.config and QUnit.urlParams
-(function() {
- var i,
- location = window.location || { search: "", protocol: "file:" },
- params = location.search.slice( 1 ).split( "&" ),
- length = params.length,
- urlParams = {},
- current;
-
- if ( params[ 0 ] ) {
- for ( i = 0; i < length; i++ ) {
- current = params[ i ].split( "=" );
- current[ 0 ] = decodeURIComponent( current[ 0 ] );
- // allow just a key to turn on a flag, e.g., test.html?noglobals
- current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true;
- urlParams[ current[ 0 ] ] = current[ 1 ];
- }
- }
-
- QUnit.urlParams = urlParams;
-
- // String search anywhere in moduleName+testName
- config.filter = urlParams.filter;
-
- // Exact match of the module name
- config.module = urlParams.module;
-
- config.testNumber = parseInt( urlParams.testNumber, 10 ) || null;
-
- // Figure out if we're running the tests from a server or not
- QUnit.isLocal = location.protocol === "file:";
-}());
-
-// Extend QUnit object,
-// these after set here because they should not be exposed as global functions
-extend( QUnit, {
- assert: assert,
-
- config: config,
-
- // Initialize the configuration options
- init: function() {
- extend( config, {
- stats: { all: 0, bad: 0 },
- moduleStats: { all: 0, bad: 0 },
- started: +new Date(),
- updateRate: 1000,
- blocking: false,
- autostart: true,
- autorun: false,
- filter: "",
- queue: [],
- semaphore: 1
- });
-
- var tests, banner, result,
- qunit = id( "qunit" );
-
- if ( qunit ) {
- qunit.innerHTML =
- "" +
- "" +
- "" +
- "" +
- "
";
- }
-
- tests = id( "qunit-tests" );
- banner = id( "qunit-banner" );
- result = id( "qunit-testresult" );
-
- if ( tests ) {
- tests.innerHTML = "";
- }
-
- if ( banner ) {
- banner.className = "";
- }
-
- if ( result ) {
- result.parentNode.removeChild( result );
- }
-
- if ( tests ) {
- result = document.createElement( "p" );
- result.id = "qunit-testresult";
- result.className = "result";
- tests.parentNode.insertBefore( result, tests );
- result.innerHTML = "Running...
";
- }
- },
-
- // Resets the test setup. Useful for tests that modify the DOM.
- reset: function() {
- var fixture = id( "qunit-fixture" );
- if ( fixture ) {
- fixture.innerHTML = config.fixture;
- }
- },
-
- // Trigger an event on an element.
- // @example triggerEvent( document.body, "click" );
- triggerEvent: function( elem, type, event ) {
- if ( document.createEvent ) {
- event = document.createEvent( "MouseEvents" );
- event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView,
- 0, 0, 0, 0, 0, false, false, false, false, 0, null);
-
- elem.dispatchEvent( event );
- } else if ( elem.fireEvent ) {
- elem.fireEvent( "on" + type );
- }
- },
-
- // Safe object type checking
- is: function( type, obj ) {
- return QUnit.objectType( obj ) === type;
- },
-
- objectType: function( obj ) {
- if ( typeof obj === "undefined" ) {
- return "undefined";
- // consider: typeof null === object
- }
- if ( obj === null ) {
- return "null";
- }
-
- var match = toString.call( obj ).match(/^\[object\s(.*)\]$/),
- type = match && match[1] || "";
-
- switch ( type ) {
- case "Number":
- if ( isNaN(obj) ) {
- return "nan";
- }
- return "number";
- case "String":
- case "Boolean":
- case "Array":
- case "Date":
- case "RegExp":
- case "Function":
- return type.toLowerCase();
- }
- if ( typeof obj === "object" ) {
- return "object";
- }
- return undefined;
- },
-
- push: function( result, actual, expected, message ) {
- if ( !config.current ) {
- throw new Error( "assertion outside test context, was " + sourceFromStacktrace() );
- }
-
- var output, source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: message,
- actual: actual,
- expected: expected
- };
-
- message = escapeText( message ) || ( result ? "okay" : "failed" );
- message = "" + message + "";
- output = message;
-
- if ( !result ) {
- expected = escapeText( QUnit.jsDump.parse(expected) );
- actual = escapeText( QUnit.jsDump.parse(actual) );
- output += "Expected: | " + expected + " |
";
-
- if ( actual !== expected ) {
- output += "Result: | " + actual + " |
";
- output += "Diff: | " + QUnit.diff( expected, actual ) + " |
";
- }
-
- source = sourceFromStacktrace();
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
- }
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: !!result,
- message: output
- });
- },
-
- pushFailure: function( message, source, actual ) {
- if ( !config.current ) {
- throw new Error( "pushFailure() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
-
- var output,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: false,
- message: message
- };
-
- message = escapeText( message ) || "error";
- message = "" + message + "";
- output = message;
-
- output += "";
-
- if ( actual ) {
- output += "Result: | " + escapeText( actual ) + " |
";
- }
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: false,
- message: output
- });
- },
-
- url: function( params ) {
- params = extend( extend( {}, QUnit.urlParams ), params );
- var key,
- querystring = "?";
-
- for ( key in params ) {
- if ( !hasOwn.call( params, key ) ) {
- continue;
- }
- querystring += encodeURIComponent( key ) + "=" +
- encodeURIComponent( params[ key ] ) + "&";
- }
- return window.location.protocol + "//" + window.location.host +
- window.location.pathname + querystring.slice( 0, -1 );
- },
-
- extend: extend,
- id: id,
- addEvent: addEvent
- // load, equiv, jsDump, diff: Attached later
-});
-
-/**
- * @deprecated: Created for backwards compatibility with test runner that set the hook function
- * into QUnit.{hook}, instead of invoking it and passing the hook function.
- * QUnit.constructor is set to the empty F() above so that we can add to it's prototype here.
- * Doing this allows us to tell if the following methods have been overwritten on the actual
- * QUnit object.
- */
-extend( QUnit.constructor.prototype, {
-
- // Logging callbacks; all receive a single argument with the listed properties
- // run test/logs.html for any related changes
- begin: registerLoggingCallback( "begin" ),
-
- // done: { failed, passed, total, runtime }
- done: registerLoggingCallback( "done" ),
-
- // log: { result, actual, expected, message }
- log: registerLoggingCallback( "log" ),
-
- // testStart: { name }
- testStart: registerLoggingCallback( "testStart" ),
-
- // testDone: { name, failed, passed, total, duration }
- testDone: registerLoggingCallback( "testDone" ),
-
- // moduleStart: { name }
- moduleStart: registerLoggingCallback( "moduleStart" ),
-
- // moduleDone: { name, failed, passed, total }
- moduleDone: registerLoggingCallback( "moduleDone" )
-});
-
-if ( typeof document === "undefined" || document.readyState === "complete" ) {
- config.autorun = true;
-}
-
-QUnit.load = function() {
- runLoggingCallbacks( "begin", QUnit, {} );
-
- // Initialize the config, saving the execution queue
- var banner, filter, i, label, len, main, ol, toolbar, userAgent, val,
- urlConfigCheckboxesContainer, urlConfigCheckboxes, moduleFilter,
- numModules = 0,
- moduleFilterHtml = "",
- urlConfigHtml = "",
- oldconfig = extend( {}, config );
-
- QUnit.init();
- extend(config, oldconfig);
-
- config.blocking = false;
-
- len = config.urlConfig.length;
-
- for ( i = 0; i < len; i++ ) {
- val = config.urlConfig[i];
- if ( typeof val === "string" ) {
- val = {
- id: val,
- label: val,
- tooltip: "[no tooltip available]"
- };
- }
- config[ val.id ] = QUnit.urlParams[ val.id ];
- urlConfigHtml += "";
- }
-
- moduleFilterHtml += "";
-
- // `userAgent` initialized at top of scope
- userAgent = id( "qunit-userAgent" );
- if ( userAgent ) {
- userAgent.innerHTML = navigator.userAgent;
- }
-
- // `banner` initialized at top of scope
- banner = id( "qunit-header" );
- if ( banner ) {
- banner.innerHTML = "" + banner.innerHTML + " ";
- }
-
- // `toolbar` initialized at top of scope
- toolbar = id( "qunit-testrunner-toolbar" );
- if ( toolbar ) {
- // `filter` initialized at top of scope
- filter = document.createElement( "input" );
- filter.type = "checkbox";
- filter.id = "qunit-filter-pass";
-
- addEvent( filter, "click", function() {
- var tmp,
- ol = document.getElementById( "qunit-tests" );
-
- if ( filter.checked ) {
- ol.className = ol.className + " hidepass";
- } else {
- tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " ";
- ol.className = tmp.replace( / hidepass /, " " );
- }
- if ( defined.sessionStorage ) {
- if (filter.checked) {
- sessionStorage.setItem( "qunit-filter-passed-tests", "true" );
- } else {
- sessionStorage.removeItem( "qunit-filter-passed-tests" );
- }
- }
- });
-
- if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem( "qunit-filter-passed-tests" ) ) {
- filter.checked = true;
- // `ol` initialized at top of scope
- ol = document.getElementById( "qunit-tests" );
- ol.className = ol.className + " hidepass";
- }
- toolbar.appendChild( filter );
-
- // `label` initialized at top of scope
- label = document.createElement( "label" );
- label.setAttribute( "for", "qunit-filter-pass" );
- label.setAttribute( "title", "Only show tests and assertons that fail. Stored in sessionStorage." );
- label.innerHTML = "Hide passed tests";
- toolbar.appendChild( label );
-
- urlConfigCheckboxesContainer = document.createElement("span");
- urlConfigCheckboxesContainer.innerHTML = urlConfigHtml;
- urlConfigCheckboxes = urlConfigCheckboxesContainer.getElementsByTagName("input");
- // For oldIE support:
- // * Add handlers to the individual elements instead of the container
- // * Use "click" instead of "change"
- // * Fallback from event.target to event.srcElement
- addEvents( urlConfigCheckboxes, "click", function( event ) {
- var params = {},
- target = event.target || event.srcElement;
- params[ target.name ] = target.checked ? true : undefined;
- window.location = QUnit.url( params );
- });
- toolbar.appendChild( urlConfigCheckboxesContainer );
-
- if (numModules > 1) {
- moduleFilter = document.createElement( 'span' );
- moduleFilter.setAttribute( 'id', 'qunit-modulefilter-container' );
- moduleFilter.innerHTML = moduleFilterHtml;
- addEvent( moduleFilter.lastChild, "change", function() {
- var selectBox = moduleFilter.getElementsByTagName("select")[0],
- selectedModule = decodeURIComponent(selectBox.options[selectBox.selectedIndex].value);
-
- window.location = QUnit.url( { module: ( selectedModule === "" ) ? undefined : selectedModule } );
- });
- toolbar.appendChild(moduleFilter);
- }
- }
-
- // `main` initialized at top of scope
- main = id( "qunit-fixture" );
- if ( main ) {
- config.fixture = main.innerHTML;
- }
-
- if ( config.autostart ) {
- QUnit.start();
- }
-};
-
-addEvent( window, "load", QUnit.load );
-
-// `onErrorFnPrev` initialized at top of scope
-// Preserve other handlers
-onErrorFnPrev = window.onerror;
-
-// Cover uncaught exceptions
-// Returning true will surpress the default browser handler,
-// returning false will let it run.
-window.onerror = function ( error, filePath, linerNr ) {
- var ret = false;
- if ( onErrorFnPrev ) {
- ret = onErrorFnPrev( error, filePath, linerNr );
- }
-
- // Treat return value as window.onerror itself does,
- // Only do our handling if not surpressed.
- if ( ret !== true ) {
- if ( QUnit.config.current ) {
- if ( QUnit.config.current.ignoreGlobalErrors ) {
- return true;
- }
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- } else {
- QUnit.test( "global failure", extend( function() {
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- }, { validTest: validTest } ) );
- }
- return false;
- }
-
- return ret;
-};
-
-function done() {
- config.autorun = true;
-
- // Log the last module results
- if ( config.currentModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.currentModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
-
- var i, key,
- banner = id( "qunit-banner" ),
- tests = id( "qunit-tests" ),
- runtime = +new Date() - config.started,
- passed = config.stats.all - config.stats.bad,
- html = [
- "Tests completed in ",
- runtime,
- " milliseconds.
",
- "",
- passed,
- " assertions of ",
- config.stats.all,
- " passed, ",
- config.stats.bad,
- " failed."
- ].join( "" );
-
- if ( banner ) {
- banner.className = ( config.stats.bad ? "qunit-fail" : "qunit-pass" );
- }
-
- if ( tests ) {
- id( "qunit-testresult" ).innerHTML = html;
- }
-
- if ( config.altertitle && typeof document !== "undefined" && document.title ) {
- // show ✖ for good, ✔ for bad suite result in title
- // use escape sequences in case file gets loaded with non-utf-8-charset
- document.title = [
- ( config.stats.bad ? "\u2716" : "\u2714" ),
- document.title.replace( /^[\u2714\u2716] /i, "" )
- ].join( " " );
- }
-
- // clear own sessionStorage items if all tests passed
- if ( config.reorder && defined.sessionStorage && config.stats.bad === 0 ) {
- // `key` & `i` initialized at top of scope
- for ( i = 0; i < sessionStorage.length; i++ ) {
- key = sessionStorage.key( i++ );
- if ( key.indexOf( "qunit-test-" ) === 0 ) {
- sessionStorage.removeItem( key );
- }
- }
- }
-
- // scroll back to top to show results
- if ( window.scrollTo ) {
- window.scrollTo(0, 0);
- }
-
- runLoggingCallbacks( "done", QUnit, {
- failed: config.stats.bad,
- passed: passed,
- total: config.stats.all,
- runtime: runtime
- });
-}
-
-/** @return Boolean: true if this test should be ran */
-function validTest( test ) {
- var include,
- filter = config.filter && config.filter.toLowerCase(),
- module = config.module && config.module.toLowerCase(),
- fullName = (test.module + ": " + test.testName).toLowerCase();
-
- // Internally-generated tests are always valid
- if ( test.callback && test.callback.validTest === validTest ) {
- delete test.callback.validTest;
- return true;
- }
-
- if ( config.testNumber ) {
- return test.testNumber === config.testNumber;
- }
-
- if ( module && ( !test.module || test.module.toLowerCase() !== module ) ) {
- return false;
- }
-
- if ( !filter ) {
- return true;
- }
-
- include = filter.charAt( 0 ) !== "!";
- if ( !include ) {
- filter = filter.slice( 1 );
- }
-
- // If the filter matches, we need to honour include
- if ( fullName.indexOf( filter ) !== -1 ) {
- return include;
- }
-
- // Otherwise, do the opposite
- return !include;
-}
-
-// so far supports only Firefox, Chrome and Opera (buggy), Safari (for real exceptions)
-// Later Safari and IE10 are supposed to support error.stack as well
-// See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack
-function extractStacktrace( e, offset ) {
- offset = offset === undefined ? 3 : offset;
-
- var stack, include, i;
-
- if ( e.stacktrace ) {
- // Opera
- return e.stacktrace.split( "\n" )[ offset + 3 ];
- } else if ( e.stack ) {
- // Firefox, Chrome
- stack = e.stack.split( "\n" );
- if (/^error$/i.test( stack[0] ) ) {
- stack.shift();
- }
- if ( fileName ) {
- include = [];
- for ( i = offset; i < stack.length; i++ ) {
- if ( stack[ i ].indexOf( fileName ) !== -1 ) {
- break;
- }
- include.push( stack[ i ] );
- }
- if ( include.length ) {
- return include.join( "\n" );
- }
- }
- return stack[ offset ];
- } else if ( e.sourceURL ) {
- // Safari, PhantomJS
- // hopefully one day Safari provides actual stacktraces
- // exclude useless self-reference for generated Error objects
- if ( /qunit.js$/.test( e.sourceURL ) ) {
- return;
- }
- // for actual exceptions, this is useful
- return e.sourceURL + ":" + e.line;
- }
-}
-function sourceFromStacktrace( offset ) {
- try {
- throw new Error();
- } catch ( e ) {
- return extractStacktrace( e, offset );
- }
-}
-
-/**
- * Escape text for attribute or text content.
- */
-function escapeText( s ) {
- if ( !s ) {
- return "";
- }
- s = s + "";
- // Both single quotes and double quotes (for attributes)
- return s.replace( /['"<>&]/g, function( s ) {
- switch( s ) {
- case '\'':
- return ''';
- case '"':
- return '"';
- case '<':
- return '<';
- case '>':
- return '>';
- case '&':
- return '&';
- }
- });
-}
-
-function synchronize( callback, last ) {
- config.queue.push( callback );
-
- if ( config.autorun && !config.blocking ) {
- process( last );
- }
-}
-
-function process( last ) {
- function next() {
- process( last );
- }
- var start = new Date().getTime();
- config.depth = config.depth ? config.depth + 1 : 1;
-
- while ( config.queue.length && !config.blocking ) {
- if ( !defined.setTimeout || config.updateRate <= 0 || ( ( new Date().getTime() - start ) < config.updateRate ) ) {
- config.queue.shift()();
- } else {
- window.setTimeout( next, 13 );
- break;
- }
- }
- config.depth--;
- if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) {
- done();
- }
-}
-
-function saveGlobal() {
- config.pollution = [];
-
- if ( config.noglobals ) {
- for ( var key in window ) {
- // in Opera sometimes DOM element ids show up here, ignore them
- if ( !hasOwn.call( window, key ) || /^qunit-test-output/.test( key ) ) {
- continue;
- }
- config.pollution.push( key );
- }
- }
-}
-
-function checkPollution() {
- var newGlobals,
- deletedGlobals,
- old = config.pollution;
-
- saveGlobal();
-
- newGlobals = diff( config.pollution, old );
- if ( newGlobals.length > 0 ) {
- QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join(", ") );
- }
-
- deletedGlobals = diff( old, config.pollution );
- if ( deletedGlobals.length > 0 ) {
- QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join(", ") );
- }
-}
-
-// returns a new Array with the elements that are in a but not in b
-function diff( a, b ) {
- var i, j,
- result = a.slice();
-
- for ( i = 0; i < result.length; i++ ) {
- for ( j = 0; j < b.length; j++ ) {
- if ( result[i] === b[j] ) {
- result.splice( i, 1 );
- i--;
- break;
- }
- }
- }
- return result;
-}
-
-function extend( a, b ) {
- for ( var prop in b ) {
- if ( b[ prop ] === undefined ) {
- delete a[ prop ];
-
- // Avoid "Member not found" error in IE8 caused by setting window.constructor
- } else if ( prop !== "constructor" || a !== window ) {
- a[ prop ] = b[ prop ];
- }
- }
-
- return a;
-}
-
-/**
- * @param {HTMLElement} elem
- * @param {string} type
- * @param {Function} fn
- */
-function addEvent( elem, type, fn ) {
- // Standards-based browsers
- if ( elem.addEventListener ) {
- elem.addEventListener( type, fn, false );
- // IE
- } else {
- elem.attachEvent( "on" + type, fn );
- }
-}
-
-/**
- * @param {Array|NodeList} elems
- * @param {string} type
- * @param {Function} fn
- */
-function addEvents( elems, type, fn ) {
- var i = elems.length;
- while ( i-- ) {
- addEvent( elems[i], type, fn );
- }
-}
-
-function hasClass( elem, name ) {
- return (" " + elem.className + " ").indexOf(" " + name + " ") > -1;
-}
-
-function addClass( elem, name ) {
- if ( !hasClass( elem, name ) ) {
- elem.className += (elem.className ? " " : "") + name;
- }
-}
-
-function removeClass( elem, name ) {
- var set = " " + elem.className + " ";
- // Class name may appear multiple times
- while ( set.indexOf(" " + name + " ") > -1 ) {
- set = set.replace(" " + name + " " , " ");
- }
- // If possible, trim it for prettiness, but not neccecarily
- elem.className = window.jQuery ? jQuery.trim( set ) : ( set.trim ? set.trim() : set );
-}
-
-function id( name ) {
- return !!( typeof document !== "undefined" && document && document.getElementById ) &&
- document.getElementById( name );
-}
-
-function registerLoggingCallback( key ) {
- return function( callback ) {
- config[key].push( callback );
- };
-}
-
-// Supports deprecated method of completely overwriting logging callbacks
-function runLoggingCallbacks( key, scope, args ) {
- var i, callbacks;
- if ( QUnit.hasOwnProperty( key ) ) {
- QUnit[ key ].call(scope, args );
- } else {
- callbacks = config[ key ];
- for ( i = 0; i < callbacks.length; i++ ) {
- callbacks[ i ].call( scope, args );
- }
- }
-}
-
-// Test for equality any JavaScript type.
-// Author: Philippe Rathé
-QUnit.equiv = (function() {
-
- // Call the o related callback with the given arguments.
- function bindCallbacks( o, callbacks, args ) {
- var prop = QUnit.objectType( o );
- if ( prop ) {
- if ( QUnit.objectType( callbacks[ prop ] ) === "function" ) {
- return callbacks[ prop ].apply( callbacks, args );
- } else {
- return callbacks[ prop ]; // or undefined
- }
- }
- }
-
- // the real equiv function
- var innerEquiv,
- // stack to decide between skip/abort functions
- callers = [],
- // stack to avoiding loops from circular referencing
- parents = [],
-
- getProto = Object.getPrototypeOf || function ( obj ) {
- return obj.__proto__;
- },
- callbacks = (function () {
-
- // for string, boolean, number and null
- function useStrictEquality( b, a ) {
- /*jshint eqeqeq:false */
- if ( b instanceof a.constructor || a instanceof b.constructor ) {
- // to catch short annotaion VS 'new' annotation of a
- // declaration
- // e.g. var i = 1;
- // var j = new Number(1);
- return a == b;
- } else {
- return a === b;
- }
- }
-
- return {
- "string": useStrictEquality,
- "boolean": useStrictEquality,
- "number": useStrictEquality,
- "null": useStrictEquality,
- "undefined": useStrictEquality,
-
- "nan": function( b ) {
- return isNaN( b );
- },
-
- "date": function( b, a ) {
- return QUnit.objectType( b ) === "date" && a.valueOf() === b.valueOf();
- },
-
- "regexp": function( b, a ) {
- return QUnit.objectType( b ) === "regexp" &&
- // the regex itself
- a.source === b.source &&
- // and its modifers
- a.global === b.global &&
- // (gmi) ...
- a.ignoreCase === b.ignoreCase &&
- a.multiline === b.multiline &&
- a.sticky === b.sticky;
- },
-
- // - skip when the property is a method of an instance (OOP)
- // - abort otherwise,
- // initial === would have catch identical references anyway
- "function": function() {
- var caller = callers[callers.length - 1];
- return caller !== Object && typeof caller !== "undefined";
- },
-
- "array": function( b, a ) {
- var i, j, len, loop;
-
- // b could be an object literal here
- if ( QUnit.objectType( b ) !== "array" ) {
- return false;
- }
-
- len = a.length;
- if ( len !== b.length ) {
- // safe and faster
- return false;
- }
-
- // track reference to avoid circular references
- parents.push( a );
- for ( i = 0; i < len; i++ ) {
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- loop = true;// dont rewalk array
- }
- }
- if ( !loop && !innerEquiv(a[i], b[i]) ) {
- parents.pop();
- return false;
- }
- }
- parents.pop();
- return true;
- },
-
- "object": function( b, a ) {
- var i, j, loop,
- // Default to true
- eq = true,
- aProperties = [],
- bProperties = [];
-
- // comparing constructors is more strict than using
- // instanceof
- if ( a.constructor !== b.constructor ) {
- // Allow objects with no prototype to be equivalent to
- // objects with Object as their constructor.
- if ( !(( getProto(a) === null && getProto(b) === Object.prototype ) ||
- ( getProto(b) === null && getProto(a) === Object.prototype ) ) ) {
- return false;
- }
- }
-
- // stack constructor before traversing properties
- callers.push( a.constructor );
- // track reference to avoid circular references
- parents.push( a );
-
- for ( i in a ) { // be strict: don't ensures hasOwnProperty
- // and go deep
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- // don't go down the same path twice
- loop = true;
- }
- }
- aProperties.push(i); // collect a's properties
-
- if (!loop && !innerEquiv( a[i], b[i] ) ) {
- eq = false;
- break;
- }
- }
-
- callers.pop(); // unstack, we are done
- parents.pop();
-
- for ( i in b ) {
- bProperties.push( i ); // collect b's properties
- }
-
- // Ensures identical properties name
- return eq && innerEquiv( aProperties.sort(), bProperties.sort() );
- }
- };
- }());
-
- innerEquiv = function() { // can take multiple arguments
- var args = [].slice.apply( arguments );
- if ( args.length < 2 ) {
- return true; // end transition
- }
-
- return (function( a, b ) {
- if ( a === b ) {
- return true; // catch the most you can
- } else if ( a === null || b === null || typeof a === "undefined" ||
- typeof b === "undefined" ||
- QUnit.objectType(a) !== QUnit.objectType(b) ) {
- return false; // don't lose time with error prone cases
- } else {
- return bindCallbacks(a, callbacks, [ b, a ]);
- }
-
- // apply transition with (1..n) arguments
- }( args[0], args[1] ) && arguments.callee.apply( this, args.splice(1, args.length - 1 )) );
- };
-
- return innerEquiv;
-}());
-
-/**
- * jsDump Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com |
- * http://flesler.blogspot.com Licensed under BSD
- * (http://www.opensource.org/licenses/bsd-license.php) Date: 5/15/2008
- *
- * @projectDescription Advanced and extensible data dumping for Javascript.
- * @version 1.0.0
- * @author Ariel Flesler
- * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html}
- */
-QUnit.jsDump = (function() {
- function quote( str ) {
- return '"' + str.toString().replace( /"/g, '\\"' ) + '"';
- }
- function literal( o ) {
- return o + "";
- }
- function join( pre, arr, post ) {
- var s = jsDump.separator(),
- base = jsDump.indent(),
- inner = jsDump.indent(1);
- if ( arr.join ) {
- arr = arr.join( "," + s + inner );
- }
- if ( !arr ) {
- return pre + post;
- }
- return [ pre, inner + arr, base + post ].join(s);
- }
- function array( arr, stack ) {
- var i = arr.length, ret = new Array(i);
- this.up();
- while ( i-- ) {
- ret[i] = this.parse( arr[i] , undefined , stack);
- }
- this.down();
- return join( "[", ret, "]" );
- }
-
- var reName = /^function (\w+)/,
- jsDump = {
- // type is used mostly internally, you can fix a (custom)type in advance
- parse: function( obj, type, stack ) {
- stack = stack || [ ];
- var inStack, res,
- parser = this.parsers[ type || this.typeOf(obj) ];
-
- type = typeof parser;
- inStack = inArray( obj, stack );
-
- if ( inStack !== -1 ) {
- return "recursion(" + (inStack - stack.length) + ")";
- }
- if ( type === "function" ) {
- stack.push( obj );
- res = parser.call( this, obj, stack );
- stack.pop();
- return res;
- }
- return ( type === "string" ) ? parser : this.parsers.error;
- },
- typeOf: function( obj ) {
- var type;
- if ( obj === null ) {
- type = "null";
- } else if ( typeof obj === "undefined" ) {
- type = "undefined";
- } else if ( QUnit.is( "regexp", obj) ) {
- type = "regexp";
- } else if ( QUnit.is( "date", obj) ) {
- type = "date";
- } else if ( QUnit.is( "function", obj) ) {
- type = "function";
- } else if ( typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined" ) {
- type = "window";
- } else if ( obj.nodeType === 9 ) {
- type = "document";
- } else if ( obj.nodeType ) {
- type = "node";
- } else if (
- // native arrays
- toString.call( obj ) === "[object Array]" ||
- // NodeList objects
- ( typeof obj.length === "number" && typeof obj.item !== "undefined" && ( obj.length ? obj.item(0) === obj[0] : ( obj.item( 0 ) === null && typeof obj[0] === "undefined" ) ) )
- ) {
- type = "array";
- } else if ( obj.constructor === Error.prototype.constructor ) {
- type = "error";
- } else {
- type = typeof obj;
- }
- return type;
- },
- separator: function() {
- return this.multiline ? this.HTML ? "
" : "\n" : this.HTML ? " " : " ";
- },
- // extra can be a number, shortcut for increasing-calling-decreasing
- indent: function( extra ) {
- if ( !this.multiline ) {
- return "";
- }
- var chr = this.indentChar;
- if ( this.HTML ) {
- chr = chr.replace( /\t/g, " " ).replace( / /g, " " );
- }
- return new Array( this._depth_ + (extra||0) ).join(chr);
- },
- up: function( a ) {
- this._depth_ += a || 1;
- },
- down: function( a ) {
- this._depth_ -= a || 1;
- },
- setParser: function( name, parser ) {
- this.parsers[name] = parser;
- },
- // The next 3 are exposed so you can use them
- quote: quote,
- literal: literal,
- join: join,
- //
- _depth_: 1,
- // This is the list of parsers, to modify them, use jsDump.setParser
- parsers: {
- window: "[Window]",
- document: "[Document]",
- error: function(error) {
- return "Error(\"" + error.message + "\")";
- },
- unknown: "[Unknown]",
- "null": "null",
- "undefined": "undefined",
- "function": function( fn ) {
- var ret = "function",
- // functions never have name in IE
- name = "name" in fn ? fn.name : (reName.exec(fn) || [])[1];
-
- if ( name ) {
- ret += " " + name;
- }
- ret += "( ";
-
- ret = [ ret, QUnit.jsDump.parse( fn, "functionArgs" ), "){" ].join( "" );
- return join( ret, QUnit.jsDump.parse(fn,"functionCode" ), "}" );
- },
- array: array,
- nodelist: array,
- "arguments": array,
- object: function( map, stack ) {
- var ret = [ ], keys, key, val, i;
- QUnit.jsDump.up();
- keys = [];
- for ( key in map ) {
- keys.push( key );
- }
- keys.sort();
- for ( i = 0; i < keys.length; i++ ) {
- key = keys[ i ];
- val = map[ key ];
- ret.push( QUnit.jsDump.parse( key, "key" ) + ": " + QUnit.jsDump.parse( val, undefined, stack ) );
- }
- QUnit.jsDump.down();
- return join( "{", ret, "}" );
- },
- node: function( node ) {
- var len, i, val,
- open = QUnit.jsDump.HTML ? "<" : "<",
- close = QUnit.jsDump.HTML ? ">" : ">",
- tag = node.nodeName.toLowerCase(),
- ret = open + tag,
- attrs = node.attributes;
-
- if ( attrs ) {
- for ( i = 0, len = attrs.length; i < len; i++ ) {
- val = attrs[i].nodeValue;
- // IE6 includes all attributes in .attributes, even ones not explicitly set.
- // Those have values like undefined, null, 0, false, "" or "inherit".
- if ( val && val !== "inherit" ) {
- ret += " " + attrs[i].nodeName + "=" + QUnit.jsDump.parse( val, "attribute" );
- }
- }
- }
- ret += close;
-
- // Show content of TextNode or CDATASection
- if ( node.nodeType === 3 || node.nodeType === 4 ) {
- ret += node.nodeValue;
- }
-
- return ret + open + "/" + tag + close;
- },
- // function calls it internally, it's the arguments part of the function
- functionArgs: function( fn ) {
- var args,
- l = fn.length;
-
- if ( !l ) {
- return "";
- }
-
- args = new Array(l);
- while ( l-- ) {
- // 97 is 'a'
- args[l] = String.fromCharCode(97+l);
- }
- return " " + args.join( ", " ) + " ";
- },
- // object calls it internally, the key part of an item in a map
- key: quote,
- // function calls it internally, it's the content of the function
- functionCode: "[code]",
- // node calls it internally, it's an html attribute value
- attribute: quote,
- string: quote,
- date: quote,
- regexp: literal,
- number: literal,
- "boolean": literal
- },
- // if true, entities are escaped ( <, >, \t, space and \n )
- HTML: false,
- // indentation unit
- indentChar: " ",
- // if true, items in a collection, are separated by a \n, else just a space.
- multiline: true
- };
-
- return jsDump;
-}());
-
-// from jquery.js
-function inArray( elem, array ) {
- if ( array.indexOf ) {
- return array.indexOf( elem );
- }
-
- for ( var i = 0, length = array.length; i < length; i++ ) {
- if ( array[ i ] === elem ) {
- return i;
- }
- }
-
- return -1;
-}
-
-/*
- * Javascript Diff Algorithm
- * By John Resig (http://ejohn.org/)
- * Modified by Chu Alan "sprite"
- *
- * Released under the MIT license.
- *
- * More Info:
- * http://ejohn.org/projects/javascript-diff-algorithm/
- *
- * Usage: QUnit.diff(expected, actual)
- *
- * QUnit.diff( "the quick brown fox jumped over", "the quick fox jumps over" ) == "the quick brown fox jumped jumps over"
- */
-QUnit.diff = (function() {
- /*jshint eqeqeq:false, eqnull:true */
- function diff( o, n ) {
- var i,
- ns = {},
- os = {};
-
- for ( i = 0; i < n.length; i++ ) {
- if ( !hasOwn.call( ns, n[i] ) ) {
- ns[ n[i] ] = {
- rows: [],
- o: null
- };
- }
- ns[ n[i] ].rows.push( i );
- }
-
- for ( i = 0; i < o.length; i++ ) {
- if ( !hasOwn.call( os, o[i] ) ) {
- os[ o[i] ] = {
- rows: [],
- n: null
- };
- }
- os[ o[i] ].rows.push( i );
- }
-
- for ( i in ns ) {
- if ( !hasOwn.call( ns, i ) ) {
- continue;
- }
- if ( ns[i].rows.length === 1 && hasOwn.call( os, i ) && os[i].rows.length === 1 ) {
- n[ ns[i].rows[0] ] = {
- text: n[ ns[i].rows[0] ],
- row: os[i].rows[0]
- };
- o[ os[i].rows[0] ] = {
- text: o[ os[i].rows[0] ],
- row: ns[i].rows[0]
- };
- }
- }
-
- for ( i = 0; i < n.length - 1; i++ ) {
- if ( n[i].text != null && n[ i + 1 ].text == null && n[i].row + 1 < o.length && o[ n[i].row + 1 ].text == null &&
- n[ i + 1 ] == o[ n[i].row + 1 ] ) {
-
- n[ i + 1 ] = {
- text: n[ i + 1 ],
- row: n[i].row + 1
- };
- o[ n[i].row + 1 ] = {
- text: o[ n[i].row + 1 ],
- row: i + 1
- };
- }
- }
-
- for ( i = n.length - 1; i > 0; i-- ) {
- if ( n[i].text != null && n[ i - 1 ].text == null && n[i].row > 0 && o[ n[i].row - 1 ].text == null &&
- n[ i - 1 ] == o[ n[i].row - 1 ]) {
-
- n[ i - 1 ] = {
- text: n[ i - 1 ],
- row: n[i].row - 1
- };
- o[ n[i].row - 1 ] = {
- text: o[ n[i].row - 1 ],
- row: i - 1
- };
- }
- }
-
- return {
- o: o,
- n: n
- };
- }
-
- return function( o, n ) {
- o = o.replace( /\s+$/, "" );
- n = n.replace( /\s+$/, "" );
-
- var i, pre,
- str = "",
- out = diff( o === "" ? [] : o.split(/\s+/), n === "" ? [] : n.split(/\s+/) ),
- oSpace = o.match(/\s+/g),
- nSpace = n.match(/\s+/g);
-
- if ( oSpace == null ) {
- oSpace = [ " " ];
- }
- else {
- oSpace.push( " " );
- }
-
- if ( nSpace == null ) {
- nSpace = [ " " ];
- }
- else {
- nSpace.push( " " );
- }
-
- if ( out.n.length === 0 ) {
- for ( i = 0; i < out.o.length; i++ ) {
- str += "" + out.o[i] + oSpace[i] + "";
- }
- }
- else {
- if ( out.n[0].text == null ) {
- for ( n = 0; n < out.o.length && out.o[n].text == null; n++ ) {
- str += "" + out.o[n] + oSpace[n] + "";
- }
- }
-
- for ( i = 0; i < out.n.length; i++ ) {
- if (out.n[i].text == null) {
- str += "" + out.n[i] + nSpace[i] + "";
- }
- else {
- // `pre` initialized at top of scope
- pre = "";
-
- for ( n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++ ) {
- pre += "" + out.o[n] + oSpace[n] + "";
- }
- str += " " + out.n[i].text + nSpace[i] + pre;
- }
- }
- }
-
- return str;
- };
-}());
-
-// for CommonJS enviroments, export everything
-if ( typeof exports !== "undefined" ) {
- extend( exports, QUnit );
-}
-
-// get at whatever the global object is, like window in browsers
-}( (function() {return this;}.call()) ));
diff --git a/test/lib/require.js b/test/lib/require.js
deleted file mode 100644
index 987f865..0000000
--- a/test/lib/require.js
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- RequireJS 2.1.5 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.
- Available via the MIT or new BSD license.
- see: http://github.com/jrburke/requirejs for details
-*/
-var requirejs,require,define;
-(function(aa){function I(b){return"[object Function]"===L.call(b)}function J(b){return"[object Array]"===L.call(b)}function y(b,c){if(b){var d;for(d=0;dthis.depCount&&!this.defined){if(I(n)){if(this.events.error)try{e=i.execCb(c,n,b,e)}catch(d){a=d}else e=i.execCb(c,n,b,e);this.map.isDefine&&((b=this.module)&&void 0!==b.exports&&b.exports!==this.exports?e=b.exports:void 0===e&&this.usingExports&&(e=this.exports));if(a)return a.requireMap=this.map,a.requireModules=[this.map.id],a.requireType="define",v(this.error=
-a)}else e=n;this.exports=e;if(this.map.isDefine&&!this.ignore&&(q[c]=e,l.onResourceLoad))l.onResourceLoad(i,this.map,this.depMaps);x(c);this.defined=!0}this.defining=!1;this.defined&&!this.defineEmitted&&(this.defineEmitted=!0,this.emit("defined",this.exports),this.defineEmitComplete=!0)}}else this.fetch()}},callPlugin:function(){var a=this.map,b=a.id,d=j(a.prefix);this.depMaps.push(d);t(d,"defined",u(this,function(e){var n,d;d=this.map.name;var g=this.map.parentMap?this.map.parentMap.name:null,h=
-i.makeRequire(a.parentMap,{enableBuildCallback:!0});if(this.map.unnormalized){if(e.normalize&&(d=e.normalize(d,function(a){return c(a,g,!0)})||""),e=j(a.prefix+"!"+d,this.map.parentMap),t(e,"defined",u(this,function(a){this.init([],function(){return a},null,{enabled:!0,ignore:!0})})),d=m(p,e.id)){this.depMaps.push(e);if(this.events.error)d.on("error",u(this,function(a){this.emit("error",a)}));d.enable()}}else n=u(this,function(a){this.init([],function(){return a},null,{enabled:!0})}),n.error=u(this,
-function(a){this.inited=!0;this.error=a;a.requireModules=[b];G(p,function(a){0===a.map.id.indexOf(b+"_unnormalized")&&x(a.map.id)});v(a)}),n.fromText=u(this,function(e,c){var d=a.name,g=j(d),C=O;c&&(e=c);C&&(O=!1);r(g);s(k.config,b)&&(k.config[d]=k.config[b]);try{l.exec(e)}catch(ca){return v(B("fromtexteval","fromText eval for "+b+" failed: "+ca,ca,[b]))}C&&(O=!0);this.depMaps.push(g);i.completeLoad(d);h([d],n)}),e.load(a.name,h,n,k)}));i.enable(d,this);this.pluginMaps[d.id]=d},enable:function(){V[this.map.id]=
-this;this.enabling=this.enabled=!0;y(this.depMaps,u(this,function(a,b){var c,e;if("string"===typeof a){a=j(a,this.map.isDefine?this.map:this.map.parentMap,!1,!this.skipMap);this.depMaps[b]=a;if(c=m(N,a.id)){this.depExports[b]=c(this);return}this.depCount+=1;t(a,"defined",u(this,function(a){this.defineDep(b,a);this.check()}));this.errback&&t(a,"error",this.errback)}c=a.id;e=p[c];!s(N,c)&&(e&&!e.enabled)&&i.enable(a,this)}));G(this.pluginMaps,u(this,function(a){var b=m(p,a.id);b&&!b.enabled&&i.enable(a,
-this)}));this.enabling=!1;this.check()},on:function(a,b){var c=this.events[a];c||(c=this.events[a]=[]);c.push(b)},emit:function(a,b){y(this.events[a],function(a){a(b)});"error"===a&&delete this.events[a]}};i={config:k,contextName:b,registry:p,defined:q,urlFetched:U,defQueue:H,Module:Z,makeModuleMap:j,nextTick:l.nextTick,onError:v,configure:function(a){a.baseUrl&&"/"!==a.baseUrl.charAt(a.baseUrl.length-1)&&(a.baseUrl+="/");var b=k.pkgs,c=k.shim,e={paths:!0,config:!0,map:!0};G(a,function(a,b){e[b]?
-"map"===b?(k.map||(k.map={}),R(k[b],a,!0,!0)):R(k[b],a,!0):k[b]=a});a.shim&&(G(a.shim,function(a,b){J(a)&&(a={deps:a});if((a.exports||a.init)&&!a.exportsFn)a.exportsFn=i.makeShimExports(a);c[b]=a}),k.shim=c);a.packages&&(y(a.packages,function(a){a="string"===typeof a?{name:a}:a;b[a.name]={name:a.name,location:a.location||a.name,main:(a.main||"main").replace(ja,"").replace(ea,"")}}),k.pkgs=b);G(p,function(a,b){!a.inited&&!a.map.unnormalized&&(a.map=j(b))});if(a.deps||a.callback)i.require(a.deps||[],
-a.callback)},makeShimExports:function(a){return function(){var b;a.init&&(b=a.init.apply(aa,arguments));return b||a.exports&&ba(a.exports)}},makeRequire:function(a,f){function d(e,c,h){var g,k;f.enableBuildCallback&&(c&&I(c))&&(c.__requireJsBuild=!0);if("string"===typeof e){if(I(c))return v(B("requireargs","Invalid require call"),h);if(a&&s(N,e))return N[e](p[a.id]);if(l.get)return l.get(i,e,a,d);g=j(e,a,!1,!0);g=g.id;return!s(q,g)?v(B("notloaded",'Module name "'+g+'" has not been loaded yet for context: '+
-b+(a?"":". Use require([])"))):q[g]}L();i.nextTick(function(){L();k=r(j(null,a));k.skipMap=f.skipMap;k.init(e,c,h,{enabled:!0});D()});return d}f=f||{};R(d,{isBrowser:A,toUrl:function(b){var d,f=b.lastIndexOf("."),g=b.split("/")[0];if(-1!==f&&(!("."===g||".."===g)||1h.attachEvent.toString().indexOf("[native code"))&&!Y?(O=!0,h.attachEvent("onreadystatechange",b.onScriptLoad)):(h.addEventListener("load",b.onScriptLoad,!1),h.addEventListener("error",b.onScriptError,!1)),h.src=d,K=h,D?x.insertBefore(h,D):x.appendChild(h),K=null,h;if(da)try{importScripts(d),b.completeLoad(c)}catch(j){b.onError(B("importscripts","importScripts failed for "+c+" at "+d,j,[c]))}};A&&M(document.getElementsByTagName("script"),function(b){x||(x=
-b.parentNode);if(t=b.getAttribute("data-main"))return r.baseUrl||(E=t.split("/"),Q=E.pop(),fa=E.length?E.join("/")+"/":"./",r.baseUrl=fa,t=Q),t=t.replace(ea,""),r.deps=r.deps?r.deps.concat(t):[t],!0});define=function(b,c,d){var l,h;"string"!==typeof b&&(d=c,c=b,b=null);J(c)||(d=c,c=[]);!c.length&&I(d)&&d.length&&(d.toString().replace(la,"").replace(ma,function(b,d){c.push(d)}),c=(1===d.length?["require"]:["require","exports","module"]).concat(c));if(O){if(!(l=K))P&&"interactive"===P.readyState||M(document.getElementsByTagName("script"),
-function(b){if("interactive"===b.readyState)return P=b}),l=P;l&&(b||(b=l.getAttribute("data-requiremodule")),h=F[l.getAttribute("data-requirecontext")])}(h?h.defQueue:T).push([b,c,d])};define.amd={jQuery:!0};l.exec=function(b){return eval(b)};l(r)}})(this);
diff --git a/test/lib/resemble.js b/test/lib/resemble.js
new file mode 100644
index 0000000..1cb8c29
--- /dev/null
+++ b/test/lib/resemble.js
@@ -0,0 +1,535 @@
+/*
+Author: James Cryer
+Company: Huddle
+Last updated date: 21 Feb 2013
+URL: https://github.com/Huddle/Resemble.js
+*/
+
+(function(_this){
+ 'use strict';
+
+ _this['resemble'] = function( fileData ){
+
+ var data = {};
+ var images = [];
+ var updateCallbackArray = [];
+
+ var tolerance = { // between 0 and 255
+ red: 16,
+ green: 16,
+ blue: 16,
+ minBrightness: 16,
+ maxBrightness: 240
+ };
+
+ var ignoreAntialiasing = false;
+ var ignoreColors = false;
+
+ function triggerDataUpdate(){
+ var len = updateCallbackArray.length;
+ var i;
+ for(i=0;i tolerance.maxBrightness;
+ }
+
+ function getHue(r,g,b){
+
+ r = r / 255;
+ g = g / 255;
+ b = b / 255;
+ var max = Math.max(r, g, b), min = Math.min(r, g, b);
+ var h;
+ var d;
+
+ if (max == min){
+ h = 0; // achromatic
+ } else{
+ d = max - min;
+ switch(max){
+ case r: h = (g - b) / d + (g < b ? 6 : 0); break;
+ case g: h = (b - r) / d + 2; break;
+ case b: h = (r - g) / d + 4; break;
+ }
+ h /= 6;
+ }
+
+ return h;
+ }
+
+ function isAntialiased(sourcePix, data, cacheSet, verticalPos, horizontalPos, width){
+ var offset;
+ var targetPix;
+ var distance = 1;
+ var i;
+ var j;
+ var hasHighContrastSibling = 0;
+ var hasSiblingWithDifferentHue = 0;
+ var hasEquivilantSibling = 0;
+
+ addHueInfo(sourcePix);
+
+ for (i = distance*-1; i <= distance; i++){
+ for (j = distance*-1; j <= distance; j++){
+
+ if(i===0 && j===0){
+ // ignore source pixel
+ } else {
+
+ offset = ((verticalPos+j)*width + (horizontalPos+i)) * 4;
+ targetPix = getPixelInfo(data, offset, cacheSet);
+
+ if(targetPix === null){
+ continue;
+ }
+
+ addBrightnessInfo(targetPix);
+ addHueInfo(targetPix);
+
+ if( isContrasting(sourcePix, targetPix) ){
+ hasHighContrastSibling++;
+ }
+
+ if( isRGBSame(sourcePix,targetPix) ){
+ hasEquivilantSibling++;
+ }
+
+ if( Math.abs(targetPix.h - sourcePix.h) > 0.3 ){
+ hasSiblingWithDifferentHue++;
+ }
+
+ if( hasSiblingWithDifferentHue > 1 || hasHighContrastSibling > 1){
+ return true;
+ }
+ }
+ }
+ }
+
+ if(hasEquivilantSibling < 2){
+ return true;
+ }
+
+ return false;
+ }
+
+ function errorPixel(px, offset){
+ px[offset] = 255; //r
+ px[offset + 1] = 0; //g
+ px[offset + 2] = 255; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyPixel(px, offset, data){
+ px[offset] = data.r; //r
+ px[offset + 1] = data.g; //g
+ px[offset + 2] = data.b; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyGrayScalePixel(px, offset, data){
+ px[offset] = data.brightness; //r
+ px[offset + 1] = data.brightness; //g
+ px[offset + 2] = data.brightness; //b
+ px[offset + 3] = 255; //a
+ }
+
+
+ function getPixelInfo(data, offset, cacheSet){
+ var r;
+ var g;
+ var b;
+ var d;
+
+ if(typeof data[offset] !== 'undefined'){
+ r = data[offset];
+ g = data[offset+1];
+ b = data[offset+2];
+ d = {
+ r: r,
+ g: g,
+ b: b
+ };
+
+ return d;
+ } else {
+ return null;
+ }
+ }
+
+ function addBrightnessInfo(data){
+ data.brightness = getBrightness(data.r,data.g,data.b); // 'corrected' lightness
+ }
+
+ function addHueInfo(data){
+ data.h = getHue(data.r,data.g,data.b);
+ }
+
+ function analyseImages(img1, img2, width, height){
+
+ var hiddenCanvas = document.createElement('canvas');
+
+ var data1 = img1.data;
+ var data2 = img2.data;
+
+ hiddenCanvas.width = width;
+ hiddenCanvas.height = height;
+
+ var context = hiddenCanvas.getContext('2d');
+ var imgd = context.createImageData(width,height);
+ var targetPix = imgd.data;
+
+ var mismatchCount = 0;
+
+ var time = Date.now();
+
+ var skip;
+
+ if( (width > 1200 || height > 1200) && ignoreAntialiasing){
+ skip = 6;
+ }
+
+ loop(height, width, function(verticalPos, horizontalPos){
+
+ if(skip){ // only skip if the image isn't small
+ if(verticalPos % skip === 0 || horizontalPos % skip === 0){
+ return;
+ }
+ }
+
+ var offset = (verticalPos*width + horizontalPos) * 4;
+ var pixel1 = getPixelInfo(data1, offset, 1);
+ var pixel2 = getPixelInfo(data2, offset, 2);
+
+ if(pixel1 === null || pixel2 === null){
+ return;
+ }
+
+ if (ignoreColors){
+
+ addBrightnessInfo(pixel1);
+ addBrightnessInfo(pixel2);
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ return;
+ }
+
+ if( isRGBSimilar(pixel1, pixel2) ){
+ copyPixel(targetPix, offset, pixel2);
+
+ } else if( ignoreAntialiasing && (
+ addBrightnessInfo(pixel1), // jit pixel info augmentation looks a little weird, sorry.
+ addBrightnessInfo(pixel2),
+ isAntialiased(pixel1, data1, 1, verticalPos, horizontalPos, width) ||
+ isAntialiased(pixel2, data2, 2, verticalPos, horizontalPos, width)
+ )){
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+
+ });
+
+ data.misMatchPercentage = (mismatchCount / (height*width) * 100).toFixed(2);
+ data.analysisTime = Date.now() - time;
+
+ data.getImageDataUrl = function(text){
+ var barHeight = 0;
+
+ if(text){
+ barHeight = addLabel(text,context,hiddenCanvas);
+ }
+
+ context.putImageData(imgd, 0, barHeight);
+
+ return hiddenCanvas.toDataURL("image/png");
+ };
+ }
+
+ function addLabel(text, context, hiddenCanvas){
+ var textPadding = 2;
+
+ context.font = '12px sans-serif';
+
+ var textWidth = context.measureText(text).width + textPadding*2;
+ var barHeight = 22;
+
+ if(textWidth > hiddenCanvas.width){
+ hiddenCanvas.width = textWidth;
+ }
+
+ hiddenCanvas.height += barHeight;
+
+ context.fillStyle = "#666";
+ context.fillRect(0,0,hiddenCanvas.width,barHeight -4);
+ context.fillStyle = "#fff";
+ context.fillRect(0,barHeight -4,hiddenCanvas.width, 4);
+
+ context.fillStyle = "#fff";
+ context.textBaseline = "top";
+ context.font = '12px sans-serif';
+ context.fillText(text, textPadding, 1);
+
+ return barHeight;
+ }
+
+ function normalise(img, w, h){
+ var c;
+ var context;
+
+ if(img.height < h || img.width < w){
+ c = document.createElement('canvas');
+ c.width = w;
+ c.height = h;
+ context = c.getContext('2d');
+ context.putImageData(img, 0, 0);
+ return context.getImageData(0, 0, w, h);
+ }
+
+ return img;
+ }
+
+ function compare(one, two){
+
+ function onceWeHaveBoth(){
+ var width;
+ var height;
+ if(images.length === 2){
+ width = images[0].width > images[1].width ? images[0].width : images[1].width;
+ height = images[0].height > images[1].height ? images[0].height : images[1].height;
+
+ if( (images[0].width === images[1].width) && (images[0].height === images[1].height) ){
+ data.isSameDimensions = true;
+ } else {
+ data.isSameDimensions = false;
+ }
+
+ analyseImages( normalise(images[0],width, height), normalise(images[1],width, height), width, height);
+
+ triggerDataUpdate();
+ }
+ }
+
+ images = [];
+ loadImageData(one, onceWeHaveBoth);
+ loadImageData(two, onceWeHaveBoth);
+ }
+
+ function getCompareApi(param){
+
+ var secondFileData,
+ hasMethod = typeof param === 'function';
+
+ if( !hasMethod ){
+ // assume it's file data
+ secondFileData = param;
+ }
+
+ var self = {
+ ignoreNothing: function(){
+
+ tolerance.red = 16;
+ tolerance.green = 16;
+ tolerance.blue = 16;
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreAntialiasing: function(){
+
+ tolerance.red = 32;
+ tolerance.green = 32;
+ tolerance.blue = 32;
+ tolerance.minBrightness = 64;
+ tolerance.maxBrightness = 96;
+
+ ignoreAntialiasing = true;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreColors: function(){
+
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = true;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ onComplete: function( callback ){
+
+ updateCallbackArray.push(callback);
+
+ var wrapper = function(){
+ compare(fileData, secondFileData);
+ };
+
+ wrapper();
+
+ return getCompareApi(wrapper);
+ }
+ };
+
+ return self;
+ }
+
+ return {
+ onComplete: function( callback ){
+ updateCallbackArray.push(callback);
+ loadImageData(fileData, function(imageData, width, height){
+ parseImage(imageData.data, width, height);
+ });
+ },
+ compareTo: function(secondFileData){
+ return getCompareApi(secondFileData);
+ }
+ };
+
+ };
+}(this));
\ No newline at end of file
diff --git a/test/testsuite.js b/test/testsuite.js
deleted file mode 100644
index b486acb..0000000
--- a/test/testsuite.js
+++ /dev/null
@@ -1,36 +0,0 @@
-requirejs.config({
- baseUrl: '/test/unit/'
-});
-
-define(function(require) {
- var testModules = [
- 'Pixi',
- 'Point',
- 'Rectangle',
- 'DisplayObject',
- 'DisplayObjectContainer',
- 'Sprite',
- 'MovieClip',
- 'InteractionManager',
- 'Stage',
- 'utils/Utils',
- 'utils/EventTarget',
- 'utils/Matrix',
- 'utils/Detector',
- 'renderers/WebGLShaders',
- 'renderers/WebGLRenderer',
- 'renderers/WebGLBatch',
- 'renderers/CanvasRenderer',
- 'extras/Strip',
- 'extras/Rope',
- 'textures/BaseTexture',
- 'textures/Texture',
- 'loaders/SpriteSheetLoader',
- 'loaders/AssetLoader'
- ];
-
- // Resolve all testModules and then start the Test Runner.
- require(testModules, function() {
- QUnit.start();
- });
-});
\ No newline at end of file
diff --git a/test/textures/SpriteSheet-Aliens.png b/test/textures/SpriteSheet-Aliens.png
new file mode 100644
index 0000000..210acb1
--- /dev/null
+++ b/test/textures/SpriteSheet-Aliens.png
Binary files differ
diff --git a/test/textures/SpriteSheet-Explosion.png b/test/textures/SpriteSheet-Explosion.png
new file mode 100755
index 0000000..79e1a69
--- /dev/null
+++ b/test/textures/SpriteSheet-Explosion.png
Binary files differ
diff --git a/test/textures/bunny.png b/test/textures/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/textures/bunny.png
Binary files differ
diff --git a/test/unit/DisplayObject.js b/test/unit/DisplayObject.js
deleted file mode 100644
index 5e7e72f..0000000
--- a/test/unit/DisplayObject.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObject');
-});
diff --git a/test/unit/DisplayObjectContainer.js b/test/unit/DisplayObjectContainer.js
deleted file mode 100644
index b323959..0000000
--- a/test/unit/DisplayObjectContainer.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObjectContainer');
-});
diff --git a/test/unit/InteractionManager.js b/test/unit/InteractionManager.js
deleted file mode 100644
index e751f52..0000000
--- a/test/unit/InteractionManager.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('InteractionManager');
-});
diff --git a/test/unit/MovieClip.js b/test/unit/MovieClip.js
deleted file mode 100644
index 37d9446..0000000
--- a/test/unit/MovieClip.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('MovieClip');
-});
diff --git a/test/unit/Pixi.js b/test/unit/Pixi.js
deleted file mode 100644
index 36eee73..0000000
--- a/test/unit/Pixi.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Pixi');
-});
diff --git a/test/unit/Point.js b/test/unit/Point.js
deleted file mode 100644
index 983ff6e..0000000
--- a/test/unit/Point.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Point');
-});
diff --git a/test/unit/Rectangle.js b/test/unit/Rectangle.js
deleted file mode 100644
index 3b439ba..0000000
--- a/test/unit/Rectangle.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Rectangle');
-});
diff --git a/test/unit/Sprite.js b/test/unit/Sprite.js
deleted file mode 100644
index ed4f596..0000000
--- a/test/unit/Sprite.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Sprite');
-});
diff --git a/test/unit/Stage.js b/test/unit/Stage.js
deleted file mode 100644
index 2d70291..0000000
--- a/test/unit/Stage.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Stage');
-});
diff --git a/test/unit/extras/Rope.js b/test/unit/extras/Rope.js
deleted file mode 100644
index 5606f14..0000000
--- a/test/unit/extras/Rope.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Rope');
-});
diff --git a/test/unit/extras/Strip.js b/test/unit/extras/Strip.js
deleted file mode 100644
index 0134d3a..0000000
--- a/test/unit/extras/Strip.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Strip');
-});
diff --git a/test/unit/loaders/AssetLoader.js b/test/unit/loaders/AssetLoader.js
deleted file mode 100644
index 13b8443..0000000
--- a/test/unit/loaders/AssetLoader.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('AssetLoader');
-});
diff --git a/test/unit/loaders/SpriteSheetLoader.js b/test/unit/loaders/SpriteSheetLoader.js
deleted file mode 100644
index 8bf0cb2..0000000
--- a/test/unit/loaders/SpriteSheetLoader.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('SpriteSheetLoader');
-});
diff --git a/test/unit/pixi/InteractionManager.js b/test/unit/pixi/InteractionManager.js
new file mode 100644
index 0000000..ed3001f
--- /dev/null
+++ b/test/unit/pixi/InteractionManager.js
@@ -0,0 +1,10 @@
+describe('pixi/InteractionManager', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var InteractionManager = PIXI.InteractionManager;
+
+ it('Module exists', function () {
+ expect(InteractionManager).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/Pixi.js b/test/unit/pixi/Pixi.js
new file mode 100644
index 0000000..27debc1
--- /dev/null
+++ b/test/unit/pixi/Pixi.js
@@ -0,0 +1,9 @@
+describe('pixi/Pixi', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+
+ it('Module exists', function () {
+ expect(global).to.have.property('PIXI').and.to.be.an('object');
+ });
+});
diff --git a/test/unit/pixi/core/Circle.js b/test/unit/pixi/core/Circle.js
new file mode 100644
index 0000000..93a4456
--- /dev/null
+++ b/test/unit/pixi/core/Circle.js
@@ -0,0 +1,22 @@
+describe('pixi/core/Circle', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Circle = PIXI.Circle;
+
+ it('Module exists', function () {
+ expect(Circle).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Circle();
+
+ expect(obj).to.be.an.instanceof(Circle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', 0);
+ expect(obj).to.have.property('y', 0);
+ expect(obj).to.have.property('radius', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Ellipse.js b/test/unit/pixi/core/Ellipse.js
new file mode 100644
index 0000000..026b56f
--- /dev/null
+++ b/test/unit/pixi/core/Ellipse.js
@@ -0,0 +1,24 @@
+describe('pixi/core/Ellipse', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Ellipse = PIXI.Ellipse;
+
+ it('Module exists', function () {
+ expect(Ellipse).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Ellipse();
+
+ expect(obj).to.be.an.instanceof(Ellipse);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+ expect(obj).to.respondTo('getBounds');
+
+ expect(obj).to.have.property('x', 0);
+ expect(obj).to.have.property('y', 0);
+ expect(obj).to.have.property('width', 0);
+ expect(obj).to.have.property('height', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Matrix.js b/test/unit/pixi/core/Matrix.js
new file mode 100644
index 0000000..b48989e
--- /dev/null
+++ b/test/unit/pixi/core/Matrix.js
@@ -0,0 +1,30 @@
+describe('pixi/core/Matrix', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var mat3 = PIXI.mat3;
+ var mat4 = PIXI.mat4;
+ var Matrix = PIXI.Matrix;
+
+ it('Ensure determineMatrixArrayType works', function () {
+ expect(Matrix).to.be.a('function');
+ });
+
+ it('mat3 exists', function () {
+ expect(mat3).to.be.an('object');
+ });
+
+ it('Confirm new mat3 matrix', function () {
+ var matrix = new mat3.create();
+ pixi_core_Matrix_confirmNewMat3(matrix);
+ });
+
+ it('mat3 exists', function () {
+ expect(mat4).to.be.an('object');
+ });
+
+ it('Confirm new mat4 matrix', function () {
+ var matrix = new mat4.create();
+ pixi_core_Matrix_confirmNewMat4(matrix);
+ });
+});
diff --git a/test/unit/pixi/core/Point.js b/test/unit/pixi/core/Point.js
new file mode 100644
index 0000000..c4d5163
--- /dev/null
+++ b/test/unit/pixi/core/Point.js
@@ -0,0 +1,15 @@
+describe('pixi/core/Point', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Point = PIXI.Point;
+
+ it('Module exists', function () {
+ expect(Point).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Point();
+ pixi_core_Point_confirm(obj, 0, 0);
+ });
+});
diff --git a/test/unit/pixi/core/Polygon.js b/test/unit/pixi/core/Polygon.js
new file mode 100644
index 0000000..dc8c918
--- /dev/null
+++ b/test/unit/pixi/core/Polygon.js
@@ -0,0 +1,20 @@
+describe('pixi/core/Polygon', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Polygon = PIXI.Polygon;
+
+ it('Module exists', function () {
+ expect(Polygon).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Polygon();
+
+ expect(obj).to.be.an.instanceof(Polygon);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.deep.property('points.length', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Rectangle.js b/test/unit/pixi/core/Rectangle.js
new file mode 100644
index 0000000..d43316e
--- /dev/null
+++ b/test/unit/pixi/core/Rectangle.js
@@ -0,0 +1,15 @@
+describe('pixi/core/Rectangle', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Rectangle = PIXI.Rectangle;
+
+ it('Module exists', function () {
+ expect(Rectangle).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var rect = new Rectangle();
+ pixi_core_Rectangle_confirm(rect, 0, 0, 0, 0);
+ });
+});
diff --git a/test/unit/pixi/display/DisplayObject.js b/test/unit/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..40c6fbc
--- /dev/null
+++ b/test/unit/pixi/display/DisplayObject.js
@@ -0,0 +1,21 @@
+describe('pixi/display/DisplayObject', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var DisplayObject = PIXI.DisplayObject;
+
+ it('Module exists', function () {
+ expect(DisplayObject).to.be.a('function');
+ expect(PIXI).to.have.property('visibleCount', 0);
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new DisplayObject();
+
+ pixi_display_DisplayObject_confirmNew(obj);
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', false);
+ expect(obj).to.have.property('stage', null);
+ });
+});
diff --git a/test/unit/pixi/display/DisplayObjectContainer.js b/test/unit/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..ce7f02f
--- /dev/null
+++ b/test/unit/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,20 @@
+describe('pixi/display/DisplayObjectContainer', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var DisplayObjectContainer = PIXI.DisplayObjectContainer;
+
+ it('Module exists', function () {
+ expect(DisplayObjectContainer).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new DisplayObjectContainer();
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', false);
+ expect(obj).to.have.property('stage', null);
+ });
+});
diff --git a/test/unit/pixi/display/MovieClip.js b/test/unit/pixi/display/MovieClip.js
new file mode 100644
index 0000000..f3c6c6a
--- /dev/null
+++ b/test/unit/pixi/display/MovieClip.js
@@ -0,0 +1,33 @@
+describe('pixi/display/MovieClip', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var MovieClip = PIXI.MovieClip;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(MovieClip).to.be.a('function');
+ });
+
+ it('Confirm new instance', function (done) {
+ var texture = Texture.fromImage('/base/test/textures/SpriteSheet-Explosion.png');
+ var obj = new MovieClip([texture]);
+
+ pixi_display_Sprite_confirmNew(obj, done);
+
+ expect(obj).to.be.an.instanceof(MovieClip);
+ expect(obj).to.respondTo('stop');
+ expect(obj).to.respondTo('play');
+ expect(obj).to.respondTo('gotoAndStop');
+ expect(obj).to.respondTo('gotoAndPlay');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('textures.length', 1);
+ expect(obj).to.have.deep.property('textures[0]', texture);
+ expect(obj).to.have.property('animationSpeed', 1);
+ expect(obj).to.have.property('loop', true);
+ expect(obj).to.have.property('onComplete', null);
+ expect(obj).to.have.property('currentFrame', 0);
+ expect(obj).to.have.property('playing', false);
+ });
+});
diff --git a/test/unit/pixi/display/Sprite.js b/test/unit/pixi/display/Sprite.js
new file mode 100644
index 0000000..54e914f
--- /dev/null
+++ b/test/unit/pixi/display/Sprite.js
@@ -0,0 +1,25 @@
+describe('pixi/display/Sprite', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Sprite = PIXI.Sprite;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(Sprite).to.be.a('function');
+ expect(PIXI).to.have.deep.property('blendModes.NORMAL', 0);
+ expect(PIXI).to.have.deep.property('blendModes.SCREEN', 1);
+ });
+
+ it('Members exist', function () {
+ expect(Sprite).itself.to.respondTo('fromImage');
+ expect(Sprite).itself.to.respondTo('fromFrame');
+ });
+
+ it('Confirm new instance', function (done) {
+ var texture = Texture.fromImage('/base/test/textures/SpriteSheet-Aliens.png');
+ var obj = new Sprite(texture);
+
+ pixi_display_Sprite_confirmNew(obj, done);
+ });
+});
diff --git a/test/unit/pixi/display/Stage.js b/test/unit/pixi/display/Stage.js
new file mode 100644
index 0000000..3cc2a4d
--- /dev/null
+++ b/test/unit/pixi/display/Stage.js
@@ -0,0 +1,49 @@
+describe('pixi/display/Stage', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Stage = PIXI.Stage;
+ var InteractionManager = PIXI.InteractionManager;
+ var Rectangle = PIXI.Rectangle;
+
+ it('Module exists', function () {
+ expect(Stage).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Stage(null, true);
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(Stage);
+ expect(obj).to.respondTo('updateTransform');
+ expect(obj).to.respondTo('setBackgroundColor');
+ expect(obj).to.respondTo('getMousePosition');
+
+ // FIXME: duplicate member in DisplayObject
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ // FIXME: convert arg to bool in constructor
+ expect(obj).to.have.property('interactive', true);
+
+ expect(obj).to.have.property('interactionManager')
+ .and.to.be.an.instanceof(InteractionManager)
+ .and.to.have.property('stage', obj);
+
+ expect(obj).to.have.property('dirty', true);
+
+ expect(obj).to.have.property('stage', obj);
+
+ expect(obj).to.have.property('hitArea')
+ .and.to.be.an.instanceof(Rectangle);
+ pixi_core_Rectangle_confirm(obj.hitArea, 0, 0, 100000, 100000);
+
+ expect(obj).to.have.property('backgroundColor', 0x000000);
+ expect(obj).to.have.deep.property('backgroundColorSplit.length', 3);
+ expect(obj).to.have.deep.property('backgroundColorSplit[0]', 0);
+ expect(obj).to.have.deep.property('backgroundColorSplit[1]', 0);
+ expect(obj).to.have.deep.property('backgroundColorSplit[2]', 0);
+ expect(obj).to.have.property('backgroundColorString', '#000000');
+
+ expect(obj).to.have.property('worldVisible', true);
+ });
+});
diff --git a/test/unit/pixi/extras/CustomRenderable.js b/test/unit/pixi/extras/CustomRenderable.js
new file mode 100644
index 0000000..8d83cf0
--- /dev/null
+++ b/test/unit/pixi/extras/CustomRenderable.js
@@ -0,0 +1,21 @@
+describe('pixi/extras/CustomRenderable', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var CustomRenderable = PIXI.CustomRenderable;
+
+ it('Module exists', function () {
+ expect(CustomRenderable).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new CustomRenderable();
+
+ pixi_display_DisplayObject_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(CustomRenderable);
+ expect(obj).to.respondTo('renderCanvas');
+ expect(obj).to.respondTo('initWebGL');
+ expect(obj).to.respondTo('renderWebGL');
+ });
+});
diff --git a/test/unit/pixi/extras/Rope.js b/test/unit/pixi/extras/Rope.js
new file mode 100644
index 0000000..6ddaf83
--- /dev/null
+++ b/test/unit/pixi/extras/Rope.js
@@ -0,0 +1,26 @@
+describe('pixi/extras/Rope', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Rope = PIXI.Rope;
+ var Texture = PIXI.Texture;
+ var Point = PIXI.Point;
+
+ it('Module exists', function () {
+ expect(Rope).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var texture = Texture.fromImage('/base/test/textures/bunny.png');
+ var obj = new Rope(texture, [new Point(), new Point(5, 10), new Point(10, 20)]);
+
+ pixi_extras_Strip_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(Rope);
+ expect(obj).to.respondTo('refresh');
+ expect(obj).to.respondTo('updateTransform');
+ expect(obj).to.respondTo('setTexture');
+
+ // TODO: Test properties
+ });
+});
diff --git a/test/unit/pixi/extras/Spine.js b/test/unit/pixi/extras/Spine.js
new file mode 100644
index 0000000..0708bc0
--- /dev/null
+++ b/test/unit/pixi/extras/Spine.js
@@ -0,0 +1,10 @@
+describe('pixi/extras/Spine', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Spine = PIXI.Spine;
+
+ it('Module exists', function () {
+ expect(Spine).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/extras/Strip.js b/test/unit/pixi/extras/Strip.js
new file mode 100644
index 0000000..8e564e1
--- /dev/null
+++ b/test/unit/pixi/extras/Strip.js
@@ -0,0 +1,18 @@
+describe('pixi/extras/Strip', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Strip = PIXI.Strip;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(Strip).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var texture = Texture.fromImage('/base/test/textures/bunny.png');
+ var obj = new Strip(texture, 20, 10000);
+
+ pixi_extras_Strip_confirmNew(obj);
+ });
+});
diff --git a/test/unit/pixi/extras/TilingSprite.js b/test/unit/pixi/extras/TilingSprite.js
new file mode 100644
index 0000000..56aea14
--- /dev/null
+++ b/test/unit/pixi/extras/TilingSprite.js
@@ -0,0 +1,24 @@
+describe('pixi/extras/TilingSprite', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var TilingSprite = PIXI.TilingSprite;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(TilingSprite).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var texture = Texture.fromImage('/base/test/textures/bunny.png');
+ var obj = new TilingSprite(texture, 6000, 12000);
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(TilingSprite);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ // TODO: Test properties
+ });
+});
diff --git a/test/unit/pixi/filters/FilterBlock.js b/test/unit/pixi/filters/FilterBlock.js
new file mode 100644
index 0000000..870cec0
--- /dev/null
+++ b/test/unit/pixi/filters/FilterBlock.js
@@ -0,0 +1,10 @@
+describe('pixi/filters/FilterBlock', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var FilterBlock = PIXI.FilterBlock;
+
+ it('Module exists', function () {
+ expect(FilterBlock).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/filters/MaskFilter.js b/test/unit/pixi/filters/MaskFilter.js
new file mode 100644
index 0000000..32d6a45
--- /dev/null
+++ b/test/unit/pixi/filters/MaskFilter.js
@@ -0,0 +1,10 @@
+describe('pixi/filters/MaskFilter', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ // var MaskFilter = PIXI.MaskFilter;
+
+ // it('Module exists', function () {
+ // expect(MaskFilter).to.be.a('function');
+ // });
+});
diff --git a/test/unit/pixi/loaders/AssetLoader.js b/test/unit/pixi/loaders/AssetLoader.js
new file mode 100644
index 0000000..a0aa0b5
--- /dev/null
+++ b/test/unit/pixi/loaders/AssetLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/AssetLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var AssetLoader = PIXI.AssetLoader;
+
+ it('Module exists', function () {
+ expect(AssetLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/BitmapFontLoader.js b/test/unit/pixi/loaders/BitmapFontLoader.js
new file mode 100644
index 0000000..6253c42
--- /dev/null
+++ b/test/unit/pixi/loaders/BitmapFontLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/BitmapFontLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var BitmapFontLoader = PIXI.BitmapFontLoader;
+
+ it('Module exists', function () {
+ expect(PIXI.BitmapFontLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/ImageLoader.js b/test/unit/pixi/loaders/ImageLoader.js
new file mode 100644
index 0000000..8b1f556
--- /dev/null
+++ b/test/unit/pixi/loaders/ImageLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/ImageLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var ImageLoader = PIXI.ImageLoader;
+
+ it('Module exists', function () {
+ expect(ImageLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/JsonLoader.js b/test/unit/pixi/loaders/JsonLoader.js
new file mode 100644
index 0000000..c577e83
--- /dev/null
+++ b/test/unit/pixi/loaders/JsonLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/JsonLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var JsonLoader = PIXI.JsonLoader;
+
+ it('Module exists', function () {
+ expect(JsonLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/SpineLoader.js b/test/unit/pixi/loaders/SpineLoader.js
new file mode 100644
index 0000000..fdcc0b8
--- /dev/null
+++ b/test/unit/pixi/loaders/SpineLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/SpineLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var SpineLoader = PIXI.SpineLoader;
+
+ it('Module exists', function () {
+ expect(SpineLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/SpriteSheetLoader.js b/test/unit/pixi/loaders/SpriteSheetLoader.js
new file mode 100644
index 0000000..57beb27
--- /dev/null
+++ b/test/unit/pixi/loaders/SpriteSheetLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/SpriteSheetLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var SpriteSheetLoader = PIXI.SpriteSheetLoader;
+
+ it('Module exists', function () {
+ expect(SpriteSheetLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/primitives/Graphics.js b/test/unit/pixi/primitives/Graphics.js
new file mode 100644
index 0000000..b8b3e5c
--- /dev/null
+++ b/test/unit/pixi/primitives/Graphics.js
@@ -0,0 +1,40 @@
+describe('pixi/primitives/Graphics', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Graphics = PIXI.Graphics;
+
+ it('Module exists', function () {
+ expect(Graphics).to.be.a('function');
+
+ expect(Graphics).itself.to.have.property('POLY', 0);
+ expect(Graphics).itself.to.have.property('RECT', 1);
+ expect(Graphics).itself.to.have.property('CIRC', 2);
+ expect(Graphics).itself.to.have.property('ELIP', 3);
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Graphics();
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(Graphics);
+ expect(obj).to.respondTo('lineStyle');
+ expect(obj).to.respondTo('lineStyle');
+ expect(obj).to.respondTo('moveTo');
+ expect(obj).to.respondTo('lineTo');
+ expect(obj).to.respondTo('beginFill');
+ expect(obj).to.respondTo('endFill');
+ expect(obj).to.respondTo('drawRect');
+ expect(obj).to.respondTo('drawCircle');
+ expect(obj).to.respondTo('drawElipse');
+ expect(obj).to.respondTo('clear');
+
+ expect(obj).to.have.property('renderable', true);
+ expect(obj).to.have.property('fillAlpha', 1);
+ expect(obj).to.have.property('lineWidth', 0);
+ expect(obj).to.have.property('lineColor', 'black');
+ expect(obj).to.have.deep.property('graphicsData.length', 0);
+ expect(obj).to.have.deep.property('currentPath.points.length', 0);
+ });
+});
diff --git a/test/unit/pixi/renderers/canvas/CanvasGraphics.js b/test/unit/pixi/renderers/canvas/CanvasGraphics.js
new file mode 100644
index 0000000..8f44472
--- /dev/null
+++ b/test/unit/pixi/renderers/canvas/CanvasGraphics.js
@@ -0,0 +1,15 @@
+describe('renders/canvas/CanvasGraphics', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var CanvasGraphics = PIXI.CanvasGraphics;
+
+ it('Module exists', function () {
+ expect(CanvasGraphics).to.be.a('function');
+ });
+
+ it('Members exist', function () {
+ expect(CanvasGraphics).itself.to.respondTo('renderGraphics');
+ expect(CanvasGraphics).itself.to.respondTo('renderGraphicsMask');
+ });
+});
diff --git a/test/unit/pixi/renderers/canvas/CanvasRenderer.js b/test/unit/pixi/renderers/canvas/CanvasRenderer.js
new file mode 100644
index 0000000..df3a12f
--- /dev/null
+++ b/test/unit/pixi/renderers/canvas/CanvasRenderer.js
@@ -0,0 +1,10 @@
+describe('renderers/canvas/CanvasRenderer', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var CanvasRenderer = PIXI.CanvasRenderer;
+
+ it('Module exists', function () {
+ expect(CanvasRenderer).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/renderers/webgl/WebGLBatch.js b/test/unit/pixi/renderers/webgl/WebGLBatch.js
new file mode 100644
index 0000000..75efd56
--- /dev/null
+++ b/test/unit/pixi/renderers/webgl/WebGLBatch.js
@@ -0,0 +1,10 @@
+describe('renderers/webgl/WebGLBatch', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var WebGLBatch = PIXI.WebGLBatch;
+
+ it('Module exists', function () {
+ expect(WebGLBatch).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/renderers/webgl/WebGLGraphics.js b/test/unit/pixi/renderers/webgl/WebGLGraphics.js
new file mode 100644
index 0000000..41bf941
--- /dev/null
+++ b/test/unit/pixi/renderers/webgl/WebGLGraphics.js
@@ -0,0 +1,19 @@
+describe('renderers/wegbl/WebGLGraphics', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var WebGLGraphics = PIXI.WebGLGraphics;
+
+ it('Module exists', function () {
+ expect(WebGLGraphics).to.be.a('function');
+ });
+
+ it('Members exist', function () {
+ expect(WebGLGraphics).itself.to.respondTo('renderGraphics');
+ expect(WebGLGraphics).itself.to.respondTo('updateGraphics');
+ expect(WebGLGraphics).itself.to.respondTo('buildRectangle');
+ expect(WebGLGraphics).itself.to.respondTo('buildCircle');
+ expect(WebGLGraphics).itself.to.respondTo('buildLine');
+ expect(WebGLGraphics).itself.to.respondTo('buildPoly');
+ });
+});
diff --git a/test/unit/pixi/renderers/webgl/WebGLRenderGroup.js b/test/unit/pixi/renderers/webgl/WebGLRenderGroup.js
new file mode 100644
index 0000000..f4ee366
--- /dev/null
+++ b/test/unit/pixi/renderers/webgl/WebGLRenderGroup.js
@@ -0,0 +1,10 @@
+describe('renderers/webgl/WebGLRenderGroup', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var WebGLRenderGroup = PIXI.WebGLRenderGroup;
+
+ it('Module exists', function () {
+ expect(WebGLRenderGroup).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/renderers/webgl/WebGLRenderer.js b/test/unit/pixi/renderers/webgl/WebGLRenderer.js
new file mode 100644
index 0000000..86533eb
--- /dev/null
+++ b/test/unit/pixi/renderers/webgl/WebGLRenderer.js
@@ -0,0 +1,10 @@
+describe('renderers/webgl/WebGLRenderer', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var WebGLRenderer = PIXI.WebGLRenderer;
+
+ it('Module exists', function () {
+ expect(WebGLRenderer).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/renderers/webgl/WebGLShaders.js b/test/unit/pixi/renderers/webgl/WebGLShaders.js
new file mode 100644
index 0000000..2872de8
--- /dev/null
+++ b/test/unit/pixi/renderers/webgl/WebGLShaders.js
@@ -0,0 +1,13 @@
+describe('renderers/webgl/WebGLShaders', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+
+ it('Module members exist', function () {
+ expect(PIXI).to.respondTo('initPrimitiveShader');
+ expect(PIXI).to.respondTo('initDefaultShader');
+ expect(PIXI).to.respondTo('initDefaultStripShader');
+ expect(PIXI).to.respondTo('activateDefaultShader');
+ expect(PIXI).to.respondTo('activatePrimitiveShader');
+ });
+});
diff --git a/test/unit/pixi/text/BitmapText.js b/test/unit/pixi/text/BitmapText.js
new file mode 100644
index 0000000..9388e3d
--- /dev/null
+++ b/test/unit/pixi/text/BitmapText.js
@@ -0,0 +1,10 @@
+describe('pixi/text/BitmapText', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var BitmapText = PIXI.BitmapText;
+
+ it('Module exists', function () {
+ expect(BitmapText).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/text/Text.js b/test/unit/pixi/text/Text.js
new file mode 100644
index 0000000..9bc9ac5
--- /dev/null
+++ b/test/unit/pixi/text/Text.js
@@ -0,0 +1,10 @@
+describe('pixi/text/Text', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Text = PIXI.Text;
+
+ it('Module exists', function () {
+ expect(Text).to.be.a('function');
+ });
+});
diff --git a/.gitignore b/.gitignore
index 12e1b62..0b88317 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
node_modules
.DS_Store
-.project
\ No newline at end of file
+.project
+*.log
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..63e4d7c
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,8 @@
+language: node_js
+node_js:
+ - 0.10
+
+before_script:
+ - npm install -g grunt-cli
+ - export DISPLAY=:99.0
+ - sh -e /etc/init.d/xvfb start
diff --git a/Gruntfile.js b/Gruntfile.js
index b083b49..103938c 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -1,10 +1,12 @@
+'use strict';
+
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-connect');
- grunt.loadNpmTasks('grunt-contrib-qunit');
grunt.loadNpmTasks('grunt-contrib-yuidoc');
+ grunt.loadTasks('tasks');
var root = 'src/pixi/',
debug = 'bin/pixi.dev.js',
@@ -79,7 +81,7 @@
},
files: {
srcBlob: '<%= dirs.src %>/**/*.js',
- testBlob: '<%= dirs.test %>/unit/**/*.js',
+ testBlob: '<%= dirs.test %>/{functional,lib/pixi,unit}/**/*.js',
build: '<%= dirs.build %>/pixi.dev.js',
buildMin: '<%= dirs.build %>/pixi.js'
},
@@ -94,7 +96,12 @@
},
jshint: {
beforeconcat: srcFiles,
- test: ['<%= files.testBlob %>'],
+ test: {
+ src: ['<%= files.testBlob %>'],
+ options: {
+ expr: true
+ }
+ },
options: {
asi: true,
smarttabs: true
@@ -128,12 +135,6 @@
]
},
connect: {
- qunit: {
- options: {
- port: grunt.option('port-test') || 9002,
- base: './'
- }
- },
test: {
options: {
port: grunt.option('port-test') || 9002,
@@ -142,13 +143,6 @@
}
}
},
- qunit: {
- all: {
- options: {
- urls: ['http://localhost:' + (grunt.option('port-test') || 9002) + '/test/index.html']
- }
- }
- },
yuidoc: {
compile: {
name: '<%= pkg.name %>',
@@ -161,6 +155,13 @@
outdir: '<%= dirs.docs %>'
}
}
+ },
+ karma: {
+ unit: {
+ configFile: 'test/karma.conf.js',
+ // browsers: ['Chrome'],
+ singleRun: true
+ }
}
});
@@ -182,9 +183,10 @@
}
)
- grunt.registerTask('default', ['concat', 'uglify', 'distribute']);
grunt.registerTask('build', ['concat', 'uglify', 'distribute']);
- grunt.registerTask('test', ['build', 'connect:qunit', 'qunit']);
+ grunt.registerTask('test', ['concat', 'jshint:test', 'karma']);
grunt.registerTask('docs', ['yuidoc']);
-
-}
\ No newline at end of file
+ grunt.registerTask('default', ['test', 'uglify', 'distribute']);
+ // Travis CI task.
+ grunt.registerTask('travis', ['test']);
+}
diff --git a/README.md b/README.md
index c62ef86..690cfe4 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,8 @@

+[](http://travis-ci.org/drkibitz/pixi.js)
+
#### JavaScript 2D Renderer ####
The aim of this project is to provide a fast lightweight 2D library that works
diff --git a/package.json b/package.json
index b373240..1246a68 100644
--- a/package.json
+++ b/package.json
@@ -18,14 +18,21 @@
"main": "bin/pixi.js",
+ "scripts": {
+ "test": "grunt travis --verbose"
+ },
+
"dependencies": {},
"devDependencies": {
"grunt": "~0.4.x",
- "grunt-contrib-jshint": "0.3.x",
+ "grunt-contrib-jshint": "0.6.x",
"grunt-contrib-uglify": "0.2.x",
- "grunt-contrib-connect": "0.2.x",
- "grunt-contrib-qunit": "0.2.x",
+ "grunt-contrib-connect": "0.3.x",
"grunt-contrib-yuidoc": "0.4.x",
- "grunt-contrib-concat": "0.1.x"
+ "grunt-contrib-concat": "0.3.x",
+ "chai": "~1.7.0",
+ "karma": "0.11.0",
+ "karma-firefox-launcher": "0.1.0",
+ "karma-mocha": "0.1.0"
}
}
diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js
index a7c520e..ee82bbd 100644
--- a/src/pixi/InteractionManager.js
+++ b/src/pixi/InteractionManager.js
@@ -62,7 +62,6 @@
this.onTouchEnd = this.onTouchEnd.bind(this);
this.onTouchMove = this.onTouchMove.bind(this);
-
this.last = 0;
}
diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js
index 1a95d20..eef1059 100644
--- a/src/pixi/core/Ellipse.js
+++ b/src/pixi/core/Ellipse.js
@@ -78,7 +78,7 @@
return (normx + normy < 0.25);
}
-PIXI.Ellipse.getBounds = function()
+PIXI.Ellipse.prototype.getBounds = function()
{
return new PIXI.Rectangle(this.x, this.y, this.width, this.height);
}
diff --git a/tasks/karma.js b/tasks/karma.js
new file mode 100644
index 0000000..c340485
--- /dev/null
+++ b/tasks/karma.js
@@ -0,0 +1,27 @@
+'use strict';
+
+var path = require('path');
+var server = require('karma').server;
+
+module.exports = function (grunt) {
+ grunt.registerMultiTask('karma', 'run karma.', function() {
+ var done = this.async();
+ var options = this.options({
+ background: false
+ });
+ var data = this.data;
+
+ //merge options onto data, with data taking precedence
+ data = grunt.util._.merge(options, data);
+ data.configFile = path.resolve(data.configFile);
+ if (data.configFile) {
+ data.configFile = grunt.template.process(data.configFile);
+ }
+
+ server.start(
+ data,
+ function(code) {
+ done(!code);
+ });
+ });
+};
diff --git a/test/functional/example-1-basics/bunny.png b/test/functional/example-1-basics/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/functional/example-1-basics/bunny.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-30.png b/test/functional/example-1-basics/frame-30.png
new file mode 100644
index 0000000..96e3409
--- /dev/null
+++ b/test/functional/example-1-basics/frame-30.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-60.png b/test/functional/example-1-basics/frame-60.png
new file mode 100644
index 0000000..af3f4ce
--- /dev/null
+++ b/test/functional/example-1-basics/frame-60.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-90.png b/test/functional/example-1-basics/frame-90.png
new file mode 100644
index 0000000..099b823
--- /dev/null
+++ b/test/functional/example-1-basics/frame-90.png
Binary files differ
diff --git a/test/functional/example-1-basics/index.js b/test/functional/example-1-basics/index.js
new file mode 100644
index 0000000..7ae7a98
--- /dev/null
+++ b/test/functional/example-1-basics/index.js
@@ -0,0 +1,133 @@
+describe('Example 1 - Basics', function () {
+ 'use strict';
+
+ var baseUri = '/base/test/functional/example-1-basics';
+ var expect = chai.expect;
+ var currentFrame = 0;
+ var frameEvents = {};
+ var stage;
+ var renderer;
+ var bunny;
+
+ function onFrame(frame, callback) {
+ frameEvents[frame] = callback;
+ }
+
+ function animate() {
+ currentFrame += 1;
+
+ requestAnimFrame( animate );
+
+ // just for fun, lets rotate mr rabbit a little
+ bunny.rotation += 0.1;
+
+ // render the stage
+ renderer.render(stage);
+
+ if (frameEvents[currentFrame])
+ frameEvents[currentFrame](currentFrame);
+ }
+
+ function initScene() {
+ // create an new instance of a pixi stage
+ stage = new PIXI.Stage(0x66FF99);
+
+ // create a renderer instance
+ renderer = PIXI.autoDetectRenderer(400, 300);
+ console.log('Is PIXI.WebGLRenderer: ' + (renderer instanceof PIXI.WebGLRenderer));
+
+ // add the renderer view element to the DOM
+ document.body.appendChild(renderer.view);
+
+ requestAnimFrame( animate );
+
+ // create a texture from an image path
+ var texture = PIXI.Texture.fromImage(baseUri + "/bunny.png");
+ // create a new Sprite using the texture
+ bunny = new PIXI.Sprite(texture);
+
+ // center the sprites anchor point
+ bunny.anchor.x = 0.5;
+ bunny.anchor.y = 0.5;
+
+ // move the sprite t the center of the screen
+ bunny.position.x = 200;
+ bunny.position.y = 150;
+
+ stage.addChild(bunny);
+ }
+
+ it('assets loaded', function (done) {
+ var loader = new PIXI.AssetLoader([
+ baseUri + '/bunny.png',
+ baseUri + '/frame-30.png',
+ baseUri + '/frame-60.png',
+ baseUri + '/frame-90.png'
+ ]);
+ // loader.on('onProgress', function (event) {
+ // console.log(event.content);
+ // });
+ loader.on('onComplete', function (event) {
+ done();
+ initScene();
+ });
+ loader.load();
+ });
+
+ it('frame 30 should match', function (done) {
+ this.timeout(700);
+ onFrame(30, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-30.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 60 should match', function (done) {
+ this.timeout(1200);
+ onFrame(60, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-60.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 90 should match', function (done) {
+ this.timeout(1700);
+ onFrame(90, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-90.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ // it('capture something', function (done) {
+ // this.timeout(2000000);
+ // onFrame(30, function () {
+ // var img = new Image();
+ // img.src = renderer.view.toDataURL('image/png');
+ // document.body.appendChild(img);
+ // });
+ // });
+});
diff --git a/test/index.html b/test/index.html
deleted file mode 100644
index 9cbcac5..0000000
--- a/test/index.html
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
- Pixi.js Test Suite
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/test/karma.conf.js b/test/karma.conf.js
new file mode 100644
index 0000000..c66a696
--- /dev/null
+++ b/test/karma.conf.js
@@ -0,0 +1,82 @@
+module.exports = function(config) {
+ config.set({
+
+ // base path, that will be used to resolve files and exclude
+ basePath : '../',
+
+ frameworks : ['mocha'],
+
+ // list of files / patterns to load in the browser
+ files : [
+ 'node_modules/chai/chai.js',
+ 'bin/pixi.dev.js',
+ 'test/lib/**/*.js',
+ 'test/unit/**/*.js',
+ // 'test/functional/**/*.js',
+ {pattern: 'test/**/*.png', watched: false, included: false, served: true}
+ ],
+
+ // list of files to exclude
+ exclude : [],
+
+ // use dolts reporter, as travis terminal does not support escaping sequences
+ // possible values: 'dots', 'progress', 'junit', 'teamcity'
+ // CLI --reporters progress
+ reporters : ['progress'],
+
+ // web server port
+ // CLI --port 9876
+ port : 9876,
+
+ // cli runner port
+ // CLI --runner-port 9100
+ runnerPort : 9100,
+
+ // enable / disable colors in the output (reporters and logs)
+ // CLI --colors --no-colors
+ colors : true,
+
+ // level of logging
+ // possible values: karma.LOG_DISABLE || karma.LOG_ERROR || karma.LOG_WARN || karma.LOG_INFO || karma.LOG_DEBUG
+ // CLI --log-level debug
+ logLevel : config.LOG_DEBUG,
+
+ // enable / disable watching file and executing tests whenever any file changes
+ // CLI --auto-watch --no-auto-watch
+ autoWatch : false,
+
+ // Start these browsers, currently available:
+ // - Chrome
+ // - ChromeCanary
+ // - Firefox
+ // - Opera
+ // - Safari (only Mac)
+ // - PhantomJS
+ // - IE (only Windows)
+ // CLI --browsers Chrome,Firefox,Safari
+ browsers : ['Firefox'],
+
+ // If browser does not capture in given timeout [ms], kill it
+ // CLI --capture-timeout 5000
+ captureTimeout : 5000,
+
+ // Auto run tests on start (when browsers are captured) and exit
+ // CLI --single-run --no-single-run
+ singleRun : true,
+
+ // report which specs are slower than 500ms
+ // CLI --report-slower-than 500
+ reportSlowerThan : 1000,
+
+ preprocessors : {
+ // '**/client/js/*.js': 'coverage'
+ },
+
+ plugins : [
+ 'karma-mocha',
+ // 'karma-chrome-launcher',
+ 'karma-firefox-launcher',
+ // 'karma-phantomjs-launcher'
+ ]
+ });
+};
diff --git a/test/lib/pixi/core/Matrix.js b/test/lib/pixi/core/Matrix.js
new file mode 100644
index 0000000..d26386b
--- /dev/null
+++ b/test/lib/pixi/core/Matrix.js
@@ -0,0 +1,40 @@
+
+function pixi_core_Matrix_confirmNewMat3(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(1);
+ expect(matrix[5]).to.equal(0);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(1);
+}
+
+function pixi_core_Matrix_confirmNewMat4(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[0]).to.equal(1);
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(0);
+ expect(matrix[5]).to.equal(1);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(0);
+ expect(matrix[9]).to.equal(0);
+ expect(matrix[10]).to.equal(1);
+ expect(matrix[11]).to.equal(0);
+ expect(matrix[12]).to.equal(0);
+ expect(matrix[13]).to.equal(0);
+ expect(matrix[14]).to.equal(0);
+ expect(matrix[15]).to.equal(1);
+}
diff --git a/test/lib/pixi/core/Point.js b/test/lib/pixi/core/Point.js
new file mode 100644
index 0000000..e5df07b
--- /dev/null
+++ b/test/lib/pixi/core/Point.js
@@ -0,0 +1,10 @@
+
+function pixi_core_Point_confirm(obj, x, y) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Point);
+ expect(obj).to.respondTo('clone');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+}
diff --git a/test/lib/pixi/core/Rectangle.js b/test/lib/pixi/core/Rectangle.js
new file mode 100644
index 0000000..23f0d12
--- /dev/null
+++ b/test/lib/pixi/core/Rectangle.js
@@ -0,0 +1,13 @@
+
+function pixi_core_Rectangle_confirm(obj, x, y, width, height) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Rectangle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+ expect(obj).to.have.property('width', width);
+ expect(obj).to.have.property('height', height);
+}
diff --git a/test/lib/pixi/display/DisplayObject.js b/test/lib/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..1388a7f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObject.js
@@ -0,0 +1,43 @@
+
+function pixi_display_DisplayObject_confirmNew(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObject);
+ expect(obj).to.respondTo('setInteractive');
+ expect(obj).to.respondTo('addFilter');
+ expect(obj).to.respondTo('removeFilter');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.property('last', obj);
+ expect(obj).to.have.property('first', obj);
+
+ expect(obj).to.contain.property('position');
+ pixi_core_Point_confirm(obj.position, 0, 0);
+ expect(obj).to.contain.property('scale');
+ pixi_core_Point_confirm(obj.scale, 1, 1);
+ expect(obj).to.contain.property('pivot');
+ pixi_core_Point_confirm(obj.pivot, 0, 0);
+
+ expect(obj).to.have.property('rotation', 0);
+ expect(obj).to.have.property('alpha', 1);
+ expect(obj).to.have.property('visible', true);
+ expect(obj).to.have.property('buttonMode', false);
+ expect(obj).to.have.property('parent', null);
+ expect(obj).to.have.property('worldAlpha', 1);
+
+ expect(obj).to.have.property('hitArea');
+ expect(obj).to.have.property('interactive'); // TODO: Have a better default value
+ expect('mask' in obj).to.be.true; // TODO: Have a better default value
+ expect(obj.mask).to.be.undefined;
+
+ expect(obj).to.have.property('renderable');
+ expect(obj).to.have.property('stage');
+
+ expect(obj).to.have.deep.property('worldTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ expect(obj).to.have.deep.property('localTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.localTransform);
+
+ expect(obj).to.have.deep.property('color.length', 0);
+ expect(obj).to.have.property('dynamic', true);
+}
diff --git a/test/lib/pixi/display/DisplayObjectContainer.js b/test/lib/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..085c59f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,16 @@
+
+function pixi_display_DisplayObjectContainer_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObject_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObjectContainer);
+ expect(obj).to.respondTo('addChild');
+ expect(obj).to.respondTo('addChildAt');
+ expect(obj).to.respondTo('swapChildren');
+ expect(obj).to.respondTo('getChildAt');
+ expect(obj).to.respondTo('removeChild');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('children.length', 0);
+}
diff --git a/test/lib/pixi/display/Sprite.js b/test/lib/pixi/display/Sprite.js
new file mode 100644
index 0000000..cc7a2d6
--- /dev/null
+++ b/test/lib/pixi/display/Sprite.js
@@ -0,0 +1,28 @@
+
+function pixi_display_Sprite_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Sprite);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', true);
+ expect(obj).to.have.property('stage', null);
+
+ expect(obj).to.have.property('anchor');
+ pixi_core_Point_confirm(obj.anchor, 0, 0);
+
+ expect(obj).to.have.property('blendMode', PIXI.blendModes.NORMAL);
+ expect(obj).to.have.property('width', 1); // TODO: is 1 expected
+ expect(obj).to.have.property('height', 1); // TODO: is 1 expected
+
+ // FIXME: Just make this a boolean that is always there
+ expect(!!obj.updateFrame).to.equal(obj.texture.baseTexture.hasLoaded);
+
+ expect(obj).to.have.property('texture');
+ pixi_textures_Texture_confirmNew(obj.texture, done);
+}
diff --git a/test/lib/pixi/extras/Strip.js b/test/lib/pixi/extras/Strip.js
new file mode 100644
index 0000000..8927a8a
--- /dev/null
+++ b/test/lib/pixi/extras/Strip.js
@@ -0,0 +1,12 @@
+
+function pixi_extras_Strip_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Strip);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ // TODO: Test properties
+}
diff --git a/test/lib/pixi/textures/Texture.js b/test/lib/pixi/textures/Texture.js
new file mode 100644
index 0000000..d5867b6
--- /dev/null
+++ b/test/lib/pixi/textures/Texture.js
@@ -0,0 +1,31 @@
+
+function pixi_textures_Texture_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ function confirmFrameDone() {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, obj.baseTexture.width, obj.baseTexture.height);
+
+ expect(obj).to.have.property('width', obj.baseTexture.width);
+ expect(obj).to.have.property('height', obj.baseTexture.height);
+ done();
+ }
+
+ expect(obj).to.be.an.instanceof(PIXI.Texture);
+ pixi_utils_EventTarget_like(obj);
+
+ expect(obj).to.have.property('baseTexture')
+ .and.to.be.an.instanceof(PIXI.BaseTexture);
+
+ expect(obj).to.have.property('scope', obj);
+
+ expect(obj).to.have.property('trim');
+ pixi_core_Point_confirm(obj.trim, 0, 0);
+
+ expect(obj).to.have.property('frame');
+ if (obj.baseTexture.hasLoaded) {
+ confirmFrameDone();
+ } else {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, 1, 1);
+ obj.addEventListener('update', confirmFrameDone);
+ }
+}
diff --git a/test/lib/pixi/utils/EventTarget.js b/test/lib/pixi/utils/EventTarget.js
new file mode 100644
index 0000000..7b1dcfa
--- /dev/null
+++ b/test/lib/pixi/utils/EventTarget.js
@@ -0,0 +1,8 @@
+
+function pixi_utils_EventTarget_like(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.respondTo('addEventListener');
+ expect(obj).to.respondTo('dispatchEvent');
+ expect(obj).to.respondTo('removeEventListener');
+}
diff --git a/test/lib/qunit-1.11.0.css b/test/lib/qunit-1.11.0.css
deleted file mode 100644
index d7fc0c8..0000000
--- a/test/lib/qunit-1.11.0.css
+++ /dev/null
@@ -1,244 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-/** Font Family and Sizes */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
- font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
-}
-
-#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
-#qunit-tests { font-size: smaller; }
-
-
-/** Resets */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter {
- margin: 0;
- padding: 0;
-}
-
-
-/** Header */
-
-#qunit-header {
- padding: 0.5em 0 0.5em 1em;
-
- color: #8699a4;
- background-color: #0d3349;
-
- font-size: 1.5em;
- line-height: 1em;
- font-weight: normal;
-
- border-radius: 5px 5px 0 0;
- -moz-border-radius: 5px 5px 0 0;
- -webkit-border-top-right-radius: 5px;
- -webkit-border-top-left-radius: 5px;
-}
-
-#qunit-header a {
- text-decoration: none;
- color: #c2ccd1;
-}
-
-#qunit-header a:hover,
-#qunit-header a:focus {
- color: #fff;
-}
-
-#qunit-testrunner-toolbar label {
- display: inline-block;
- padding: 0 .5em 0 .1em;
-}
-
-#qunit-banner {
- height: 5px;
-}
-
-#qunit-testrunner-toolbar {
- padding: 0.5em 0 0.5em 2em;
- color: #5E740B;
- background-color: #eee;
- overflow: hidden;
-}
-
-#qunit-userAgent {
- padding: 0.5em 0 0.5em 2.5em;
- background-color: #2b81af;
- color: #fff;
- text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
-}
-
-#qunit-modulefilter-container {
- float: right;
-}
-
-/** Tests: Pass/Fail */
-
-#qunit-tests {
- list-style-position: inside;
-}
-
-#qunit-tests li {
- padding: 0.4em 0.5em 0.4em 2.5em;
- border-bottom: 1px solid #fff;
- list-style-position: inside;
-}
-
-#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running {
- display: none;
-}
-
-#qunit-tests li strong {
- cursor: pointer;
-}
-
-#qunit-tests li a {
- padding: 0.5em;
- color: #c2ccd1;
- text-decoration: none;
-}
-#qunit-tests li a:hover,
-#qunit-tests li a:focus {
- color: #000;
-}
-
-#qunit-tests li .runtime {
- float: right;
- font-size: smaller;
-}
-
-.qunit-assert-list {
- margin-top: 0.5em;
- padding: 0.5em;
-
- background-color: #fff;
-
- border-radius: 5px;
- -moz-border-radius: 5px;
- -webkit-border-radius: 5px;
-}
-
-.qunit-collapsed {
- display: none;
-}
-
-#qunit-tests table {
- border-collapse: collapse;
- margin-top: .2em;
-}
-
-#qunit-tests th {
- text-align: right;
- vertical-align: top;
- padding: 0 .5em 0 0;
-}
-
-#qunit-tests td {
- vertical-align: top;
-}
-
-#qunit-tests pre {
- margin: 0;
- white-space: pre-wrap;
- word-wrap: break-word;
-}
-
-#qunit-tests del {
- background-color: #e0f2be;
- color: #374e0c;
- text-decoration: none;
-}
-
-#qunit-tests ins {
- background-color: #ffcaca;
- color: #500;
- text-decoration: none;
-}
-
-/*** Test Counts */
-
-#qunit-tests b.counts { color: black; }
-#qunit-tests b.passed { color: #5E740B; }
-#qunit-tests b.failed { color: #710909; }
-
-#qunit-tests li li {
- padding: 5px;
- background-color: #fff;
- border-bottom: none;
- list-style-position: inside;
-}
-
-/*** Passing Styles */
-
-#qunit-tests li li.pass {
- color: #3c510c;
- background-color: #fff;
- border-left: 10px solid #C6E746;
-}
-
-#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
-#qunit-tests .pass .test-name { color: #366097; }
-
-#qunit-tests .pass .test-actual,
-#qunit-tests .pass .test-expected { color: #999999; }
-
-#qunit-banner.qunit-pass { background-color: #C6E746; }
-
-/*** Failing Styles */
-
-#qunit-tests li li.fail {
- color: #710909;
- background-color: #fff;
- border-left: 10px solid #EE5757;
- white-space: pre;
-}
-
-#qunit-tests > li:last-child {
- border-radius: 0 0 5px 5px;
- -moz-border-radius: 0 0 5px 5px;
- -webkit-border-bottom-right-radius: 5px;
- -webkit-border-bottom-left-radius: 5px;
-}
-
-#qunit-tests .fail { color: #000000; background-color: #EE5757; }
-#qunit-tests .fail .test-name,
-#qunit-tests .fail .module-name { color: #000000; }
-
-#qunit-tests .fail .test-actual { color: #EE5757; }
-#qunit-tests .fail .test-expected { color: green; }
-
-#qunit-banner.qunit-fail { background-color: #EE5757; }
-
-
-/** Result */
-
-#qunit-testresult {
- padding: 0.5em 0.5em 0.5em 2.5em;
-
- color: #2b81af;
- background-color: #D2E0E6;
-
- border-bottom: 1px solid white;
-}
-#qunit-testresult .module-name {
- font-weight: bold;
-}
-
-/** Fixture */
-
-#qunit-fixture {
- position: absolute;
- top: -10000px;
- left: -10000px;
- width: 1000px;
- height: 1000px;
-}
diff --git a/test/lib/qunit-1.11.0.js b/test/lib/qunit-1.11.0.js
deleted file mode 100644
index 302545f..0000000
--- a/test/lib/qunit-1.11.0.js
+++ /dev/null
@@ -1,2152 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-(function( window ) {
-
-var QUnit,
- assert,
- config,
- onErrorFnPrev,
- testId = 0,
- fileName = (sourceFromStacktrace( 0 ) || "" ).replace(/(:\d+)+\)?/, "").replace(/.+\//, ""),
- toString = Object.prototype.toString,
- hasOwn = Object.prototype.hasOwnProperty,
- // Keep a local reference to Date (GH-283)
- Date = window.Date,
- defined = {
- setTimeout: typeof window.setTimeout !== "undefined",
- sessionStorage: (function() {
- var x = "qunit-test-string";
- try {
- sessionStorage.setItem( x, x );
- sessionStorage.removeItem( x );
- return true;
- } catch( e ) {
- return false;
- }
- }())
- },
- /**
- * Provides a normalized error string, correcting an issue
- * with IE 7 (and prior) where Error.prototype.toString is
- * not properly implemented
- *
- * Based on http://es5.github.com/#x15.11.4.4
- *
- * @param {String|Error} error
- * @return {String} error message
- */
- errorString = function( error ) {
- var name, message,
- errorString = error.toString();
- if ( errorString.substring( 0, 7 ) === "[object" ) {
- name = error.name ? error.name.toString() : "Error";
- message = error.message ? error.message.toString() : "";
- if ( name && message ) {
- return name + ": " + message;
- } else if ( name ) {
- return name;
- } else if ( message ) {
- return message;
- } else {
- return "Error";
- }
- } else {
- return errorString;
- }
- },
- /**
- * Makes a clone of an object using only Array or Object as base,
- * and copies over the own enumerable properties.
- *
- * @param {Object} obj
- * @return {Object} New object with only the own properties (recursively).
- */
- objectValues = function( obj ) {
- // Grunt 0.3.x uses an older version of jshint that still has jshint/jshint#392.
- /*jshint newcap: false */
- var key, val,
- vals = QUnit.is( "array", obj ) ? [] : {};
- for ( key in obj ) {
- if ( hasOwn.call( obj, key ) ) {
- val = obj[key];
- vals[key] = val === Object(val) ? objectValues(val) : val;
- }
- }
- return vals;
- };
-
-function Test( settings ) {
- extend( this, settings );
- this.assertions = [];
- this.testNumber = ++Test.count;
-}
-
-Test.count = 0;
-
-Test.prototype = {
- init: function() {
- var a, b, li,
- tests = id( "qunit-tests" );
-
- if ( tests ) {
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml;
-
- // `a` initialized at top of scope
- a = document.createElement( "a" );
- a.innerHTML = "Rerun";
- a.href = QUnit.url({ testNumber: this.testNumber });
-
- li = document.createElement( "li" );
- li.appendChild( b );
- li.appendChild( a );
- li.className = "running";
- li.id = this.id = "qunit-test-output" + testId++;
-
- tests.appendChild( li );
- }
- },
- setup: function() {
- if ( this.module !== config.previousModule ) {
- if ( config.previousModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.previousModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
- config.previousModule = this.module;
- config.moduleStats = { all: 0, bad: 0 };
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- } else if ( config.autorun ) {
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- }
-
- config.current = this;
-
- this.testEnvironment = extend({
- setup: function() {},
- teardown: function() {}
- }, this.moduleTestEnvironment );
-
- this.started = +new Date();
- runLoggingCallbacks( "testStart", QUnit, {
- name: this.testName,
- module: this.module
- });
-
- // allow utility functions to access the current test environment
- // TODO why??
- QUnit.current_testEnvironment = this.testEnvironment;
-
- if ( !config.pollution ) {
- saveGlobal();
- }
- if ( config.notrycatch ) {
- this.testEnvironment.setup.call( this.testEnvironment );
- return;
- }
- try {
- this.testEnvironment.setup.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Setup failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- },
- run: function() {
- config.current = this;
-
- var running = id( "qunit-testresult" );
-
- if ( running ) {
- running.innerHTML = "Running:
" + this.nameHtml;
- }
-
- if ( this.async ) {
- QUnit.stop();
- }
-
- this.callbackStarted = +new Date();
-
- if ( config.notrycatch ) {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- return;
- }
-
- try {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- } catch( e ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
-
- QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + " " + this.stack + ": " + ( e.message || e ), extractStacktrace( e, 0 ) );
- // else next test will carry the responsibility
- saveGlobal();
-
- // Restart the tests if they're blocking
- if ( config.blocking ) {
- QUnit.start();
- }
- }
- },
- teardown: function() {
- config.current = this;
- if ( config.notrycatch ) {
- if ( typeof this.callbackRuntime === "undefined" ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
- }
- this.testEnvironment.teardown.call( this.testEnvironment );
- return;
- } else {
- try {
- this.testEnvironment.teardown.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Teardown failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- }
- checkPollution();
- },
- finish: function() {
- config.current = this;
- if ( config.requireExpects && this.expected === null ) {
- QUnit.pushFailure( "Expected number of assertions to be defined, but expect() was not called.", this.stack );
- } else if ( this.expected !== null && this.expected !== this.assertions.length ) {
- QUnit.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack );
- } else if ( this.expected === null && !this.assertions.length ) {
- QUnit.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions.", this.stack );
- }
-
- var i, assertion, a, b, time, li, ol,
- test = this,
- good = 0,
- bad = 0,
- tests = id( "qunit-tests" );
-
- this.runtime = +new Date() - this.started;
- config.stats.all += this.assertions.length;
- config.moduleStats.all += this.assertions.length;
-
- if ( tests ) {
- ol = document.createElement( "ol" );
- ol.className = "qunit-assert-list";
-
- for ( i = 0; i < this.assertions.length; i++ ) {
- assertion = this.assertions[i];
-
- li = document.createElement( "li" );
- li.className = assertion.result ? "pass" : "fail";
- li.innerHTML = assertion.message || ( assertion.result ? "okay" : "failed" );
- ol.appendChild( li );
-
- if ( assertion.result ) {
- good++;
- } else {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
-
- // store result when possible
- if ( QUnit.config.reorder && defined.sessionStorage ) {
- if ( bad ) {
- sessionStorage.setItem( "qunit-test-" + this.module + "-" + this.testName, bad );
- } else {
- sessionStorage.removeItem( "qunit-test-" + this.module + "-" + this.testName );
- }
- }
-
- if ( bad === 0 ) {
- addClass( ol, "qunit-collapsed" );
- }
-
- // `b` initialized at top of scope
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml + " (" + bad + ", " + good + ", " + this.assertions.length + ")";
-
- addEvent(b, "click", function() {
- var next = b.parentNode.lastChild,
- collapsed = hasClass( next, "qunit-collapsed" );
- ( collapsed ? removeClass : addClass )( next, "qunit-collapsed" );
- });
-
- addEvent(b, "dblclick", function( e ) {
- var target = e && e.target ? e.target : window.event.srcElement;
- if ( target.nodeName.toLowerCase() === "span" || target.nodeName.toLowerCase() === "b" ) {
- target = target.parentNode;
- }
- if ( window.location && target.nodeName.toLowerCase() === "strong" ) {
- window.location = QUnit.url({ testNumber: test.testNumber });
- }
- });
-
- // `time` initialized at top of scope
- time = document.createElement( "span" );
- time.className = "runtime";
- time.innerHTML = this.runtime + " ms";
-
- // `li` initialized at top of scope
- li = id( this.id );
- li.className = bad ? "fail" : "pass";
- li.removeChild( li.firstChild );
- a = li.firstChild;
- li.appendChild( b );
- li.appendChild( a );
- li.appendChild( time );
- li.appendChild( ol );
-
- } else {
- for ( i = 0; i < this.assertions.length; i++ ) {
- if ( !this.assertions[i].result ) {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
- }
-
- runLoggingCallbacks( "testDone", QUnit, {
- name: this.testName,
- module: this.module,
- failed: bad,
- passed: this.assertions.length - bad,
- total: this.assertions.length,
- duration: this.runtime
- });
-
- QUnit.reset();
-
- config.current = undefined;
- },
-
- queue: function() {
- var bad,
- test = this;
-
- synchronize(function() {
- test.init();
- });
- function run() {
- // each of these can by async
- synchronize(function() {
- test.setup();
- });
- synchronize(function() {
- test.run();
- });
- synchronize(function() {
- test.teardown();
- });
- synchronize(function() {
- test.finish();
- });
- }
-
- // `bad` initialized at top of scope
- // defer when previous test run passed, if storage is available
- bad = QUnit.config.reorder && defined.sessionStorage &&
- +sessionStorage.getItem( "qunit-test-" + this.module + "-" + this.testName );
-
- if ( bad ) {
- run();
- } else {
- synchronize( run, true );
- }
- }
-};
-
-// Root QUnit object.
-// `QUnit` initialized at top of scope
-QUnit = {
-
- // call on start of module test to prepend name to all tests
- module: function( name, testEnvironment ) {
- config.currentModule = name;
- config.currentModuleTestEnvironment = testEnvironment;
- config.modules[name] = true;
- },
-
- asyncTest: function( testName, expected, callback ) {
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- QUnit.test( testName, expected, callback, true );
- },
-
- test: function( testName, expected, callback, async ) {
- var test,
- nameHtml = "" + escapeText( testName ) + "";
-
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- if ( config.currentModule ) {
- nameHtml = "" + escapeText( config.currentModule ) + ": " + nameHtml;
- }
-
- test = new Test({
- nameHtml: nameHtml,
- testName: testName,
- expected: expected,
- async: async,
- callback: callback,
- module: config.currentModule,
- moduleTestEnvironment: config.currentModuleTestEnvironment,
- stack: sourceFromStacktrace( 2 )
- });
-
- if ( !validTest( test ) ) {
- return;
- }
-
- test.queue();
- },
-
- // Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through.
- expect: function( asserts ) {
- if (arguments.length === 1) {
- config.current.expected = asserts;
- } else {
- return config.current.expected;
- }
- },
-
- start: function( count ) {
- // QUnit hasn't been initialized yet.
- // Note: RequireJS (et al) may delay onLoad
- if ( config.semaphore === undefined ) {
- QUnit.begin(function() {
- // This is triggered at the top of QUnit.load, push start() to the event loop, to allow QUnit.load to finish first
- setTimeout(function() {
- QUnit.start( count );
- });
- });
- return;
- }
-
- config.semaphore -= count || 1;
- // don't start until equal number of stop-calls
- if ( config.semaphore > 0 ) {
- return;
- }
- // ignore if start is called more often then stop
- if ( config.semaphore < 0 ) {
- config.semaphore = 0;
- QUnit.pushFailure( "Called start() while already started (QUnit.config.semaphore was 0 already)", null, sourceFromStacktrace(2) );
- return;
- }
- // A slight delay, to avoid any current callbacks
- if ( defined.setTimeout ) {
- window.setTimeout(function() {
- if ( config.semaphore > 0 ) {
- return;
- }
- if ( config.timeout ) {
- clearTimeout( config.timeout );
- }
-
- config.blocking = false;
- process( true );
- }, 13);
- } else {
- config.blocking = false;
- process( true );
- }
- },
-
- stop: function( count ) {
- config.semaphore += count || 1;
- config.blocking = true;
-
- if ( config.testTimeout && defined.setTimeout ) {
- clearTimeout( config.timeout );
- config.timeout = window.setTimeout(function() {
- QUnit.ok( false, "Test timed out" );
- config.semaphore = 1;
- QUnit.start();
- }, config.testTimeout );
- }
- }
-};
-
-// `assert` initialized at top of scope
-// Asssert helpers
-// All of these must either call QUnit.push() or manually do:
-// - runLoggingCallbacks( "log", .. );
-// - config.current.assertions.push({ .. });
-// We attach it to the QUnit object *after* we expose the public API,
-// otherwise `assert` will become a global variable in browsers (#341).
-assert = {
- /**
- * Asserts rough true-ish result.
- * @name ok
- * @function
- * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" );
- */
- ok: function( result, msg ) {
- if ( !config.current ) {
- throw new Error( "ok() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
- result = !!result;
-
- var source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: msg
- };
-
- msg = escapeText( msg || (result ? "okay" : "failed" ) );
- msg = "" + msg + "";
-
- if ( !result ) {
- source = sourceFromStacktrace( 2 );
- if ( source ) {
- details.source = source;
- msg += "Source: | " + escapeText( source ) + " |
---|
";
- }
- }
- runLoggingCallbacks( "log", QUnit, details );
- config.current.assertions.push({
- result: result,
- message: msg
- });
- },
-
- /**
- * Assert that the first two arguments are equal, with an optional message.
- * Prints out both actual and expected values.
- * @name equal
- * @function
- * @example equal( format( "Received {0} bytes.", 2), "Received 2 bytes.", "format() replaces {0} with next argument" );
- */
- equal: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected == actual, actual, expected, message );
- },
-
- /**
- * @name notEqual
- * @function
- */
- notEqual: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected != actual, actual, expected, message );
- },
-
- /**
- * @name propEqual
- * @function
- */
- propEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notPropEqual
- * @function
- */
- notPropEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name deepEqual
- * @function
- */
- deepEqual: function( actual, expected, message ) {
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notDeepEqual
- * @function
- */
- notDeepEqual: function( actual, expected, message ) {
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name strictEqual
- * @function
- */
- strictEqual: function( actual, expected, message ) {
- QUnit.push( expected === actual, actual, expected, message );
- },
-
- /**
- * @name notStrictEqual
- * @function
- */
- notStrictEqual: function( actual, expected, message ) {
- QUnit.push( expected !== actual, actual, expected, message );
- },
-
- "throws": function( block, expected, message ) {
- var actual,
- expectedOutput = expected,
- ok = false;
-
- // 'expected' is optional
- if ( typeof expected === "string" ) {
- message = expected;
- expected = null;
- }
-
- config.current.ignoreGlobalErrors = true;
- try {
- block.call( config.current.testEnvironment );
- } catch (e) {
- actual = e;
- }
- config.current.ignoreGlobalErrors = false;
-
- if ( actual ) {
- // we don't want to validate thrown error
- if ( !expected ) {
- ok = true;
- expectedOutput = null;
- // expected is a regexp
- } else if ( QUnit.objectType( expected ) === "regexp" ) {
- ok = expected.test( errorString( actual ) );
- // expected is a constructor
- } else if ( actual instanceof expected ) {
- ok = true;
- // expected is a validation function which returns true is validation passed
- } else if ( expected.call( {}, actual ) === true ) {
- expectedOutput = null;
- ok = true;
- }
-
- QUnit.push( ok, actual, expectedOutput, message );
- } else {
- QUnit.pushFailure( message, null, 'No exception was thrown.' );
- }
- }
-};
-
-/**
- * @deprecate since 1.8.0
- * Kept assertion helpers in root for backwards compatibility.
- */
-extend( QUnit, assert );
-
-/**
- * @deprecated since 1.9.0
- * Kept root "raises()" for backwards compatibility.
- * (Note that we don't introduce assert.raises).
- */
-QUnit.raises = assert[ "throws" ];
-
-/**
- * @deprecated since 1.0.0, replaced with error pushes since 1.3.0
- * Kept to avoid TypeErrors for undefined methods.
- */
-QUnit.equals = function() {
- QUnit.push( false, false, false, "QUnit.equals has been deprecated since 2009 (e88049a0), use QUnit.equal instead" );
-};
-QUnit.same = function() {
- QUnit.push( false, false, false, "QUnit.same has been deprecated since 2009 (e88049a0), use QUnit.deepEqual instead" );
-};
-
-// We want access to the constructor's prototype
-(function() {
- function F() {}
- F.prototype = QUnit;
- QUnit = new F();
- // Make F QUnit's constructor so that we can add to the prototype later
- QUnit.constructor = F;
-}());
-
-/**
- * Config object: Maintain internal state
- * Later exposed as QUnit.config
- * `config` initialized at top of scope
- */
-config = {
- // The queue of tests to run
- queue: [],
-
- // block until document ready
- blocking: true,
-
- // when enabled, show only failing tests
- // gets persisted through sessionStorage and can be changed in UI via checkbox
- hidepassed: false,
-
- // by default, run previously failed tests first
- // very useful in combination with "Hide passed tests" checked
- reorder: true,
-
- // by default, modify document.title when suite is done
- altertitle: true,
-
- // when enabled, all tests must call expect()
- requireExpects: false,
-
- // add checkboxes that are persisted in the query-string
- // when enabled, the id is set to `true` as a `QUnit.config` property
- urlConfig: [
- {
- id: "noglobals",
- label: "Check for Globals",
- tooltip: "Enabling this will test if any test introduces new properties on the `window` object. Stored as query-strings."
- },
- {
- id: "notrycatch",
- label: "No try-catch",
- tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging exceptions in IE reasonable. Stored as query-strings."
- }
- ],
-
- // Set of all modules.
- modules: {},
-
- // logging callback queues
- begin: [],
- done: [],
- log: [],
- testStart: [],
- testDone: [],
- moduleStart: [],
- moduleDone: []
-};
-
-// Export global variables, unless an 'exports' object exists,
-// in that case we assume we're in CommonJS (dealt with on the bottom of the script)
-if ( typeof exports === "undefined" ) {
- extend( window, QUnit );
-
- // Expose QUnit object
- window.QUnit = QUnit;
-}
-
-// Initialize more QUnit.config and QUnit.urlParams
-(function() {
- var i,
- location = window.location || { search: "", protocol: "file:" },
- params = location.search.slice( 1 ).split( "&" ),
- length = params.length,
- urlParams = {},
- current;
-
- if ( params[ 0 ] ) {
- for ( i = 0; i < length; i++ ) {
- current = params[ i ].split( "=" );
- current[ 0 ] = decodeURIComponent( current[ 0 ] );
- // allow just a key to turn on a flag, e.g., test.html?noglobals
- current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true;
- urlParams[ current[ 0 ] ] = current[ 1 ];
- }
- }
-
- QUnit.urlParams = urlParams;
-
- // String search anywhere in moduleName+testName
- config.filter = urlParams.filter;
-
- // Exact match of the module name
- config.module = urlParams.module;
-
- config.testNumber = parseInt( urlParams.testNumber, 10 ) || null;
-
- // Figure out if we're running the tests from a server or not
- QUnit.isLocal = location.protocol === "file:";
-}());
-
-// Extend QUnit object,
-// these after set here because they should not be exposed as global functions
-extend( QUnit, {
- assert: assert,
-
- config: config,
-
- // Initialize the configuration options
- init: function() {
- extend( config, {
- stats: { all: 0, bad: 0 },
- moduleStats: { all: 0, bad: 0 },
- started: +new Date(),
- updateRate: 1000,
- blocking: false,
- autostart: true,
- autorun: false,
- filter: "",
- queue: [],
- semaphore: 1
- });
-
- var tests, banner, result,
- qunit = id( "qunit" );
-
- if ( qunit ) {
- qunit.innerHTML =
- "" +
- "" +
- "" +
- "" +
- "
";
- }
-
- tests = id( "qunit-tests" );
- banner = id( "qunit-banner" );
- result = id( "qunit-testresult" );
-
- if ( tests ) {
- tests.innerHTML = "";
- }
-
- if ( banner ) {
- banner.className = "";
- }
-
- if ( result ) {
- result.parentNode.removeChild( result );
- }
-
- if ( tests ) {
- result = document.createElement( "p" );
- result.id = "qunit-testresult";
- result.className = "result";
- tests.parentNode.insertBefore( result, tests );
- result.innerHTML = "Running...
";
- }
- },
-
- // Resets the test setup. Useful for tests that modify the DOM.
- reset: function() {
- var fixture = id( "qunit-fixture" );
- if ( fixture ) {
- fixture.innerHTML = config.fixture;
- }
- },
-
- // Trigger an event on an element.
- // @example triggerEvent( document.body, "click" );
- triggerEvent: function( elem, type, event ) {
- if ( document.createEvent ) {
- event = document.createEvent( "MouseEvents" );
- event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView,
- 0, 0, 0, 0, 0, false, false, false, false, 0, null);
-
- elem.dispatchEvent( event );
- } else if ( elem.fireEvent ) {
- elem.fireEvent( "on" + type );
- }
- },
-
- // Safe object type checking
- is: function( type, obj ) {
- return QUnit.objectType( obj ) === type;
- },
-
- objectType: function( obj ) {
- if ( typeof obj === "undefined" ) {
- return "undefined";
- // consider: typeof null === object
- }
- if ( obj === null ) {
- return "null";
- }
-
- var match = toString.call( obj ).match(/^\[object\s(.*)\]$/),
- type = match && match[1] || "";
-
- switch ( type ) {
- case "Number":
- if ( isNaN(obj) ) {
- return "nan";
- }
- return "number";
- case "String":
- case "Boolean":
- case "Array":
- case "Date":
- case "RegExp":
- case "Function":
- return type.toLowerCase();
- }
- if ( typeof obj === "object" ) {
- return "object";
- }
- return undefined;
- },
-
- push: function( result, actual, expected, message ) {
- if ( !config.current ) {
- throw new Error( "assertion outside test context, was " + sourceFromStacktrace() );
- }
-
- var output, source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: message,
- actual: actual,
- expected: expected
- };
-
- message = escapeText( message ) || ( result ? "okay" : "failed" );
- message = "" + message + "";
- output = message;
-
- if ( !result ) {
- expected = escapeText( QUnit.jsDump.parse(expected) );
- actual = escapeText( QUnit.jsDump.parse(actual) );
- output += "Expected: | " + expected + " |
";
-
- if ( actual !== expected ) {
- output += "Result: | " + actual + " |
";
- output += "Diff: | " + QUnit.diff( expected, actual ) + " |
";
- }
-
- source = sourceFromStacktrace();
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
- }
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: !!result,
- message: output
- });
- },
-
- pushFailure: function( message, source, actual ) {
- if ( !config.current ) {
- throw new Error( "pushFailure() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
-
- var output,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: false,
- message: message
- };
-
- message = escapeText( message ) || "error";
- message = "" + message + "";
- output = message;
-
- output += "";
-
- if ( actual ) {
- output += "Result: | " + escapeText( actual ) + " |
";
- }
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: false,
- message: output
- });
- },
-
- url: function( params ) {
- params = extend( extend( {}, QUnit.urlParams ), params );
- var key,
- querystring = "?";
-
- for ( key in params ) {
- if ( !hasOwn.call( params, key ) ) {
- continue;
- }
- querystring += encodeURIComponent( key ) + "=" +
- encodeURIComponent( params[ key ] ) + "&";
- }
- return window.location.protocol + "//" + window.location.host +
- window.location.pathname + querystring.slice( 0, -1 );
- },
-
- extend: extend,
- id: id,
- addEvent: addEvent
- // load, equiv, jsDump, diff: Attached later
-});
-
-/**
- * @deprecated: Created for backwards compatibility with test runner that set the hook function
- * into QUnit.{hook}, instead of invoking it and passing the hook function.
- * QUnit.constructor is set to the empty F() above so that we can add to it's prototype here.
- * Doing this allows us to tell if the following methods have been overwritten on the actual
- * QUnit object.
- */
-extend( QUnit.constructor.prototype, {
-
- // Logging callbacks; all receive a single argument with the listed properties
- // run test/logs.html for any related changes
- begin: registerLoggingCallback( "begin" ),
-
- // done: { failed, passed, total, runtime }
- done: registerLoggingCallback( "done" ),
-
- // log: { result, actual, expected, message }
- log: registerLoggingCallback( "log" ),
-
- // testStart: { name }
- testStart: registerLoggingCallback( "testStart" ),
-
- // testDone: { name, failed, passed, total, duration }
- testDone: registerLoggingCallback( "testDone" ),
-
- // moduleStart: { name }
- moduleStart: registerLoggingCallback( "moduleStart" ),
-
- // moduleDone: { name, failed, passed, total }
- moduleDone: registerLoggingCallback( "moduleDone" )
-});
-
-if ( typeof document === "undefined" || document.readyState === "complete" ) {
- config.autorun = true;
-}
-
-QUnit.load = function() {
- runLoggingCallbacks( "begin", QUnit, {} );
-
- // Initialize the config, saving the execution queue
- var banner, filter, i, label, len, main, ol, toolbar, userAgent, val,
- urlConfigCheckboxesContainer, urlConfigCheckboxes, moduleFilter,
- numModules = 0,
- moduleFilterHtml = "",
- urlConfigHtml = "",
- oldconfig = extend( {}, config );
-
- QUnit.init();
- extend(config, oldconfig);
-
- config.blocking = false;
-
- len = config.urlConfig.length;
-
- for ( i = 0; i < len; i++ ) {
- val = config.urlConfig[i];
- if ( typeof val === "string" ) {
- val = {
- id: val,
- label: val,
- tooltip: "[no tooltip available]"
- };
- }
- config[ val.id ] = QUnit.urlParams[ val.id ];
- urlConfigHtml += "";
- }
-
- moduleFilterHtml += "";
-
- // `userAgent` initialized at top of scope
- userAgent = id( "qunit-userAgent" );
- if ( userAgent ) {
- userAgent.innerHTML = navigator.userAgent;
- }
-
- // `banner` initialized at top of scope
- banner = id( "qunit-header" );
- if ( banner ) {
- banner.innerHTML = "" + banner.innerHTML + " ";
- }
-
- // `toolbar` initialized at top of scope
- toolbar = id( "qunit-testrunner-toolbar" );
- if ( toolbar ) {
- // `filter` initialized at top of scope
- filter = document.createElement( "input" );
- filter.type = "checkbox";
- filter.id = "qunit-filter-pass";
-
- addEvent( filter, "click", function() {
- var tmp,
- ol = document.getElementById( "qunit-tests" );
-
- if ( filter.checked ) {
- ol.className = ol.className + " hidepass";
- } else {
- tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " ";
- ol.className = tmp.replace( / hidepass /, " " );
- }
- if ( defined.sessionStorage ) {
- if (filter.checked) {
- sessionStorage.setItem( "qunit-filter-passed-tests", "true" );
- } else {
- sessionStorage.removeItem( "qunit-filter-passed-tests" );
- }
- }
- });
-
- if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem( "qunit-filter-passed-tests" ) ) {
- filter.checked = true;
- // `ol` initialized at top of scope
- ol = document.getElementById( "qunit-tests" );
- ol.className = ol.className + " hidepass";
- }
- toolbar.appendChild( filter );
-
- // `label` initialized at top of scope
- label = document.createElement( "label" );
- label.setAttribute( "for", "qunit-filter-pass" );
- label.setAttribute( "title", "Only show tests and assertons that fail. Stored in sessionStorage." );
- label.innerHTML = "Hide passed tests";
- toolbar.appendChild( label );
-
- urlConfigCheckboxesContainer = document.createElement("span");
- urlConfigCheckboxesContainer.innerHTML = urlConfigHtml;
- urlConfigCheckboxes = urlConfigCheckboxesContainer.getElementsByTagName("input");
- // For oldIE support:
- // * Add handlers to the individual elements instead of the container
- // * Use "click" instead of "change"
- // * Fallback from event.target to event.srcElement
- addEvents( urlConfigCheckboxes, "click", function( event ) {
- var params = {},
- target = event.target || event.srcElement;
- params[ target.name ] = target.checked ? true : undefined;
- window.location = QUnit.url( params );
- });
- toolbar.appendChild( urlConfigCheckboxesContainer );
-
- if (numModules > 1) {
- moduleFilter = document.createElement( 'span' );
- moduleFilter.setAttribute( 'id', 'qunit-modulefilter-container' );
- moduleFilter.innerHTML = moduleFilterHtml;
- addEvent( moduleFilter.lastChild, "change", function() {
- var selectBox = moduleFilter.getElementsByTagName("select")[0],
- selectedModule = decodeURIComponent(selectBox.options[selectBox.selectedIndex].value);
-
- window.location = QUnit.url( { module: ( selectedModule === "" ) ? undefined : selectedModule } );
- });
- toolbar.appendChild(moduleFilter);
- }
- }
-
- // `main` initialized at top of scope
- main = id( "qunit-fixture" );
- if ( main ) {
- config.fixture = main.innerHTML;
- }
-
- if ( config.autostart ) {
- QUnit.start();
- }
-};
-
-addEvent( window, "load", QUnit.load );
-
-// `onErrorFnPrev` initialized at top of scope
-// Preserve other handlers
-onErrorFnPrev = window.onerror;
-
-// Cover uncaught exceptions
-// Returning true will surpress the default browser handler,
-// returning false will let it run.
-window.onerror = function ( error, filePath, linerNr ) {
- var ret = false;
- if ( onErrorFnPrev ) {
- ret = onErrorFnPrev( error, filePath, linerNr );
- }
-
- // Treat return value as window.onerror itself does,
- // Only do our handling if not surpressed.
- if ( ret !== true ) {
- if ( QUnit.config.current ) {
- if ( QUnit.config.current.ignoreGlobalErrors ) {
- return true;
- }
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- } else {
- QUnit.test( "global failure", extend( function() {
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- }, { validTest: validTest } ) );
- }
- return false;
- }
-
- return ret;
-};
-
-function done() {
- config.autorun = true;
-
- // Log the last module results
- if ( config.currentModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.currentModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
-
- var i, key,
- banner = id( "qunit-banner" ),
- tests = id( "qunit-tests" ),
- runtime = +new Date() - config.started,
- passed = config.stats.all - config.stats.bad,
- html = [
- "Tests completed in ",
- runtime,
- " milliseconds.
",
- "",
- passed,
- " assertions of ",
- config.stats.all,
- " passed, ",
- config.stats.bad,
- " failed."
- ].join( "" );
-
- if ( banner ) {
- banner.className = ( config.stats.bad ? "qunit-fail" : "qunit-pass" );
- }
-
- if ( tests ) {
- id( "qunit-testresult" ).innerHTML = html;
- }
-
- if ( config.altertitle && typeof document !== "undefined" && document.title ) {
- // show ✖ for good, ✔ for bad suite result in title
- // use escape sequences in case file gets loaded with non-utf-8-charset
- document.title = [
- ( config.stats.bad ? "\u2716" : "\u2714" ),
- document.title.replace( /^[\u2714\u2716] /i, "" )
- ].join( " " );
- }
-
- // clear own sessionStorage items if all tests passed
- if ( config.reorder && defined.sessionStorage && config.stats.bad === 0 ) {
- // `key` & `i` initialized at top of scope
- for ( i = 0; i < sessionStorage.length; i++ ) {
- key = sessionStorage.key( i++ );
- if ( key.indexOf( "qunit-test-" ) === 0 ) {
- sessionStorage.removeItem( key );
- }
- }
- }
-
- // scroll back to top to show results
- if ( window.scrollTo ) {
- window.scrollTo(0, 0);
- }
-
- runLoggingCallbacks( "done", QUnit, {
- failed: config.stats.bad,
- passed: passed,
- total: config.stats.all,
- runtime: runtime
- });
-}
-
-/** @return Boolean: true if this test should be ran */
-function validTest( test ) {
- var include,
- filter = config.filter && config.filter.toLowerCase(),
- module = config.module && config.module.toLowerCase(),
- fullName = (test.module + ": " + test.testName).toLowerCase();
-
- // Internally-generated tests are always valid
- if ( test.callback && test.callback.validTest === validTest ) {
- delete test.callback.validTest;
- return true;
- }
-
- if ( config.testNumber ) {
- return test.testNumber === config.testNumber;
- }
-
- if ( module && ( !test.module || test.module.toLowerCase() !== module ) ) {
- return false;
- }
-
- if ( !filter ) {
- return true;
- }
-
- include = filter.charAt( 0 ) !== "!";
- if ( !include ) {
- filter = filter.slice( 1 );
- }
-
- // If the filter matches, we need to honour include
- if ( fullName.indexOf( filter ) !== -1 ) {
- return include;
- }
-
- // Otherwise, do the opposite
- return !include;
-}
-
-// so far supports only Firefox, Chrome and Opera (buggy), Safari (for real exceptions)
-// Later Safari and IE10 are supposed to support error.stack as well
-// See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack
-function extractStacktrace( e, offset ) {
- offset = offset === undefined ? 3 : offset;
-
- var stack, include, i;
-
- if ( e.stacktrace ) {
- // Opera
- return e.stacktrace.split( "\n" )[ offset + 3 ];
- } else if ( e.stack ) {
- // Firefox, Chrome
- stack = e.stack.split( "\n" );
- if (/^error$/i.test( stack[0] ) ) {
- stack.shift();
- }
- if ( fileName ) {
- include = [];
- for ( i = offset; i < stack.length; i++ ) {
- if ( stack[ i ].indexOf( fileName ) !== -1 ) {
- break;
- }
- include.push( stack[ i ] );
- }
- if ( include.length ) {
- return include.join( "\n" );
- }
- }
- return stack[ offset ];
- } else if ( e.sourceURL ) {
- // Safari, PhantomJS
- // hopefully one day Safari provides actual stacktraces
- // exclude useless self-reference for generated Error objects
- if ( /qunit.js$/.test( e.sourceURL ) ) {
- return;
- }
- // for actual exceptions, this is useful
- return e.sourceURL + ":" + e.line;
- }
-}
-function sourceFromStacktrace( offset ) {
- try {
- throw new Error();
- } catch ( e ) {
- return extractStacktrace( e, offset );
- }
-}
-
-/**
- * Escape text for attribute or text content.
- */
-function escapeText( s ) {
- if ( !s ) {
- return "";
- }
- s = s + "";
- // Both single quotes and double quotes (for attributes)
- return s.replace( /['"<>&]/g, function( s ) {
- switch( s ) {
- case '\'':
- return ''';
- case '"':
- return '"';
- case '<':
- return '<';
- case '>':
- return '>';
- case '&':
- return '&';
- }
- });
-}
-
-function synchronize( callback, last ) {
- config.queue.push( callback );
-
- if ( config.autorun && !config.blocking ) {
- process( last );
- }
-}
-
-function process( last ) {
- function next() {
- process( last );
- }
- var start = new Date().getTime();
- config.depth = config.depth ? config.depth + 1 : 1;
-
- while ( config.queue.length && !config.blocking ) {
- if ( !defined.setTimeout || config.updateRate <= 0 || ( ( new Date().getTime() - start ) < config.updateRate ) ) {
- config.queue.shift()();
- } else {
- window.setTimeout( next, 13 );
- break;
- }
- }
- config.depth--;
- if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) {
- done();
- }
-}
-
-function saveGlobal() {
- config.pollution = [];
-
- if ( config.noglobals ) {
- for ( var key in window ) {
- // in Opera sometimes DOM element ids show up here, ignore them
- if ( !hasOwn.call( window, key ) || /^qunit-test-output/.test( key ) ) {
- continue;
- }
- config.pollution.push( key );
- }
- }
-}
-
-function checkPollution() {
- var newGlobals,
- deletedGlobals,
- old = config.pollution;
-
- saveGlobal();
-
- newGlobals = diff( config.pollution, old );
- if ( newGlobals.length > 0 ) {
- QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join(", ") );
- }
-
- deletedGlobals = diff( old, config.pollution );
- if ( deletedGlobals.length > 0 ) {
- QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join(", ") );
- }
-}
-
-// returns a new Array with the elements that are in a but not in b
-function diff( a, b ) {
- var i, j,
- result = a.slice();
-
- for ( i = 0; i < result.length; i++ ) {
- for ( j = 0; j < b.length; j++ ) {
- if ( result[i] === b[j] ) {
- result.splice( i, 1 );
- i--;
- break;
- }
- }
- }
- return result;
-}
-
-function extend( a, b ) {
- for ( var prop in b ) {
- if ( b[ prop ] === undefined ) {
- delete a[ prop ];
-
- // Avoid "Member not found" error in IE8 caused by setting window.constructor
- } else if ( prop !== "constructor" || a !== window ) {
- a[ prop ] = b[ prop ];
- }
- }
-
- return a;
-}
-
-/**
- * @param {HTMLElement} elem
- * @param {string} type
- * @param {Function} fn
- */
-function addEvent( elem, type, fn ) {
- // Standards-based browsers
- if ( elem.addEventListener ) {
- elem.addEventListener( type, fn, false );
- // IE
- } else {
- elem.attachEvent( "on" + type, fn );
- }
-}
-
-/**
- * @param {Array|NodeList} elems
- * @param {string} type
- * @param {Function} fn
- */
-function addEvents( elems, type, fn ) {
- var i = elems.length;
- while ( i-- ) {
- addEvent( elems[i], type, fn );
- }
-}
-
-function hasClass( elem, name ) {
- return (" " + elem.className + " ").indexOf(" " + name + " ") > -1;
-}
-
-function addClass( elem, name ) {
- if ( !hasClass( elem, name ) ) {
- elem.className += (elem.className ? " " : "") + name;
- }
-}
-
-function removeClass( elem, name ) {
- var set = " " + elem.className + " ";
- // Class name may appear multiple times
- while ( set.indexOf(" " + name + " ") > -1 ) {
- set = set.replace(" " + name + " " , " ");
- }
- // If possible, trim it for prettiness, but not neccecarily
- elem.className = window.jQuery ? jQuery.trim( set ) : ( set.trim ? set.trim() : set );
-}
-
-function id( name ) {
- return !!( typeof document !== "undefined" && document && document.getElementById ) &&
- document.getElementById( name );
-}
-
-function registerLoggingCallback( key ) {
- return function( callback ) {
- config[key].push( callback );
- };
-}
-
-// Supports deprecated method of completely overwriting logging callbacks
-function runLoggingCallbacks( key, scope, args ) {
- var i, callbacks;
- if ( QUnit.hasOwnProperty( key ) ) {
- QUnit[ key ].call(scope, args );
- } else {
- callbacks = config[ key ];
- for ( i = 0; i < callbacks.length; i++ ) {
- callbacks[ i ].call( scope, args );
- }
- }
-}
-
-// Test for equality any JavaScript type.
-// Author: Philippe Rathé
-QUnit.equiv = (function() {
-
- // Call the o related callback with the given arguments.
- function bindCallbacks( o, callbacks, args ) {
- var prop = QUnit.objectType( o );
- if ( prop ) {
- if ( QUnit.objectType( callbacks[ prop ] ) === "function" ) {
- return callbacks[ prop ].apply( callbacks, args );
- } else {
- return callbacks[ prop ]; // or undefined
- }
- }
- }
-
- // the real equiv function
- var innerEquiv,
- // stack to decide between skip/abort functions
- callers = [],
- // stack to avoiding loops from circular referencing
- parents = [],
-
- getProto = Object.getPrototypeOf || function ( obj ) {
- return obj.__proto__;
- },
- callbacks = (function () {
-
- // for string, boolean, number and null
- function useStrictEquality( b, a ) {
- /*jshint eqeqeq:false */
- if ( b instanceof a.constructor || a instanceof b.constructor ) {
- // to catch short annotaion VS 'new' annotation of a
- // declaration
- // e.g. var i = 1;
- // var j = new Number(1);
- return a == b;
- } else {
- return a === b;
- }
- }
-
- return {
- "string": useStrictEquality,
- "boolean": useStrictEquality,
- "number": useStrictEquality,
- "null": useStrictEquality,
- "undefined": useStrictEquality,
-
- "nan": function( b ) {
- return isNaN( b );
- },
-
- "date": function( b, a ) {
- return QUnit.objectType( b ) === "date" && a.valueOf() === b.valueOf();
- },
-
- "regexp": function( b, a ) {
- return QUnit.objectType( b ) === "regexp" &&
- // the regex itself
- a.source === b.source &&
- // and its modifers
- a.global === b.global &&
- // (gmi) ...
- a.ignoreCase === b.ignoreCase &&
- a.multiline === b.multiline &&
- a.sticky === b.sticky;
- },
-
- // - skip when the property is a method of an instance (OOP)
- // - abort otherwise,
- // initial === would have catch identical references anyway
- "function": function() {
- var caller = callers[callers.length - 1];
- return caller !== Object && typeof caller !== "undefined";
- },
-
- "array": function( b, a ) {
- var i, j, len, loop;
-
- // b could be an object literal here
- if ( QUnit.objectType( b ) !== "array" ) {
- return false;
- }
-
- len = a.length;
- if ( len !== b.length ) {
- // safe and faster
- return false;
- }
-
- // track reference to avoid circular references
- parents.push( a );
- for ( i = 0; i < len; i++ ) {
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- loop = true;// dont rewalk array
- }
- }
- if ( !loop && !innerEquiv(a[i], b[i]) ) {
- parents.pop();
- return false;
- }
- }
- parents.pop();
- return true;
- },
-
- "object": function( b, a ) {
- var i, j, loop,
- // Default to true
- eq = true,
- aProperties = [],
- bProperties = [];
-
- // comparing constructors is more strict than using
- // instanceof
- if ( a.constructor !== b.constructor ) {
- // Allow objects with no prototype to be equivalent to
- // objects with Object as their constructor.
- if ( !(( getProto(a) === null && getProto(b) === Object.prototype ) ||
- ( getProto(b) === null && getProto(a) === Object.prototype ) ) ) {
- return false;
- }
- }
-
- // stack constructor before traversing properties
- callers.push( a.constructor );
- // track reference to avoid circular references
- parents.push( a );
-
- for ( i in a ) { // be strict: don't ensures hasOwnProperty
- // and go deep
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- // don't go down the same path twice
- loop = true;
- }
- }
- aProperties.push(i); // collect a's properties
-
- if (!loop && !innerEquiv( a[i], b[i] ) ) {
- eq = false;
- break;
- }
- }
-
- callers.pop(); // unstack, we are done
- parents.pop();
-
- for ( i in b ) {
- bProperties.push( i ); // collect b's properties
- }
-
- // Ensures identical properties name
- return eq && innerEquiv( aProperties.sort(), bProperties.sort() );
- }
- };
- }());
-
- innerEquiv = function() { // can take multiple arguments
- var args = [].slice.apply( arguments );
- if ( args.length < 2 ) {
- return true; // end transition
- }
-
- return (function( a, b ) {
- if ( a === b ) {
- return true; // catch the most you can
- } else if ( a === null || b === null || typeof a === "undefined" ||
- typeof b === "undefined" ||
- QUnit.objectType(a) !== QUnit.objectType(b) ) {
- return false; // don't lose time with error prone cases
- } else {
- return bindCallbacks(a, callbacks, [ b, a ]);
- }
-
- // apply transition with (1..n) arguments
- }( args[0], args[1] ) && arguments.callee.apply( this, args.splice(1, args.length - 1 )) );
- };
-
- return innerEquiv;
-}());
-
-/**
- * jsDump Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com |
- * http://flesler.blogspot.com Licensed under BSD
- * (http://www.opensource.org/licenses/bsd-license.php) Date: 5/15/2008
- *
- * @projectDescription Advanced and extensible data dumping for Javascript.
- * @version 1.0.0
- * @author Ariel Flesler
- * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html}
- */
-QUnit.jsDump = (function() {
- function quote( str ) {
- return '"' + str.toString().replace( /"/g, '\\"' ) + '"';
- }
- function literal( o ) {
- return o + "";
- }
- function join( pre, arr, post ) {
- var s = jsDump.separator(),
- base = jsDump.indent(),
- inner = jsDump.indent(1);
- if ( arr.join ) {
- arr = arr.join( "," + s + inner );
- }
- if ( !arr ) {
- return pre + post;
- }
- return [ pre, inner + arr, base + post ].join(s);
- }
- function array( arr, stack ) {
- var i = arr.length, ret = new Array(i);
- this.up();
- while ( i-- ) {
- ret[i] = this.parse( arr[i] , undefined , stack);
- }
- this.down();
- return join( "[", ret, "]" );
- }
-
- var reName = /^function (\w+)/,
- jsDump = {
- // type is used mostly internally, you can fix a (custom)type in advance
- parse: function( obj, type, stack ) {
- stack = stack || [ ];
- var inStack, res,
- parser = this.parsers[ type || this.typeOf(obj) ];
-
- type = typeof parser;
- inStack = inArray( obj, stack );
-
- if ( inStack !== -1 ) {
- return "recursion(" + (inStack - stack.length) + ")";
- }
- if ( type === "function" ) {
- stack.push( obj );
- res = parser.call( this, obj, stack );
- stack.pop();
- return res;
- }
- return ( type === "string" ) ? parser : this.parsers.error;
- },
- typeOf: function( obj ) {
- var type;
- if ( obj === null ) {
- type = "null";
- } else if ( typeof obj === "undefined" ) {
- type = "undefined";
- } else if ( QUnit.is( "regexp", obj) ) {
- type = "regexp";
- } else if ( QUnit.is( "date", obj) ) {
- type = "date";
- } else if ( QUnit.is( "function", obj) ) {
- type = "function";
- } else if ( typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined" ) {
- type = "window";
- } else if ( obj.nodeType === 9 ) {
- type = "document";
- } else if ( obj.nodeType ) {
- type = "node";
- } else if (
- // native arrays
- toString.call( obj ) === "[object Array]" ||
- // NodeList objects
- ( typeof obj.length === "number" && typeof obj.item !== "undefined" && ( obj.length ? obj.item(0) === obj[0] : ( obj.item( 0 ) === null && typeof obj[0] === "undefined" ) ) )
- ) {
- type = "array";
- } else if ( obj.constructor === Error.prototype.constructor ) {
- type = "error";
- } else {
- type = typeof obj;
- }
- return type;
- },
- separator: function() {
- return this.multiline ? this.HTML ? "
" : "\n" : this.HTML ? " " : " ";
- },
- // extra can be a number, shortcut for increasing-calling-decreasing
- indent: function( extra ) {
- if ( !this.multiline ) {
- return "";
- }
- var chr = this.indentChar;
- if ( this.HTML ) {
- chr = chr.replace( /\t/g, " " ).replace( / /g, " " );
- }
- return new Array( this._depth_ + (extra||0) ).join(chr);
- },
- up: function( a ) {
- this._depth_ += a || 1;
- },
- down: function( a ) {
- this._depth_ -= a || 1;
- },
- setParser: function( name, parser ) {
- this.parsers[name] = parser;
- },
- // The next 3 are exposed so you can use them
- quote: quote,
- literal: literal,
- join: join,
- //
- _depth_: 1,
- // This is the list of parsers, to modify them, use jsDump.setParser
- parsers: {
- window: "[Window]",
- document: "[Document]",
- error: function(error) {
- return "Error(\"" + error.message + "\")";
- },
- unknown: "[Unknown]",
- "null": "null",
- "undefined": "undefined",
- "function": function( fn ) {
- var ret = "function",
- // functions never have name in IE
- name = "name" in fn ? fn.name : (reName.exec(fn) || [])[1];
-
- if ( name ) {
- ret += " " + name;
- }
- ret += "( ";
-
- ret = [ ret, QUnit.jsDump.parse( fn, "functionArgs" ), "){" ].join( "" );
- return join( ret, QUnit.jsDump.parse(fn,"functionCode" ), "}" );
- },
- array: array,
- nodelist: array,
- "arguments": array,
- object: function( map, stack ) {
- var ret = [ ], keys, key, val, i;
- QUnit.jsDump.up();
- keys = [];
- for ( key in map ) {
- keys.push( key );
- }
- keys.sort();
- for ( i = 0; i < keys.length; i++ ) {
- key = keys[ i ];
- val = map[ key ];
- ret.push( QUnit.jsDump.parse( key, "key" ) + ": " + QUnit.jsDump.parse( val, undefined, stack ) );
- }
- QUnit.jsDump.down();
- return join( "{", ret, "}" );
- },
- node: function( node ) {
- var len, i, val,
- open = QUnit.jsDump.HTML ? "<" : "<",
- close = QUnit.jsDump.HTML ? ">" : ">",
- tag = node.nodeName.toLowerCase(),
- ret = open + tag,
- attrs = node.attributes;
-
- if ( attrs ) {
- for ( i = 0, len = attrs.length; i < len; i++ ) {
- val = attrs[i].nodeValue;
- // IE6 includes all attributes in .attributes, even ones not explicitly set.
- // Those have values like undefined, null, 0, false, "" or "inherit".
- if ( val && val !== "inherit" ) {
- ret += " " + attrs[i].nodeName + "=" + QUnit.jsDump.parse( val, "attribute" );
- }
- }
- }
- ret += close;
-
- // Show content of TextNode or CDATASection
- if ( node.nodeType === 3 || node.nodeType === 4 ) {
- ret += node.nodeValue;
- }
-
- return ret + open + "/" + tag + close;
- },
- // function calls it internally, it's the arguments part of the function
- functionArgs: function( fn ) {
- var args,
- l = fn.length;
-
- if ( !l ) {
- return "";
- }
-
- args = new Array(l);
- while ( l-- ) {
- // 97 is 'a'
- args[l] = String.fromCharCode(97+l);
- }
- return " " + args.join( ", " ) + " ";
- },
- // object calls it internally, the key part of an item in a map
- key: quote,
- // function calls it internally, it's the content of the function
- functionCode: "[code]",
- // node calls it internally, it's an html attribute value
- attribute: quote,
- string: quote,
- date: quote,
- regexp: literal,
- number: literal,
- "boolean": literal
- },
- // if true, entities are escaped ( <, >, \t, space and \n )
- HTML: false,
- // indentation unit
- indentChar: " ",
- // if true, items in a collection, are separated by a \n, else just a space.
- multiline: true
- };
-
- return jsDump;
-}());
-
-// from jquery.js
-function inArray( elem, array ) {
- if ( array.indexOf ) {
- return array.indexOf( elem );
- }
-
- for ( var i = 0, length = array.length; i < length; i++ ) {
- if ( array[ i ] === elem ) {
- return i;
- }
- }
-
- return -1;
-}
-
-/*
- * Javascript Diff Algorithm
- * By John Resig (http://ejohn.org/)
- * Modified by Chu Alan "sprite"
- *
- * Released under the MIT license.
- *
- * More Info:
- * http://ejohn.org/projects/javascript-diff-algorithm/
- *
- * Usage: QUnit.diff(expected, actual)
- *
- * QUnit.diff( "the quick brown fox jumped over", "the quick fox jumps over" ) == "the quick brown fox jumped jumps over"
- */
-QUnit.diff = (function() {
- /*jshint eqeqeq:false, eqnull:true */
- function diff( o, n ) {
- var i,
- ns = {},
- os = {};
-
- for ( i = 0; i < n.length; i++ ) {
- if ( !hasOwn.call( ns, n[i] ) ) {
- ns[ n[i] ] = {
- rows: [],
- o: null
- };
- }
- ns[ n[i] ].rows.push( i );
- }
-
- for ( i = 0; i < o.length; i++ ) {
- if ( !hasOwn.call( os, o[i] ) ) {
- os[ o[i] ] = {
- rows: [],
- n: null
- };
- }
- os[ o[i] ].rows.push( i );
- }
-
- for ( i in ns ) {
- if ( !hasOwn.call( ns, i ) ) {
- continue;
- }
- if ( ns[i].rows.length === 1 && hasOwn.call( os, i ) && os[i].rows.length === 1 ) {
- n[ ns[i].rows[0] ] = {
- text: n[ ns[i].rows[0] ],
- row: os[i].rows[0]
- };
- o[ os[i].rows[0] ] = {
- text: o[ os[i].rows[0] ],
- row: ns[i].rows[0]
- };
- }
- }
-
- for ( i = 0; i < n.length - 1; i++ ) {
- if ( n[i].text != null && n[ i + 1 ].text == null && n[i].row + 1 < o.length && o[ n[i].row + 1 ].text == null &&
- n[ i + 1 ] == o[ n[i].row + 1 ] ) {
-
- n[ i + 1 ] = {
- text: n[ i + 1 ],
- row: n[i].row + 1
- };
- o[ n[i].row + 1 ] = {
- text: o[ n[i].row + 1 ],
- row: i + 1
- };
- }
- }
-
- for ( i = n.length - 1; i > 0; i-- ) {
- if ( n[i].text != null && n[ i - 1 ].text == null && n[i].row > 0 && o[ n[i].row - 1 ].text == null &&
- n[ i - 1 ] == o[ n[i].row - 1 ]) {
-
- n[ i - 1 ] = {
- text: n[ i - 1 ],
- row: n[i].row - 1
- };
- o[ n[i].row - 1 ] = {
- text: o[ n[i].row - 1 ],
- row: i - 1
- };
- }
- }
-
- return {
- o: o,
- n: n
- };
- }
-
- return function( o, n ) {
- o = o.replace( /\s+$/, "" );
- n = n.replace( /\s+$/, "" );
-
- var i, pre,
- str = "",
- out = diff( o === "" ? [] : o.split(/\s+/), n === "" ? [] : n.split(/\s+/) ),
- oSpace = o.match(/\s+/g),
- nSpace = n.match(/\s+/g);
-
- if ( oSpace == null ) {
- oSpace = [ " " ];
- }
- else {
- oSpace.push( " " );
- }
-
- if ( nSpace == null ) {
- nSpace = [ " " ];
- }
- else {
- nSpace.push( " " );
- }
-
- if ( out.n.length === 0 ) {
- for ( i = 0; i < out.o.length; i++ ) {
- str += "" + out.o[i] + oSpace[i] + "";
- }
- }
- else {
- if ( out.n[0].text == null ) {
- for ( n = 0; n < out.o.length && out.o[n].text == null; n++ ) {
- str += "" + out.o[n] + oSpace[n] + "";
- }
- }
-
- for ( i = 0; i < out.n.length; i++ ) {
- if (out.n[i].text == null) {
- str += "" + out.n[i] + nSpace[i] + "";
- }
- else {
- // `pre` initialized at top of scope
- pre = "";
-
- for ( n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++ ) {
- pre += "" + out.o[n] + oSpace[n] + "";
- }
- str += " " + out.n[i].text + nSpace[i] + pre;
- }
- }
- }
-
- return str;
- };
-}());
-
-// for CommonJS enviroments, export everything
-if ( typeof exports !== "undefined" ) {
- extend( exports, QUnit );
-}
-
-// get at whatever the global object is, like window in browsers
-}( (function() {return this;}.call()) ));
diff --git a/test/lib/require.js b/test/lib/require.js
deleted file mode 100644
index 987f865..0000000
--- a/test/lib/require.js
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- RequireJS 2.1.5 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.
- Available via the MIT or new BSD license.
- see: http://github.com/jrburke/requirejs for details
-*/
-var requirejs,require,define;
-(function(aa){function I(b){return"[object Function]"===L.call(b)}function J(b){return"[object Array]"===L.call(b)}function y(b,c){if(b){var d;for(d=0;dthis.depCount&&!this.defined){if(I(n)){if(this.events.error)try{e=i.execCb(c,n,b,e)}catch(d){a=d}else e=i.execCb(c,n,b,e);this.map.isDefine&&((b=this.module)&&void 0!==b.exports&&b.exports!==this.exports?e=b.exports:void 0===e&&this.usingExports&&(e=this.exports));if(a)return a.requireMap=this.map,a.requireModules=[this.map.id],a.requireType="define",v(this.error=
-a)}else e=n;this.exports=e;if(this.map.isDefine&&!this.ignore&&(q[c]=e,l.onResourceLoad))l.onResourceLoad(i,this.map,this.depMaps);x(c);this.defined=!0}this.defining=!1;this.defined&&!this.defineEmitted&&(this.defineEmitted=!0,this.emit("defined",this.exports),this.defineEmitComplete=!0)}}else this.fetch()}},callPlugin:function(){var a=this.map,b=a.id,d=j(a.prefix);this.depMaps.push(d);t(d,"defined",u(this,function(e){var n,d;d=this.map.name;var g=this.map.parentMap?this.map.parentMap.name:null,h=
-i.makeRequire(a.parentMap,{enableBuildCallback:!0});if(this.map.unnormalized){if(e.normalize&&(d=e.normalize(d,function(a){return c(a,g,!0)})||""),e=j(a.prefix+"!"+d,this.map.parentMap),t(e,"defined",u(this,function(a){this.init([],function(){return a},null,{enabled:!0,ignore:!0})})),d=m(p,e.id)){this.depMaps.push(e);if(this.events.error)d.on("error",u(this,function(a){this.emit("error",a)}));d.enable()}}else n=u(this,function(a){this.init([],function(){return a},null,{enabled:!0})}),n.error=u(this,
-function(a){this.inited=!0;this.error=a;a.requireModules=[b];G(p,function(a){0===a.map.id.indexOf(b+"_unnormalized")&&x(a.map.id)});v(a)}),n.fromText=u(this,function(e,c){var d=a.name,g=j(d),C=O;c&&(e=c);C&&(O=!1);r(g);s(k.config,b)&&(k.config[d]=k.config[b]);try{l.exec(e)}catch(ca){return v(B("fromtexteval","fromText eval for "+b+" failed: "+ca,ca,[b]))}C&&(O=!0);this.depMaps.push(g);i.completeLoad(d);h([d],n)}),e.load(a.name,h,n,k)}));i.enable(d,this);this.pluginMaps[d.id]=d},enable:function(){V[this.map.id]=
-this;this.enabling=this.enabled=!0;y(this.depMaps,u(this,function(a,b){var c,e;if("string"===typeof a){a=j(a,this.map.isDefine?this.map:this.map.parentMap,!1,!this.skipMap);this.depMaps[b]=a;if(c=m(N,a.id)){this.depExports[b]=c(this);return}this.depCount+=1;t(a,"defined",u(this,function(a){this.defineDep(b,a);this.check()}));this.errback&&t(a,"error",this.errback)}c=a.id;e=p[c];!s(N,c)&&(e&&!e.enabled)&&i.enable(a,this)}));G(this.pluginMaps,u(this,function(a){var b=m(p,a.id);b&&!b.enabled&&i.enable(a,
-this)}));this.enabling=!1;this.check()},on:function(a,b){var c=this.events[a];c||(c=this.events[a]=[]);c.push(b)},emit:function(a,b){y(this.events[a],function(a){a(b)});"error"===a&&delete this.events[a]}};i={config:k,contextName:b,registry:p,defined:q,urlFetched:U,defQueue:H,Module:Z,makeModuleMap:j,nextTick:l.nextTick,onError:v,configure:function(a){a.baseUrl&&"/"!==a.baseUrl.charAt(a.baseUrl.length-1)&&(a.baseUrl+="/");var b=k.pkgs,c=k.shim,e={paths:!0,config:!0,map:!0};G(a,function(a,b){e[b]?
-"map"===b?(k.map||(k.map={}),R(k[b],a,!0,!0)):R(k[b],a,!0):k[b]=a});a.shim&&(G(a.shim,function(a,b){J(a)&&(a={deps:a});if((a.exports||a.init)&&!a.exportsFn)a.exportsFn=i.makeShimExports(a);c[b]=a}),k.shim=c);a.packages&&(y(a.packages,function(a){a="string"===typeof a?{name:a}:a;b[a.name]={name:a.name,location:a.location||a.name,main:(a.main||"main").replace(ja,"").replace(ea,"")}}),k.pkgs=b);G(p,function(a,b){!a.inited&&!a.map.unnormalized&&(a.map=j(b))});if(a.deps||a.callback)i.require(a.deps||[],
-a.callback)},makeShimExports:function(a){return function(){var b;a.init&&(b=a.init.apply(aa,arguments));return b||a.exports&&ba(a.exports)}},makeRequire:function(a,f){function d(e,c,h){var g,k;f.enableBuildCallback&&(c&&I(c))&&(c.__requireJsBuild=!0);if("string"===typeof e){if(I(c))return v(B("requireargs","Invalid require call"),h);if(a&&s(N,e))return N[e](p[a.id]);if(l.get)return l.get(i,e,a,d);g=j(e,a,!1,!0);g=g.id;return!s(q,g)?v(B("notloaded",'Module name "'+g+'" has not been loaded yet for context: '+
-b+(a?"":". Use require([])"))):q[g]}L();i.nextTick(function(){L();k=r(j(null,a));k.skipMap=f.skipMap;k.init(e,c,h,{enabled:!0});D()});return d}f=f||{};R(d,{isBrowser:A,toUrl:function(b){var d,f=b.lastIndexOf("."),g=b.split("/")[0];if(-1!==f&&(!("."===g||".."===g)||1h.attachEvent.toString().indexOf("[native code"))&&!Y?(O=!0,h.attachEvent("onreadystatechange",b.onScriptLoad)):(h.addEventListener("load",b.onScriptLoad,!1),h.addEventListener("error",b.onScriptError,!1)),h.src=d,K=h,D?x.insertBefore(h,D):x.appendChild(h),K=null,h;if(da)try{importScripts(d),b.completeLoad(c)}catch(j){b.onError(B("importscripts","importScripts failed for "+c+" at "+d,j,[c]))}};A&&M(document.getElementsByTagName("script"),function(b){x||(x=
-b.parentNode);if(t=b.getAttribute("data-main"))return r.baseUrl||(E=t.split("/"),Q=E.pop(),fa=E.length?E.join("/")+"/":"./",r.baseUrl=fa,t=Q),t=t.replace(ea,""),r.deps=r.deps?r.deps.concat(t):[t],!0});define=function(b,c,d){var l,h;"string"!==typeof b&&(d=c,c=b,b=null);J(c)||(d=c,c=[]);!c.length&&I(d)&&d.length&&(d.toString().replace(la,"").replace(ma,function(b,d){c.push(d)}),c=(1===d.length?["require"]:["require","exports","module"]).concat(c));if(O){if(!(l=K))P&&"interactive"===P.readyState||M(document.getElementsByTagName("script"),
-function(b){if("interactive"===b.readyState)return P=b}),l=P;l&&(b||(b=l.getAttribute("data-requiremodule")),h=F[l.getAttribute("data-requirecontext")])}(h?h.defQueue:T).push([b,c,d])};define.amd={jQuery:!0};l.exec=function(b){return eval(b)};l(r)}})(this);
diff --git a/test/lib/resemble.js b/test/lib/resemble.js
new file mode 100644
index 0000000..1cb8c29
--- /dev/null
+++ b/test/lib/resemble.js
@@ -0,0 +1,535 @@
+/*
+Author: James Cryer
+Company: Huddle
+Last updated date: 21 Feb 2013
+URL: https://github.com/Huddle/Resemble.js
+*/
+
+(function(_this){
+ 'use strict';
+
+ _this['resemble'] = function( fileData ){
+
+ var data = {};
+ var images = [];
+ var updateCallbackArray = [];
+
+ var tolerance = { // between 0 and 255
+ red: 16,
+ green: 16,
+ blue: 16,
+ minBrightness: 16,
+ maxBrightness: 240
+ };
+
+ var ignoreAntialiasing = false;
+ var ignoreColors = false;
+
+ function triggerDataUpdate(){
+ var len = updateCallbackArray.length;
+ var i;
+ for(i=0;i tolerance.maxBrightness;
+ }
+
+ function getHue(r,g,b){
+
+ r = r / 255;
+ g = g / 255;
+ b = b / 255;
+ var max = Math.max(r, g, b), min = Math.min(r, g, b);
+ var h;
+ var d;
+
+ if (max == min){
+ h = 0; // achromatic
+ } else{
+ d = max - min;
+ switch(max){
+ case r: h = (g - b) / d + (g < b ? 6 : 0); break;
+ case g: h = (b - r) / d + 2; break;
+ case b: h = (r - g) / d + 4; break;
+ }
+ h /= 6;
+ }
+
+ return h;
+ }
+
+ function isAntialiased(sourcePix, data, cacheSet, verticalPos, horizontalPos, width){
+ var offset;
+ var targetPix;
+ var distance = 1;
+ var i;
+ var j;
+ var hasHighContrastSibling = 0;
+ var hasSiblingWithDifferentHue = 0;
+ var hasEquivilantSibling = 0;
+
+ addHueInfo(sourcePix);
+
+ for (i = distance*-1; i <= distance; i++){
+ for (j = distance*-1; j <= distance; j++){
+
+ if(i===0 && j===0){
+ // ignore source pixel
+ } else {
+
+ offset = ((verticalPos+j)*width + (horizontalPos+i)) * 4;
+ targetPix = getPixelInfo(data, offset, cacheSet);
+
+ if(targetPix === null){
+ continue;
+ }
+
+ addBrightnessInfo(targetPix);
+ addHueInfo(targetPix);
+
+ if( isContrasting(sourcePix, targetPix) ){
+ hasHighContrastSibling++;
+ }
+
+ if( isRGBSame(sourcePix,targetPix) ){
+ hasEquivilantSibling++;
+ }
+
+ if( Math.abs(targetPix.h - sourcePix.h) > 0.3 ){
+ hasSiblingWithDifferentHue++;
+ }
+
+ if( hasSiblingWithDifferentHue > 1 || hasHighContrastSibling > 1){
+ return true;
+ }
+ }
+ }
+ }
+
+ if(hasEquivilantSibling < 2){
+ return true;
+ }
+
+ return false;
+ }
+
+ function errorPixel(px, offset){
+ px[offset] = 255; //r
+ px[offset + 1] = 0; //g
+ px[offset + 2] = 255; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyPixel(px, offset, data){
+ px[offset] = data.r; //r
+ px[offset + 1] = data.g; //g
+ px[offset + 2] = data.b; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyGrayScalePixel(px, offset, data){
+ px[offset] = data.brightness; //r
+ px[offset + 1] = data.brightness; //g
+ px[offset + 2] = data.brightness; //b
+ px[offset + 3] = 255; //a
+ }
+
+
+ function getPixelInfo(data, offset, cacheSet){
+ var r;
+ var g;
+ var b;
+ var d;
+
+ if(typeof data[offset] !== 'undefined'){
+ r = data[offset];
+ g = data[offset+1];
+ b = data[offset+2];
+ d = {
+ r: r,
+ g: g,
+ b: b
+ };
+
+ return d;
+ } else {
+ return null;
+ }
+ }
+
+ function addBrightnessInfo(data){
+ data.brightness = getBrightness(data.r,data.g,data.b); // 'corrected' lightness
+ }
+
+ function addHueInfo(data){
+ data.h = getHue(data.r,data.g,data.b);
+ }
+
+ function analyseImages(img1, img2, width, height){
+
+ var hiddenCanvas = document.createElement('canvas');
+
+ var data1 = img1.data;
+ var data2 = img2.data;
+
+ hiddenCanvas.width = width;
+ hiddenCanvas.height = height;
+
+ var context = hiddenCanvas.getContext('2d');
+ var imgd = context.createImageData(width,height);
+ var targetPix = imgd.data;
+
+ var mismatchCount = 0;
+
+ var time = Date.now();
+
+ var skip;
+
+ if( (width > 1200 || height > 1200) && ignoreAntialiasing){
+ skip = 6;
+ }
+
+ loop(height, width, function(verticalPos, horizontalPos){
+
+ if(skip){ // only skip if the image isn't small
+ if(verticalPos % skip === 0 || horizontalPos % skip === 0){
+ return;
+ }
+ }
+
+ var offset = (verticalPos*width + horizontalPos) * 4;
+ var pixel1 = getPixelInfo(data1, offset, 1);
+ var pixel2 = getPixelInfo(data2, offset, 2);
+
+ if(pixel1 === null || pixel2 === null){
+ return;
+ }
+
+ if (ignoreColors){
+
+ addBrightnessInfo(pixel1);
+ addBrightnessInfo(pixel2);
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ return;
+ }
+
+ if( isRGBSimilar(pixel1, pixel2) ){
+ copyPixel(targetPix, offset, pixel2);
+
+ } else if( ignoreAntialiasing && (
+ addBrightnessInfo(pixel1), // jit pixel info augmentation looks a little weird, sorry.
+ addBrightnessInfo(pixel2),
+ isAntialiased(pixel1, data1, 1, verticalPos, horizontalPos, width) ||
+ isAntialiased(pixel2, data2, 2, verticalPos, horizontalPos, width)
+ )){
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+
+ });
+
+ data.misMatchPercentage = (mismatchCount / (height*width) * 100).toFixed(2);
+ data.analysisTime = Date.now() - time;
+
+ data.getImageDataUrl = function(text){
+ var barHeight = 0;
+
+ if(text){
+ barHeight = addLabel(text,context,hiddenCanvas);
+ }
+
+ context.putImageData(imgd, 0, barHeight);
+
+ return hiddenCanvas.toDataURL("image/png");
+ };
+ }
+
+ function addLabel(text, context, hiddenCanvas){
+ var textPadding = 2;
+
+ context.font = '12px sans-serif';
+
+ var textWidth = context.measureText(text).width + textPadding*2;
+ var barHeight = 22;
+
+ if(textWidth > hiddenCanvas.width){
+ hiddenCanvas.width = textWidth;
+ }
+
+ hiddenCanvas.height += barHeight;
+
+ context.fillStyle = "#666";
+ context.fillRect(0,0,hiddenCanvas.width,barHeight -4);
+ context.fillStyle = "#fff";
+ context.fillRect(0,barHeight -4,hiddenCanvas.width, 4);
+
+ context.fillStyle = "#fff";
+ context.textBaseline = "top";
+ context.font = '12px sans-serif';
+ context.fillText(text, textPadding, 1);
+
+ return barHeight;
+ }
+
+ function normalise(img, w, h){
+ var c;
+ var context;
+
+ if(img.height < h || img.width < w){
+ c = document.createElement('canvas');
+ c.width = w;
+ c.height = h;
+ context = c.getContext('2d');
+ context.putImageData(img, 0, 0);
+ return context.getImageData(0, 0, w, h);
+ }
+
+ return img;
+ }
+
+ function compare(one, two){
+
+ function onceWeHaveBoth(){
+ var width;
+ var height;
+ if(images.length === 2){
+ width = images[0].width > images[1].width ? images[0].width : images[1].width;
+ height = images[0].height > images[1].height ? images[0].height : images[1].height;
+
+ if( (images[0].width === images[1].width) && (images[0].height === images[1].height) ){
+ data.isSameDimensions = true;
+ } else {
+ data.isSameDimensions = false;
+ }
+
+ analyseImages( normalise(images[0],width, height), normalise(images[1],width, height), width, height);
+
+ triggerDataUpdate();
+ }
+ }
+
+ images = [];
+ loadImageData(one, onceWeHaveBoth);
+ loadImageData(two, onceWeHaveBoth);
+ }
+
+ function getCompareApi(param){
+
+ var secondFileData,
+ hasMethod = typeof param === 'function';
+
+ if( !hasMethod ){
+ // assume it's file data
+ secondFileData = param;
+ }
+
+ var self = {
+ ignoreNothing: function(){
+
+ tolerance.red = 16;
+ tolerance.green = 16;
+ tolerance.blue = 16;
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreAntialiasing: function(){
+
+ tolerance.red = 32;
+ tolerance.green = 32;
+ tolerance.blue = 32;
+ tolerance.minBrightness = 64;
+ tolerance.maxBrightness = 96;
+
+ ignoreAntialiasing = true;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreColors: function(){
+
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = true;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ onComplete: function( callback ){
+
+ updateCallbackArray.push(callback);
+
+ var wrapper = function(){
+ compare(fileData, secondFileData);
+ };
+
+ wrapper();
+
+ return getCompareApi(wrapper);
+ }
+ };
+
+ return self;
+ }
+
+ return {
+ onComplete: function( callback ){
+ updateCallbackArray.push(callback);
+ loadImageData(fileData, function(imageData, width, height){
+ parseImage(imageData.data, width, height);
+ });
+ },
+ compareTo: function(secondFileData){
+ return getCompareApi(secondFileData);
+ }
+ };
+
+ };
+}(this));
\ No newline at end of file
diff --git a/test/testsuite.js b/test/testsuite.js
deleted file mode 100644
index b486acb..0000000
--- a/test/testsuite.js
+++ /dev/null
@@ -1,36 +0,0 @@
-requirejs.config({
- baseUrl: '/test/unit/'
-});
-
-define(function(require) {
- var testModules = [
- 'Pixi',
- 'Point',
- 'Rectangle',
- 'DisplayObject',
- 'DisplayObjectContainer',
- 'Sprite',
- 'MovieClip',
- 'InteractionManager',
- 'Stage',
- 'utils/Utils',
- 'utils/EventTarget',
- 'utils/Matrix',
- 'utils/Detector',
- 'renderers/WebGLShaders',
- 'renderers/WebGLRenderer',
- 'renderers/WebGLBatch',
- 'renderers/CanvasRenderer',
- 'extras/Strip',
- 'extras/Rope',
- 'textures/BaseTexture',
- 'textures/Texture',
- 'loaders/SpriteSheetLoader',
- 'loaders/AssetLoader'
- ];
-
- // Resolve all testModules and then start the Test Runner.
- require(testModules, function() {
- QUnit.start();
- });
-});
\ No newline at end of file
diff --git a/test/textures/SpriteSheet-Aliens.png b/test/textures/SpriteSheet-Aliens.png
new file mode 100644
index 0000000..210acb1
--- /dev/null
+++ b/test/textures/SpriteSheet-Aliens.png
Binary files differ
diff --git a/test/textures/SpriteSheet-Explosion.png b/test/textures/SpriteSheet-Explosion.png
new file mode 100755
index 0000000..79e1a69
--- /dev/null
+++ b/test/textures/SpriteSheet-Explosion.png
Binary files differ
diff --git a/test/textures/bunny.png b/test/textures/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/textures/bunny.png
Binary files differ
diff --git a/test/unit/DisplayObject.js b/test/unit/DisplayObject.js
deleted file mode 100644
index 5e7e72f..0000000
--- a/test/unit/DisplayObject.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObject');
-});
diff --git a/test/unit/DisplayObjectContainer.js b/test/unit/DisplayObjectContainer.js
deleted file mode 100644
index b323959..0000000
--- a/test/unit/DisplayObjectContainer.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObjectContainer');
-});
diff --git a/test/unit/InteractionManager.js b/test/unit/InteractionManager.js
deleted file mode 100644
index e751f52..0000000
--- a/test/unit/InteractionManager.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('InteractionManager');
-});
diff --git a/test/unit/MovieClip.js b/test/unit/MovieClip.js
deleted file mode 100644
index 37d9446..0000000
--- a/test/unit/MovieClip.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('MovieClip');
-});
diff --git a/test/unit/Pixi.js b/test/unit/Pixi.js
deleted file mode 100644
index 36eee73..0000000
--- a/test/unit/Pixi.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Pixi');
-});
diff --git a/test/unit/Point.js b/test/unit/Point.js
deleted file mode 100644
index 983ff6e..0000000
--- a/test/unit/Point.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Point');
-});
diff --git a/test/unit/Rectangle.js b/test/unit/Rectangle.js
deleted file mode 100644
index 3b439ba..0000000
--- a/test/unit/Rectangle.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Rectangle');
-});
diff --git a/test/unit/Sprite.js b/test/unit/Sprite.js
deleted file mode 100644
index ed4f596..0000000
--- a/test/unit/Sprite.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Sprite');
-});
diff --git a/test/unit/Stage.js b/test/unit/Stage.js
deleted file mode 100644
index 2d70291..0000000
--- a/test/unit/Stage.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Stage');
-});
diff --git a/test/unit/extras/Rope.js b/test/unit/extras/Rope.js
deleted file mode 100644
index 5606f14..0000000
--- a/test/unit/extras/Rope.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Rope');
-});
diff --git a/test/unit/extras/Strip.js b/test/unit/extras/Strip.js
deleted file mode 100644
index 0134d3a..0000000
--- a/test/unit/extras/Strip.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Strip');
-});
diff --git a/test/unit/loaders/AssetLoader.js b/test/unit/loaders/AssetLoader.js
deleted file mode 100644
index 13b8443..0000000
--- a/test/unit/loaders/AssetLoader.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('AssetLoader');
-});
diff --git a/test/unit/loaders/SpriteSheetLoader.js b/test/unit/loaders/SpriteSheetLoader.js
deleted file mode 100644
index 8bf0cb2..0000000
--- a/test/unit/loaders/SpriteSheetLoader.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('SpriteSheetLoader');
-});
diff --git a/test/unit/pixi/InteractionManager.js b/test/unit/pixi/InteractionManager.js
new file mode 100644
index 0000000..ed3001f
--- /dev/null
+++ b/test/unit/pixi/InteractionManager.js
@@ -0,0 +1,10 @@
+describe('pixi/InteractionManager', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var InteractionManager = PIXI.InteractionManager;
+
+ it('Module exists', function () {
+ expect(InteractionManager).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/Pixi.js b/test/unit/pixi/Pixi.js
new file mode 100644
index 0000000..27debc1
--- /dev/null
+++ b/test/unit/pixi/Pixi.js
@@ -0,0 +1,9 @@
+describe('pixi/Pixi', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+
+ it('Module exists', function () {
+ expect(global).to.have.property('PIXI').and.to.be.an('object');
+ });
+});
diff --git a/test/unit/pixi/core/Circle.js b/test/unit/pixi/core/Circle.js
new file mode 100644
index 0000000..93a4456
--- /dev/null
+++ b/test/unit/pixi/core/Circle.js
@@ -0,0 +1,22 @@
+describe('pixi/core/Circle', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Circle = PIXI.Circle;
+
+ it('Module exists', function () {
+ expect(Circle).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Circle();
+
+ expect(obj).to.be.an.instanceof(Circle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', 0);
+ expect(obj).to.have.property('y', 0);
+ expect(obj).to.have.property('radius', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Ellipse.js b/test/unit/pixi/core/Ellipse.js
new file mode 100644
index 0000000..026b56f
--- /dev/null
+++ b/test/unit/pixi/core/Ellipse.js
@@ -0,0 +1,24 @@
+describe('pixi/core/Ellipse', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Ellipse = PIXI.Ellipse;
+
+ it('Module exists', function () {
+ expect(Ellipse).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Ellipse();
+
+ expect(obj).to.be.an.instanceof(Ellipse);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+ expect(obj).to.respondTo('getBounds');
+
+ expect(obj).to.have.property('x', 0);
+ expect(obj).to.have.property('y', 0);
+ expect(obj).to.have.property('width', 0);
+ expect(obj).to.have.property('height', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Matrix.js b/test/unit/pixi/core/Matrix.js
new file mode 100644
index 0000000..b48989e
--- /dev/null
+++ b/test/unit/pixi/core/Matrix.js
@@ -0,0 +1,30 @@
+describe('pixi/core/Matrix', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var mat3 = PIXI.mat3;
+ var mat4 = PIXI.mat4;
+ var Matrix = PIXI.Matrix;
+
+ it('Ensure determineMatrixArrayType works', function () {
+ expect(Matrix).to.be.a('function');
+ });
+
+ it('mat3 exists', function () {
+ expect(mat3).to.be.an('object');
+ });
+
+ it('Confirm new mat3 matrix', function () {
+ var matrix = new mat3.create();
+ pixi_core_Matrix_confirmNewMat3(matrix);
+ });
+
+ it('mat3 exists', function () {
+ expect(mat4).to.be.an('object');
+ });
+
+ it('Confirm new mat4 matrix', function () {
+ var matrix = new mat4.create();
+ pixi_core_Matrix_confirmNewMat4(matrix);
+ });
+});
diff --git a/test/unit/pixi/core/Point.js b/test/unit/pixi/core/Point.js
new file mode 100644
index 0000000..c4d5163
--- /dev/null
+++ b/test/unit/pixi/core/Point.js
@@ -0,0 +1,15 @@
+describe('pixi/core/Point', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Point = PIXI.Point;
+
+ it('Module exists', function () {
+ expect(Point).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Point();
+ pixi_core_Point_confirm(obj, 0, 0);
+ });
+});
diff --git a/test/unit/pixi/core/Polygon.js b/test/unit/pixi/core/Polygon.js
new file mode 100644
index 0000000..dc8c918
--- /dev/null
+++ b/test/unit/pixi/core/Polygon.js
@@ -0,0 +1,20 @@
+describe('pixi/core/Polygon', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Polygon = PIXI.Polygon;
+
+ it('Module exists', function () {
+ expect(Polygon).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Polygon();
+
+ expect(obj).to.be.an.instanceof(Polygon);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.deep.property('points.length', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Rectangle.js b/test/unit/pixi/core/Rectangle.js
new file mode 100644
index 0000000..d43316e
--- /dev/null
+++ b/test/unit/pixi/core/Rectangle.js
@@ -0,0 +1,15 @@
+describe('pixi/core/Rectangle', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Rectangle = PIXI.Rectangle;
+
+ it('Module exists', function () {
+ expect(Rectangle).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var rect = new Rectangle();
+ pixi_core_Rectangle_confirm(rect, 0, 0, 0, 0);
+ });
+});
diff --git a/test/unit/pixi/display/DisplayObject.js b/test/unit/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..40c6fbc
--- /dev/null
+++ b/test/unit/pixi/display/DisplayObject.js
@@ -0,0 +1,21 @@
+describe('pixi/display/DisplayObject', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var DisplayObject = PIXI.DisplayObject;
+
+ it('Module exists', function () {
+ expect(DisplayObject).to.be.a('function');
+ expect(PIXI).to.have.property('visibleCount', 0);
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new DisplayObject();
+
+ pixi_display_DisplayObject_confirmNew(obj);
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', false);
+ expect(obj).to.have.property('stage', null);
+ });
+});
diff --git a/test/unit/pixi/display/DisplayObjectContainer.js b/test/unit/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..ce7f02f
--- /dev/null
+++ b/test/unit/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,20 @@
+describe('pixi/display/DisplayObjectContainer', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var DisplayObjectContainer = PIXI.DisplayObjectContainer;
+
+ it('Module exists', function () {
+ expect(DisplayObjectContainer).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new DisplayObjectContainer();
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', false);
+ expect(obj).to.have.property('stage', null);
+ });
+});
diff --git a/test/unit/pixi/display/MovieClip.js b/test/unit/pixi/display/MovieClip.js
new file mode 100644
index 0000000..f3c6c6a
--- /dev/null
+++ b/test/unit/pixi/display/MovieClip.js
@@ -0,0 +1,33 @@
+describe('pixi/display/MovieClip', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var MovieClip = PIXI.MovieClip;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(MovieClip).to.be.a('function');
+ });
+
+ it('Confirm new instance', function (done) {
+ var texture = Texture.fromImage('/base/test/textures/SpriteSheet-Explosion.png');
+ var obj = new MovieClip([texture]);
+
+ pixi_display_Sprite_confirmNew(obj, done);
+
+ expect(obj).to.be.an.instanceof(MovieClip);
+ expect(obj).to.respondTo('stop');
+ expect(obj).to.respondTo('play');
+ expect(obj).to.respondTo('gotoAndStop');
+ expect(obj).to.respondTo('gotoAndPlay');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('textures.length', 1);
+ expect(obj).to.have.deep.property('textures[0]', texture);
+ expect(obj).to.have.property('animationSpeed', 1);
+ expect(obj).to.have.property('loop', true);
+ expect(obj).to.have.property('onComplete', null);
+ expect(obj).to.have.property('currentFrame', 0);
+ expect(obj).to.have.property('playing', false);
+ });
+});
diff --git a/test/unit/pixi/display/Sprite.js b/test/unit/pixi/display/Sprite.js
new file mode 100644
index 0000000..54e914f
--- /dev/null
+++ b/test/unit/pixi/display/Sprite.js
@@ -0,0 +1,25 @@
+describe('pixi/display/Sprite', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Sprite = PIXI.Sprite;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(Sprite).to.be.a('function');
+ expect(PIXI).to.have.deep.property('blendModes.NORMAL', 0);
+ expect(PIXI).to.have.deep.property('blendModes.SCREEN', 1);
+ });
+
+ it('Members exist', function () {
+ expect(Sprite).itself.to.respondTo('fromImage');
+ expect(Sprite).itself.to.respondTo('fromFrame');
+ });
+
+ it('Confirm new instance', function (done) {
+ var texture = Texture.fromImage('/base/test/textures/SpriteSheet-Aliens.png');
+ var obj = new Sprite(texture);
+
+ pixi_display_Sprite_confirmNew(obj, done);
+ });
+});
diff --git a/test/unit/pixi/display/Stage.js b/test/unit/pixi/display/Stage.js
new file mode 100644
index 0000000..3cc2a4d
--- /dev/null
+++ b/test/unit/pixi/display/Stage.js
@@ -0,0 +1,49 @@
+describe('pixi/display/Stage', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Stage = PIXI.Stage;
+ var InteractionManager = PIXI.InteractionManager;
+ var Rectangle = PIXI.Rectangle;
+
+ it('Module exists', function () {
+ expect(Stage).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Stage(null, true);
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(Stage);
+ expect(obj).to.respondTo('updateTransform');
+ expect(obj).to.respondTo('setBackgroundColor');
+ expect(obj).to.respondTo('getMousePosition');
+
+ // FIXME: duplicate member in DisplayObject
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ // FIXME: convert arg to bool in constructor
+ expect(obj).to.have.property('interactive', true);
+
+ expect(obj).to.have.property('interactionManager')
+ .and.to.be.an.instanceof(InteractionManager)
+ .and.to.have.property('stage', obj);
+
+ expect(obj).to.have.property('dirty', true);
+
+ expect(obj).to.have.property('stage', obj);
+
+ expect(obj).to.have.property('hitArea')
+ .and.to.be.an.instanceof(Rectangle);
+ pixi_core_Rectangle_confirm(obj.hitArea, 0, 0, 100000, 100000);
+
+ expect(obj).to.have.property('backgroundColor', 0x000000);
+ expect(obj).to.have.deep.property('backgroundColorSplit.length', 3);
+ expect(obj).to.have.deep.property('backgroundColorSplit[0]', 0);
+ expect(obj).to.have.deep.property('backgroundColorSplit[1]', 0);
+ expect(obj).to.have.deep.property('backgroundColorSplit[2]', 0);
+ expect(obj).to.have.property('backgroundColorString', '#000000');
+
+ expect(obj).to.have.property('worldVisible', true);
+ });
+});
diff --git a/test/unit/pixi/extras/CustomRenderable.js b/test/unit/pixi/extras/CustomRenderable.js
new file mode 100644
index 0000000..8d83cf0
--- /dev/null
+++ b/test/unit/pixi/extras/CustomRenderable.js
@@ -0,0 +1,21 @@
+describe('pixi/extras/CustomRenderable', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var CustomRenderable = PIXI.CustomRenderable;
+
+ it('Module exists', function () {
+ expect(CustomRenderable).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new CustomRenderable();
+
+ pixi_display_DisplayObject_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(CustomRenderable);
+ expect(obj).to.respondTo('renderCanvas');
+ expect(obj).to.respondTo('initWebGL');
+ expect(obj).to.respondTo('renderWebGL');
+ });
+});
diff --git a/test/unit/pixi/extras/Rope.js b/test/unit/pixi/extras/Rope.js
new file mode 100644
index 0000000..6ddaf83
--- /dev/null
+++ b/test/unit/pixi/extras/Rope.js
@@ -0,0 +1,26 @@
+describe('pixi/extras/Rope', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Rope = PIXI.Rope;
+ var Texture = PIXI.Texture;
+ var Point = PIXI.Point;
+
+ it('Module exists', function () {
+ expect(Rope).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var texture = Texture.fromImage('/base/test/textures/bunny.png');
+ var obj = new Rope(texture, [new Point(), new Point(5, 10), new Point(10, 20)]);
+
+ pixi_extras_Strip_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(Rope);
+ expect(obj).to.respondTo('refresh');
+ expect(obj).to.respondTo('updateTransform');
+ expect(obj).to.respondTo('setTexture');
+
+ // TODO: Test properties
+ });
+});
diff --git a/test/unit/pixi/extras/Spine.js b/test/unit/pixi/extras/Spine.js
new file mode 100644
index 0000000..0708bc0
--- /dev/null
+++ b/test/unit/pixi/extras/Spine.js
@@ -0,0 +1,10 @@
+describe('pixi/extras/Spine', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Spine = PIXI.Spine;
+
+ it('Module exists', function () {
+ expect(Spine).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/extras/Strip.js b/test/unit/pixi/extras/Strip.js
new file mode 100644
index 0000000..8e564e1
--- /dev/null
+++ b/test/unit/pixi/extras/Strip.js
@@ -0,0 +1,18 @@
+describe('pixi/extras/Strip', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Strip = PIXI.Strip;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(Strip).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var texture = Texture.fromImage('/base/test/textures/bunny.png');
+ var obj = new Strip(texture, 20, 10000);
+
+ pixi_extras_Strip_confirmNew(obj);
+ });
+});
diff --git a/test/unit/pixi/extras/TilingSprite.js b/test/unit/pixi/extras/TilingSprite.js
new file mode 100644
index 0000000..56aea14
--- /dev/null
+++ b/test/unit/pixi/extras/TilingSprite.js
@@ -0,0 +1,24 @@
+describe('pixi/extras/TilingSprite', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var TilingSprite = PIXI.TilingSprite;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(TilingSprite).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var texture = Texture.fromImage('/base/test/textures/bunny.png');
+ var obj = new TilingSprite(texture, 6000, 12000);
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(TilingSprite);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ // TODO: Test properties
+ });
+});
diff --git a/test/unit/pixi/filters/FilterBlock.js b/test/unit/pixi/filters/FilterBlock.js
new file mode 100644
index 0000000..870cec0
--- /dev/null
+++ b/test/unit/pixi/filters/FilterBlock.js
@@ -0,0 +1,10 @@
+describe('pixi/filters/FilterBlock', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var FilterBlock = PIXI.FilterBlock;
+
+ it('Module exists', function () {
+ expect(FilterBlock).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/filters/MaskFilter.js b/test/unit/pixi/filters/MaskFilter.js
new file mode 100644
index 0000000..32d6a45
--- /dev/null
+++ b/test/unit/pixi/filters/MaskFilter.js
@@ -0,0 +1,10 @@
+describe('pixi/filters/MaskFilter', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ // var MaskFilter = PIXI.MaskFilter;
+
+ // it('Module exists', function () {
+ // expect(MaskFilter).to.be.a('function');
+ // });
+});
diff --git a/test/unit/pixi/loaders/AssetLoader.js b/test/unit/pixi/loaders/AssetLoader.js
new file mode 100644
index 0000000..a0aa0b5
--- /dev/null
+++ b/test/unit/pixi/loaders/AssetLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/AssetLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var AssetLoader = PIXI.AssetLoader;
+
+ it('Module exists', function () {
+ expect(AssetLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/BitmapFontLoader.js b/test/unit/pixi/loaders/BitmapFontLoader.js
new file mode 100644
index 0000000..6253c42
--- /dev/null
+++ b/test/unit/pixi/loaders/BitmapFontLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/BitmapFontLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var BitmapFontLoader = PIXI.BitmapFontLoader;
+
+ it('Module exists', function () {
+ expect(PIXI.BitmapFontLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/ImageLoader.js b/test/unit/pixi/loaders/ImageLoader.js
new file mode 100644
index 0000000..8b1f556
--- /dev/null
+++ b/test/unit/pixi/loaders/ImageLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/ImageLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var ImageLoader = PIXI.ImageLoader;
+
+ it('Module exists', function () {
+ expect(ImageLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/JsonLoader.js b/test/unit/pixi/loaders/JsonLoader.js
new file mode 100644
index 0000000..c577e83
--- /dev/null
+++ b/test/unit/pixi/loaders/JsonLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/JsonLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var JsonLoader = PIXI.JsonLoader;
+
+ it('Module exists', function () {
+ expect(JsonLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/SpineLoader.js b/test/unit/pixi/loaders/SpineLoader.js
new file mode 100644
index 0000000..fdcc0b8
--- /dev/null
+++ b/test/unit/pixi/loaders/SpineLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/SpineLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var SpineLoader = PIXI.SpineLoader;
+
+ it('Module exists', function () {
+ expect(SpineLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/SpriteSheetLoader.js b/test/unit/pixi/loaders/SpriteSheetLoader.js
new file mode 100644
index 0000000..57beb27
--- /dev/null
+++ b/test/unit/pixi/loaders/SpriteSheetLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/SpriteSheetLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var SpriteSheetLoader = PIXI.SpriteSheetLoader;
+
+ it('Module exists', function () {
+ expect(SpriteSheetLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/primitives/Graphics.js b/test/unit/pixi/primitives/Graphics.js
new file mode 100644
index 0000000..b8b3e5c
--- /dev/null
+++ b/test/unit/pixi/primitives/Graphics.js
@@ -0,0 +1,40 @@
+describe('pixi/primitives/Graphics', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Graphics = PIXI.Graphics;
+
+ it('Module exists', function () {
+ expect(Graphics).to.be.a('function');
+
+ expect(Graphics).itself.to.have.property('POLY', 0);
+ expect(Graphics).itself.to.have.property('RECT', 1);
+ expect(Graphics).itself.to.have.property('CIRC', 2);
+ expect(Graphics).itself.to.have.property('ELIP', 3);
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Graphics();
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(Graphics);
+ expect(obj).to.respondTo('lineStyle');
+ expect(obj).to.respondTo('lineStyle');
+ expect(obj).to.respondTo('moveTo');
+ expect(obj).to.respondTo('lineTo');
+ expect(obj).to.respondTo('beginFill');
+ expect(obj).to.respondTo('endFill');
+ expect(obj).to.respondTo('drawRect');
+ expect(obj).to.respondTo('drawCircle');
+ expect(obj).to.respondTo('drawElipse');
+ expect(obj).to.respondTo('clear');
+
+ expect(obj).to.have.property('renderable', true);
+ expect(obj).to.have.property('fillAlpha', 1);
+ expect(obj).to.have.property('lineWidth', 0);
+ expect(obj).to.have.property('lineColor', 'black');
+ expect(obj).to.have.deep.property('graphicsData.length', 0);
+ expect(obj).to.have.deep.property('currentPath.points.length', 0);
+ });
+});
diff --git a/test/unit/pixi/renderers/canvas/CanvasGraphics.js b/test/unit/pixi/renderers/canvas/CanvasGraphics.js
new file mode 100644
index 0000000..8f44472
--- /dev/null
+++ b/test/unit/pixi/renderers/canvas/CanvasGraphics.js
@@ -0,0 +1,15 @@
+describe('renders/canvas/CanvasGraphics', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var CanvasGraphics = PIXI.CanvasGraphics;
+
+ it('Module exists', function () {
+ expect(CanvasGraphics).to.be.a('function');
+ });
+
+ it('Members exist', function () {
+ expect(CanvasGraphics).itself.to.respondTo('renderGraphics');
+ expect(CanvasGraphics).itself.to.respondTo('renderGraphicsMask');
+ });
+});
diff --git a/test/unit/pixi/renderers/canvas/CanvasRenderer.js b/test/unit/pixi/renderers/canvas/CanvasRenderer.js
new file mode 100644
index 0000000..df3a12f
--- /dev/null
+++ b/test/unit/pixi/renderers/canvas/CanvasRenderer.js
@@ -0,0 +1,10 @@
+describe('renderers/canvas/CanvasRenderer', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var CanvasRenderer = PIXI.CanvasRenderer;
+
+ it('Module exists', function () {
+ expect(CanvasRenderer).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/renderers/webgl/WebGLBatch.js b/test/unit/pixi/renderers/webgl/WebGLBatch.js
new file mode 100644
index 0000000..75efd56
--- /dev/null
+++ b/test/unit/pixi/renderers/webgl/WebGLBatch.js
@@ -0,0 +1,10 @@
+describe('renderers/webgl/WebGLBatch', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var WebGLBatch = PIXI.WebGLBatch;
+
+ it('Module exists', function () {
+ expect(WebGLBatch).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/renderers/webgl/WebGLGraphics.js b/test/unit/pixi/renderers/webgl/WebGLGraphics.js
new file mode 100644
index 0000000..41bf941
--- /dev/null
+++ b/test/unit/pixi/renderers/webgl/WebGLGraphics.js
@@ -0,0 +1,19 @@
+describe('renderers/wegbl/WebGLGraphics', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var WebGLGraphics = PIXI.WebGLGraphics;
+
+ it('Module exists', function () {
+ expect(WebGLGraphics).to.be.a('function');
+ });
+
+ it('Members exist', function () {
+ expect(WebGLGraphics).itself.to.respondTo('renderGraphics');
+ expect(WebGLGraphics).itself.to.respondTo('updateGraphics');
+ expect(WebGLGraphics).itself.to.respondTo('buildRectangle');
+ expect(WebGLGraphics).itself.to.respondTo('buildCircle');
+ expect(WebGLGraphics).itself.to.respondTo('buildLine');
+ expect(WebGLGraphics).itself.to.respondTo('buildPoly');
+ });
+});
diff --git a/test/unit/pixi/renderers/webgl/WebGLRenderGroup.js b/test/unit/pixi/renderers/webgl/WebGLRenderGroup.js
new file mode 100644
index 0000000..f4ee366
--- /dev/null
+++ b/test/unit/pixi/renderers/webgl/WebGLRenderGroup.js
@@ -0,0 +1,10 @@
+describe('renderers/webgl/WebGLRenderGroup', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var WebGLRenderGroup = PIXI.WebGLRenderGroup;
+
+ it('Module exists', function () {
+ expect(WebGLRenderGroup).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/renderers/webgl/WebGLRenderer.js b/test/unit/pixi/renderers/webgl/WebGLRenderer.js
new file mode 100644
index 0000000..86533eb
--- /dev/null
+++ b/test/unit/pixi/renderers/webgl/WebGLRenderer.js
@@ -0,0 +1,10 @@
+describe('renderers/webgl/WebGLRenderer', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var WebGLRenderer = PIXI.WebGLRenderer;
+
+ it('Module exists', function () {
+ expect(WebGLRenderer).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/renderers/webgl/WebGLShaders.js b/test/unit/pixi/renderers/webgl/WebGLShaders.js
new file mode 100644
index 0000000..2872de8
--- /dev/null
+++ b/test/unit/pixi/renderers/webgl/WebGLShaders.js
@@ -0,0 +1,13 @@
+describe('renderers/webgl/WebGLShaders', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+
+ it('Module members exist', function () {
+ expect(PIXI).to.respondTo('initPrimitiveShader');
+ expect(PIXI).to.respondTo('initDefaultShader');
+ expect(PIXI).to.respondTo('initDefaultStripShader');
+ expect(PIXI).to.respondTo('activateDefaultShader');
+ expect(PIXI).to.respondTo('activatePrimitiveShader');
+ });
+});
diff --git a/test/unit/pixi/text/BitmapText.js b/test/unit/pixi/text/BitmapText.js
new file mode 100644
index 0000000..9388e3d
--- /dev/null
+++ b/test/unit/pixi/text/BitmapText.js
@@ -0,0 +1,10 @@
+describe('pixi/text/BitmapText', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var BitmapText = PIXI.BitmapText;
+
+ it('Module exists', function () {
+ expect(BitmapText).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/text/Text.js b/test/unit/pixi/text/Text.js
new file mode 100644
index 0000000..9bc9ac5
--- /dev/null
+++ b/test/unit/pixi/text/Text.js
@@ -0,0 +1,10 @@
+describe('pixi/text/Text', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Text = PIXI.Text;
+
+ it('Module exists', function () {
+ expect(Text).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/textures/BaseTexture.js b/test/unit/pixi/textures/BaseTexture.js
new file mode 100644
index 0000000..e34b64c
--- /dev/null
+++ b/test/unit/pixi/textures/BaseTexture.js
@@ -0,0 +1,13 @@
+describe('pixi/textures/BaseTexture', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var BaseTexture = PIXI.BaseTexture;
+
+ it('Module exists', function () {
+ expect(BaseTexture).to.be.a('function');
+ expect(PIXI).to.have.property('BaseTextureCache').and.to.be.an('object');
+ expect(PIXI).to.have.deep.property('texturesToUpdate.length');
+ expect(PIXI).to.have.deep.property('texturesToDestroy.length', 0);
+ });
+});
diff --git a/.gitignore b/.gitignore
index 12e1b62..0b88317 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
node_modules
.DS_Store
-.project
\ No newline at end of file
+.project
+*.log
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..63e4d7c
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,8 @@
+language: node_js
+node_js:
+ - 0.10
+
+before_script:
+ - npm install -g grunt-cli
+ - export DISPLAY=:99.0
+ - sh -e /etc/init.d/xvfb start
diff --git a/Gruntfile.js b/Gruntfile.js
index b083b49..103938c 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -1,10 +1,12 @@
+'use strict';
+
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-connect');
- grunt.loadNpmTasks('grunt-contrib-qunit');
grunt.loadNpmTasks('grunt-contrib-yuidoc');
+ grunt.loadTasks('tasks');
var root = 'src/pixi/',
debug = 'bin/pixi.dev.js',
@@ -79,7 +81,7 @@
},
files: {
srcBlob: '<%= dirs.src %>/**/*.js',
- testBlob: '<%= dirs.test %>/unit/**/*.js',
+ testBlob: '<%= dirs.test %>/{functional,lib/pixi,unit}/**/*.js',
build: '<%= dirs.build %>/pixi.dev.js',
buildMin: '<%= dirs.build %>/pixi.js'
},
@@ -94,7 +96,12 @@
},
jshint: {
beforeconcat: srcFiles,
- test: ['<%= files.testBlob %>'],
+ test: {
+ src: ['<%= files.testBlob %>'],
+ options: {
+ expr: true
+ }
+ },
options: {
asi: true,
smarttabs: true
@@ -128,12 +135,6 @@
]
},
connect: {
- qunit: {
- options: {
- port: grunt.option('port-test') || 9002,
- base: './'
- }
- },
test: {
options: {
port: grunt.option('port-test') || 9002,
@@ -142,13 +143,6 @@
}
}
},
- qunit: {
- all: {
- options: {
- urls: ['http://localhost:' + (grunt.option('port-test') || 9002) + '/test/index.html']
- }
- }
- },
yuidoc: {
compile: {
name: '<%= pkg.name %>',
@@ -161,6 +155,13 @@
outdir: '<%= dirs.docs %>'
}
}
+ },
+ karma: {
+ unit: {
+ configFile: 'test/karma.conf.js',
+ // browsers: ['Chrome'],
+ singleRun: true
+ }
}
});
@@ -182,9 +183,10 @@
}
)
- grunt.registerTask('default', ['concat', 'uglify', 'distribute']);
grunt.registerTask('build', ['concat', 'uglify', 'distribute']);
- grunt.registerTask('test', ['build', 'connect:qunit', 'qunit']);
+ grunt.registerTask('test', ['concat', 'jshint:test', 'karma']);
grunt.registerTask('docs', ['yuidoc']);
-
-}
\ No newline at end of file
+ grunt.registerTask('default', ['test', 'uglify', 'distribute']);
+ // Travis CI task.
+ grunt.registerTask('travis', ['test']);
+}
diff --git a/README.md b/README.md
index c62ef86..690cfe4 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,8 @@

+[](http://travis-ci.org/drkibitz/pixi.js)
+
#### JavaScript 2D Renderer ####
The aim of this project is to provide a fast lightweight 2D library that works
diff --git a/package.json b/package.json
index b373240..1246a68 100644
--- a/package.json
+++ b/package.json
@@ -18,14 +18,21 @@
"main": "bin/pixi.js",
+ "scripts": {
+ "test": "grunt travis --verbose"
+ },
+
"dependencies": {},
"devDependencies": {
"grunt": "~0.4.x",
- "grunt-contrib-jshint": "0.3.x",
+ "grunt-contrib-jshint": "0.6.x",
"grunt-contrib-uglify": "0.2.x",
- "grunt-contrib-connect": "0.2.x",
- "grunt-contrib-qunit": "0.2.x",
+ "grunt-contrib-connect": "0.3.x",
"grunt-contrib-yuidoc": "0.4.x",
- "grunt-contrib-concat": "0.1.x"
+ "grunt-contrib-concat": "0.3.x",
+ "chai": "~1.7.0",
+ "karma": "0.11.0",
+ "karma-firefox-launcher": "0.1.0",
+ "karma-mocha": "0.1.0"
}
}
diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js
index a7c520e..ee82bbd 100644
--- a/src/pixi/InteractionManager.js
+++ b/src/pixi/InteractionManager.js
@@ -62,7 +62,6 @@
this.onTouchEnd = this.onTouchEnd.bind(this);
this.onTouchMove = this.onTouchMove.bind(this);
-
this.last = 0;
}
diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js
index 1a95d20..eef1059 100644
--- a/src/pixi/core/Ellipse.js
+++ b/src/pixi/core/Ellipse.js
@@ -78,7 +78,7 @@
return (normx + normy < 0.25);
}
-PIXI.Ellipse.getBounds = function()
+PIXI.Ellipse.prototype.getBounds = function()
{
return new PIXI.Rectangle(this.x, this.y, this.width, this.height);
}
diff --git a/tasks/karma.js b/tasks/karma.js
new file mode 100644
index 0000000..c340485
--- /dev/null
+++ b/tasks/karma.js
@@ -0,0 +1,27 @@
+'use strict';
+
+var path = require('path');
+var server = require('karma').server;
+
+module.exports = function (grunt) {
+ grunt.registerMultiTask('karma', 'run karma.', function() {
+ var done = this.async();
+ var options = this.options({
+ background: false
+ });
+ var data = this.data;
+
+ //merge options onto data, with data taking precedence
+ data = grunt.util._.merge(options, data);
+ data.configFile = path.resolve(data.configFile);
+ if (data.configFile) {
+ data.configFile = grunt.template.process(data.configFile);
+ }
+
+ server.start(
+ data,
+ function(code) {
+ done(!code);
+ });
+ });
+};
diff --git a/test/functional/example-1-basics/bunny.png b/test/functional/example-1-basics/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/functional/example-1-basics/bunny.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-30.png b/test/functional/example-1-basics/frame-30.png
new file mode 100644
index 0000000..96e3409
--- /dev/null
+++ b/test/functional/example-1-basics/frame-30.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-60.png b/test/functional/example-1-basics/frame-60.png
new file mode 100644
index 0000000..af3f4ce
--- /dev/null
+++ b/test/functional/example-1-basics/frame-60.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-90.png b/test/functional/example-1-basics/frame-90.png
new file mode 100644
index 0000000..099b823
--- /dev/null
+++ b/test/functional/example-1-basics/frame-90.png
Binary files differ
diff --git a/test/functional/example-1-basics/index.js b/test/functional/example-1-basics/index.js
new file mode 100644
index 0000000..7ae7a98
--- /dev/null
+++ b/test/functional/example-1-basics/index.js
@@ -0,0 +1,133 @@
+describe('Example 1 - Basics', function () {
+ 'use strict';
+
+ var baseUri = '/base/test/functional/example-1-basics';
+ var expect = chai.expect;
+ var currentFrame = 0;
+ var frameEvents = {};
+ var stage;
+ var renderer;
+ var bunny;
+
+ function onFrame(frame, callback) {
+ frameEvents[frame] = callback;
+ }
+
+ function animate() {
+ currentFrame += 1;
+
+ requestAnimFrame( animate );
+
+ // just for fun, lets rotate mr rabbit a little
+ bunny.rotation += 0.1;
+
+ // render the stage
+ renderer.render(stage);
+
+ if (frameEvents[currentFrame])
+ frameEvents[currentFrame](currentFrame);
+ }
+
+ function initScene() {
+ // create an new instance of a pixi stage
+ stage = new PIXI.Stage(0x66FF99);
+
+ // create a renderer instance
+ renderer = PIXI.autoDetectRenderer(400, 300);
+ console.log('Is PIXI.WebGLRenderer: ' + (renderer instanceof PIXI.WebGLRenderer));
+
+ // add the renderer view element to the DOM
+ document.body.appendChild(renderer.view);
+
+ requestAnimFrame( animate );
+
+ // create a texture from an image path
+ var texture = PIXI.Texture.fromImage(baseUri + "/bunny.png");
+ // create a new Sprite using the texture
+ bunny = new PIXI.Sprite(texture);
+
+ // center the sprites anchor point
+ bunny.anchor.x = 0.5;
+ bunny.anchor.y = 0.5;
+
+ // move the sprite t the center of the screen
+ bunny.position.x = 200;
+ bunny.position.y = 150;
+
+ stage.addChild(bunny);
+ }
+
+ it('assets loaded', function (done) {
+ var loader = new PIXI.AssetLoader([
+ baseUri + '/bunny.png',
+ baseUri + '/frame-30.png',
+ baseUri + '/frame-60.png',
+ baseUri + '/frame-90.png'
+ ]);
+ // loader.on('onProgress', function (event) {
+ // console.log(event.content);
+ // });
+ loader.on('onComplete', function (event) {
+ done();
+ initScene();
+ });
+ loader.load();
+ });
+
+ it('frame 30 should match', function (done) {
+ this.timeout(700);
+ onFrame(30, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-30.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 60 should match', function (done) {
+ this.timeout(1200);
+ onFrame(60, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-60.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 90 should match', function (done) {
+ this.timeout(1700);
+ onFrame(90, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-90.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ // it('capture something', function (done) {
+ // this.timeout(2000000);
+ // onFrame(30, function () {
+ // var img = new Image();
+ // img.src = renderer.view.toDataURL('image/png');
+ // document.body.appendChild(img);
+ // });
+ // });
+});
diff --git a/test/index.html b/test/index.html
deleted file mode 100644
index 9cbcac5..0000000
--- a/test/index.html
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
- Pixi.js Test Suite
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/test/karma.conf.js b/test/karma.conf.js
new file mode 100644
index 0000000..c66a696
--- /dev/null
+++ b/test/karma.conf.js
@@ -0,0 +1,82 @@
+module.exports = function(config) {
+ config.set({
+
+ // base path, that will be used to resolve files and exclude
+ basePath : '../',
+
+ frameworks : ['mocha'],
+
+ // list of files / patterns to load in the browser
+ files : [
+ 'node_modules/chai/chai.js',
+ 'bin/pixi.dev.js',
+ 'test/lib/**/*.js',
+ 'test/unit/**/*.js',
+ // 'test/functional/**/*.js',
+ {pattern: 'test/**/*.png', watched: false, included: false, served: true}
+ ],
+
+ // list of files to exclude
+ exclude : [],
+
+ // use dolts reporter, as travis terminal does not support escaping sequences
+ // possible values: 'dots', 'progress', 'junit', 'teamcity'
+ // CLI --reporters progress
+ reporters : ['progress'],
+
+ // web server port
+ // CLI --port 9876
+ port : 9876,
+
+ // cli runner port
+ // CLI --runner-port 9100
+ runnerPort : 9100,
+
+ // enable / disable colors in the output (reporters and logs)
+ // CLI --colors --no-colors
+ colors : true,
+
+ // level of logging
+ // possible values: karma.LOG_DISABLE || karma.LOG_ERROR || karma.LOG_WARN || karma.LOG_INFO || karma.LOG_DEBUG
+ // CLI --log-level debug
+ logLevel : config.LOG_DEBUG,
+
+ // enable / disable watching file and executing tests whenever any file changes
+ // CLI --auto-watch --no-auto-watch
+ autoWatch : false,
+
+ // Start these browsers, currently available:
+ // - Chrome
+ // - ChromeCanary
+ // - Firefox
+ // - Opera
+ // - Safari (only Mac)
+ // - PhantomJS
+ // - IE (only Windows)
+ // CLI --browsers Chrome,Firefox,Safari
+ browsers : ['Firefox'],
+
+ // If browser does not capture in given timeout [ms], kill it
+ // CLI --capture-timeout 5000
+ captureTimeout : 5000,
+
+ // Auto run tests on start (when browsers are captured) and exit
+ // CLI --single-run --no-single-run
+ singleRun : true,
+
+ // report which specs are slower than 500ms
+ // CLI --report-slower-than 500
+ reportSlowerThan : 1000,
+
+ preprocessors : {
+ // '**/client/js/*.js': 'coverage'
+ },
+
+ plugins : [
+ 'karma-mocha',
+ // 'karma-chrome-launcher',
+ 'karma-firefox-launcher',
+ // 'karma-phantomjs-launcher'
+ ]
+ });
+};
diff --git a/test/lib/pixi/core/Matrix.js b/test/lib/pixi/core/Matrix.js
new file mode 100644
index 0000000..d26386b
--- /dev/null
+++ b/test/lib/pixi/core/Matrix.js
@@ -0,0 +1,40 @@
+
+function pixi_core_Matrix_confirmNewMat3(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(1);
+ expect(matrix[5]).to.equal(0);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(1);
+}
+
+function pixi_core_Matrix_confirmNewMat4(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[0]).to.equal(1);
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(0);
+ expect(matrix[5]).to.equal(1);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(0);
+ expect(matrix[9]).to.equal(0);
+ expect(matrix[10]).to.equal(1);
+ expect(matrix[11]).to.equal(0);
+ expect(matrix[12]).to.equal(0);
+ expect(matrix[13]).to.equal(0);
+ expect(matrix[14]).to.equal(0);
+ expect(matrix[15]).to.equal(1);
+}
diff --git a/test/lib/pixi/core/Point.js b/test/lib/pixi/core/Point.js
new file mode 100644
index 0000000..e5df07b
--- /dev/null
+++ b/test/lib/pixi/core/Point.js
@@ -0,0 +1,10 @@
+
+function pixi_core_Point_confirm(obj, x, y) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Point);
+ expect(obj).to.respondTo('clone');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+}
diff --git a/test/lib/pixi/core/Rectangle.js b/test/lib/pixi/core/Rectangle.js
new file mode 100644
index 0000000..23f0d12
--- /dev/null
+++ b/test/lib/pixi/core/Rectangle.js
@@ -0,0 +1,13 @@
+
+function pixi_core_Rectangle_confirm(obj, x, y, width, height) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Rectangle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+ expect(obj).to.have.property('width', width);
+ expect(obj).to.have.property('height', height);
+}
diff --git a/test/lib/pixi/display/DisplayObject.js b/test/lib/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..1388a7f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObject.js
@@ -0,0 +1,43 @@
+
+function pixi_display_DisplayObject_confirmNew(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObject);
+ expect(obj).to.respondTo('setInteractive');
+ expect(obj).to.respondTo('addFilter');
+ expect(obj).to.respondTo('removeFilter');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.property('last', obj);
+ expect(obj).to.have.property('first', obj);
+
+ expect(obj).to.contain.property('position');
+ pixi_core_Point_confirm(obj.position, 0, 0);
+ expect(obj).to.contain.property('scale');
+ pixi_core_Point_confirm(obj.scale, 1, 1);
+ expect(obj).to.contain.property('pivot');
+ pixi_core_Point_confirm(obj.pivot, 0, 0);
+
+ expect(obj).to.have.property('rotation', 0);
+ expect(obj).to.have.property('alpha', 1);
+ expect(obj).to.have.property('visible', true);
+ expect(obj).to.have.property('buttonMode', false);
+ expect(obj).to.have.property('parent', null);
+ expect(obj).to.have.property('worldAlpha', 1);
+
+ expect(obj).to.have.property('hitArea');
+ expect(obj).to.have.property('interactive'); // TODO: Have a better default value
+ expect('mask' in obj).to.be.true; // TODO: Have a better default value
+ expect(obj.mask).to.be.undefined;
+
+ expect(obj).to.have.property('renderable');
+ expect(obj).to.have.property('stage');
+
+ expect(obj).to.have.deep.property('worldTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ expect(obj).to.have.deep.property('localTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.localTransform);
+
+ expect(obj).to.have.deep.property('color.length', 0);
+ expect(obj).to.have.property('dynamic', true);
+}
diff --git a/test/lib/pixi/display/DisplayObjectContainer.js b/test/lib/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..085c59f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,16 @@
+
+function pixi_display_DisplayObjectContainer_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObject_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObjectContainer);
+ expect(obj).to.respondTo('addChild');
+ expect(obj).to.respondTo('addChildAt');
+ expect(obj).to.respondTo('swapChildren');
+ expect(obj).to.respondTo('getChildAt');
+ expect(obj).to.respondTo('removeChild');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('children.length', 0);
+}
diff --git a/test/lib/pixi/display/Sprite.js b/test/lib/pixi/display/Sprite.js
new file mode 100644
index 0000000..cc7a2d6
--- /dev/null
+++ b/test/lib/pixi/display/Sprite.js
@@ -0,0 +1,28 @@
+
+function pixi_display_Sprite_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Sprite);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', true);
+ expect(obj).to.have.property('stage', null);
+
+ expect(obj).to.have.property('anchor');
+ pixi_core_Point_confirm(obj.anchor, 0, 0);
+
+ expect(obj).to.have.property('blendMode', PIXI.blendModes.NORMAL);
+ expect(obj).to.have.property('width', 1); // TODO: is 1 expected
+ expect(obj).to.have.property('height', 1); // TODO: is 1 expected
+
+ // FIXME: Just make this a boolean that is always there
+ expect(!!obj.updateFrame).to.equal(obj.texture.baseTexture.hasLoaded);
+
+ expect(obj).to.have.property('texture');
+ pixi_textures_Texture_confirmNew(obj.texture, done);
+}
diff --git a/test/lib/pixi/extras/Strip.js b/test/lib/pixi/extras/Strip.js
new file mode 100644
index 0000000..8927a8a
--- /dev/null
+++ b/test/lib/pixi/extras/Strip.js
@@ -0,0 +1,12 @@
+
+function pixi_extras_Strip_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Strip);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ // TODO: Test properties
+}
diff --git a/test/lib/pixi/textures/Texture.js b/test/lib/pixi/textures/Texture.js
new file mode 100644
index 0000000..d5867b6
--- /dev/null
+++ b/test/lib/pixi/textures/Texture.js
@@ -0,0 +1,31 @@
+
+function pixi_textures_Texture_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ function confirmFrameDone() {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, obj.baseTexture.width, obj.baseTexture.height);
+
+ expect(obj).to.have.property('width', obj.baseTexture.width);
+ expect(obj).to.have.property('height', obj.baseTexture.height);
+ done();
+ }
+
+ expect(obj).to.be.an.instanceof(PIXI.Texture);
+ pixi_utils_EventTarget_like(obj);
+
+ expect(obj).to.have.property('baseTexture')
+ .and.to.be.an.instanceof(PIXI.BaseTexture);
+
+ expect(obj).to.have.property('scope', obj);
+
+ expect(obj).to.have.property('trim');
+ pixi_core_Point_confirm(obj.trim, 0, 0);
+
+ expect(obj).to.have.property('frame');
+ if (obj.baseTexture.hasLoaded) {
+ confirmFrameDone();
+ } else {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, 1, 1);
+ obj.addEventListener('update', confirmFrameDone);
+ }
+}
diff --git a/test/lib/pixi/utils/EventTarget.js b/test/lib/pixi/utils/EventTarget.js
new file mode 100644
index 0000000..7b1dcfa
--- /dev/null
+++ b/test/lib/pixi/utils/EventTarget.js
@@ -0,0 +1,8 @@
+
+function pixi_utils_EventTarget_like(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.respondTo('addEventListener');
+ expect(obj).to.respondTo('dispatchEvent');
+ expect(obj).to.respondTo('removeEventListener');
+}
diff --git a/test/lib/qunit-1.11.0.css b/test/lib/qunit-1.11.0.css
deleted file mode 100644
index d7fc0c8..0000000
--- a/test/lib/qunit-1.11.0.css
+++ /dev/null
@@ -1,244 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-/** Font Family and Sizes */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
- font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
-}
-
-#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
-#qunit-tests { font-size: smaller; }
-
-
-/** Resets */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter {
- margin: 0;
- padding: 0;
-}
-
-
-/** Header */
-
-#qunit-header {
- padding: 0.5em 0 0.5em 1em;
-
- color: #8699a4;
- background-color: #0d3349;
-
- font-size: 1.5em;
- line-height: 1em;
- font-weight: normal;
-
- border-radius: 5px 5px 0 0;
- -moz-border-radius: 5px 5px 0 0;
- -webkit-border-top-right-radius: 5px;
- -webkit-border-top-left-radius: 5px;
-}
-
-#qunit-header a {
- text-decoration: none;
- color: #c2ccd1;
-}
-
-#qunit-header a:hover,
-#qunit-header a:focus {
- color: #fff;
-}
-
-#qunit-testrunner-toolbar label {
- display: inline-block;
- padding: 0 .5em 0 .1em;
-}
-
-#qunit-banner {
- height: 5px;
-}
-
-#qunit-testrunner-toolbar {
- padding: 0.5em 0 0.5em 2em;
- color: #5E740B;
- background-color: #eee;
- overflow: hidden;
-}
-
-#qunit-userAgent {
- padding: 0.5em 0 0.5em 2.5em;
- background-color: #2b81af;
- color: #fff;
- text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
-}
-
-#qunit-modulefilter-container {
- float: right;
-}
-
-/** Tests: Pass/Fail */
-
-#qunit-tests {
- list-style-position: inside;
-}
-
-#qunit-tests li {
- padding: 0.4em 0.5em 0.4em 2.5em;
- border-bottom: 1px solid #fff;
- list-style-position: inside;
-}
-
-#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running {
- display: none;
-}
-
-#qunit-tests li strong {
- cursor: pointer;
-}
-
-#qunit-tests li a {
- padding: 0.5em;
- color: #c2ccd1;
- text-decoration: none;
-}
-#qunit-tests li a:hover,
-#qunit-tests li a:focus {
- color: #000;
-}
-
-#qunit-tests li .runtime {
- float: right;
- font-size: smaller;
-}
-
-.qunit-assert-list {
- margin-top: 0.5em;
- padding: 0.5em;
-
- background-color: #fff;
-
- border-radius: 5px;
- -moz-border-radius: 5px;
- -webkit-border-radius: 5px;
-}
-
-.qunit-collapsed {
- display: none;
-}
-
-#qunit-tests table {
- border-collapse: collapse;
- margin-top: .2em;
-}
-
-#qunit-tests th {
- text-align: right;
- vertical-align: top;
- padding: 0 .5em 0 0;
-}
-
-#qunit-tests td {
- vertical-align: top;
-}
-
-#qunit-tests pre {
- margin: 0;
- white-space: pre-wrap;
- word-wrap: break-word;
-}
-
-#qunit-tests del {
- background-color: #e0f2be;
- color: #374e0c;
- text-decoration: none;
-}
-
-#qunit-tests ins {
- background-color: #ffcaca;
- color: #500;
- text-decoration: none;
-}
-
-/*** Test Counts */
-
-#qunit-tests b.counts { color: black; }
-#qunit-tests b.passed { color: #5E740B; }
-#qunit-tests b.failed { color: #710909; }
-
-#qunit-tests li li {
- padding: 5px;
- background-color: #fff;
- border-bottom: none;
- list-style-position: inside;
-}
-
-/*** Passing Styles */
-
-#qunit-tests li li.pass {
- color: #3c510c;
- background-color: #fff;
- border-left: 10px solid #C6E746;
-}
-
-#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
-#qunit-tests .pass .test-name { color: #366097; }
-
-#qunit-tests .pass .test-actual,
-#qunit-tests .pass .test-expected { color: #999999; }
-
-#qunit-banner.qunit-pass { background-color: #C6E746; }
-
-/*** Failing Styles */
-
-#qunit-tests li li.fail {
- color: #710909;
- background-color: #fff;
- border-left: 10px solid #EE5757;
- white-space: pre;
-}
-
-#qunit-tests > li:last-child {
- border-radius: 0 0 5px 5px;
- -moz-border-radius: 0 0 5px 5px;
- -webkit-border-bottom-right-radius: 5px;
- -webkit-border-bottom-left-radius: 5px;
-}
-
-#qunit-tests .fail { color: #000000; background-color: #EE5757; }
-#qunit-tests .fail .test-name,
-#qunit-tests .fail .module-name { color: #000000; }
-
-#qunit-tests .fail .test-actual { color: #EE5757; }
-#qunit-tests .fail .test-expected { color: green; }
-
-#qunit-banner.qunit-fail { background-color: #EE5757; }
-
-
-/** Result */
-
-#qunit-testresult {
- padding: 0.5em 0.5em 0.5em 2.5em;
-
- color: #2b81af;
- background-color: #D2E0E6;
-
- border-bottom: 1px solid white;
-}
-#qunit-testresult .module-name {
- font-weight: bold;
-}
-
-/** Fixture */
-
-#qunit-fixture {
- position: absolute;
- top: -10000px;
- left: -10000px;
- width: 1000px;
- height: 1000px;
-}
diff --git a/test/lib/qunit-1.11.0.js b/test/lib/qunit-1.11.0.js
deleted file mode 100644
index 302545f..0000000
--- a/test/lib/qunit-1.11.0.js
+++ /dev/null
@@ -1,2152 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-(function( window ) {
-
-var QUnit,
- assert,
- config,
- onErrorFnPrev,
- testId = 0,
- fileName = (sourceFromStacktrace( 0 ) || "" ).replace(/(:\d+)+\)?/, "").replace(/.+\//, ""),
- toString = Object.prototype.toString,
- hasOwn = Object.prototype.hasOwnProperty,
- // Keep a local reference to Date (GH-283)
- Date = window.Date,
- defined = {
- setTimeout: typeof window.setTimeout !== "undefined",
- sessionStorage: (function() {
- var x = "qunit-test-string";
- try {
- sessionStorage.setItem( x, x );
- sessionStorage.removeItem( x );
- return true;
- } catch( e ) {
- return false;
- }
- }())
- },
- /**
- * Provides a normalized error string, correcting an issue
- * with IE 7 (and prior) where Error.prototype.toString is
- * not properly implemented
- *
- * Based on http://es5.github.com/#x15.11.4.4
- *
- * @param {String|Error} error
- * @return {String} error message
- */
- errorString = function( error ) {
- var name, message,
- errorString = error.toString();
- if ( errorString.substring( 0, 7 ) === "[object" ) {
- name = error.name ? error.name.toString() : "Error";
- message = error.message ? error.message.toString() : "";
- if ( name && message ) {
- return name + ": " + message;
- } else if ( name ) {
- return name;
- } else if ( message ) {
- return message;
- } else {
- return "Error";
- }
- } else {
- return errorString;
- }
- },
- /**
- * Makes a clone of an object using only Array or Object as base,
- * and copies over the own enumerable properties.
- *
- * @param {Object} obj
- * @return {Object} New object with only the own properties (recursively).
- */
- objectValues = function( obj ) {
- // Grunt 0.3.x uses an older version of jshint that still has jshint/jshint#392.
- /*jshint newcap: false */
- var key, val,
- vals = QUnit.is( "array", obj ) ? [] : {};
- for ( key in obj ) {
- if ( hasOwn.call( obj, key ) ) {
- val = obj[key];
- vals[key] = val === Object(val) ? objectValues(val) : val;
- }
- }
- return vals;
- };
-
-function Test( settings ) {
- extend( this, settings );
- this.assertions = [];
- this.testNumber = ++Test.count;
-}
-
-Test.count = 0;
-
-Test.prototype = {
- init: function() {
- var a, b, li,
- tests = id( "qunit-tests" );
-
- if ( tests ) {
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml;
-
- // `a` initialized at top of scope
- a = document.createElement( "a" );
- a.innerHTML = "Rerun";
- a.href = QUnit.url({ testNumber: this.testNumber });
-
- li = document.createElement( "li" );
- li.appendChild( b );
- li.appendChild( a );
- li.className = "running";
- li.id = this.id = "qunit-test-output" + testId++;
-
- tests.appendChild( li );
- }
- },
- setup: function() {
- if ( this.module !== config.previousModule ) {
- if ( config.previousModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.previousModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
- config.previousModule = this.module;
- config.moduleStats = { all: 0, bad: 0 };
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- } else if ( config.autorun ) {
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- }
-
- config.current = this;
-
- this.testEnvironment = extend({
- setup: function() {},
- teardown: function() {}
- }, this.moduleTestEnvironment );
-
- this.started = +new Date();
- runLoggingCallbacks( "testStart", QUnit, {
- name: this.testName,
- module: this.module
- });
-
- // allow utility functions to access the current test environment
- // TODO why??
- QUnit.current_testEnvironment = this.testEnvironment;
-
- if ( !config.pollution ) {
- saveGlobal();
- }
- if ( config.notrycatch ) {
- this.testEnvironment.setup.call( this.testEnvironment );
- return;
- }
- try {
- this.testEnvironment.setup.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Setup failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- },
- run: function() {
- config.current = this;
-
- var running = id( "qunit-testresult" );
-
- if ( running ) {
- running.innerHTML = "Running:
" + this.nameHtml;
- }
-
- if ( this.async ) {
- QUnit.stop();
- }
-
- this.callbackStarted = +new Date();
-
- if ( config.notrycatch ) {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- return;
- }
-
- try {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- } catch( e ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
-
- QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + " " + this.stack + ": " + ( e.message || e ), extractStacktrace( e, 0 ) );
- // else next test will carry the responsibility
- saveGlobal();
-
- // Restart the tests if they're blocking
- if ( config.blocking ) {
- QUnit.start();
- }
- }
- },
- teardown: function() {
- config.current = this;
- if ( config.notrycatch ) {
- if ( typeof this.callbackRuntime === "undefined" ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
- }
- this.testEnvironment.teardown.call( this.testEnvironment );
- return;
- } else {
- try {
- this.testEnvironment.teardown.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Teardown failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- }
- checkPollution();
- },
- finish: function() {
- config.current = this;
- if ( config.requireExpects && this.expected === null ) {
- QUnit.pushFailure( "Expected number of assertions to be defined, but expect() was not called.", this.stack );
- } else if ( this.expected !== null && this.expected !== this.assertions.length ) {
- QUnit.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack );
- } else if ( this.expected === null && !this.assertions.length ) {
- QUnit.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions.", this.stack );
- }
-
- var i, assertion, a, b, time, li, ol,
- test = this,
- good = 0,
- bad = 0,
- tests = id( "qunit-tests" );
-
- this.runtime = +new Date() - this.started;
- config.stats.all += this.assertions.length;
- config.moduleStats.all += this.assertions.length;
-
- if ( tests ) {
- ol = document.createElement( "ol" );
- ol.className = "qunit-assert-list";
-
- for ( i = 0; i < this.assertions.length; i++ ) {
- assertion = this.assertions[i];
-
- li = document.createElement( "li" );
- li.className = assertion.result ? "pass" : "fail";
- li.innerHTML = assertion.message || ( assertion.result ? "okay" : "failed" );
- ol.appendChild( li );
-
- if ( assertion.result ) {
- good++;
- } else {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
-
- // store result when possible
- if ( QUnit.config.reorder && defined.sessionStorage ) {
- if ( bad ) {
- sessionStorage.setItem( "qunit-test-" + this.module + "-" + this.testName, bad );
- } else {
- sessionStorage.removeItem( "qunit-test-" + this.module + "-" + this.testName );
- }
- }
-
- if ( bad === 0 ) {
- addClass( ol, "qunit-collapsed" );
- }
-
- // `b` initialized at top of scope
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml + " (" + bad + ", " + good + ", " + this.assertions.length + ")";
-
- addEvent(b, "click", function() {
- var next = b.parentNode.lastChild,
- collapsed = hasClass( next, "qunit-collapsed" );
- ( collapsed ? removeClass : addClass )( next, "qunit-collapsed" );
- });
-
- addEvent(b, "dblclick", function( e ) {
- var target = e && e.target ? e.target : window.event.srcElement;
- if ( target.nodeName.toLowerCase() === "span" || target.nodeName.toLowerCase() === "b" ) {
- target = target.parentNode;
- }
- if ( window.location && target.nodeName.toLowerCase() === "strong" ) {
- window.location = QUnit.url({ testNumber: test.testNumber });
- }
- });
-
- // `time` initialized at top of scope
- time = document.createElement( "span" );
- time.className = "runtime";
- time.innerHTML = this.runtime + " ms";
-
- // `li` initialized at top of scope
- li = id( this.id );
- li.className = bad ? "fail" : "pass";
- li.removeChild( li.firstChild );
- a = li.firstChild;
- li.appendChild( b );
- li.appendChild( a );
- li.appendChild( time );
- li.appendChild( ol );
-
- } else {
- for ( i = 0; i < this.assertions.length; i++ ) {
- if ( !this.assertions[i].result ) {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
- }
-
- runLoggingCallbacks( "testDone", QUnit, {
- name: this.testName,
- module: this.module,
- failed: bad,
- passed: this.assertions.length - bad,
- total: this.assertions.length,
- duration: this.runtime
- });
-
- QUnit.reset();
-
- config.current = undefined;
- },
-
- queue: function() {
- var bad,
- test = this;
-
- synchronize(function() {
- test.init();
- });
- function run() {
- // each of these can by async
- synchronize(function() {
- test.setup();
- });
- synchronize(function() {
- test.run();
- });
- synchronize(function() {
- test.teardown();
- });
- synchronize(function() {
- test.finish();
- });
- }
-
- // `bad` initialized at top of scope
- // defer when previous test run passed, if storage is available
- bad = QUnit.config.reorder && defined.sessionStorage &&
- +sessionStorage.getItem( "qunit-test-" + this.module + "-" + this.testName );
-
- if ( bad ) {
- run();
- } else {
- synchronize( run, true );
- }
- }
-};
-
-// Root QUnit object.
-// `QUnit` initialized at top of scope
-QUnit = {
-
- // call on start of module test to prepend name to all tests
- module: function( name, testEnvironment ) {
- config.currentModule = name;
- config.currentModuleTestEnvironment = testEnvironment;
- config.modules[name] = true;
- },
-
- asyncTest: function( testName, expected, callback ) {
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- QUnit.test( testName, expected, callback, true );
- },
-
- test: function( testName, expected, callback, async ) {
- var test,
- nameHtml = "" + escapeText( testName ) + "";
-
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- if ( config.currentModule ) {
- nameHtml = "" + escapeText( config.currentModule ) + ": " + nameHtml;
- }
-
- test = new Test({
- nameHtml: nameHtml,
- testName: testName,
- expected: expected,
- async: async,
- callback: callback,
- module: config.currentModule,
- moduleTestEnvironment: config.currentModuleTestEnvironment,
- stack: sourceFromStacktrace( 2 )
- });
-
- if ( !validTest( test ) ) {
- return;
- }
-
- test.queue();
- },
-
- // Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through.
- expect: function( asserts ) {
- if (arguments.length === 1) {
- config.current.expected = asserts;
- } else {
- return config.current.expected;
- }
- },
-
- start: function( count ) {
- // QUnit hasn't been initialized yet.
- // Note: RequireJS (et al) may delay onLoad
- if ( config.semaphore === undefined ) {
- QUnit.begin(function() {
- // This is triggered at the top of QUnit.load, push start() to the event loop, to allow QUnit.load to finish first
- setTimeout(function() {
- QUnit.start( count );
- });
- });
- return;
- }
-
- config.semaphore -= count || 1;
- // don't start until equal number of stop-calls
- if ( config.semaphore > 0 ) {
- return;
- }
- // ignore if start is called more often then stop
- if ( config.semaphore < 0 ) {
- config.semaphore = 0;
- QUnit.pushFailure( "Called start() while already started (QUnit.config.semaphore was 0 already)", null, sourceFromStacktrace(2) );
- return;
- }
- // A slight delay, to avoid any current callbacks
- if ( defined.setTimeout ) {
- window.setTimeout(function() {
- if ( config.semaphore > 0 ) {
- return;
- }
- if ( config.timeout ) {
- clearTimeout( config.timeout );
- }
-
- config.blocking = false;
- process( true );
- }, 13);
- } else {
- config.blocking = false;
- process( true );
- }
- },
-
- stop: function( count ) {
- config.semaphore += count || 1;
- config.blocking = true;
-
- if ( config.testTimeout && defined.setTimeout ) {
- clearTimeout( config.timeout );
- config.timeout = window.setTimeout(function() {
- QUnit.ok( false, "Test timed out" );
- config.semaphore = 1;
- QUnit.start();
- }, config.testTimeout );
- }
- }
-};
-
-// `assert` initialized at top of scope
-// Asssert helpers
-// All of these must either call QUnit.push() or manually do:
-// - runLoggingCallbacks( "log", .. );
-// - config.current.assertions.push({ .. });
-// We attach it to the QUnit object *after* we expose the public API,
-// otherwise `assert` will become a global variable in browsers (#341).
-assert = {
- /**
- * Asserts rough true-ish result.
- * @name ok
- * @function
- * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" );
- */
- ok: function( result, msg ) {
- if ( !config.current ) {
- throw new Error( "ok() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
- result = !!result;
-
- var source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: msg
- };
-
- msg = escapeText( msg || (result ? "okay" : "failed" ) );
- msg = "" + msg + "";
-
- if ( !result ) {
- source = sourceFromStacktrace( 2 );
- if ( source ) {
- details.source = source;
- msg += "Source: | " + escapeText( source ) + " |
---|
";
- }
- }
- runLoggingCallbacks( "log", QUnit, details );
- config.current.assertions.push({
- result: result,
- message: msg
- });
- },
-
- /**
- * Assert that the first two arguments are equal, with an optional message.
- * Prints out both actual and expected values.
- * @name equal
- * @function
- * @example equal( format( "Received {0} bytes.", 2), "Received 2 bytes.", "format() replaces {0} with next argument" );
- */
- equal: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected == actual, actual, expected, message );
- },
-
- /**
- * @name notEqual
- * @function
- */
- notEqual: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected != actual, actual, expected, message );
- },
-
- /**
- * @name propEqual
- * @function
- */
- propEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notPropEqual
- * @function
- */
- notPropEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name deepEqual
- * @function
- */
- deepEqual: function( actual, expected, message ) {
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notDeepEqual
- * @function
- */
- notDeepEqual: function( actual, expected, message ) {
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name strictEqual
- * @function
- */
- strictEqual: function( actual, expected, message ) {
- QUnit.push( expected === actual, actual, expected, message );
- },
-
- /**
- * @name notStrictEqual
- * @function
- */
- notStrictEqual: function( actual, expected, message ) {
- QUnit.push( expected !== actual, actual, expected, message );
- },
-
- "throws": function( block, expected, message ) {
- var actual,
- expectedOutput = expected,
- ok = false;
-
- // 'expected' is optional
- if ( typeof expected === "string" ) {
- message = expected;
- expected = null;
- }
-
- config.current.ignoreGlobalErrors = true;
- try {
- block.call( config.current.testEnvironment );
- } catch (e) {
- actual = e;
- }
- config.current.ignoreGlobalErrors = false;
-
- if ( actual ) {
- // we don't want to validate thrown error
- if ( !expected ) {
- ok = true;
- expectedOutput = null;
- // expected is a regexp
- } else if ( QUnit.objectType( expected ) === "regexp" ) {
- ok = expected.test( errorString( actual ) );
- // expected is a constructor
- } else if ( actual instanceof expected ) {
- ok = true;
- // expected is a validation function which returns true is validation passed
- } else if ( expected.call( {}, actual ) === true ) {
- expectedOutput = null;
- ok = true;
- }
-
- QUnit.push( ok, actual, expectedOutput, message );
- } else {
- QUnit.pushFailure( message, null, 'No exception was thrown.' );
- }
- }
-};
-
-/**
- * @deprecate since 1.8.0
- * Kept assertion helpers in root for backwards compatibility.
- */
-extend( QUnit, assert );
-
-/**
- * @deprecated since 1.9.0
- * Kept root "raises()" for backwards compatibility.
- * (Note that we don't introduce assert.raises).
- */
-QUnit.raises = assert[ "throws" ];
-
-/**
- * @deprecated since 1.0.0, replaced with error pushes since 1.3.0
- * Kept to avoid TypeErrors for undefined methods.
- */
-QUnit.equals = function() {
- QUnit.push( false, false, false, "QUnit.equals has been deprecated since 2009 (e88049a0), use QUnit.equal instead" );
-};
-QUnit.same = function() {
- QUnit.push( false, false, false, "QUnit.same has been deprecated since 2009 (e88049a0), use QUnit.deepEqual instead" );
-};
-
-// We want access to the constructor's prototype
-(function() {
- function F() {}
- F.prototype = QUnit;
- QUnit = new F();
- // Make F QUnit's constructor so that we can add to the prototype later
- QUnit.constructor = F;
-}());
-
-/**
- * Config object: Maintain internal state
- * Later exposed as QUnit.config
- * `config` initialized at top of scope
- */
-config = {
- // The queue of tests to run
- queue: [],
-
- // block until document ready
- blocking: true,
-
- // when enabled, show only failing tests
- // gets persisted through sessionStorage and can be changed in UI via checkbox
- hidepassed: false,
-
- // by default, run previously failed tests first
- // very useful in combination with "Hide passed tests" checked
- reorder: true,
-
- // by default, modify document.title when suite is done
- altertitle: true,
-
- // when enabled, all tests must call expect()
- requireExpects: false,
-
- // add checkboxes that are persisted in the query-string
- // when enabled, the id is set to `true` as a `QUnit.config` property
- urlConfig: [
- {
- id: "noglobals",
- label: "Check for Globals",
- tooltip: "Enabling this will test if any test introduces new properties on the `window` object. Stored as query-strings."
- },
- {
- id: "notrycatch",
- label: "No try-catch",
- tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging exceptions in IE reasonable. Stored as query-strings."
- }
- ],
-
- // Set of all modules.
- modules: {},
-
- // logging callback queues
- begin: [],
- done: [],
- log: [],
- testStart: [],
- testDone: [],
- moduleStart: [],
- moduleDone: []
-};
-
-// Export global variables, unless an 'exports' object exists,
-// in that case we assume we're in CommonJS (dealt with on the bottom of the script)
-if ( typeof exports === "undefined" ) {
- extend( window, QUnit );
-
- // Expose QUnit object
- window.QUnit = QUnit;
-}
-
-// Initialize more QUnit.config and QUnit.urlParams
-(function() {
- var i,
- location = window.location || { search: "", protocol: "file:" },
- params = location.search.slice( 1 ).split( "&" ),
- length = params.length,
- urlParams = {},
- current;
-
- if ( params[ 0 ] ) {
- for ( i = 0; i < length; i++ ) {
- current = params[ i ].split( "=" );
- current[ 0 ] = decodeURIComponent( current[ 0 ] );
- // allow just a key to turn on a flag, e.g., test.html?noglobals
- current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true;
- urlParams[ current[ 0 ] ] = current[ 1 ];
- }
- }
-
- QUnit.urlParams = urlParams;
-
- // String search anywhere in moduleName+testName
- config.filter = urlParams.filter;
-
- // Exact match of the module name
- config.module = urlParams.module;
-
- config.testNumber = parseInt( urlParams.testNumber, 10 ) || null;
-
- // Figure out if we're running the tests from a server or not
- QUnit.isLocal = location.protocol === "file:";
-}());
-
-// Extend QUnit object,
-// these after set here because they should not be exposed as global functions
-extend( QUnit, {
- assert: assert,
-
- config: config,
-
- // Initialize the configuration options
- init: function() {
- extend( config, {
- stats: { all: 0, bad: 0 },
- moduleStats: { all: 0, bad: 0 },
- started: +new Date(),
- updateRate: 1000,
- blocking: false,
- autostart: true,
- autorun: false,
- filter: "",
- queue: [],
- semaphore: 1
- });
-
- var tests, banner, result,
- qunit = id( "qunit" );
-
- if ( qunit ) {
- qunit.innerHTML =
- "" +
- "" +
- "" +
- "" +
- "
";
- }
-
- tests = id( "qunit-tests" );
- banner = id( "qunit-banner" );
- result = id( "qunit-testresult" );
-
- if ( tests ) {
- tests.innerHTML = "";
- }
-
- if ( banner ) {
- banner.className = "";
- }
-
- if ( result ) {
- result.parentNode.removeChild( result );
- }
-
- if ( tests ) {
- result = document.createElement( "p" );
- result.id = "qunit-testresult";
- result.className = "result";
- tests.parentNode.insertBefore( result, tests );
- result.innerHTML = "Running...
";
- }
- },
-
- // Resets the test setup. Useful for tests that modify the DOM.
- reset: function() {
- var fixture = id( "qunit-fixture" );
- if ( fixture ) {
- fixture.innerHTML = config.fixture;
- }
- },
-
- // Trigger an event on an element.
- // @example triggerEvent( document.body, "click" );
- triggerEvent: function( elem, type, event ) {
- if ( document.createEvent ) {
- event = document.createEvent( "MouseEvents" );
- event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView,
- 0, 0, 0, 0, 0, false, false, false, false, 0, null);
-
- elem.dispatchEvent( event );
- } else if ( elem.fireEvent ) {
- elem.fireEvent( "on" + type );
- }
- },
-
- // Safe object type checking
- is: function( type, obj ) {
- return QUnit.objectType( obj ) === type;
- },
-
- objectType: function( obj ) {
- if ( typeof obj === "undefined" ) {
- return "undefined";
- // consider: typeof null === object
- }
- if ( obj === null ) {
- return "null";
- }
-
- var match = toString.call( obj ).match(/^\[object\s(.*)\]$/),
- type = match && match[1] || "";
-
- switch ( type ) {
- case "Number":
- if ( isNaN(obj) ) {
- return "nan";
- }
- return "number";
- case "String":
- case "Boolean":
- case "Array":
- case "Date":
- case "RegExp":
- case "Function":
- return type.toLowerCase();
- }
- if ( typeof obj === "object" ) {
- return "object";
- }
- return undefined;
- },
-
- push: function( result, actual, expected, message ) {
- if ( !config.current ) {
- throw new Error( "assertion outside test context, was " + sourceFromStacktrace() );
- }
-
- var output, source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: message,
- actual: actual,
- expected: expected
- };
-
- message = escapeText( message ) || ( result ? "okay" : "failed" );
- message = "" + message + "";
- output = message;
-
- if ( !result ) {
- expected = escapeText( QUnit.jsDump.parse(expected) );
- actual = escapeText( QUnit.jsDump.parse(actual) );
- output += "Expected: | " + expected + " |
";
-
- if ( actual !== expected ) {
- output += "Result: | " + actual + " |
";
- output += "Diff: | " + QUnit.diff( expected, actual ) + " |
";
- }
-
- source = sourceFromStacktrace();
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
- }
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: !!result,
- message: output
- });
- },
-
- pushFailure: function( message, source, actual ) {
- if ( !config.current ) {
- throw new Error( "pushFailure() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
-
- var output,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: false,
- message: message
- };
-
- message = escapeText( message ) || "error";
- message = "" + message + "";
- output = message;
-
- output += "";
-
- if ( actual ) {
- output += "Result: | " + escapeText( actual ) + " |
";
- }
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: false,
- message: output
- });
- },
-
- url: function( params ) {
- params = extend( extend( {}, QUnit.urlParams ), params );
- var key,
- querystring = "?";
-
- for ( key in params ) {
- if ( !hasOwn.call( params, key ) ) {
- continue;
- }
- querystring += encodeURIComponent( key ) + "=" +
- encodeURIComponent( params[ key ] ) + "&";
- }
- return window.location.protocol + "//" + window.location.host +
- window.location.pathname + querystring.slice( 0, -1 );
- },
-
- extend: extend,
- id: id,
- addEvent: addEvent
- // load, equiv, jsDump, diff: Attached later
-});
-
-/**
- * @deprecated: Created for backwards compatibility with test runner that set the hook function
- * into QUnit.{hook}, instead of invoking it and passing the hook function.
- * QUnit.constructor is set to the empty F() above so that we can add to it's prototype here.
- * Doing this allows us to tell if the following methods have been overwritten on the actual
- * QUnit object.
- */
-extend( QUnit.constructor.prototype, {
-
- // Logging callbacks; all receive a single argument with the listed properties
- // run test/logs.html for any related changes
- begin: registerLoggingCallback( "begin" ),
-
- // done: { failed, passed, total, runtime }
- done: registerLoggingCallback( "done" ),
-
- // log: { result, actual, expected, message }
- log: registerLoggingCallback( "log" ),
-
- // testStart: { name }
- testStart: registerLoggingCallback( "testStart" ),
-
- // testDone: { name, failed, passed, total, duration }
- testDone: registerLoggingCallback( "testDone" ),
-
- // moduleStart: { name }
- moduleStart: registerLoggingCallback( "moduleStart" ),
-
- // moduleDone: { name, failed, passed, total }
- moduleDone: registerLoggingCallback( "moduleDone" )
-});
-
-if ( typeof document === "undefined" || document.readyState === "complete" ) {
- config.autorun = true;
-}
-
-QUnit.load = function() {
- runLoggingCallbacks( "begin", QUnit, {} );
-
- // Initialize the config, saving the execution queue
- var banner, filter, i, label, len, main, ol, toolbar, userAgent, val,
- urlConfigCheckboxesContainer, urlConfigCheckboxes, moduleFilter,
- numModules = 0,
- moduleFilterHtml = "",
- urlConfigHtml = "",
- oldconfig = extend( {}, config );
-
- QUnit.init();
- extend(config, oldconfig);
-
- config.blocking = false;
-
- len = config.urlConfig.length;
-
- for ( i = 0; i < len; i++ ) {
- val = config.urlConfig[i];
- if ( typeof val === "string" ) {
- val = {
- id: val,
- label: val,
- tooltip: "[no tooltip available]"
- };
- }
- config[ val.id ] = QUnit.urlParams[ val.id ];
- urlConfigHtml += "";
- }
-
- moduleFilterHtml += "";
-
- // `userAgent` initialized at top of scope
- userAgent = id( "qunit-userAgent" );
- if ( userAgent ) {
- userAgent.innerHTML = navigator.userAgent;
- }
-
- // `banner` initialized at top of scope
- banner = id( "qunit-header" );
- if ( banner ) {
- banner.innerHTML = "" + banner.innerHTML + " ";
- }
-
- // `toolbar` initialized at top of scope
- toolbar = id( "qunit-testrunner-toolbar" );
- if ( toolbar ) {
- // `filter` initialized at top of scope
- filter = document.createElement( "input" );
- filter.type = "checkbox";
- filter.id = "qunit-filter-pass";
-
- addEvent( filter, "click", function() {
- var tmp,
- ol = document.getElementById( "qunit-tests" );
-
- if ( filter.checked ) {
- ol.className = ol.className + " hidepass";
- } else {
- tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " ";
- ol.className = tmp.replace( / hidepass /, " " );
- }
- if ( defined.sessionStorage ) {
- if (filter.checked) {
- sessionStorage.setItem( "qunit-filter-passed-tests", "true" );
- } else {
- sessionStorage.removeItem( "qunit-filter-passed-tests" );
- }
- }
- });
-
- if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem( "qunit-filter-passed-tests" ) ) {
- filter.checked = true;
- // `ol` initialized at top of scope
- ol = document.getElementById( "qunit-tests" );
- ol.className = ol.className + " hidepass";
- }
- toolbar.appendChild( filter );
-
- // `label` initialized at top of scope
- label = document.createElement( "label" );
- label.setAttribute( "for", "qunit-filter-pass" );
- label.setAttribute( "title", "Only show tests and assertons that fail. Stored in sessionStorage." );
- label.innerHTML = "Hide passed tests";
- toolbar.appendChild( label );
-
- urlConfigCheckboxesContainer = document.createElement("span");
- urlConfigCheckboxesContainer.innerHTML = urlConfigHtml;
- urlConfigCheckboxes = urlConfigCheckboxesContainer.getElementsByTagName("input");
- // For oldIE support:
- // * Add handlers to the individual elements instead of the container
- // * Use "click" instead of "change"
- // * Fallback from event.target to event.srcElement
- addEvents( urlConfigCheckboxes, "click", function( event ) {
- var params = {},
- target = event.target || event.srcElement;
- params[ target.name ] = target.checked ? true : undefined;
- window.location = QUnit.url( params );
- });
- toolbar.appendChild( urlConfigCheckboxesContainer );
-
- if (numModules > 1) {
- moduleFilter = document.createElement( 'span' );
- moduleFilter.setAttribute( 'id', 'qunit-modulefilter-container' );
- moduleFilter.innerHTML = moduleFilterHtml;
- addEvent( moduleFilter.lastChild, "change", function() {
- var selectBox = moduleFilter.getElementsByTagName("select")[0],
- selectedModule = decodeURIComponent(selectBox.options[selectBox.selectedIndex].value);
-
- window.location = QUnit.url( { module: ( selectedModule === "" ) ? undefined : selectedModule } );
- });
- toolbar.appendChild(moduleFilter);
- }
- }
-
- // `main` initialized at top of scope
- main = id( "qunit-fixture" );
- if ( main ) {
- config.fixture = main.innerHTML;
- }
-
- if ( config.autostart ) {
- QUnit.start();
- }
-};
-
-addEvent( window, "load", QUnit.load );
-
-// `onErrorFnPrev` initialized at top of scope
-// Preserve other handlers
-onErrorFnPrev = window.onerror;
-
-// Cover uncaught exceptions
-// Returning true will surpress the default browser handler,
-// returning false will let it run.
-window.onerror = function ( error, filePath, linerNr ) {
- var ret = false;
- if ( onErrorFnPrev ) {
- ret = onErrorFnPrev( error, filePath, linerNr );
- }
-
- // Treat return value as window.onerror itself does,
- // Only do our handling if not surpressed.
- if ( ret !== true ) {
- if ( QUnit.config.current ) {
- if ( QUnit.config.current.ignoreGlobalErrors ) {
- return true;
- }
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- } else {
- QUnit.test( "global failure", extend( function() {
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- }, { validTest: validTest } ) );
- }
- return false;
- }
-
- return ret;
-};
-
-function done() {
- config.autorun = true;
-
- // Log the last module results
- if ( config.currentModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.currentModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
-
- var i, key,
- banner = id( "qunit-banner" ),
- tests = id( "qunit-tests" ),
- runtime = +new Date() - config.started,
- passed = config.stats.all - config.stats.bad,
- html = [
- "Tests completed in ",
- runtime,
- " milliseconds.
",
- "",
- passed,
- " assertions of ",
- config.stats.all,
- " passed, ",
- config.stats.bad,
- " failed."
- ].join( "" );
-
- if ( banner ) {
- banner.className = ( config.stats.bad ? "qunit-fail" : "qunit-pass" );
- }
-
- if ( tests ) {
- id( "qunit-testresult" ).innerHTML = html;
- }
-
- if ( config.altertitle && typeof document !== "undefined" && document.title ) {
- // show ✖ for good, ✔ for bad suite result in title
- // use escape sequences in case file gets loaded with non-utf-8-charset
- document.title = [
- ( config.stats.bad ? "\u2716" : "\u2714" ),
- document.title.replace( /^[\u2714\u2716] /i, "" )
- ].join( " " );
- }
-
- // clear own sessionStorage items if all tests passed
- if ( config.reorder && defined.sessionStorage && config.stats.bad === 0 ) {
- // `key` & `i` initialized at top of scope
- for ( i = 0; i < sessionStorage.length; i++ ) {
- key = sessionStorage.key( i++ );
- if ( key.indexOf( "qunit-test-" ) === 0 ) {
- sessionStorage.removeItem( key );
- }
- }
- }
-
- // scroll back to top to show results
- if ( window.scrollTo ) {
- window.scrollTo(0, 0);
- }
-
- runLoggingCallbacks( "done", QUnit, {
- failed: config.stats.bad,
- passed: passed,
- total: config.stats.all,
- runtime: runtime
- });
-}
-
-/** @return Boolean: true if this test should be ran */
-function validTest( test ) {
- var include,
- filter = config.filter && config.filter.toLowerCase(),
- module = config.module && config.module.toLowerCase(),
- fullName = (test.module + ": " + test.testName).toLowerCase();
-
- // Internally-generated tests are always valid
- if ( test.callback && test.callback.validTest === validTest ) {
- delete test.callback.validTest;
- return true;
- }
-
- if ( config.testNumber ) {
- return test.testNumber === config.testNumber;
- }
-
- if ( module && ( !test.module || test.module.toLowerCase() !== module ) ) {
- return false;
- }
-
- if ( !filter ) {
- return true;
- }
-
- include = filter.charAt( 0 ) !== "!";
- if ( !include ) {
- filter = filter.slice( 1 );
- }
-
- // If the filter matches, we need to honour include
- if ( fullName.indexOf( filter ) !== -1 ) {
- return include;
- }
-
- // Otherwise, do the opposite
- return !include;
-}
-
-// so far supports only Firefox, Chrome and Opera (buggy), Safari (for real exceptions)
-// Later Safari and IE10 are supposed to support error.stack as well
-// See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack
-function extractStacktrace( e, offset ) {
- offset = offset === undefined ? 3 : offset;
-
- var stack, include, i;
-
- if ( e.stacktrace ) {
- // Opera
- return e.stacktrace.split( "\n" )[ offset + 3 ];
- } else if ( e.stack ) {
- // Firefox, Chrome
- stack = e.stack.split( "\n" );
- if (/^error$/i.test( stack[0] ) ) {
- stack.shift();
- }
- if ( fileName ) {
- include = [];
- for ( i = offset; i < stack.length; i++ ) {
- if ( stack[ i ].indexOf( fileName ) !== -1 ) {
- break;
- }
- include.push( stack[ i ] );
- }
- if ( include.length ) {
- return include.join( "\n" );
- }
- }
- return stack[ offset ];
- } else if ( e.sourceURL ) {
- // Safari, PhantomJS
- // hopefully one day Safari provides actual stacktraces
- // exclude useless self-reference for generated Error objects
- if ( /qunit.js$/.test( e.sourceURL ) ) {
- return;
- }
- // for actual exceptions, this is useful
- return e.sourceURL + ":" + e.line;
- }
-}
-function sourceFromStacktrace( offset ) {
- try {
- throw new Error();
- } catch ( e ) {
- return extractStacktrace( e, offset );
- }
-}
-
-/**
- * Escape text for attribute or text content.
- */
-function escapeText( s ) {
- if ( !s ) {
- return "";
- }
- s = s + "";
- // Both single quotes and double quotes (for attributes)
- return s.replace( /['"<>&]/g, function( s ) {
- switch( s ) {
- case '\'':
- return ''';
- case '"':
- return '"';
- case '<':
- return '<';
- case '>':
- return '>';
- case '&':
- return '&';
- }
- });
-}
-
-function synchronize( callback, last ) {
- config.queue.push( callback );
-
- if ( config.autorun && !config.blocking ) {
- process( last );
- }
-}
-
-function process( last ) {
- function next() {
- process( last );
- }
- var start = new Date().getTime();
- config.depth = config.depth ? config.depth + 1 : 1;
-
- while ( config.queue.length && !config.blocking ) {
- if ( !defined.setTimeout || config.updateRate <= 0 || ( ( new Date().getTime() - start ) < config.updateRate ) ) {
- config.queue.shift()();
- } else {
- window.setTimeout( next, 13 );
- break;
- }
- }
- config.depth--;
- if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) {
- done();
- }
-}
-
-function saveGlobal() {
- config.pollution = [];
-
- if ( config.noglobals ) {
- for ( var key in window ) {
- // in Opera sometimes DOM element ids show up here, ignore them
- if ( !hasOwn.call( window, key ) || /^qunit-test-output/.test( key ) ) {
- continue;
- }
- config.pollution.push( key );
- }
- }
-}
-
-function checkPollution() {
- var newGlobals,
- deletedGlobals,
- old = config.pollution;
-
- saveGlobal();
-
- newGlobals = diff( config.pollution, old );
- if ( newGlobals.length > 0 ) {
- QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join(", ") );
- }
-
- deletedGlobals = diff( old, config.pollution );
- if ( deletedGlobals.length > 0 ) {
- QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join(", ") );
- }
-}
-
-// returns a new Array with the elements that are in a but not in b
-function diff( a, b ) {
- var i, j,
- result = a.slice();
-
- for ( i = 0; i < result.length; i++ ) {
- for ( j = 0; j < b.length; j++ ) {
- if ( result[i] === b[j] ) {
- result.splice( i, 1 );
- i--;
- break;
- }
- }
- }
- return result;
-}
-
-function extend( a, b ) {
- for ( var prop in b ) {
- if ( b[ prop ] === undefined ) {
- delete a[ prop ];
-
- // Avoid "Member not found" error in IE8 caused by setting window.constructor
- } else if ( prop !== "constructor" || a !== window ) {
- a[ prop ] = b[ prop ];
- }
- }
-
- return a;
-}
-
-/**
- * @param {HTMLElement} elem
- * @param {string} type
- * @param {Function} fn
- */
-function addEvent( elem, type, fn ) {
- // Standards-based browsers
- if ( elem.addEventListener ) {
- elem.addEventListener( type, fn, false );
- // IE
- } else {
- elem.attachEvent( "on" + type, fn );
- }
-}
-
-/**
- * @param {Array|NodeList} elems
- * @param {string} type
- * @param {Function} fn
- */
-function addEvents( elems, type, fn ) {
- var i = elems.length;
- while ( i-- ) {
- addEvent( elems[i], type, fn );
- }
-}
-
-function hasClass( elem, name ) {
- return (" " + elem.className + " ").indexOf(" " + name + " ") > -1;
-}
-
-function addClass( elem, name ) {
- if ( !hasClass( elem, name ) ) {
- elem.className += (elem.className ? " " : "") + name;
- }
-}
-
-function removeClass( elem, name ) {
- var set = " " + elem.className + " ";
- // Class name may appear multiple times
- while ( set.indexOf(" " + name + " ") > -1 ) {
- set = set.replace(" " + name + " " , " ");
- }
- // If possible, trim it for prettiness, but not neccecarily
- elem.className = window.jQuery ? jQuery.trim( set ) : ( set.trim ? set.trim() : set );
-}
-
-function id( name ) {
- return !!( typeof document !== "undefined" && document && document.getElementById ) &&
- document.getElementById( name );
-}
-
-function registerLoggingCallback( key ) {
- return function( callback ) {
- config[key].push( callback );
- };
-}
-
-// Supports deprecated method of completely overwriting logging callbacks
-function runLoggingCallbacks( key, scope, args ) {
- var i, callbacks;
- if ( QUnit.hasOwnProperty( key ) ) {
- QUnit[ key ].call(scope, args );
- } else {
- callbacks = config[ key ];
- for ( i = 0; i < callbacks.length; i++ ) {
- callbacks[ i ].call( scope, args );
- }
- }
-}
-
-// Test for equality any JavaScript type.
-// Author: Philippe Rathé
-QUnit.equiv = (function() {
-
- // Call the o related callback with the given arguments.
- function bindCallbacks( o, callbacks, args ) {
- var prop = QUnit.objectType( o );
- if ( prop ) {
- if ( QUnit.objectType( callbacks[ prop ] ) === "function" ) {
- return callbacks[ prop ].apply( callbacks, args );
- } else {
- return callbacks[ prop ]; // or undefined
- }
- }
- }
-
- // the real equiv function
- var innerEquiv,
- // stack to decide between skip/abort functions
- callers = [],
- // stack to avoiding loops from circular referencing
- parents = [],
-
- getProto = Object.getPrototypeOf || function ( obj ) {
- return obj.__proto__;
- },
- callbacks = (function () {
-
- // for string, boolean, number and null
- function useStrictEquality( b, a ) {
- /*jshint eqeqeq:false */
- if ( b instanceof a.constructor || a instanceof b.constructor ) {
- // to catch short annotaion VS 'new' annotation of a
- // declaration
- // e.g. var i = 1;
- // var j = new Number(1);
- return a == b;
- } else {
- return a === b;
- }
- }
-
- return {
- "string": useStrictEquality,
- "boolean": useStrictEquality,
- "number": useStrictEquality,
- "null": useStrictEquality,
- "undefined": useStrictEquality,
-
- "nan": function( b ) {
- return isNaN( b );
- },
-
- "date": function( b, a ) {
- return QUnit.objectType( b ) === "date" && a.valueOf() === b.valueOf();
- },
-
- "regexp": function( b, a ) {
- return QUnit.objectType( b ) === "regexp" &&
- // the regex itself
- a.source === b.source &&
- // and its modifers
- a.global === b.global &&
- // (gmi) ...
- a.ignoreCase === b.ignoreCase &&
- a.multiline === b.multiline &&
- a.sticky === b.sticky;
- },
-
- // - skip when the property is a method of an instance (OOP)
- // - abort otherwise,
- // initial === would have catch identical references anyway
- "function": function() {
- var caller = callers[callers.length - 1];
- return caller !== Object && typeof caller !== "undefined";
- },
-
- "array": function( b, a ) {
- var i, j, len, loop;
-
- // b could be an object literal here
- if ( QUnit.objectType( b ) !== "array" ) {
- return false;
- }
-
- len = a.length;
- if ( len !== b.length ) {
- // safe and faster
- return false;
- }
-
- // track reference to avoid circular references
- parents.push( a );
- for ( i = 0; i < len; i++ ) {
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- loop = true;// dont rewalk array
- }
- }
- if ( !loop && !innerEquiv(a[i], b[i]) ) {
- parents.pop();
- return false;
- }
- }
- parents.pop();
- return true;
- },
-
- "object": function( b, a ) {
- var i, j, loop,
- // Default to true
- eq = true,
- aProperties = [],
- bProperties = [];
-
- // comparing constructors is more strict than using
- // instanceof
- if ( a.constructor !== b.constructor ) {
- // Allow objects with no prototype to be equivalent to
- // objects with Object as their constructor.
- if ( !(( getProto(a) === null && getProto(b) === Object.prototype ) ||
- ( getProto(b) === null && getProto(a) === Object.prototype ) ) ) {
- return false;
- }
- }
-
- // stack constructor before traversing properties
- callers.push( a.constructor );
- // track reference to avoid circular references
- parents.push( a );
-
- for ( i in a ) { // be strict: don't ensures hasOwnProperty
- // and go deep
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- // don't go down the same path twice
- loop = true;
- }
- }
- aProperties.push(i); // collect a's properties
-
- if (!loop && !innerEquiv( a[i], b[i] ) ) {
- eq = false;
- break;
- }
- }
-
- callers.pop(); // unstack, we are done
- parents.pop();
-
- for ( i in b ) {
- bProperties.push( i ); // collect b's properties
- }
-
- // Ensures identical properties name
- return eq && innerEquiv( aProperties.sort(), bProperties.sort() );
- }
- };
- }());
-
- innerEquiv = function() { // can take multiple arguments
- var args = [].slice.apply( arguments );
- if ( args.length < 2 ) {
- return true; // end transition
- }
-
- return (function( a, b ) {
- if ( a === b ) {
- return true; // catch the most you can
- } else if ( a === null || b === null || typeof a === "undefined" ||
- typeof b === "undefined" ||
- QUnit.objectType(a) !== QUnit.objectType(b) ) {
- return false; // don't lose time with error prone cases
- } else {
- return bindCallbacks(a, callbacks, [ b, a ]);
- }
-
- // apply transition with (1..n) arguments
- }( args[0], args[1] ) && arguments.callee.apply( this, args.splice(1, args.length - 1 )) );
- };
-
- return innerEquiv;
-}());
-
-/**
- * jsDump Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com |
- * http://flesler.blogspot.com Licensed under BSD
- * (http://www.opensource.org/licenses/bsd-license.php) Date: 5/15/2008
- *
- * @projectDescription Advanced and extensible data dumping for Javascript.
- * @version 1.0.0
- * @author Ariel Flesler
- * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html}
- */
-QUnit.jsDump = (function() {
- function quote( str ) {
- return '"' + str.toString().replace( /"/g, '\\"' ) + '"';
- }
- function literal( o ) {
- return o + "";
- }
- function join( pre, arr, post ) {
- var s = jsDump.separator(),
- base = jsDump.indent(),
- inner = jsDump.indent(1);
- if ( arr.join ) {
- arr = arr.join( "," + s + inner );
- }
- if ( !arr ) {
- return pre + post;
- }
- return [ pre, inner + arr, base + post ].join(s);
- }
- function array( arr, stack ) {
- var i = arr.length, ret = new Array(i);
- this.up();
- while ( i-- ) {
- ret[i] = this.parse( arr[i] , undefined , stack);
- }
- this.down();
- return join( "[", ret, "]" );
- }
-
- var reName = /^function (\w+)/,
- jsDump = {
- // type is used mostly internally, you can fix a (custom)type in advance
- parse: function( obj, type, stack ) {
- stack = stack || [ ];
- var inStack, res,
- parser = this.parsers[ type || this.typeOf(obj) ];
-
- type = typeof parser;
- inStack = inArray( obj, stack );
-
- if ( inStack !== -1 ) {
- return "recursion(" + (inStack - stack.length) + ")";
- }
- if ( type === "function" ) {
- stack.push( obj );
- res = parser.call( this, obj, stack );
- stack.pop();
- return res;
- }
- return ( type === "string" ) ? parser : this.parsers.error;
- },
- typeOf: function( obj ) {
- var type;
- if ( obj === null ) {
- type = "null";
- } else if ( typeof obj === "undefined" ) {
- type = "undefined";
- } else if ( QUnit.is( "regexp", obj) ) {
- type = "regexp";
- } else if ( QUnit.is( "date", obj) ) {
- type = "date";
- } else if ( QUnit.is( "function", obj) ) {
- type = "function";
- } else if ( typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined" ) {
- type = "window";
- } else if ( obj.nodeType === 9 ) {
- type = "document";
- } else if ( obj.nodeType ) {
- type = "node";
- } else if (
- // native arrays
- toString.call( obj ) === "[object Array]" ||
- // NodeList objects
- ( typeof obj.length === "number" && typeof obj.item !== "undefined" && ( obj.length ? obj.item(0) === obj[0] : ( obj.item( 0 ) === null && typeof obj[0] === "undefined" ) ) )
- ) {
- type = "array";
- } else if ( obj.constructor === Error.prototype.constructor ) {
- type = "error";
- } else {
- type = typeof obj;
- }
- return type;
- },
- separator: function() {
- return this.multiline ? this.HTML ? "
" : "\n" : this.HTML ? " " : " ";
- },
- // extra can be a number, shortcut for increasing-calling-decreasing
- indent: function( extra ) {
- if ( !this.multiline ) {
- return "";
- }
- var chr = this.indentChar;
- if ( this.HTML ) {
- chr = chr.replace( /\t/g, " " ).replace( / /g, " " );
- }
- return new Array( this._depth_ + (extra||0) ).join(chr);
- },
- up: function( a ) {
- this._depth_ += a || 1;
- },
- down: function( a ) {
- this._depth_ -= a || 1;
- },
- setParser: function( name, parser ) {
- this.parsers[name] = parser;
- },
- // The next 3 are exposed so you can use them
- quote: quote,
- literal: literal,
- join: join,
- //
- _depth_: 1,
- // This is the list of parsers, to modify them, use jsDump.setParser
- parsers: {
- window: "[Window]",
- document: "[Document]",
- error: function(error) {
- return "Error(\"" + error.message + "\")";
- },
- unknown: "[Unknown]",
- "null": "null",
- "undefined": "undefined",
- "function": function( fn ) {
- var ret = "function",
- // functions never have name in IE
- name = "name" in fn ? fn.name : (reName.exec(fn) || [])[1];
-
- if ( name ) {
- ret += " " + name;
- }
- ret += "( ";
-
- ret = [ ret, QUnit.jsDump.parse( fn, "functionArgs" ), "){" ].join( "" );
- return join( ret, QUnit.jsDump.parse(fn,"functionCode" ), "}" );
- },
- array: array,
- nodelist: array,
- "arguments": array,
- object: function( map, stack ) {
- var ret = [ ], keys, key, val, i;
- QUnit.jsDump.up();
- keys = [];
- for ( key in map ) {
- keys.push( key );
- }
- keys.sort();
- for ( i = 0; i < keys.length; i++ ) {
- key = keys[ i ];
- val = map[ key ];
- ret.push( QUnit.jsDump.parse( key, "key" ) + ": " + QUnit.jsDump.parse( val, undefined, stack ) );
- }
- QUnit.jsDump.down();
- return join( "{", ret, "}" );
- },
- node: function( node ) {
- var len, i, val,
- open = QUnit.jsDump.HTML ? "<" : "<",
- close = QUnit.jsDump.HTML ? ">" : ">",
- tag = node.nodeName.toLowerCase(),
- ret = open + tag,
- attrs = node.attributes;
-
- if ( attrs ) {
- for ( i = 0, len = attrs.length; i < len; i++ ) {
- val = attrs[i].nodeValue;
- // IE6 includes all attributes in .attributes, even ones not explicitly set.
- // Those have values like undefined, null, 0, false, "" or "inherit".
- if ( val && val !== "inherit" ) {
- ret += " " + attrs[i].nodeName + "=" + QUnit.jsDump.parse( val, "attribute" );
- }
- }
- }
- ret += close;
-
- // Show content of TextNode or CDATASection
- if ( node.nodeType === 3 || node.nodeType === 4 ) {
- ret += node.nodeValue;
- }
-
- return ret + open + "/" + tag + close;
- },
- // function calls it internally, it's the arguments part of the function
- functionArgs: function( fn ) {
- var args,
- l = fn.length;
-
- if ( !l ) {
- return "";
- }
-
- args = new Array(l);
- while ( l-- ) {
- // 97 is 'a'
- args[l] = String.fromCharCode(97+l);
- }
- return " " + args.join( ", " ) + " ";
- },
- // object calls it internally, the key part of an item in a map
- key: quote,
- // function calls it internally, it's the content of the function
- functionCode: "[code]",
- // node calls it internally, it's an html attribute value
- attribute: quote,
- string: quote,
- date: quote,
- regexp: literal,
- number: literal,
- "boolean": literal
- },
- // if true, entities are escaped ( <, >, \t, space and \n )
- HTML: false,
- // indentation unit
- indentChar: " ",
- // if true, items in a collection, are separated by a \n, else just a space.
- multiline: true
- };
-
- return jsDump;
-}());
-
-// from jquery.js
-function inArray( elem, array ) {
- if ( array.indexOf ) {
- return array.indexOf( elem );
- }
-
- for ( var i = 0, length = array.length; i < length; i++ ) {
- if ( array[ i ] === elem ) {
- return i;
- }
- }
-
- return -1;
-}
-
-/*
- * Javascript Diff Algorithm
- * By John Resig (http://ejohn.org/)
- * Modified by Chu Alan "sprite"
- *
- * Released under the MIT license.
- *
- * More Info:
- * http://ejohn.org/projects/javascript-diff-algorithm/
- *
- * Usage: QUnit.diff(expected, actual)
- *
- * QUnit.diff( "the quick brown fox jumped over", "the quick fox jumps over" ) == "the quick brown fox jumped jumps over"
- */
-QUnit.diff = (function() {
- /*jshint eqeqeq:false, eqnull:true */
- function diff( o, n ) {
- var i,
- ns = {},
- os = {};
-
- for ( i = 0; i < n.length; i++ ) {
- if ( !hasOwn.call( ns, n[i] ) ) {
- ns[ n[i] ] = {
- rows: [],
- o: null
- };
- }
- ns[ n[i] ].rows.push( i );
- }
-
- for ( i = 0; i < o.length; i++ ) {
- if ( !hasOwn.call( os, o[i] ) ) {
- os[ o[i] ] = {
- rows: [],
- n: null
- };
- }
- os[ o[i] ].rows.push( i );
- }
-
- for ( i in ns ) {
- if ( !hasOwn.call( ns, i ) ) {
- continue;
- }
- if ( ns[i].rows.length === 1 && hasOwn.call( os, i ) && os[i].rows.length === 1 ) {
- n[ ns[i].rows[0] ] = {
- text: n[ ns[i].rows[0] ],
- row: os[i].rows[0]
- };
- o[ os[i].rows[0] ] = {
- text: o[ os[i].rows[0] ],
- row: ns[i].rows[0]
- };
- }
- }
-
- for ( i = 0; i < n.length - 1; i++ ) {
- if ( n[i].text != null && n[ i + 1 ].text == null && n[i].row + 1 < o.length && o[ n[i].row + 1 ].text == null &&
- n[ i + 1 ] == o[ n[i].row + 1 ] ) {
-
- n[ i + 1 ] = {
- text: n[ i + 1 ],
- row: n[i].row + 1
- };
- o[ n[i].row + 1 ] = {
- text: o[ n[i].row + 1 ],
- row: i + 1
- };
- }
- }
-
- for ( i = n.length - 1; i > 0; i-- ) {
- if ( n[i].text != null && n[ i - 1 ].text == null && n[i].row > 0 && o[ n[i].row - 1 ].text == null &&
- n[ i - 1 ] == o[ n[i].row - 1 ]) {
-
- n[ i - 1 ] = {
- text: n[ i - 1 ],
- row: n[i].row - 1
- };
- o[ n[i].row - 1 ] = {
- text: o[ n[i].row - 1 ],
- row: i - 1
- };
- }
- }
-
- return {
- o: o,
- n: n
- };
- }
-
- return function( o, n ) {
- o = o.replace( /\s+$/, "" );
- n = n.replace( /\s+$/, "" );
-
- var i, pre,
- str = "",
- out = diff( o === "" ? [] : o.split(/\s+/), n === "" ? [] : n.split(/\s+/) ),
- oSpace = o.match(/\s+/g),
- nSpace = n.match(/\s+/g);
-
- if ( oSpace == null ) {
- oSpace = [ " " ];
- }
- else {
- oSpace.push( " " );
- }
-
- if ( nSpace == null ) {
- nSpace = [ " " ];
- }
- else {
- nSpace.push( " " );
- }
-
- if ( out.n.length === 0 ) {
- for ( i = 0; i < out.o.length; i++ ) {
- str += "" + out.o[i] + oSpace[i] + "";
- }
- }
- else {
- if ( out.n[0].text == null ) {
- for ( n = 0; n < out.o.length && out.o[n].text == null; n++ ) {
- str += "" + out.o[n] + oSpace[n] + "";
- }
- }
-
- for ( i = 0; i < out.n.length; i++ ) {
- if (out.n[i].text == null) {
- str += "" + out.n[i] + nSpace[i] + "";
- }
- else {
- // `pre` initialized at top of scope
- pre = "";
-
- for ( n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++ ) {
- pre += "" + out.o[n] + oSpace[n] + "";
- }
- str += " " + out.n[i].text + nSpace[i] + pre;
- }
- }
- }
-
- return str;
- };
-}());
-
-// for CommonJS enviroments, export everything
-if ( typeof exports !== "undefined" ) {
- extend( exports, QUnit );
-}
-
-// get at whatever the global object is, like window in browsers
-}( (function() {return this;}.call()) ));
diff --git a/test/lib/require.js b/test/lib/require.js
deleted file mode 100644
index 987f865..0000000
--- a/test/lib/require.js
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- RequireJS 2.1.5 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.
- Available via the MIT or new BSD license.
- see: http://github.com/jrburke/requirejs for details
-*/
-var requirejs,require,define;
-(function(aa){function I(b){return"[object Function]"===L.call(b)}function J(b){return"[object Array]"===L.call(b)}function y(b,c){if(b){var d;for(d=0;dthis.depCount&&!this.defined){if(I(n)){if(this.events.error)try{e=i.execCb(c,n,b,e)}catch(d){a=d}else e=i.execCb(c,n,b,e);this.map.isDefine&&((b=this.module)&&void 0!==b.exports&&b.exports!==this.exports?e=b.exports:void 0===e&&this.usingExports&&(e=this.exports));if(a)return a.requireMap=this.map,a.requireModules=[this.map.id],a.requireType="define",v(this.error=
-a)}else e=n;this.exports=e;if(this.map.isDefine&&!this.ignore&&(q[c]=e,l.onResourceLoad))l.onResourceLoad(i,this.map,this.depMaps);x(c);this.defined=!0}this.defining=!1;this.defined&&!this.defineEmitted&&(this.defineEmitted=!0,this.emit("defined",this.exports),this.defineEmitComplete=!0)}}else this.fetch()}},callPlugin:function(){var a=this.map,b=a.id,d=j(a.prefix);this.depMaps.push(d);t(d,"defined",u(this,function(e){var n,d;d=this.map.name;var g=this.map.parentMap?this.map.parentMap.name:null,h=
-i.makeRequire(a.parentMap,{enableBuildCallback:!0});if(this.map.unnormalized){if(e.normalize&&(d=e.normalize(d,function(a){return c(a,g,!0)})||""),e=j(a.prefix+"!"+d,this.map.parentMap),t(e,"defined",u(this,function(a){this.init([],function(){return a},null,{enabled:!0,ignore:!0})})),d=m(p,e.id)){this.depMaps.push(e);if(this.events.error)d.on("error",u(this,function(a){this.emit("error",a)}));d.enable()}}else n=u(this,function(a){this.init([],function(){return a},null,{enabled:!0})}),n.error=u(this,
-function(a){this.inited=!0;this.error=a;a.requireModules=[b];G(p,function(a){0===a.map.id.indexOf(b+"_unnormalized")&&x(a.map.id)});v(a)}),n.fromText=u(this,function(e,c){var d=a.name,g=j(d),C=O;c&&(e=c);C&&(O=!1);r(g);s(k.config,b)&&(k.config[d]=k.config[b]);try{l.exec(e)}catch(ca){return v(B("fromtexteval","fromText eval for "+b+" failed: "+ca,ca,[b]))}C&&(O=!0);this.depMaps.push(g);i.completeLoad(d);h([d],n)}),e.load(a.name,h,n,k)}));i.enable(d,this);this.pluginMaps[d.id]=d},enable:function(){V[this.map.id]=
-this;this.enabling=this.enabled=!0;y(this.depMaps,u(this,function(a,b){var c,e;if("string"===typeof a){a=j(a,this.map.isDefine?this.map:this.map.parentMap,!1,!this.skipMap);this.depMaps[b]=a;if(c=m(N,a.id)){this.depExports[b]=c(this);return}this.depCount+=1;t(a,"defined",u(this,function(a){this.defineDep(b,a);this.check()}));this.errback&&t(a,"error",this.errback)}c=a.id;e=p[c];!s(N,c)&&(e&&!e.enabled)&&i.enable(a,this)}));G(this.pluginMaps,u(this,function(a){var b=m(p,a.id);b&&!b.enabled&&i.enable(a,
-this)}));this.enabling=!1;this.check()},on:function(a,b){var c=this.events[a];c||(c=this.events[a]=[]);c.push(b)},emit:function(a,b){y(this.events[a],function(a){a(b)});"error"===a&&delete this.events[a]}};i={config:k,contextName:b,registry:p,defined:q,urlFetched:U,defQueue:H,Module:Z,makeModuleMap:j,nextTick:l.nextTick,onError:v,configure:function(a){a.baseUrl&&"/"!==a.baseUrl.charAt(a.baseUrl.length-1)&&(a.baseUrl+="/");var b=k.pkgs,c=k.shim,e={paths:!0,config:!0,map:!0};G(a,function(a,b){e[b]?
-"map"===b?(k.map||(k.map={}),R(k[b],a,!0,!0)):R(k[b],a,!0):k[b]=a});a.shim&&(G(a.shim,function(a,b){J(a)&&(a={deps:a});if((a.exports||a.init)&&!a.exportsFn)a.exportsFn=i.makeShimExports(a);c[b]=a}),k.shim=c);a.packages&&(y(a.packages,function(a){a="string"===typeof a?{name:a}:a;b[a.name]={name:a.name,location:a.location||a.name,main:(a.main||"main").replace(ja,"").replace(ea,"")}}),k.pkgs=b);G(p,function(a,b){!a.inited&&!a.map.unnormalized&&(a.map=j(b))});if(a.deps||a.callback)i.require(a.deps||[],
-a.callback)},makeShimExports:function(a){return function(){var b;a.init&&(b=a.init.apply(aa,arguments));return b||a.exports&&ba(a.exports)}},makeRequire:function(a,f){function d(e,c,h){var g,k;f.enableBuildCallback&&(c&&I(c))&&(c.__requireJsBuild=!0);if("string"===typeof e){if(I(c))return v(B("requireargs","Invalid require call"),h);if(a&&s(N,e))return N[e](p[a.id]);if(l.get)return l.get(i,e,a,d);g=j(e,a,!1,!0);g=g.id;return!s(q,g)?v(B("notloaded",'Module name "'+g+'" has not been loaded yet for context: '+
-b+(a?"":". Use require([])"))):q[g]}L();i.nextTick(function(){L();k=r(j(null,a));k.skipMap=f.skipMap;k.init(e,c,h,{enabled:!0});D()});return d}f=f||{};R(d,{isBrowser:A,toUrl:function(b){var d,f=b.lastIndexOf("."),g=b.split("/")[0];if(-1!==f&&(!("."===g||".."===g)||1h.attachEvent.toString().indexOf("[native code"))&&!Y?(O=!0,h.attachEvent("onreadystatechange",b.onScriptLoad)):(h.addEventListener("load",b.onScriptLoad,!1),h.addEventListener("error",b.onScriptError,!1)),h.src=d,K=h,D?x.insertBefore(h,D):x.appendChild(h),K=null,h;if(da)try{importScripts(d),b.completeLoad(c)}catch(j){b.onError(B("importscripts","importScripts failed for "+c+" at "+d,j,[c]))}};A&&M(document.getElementsByTagName("script"),function(b){x||(x=
-b.parentNode);if(t=b.getAttribute("data-main"))return r.baseUrl||(E=t.split("/"),Q=E.pop(),fa=E.length?E.join("/")+"/":"./",r.baseUrl=fa,t=Q),t=t.replace(ea,""),r.deps=r.deps?r.deps.concat(t):[t],!0});define=function(b,c,d){var l,h;"string"!==typeof b&&(d=c,c=b,b=null);J(c)||(d=c,c=[]);!c.length&&I(d)&&d.length&&(d.toString().replace(la,"").replace(ma,function(b,d){c.push(d)}),c=(1===d.length?["require"]:["require","exports","module"]).concat(c));if(O){if(!(l=K))P&&"interactive"===P.readyState||M(document.getElementsByTagName("script"),
-function(b){if("interactive"===b.readyState)return P=b}),l=P;l&&(b||(b=l.getAttribute("data-requiremodule")),h=F[l.getAttribute("data-requirecontext")])}(h?h.defQueue:T).push([b,c,d])};define.amd={jQuery:!0};l.exec=function(b){return eval(b)};l(r)}})(this);
diff --git a/test/lib/resemble.js b/test/lib/resemble.js
new file mode 100644
index 0000000..1cb8c29
--- /dev/null
+++ b/test/lib/resemble.js
@@ -0,0 +1,535 @@
+/*
+Author: James Cryer
+Company: Huddle
+Last updated date: 21 Feb 2013
+URL: https://github.com/Huddle/Resemble.js
+*/
+
+(function(_this){
+ 'use strict';
+
+ _this['resemble'] = function( fileData ){
+
+ var data = {};
+ var images = [];
+ var updateCallbackArray = [];
+
+ var tolerance = { // between 0 and 255
+ red: 16,
+ green: 16,
+ blue: 16,
+ minBrightness: 16,
+ maxBrightness: 240
+ };
+
+ var ignoreAntialiasing = false;
+ var ignoreColors = false;
+
+ function triggerDataUpdate(){
+ var len = updateCallbackArray.length;
+ var i;
+ for(i=0;i tolerance.maxBrightness;
+ }
+
+ function getHue(r,g,b){
+
+ r = r / 255;
+ g = g / 255;
+ b = b / 255;
+ var max = Math.max(r, g, b), min = Math.min(r, g, b);
+ var h;
+ var d;
+
+ if (max == min){
+ h = 0; // achromatic
+ } else{
+ d = max - min;
+ switch(max){
+ case r: h = (g - b) / d + (g < b ? 6 : 0); break;
+ case g: h = (b - r) / d + 2; break;
+ case b: h = (r - g) / d + 4; break;
+ }
+ h /= 6;
+ }
+
+ return h;
+ }
+
+ function isAntialiased(sourcePix, data, cacheSet, verticalPos, horizontalPos, width){
+ var offset;
+ var targetPix;
+ var distance = 1;
+ var i;
+ var j;
+ var hasHighContrastSibling = 0;
+ var hasSiblingWithDifferentHue = 0;
+ var hasEquivilantSibling = 0;
+
+ addHueInfo(sourcePix);
+
+ for (i = distance*-1; i <= distance; i++){
+ for (j = distance*-1; j <= distance; j++){
+
+ if(i===0 && j===0){
+ // ignore source pixel
+ } else {
+
+ offset = ((verticalPos+j)*width + (horizontalPos+i)) * 4;
+ targetPix = getPixelInfo(data, offset, cacheSet);
+
+ if(targetPix === null){
+ continue;
+ }
+
+ addBrightnessInfo(targetPix);
+ addHueInfo(targetPix);
+
+ if( isContrasting(sourcePix, targetPix) ){
+ hasHighContrastSibling++;
+ }
+
+ if( isRGBSame(sourcePix,targetPix) ){
+ hasEquivilantSibling++;
+ }
+
+ if( Math.abs(targetPix.h - sourcePix.h) > 0.3 ){
+ hasSiblingWithDifferentHue++;
+ }
+
+ if( hasSiblingWithDifferentHue > 1 || hasHighContrastSibling > 1){
+ return true;
+ }
+ }
+ }
+ }
+
+ if(hasEquivilantSibling < 2){
+ return true;
+ }
+
+ return false;
+ }
+
+ function errorPixel(px, offset){
+ px[offset] = 255; //r
+ px[offset + 1] = 0; //g
+ px[offset + 2] = 255; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyPixel(px, offset, data){
+ px[offset] = data.r; //r
+ px[offset + 1] = data.g; //g
+ px[offset + 2] = data.b; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyGrayScalePixel(px, offset, data){
+ px[offset] = data.brightness; //r
+ px[offset + 1] = data.brightness; //g
+ px[offset + 2] = data.brightness; //b
+ px[offset + 3] = 255; //a
+ }
+
+
+ function getPixelInfo(data, offset, cacheSet){
+ var r;
+ var g;
+ var b;
+ var d;
+
+ if(typeof data[offset] !== 'undefined'){
+ r = data[offset];
+ g = data[offset+1];
+ b = data[offset+2];
+ d = {
+ r: r,
+ g: g,
+ b: b
+ };
+
+ return d;
+ } else {
+ return null;
+ }
+ }
+
+ function addBrightnessInfo(data){
+ data.brightness = getBrightness(data.r,data.g,data.b); // 'corrected' lightness
+ }
+
+ function addHueInfo(data){
+ data.h = getHue(data.r,data.g,data.b);
+ }
+
+ function analyseImages(img1, img2, width, height){
+
+ var hiddenCanvas = document.createElement('canvas');
+
+ var data1 = img1.data;
+ var data2 = img2.data;
+
+ hiddenCanvas.width = width;
+ hiddenCanvas.height = height;
+
+ var context = hiddenCanvas.getContext('2d');
+ var imgd = context.createImageData(width,height);
+ var targetPix = imgd.data;
+
+ var mismatchCount = 0;
+
+ var time = Date.now();
+
+ var skip;
+
+ if( (width > 1200 || height > 1200) && ignoreAntialiasing){
+ skip = 6;
+ }
+
+ loop(height, width, function(verticalPos, horizontalPos){
+
+ if(skip){ // only skip if the image isn't small
+ if(verticalPos % skip === 0 || horizontalPos % skip === 0){
+ return;
+ }
+ }
+
+ var offset = (verticalPos*width + horizontalPos) * 4;
+ var pixel1 = getPixelInfo(data1, offset, 1);
+ var pixel2 = getPixelInfo(data2, offset, 2);
+
+ if(pixel1 === null || pixel2 === null){
+ return;
+ }
+
+ if (ignoreColors){
+
+ addBrightnessInfo(pixel1);
+ addBrightnessInfo(pixel2);
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ return;
+ }
+
+ if( isRGBSimilar(pixel1, pixel2) ){
+ copyPixel(targetPix, offset, pixel2);
+
+ } else if( ignoreAntialiasing && (
+ addBrightnessInfo(pixel1), // jit pixel info augmentation looks a little weird, sorry.
+ addBrightnessInfo(pixel2),
+ isAntialiased(pixel1, data1, 1, verticalPos, horizontalPos, width) ||
+ isAntialiased(pixel2, data2, 2, verticalPos, horizontalPos, width)
+ )){
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+
+ });
+
+ data.misMatchPercentage = (mismatchCount / (height*width) * 100).toFixed(2);
+ data.analysisTime = Date.now() - time;
+
+ data.getImageDataUrl = function(text){
+ var barHeight = 0;
+
+ if(text){
+ barHeight = addLabel(text,context,hiddenCanvas);
+ }
+
+ context.putImageData(imgd, 0, barHeight);
+
+ return hiddenCanvas.toDataURL("image/png");
+ };
+ }
+
+ function addLabel(text, context, hiddenCanvas){
+ var textPadding = 2;
+
+ context.font = '12px sans-serif';
+
+ var textWidth = context.measureText(text).width + textPadding*2;
+ var barHeight = 22;
+
+ if(textWidth > hiddenCanvas.width){
+ hiddenCanvas.width = textWidth;
+ }
+
+ hiddenCanvas.height += barHeight;
+
+ context.fillStyle = "#666";
+ context.fillRect(0,0,hiddenCanvas.width,barHeight -4);
+ context.fillStyle = "#fff";
+ context.fillRect(0,barHeight -4,hiddenCanvas.width, 4);
+
+ context.fillStyle = "#fff";
+ context.textBaseline = "top";
+ context.font = '12px sans-serif';
+ context.fillText(text, textPadding, 1);
+
+ return barHeight;
+ }
+
+ function normalise(img, w, h){
+ var c;
+ var context;
+
+ if(img.height < h || img.width < w){
+ c = document.createElement('canvas');
+ c.width = w;
+ c.height = h;
+ context = c.getContext('2d');
+ context.putImageData(img, 0, 0);
+ return context.getImageData(0, 0, w, h);
+ }
+
+ return img;
+ }
+
+ function compare(one, two){
+
+ function onceWeHaveBoth(){
+ var width;
+ var height;
+ if(images.length === 2){
+ width = images[0].width > images[1].width ? images[0].width : images[1].width;
+ height = images[0].height > images[1].height ? images[0].height : images[1].height;
+
+ if( (images[0].width === images[1].width) && (images[0].height === images[1].height) ){
+ data.isSameDimensions = true;
+ } else {
+ data.isSameDimensions = false;
+ }
+
+ analyseImages( normalise(images[0],width, height), normalise(images[1],width, height), width, height);
+
+ triggerDataUpdate();
+ }
+ }
+
+ images = [];
+ loadImageData(one, onceWeHaveBoth);
+ loadImageData(two, onceWeHaveBoth);
+ }
+
+ function getCompareApi(param){
+
+ var secondFileData,
+ hasMethod = typeof param === 'function';
+
+ if( !hasMethod ){
+ // assume it's file data
+ secondFileData = param;
+ }
+
+ var self = {
+ ignoreNothing: function(){
+
+ tolerance.red = 16;
+ tolerance.green = 16;
+ tolerance.blue = 16;
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreAntialiasing: function(){
+
+ tolerance.red = 32;
+ tolerance.green = 32;
+ tolerance.blue = 32;
+ tolerance.minBrightness = 64;
+ tolerance.maxBrightness = 96;
+
+ ignoreAntialiasing = true;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreColors: function(){
+
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = true;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ onComplete: function( callback ){
+
+ updateCallbackArray.push(callback);
+
+ var wrapper = function(){
+ compare(fileData, secondFileData);
+ };
+
+ wrapper();
+
+ return getCompareApi(wrapper);
+ }
+ };
+
+ return self;
+ }
+
+ return {
+ onComplete: function( callback ){
+ updateCallbackArray.push(callback);
+ loadImageData(fileData, function(imageData, width, height){
+ parseImage(imageData.data, width, height);
+ });
+ },
+ compareTo: function(secondFileData){
+ return getCompareApi(secondFileData);
+ }
+ };
+
+ };
+}(this));
\ No newline at end of file
diff --git a/test/testsuite.js b/test/testsuite.js
deleted file mode 100644
index b486acb..0000000
--- a/test/testsuite.js
+++ /dev/null
@@ -1,36 +0,0 @@
-requirejs.config({
- baseUrl: '/test/unit/'
-});
-
-define(function(require) {
- var testModules = [
- 'Pixi',
- 'Point',
- 'Rectangle',
- 'DisplayObject',
- 'DisplayObjectContainer',
- 'Sprite',
- 'MovieClip',
- 'InteractionManager',
- 'Stage',
- 'utils/Utils',
- 'utils/EventTarget',
- 'utils/Matrix',
- 'utils/Detector',
- 'renderers/WebGLShaders',
- 'renderers/WebGLRenderer',
- 'renderers/WebGLBatch',
- 'renderers/CanvasRenderer',
- 'extras/Strip',
- 'extras/Rope',
- 'textures/BaseTexture',
- 'textures/Texture',
- 'loaders/SpriteSheetLoader',
- 'loaders/AssetLoader'
- ];
-
- // Resolve all testModules and then start the Test Runner.
- require(testModules, function() {
- QUnit.start();
- });
-});
\ No newline at end of file
diff --git a/test/textures/SpriteSheet-Aliens.png b/test/textures/SpriteSheet-Aliens.png
new file mode 100644
index 0000000..210acb1
--- /dev/null
+++ b/test/textures/SpriteSheet-Aliens.png
Binary files differ
diff --git a/test/textures/SpriteSheet-Explosion.png b/test/textures/SpriteSheet-Explosion.png
new file mode 100755
index 0000000..79e1a69
--- /dev/null
+++ b/test/textures/SpriteSheet-Explosion.png
Binary files differ
diff --git a/test/textures/bunny.png b/test/textures/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/textures/bunny.png
Binary files differ
diff --git a/test/unit/DisplayObject.js b/test/unit/DisplayObject.js
deleted file mode 100644
index 5e7e72f..0000000
--- a/test/unit/DisplayObject.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObject');
-});
diff --git a/test/unit/DisplayObjectContainer.js b/test/unit/DisplayObjectContainer.js
deleted file mode 100644
index b323959..0000000
--- a/test/unit/DisplayObjectContainer.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObjectContainer');
-});
diff --git a/test/unit/InteractionManager.js b/test/unit/InteractionManager.js
deleted file mode 100644
index e751f52..0000000
--- a/test/unit/InteractionManager.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('InteractionManager');
-});
diff --git a/test/unit/MovieClip.js b/test/unit/MovieClip.js
deleted file mode 100644
index 37d9446..0000000
--- a/test/unit/MovieClip.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('MovieClip');
-});
diff --git a/test/unit/Pixi.js b/test/unit/Pixi.js
deleted file mode 100644
index 36eee73..0000000
--- a/test/unit/Pixi.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Pixi');
-});
diff --git a/test/unit/Point.js b/test/unit/Point.js
deleted file mode 100644
index 983ff6e..0000000
--- a/test/unit/Point.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Point');
-});
diff --git a/test/unit/Rectangle.js b/test/unit/Rectangle.js
deleted file mode 100644
index 3b439ba..0000000
--- a/test/unit/Rectangle.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Rectangle');
-});
diff --git a/test/unit/Sprite.js b/test/unit/Sprite.js
deleted file mode 100644
index ed4f596..0000000
--- a/test/unit/Sprite.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Sprite');
-});
diff --git a/test/unit/Stage.js b/test/unit/Stage.js
deleted file mode 100644
index 2d70291..0000000
--- a/test/unit/Stage.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Stage');
-});
diff --git a/test/unit/extras/Rope.js b/test/unit/extras/Rope.js
deleted file mode 100644
index 5606f14..0000000
--- a/test/unit/extras/Rope.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Rope');
-});
diff --git a/test/unit/extras/Strip.js b/test/unit/extras/Strip.js
deleted file mode 100644
index 0134d3a..0000000
--- a/test/unit/extras/Strip.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Strip');
-});
diff --git a/test/unit/loaders/AssetLoader.js b/test/unit/loaders/AssetLoader.js
deleted file mode 100644
index 13b8443..0000000
--- a/test/unit/loaders/AssetLoader.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('AssetLoader');
-});
diff --git a/test/unit/loaders/SpriteSheetLoader.js b/test/unit/loaders/SpriteSheetLoader.js
deleted file mode 100644
index 8bf0cb2..0000000
--- a/test/unit/loaders/SpriteSheetLoader.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('SpriteSheetLoader');
-});
diff --git a/test/unit/pixi/InteractionManager.js b/test/unit/pixi/InteractionManager.js
new file mode 100644
index 0000000..ed3001f
--- /dev/null
+++ b/test/unit/pixi/InteractionManager.js
@@ -0,0 +1,10 @@
+describe('pixi/InteractionManager', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var InteractionManager = PIXI.InteractionManager;
+
+ it('Module exists', function () {
+ expect(InteractionManager).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/Pixi.js b/test/unit/pixi/Pixi.js
new file mode 100644
index 0000000..27debc1
--- /dev/null
+++ b/test/unit/pixi/Pixi.js
@@ -0,0 +1,9 @@
+describe('pixi/Pixi', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+
+ it('Module exists', function () {
+ expect(global).to.have.property('PIXI').and.to.be.an('object');
+ });
+});
diff --git a/test/unit/pixi/core/Circle.js b/test/unit/pixi/core/Circle.js
new file mode 100644
index 0000000..93a4456
--- /dev/null
+++ b/test/unit/pixi/core/Circle.js
@@ -0,0 +1,22 @@
+describe('pixi/core/Circle', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Circle = PIXI.Circle;
+
+ it('Module exists', function () {
+ expect(Circle).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Circle();
+
+ expect(obj).to.be.an.instanceof(Circle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', 0);
+ expect(obj).to.have.property('y', 0);
+ expect(obj).to.have.property('radius', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Ellipse.js b/test/unit/pixi/core/Ellipse.js
new file mode 100644
index 0000000..026b56f
--- /dev/null
+++ b/test/unit/pixi/core/Ellipse.js
@@ -0,0 +1,24 @@
+describe('pixi/core/Ellipse', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Ellipse = PIXI.Ellipse;
+
+ it('Module exists', function () {
+ expect(Ellipse).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Ellipse();
+
+ expect(obj).to.be.an.instanceof(Ellipse);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+ expect(obj).to.respondTo('getBounds');
+
+ expect(obj).to.have.property('x', 0);
+ expect(obj).to.have.property('y', 0);
+ expect(obj).to.have.property('width', 0);
+ expect(obj).to.have.property('height', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Matrix.js b/test/unit/pixi/core/Matrix.js
new file mode 100644
index 0000000..b48989e
--- /dev/null
+++ b/test/unit/pixi/core/Matrix.js
@@ -0,0 +1,30 @@
+describe('pixi/core/Matrix', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var mat3 = PIXI.mat3;
+ var mat4 = PIXI.mat4;
+ var Matrix = PIXI.Matrix;
+
+ it('Ensure determineMatrixArrayType works', function () {
+ expect(Matrix).to.be.a('function');
+ });
+
+ it('mat3 exists', function () {
+ expect(mat3).to.be.an('object');
+ });
+
+ it('Confirm new mat3 matrix', function () {
+ var matrix = new mat3.create();
+ pixi_core_Matrix_confirmNewMat3(matrix);
+ });
+
+ it('mat3 exists', function () {
+ expect(mat4).to.be.an('object');
+ });
+
+ it('Confirm new mat4 matrix', function () {
+ var matrix = new mat4.create();
+ pixi_core_Matrix_confirmNewMat4(matrix);
+ });
+});
diff --git a/test/unit/pixi/core/Point.js b/test/unit/pixi/core/Point.js
new file mode 100644
index 0000000..c4d5163
--- /dev/null
+++ b/test/unit/pixi/core/Point.js
@@ -0,0 +1,15 @@
+describe('pixi/core/Point', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Point = PIXI.Point;
+
+ it('Module exists', function () {
+ expect(Point).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Point();
+ pixi_core_Point_confirm(obj, 0, 0);
+ });
+});
diff --git a/test/unit/pixi/core/Polygon.js b/test/unit/pixi/core/Polygon.js
new file mode 100644
index 0000000..dc8c918
--- /dev/null
+++ b/test/unit/pixi/core/Polygon.js
@@ -0,0 +1,20 @@
+describe('pixi/core/Polygon', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Polygon = PIXI.Polygon;
+
+ it('Module exists', function () {
+ expect(Polygon).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Polygon();
+
+ expect(obj).to.be.an.instanceof(Polygon);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.deep.property('points.length', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Rectangle.js b/test/unit/pixi/core/Rectangle.js
new file mode 100644
index 0000000..d43316e
--- /dev/null
+++ b/test/unit/pixi/core/Rectangle.js
@@ -0,0 +1,15 @@
+describe('pixi/core/Rectangle', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Rectangle = PIXI.Rectangle;
+
+ it('Module exists', function () {
+ expect(Rectangle).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var rect = new Rectangle();
+ pixi_core_Rectangle_confirm(rect, 0, 0, 0, 0);
+ });
+});
diff --git a/test/unit/pixi/display/DisplayObject.js b/test/unit/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..40c6fbc
--- /dev/null
+++ b/test/unit/pixi/display/DisplayObject.js
@@ -0,0 +1,21 @@
+describe('pixi/display/DisplayObject', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var DisplayObject = PIXI.DisplayObject;
+
+ it('Module exists', function () {
+ expect(DisplayObject).to.be.a('function');
+ expect(PIXI).to.have.property('visibleCount', 0);
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new DisplayObject();
+
+ pixi_display_DisplayObject_confirmNew(obj);
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', false);
+ expect(obj).to.have.property('stage', null);
+ });
+});
diff --git a/test/unit/pixi/display/DisplayObjectContainer.js b/test/unit/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..ce7f02f
--- /dev/null
+++ b/test/unit/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,20 @@
+describe('pixi/display/DisplayObjectContainer', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var DisplayObjectContainer = PIXI.DisplayObjectContainer;
+
+ it('Module exists', function () {
+ expect(DisplayObjectContainer).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new DisplayObjectContainer();
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', false);
+ expect(obj).to.have.property('stage', null);
+ });
+});
diff --git a/test/unit/pixi/display/MovieClip.js b/test/unit/pixi/display/MovieClip.js
new file mode 100644
index 0000000..f3c6c6a
--- /dev/null
+++ b/test/unit/pixi/display/MovieClip.js
@@ -0,0 +1,33 @@
+describe('pixi/display/MovieClip', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var MovieClip = PIXI.MovieClip;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(MovieClip).to.be.a('function');
+ });
+
+ it('Confirm new instance', function (done) {
+ var texture = Texture.fromImage('/base/test/textures/SpriteSheet-Explosion.png');
+ var obj = new MovieClip([texture]);
+
+ pixi_display_Sprite_confirmNew(obj, done);
+
+ expect(obj).to.be.an.instanceof(MovieClip);
+ expect(obj).to.respondTo('stop');
+ expect(obj).to.respondTo('play');
+ expect(obj).to.respondTo('gotoAndStop');
+ expect(obj).to.respondTo('gotoAndPlay');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('textures.length', 1);
+ expect(obj).to.have.deep.property('textures[0]', texture);
+ expect(obj).to.have.property('animationSpeed', 1);
+ expect(obj).to.have.property('loop', true);
+ expect(obj).to.have.property('onComplete', null);
+ expect(obj).to.have.property('currentFrame', 0);
+ expect(obj).to.have.property('playing', false);
+ });
+});
diff --git a/test/unit/pixi/display/Sprite.js b/test/unit/pixi/display/Sprite.js
new file mode 100644
index 0000000..54e914f
--- /dev/null
+++ b/test/unit/pixi/display/Sprite.js
@@ -0,0 +1,25 @@
+describe('pixi/display/Sprite', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Sprite = PIXI.Sprite;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(Sprite).to.be.a('function');
+ expect(PIXI).to.have.deep.property('blendModes.NORMAL', 0);
+ expect(PIXI).to.have.deep.property('blendModes.SCREEN', 1);
+ });
+
+ it('Members exist', function () {
+ expect(Sprite).itself.to.respondTo('fromImage');
+ expect(Sprite).itself.to.respondTo('fromFrame');
+ });
+
+ it('Confirm new instance', function (done) {
+ var texture = Texture.fromImage('/base/test/textures/SpriteSheet-Aliens.png');
+ var obj = new Sprite(texture);
+
+ pixi_display_Sprite_confirmNew(obj, done);
+ });
+});
diff --git a/test/unit/pixi/display/Stage.js b/test/unit/pixi/display/Stage.js
new file mode 100644
index 0000000..3cc2a4d
--- /dev/null
+++ b/test/unit/pixi/display/Stage.js
@@ -0,0 +1,49 @@
+describe('pixi/display/Stage', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Stage = PIXI.Stage;
+ var InteractionManager = PIXI.InteractionManager;
+ var Rectangle = PIXI.Rectangle;
+
+ it('Module exists', function () {
+ expect(Stage).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Stage(null, true);
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(Stage);
+ expect(obj).to.respondTo('updateTransform');
+ expect(obj).to.respondTo('setBackgroundColor');
+ expect(obj).to.respondTo('getMousePosition');
+
+ // FIXME: duplicate member in DisplayObject
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ // FIXME: convert arg to bool in constructor
+ expect(obj).to.have.property('interactive', true);
+
+ expect(obj).to.have.property('interactionManager')
+ .and.to.be.an.instanceof(InteractionManager)
+ .and.to.have.property('stage', obj);
+
+ expect(obj).to.have.property('dirty', true);
+
+ expect(obj).to.have.property('stage', obj);
+
+ expect(obj).to.have.property('hitArea')
+ .and.to.be.an.instanceof(Rectangle);
+ pixi_core_Rectangle_confirm(obj.hitArea, 0, 0, 100000, 100000);
+
+ expect(obj).to.have.property('backgroundColor', 0x000000);
+ expect(obj).to.have.deep.property('backgroundColorSplit.length', 3);
+ expect(obj).to.have.deep.property('backgroundColorSplit[0]', 0);
+ expect(obj).to.have.deep.property('backgroundColorSplit[1]', 0);
+ expect(obj).to.have.deep.property('backgroundColorSplit[2]', 0);
+ expect(obj).to.have.property('backgroundColorString', '#000000');
+
+ expect(obj).to.have.property('worldVisible', true);
+ });
+});
diff --git a/test/unit/pixi/extras/CustomRenderable.js b/test/unit/pixi/extras/CustomRenderable.js
new file mode 100644
index 0000000..8d83cf0
--- /dev/null
+++ b/test/unit/pixi/extras/CustomRenderable.js
@@ -0,0 +1,21 @@
+describe('pixi/extras/CustomRenderable', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var CustomRenderable = PIXI.CustomRenderable;
+
+ it('Module exists', function () {
+ expect(CustomRenderable).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new CustomRenderable();
+
+ pixi_display_DisplayObject_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(CustomRenderable);
+ expect(obj).to.respondTo('renderCanvas');
+ expect(obj).to.respondTo('initWebGL');
+ expect(obj).to.respondTo('renderWebGL');
+ });
+});
diff --git a/test/unit/pixi/extras/Rope.js b/test/unit/pixi/extras/Rope.js
new file mode 100644
index 0000000..6ddaf83
--- /dev/null
+++ b/test/unit/pixi/extras/Rope.js
@@ -0,0 +1,26 @@
+describe('pixi/extras/Rope', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Rope = PIXI.Rope;
+ var Texture = PIXI.Texture;
+ var Point = PIXI.Point;
+
+ it('Module exists', function () {
+ expect(Rope).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var texture = Texture.fromImage('/base/test/textures/bunny.png');
+ var obj = new Rope(texture, [new Point(), new Point(5, 10), new Point(10, 20)]);
+
+ pixi_extras_Strip_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(Rope);
+ expect(obj).to.respondTo('refresh');
+ expect(obj).to.respondTo('updateTransform');
+ expect(obj).to.respondTo('setTexture');
+
+ // TODO: Test properties
+ });
+});
diff --git a/test/unit/pixi/extras/Spine.js b/test/unit/pixi/extras/Spine.js
new file mode 100644
index 0000000..0708bc0
--- /dev/null
+++ b/test/unit/pixi/extras/Spine.js
@@ -0,0 +1,10 @@
+describe('pixi/extras/Spine', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Spine = PIXI.Spine;
+
+ it('Module exists', function () {
+ expect(Spine).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/extras/Strip.js b/test/unit/pixi/extras/Strip.js
new file mode 100644
index 0000000..8e564e1
--- /dev/null
+++ b/test/unit/pixi/extras/Strip.js
@@ -0,0 +1,18 @@
+describe('pixi/extras/Strip', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Strip = PIXI.Strip;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(Strip).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var texture = Texture.fromImage('/base/test/textures/bunny.png');
+ var obj = new Strip(texture, 20, 10000);
+
+ pixi_extras_Strip_confirmNew(obj);
+ });
+});
diff --git a/test/unit/pixi/extras/TilingSprite.js b/test/unit/pixi/extras/TilingSprite.js
new file mode 100644
index 0000000..56aea14
--- /dev/null
+++ b/test/unit/pixi/extras/TilingSprite.js
@@ -0,0 +1,24 @@
+describe('pixi/extras/TilingSprite', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var TilingSprite = PIXI.TilingSprite;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(TilingSprite).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var texture = Texture.fromImage('/base/test/textures/bunny.png');
+ var obj = new TilingSprite(texture, 6000, 12000);
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(TilingSprite);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ // TODO: Test properties
+ });
+});
diff --git a/test/unit/pixi/filters/FilterBlock.js b/test/unit/pixi/filters/FilterBlock.js
new file mode 100644
index 0000000..870cec0
--- /dev/null
+++ b/test/unit/pixi/filters/FilterBlock.js
@@ -0,0 +1,10 @@
+describe('pixi/filters/FilterBlock', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var FilterBlock = PIXI.FilterBlock;
+
+ it('Module exists', function () {
+ expect(FilterBlock).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/filters/MaskFilter.js b/test/unit/pixi/filters/MaskFilter.js
new file mode 100644
index 0000000..32d6a45
--- /dev/null
+++ b/test/unit/pixi/filters/MaskFilter.js
@@ -0,0 +1,10 @@
+describe('pixi/filters/MaskFilter', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ // var MaskFilter = PIXI.MaskFilter;
+
+ // it('Module exists', function () {
+ // expect(MaskFilter).to.be.a('function');
+ // });
+});
diff --git a/test/unit/pixi/loaders/AssetLoader.js b/test/unit/pixi/loaders/AssetLoader.js
new file mode 100644
index 0000000..a0aa0b5
--- /dev/null
+++ b/test/unit/pixi/loaders/AssetLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/AssetLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var AssetLoader = PIXI.AssetLoader;
+
+ it('Module exists', function () {
+ expect(AssetLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/BitmapFontLoader.js b/test/unit/pixi/loaders/BitmapFontLoader.js
new file mode 100644
index 0000000..6253c42
--- /dev/null
+++ b/test/unit/pixi/loaders/BitmapFontLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/BitmapFontLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var BitmapFontLoader = PIXI.BitmapFontLoader;
+
+ it('Module exists', function () {
+ expect(PIXI.BitmapFontLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/ImageLoader.js b/test/unit/pixi/loaders/ImageLoader.js
new file mode 100644
index 0000000..8b1f556
--- /dev/null
+++ b/test/unit/pixi/loaders/ImageLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/ImageLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var ImageLoader = PIXI.ImageLoader;
+
+ it('Module exists', function () {
+ expect(ImageLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/JsonLoader.js b/test/unit/pixi/loaders/JsonLoader.js
new file mode 100644
index 0000000..c577e83
--- /dev/null
+++ b/test/unit/pixi/loaders/JsonLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/JsonLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var JsonLoader = PIXI.JsonLoader;
+
+ it('Module exists', function () {
+ expect(JsonLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/SpineLoader.js b/test/unit/pixi/loaders/SpineLoader.js
new file mode 100644
index 0000000..fdcc0b8
--- /dev/null
+++ b/test/unit/pixi/loaders/SpineLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/SpineLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var SpineLoader = PIXI.SpineLoader;
+
+ it('Module exists', function () {
+ expect(SpineLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/SpriteSheetLoader.js b/test/unit/pixi/loaders/SpriteSheetLoader.js
new file mode 100644
index 0000000..57beb27
--- /dev/null
+++ b/test/unit/pixi/loaders/SpriteSheetLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/SpriteSheetLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var SpriteSheetLoader = PIXI.SpriteSheetLoader;
+
+ it('Module exists', function () {
+ expect(SpriteSheetLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/primitives/Graphics.js b/test/unit/pixi/primitives/Graphics.js
new file mode 100644
index 0000000..b8b3e5c
--- /dev/null
+++ b/test/unit/pixi/primitives/Graphics.js
@@ -0,0 +1,40 @@
+describe('pixi/primitives/Graphics', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Graphics = PIXI.Graphics;
+
+ it('Module exists', function () {
+ expect(Graphics).to.be.a('function');
+
+ expect(Graphics).itself.to.have.property('POLY', 0);
+ expect(Graphics).itself.to.have.property('RECT', 1);
+ expect(Graphics).itself.to.have.property('CIRC', 2);
+ expect(Graphics).itself.to.have.property('ELIP', 3);
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Graphics();
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(Graphics);
+ expect(obj).to.respondTo('lineStyle');
+ expect(obj).to.respondTo('lineStyle');
+ expect(obj).to.respondTo('moveTo');
+ expect(obj).to.respondTo('lineTo');
+ expect(obj).to.respondTo('beginFill');
+ expect(obj).to.respondTo('endFill');
+ expect(obj).to.respondTo('drawRect');
+ expect(obj).to.respondTo('drawCircle');
+ expect(obj).to.respondTo('drawElipse');
+ expect(obj).to.respondTo('clear');
+
+ expect(obj).to.have.property('renderable', true);
+ expect(obj).to.have.property('fillAlpha', 1);
+ expect(obj).to.have.property('lineWidth', 0);
+ expect(obj).to.have.property('lineColor', 'black');
+ expect(obj).to.have.deep.property('graphicsData.length', 0);
+ expect(obj).to.have.deep.property('currentPath.points.length', 0);
+ });
+});
diff --git a/test/unit/pixi/renderers/canvas/CanvasGraphics.js b/test/unit/pixi/renderers/canvas/CanvasGraphics.js
new file mode 100644
index 0000000..8f44472
--- /dev/null
+++ b/test/unit/pixi/renderers/canvas/CanvasGraphics.js
@@ -0,0 +1,15 @@
+describe('renders/canvas/CanvasGraphics', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var CanvasGraphics = PIXI.CanvasGraphics;
+
+ it('Module exists', function () {
+ expect(CanvasGraphics).to.be.a('function');
+ });
+
+ it('Members exist', function () {
+ expect(CanvasGraphics).itself.to.respondTo('renderGraphics');
+ expect(CanvasGraphics).itself.to.respondTo('renderGraphicsMask');
+ });
+});
diff --git a/test/unit/pixi/renderers/canvas/CanvasRenderer.js b/test/unit/pixi/renderers/canvas/CanvasRenderer.js
new file mode 100644
index 0000000..df3a12f
--- /dev/null
+++ b/test/unit/pixi/renderers/canvas/CanvasRenderer.js
@@ -0,0 +1,10 @@
+describe('renderers/canvas/CanvasRenderer', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var CanvasRenderer = PIXI.CanvasRenderer;
+
+ it('Module exists', function () {
+ expect(CanvasRenderer).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/renderers/webgl/WebGLBatch.js b/test/unit/pixi/renderers/webgl/WebGLBatch.js
new file mode 100644
index 0000000..75efd56
--- /dev/null
+++ b/test/unit/pixi/renderers/webgl/WebGLBatch.js
@@ -0,0 +1,10 @@
+describe('renderers/webgl/WebGLBatch', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var WebGLBatch = PIXI.WebGLBatch;
+
+ it('Module exists', function () {
+ expect(WebGLBatch).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/renderers/webgl/WebGLGraphics.js b/test/unit/pixi/renderers/webgl/WebGLGraphics.js
new file mode 100644
index 0000000..41bf941
--- /dev/null
+++ b/test/unit/pixi/renderers/webgl/WebGLGraphics.js
@@ -0,0 +1,19 @@
+describe('renderers/wegbl/WebGLGraphics', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var WebGLGraphics = PIXI.WebGLGraphics;
+
+ it('Module exists', function () {
+ expect(WebGLGraphics).to.be.a('function');
+ });
+
+ it('Members exist', function () {
+ expect(WebGLGraphics).itself.to.respondTo('renderGraphics');
+ expect(WebGLGraphics).itself.to.respondTo('updateGraphics');
+ expect(WebGLGraphics).itself.to.respondTo('buildRectangle');
+ expect(WebGLGraphics).itself.to.respondTo('buildCircle');
+ expect(WebGLGraphics).itself.to.respondTo('buildLine');
+ expect(WebGLGraphics).itself.to.respondTo('buildPoly');
+ });
+});
diff --git a/test/unit/pixi/renderers/webgl/WebGLRenderGroup.js b/test/unit/pixi/renderers/webgl/WebGLRenderGroup.js
new file mode 100644
index 0000000..f4ee366
--- /dev/null
+++ b/test/unit/pixi/renderers/webgl/WebGLRenderGroup.js
@@ -0,0 +1,10 @@
+describe('renderers/webgl/WebGLRenderGroup', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var WebGLRenderGroup = PIXI.WebGLRenderGroup;
+
+ it('Module exists', function () {
+ expect(WebGLRenderGroup).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/renderers/webgl/WebGLRenderer.js b/test/unit/pixi/renderers/webgl/WebGLRenderer.js
new file mode 100644
index 0000000..86533eb
--- /dev/null
+++ b/test/unit/pixi/renderers/webgl/WebGLRenderer.js
@@ -0,0 +1,10 @@
+describe('renderers/webgl/WebGLRenderer', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var WebGLRenderer = PIXI.WebGLRenderer;
+
+ it('Module exists', function () {
+ expect(WebGLRenderer).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/renderers/webgl/WebGLShaders.js b/test/unit/pixi/renderers/webgl/WebGLShaders.js
new file mode 100644
index 0000000..2872de8
--- /dev/null
+++ b/test/unit/pixi/renderers/webgl/WebGLShaders.js
@@ -0,0 +1,13 @@
+describe('renderers/webgl/WebGLShaders', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+
+ it('Module members exist', function () {
+ expect(PIXI).to.respondTo('initPrimitiveShader');
+ expect(PIXI).to.respondTo('initDefaultShader');
+ expect(PIXI).to.respondTo('initDefaultStripShader');
+ expect(PIXI).to.respondTo('activateDefaultShader');
+ expect(PIXI).to.respondTo('activatePrimitiveShader');
+ });
+});
diff --git a/test/unit/pixi/text/BitmapText.js b/test/unit/pixi/text/BitmapText.js
new file mode 100644
index 0000000..9388e3d
--- /dev/null
+++ b/test/unit/pixi/text/BitmapText.js
@@ -0,0 +1,10 @@
+describe('pixi/text/BitmapText', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var BitmapText = PIXI.BitmapText;
+
+ it('Module exists', function () {
+ expect(BitmapText).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/text/Text.js b/test/unit/pixi/text/Text.js
new file mode 100644
index 0000000..9bc9ac5
--- /dev/null
+++ b/test/unit/pixi/text/Text.js
@@ -0,0 +1,10 @@
+describe('pixi/text/Text', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Text = PIXI.Text;
+
+ it('Module exists', function () {
+ expect(Text).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/textures/BaseTexture.js b/test/unit/pixi/textures/BaseTexture.js
new file mode 100644
index 0000000..e34b64c
--- /dev/null
+++ b/test/unit/pixi/textures/BaseTexture.js
@@ -0,0 +1,13 @@
+describe('pixi/textures/BaseTexture', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var BaseTexture = PIXI.BaseTexture;
+
+ it('Module exists', function () {
+ expect(BaseTexture).to.be.a('function');
+ expect(PIXI).to.have.property('BaseTextureCache').and.to.be.an('object');
+ expect(PIXI).to.have.deep.property('texturesToUpdate.length');
+ expect(PIXI).to.have.deep.property('texturesToDestroy.length', 0);
+ });
+});
diff --git a/test/unit/pixi/textures/RenderTexture.js b/test/unit/pixi/textures/RenderTexture.js
new file mode 100644
index 0000000..4a69b44
--- /dev/null
+++ b/test/unit/pixi/textures/RenderTexture.js
@@ -0,0 +1,10 @@
+describe('pixi/textures/RenderTexture', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var RenderTexture = PIXI.RenderTexture;
+
+ it('Module exists', function () {
+ expect(RenderTexture).to.be.a('function');
+ });
+});
diff --git a/.gitignore b/.gitignore
index 12e1b62..0b88317 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
node_modules
.DS_Store
-.project
\ No newline at end of file
+.project
+*.log
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..63e4d7c
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,8 @@
+language: node_js
+node_js:
+ - 0.10
+
+before_script:
+ - npm install -g grunt-cli
+ - export DISPLAY=:99.0
+ - sh -e /etc/init.d/xvfb start
diff --git a/Gruntfile.js b/Gruntfile.js
index b083b49..103938c 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -1,10 +1,12 @@
+'use strict';
+
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-connect');
- grunt.loadNpmTasks('grunt-contrib-qunit');
grunt.loadNpmTasks('grunt-contrib-yuidoc');
+ grunt.loadTasks('tasks');
var root = 'src/pixi/',
debug = 'bin/pixi.dev.js',
@@ -79,7 +81,7 @@
},
files: {
srcBlob: '<%= dirs.src %>/**/*.js',
- testBlob: '<%= dirs.test %>/unit/**/*.js',
+ testBlob: '<%= dirs.test %>/{functional,lib/pixi,unit}/**/*.js',
build: '<%= dirs.build %>/pixi.dev.js',
buildMin: '<%= dirs.build %>/pixi.js'
},
@@ -94,7 +96,12 @@
},
jshint: {
beforeconcat: srcFiles,
- test: ['<%= files.testBlob %>'],
+ test: {
+ src: ['<%= files.testBlob %>'],
+ options: {
+ expr: true
+ }
+ },
options: {
asi: true,
smarttabs: true
@@ -128,12 +135,6 @@
]
},
connect: {
- qunit: {
- options: {
- port: grunt.option('port-test') || 9002,
- base: './'
- }
- },
test: {
options: {
port: grunt.option('port-test') || 9002,
@@ -142,13 +143,6 @@
}
}
},
- qunit: {
- all: {
- options: {
- urls: ['http://localhost:' + (grunt.option('port-test') || 9002) + '/test/index.html']
- }
- }
- },
yuidoc: {
compile: {
name: '<%= pkg.name %>',
@@ -161,6 +155,13 @@
outdir: '<%= dirs.docs %>'
}
}
+ },
+ karma: {
+ unit: {
+ configFile: 'test/karma.conf.js',
+ // browsers: ['Chrome'],
+ singleRun: true
+ }
}
});
@@ -182,9 +183,10 @@
}
)
- grunt.registerTask('default', ['concat', 'uglify', 'distribute']);
grunt.registerTask('build', ['concat', 'uglify', 'distribute']);
- grunt.registerTask('test', ['build', 'connect:qunit', 'qunit']);
+ grunt.registerTask('test', ['concat', 'jshint:test', 'karma']);
grunt.registerTask('docs', ['yuidoc']);
-
-}
\ No newline at end of file
+ grunt.registerTask('default', ['test', 'uglify', 'distribute']);
+ // Travis CI task.
+ grunt.registerTask('travis', ['test']);
+}
diff --git a/README.md b/README.md
index c62ef86..690cfe4 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,8 @@

+[](http://travis-ci.org/drkibitz/pixi.js)
+
#### JavaScript 2D Renderer ####
The aim of this project is to provide a fast lightweight 2D library that works
diff --git a/package.json b/package.json
index b373240..1246a68 100644
--- a/package.json
+++ b/package.json
@@ -18,14 +18,21 @@
"main": "bin/pixi.js",
+ "scripts": {
+ "test": "grunt travis --verbose"
+ },
+
"dependencies": {},
"devDependencies": {
"grunt": "~0.4.x",
- "grunt-contrib-jshint": "0.3.x",
+ "grunt-contrib-jshint": "0.6.x",
"grunt-contrib-uglify": "0.2.x",
- "grunt-contrib-connect": "0.2.x",
- "grunt-contrib-qunit": "0.2.x",
+ "grunt-contrib-connect": "0.3.x",
"grunt-contrib-yuidoc": "0.4.x",
- "grunt-contrib-concat": "0.1.x"
+ "grunt-contrib-concat": "0.3.x",
+ "chai": "~1.7.0",
+ "karma": "0.11.0",
+ "karma-firefox-launcher": "0.1.0",
+ "karma-mocha": "0.1.0"
}
}
diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js
index a7c520e..ee82bbd 100644
--- a/src/pixi/InteractionManager.js
+++ b/src/pixi/InteractionManager.js
@@ -62,7 +62,6 @@
this.onTouchEnd = this.onTouchEnd.bind(this);
this.onTouchMove = this.onTouchMove.bind(this);
-
this.last = 0;
}
diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js
index 1a95d20..eef1059 100644
--- a/src/pixi/core/Ellipse.js
+++ b/src/pixi/core/Ellipse.js
@@ -78,7 +78,7 @@
return (normx + normy < 0.25);
}
-PIXI.Ellipse.getBounds = function()
+PIXI.Ellipse.prototype.getBounds = function()
{
return new PIXI.Rectangle(this.x, this.y, this.width, this.height);
}
diff --git a/tasks/karma.js b/tasks/karma.js
new file mode 100644
index 0000000..c340485
--- /dev/null
+++ b/tasks/karma.js
@@ -0,0 +1,27 @@
+'use strict';
+
+var path = require('path');
+var server = require('karma').server;
+
+module.exports = function (grunt) {
+ grunt.registerMultiTask('karma', 'run karma.', function() {
+ var done = this.async();
+ var options = this.options({
+ background: false
+ });
+ var data = this.data;
+
+ //merge options onto data, with data taking precedence
+ data = grunt.util._.merge(options, data);
+ data.configFile = path.resolve(data.configFile);
+ if (data.configFile) {
+ data.configFile = grunt.template.process(data.configFile);
+ }
+
+ server.start(
+ data,
+ function(code) {
+ done(!code);
+ });
+ });
+};
diff --git a/test/functional/example-1-basics/bunny.png b/test/functional/example-1-basics/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/functional/example-1-basics/bunny.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-30.png b/test/functional/example-1-basics/frame-30.png
new file mode 100644
index 0000000..96e3409
--- /dev/null
+++ b/test/functional/example-1-basics/frame-30.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-60.png b/test/functional/example-1-basics/frame-60.png
new file mode 100644
index 0000000..af3f4ce
--- /dev/null
+++ b/test/functional/example-1-basics/frame-60.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-90.png b/test/functional/example-1-basics/frame-90.png
new file mode 100644
index 0000000..099b823
--- /dev/null
+++ b/test/functional/example-1-basics/frame-90.png
Binary files differ
diff --git a/test/functional/example-1-basics/index.js b/test/functional/example-1-basics/index.js
new file mode 100644
index 0000000..7ae7a98
--- /dev/null
+++ b/test/functional/example-1-basics/index.js
@@ -0,0 +1,133 @@
+describe('Example 1 - Basics', function () {
+ 'use strict';
+
+ var baseUri = '/base/test/functional/example-1-basics';
+ var expect = chai.expect;
+ var currentFrame = 0;
+ var frameEvents = {};
+ var stage;
+ var renderer;
+ var bunny;
+
+ function onFrame(frame, callback) {
+ frameEvents[frame] = callback;
+ }
+
+ function animate() {
+ currentFrame += 1;
+
+ requestAnimFrame( animate );
+
+ // just for fun, lets rotate mr rabbit a little
+ bunny.rotation += 0.1;
+
+ // render the stage
+ renderer.render(stage);
+
+ if (frameEvents[currentFrame])
+ frameEvents[currentFrame](currentFrame);
+ }
+
+ function initScene() {
+ // create an new instance of a pixi stage
+ stage = new PIXI.Stage(0x66FF99);
+
+ // create a renderer instance
+ renderer = PIXI.autoDetectRenderer(400, 300);
+ console.log('Is PIXI.WebGLRenderer: ' + (renderer instanceof PIXI.WebGLRenderer));
+
+ // add the renderer view element to the DOM
+ document.body.appendChild(renderer.view);
+
+ requestAnimFrame( animate );
+
+ // create a texture from an image path
+ var texture = PIXI.Texture.fromImage(baseUri + "/bunny.png");
+ // create a new Sprite using the texture
+ bunny = new PIXI.Sprite(texture);
+
+ // center the sprites anchor point
+ bunny.anchor.x = 0.5;
+ bunny.anchor.y = 0.5;
+
+ // move the sprite t the center of the screen
+ bunny.position.x = 200;
+ bunny.position.y = 150;
+
+ stage.addChild(bunny);
+ }
+
+ it('assets loaded', function (done) {
+ var loader = new PIXI.AssetLoader([
+ baseUri + '/bunny.png',
+ baseUri + '/frame-30.png',
+ baseUri + '/frame-60.png',
+ baseUri + '/frame-90.png'
+ ]);
+ // loader.on('onProgress', function (event) {
+ // console.log(event.content);
+ // });
+ loader.on('onComplete', function (event) {
+ done();
+ initScene();
+ });
+ loader.load();
+ });
+
+ it('frame 30 should match', function (done) {
+ this.timeout(700);
+ onFrame(30, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-30.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 60 should match', function (done) {
+ this.timeout(1200);
+ onFrame(60, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-60.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 90 should match', function (done) {
+ this.timeout(1700);
+ onFrame(90, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-90.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ // it('capture something', function (done) {
+ // this.timeout(2000000);
+ // onFrame(30, function () {
+ // var img = new Image();
+ // img.src = renderer.view.toDataURL('image/png');
+ // document.body.appendChild(img);
+ // });
+ // });
+});
diff --git a/test/index.html b/test/index.html
deleted file mode 100644
index 9cbcac5..0000000
--- a/test/index.html
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
- Pixi.js Test Suite
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/test/karma.conf.js b/test/karma.conf.js
new file mode 100644
index 0000000..c66a696
--- /dev/null
+++ b/test/karma.conf.js
@@ -0,0 +1,82 @@
+module.exports = function(config) {
+ config.set({
+
+ // base path, that will be used to resolve files and exclude
+ basePath : '../',
+
+ frameworks : ['mocha'],
+
+ // list of files / patterns to load in the browser
+ files : [
+ 'node_modules/chai/chai.js',
+ 'bin/pixi.dev.js',
+ 'test/lib/**/*.js',
+ 'test/unit/**/*.js',
+ // 'test/functional/**/*.js',
+ {pattern: 'test/**/*.png', watched: false, included: false, served: true}
+ ],
+
+ // list of files to exclude
+ exclude : [],
+
+ // use dolts reporter, as travis terminal does not support escaping sequences
+ // possible values: 'dots', 'progress', 'junit', 'teamcity'
+ // CLI --reporters progress
+ reporters : ['progress'],
+
+ // web server port
+ // CLI --port 9876
+ port : 9876,
+
+ // cli runner port
+ // CLI --runner-port 9100
+ runnerPort : 9100,
+
+ // enable / disable colors in the output (reporters and logs)
+ // CLI --colors --no-colors
+ colors : true,
+
+ // level of logging
+ // possible values: karma.LOG_DISABLE || karma.LOG_ERROR || karma.LOG_WARN || karma.LOG_INFO || karma.LOG_DEBUG
+ // CLI --log-level debug
+ logLevel : config.LOG_DEBUG,
+
+ // enable / disable watching file and executing tests whenever any file changes
+ // CLI --auto-watch --no-auto-watch
+ autoWatch : false,
+
+ // Start these browsers, currently available:
+ // - Chrome
+ // - ChromeCanary
+ // - Firefox
+ // - Opera
+ // - Safari (only Mac)
+ // - PhantomJS
+ // - IE (only Windows)
+ // CLI --browsers Chrome,Firefox,Safari
+ browsers : ['Firefox'],
+
+ // If browser does not capture in given timeout [ms], kill it
+ // CLI --capture-timeout 5000
+ captureTimeout : 5000,
+
+ // Auto run tests on start (when browsers are captured) and exit
+ // CLI --single-run --no-single-run
+ singleRun : true,
+
+ // report which specs are slower than 500ms
+ // CLI --report-slower-than 500
+ reportSlowerThan : 1000,
+
+ preprocessors : {
+ // '**/client/js/*.js': 'coverage'
+ },
+
+ plugins : [
+ 'karma-mocha',
+ // 'karma-chrome-launcher',
+ 'karma-firefox-launcher',
+ // 'karma-phantomjs-launcher'
+ ]
+ });
+};
diff --git a/test/lib/pixi/core/Matrix.js b/test/lib/pixi/core/Matrix.js
new file mode 100644
index 0000000..d26386b
--- /dev/null
+++ b/test/lib/pixi/core/Matrix.js
@@ -0,0 +1,40 @@
+
+function pixi_core_Matrix_confirmNewMat3(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(1);
+ expect(matrix[5]).to.equal(0);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(1);
+}
+
+function pixi_core_Matrix_confirmNewMat4(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[0]).to.equal(1);
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(0);
+ expect(matrix[5]).to.equal(1);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(0);
+ expect(matrix[9]).to.equal(0);
+ expect(matrix[10]).to.equal(1);
+ expect(matrix[11]).to.equal(0);
+ expect(matrix[12]).to.equal(0);
+ expect(matrix[13]).to.equal(0);
+ expect(matrix[14]).to.equal(0);
+ expect(matrix[15]).to.equal(1);
+}
diff --git a/test/lib/pixi/core/Point.js b/test/lib/pixi/core/Point.js
new file mode 100644
index 0000000..e5df07b
--- /dev/null
+++ b/test/lib/pixi/core/Point.js
@@ -0,0 +1,10 @@
+
+function pixi_core_Point_confirm(obj, x, y) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Point);
+ expect(obj).to.respondTo('clone');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+}
diff --git a/test/lib/pixi/core/Rectangle.js b/test/lib/pixi/core/Rectangle.js
new file mode 100644
index 0000000..23f0d12
--- /dev/null
+++ b/test/lib/pixi/core/Rectangle.js
@@ -0,0 +1,13 @@
+
+function pixi_core_Rectangle_confirm(obj, x, y, width, height) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Rectangle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+ expect(obj).to.have.property('width', width);
+ expect(obj).to.have.property('height', height);
+}
diff --git a/test/lib/pixi/display/DisplayObject.js b/test/lib/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..1388a7f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObject.js
@@ -0,0 +1,43 @@
+
+function pixi_display_DisplayObject_confirmNew(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObject);
+ expect(obj).to.respondTo('setInteractive');
+ expect(obj).to.respondTo('addFilter');
+ expect(obj).to.respondTo('removeFilter');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.property('last', obj);
+ expect(obj).to.have.property('first', obj);
+
+ expect(obj).to.contain.property('position');
+ pixi_core_Point_confirm(obj.position, 0, 0);
+ expect(obj).to.contain.property('scale');
+ pixi_core_Point_confirm(obj.scale, 1, 1);
+ expect(obj).to.contain.property('pivot');
+ pixi_core_Point_confirm(obj.pivot, 0, 0);
+
+ expect(obj).to.have.property('rotation', 0);
+ expect(obj).to.have.property('alpha', 1);
+ expect(obj).to.have.property('visible', true);
+ expect(obj).to.have.property('buttonMode', false);
+ expect(obj).to.have.property('parent', null);
+ expect(obj).to.have.property('worldAlpha', 1);
+
+ expect(obj).to.have.property('hitArea');
+ expect(obj).to.have.property('interactive'); // TODO: Have a better default value
+ expect('mask' in obj).to.be.true; // TODO: Have a better default value
+ expect(obj.mask).to.be.undefined;
+
+ expect(obj).to.have.property('renderable');
+ expect(obj).to.have.property('stage');
+
+ expect(obj).to.have.deep.property('worldTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ expect(obj).to.have.deep.property('localTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.localTransform);
+
+ expect(obj).to.have.deep.property('color.length', 0);
+ expect(obj).to.have.property('dynamic', true);
+}
diff --git a/test/lib/pixi/display/DisplayObjectContainer.js b/test/lib/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..085c59f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,16 @@
+
+function pixi_display_DisplayObjectContainer_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObject_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObjectContainer);
+ expect(obj).to.respondTo('addChild');
+ expect(obj).to.respondTo('addChildAt');
+ expect(obj).to.respondTo('swapChildren');
+ expect(obj).to.respondTo('getChildAt');
+ expect(obj).to.respondTo('removeChild');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('children.length', 0);
+}
diff --git a/test/lib/pixi/display/Sprite.js b/test/lib/pixi/display/Sprite.js
new file mode 100644
index 0000000..cc7a2d6
--- /dev/null
+++ b/test/lib/pixi/display/Sprite.js
@@ -0,0 +1,28 @@
+
+function pixi_display_Sprite_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Sprite);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', true);
+ expect(obj).to.have.property('stage', null);
+
+ expect(obj).to.have.property('anchor');
+ pixi_core_Point_confirm(obj.anchor, 0, 0);
+
+ expect(obj).to.have.property('blendMode', PIXI.blendModes.NORMAL);
+ expect(obj).to.have.property('width', 1); // TODO: is 1 expected
+ expect(obj).to.have.property('height', 1); // TODO: is 1 expected
+
+ // FIXME: Just make this a boolean that is always there
+ expect(!!obj.updateFrame).to.equal(obj.texture.baseTexture.hasLoaded);
+
+ expect(obj).to.have.property('texture');
+ pixi_textures_Texture_confirmNew(obj.texture, done);
+}
diff --git a/test/lib/pixi/extras/Strip.js b/test/lib/pixi/extras/Strip.js
new file mode 100644
index 0000000..8927a8a
--- /dev/null
+++ b/test/lib/pixi/extras/Strip.js
@@ -0,0 +1,12 @@
+
+function pixi_extras_Strip_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Strip);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ // TODO: Test properties
+}
diff --git a/test/lib/pixi/textures/Texture.js b/test/lib/pixi/textures/Texture.js
new file mode 100644
index 0000000..d5867b6
--- /dev/null
+++ b/test/lib/pixi/textures/Texture.js
@@ -0,0 +1,31 @@
+
+function pixi_textures_Texture_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ function confirmFrameDone() {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, obj.baseTexture.width, obj.baseTexture.height);
+
+ expect(obj).to.have.property('width', obj.baseTexture.width);
+ expect(obj).to.have.property('height', obj.baseTexture.height);
+ done();
+ }
+
+ expect(obj).to.be.an.instanceof(PIXI.Texture);
+ pixi_utils_EventTarget_like(obj);
+
+ expect(obj).to.have.property('baseTexture')
+ .and.to.be.an.instanceof(PIXI.BaseTexture);
+
+ expect(obj).to.have.property('scope', obj);
+
+ expect(obj).to.have.property('trim');
+ pixi_core_Point_confirm(obj.trim, 0, 0);
+
+ expect(obj).to.have.property('frame');
+ if (obj.baseTexture.hasLoaded) {
+ confirmFrameDone();
+ } else {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, 1, 1);
+ obj.addEventListener('update', confirmFrameDone);
+ }
+}
diff --git a/test/lib/pixi/utils/EventTarget.js b/test/lib/pixi/utils/EventTarget.js
new file mode 100644
index 0000000..7b1dcfa
--- /dev/null
+++ b/test/lib/pixi/utils/EventTarget.js
@@ -0,0 +1,8 @@
+
+function pixi_utils_EventTarget_like(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.respondTo('addEventListener');
+ expect(obj).to.respondTo('dispatchEvent');
+ expect(obj).to.respondTo('removeEventListener');
+}
diff --git a/test/lib/qunit-1.11.0.css b/test/lib/qunit-1.11.0.css
deleted file mode 100644
index d7fc0c8..0000000
--- a/test/lib/qunit-1.11.0.css
+++ /dev/null
@@ -1,244 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-/** Font Family and Sizes */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
- font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
-}
-
-#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
-#qunit-tests { font-size: smaller; }
-
-
-/** Resets */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter {
- margin: 0;
- padding: 0;
-}
-
-
-/** Header */
-
-#qunit-header {
- padding: 0.5em 0 0.5em 1em;
-
- color: #8699a4;
- background-color: #0d3349;
-
- font-size: 1.5em;
- line-height: 1em;
- font-weight: normal;
-
- border-radius: 5px 5px 0 0;
- -moz-border-radius: 5px 5px 0 0;
- -webkit-border-top-right-radius: 5px;
- -webkit-border-top-left-radius: 5px;
-}
-
-#qunit-header a {
- text-decoration: none;
- color: #c2ccd1;
-}
-
-#qunit-header a:hover,
-#qunit-header a:focus {
- color: #fff;
-}
-
-#qunit-testrunner-toolbar label {
- display: inline-block;
- padding: 0 .5em 0 .1em;
-}
-
-#qunit-banner {
- height: 5px;
-}
-
-#qunit-testrunner-toolbar {
- padding: 0.5em 0 0.5em 2em;
- color: #5E740B;
- background-color: #eee;
- overflow: hidden;
-}
-
-#qunit-userAgent {
- padding: 0.5em 0 0.5em 2.5em;
- background-color: #2b81af;
- color: #fff;
- text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
-}
-
-#qunit-modulefilter-container {
- float: right;
-}
-
-/** Tests: Pass/Fail */
-
-#qunit-tests {
- list-style-position: inside;
-}
-
-#qunit-tests li {
- padding: 0.4em 0.5em 0.4em 2.5em;
- border-bottom: 1px solid #fff;
- list-style-position: inside;
-}
-
-#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running {
- display: none;
-}
-
-#qunit-tests li strong {
- cursor: pointer;
-}
-
-#qunit-tests li a {
- padding: 0.5em;
- color: #c2ccd1;
- text-decoration: none;
-}
-#qunit-tests li a:hover,
-#qunit-tests li a:focus {
- color: #000;
-}
-
-#qunit-tests li .runtime {
- float: right;
- font-size: smaller;
-}
-
-.qunit-assert-list {
- margin-top: 0.5em;
- padding: 0.5em;
-
- background-color: #fff;
-
- border-radius: 5px;
- -moz-border-radius: 5px;
- -webkit-border-radius: 5px;
-}
-
-.qunit-collapsed {
- display: none;
-}
-
-#qunit-tests table {
- border-collapse: collapse;
- margin-top: .2em;
-}
-
-#qunit-tests th {
- text-align: right;
- vertical-align: top;
- padding: 0 .5em 0 0;
-}
-
-#qunit-tests td {
- vertical-align: top;
-}
-
-#qunit-tests pre {
- margin: 0;
- white-space: pre-wrap;
- word-wrap: break-word;
-}
-
-#qunit-tests del {
- background-color: #e0f2be;
- color: #374e0c;
- text-decoration: none;
-}
-
-#qunit-tests ins {
- background-color: #ffcaca;
- color: #500;
- text-decoration: none;
-}
-
-/*** Test Counts */
-
-#qunit-tests b.counts { color: black; }
-#qunit-tests b.passed { color: #5E740B; }
-#qunit-tests b.failed { color: #710909; }
-
-#qunit-tests li li {
- padding: 5px;
- background-color: #fff;
- border-bottom: none;
- list-style-position: inside;
-}
-
-/*** Passing Styles */
-
-#qunit-tests li li.pass {
- color: #3c510c;
- background-color: #fff;
- border-left: 10px solid #C6E746;
-}
-
-#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
-#qunit-tests .pass .test-name { color: #366097; }
-
-#qunit-tests .pass .test-actual,
-#qunit-tests .pass .test-expected { color: #999999; }
-
-#qunit-banner.qunit-pass { background-color: #C6E746; }
-
-/*** Failing Styles */
-
-#qunit-tests li li.fail {
- color: #710909;
- background-color: #fff;
- border-left: 10px solid #EE5757;
- white-space: pre;
-}
-
-#qunit-tests > li:last-child {
- border-radius: 0 0 5px 5px;
- -moz-border-radius: 0 0 5px 5px;
- -webkit-border-bottom-right-radius: 5px;
- -webkit-border-bottom-left-radius: 5px;
-}
-
-#qunit-tests .fail { color: #000000; background-color: #EE5757; }
-#qunit-tests .fail .test-name,
-#qunit-tests .fail .module-name { color: #000000; }
-
-#qunit-tests .fail .test-actual { color: #EE5757; }
-#qunit-tests .fail .test-expected { color: green; }
-
-#qunit-banner.qunit-fail { background-color: #EE5757; }
-
-
-/** Result */
-
-#qunit-testresult {
- padding: 0.5em 0.5em 0.5em 2.5em;
-
- color: #2b81af;
- background-color: #D2E0E6;
-
- border-bottom: 1px solid white;
-}
-#qunit-testresult .module-name {
- font-weight: bold;
-}
-
-/** Fixture */
-
-#qunit-fixture {
- position: absolute;
- top: -10000px;
- left: -10000px;
- width: 1000px;
- height: 1000px;
-}
diff --git a/test/lib/qunit-1.11.0.js b/test/lib/qunit-1.11.0.js
deleted file mode 100644
index 302545f..0000000
--- a/test/lib/qunit-1.11.0.js
+++ /dev/null
@@ -1,2152 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-(function( window ) {
-
-var QUnit,
- assert,
- config,
- onErrorFnPrev,
- testId = 0,
- fileName = (sourceFromStacktrace( 0 ) || "" ).replace(/(:\d+)+\)?/, "").replace(/.+\//, ""),
- toString = Object.prototype.toString,
- hasOwn = Object.prototype.hasOwnProperty,
- // Keep a local reference to Date (GH-283)
- Date = window.Date,
- defined = {
- setTimeout: typeof window.setTimeout !== "undefined",
- sessionStorage: (function() {
- var x = "qunit-test-string";
- try {
- sessionStorage.setItem( x, x );
- sessionStorage.removeItem( x );
- return true;
- } catch( e ) {
- return false;
- }
- }())
- },
- /**
- * Provides a normalized error string, correcting an issue
- * with IE 7 (and prior) where Error.prototype.toString is
- * not properly implemented
- *
- * Based on http://es5.github.com/#x15.11.4.4
- *
- * @param {String|Error} error
- * @return {String} error message
- */
- errorString = function( error ) {
- var name, message,
- errorString = error.toString();
- if ( errorString.substring( 0, 7 ) === "[object" ) {
- name = error.name ? error.name.toString() : "Error";
- message = error.message ? error.message.toString() : "";
- if ( name && message ) {
- return name + ": " + message;
- } else if ( name ) {
- return name;
- } else if ( message ) {
- return message;
- } else {
- return "Error";
- }
- } else {
- return errorString;
- }
- },
- /**
- * Makes a clone of an object using only Array or Object as base,
- * and copies over the own enumerable properties.
- *
- * @param {Object} obj
- * @return {Object} New object with only the own properties (recursively).
- */
- objectValues = function( obj ) {
- // Grunt 0.3.x uses an older version of jshint that still has jshint/jshint#392.
- /*jshint newcap: false */
- var key, val,
- vals = QUnit.is( "array", obj ) ? [] : {};
- for ( key in obj ) {
- if ( hasOwn.call( obj, key ) ) {
- val = obj[key];
- vals[key] = val === Object(val) ? objectValues(val) : val;
- }
- }
- return vals;
- };
-
-function Test( settings ) {
- extend( this, settings );
- this.assertions = [];
- this.testNumber = ++Test.count;
-}
-
-Test.count = 0;
-
-Test.prototype = {
- init: function() {
- var a, b, li,
- tests = id( "qunit-tests" );
-
- if ( tests ) {
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml;
-
- // `a` initialized at top of scope
- a = document.createElement( "a" );
- a.innerHTML = "Rerun";
- a.href = QUnit.url({ testNumber: this.testNumber });
-
- li = document.createElement( "li" );
- li.appendChild( b );
- li.appendChild( a );
- li.className = "running";
- li.id = this.id = "qunit-test-output" + testId++;
-
- tests.appendChild( li );
- }
- },
- setup: function() {
- if ( this.module !== config.previousModule ) {
- if ( config.previousModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.previousModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
- config.previousModule = this.module;
- config.moduleStats = { all: 0, bad: 0 };
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- } else if ( config.autorun ) {
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- }
-
- config.current = this;
-
- this.testEnvironment = extend({
- setup: function() {},
- teardown: function() {}
- }, this.moduleTestEnvironment );
-
- this.started = +new Date();
- runLoggingCallbacks( "testStart", QUnit, {
- name: this.testName,
- module: this.module
- });
-
- // allow utility functions to access the current test environment
- // TODO why??
- QUnit.current_testEnvironment = this.testEnvironment;
-
- if ( !config.pollution ) {
- saveGlobal();
- }
- if ( config.notrycatch ) {
- this.testEnvironment.setup.call( this.testEnvironment );
- return;
- }
- try {
- this.testEnvironment.setup.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Setup failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- },
- run: function() {
- config.current = this;
-
- var running = id( "qunit-testresult" );
-
- if ( running ) {
- running.innerHTML = "Running:
" + this.nameHtml;
- }
-
- if ( this.async ) {
- QUnit.stop();
- }
-
- this.callbackStarted = +new Date();
-
- if ( config.notrycatch ) {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- return;
- }
-
- try {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- } catch( e ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
-
- QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + " " + this.stack + ": " + ( e.message || e ), extractStacktrace( e, 0 ) );
- // else next test will carry the responsibility
- saveGlobal();
-
- // Restart the tests if they're blocking
- if ( config.blocking ) {
- QUnit.start();
- }
- }
- },
- teardown: function() {
- config.current = this;
- if ( config.notrycatch ) {
- if ( typeof this.callbackRuntime === "undefined" ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
- }
- this.testEnvironment.teardown.call( this.testEnvironment );
- return;
- } else {
- try {
- this.testEnvironment.teardown.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Teardown failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- }
- checkPollution();
- },
- finish: function() {
- config.current = this;
- if ( config.requireExpects && this.expected === null ) {
- QUnit.pushFailure( "Expected number of assertions to be defined, but expect() was not called.", this.stack );
- } else if ( this.expected !== null && this.expected !== this.assertions.length ) {
- QUnit.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack );
- } else if ( this.expected === null && !this.assertions.length ) {
- QUnit.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions.", this.stack );
- }
-
- var i, assertion, a, b, time, li, ol,
- test = this,
- good = 0,
- bad = 0,
- tests = id( "qunit-tests" );
-
- this.runtime = +new Date() - this.started;
- config.stats.all += this.assertions.length;
- config.moduleStats.all += this.assertions.length;
-
- if ( tests ) {
- ol = document.createElement( "ol" );
- ol.className = "qunit-assert-list";
-
- for ( i = 0; i < this.assertions.length; i++ ) {
- assertion = this.assertions[i];
-
- li = document.createElement( "li" );
- li.className = assertion.result ? "pass" : "fail";
- li.innerHTML = assertion.message || ( assertion.result ? "okay" : "failed" );
- ol.appendChild( li );
-
- if ( assertion.result ) {
- good++;
- } else {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
-
- // store result when possible
- if ( QUnit.config.reorder && defined.sessionStorage ) {
- if ( bad ) {
- sessionStorage.setItem( "qunit-test-" + this.module + "-" + this.testName, bad );
- } else {
- sessionStorage.removeItem( "qunit-test-" + this.module + "-" + this.testName );
- }
- }
-
- if ( bad === 0 ) {
- addClass( ol, "qunit-collapsed" );
- }
-
- // `b` initialized at top of scope
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml + " (" + bad + ", " + good + ", " + this.assertions.length + ")";
-
- addEvent(b, "click", function() {
- var next = b.parentNode.lastChild,
- collapsed = hasClass( next, "qunit-collapsed" );
- ( collapsed ? removeClass : addClass )( next, "qunit-collapsed" );
- });
-
- addEvent(b, "dblclick", function( e ) {
- var target = e && e.target ? e.target : window.event.srcElement;
- if ( target.nodeName.toLowerCase() === "span" || target.nodeName.toLowerCase() === "b" ) {
- target = target.parentNode;
- }
- if ( window.location && target.nodeName.toLowerCase() === "strong" ) {
- window.location = QUnit.url({ testNumber: test.testNumber });
- }
- });
-
- // `time` initialized at top of scope
- time = document.createElement( "span" );
- time.className = "runtime";
- time.innerHTML = this.runtime + " ms";
-
- // `li` initialized at top of scope
- li = id( this.id );
- li.className = bad ? "fail" : "pass";
- li.removeChild( li.firstChild );
- a = li.firstChild;
- li.appendChild( b );
- li.appendChild( a );
- li.appendChild( time );
- li.appendChild( ol );
-
- } else {
- for ( i = 0; i < this.assertions.length; i++ ) {
- if ( !this.assertions[i].result ) {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
- }
-
- runLoggingCallbacks( "testDone", QUnit, {
- name: this.testName,
- module: this.module,
- failed: bad,
- passed: this.assertions.length - bad,
- total: this.assertions.length,
- duration: this.runtime
- });
-
- QUnit.reset();
-
- config.current = undefined;
- },
-
- queue: function() {
- var bad,
- test = this;
-
- synchronize(function() {
- test.init();
- });
- function run() {
- // each of these can by async
- synchronize(function() {
- test.setup();
- });
- synchronize(function() {
- test.run();
- });
- synchronize(function() {
- test.teardown();
- });
- synchronize(function() {
- test.finish();
- });
- }
-
- // `bad` initialized at top of scope
- // defer when previous test run passed, if storage is available
- bad = QUnit.config.reorder && defined.sessionStorage &&
- +sessionStorage.getItem( "qunit-test-" + this.module + "-" + this.testName );
-
- if ( bad ) {
- run();
- } else {
- synchronize( run, true );
- }
- }
-};
-
-// Root QUnit object.
-// `QUnit` initialized at top of scope
-QUnit = {
-
- // call on start of module test to prepend name to all tests
- module: function( name, testEnvironment ) {
- config.currentModule = name;
- config.currentModuleTestEnvironment = testEnvironment;
- config.modules[name] = true;
- },
-
- asyncTest: function( testName, expected, callback ) {
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- QUnit.test( testName, expected, callback, true );
- },
-
- test: function( testName, expected, callback, async ) {
- var test,
- nameHtml = "" + escapeText( testName ) + "";
-
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- if ( config.currentModule ) {
- nameHtml = "" + escapeText( config.currentModule ) + ": " + nameHtml;
- }
-
- test = new Test({
- nameHtml: nameHtml,
- testName: testName,
- expected: expected,
- async: async,
- callback: callback,
- module: config.currentModule,
- moduleTestEnvironment: config.currentModuleTestEnvironment,
- stack: sourceFromStacktrace( 2 )
- });
-
- if ( !validTest( test ) ) {
- return;
- }
-
- test.queue();
- },
-
- // Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through.
- expect: function( asserts ) {
- if (arguments.length === 1) {
- config.current.expected = asserts;
- } else {
- return config.current.expected;
- }
- },
-
- start: function( count ) {
- // QUnit hasn't been initialized yet.
- // Note: RequireJS (et al) may delay onLoad
- if ( config.semaphore === undefined ) {
- QUnit.begin(function() {
- // This is triggered at the top of QUnit.load, push start() to the event loop, to allow QUnit.load to finish first
- setTimeout(function() {
- QUnit.start( count );
- });
- });
- return;
- }
-
- config.semaphore -= count || 1;
- // don't start until equal number of stop-calls
- if ( config.semaphore > 0 ) {
- return;
- }
- // ignore if start is called more often then stop
- if ( config.semaphore < 0 ) {
- config.semaphore = 0;
- QUnit.pushFailure( "Called start() while already started (QUnit.config.semaphore was 0 already)", null, sourceFromStacktrace(2) );
- return;
- }
- // A slight delay, to avoid any current callbacks
- if ( defined.setTimeout ) {
- window.setTimeout(function() {
- if ( config.semaphore > 0 ) {
- return;
- }
- if ( config.timeout ) {
- clearTimeout( config.timeout );
- }
-
- config.blocking = false;
- process( true );
- }, 13);
- } else {
- config.blocking = false;
- process( true );
- }
- },
-
- stop: function( count ) {
- config.semaphore += count || 1;
- config.blocking = true;
-
- if ( config.testTimeout && defined.setTimeout ) {
- clearTimeout( config.timeout );
- config.timeout = window.setTimeout(function() {
- QUnit.ok( false, "Test timed out" );
- config.semaphore = 1;
- QUnit.start();
- }, config.testTimeout );
- }
- }
-};
-
-// `assert` initialized at top of scope
-// Asssert helpers
-// All of these must either call QUnit.push() or manually do:
-// - runLoggingCallbacks( "log", .. );
-// - config.current.assertions.push({ .. });
-// We attach it to the QUnit object *after* we expose the public API,
-// otherwise `assert` will become a global variable in browsers (#341).
-assert = {
- /**
- * Asserts rough true-ish result.
- * @name ok
- * @function
- * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" );
- */
- ok: function( result, msg ) {
- if ( !config.current ) {
- throw new Error( "ok() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
- result = !!result;
-
- var source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: msg
- };
-
- msg = escapeText( msg || (result ? "okay" : "failed" ) );
- msg = "" + msg + "";
-
- if ( !result ) {
- source = sourceFromStacktrace( 2 );
- if ( source ) {
- details.source = source;
- msg += "Source: | " + escapeText( source ) + " |
---|
";
- }
- }
- runLoggingCallbacks( "log", QUnit, details );
- config.current.assertions.push({
- result: result,
- message: msg
- });
- },
-
- /**
- * Assert that the first two arguments are equal, with an optional message.
- * Prints out both actual and expected values.
- * @name equal
- * @function
- * @example equal( format( "Received {0} bytes.", 2), "Received 2 bytes.", "format() replaces {0} with next argument" );
- */
- equal: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected == actual, actual, expected, message );
- },
-
- /**
- * @name notEqual
- * @function
- */
- notEqual: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected != actual, actual, expected, message );
- },
-
- /**
- * @name propEqual
- * @function
- */
- propEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notPropEqual
- * @function
- */
- notPropEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name deepEqual
- * @function
- */
- deepEqual: function( actual, expected, message ) {
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notDeepEqual
- * @function
- */
- notDeepEqual: function( actual, expected, message ) {
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name strictEqual
- * @function
- */
- strictEqual: function( actual, expected, message ) {
- QUnit.push( expected === actual, actual, expected, message );
- },
-
- /**
- * @name notStrictEqual
- * @function
- */
- notStrictEqual: function( actual, expected, message ) {
- QUnit.push( expected !== actual, actual, expected, message );
- },
-
- "throws": function( block, expected, message ) {
- var actual,
- expectedOutput = expected,
- ok = false;
-
- // 'expected' is optional
- if ( typeof expected === "string" ) {
- message = expected;
- expected = null;
- }
-
- config.current.ignoreGlobalErrors = true;
- try {
- block.call( config.current.testEnvironment );
- } catch (e) {
- actual = e;
- }
- config.current.ignoreGlobalErrors = false;
-
- if ( actual ) {
- // we don't want to validate thrown error
- if ( !expected ) {
- ok = true;
- expectedOutput = null;
- // expected is a regexp
- } else if ( QUnit.objectType( expected ) === "regexp" ) {
- ok = expected.test( errorString( actual ) );
- // expected is a constructor
- } else if ( actual instanceof expected ) {
- ok = true;
- // expected is a validation function which returns true is validation passed
- } else if ( expected.call( {}, actual ) === true ) {
- expectedOutput = null;
- ok = true;
- }
-
- QUnit.push( ok, actual, expectedOutput, message );
- } else {
- QUnit.pushFailure( message, null, 'No exception was thrown.' );
- }
- }
-};
-
-/**
- * @deprecate since 1.8.0
- * Kept assertion helpers in root for backwards compatibility.
- */
-extend( QUnit, assert );
-
-/**
- * @deprecated since 1.9.0
- * Kept root "raises()" for backwards compatibility.
- * (Note that we don't introduce assert.raises).
- */
-QUnit.raises = assert[ "throws" ];
-
-/**
- * @deprecated since 1.0.0, replaced with error pushes since 1.3.0
- * Kept to avoid TypeErrors for undefined methods.
- */
-QUnit.equals = function() {
- QUnit.push( false, false, false, "QUnit.equals has been deprecated since 2009 (e88049a0), use QUnit.equal instead" );
-};
-QUnit.same = function() {
- QUnit.push( false, false, false, "QUnit.same has been deprecated since 2009 (e88049a0), use QUnit.deepEqual instead" );
-};
-
-// We want access to the constructor's prototype
-(function() {
- function F() {}
- F.prototype = QUnit;
- QUnit = new F();
- // Make F QUnit's constructor so that we can add to the prototype later
- QUnit.constructor = F;
-}());
-
-/**
- * Config object: Maintain internal state
- * Later exposed as QUnit.config
- * `config` initialized at top of scope
- */
-config = {
- // The queue of tests to run
- queue: [],
-
- // block until document ready
- blocking: true,
-
- // when enabled, show only failing tests
- // gets persisted through sessionStorage and can be changed in UI via checkbox
- hidepassed: false,
-
- // by default, run previously failed tests first
- // very useful in combination with "Hide passed tests" checked
- reorder: true,
-
- // by default, modify document.title when suite is done
- altertitle: true,
-
- // when enabled, all tests must call expect()
- requireExpects: false,
-
- // add checkboxes that are persisted in the query-string
- // when enabled, the id is set to `true` as a `QUnit.config` property
- urlConfig: [
- {
- id: "noglobals",
- label: "Check for Globals",
- tooltip: "Enabling this will test if any test introduces new properties on the `window` object. Stored as query-strings."
- },
- {
- id: "notrycatch",
- label: "No try-catch",
- tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging exceptions in IE reasonable. Stored as query-strings."
- }
- ],
-
- // Set of all modules.
- modules: {},
-
- // logging callback queues
- begin: [],
- done: [],
- log: [],
- testStart: [],
- testDone: [],
- moduleStart: [],
- moduleDone: []
-};
-
-// Export global variables, unless an 'exports' object exists,
-// in that case we assume we're in CommonJS (dealt with on the bottom of the script)
-if ( typeof exports === "undefined" ) {
- extend( window, QUnit );
-
- // Expose QUnit object
- window.QUnit = QUnit;
-}
-
-// Initialize more QUnit.config and QUnit.urlParams
-(function() {
- var i,
- location = window.location || { search: "", protocol: "file:" },
- params = location.search.slice( 1 ).split( "&" ),
- length = params.length,
- urlParams = {},
- current;
-
- if ( params[ 0 ] ) {
- for ( i = 0; i < length; i++ ) {
- current = params[ i ].split( "=" );
- current[ 0 ] = decodeURIComponent( current[ 0 ] );
- // allow just a key to turn on a flag, e.g., test.html?noglobals
- current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true;
- urlParams[ current[ 0 ] ] = current[ 1 ];
- }
- }
-
- QUnit.urlParams = urlParams;
-
- // String search anywhere in moduleName+testName
- config.filter = urlParams.filter;
-
- // Exact match of the module name
- config.module = urlParams.module;
-
- config.testNumber = parseInt( urlParams.testNumber, 10 ) || null;
-
- // Figure out if we're running the tests from a server or not
- QUnit.isLocal = location.protocol === "file:";
-}());
-
-// Extend QUnit object,
-// these after set here because they should not be exposed as global functions
-extend( QUnit, {
- assert: assert,
-
- config: config,
-
- // Initialize the configuration options
- init: function() {
- extend( config, {
- stats: { all: 0, bad: 0 },
- moduleStats: { all: 0, bad: 0 },
- started: +new Date(),
- updateRate: 1000,
- blocking: false,
- autostart: true,
- autorun: false,
- filter: "",
- queue: [],
- semaphore: 1
- });
-
- var tests, banner, result,
- qunit = id( "qunit" );
-
- if ( qunit ) {
- qunit.innerHTML =
- "" +
- "" +
- "" +
- "" +
- "
";
- }
-
- tests = id( "qunit-tests" );
- banner = id( "qunit-banner" );
- result = id( "qunit-testresult" );
-
- if ( tests ) {
- tests.innerHTML = "";
- }
-
- if ( banner ) {
- banner.className = "";
- }
-
- if ( result ) {
- result.parentNode.removeChild( result );
- }
-
- if ( tests ) {
- result = document.createElement( "p" );
- result.id = "qunit-testresult";
- result.className = "result";
- tests.parentNode.insertBefore( result, tests );
- result.innerHTML = "Running...
";
- }
- },
-
- // Resets the test setup. Useful for tests that modify the DOM.
- reset: function() {
- var fixture = id( "qunit-fixture" );
- if ( fixture ) {
- fixture.innerHTML = config.fixture;
- }
- },
-
- // Trigger an event on an element.
- // @example triggerEvent( document.body, "click" );
- triggerEvent: function( elem, type, event ) {
- if ( document.createEvent ) {
- event = document.createEvent( "MouseEvents" );
- event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView,
- 0, 0, 0, 0, 0, false, false, false, false, 0, null);
-
- elem.dispatchEvent( event );
- } else if ( elem.fireEvent ) {
- elem.fireEvent( "on" + type );
- }
- },
-
- // Safe object type checking
- is: function( type, obj ) {
- return QUnit.objectType( obj ) === type;
- },
-
- objectType: function( obj ) {
- if ( typeof obj === "undefined" ) {
- return "undefined";
- // consider: typeof null === object
- }
- if ( obj === null ) {
- return "null";
- }
-
- var match = toString.call( obj ).match(/^\[object\s(.*)\]$/),
- type = match && match[1] || "";
-
- switch ( type ) {
- case "Number":
- if ( isNaN(obj) ) {
- return "nan";
- }
- return "number";
- case "String":
- case "Boolean":
- case "Array":
- case "Date":
- case "RegExp":
- case "Function":
- return type.toLowerCase();
- }
- if ( typeof obj === "object" ) {
- return "object";
- }
- return undefined;
- },
-
- push: function( result, actual, expected, message ) {
- if ( !config.current ) {
- throw new Error( "assertion outside test context, was " + sourceFromStacktrace() );
- }
-
- var output, source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: message,
- actual: actual,
- expected: expected
- };
-
- message = escapeText( message ) || ( result ? "okay" : "failed" );
- message = "" + message + "";
- output = message;
-
- if ( !result ) {
- expected = escapeText( QUnit.jsDump.parse(expected) );
- actual = escapeText( QUnit.jsDump.parse(actual) );
- output += "Expected: | " + expected + " |
";
-
- if ( actual !== expected ) {
- output += "Result: | " + actual + " |
";
- output += "Diff: | " + QUnit.diff( expected, actual ) + " |
";
- }
-
- source = sourceFromStacktrace();
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
- }
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: !!result,
- message: output
- });
- },
-
- pushFailure: function( message, source, actual ) {
- if ( !config.current ) {
- throw new Error( "pushFailure() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
-
- var output,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: false,
- message: message
- };
-
- message = escapeText( message ) || "error";
- message = "" + message + "";
- output = message;
-
- output += "";
-
- if ( actual ) {
- output += "Result: | " + escapeText( actual ) + " |
";
- }
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: false,
- message: output
- });
- },
-
- url: function( params ) {
- params = extend( extend( {}, QUnit.urlParams ), params );
- var key,
- querystring = "?";
-
- for ( key in params ) {
- if ( !hasOwn.call( params, key ) ) {
- continue;
- }
- querystring += encodeURIComponent( key ) + "=" +
- encodeURIComponent( params[ key ] ) + "&";
- }
- return window.location.protocol + "//" + window.location.host +
- window.location.pathname + querystring.slice( 0, -1 );
- },
-
- extend: extend,
- id: id,
- addEvent: addEvent
- // load, equiv, jsDump, diff: Attached later
-});
-
-/**
- * @deprecated: Created for backwards compatibility with test runner that set the hook function
- * into QUnit.{hook}, instead of invoking it and passing the hook function.
- * QUnit.constructor is set to the empty F() above so that we can add to it's prototype here.
- * Doing this allows us to tell if the following methods have been overwritten on the actual
- * QUnit object.
- */
-extend( QUnit.constructor.prototype, {
-
- // Logging callbacks; all receive a single argument with the listed properties
- // run test/logs.html for any related changes
- begin: registerLoggingCallback( "begin" ),
-
- // done: { failed, passed, total, runtime }
- done: registerLoggingCallback( "done" ),
-
- // log: { result, actual, expected, message }
- log: registerLoggingCallback( "log" ),
-
- // testStart: { name }
- testStart: registerLoggingCallback( "testStart" ),
-
- // testDone: { name, failed, passed, total, duration }
- testDone: registerLoggingCallback( "testDone" ),
-
- // moduleStart: { name }
- moduleStart: registerLoggingCallback( "moduleStart" ),
-
- // moduleDone: { name, failed, passed, total }
- moduleDone: registerLoggingCallback( "moduleDone" )
-});
-
-if ( typeof document === "undefined" || document.readyState === "complete" ) {
- config.autorun = true;
-}
-
-QUnit.load = function() {
- runLoggingCallbacks( "begin", QUnit, {} );
-
- // Initialize the config, saving the execution queue
- var banner, filter, i, label, len, main, ol, toolbar, userAgent, val,
- urlConfigCheckboxesContainer, urlConfigCheckboxes, moduleFilter,
- numModules = 0,
- moduleFilterHtml = "",
- urlConfigHtml = "",
- oldconfig = extend( {}, config );
-
- QUnit.init();
- extend(config, oldconfig);
-
- config.blocking = false;
-
- len = config.urlConfig.length;
-
- for ( i = 0; i < len; i++ ) {
- val = config.urlConfig[i];
- if ( typeof val === "string" ) {
- val = {
- id: val,
- label: val,
- tooltip: "[no tooltip available]"
- };
- }
- config[ val.id ] = QUnit.urlParams[ val.id ];
- urlConfigHtml += "";
- }
-
- moduleFilterHtml += "";
-
- // `userAgent` initialized at top of scope
- userAgent = id( "qunit-userAgent" );
- if ( userAgent ) {
- userAgent.innerHTML = navigator.userAgent;
- }
-
- // `banner` initialized at top of scope
- banner = id( "qunit-header" );
- if ( banner ) {
- banner.innerHTML = "" + banner.innerHTML + " ";
- }
-
- // `toolbar` initialized at top of scope
- toolbar = id( "qunit-testrunner-toolbar" );
- if ( toolbar ) {
- // `filter` initialized at top of scope
- filter = document.createElement( "input" );
- filter.type = "checkbox";
- filter.id = "qunit-filter-pass";
-
- addEvent( filter, "click", function() {
- var tmp,
- ol = document.getElementById( "qunit-tests" );
-
- if ( filter.checked ) {
- ol.className = ol.className + " hidepass";
- } else {
- tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " ";
- ol.className = tmp.replace( / hidepass /, " " );
- }
- if ( defined.sessionStorage ) {
- if (filter.checked) {
- sessionStorage.setItem( "qunit-filter-passed-tests", "true" );
- } else {
- sessionStorage.removeItem( "qunit-filter-passed-tests" );
- }
- }
- });
-
- if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem( "qunit-filter-passed-tests" ) ) {
- filter.checked = true;
- // `ol` initialized at top of scope
- ol = document.getElementById( "qunit-tests" );
- ol.className = ol.className + " hidepass";
- }
- toolbar.appendChild( filter );
-
- // `label` initialized at top of scope
- label = document.createElement( "label" );
- label.setAttribute( "for", "qunit-filter-pass" );
- label.setAttribute( "title", "Only show tests and assertons that fail. Stored in sessionStorage." );
- label.innerHTML = "Hide passed tests";
- toolbar.appendChild( label );
-
- urlConfigCheckboxesContainer = document.createElement("span");
- urlConfigCheckboxesContainer.innerHTML = urlConfigHtml;
- urlConfigCheckboxes = urlConfigCheckboxesContainer.getElementsByTagName("input");
- // For oldIE support:
- // * Add handlers to the individual elements instead of the container
- // * Use "click" instead of "change"
- // * Fallback from event.target to event.srcElement
- addEvents( urlConfigCheckboxes, "click", function( event ) {
- var params = {},
- target = event.target || event.srcElement;
- params[ target.name ] = target.checked ? true : undefined;
- window.location = QUnit.url( params );
- });
- toolbar.appendChild( urlConfigCheckboxesContainer );
-
- if (numModules > 1) {
- moduleFilter = document.createElement( 'span' );
- moduleFilter.setAttribute( 'id', 'qunit-modulefilter-container' );
- moduleFilter.innerHTML = moduleFilterHtml;
- addEvent( moduleFilter.lastChild, "change", function() {
- var selectBox = moduleFilter.getElementsByTagName("select")[0],
- selectedModule = decodeURIComponent(selectBox.options[selectBox.selectedIndex].value);
-
- window.location = QUnit.url( { module: ( selectedModule === "" ) ? undefined : selectedModule } );
- });
- toolbar.appendChild(moduleFilter);
- }
- }
-
- // `main` initialized at top of scope
- main = id( "qunit-fixture" );
- if ( main ) {
- config.fixture = main.innerHTML;
- }
-
- if ( config.autostart ) {
- QUnit.start();
- }
-};
-
-addEvent( window, "load", QUnit.load );
-
-// `onErrorFnPrev` initialized at top of scope
-// Preserve other handlers
-onErrorFnPrev = window.onerror;
-
-// Cover uncaught exceptions
-// Returning true will surpress the default browser handler,
-// returning false will let it run.
-window.onerror = function ( error, filePath, linerNr ) {
- var ret = false;
- if ( onErrorFnPrev ) {
- ret = onErrorFnPrev( error, filePath, linerNr );
- }
-
- // Treat return value as window.onerror itself does,
- // Only do our handling if not surpressed.
- if ( ret !== true ) {
- if ( QUnit.config.current ) {
- if ( QUnit.config.current.ignoreGlobalErrors ) {
- return true;
- }
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- } else {
- QUnit.test( "global failure", extend( function() {
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- }, { validTest: validTest } ) );
- }
- return false;
- }
-
- return ret;
-};
-
-function done() {
- config.autorun = true;
-
- // Log the last module results
- if ( config.currentModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.currentModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
-
- var i, key,
- banner = id( "qunit-banner" ),
- tests = id( "qunit-tests" ),
- runtime = +new Date() - config.started,
- passed = config.stats.all - config.stats.bad,
- html = [
- "Tests completed in ",
- runtime,
- " milliseconds.
",
- "",
- passed,
- " assertions of ",
- config.stats.all,
- " passed, ",
- config.stats.bad,
- " failed."
- ].join( "" );
-
- if ( banner ) {
- banner.className = ( config.stats.bad ? "qunit-fail" : "qunit-pass" );
- }
-
- if ( tests ) {
- id( "qunit-testresult" ).innerHTML = html;
- }
-
- if ( config.altertitle && typeof document !== "undefined" && document.title ) {
- // show ✖ for good, ✔ for bad suite result in title
- // use escape sequences in case file gets loaded with non-utf-8-charset
- document.title = [
- ( config.stats.bad ? "\u2716" : "\u2714" ),
- document.title.replace( /^[\u2714\u2716] /i, "" )
- ].join( " " );
- }
-
- // clear own sessionStorage items if all tests passed
- if ( config.reorder && defined.sessionStorage && config.stats.bad === 0 ) {
- // `key` & `i` initialized at top of scope
- for ( i = 0; i < sessionStorage.length; i++ ) {
- key = sessionStorage.key( i++ );
- if ( key.indexOf( "qunit-test-" ) === 0 ) {
- sessionStorage.removeItem( key );
- }
- }
- }
-
- // scroll back to top to show results
- if ( window.scrollTo ) {
- window.scrollTo(0, 0);
- }
-
- runLoggingCallbacks( "done", QUnit, {
- failed: config.stats.bad,
- passed: passed,
- total: config.stats.all,
- runtime: runtime
- });
-}
-
-/** @return Boolean: true if this test should be ran */
-function validTest( test ) {
- var include,
- filter = config.filter && config.filter.toLowerCase(),
- module = config.module && config.module.toLowerCase(),
- fullName = (test.module + ": " + test.testName).toLowerCase();
-
- // Internally-generated tests are always valid
- if ( test.callback && test.callback.validTest === validTest ) {
- delete test.callback.validTest;
- return true;
- }
-
- if ( config.testNumber ) {
- return test.testNumber === config.testNumber;
- }
-
- if ( module && ( !test.module || test.module.toLowerCase() !== module ) ) {
- return false;
- }
-
- if ( !filter ) {
- return true;
- }
-
- include = filter.charAt( 0 ) !== "!";
- if ( !include ) {
- filter = filter.slice( 1 );
- }
-
- // If the filter matches, we need to honour include
- if ( fullName.indexOf( filter ) !== -1 ) {
- return include;
- }
-
- // Otherwise, do the opposite
- return !include;
-}
-
-// so far supports only Firefox, Chrome and Opera (buggy), Safari (for real exceptions)
-// Later Safari and IE10 are supposed to support error.stack as well
-// See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack
-function extractStacktrace( e, offset ) {
- offset = offset === undefined ? 3 : offset;
-
- var stack, include, i;
-
- if ( e.stacktrace ) {
- // Opera
- return e.stacktrace.split( "\n" )[ offset + 3 ];
- } else if ( e.stack ) {
- // Firefox, Chrome
- stack = e.stack.split( "\n" );
- if (/^error$/i.test( stack[0] ) ) {
- stack.shift();
- }
- if ( fileName ) {
- include = [];
- for ( i = offset; i < stack.length; i++ ) {
- if ( stack[ i ].indexOf( fileName ) !== -1 ) {
- break;
- }
- include.push( stack[ i ] );
- }
- if ( include.length ) {
- return include.join( "\n" );
- }
- }
- return stack[ offset ];
- } else if ( e.sourceURL ) {
- // Safari, PhantomJS
- // hopefully one day Safari provides actual stacktraces
- // exclude useless self-reference for generated Error objects
- if ( /qunit.js$/.test( e.sourceURL ) ) {
- return;
- }
- // for actual exceptions, this is useful
- return e.sourceURL + ":" + e.line;
- }
-}
-function sourceFromStacktrace( offset ) {
- try {
- throw new Error();
- } catch ( e ) {
- return extractStacktrace( e, offset );
- }
-}
-
-/**
- * Escape text for attribute or text content.
- */
-function escapeText( s ) {
- if ( !s ) {
- return "";
- }
- s = s + "";
- // Both single quotes and double quotes (for attributes)
- return s.replace( /['"<>&]/g, function( s ) {
- switch( s ) {
- case '\'':
- return ''';
- case '"':
- return '"';
- case '<':
- return '<';
- case '>':
- return '>';
- case '&':
- return '&';
- }
- });
-}
-
-function synchronize( callback, last ) {
- config.queue.push( callback );
-
- if ( config.autorun && !config.blocking ) {
- process( last );
- }
-}
-
-function process( last ) {
- function next() {
- process( last );
- }
- var start = new Date().getTime();
- config.depth = config.depth ? config.depth + 1 : 1;
-
- while ( config.queue.length && !config.blocking ) {
- if ( !defined.setTimeout || config.updateRate <= 0 || ( ( new Date().getTime() - start ) < config.updateRate ) ) {
- config.queue.shift()();
- } else {
- window.setTimeout( next, 13 );
- break;
- }
- }
- config.depth--;
- if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) {
- done();
- }
-}
-
-function saveGlobal() {
- config.pollution = [];
-
- if ( config.noglobals ) {
- for ( var key in window ) {
- // in Opera sometimes DOM element ids show up here, ignore them
- if ( !hasOwn.call( window, key ) || /^qunit-test-output/.test( key ) ) {
- continue;
- }
- config.pollution.push( key );
- }
- }
-}
-
-function checkPollution() {
- var newGlobals,
- deletedGlobals,
- old = config.pollution;
-
- saveGlobal();
-
- newGlobals = diff( config.pollution, old );
- if ( newGlobals.length > 0 ) {
- QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join(", ") );
- }
-
- deletedGlobals = diff( old, config.pollution );
- if ( deletedGlobals.length > 0 ) {
- QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join(", ") );
- }
-}
-
-// returns a new Array with the elements that are in a but not in b
-function diff( a, b ) {
- var i, j,
- result = a.slice();
-
- for ( i = 0; i < result.length; i++ ) {
- for ( j = 0; j < b.length; j++ ) {
- if ( result[i] === b[j] ) {
- result.splice( i, 1 );
- i--;
- break;
- }
- }
- }
- return result;
-}
-
-function extend( a, b ) {
- for ( var prop in b ) {
- if ( b[ prop ] === undefined ) {
- delete a[ prop ];
-
- // Avoid "Member not found" error in IE8 caused by setting window.constructor
- } else if ( prop !== "constructor" || a !== window ) {
- a[ prop ] = b[ prop ];
- }
- }
-
- return a;
-}
-
-/**
- * @param {HTMLElement} elem
- * @param {string} type
- * @param {Function} fn
- */
-function addEvent( elem, type, fn ) {
- // Standards-based browsers
- if ( elem.addEventListener ) {
- elem.addEventListener( type, fn, false );
- // IE
- } else {
- elem.attachEvent( "on" + type, fn );
- }
-}
-
-/**
- * @param {Array|NodeList} elems
- * @param {string} type
- * @param {Function} fn
- */
-function addEvents( elems, type, fn ) {
- var i = elems.length;
- while ( i-- ) {
- addEvent( elems[i], type, fn );
- }
-}
-
-function hasClass( elem, name ) {
- return (" " + elem.className + " ").indexOf(" " + name + " ") > -1;
-}
-
-function addClass( elem, name ) {
- if ( !hasClass( elem, name ) ) {
- elem.className += (elem.className ? " " : "") + name;
- }
-}
-
-function removeClass( elem, name ) {
- var set = " " + elem.className + " ";
- // Class name may appear multiple times
- while ( set.indexOf(" " + name + " ") > -1 ) {
- set = set.replace(" " + name + " " , " ");
- }
- // If possible, trim it for prettiness, but not neccecarily
- elem.className = window.jQuery ? jQuery.trim( set ) : ( set.trim ? set.trim() : set );
-}
-
-function id( name ) {
- return !!( typeof document !== "undefined" && document && document.getElementById ) &&
- document.getElementById( name );
-}
-
-function registerLoggingCallback( key ) {
- return function( callback ) {
- config[key].push( callback );
- };
-}
-
-// Supports deprecated method of completely overwriting logging callbacks
-function runLoggingCallbacks( key, scope, args ) {
- var i, callbacks;
- if ( QUnit.hasOwnProperty( key ) ) {
- QUnit[ key ].call(scope, args );
- } else {
- callbacks = config[ key ];
- for ( i = 0; i < callbacks.length; i++ ) {
- callbacks[ i ].call( scope, args );
- }
- }
-}
-
-// Test for equality any JavaScript type.
-// Author: Philippe Rathé
-QUnit.equiv = (function() {
-
- // Call the o related callback with the given arguments.
- function bindCallbacks( o, callbacks, args ) {
- var prop = QUnit.objectType( o );
- if ( prop ) {
- if ( QUnit.objectType( callbacks[ prop ] ) === "function" ) {
- return callbacks[ prop ].apply( callbacks, args );
- } else {
- return callbacks[ prop ]; // or undefined
- }
- }
- }
-
- // the real equiv function
- var innerEquiv,
- // stack to decide between skip/abort functions
- callers = [],
- // stack to avoiding loops from circular referencing
- parents = [],
-
- getProto = Object.getPrototypeOf || function ( obj ) {
- return obj.__proto__;
- },
- callbacks = (function () {
-
- // for string, boolean, number and null
- function useStrictEquality( b, a ) {
- /*jshint eqeqeq:false */
- if ( b instanceof a.constructor || a instanceof b.constructor ) {
- // to catch short annotaion VS 'new' annotation of a
- // declaration
- // e.g. var i = 1;
- // var j = new Number(1);
- return a == b;
- } else {
- return a === b;
- }
- }
-
- return {
- "string": useStrictEquality,
- "boolean": useStrictEquality,
- "number": useStrictEquality,
- "null": useStrictEquality,
- "undefined": useStrictEquality,
-
- "nan": function( b ) {
- return isNaN( b );
- },
-
- "date": function( b, a ) {
- return QUnit.objectType( b ) === "date" && a.valueOf() === b.valueOf();
- },
-
- "regexp": function( b, a ) {
- return QUnit.objectType( b ) === "regexp" &&
- // the regex itself
- a.source === b.source &&
- // and its modifers
- a.global === b.global &&
- // (gmi) ...
- a.ignoreCase === b.ignoreCase &&
- a.multiline === b.multiline &&
- a.sticky === b.sticky;
- },
-
- // - skip when the property is a method of an instance (OOP)
- // - abort otherwise,
- // initial === would have catch identical references anyway
- "function": function() {
- var caller = callers[callers.length - 1];
- return caller !== Object && typeof caller !== "undefined";
- },
-
- "array": function( b, a ) {
- var i, j, len, loop;
-
- // b could be an object literal here
- if ( QUnit.objectType( b ) !== "array" ) {
- return false;
- }
-
- len = a.length;
- if ( len !== b.length ) {
- // safe and faster
- return false;
- }
-
- // track reference to avoid circular references
- parents.push( a );
- for ( i = 0; i < len; i++ ) {
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- loop = true;// dont rewalk array
- }
- }
- if ( !loop && !innerEquiv(a[i], b[i]) ) {
- parents.pop();
- return false;
- }
- }
- parents.pop();
- return true;
- },
-
- "object": function( b, a ) {
- var i, j, loop,
- // Default to true
- eq = true,
- aProperties = [],
- bProperties = [];
-
- // comparing constructors is more strict than using
- // instanceof
- if ( a.constructor !== b.constructor ) {
- // Allow objects with no prototype to be equivalent to
- // objects with Object as their constructor.
- if ( !(( getProto(a) === null && getProto(b) === Object.prototype ) ||
- ( getProto(b) === null && getProto(a) === Object.prototype ) ) ) {
- return false;
- }
- }
-
- // stack constructor before traversing properties
- callers.push( a.constructor );
- // track reference to avoid circular references
- parents.push( a );
-
- for ( i in a ) { // be strict: don't ensures hasOwnProperty
- // and go deep
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- // don't go down the same path twice
- loop = true;
- }
- }
- aProperties.push(i); // collect a's properties
-
- if (!loop && !innerEquiv( a[i], b[i] ) ) {
- eq = false;
- break;
- }
- }
-
- callers.pop(); // unstack, we are done
- parents.pop();
-
- for ( i in b ) {
- bProperties.push( i ); // collect b's properties
- }
-
- // Ensures identical properties name
- return eq && innerEquiv( aProperties.sort(), bProperties.sort() );
- }
- };
- }());
-
- innerEquiv = function() { // can take multiple arguments
- var args = [].slice.apply( arguments );
- if ( args.length < 2 ) {
- return true; // end transition
- }
-
- return (function( a, b ) {
- if ( a === b ) {
- return true; // catch the most you can
- } else if ( a === null || b === null || typeof a === "undefined" ||
- typeof b === "undefined" ||
- QUnit.objectType(a) !== QUnit.objectType(b) ) {
- return false; // don't lose time with error prone cases
- } else {
- return bindCallbacks(a, callbacks, [ b, a ]);
- }
-
- // apply transition with (1..n) arguments
- }( args[0], args[1] ) && arguments.callee.apply( this, args.splice(1, args.length - 1 )) );
- };
-
- return innerEquiv;
-}());
-
-/**
- * jsDump Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com |
- * http://flesler.blogspot.com Licensed under BSD
- * (http://www.opensource.org/licenses/bsd-license.php) Date: 5/15/2008
- *
- * @projectDescription Advanced and extensible data dumping for Javascript.
- * @version 1.0.0
- * @author Ariel Flesler
- * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html}
- */
-QUnit.jsDump = (function() {
- function quote( str ) {
- return '"' + str.toString().replace( /"/g, '\\"' ) + '"';
- }
- function literal( o ) {
- return o + "";
- }
- function join( pre, arr, post ) {
- var s = jsDump.separator(),
- base = jsDump.indent(),
- inner = jsDump.indent(1);
- if ( arr.join ) {
- arr = arr.join( "," + s + inner );
- }
- if ( !arr ) {
- return pre + post;
- }
- return [ pre, inner + arr, base + post ].join(s);
- }
- function array( arr, stack ) {
- var i = arr.length, ret = new Array(i);
- this.up();
- while ( i-- ) {
- ret[i] = this.parse( arr[i] , undefined , stack);
- }
- this.down();
- return join( "[", ret, "]" );
- }
-
- var reName = /^function (\w+)/,
- jsDump = {
- // type is used mostly internally, you can fix a (custom)type in advance
- parse: function( obj, type, stack ) {
- stack = stack || [ ];
- var inStack, res,
- parser = this.parsers[ type || this.typeOf(obj) ];
-
- type = typeof parser;
- inStack = inArray( obj, stack );
-
- if ( inStack !== -1 ) {
- return "recursion(" + (inStack - stack.length) + ")";
- }
- if ( type === "function" ) {
- stack.push( obj );
- res = parser.call( this, obj, stack );
- stack.pop();
- return res;
- }
- return ( type === "string" ) ? parser : this.parsers.error;
- },
- typeOf: function( obj ) {
- var type;
- if ( obj === null ) {
- type = "null";
- } else if ( typeof obj === "undefined" ) {
- type = "undefined";
- } else if ( QUnit.is( "regexp", obj) ) {
- type = "regexp";
- } else if ( QUnit.is( "date", obj) ) {
- type = "date";
- } else if ( QUnit.is( "function", obj) ) {
- type = "function";
- } else if ( typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined" ) {
- type = "window";
- } else if ( obj.nodeType === 9 ) {
- type = "document";
- } else if ( obj.nodeType ) {
- type = "node";
- } else if (
- // native arrays
- toString.call( obj ) === "[object Array]" ||
- // NodeList objects
- ( typeof obj.length === "number" && typeof obj.item !== "undefined" && ( obj.length ? obj.item(0) === obj[0] : ( obj.item( 0 ) === null && typeof obj[0] === "undefined" ) ) )
- ) {
- type = "array";
- } else if ( obj.constructor === Error.prototype.constructor ) {
- type = "error";
- } else {
- type = typeof obj;
- }
- return type;
- },
- separator: function() {
- return this.multiline ? this.HTML ? "
" : "\n" : this.HTML ? " " : " ";
- },
- // extra can be a number, shortcut for increasing-calling-decreasing
- indent: function( extra ) {
- if ( !this.multiline ) {
- return "";
- }
- var chr = this.indentChar;
- if ( this.HTML ) {
- chr = chr.replace( /\t/g, " " ).replace( / /g, " " );
- }
- return new Array( this._depth_ + (extra||0) ).join(chr);
- },
- up: function( a ) {
- this._depth_ += a || 1;
- },
- down: function( a ) {
- this._depth_ -= a || 1;
- },
- setParser: function( name, parser ) {
- this.parsers[name] = parser;
- },
- // The next 3 are exposed so you can use them
- quote: quote,
- literal: literal,
- join: join,
- //
- _depth_: 1,
- // This is the list of parsers, to modify them, use jsDump.setParser
- parsers: {
- window: "[Window]",
- document: "[Document]",
- error: function(error) {
- return "Error(\"" + error.message + "\")";
- },
- unknown: "[Unknown]",
- "null": "null",
- "undefined": "undefined",
- "function": function( fn ) {
- var ret = "function",
- // functions never have name in IE
- name = "name" in fn ? fn.name : (reName.exec(fn) || [])[1];
-
- if ( name ) {
- ret += " " + name;
- }
- ret += "( ";
-
- ret = [ ret, QUnit.jsDump.parse( fn, "functionArgs" ), "){" ].join( "" );
- return join( ret, QUnit.jsDump.parse(fn,"functionCode" ), "}" );
- },
- array: array,
- nodelist: array,
- "arguments": array,
- object: function( map, stack ) {
- var ret = [ ], keys, key, val, i;
- QUnit.jsDump.up();
- keys = [];
- for ( key in map ) {
- keys.push( key );
- }
- keys.sort();
- for ( i = 0; i < keys.length; i++ ) {
- key = keys[ i ];
- val = map[ key ];
- ret.push( QUnit.jsDump.parse( key, "key" ) + ": " + QUnit.jsDump.parse( val, undefined, stack ) );
- }
- QUnit.jsDump.down();
- return join( "{", ret, "}" );
- },
- node: function( node ) {
- var len, i, val,
- open = QUnit.jsDump.HTML ? "<" : "<",
- close = QUnit.jsDump.HTML ? ">" : ">",
- tag = node.nodeName.toLowerCase(),
- ret = open + tag,
- attrs = node.attributes;
-
- if ( attrs ) {
- for ( i = 0, len = attrs.length; i < len; i++ ) {
- val = attrs[i].nodeValue;
- // IE6 includes all attributes in .attributes, even ones not explicitly set.
- // Those have values like undefined, null, 0, false, "" or "inherit".
- if ( val && val !== "inherit" ) {
- ret += " " + attrs[i].nodeName + "=" + QUnit.jsDump.parse( val, "attribute" );
- }
- }
- }
- ret += close;
-
- // Show content of TextNode or CDATASection
- if ( node.nodeType === 3 || node.nodeType === 4 ) {
- ret += node.nodeValue;
- }
-
- return ret + open + "/" + tag + close;
- },
- // function calls it internally, it's the arguments part of the function
- functionArgs: function( fn ) {
- var args,
- l = fn.length;
-
- if ( !l ) {
- return "";
- }
-
- args = new Array(l);
- while ( l-- ) {
- // 97 is 'a'
- args[l] = String.fromCharCode(97+l);
- }
- return " " + args.join( ", " ) + " ";
- },
- // object calls it internally, the key part of an item in a map
- key: quote,
- // function calls it internally, it's the content of the function
- functionCode: "[code]",
- // node calls it internally, it's an html attribute value
- attribute: quote,
- string: quote,
- date: quote,
- regexp: literal,
- number: literal,
- "boolean": literal
- },
- // if true, entities are escaped ( <, >, \t, space and \n )
- HTML: false,
- // indentation unit
- indentChar: " ",
- // if true, items in a collection, are separated by a \n, else just a space.
- multiline: true
- };
-
- return jsDump;
-}());
-
-// from jquery.js
-function inArray( elem, array ) {
- if ( array.indexOf ) {
- return array.indexOf( elem );
- }
-
- for ( var i = 0, length = array.length; i < length; i++ ) {
- if ( array[ i ] === elem ) {
- return i;
- }
- }
-
- return -1;
-}
-
-/*
- * Javascript Diff Algorithm
- * By John Resig (http://ejohn.org/)
- * Modified by Chu Alan "sprite"
- *
- * Released under the MIT license.
- *
- * More Info:
- * http://ejohn.org/projects/javascript-diff-algorithm/
- *
- * Usage: QUnit.diff(expected, actual)
- *
- * QUnit.diff( "the quick brown fox jumped over", "the quick fox jumps over" ) == "the quick brown fox jumped jumps over"
- */
-QUnit.diff = (function() {
- /*jshint eqeqeq:false, eqnull:true */
- function diff( o, n ) {
- var i,
- ns = {},
- os = {};
-
- for ( i = 0; i < n.length; i++ ) {
- if ( !hasOwn.call( ns, n[i] ) ) {
- ns[ n[i] ] = {
- rows: [],
- o: null
- };
- }
- ns[ n[i] ].rows.push( i );
- }
-
- for ( i = 0; i < o.length; i++ ) {
- if ( !hasOwn.call( os, o[i] ) ) {
- os[ o[i] ] = {
- rows: [],
- n: null
- };
- }
- os[ o[i] ].rows.push( i );
- }
-
- for ( i in ns ) {
- if ( !hasOwn.call( ns, i ) ) {
- continue;
- }
- if ( ns[i].rows.length === 1 && hasOwn.call( os, i ) && os[i].rows.length === 1 ) {
- n[ ns[i].rows[0] ] = {
- text: n[ ns[i].rows[0] ],
- row: os[i].rows[0]
- };
- o[ os[i].rows[0] ] = {
- text: o[ os[i].rows[0] ],
- row: ns[i].rows[0]
- };
- }
- }
-
- for ( i = 0; i < n.length - 1; i++ ) {
- if ( n[i].text != null && n[ i + 1 ].text == null && n[i].row + 1 < o.length && o[ n[i].row + 1 ].text == null &&
- n[ i + 1 ] == o[ n[i].row + 1 ] ) {
-
- n[ i + 1 ] = {
- text: n[ i + 1 ],
- row: n[i].row + 1
- };
- o[ n[i].row + 1 ] = {
- text: o[ n[i].row + 1 ],
- row: i + 1
- };
- }
- }
-
- for ( i = n.length - 1; i > 0; i-- ) {
- if ( n[i].text != null && n[ i - 1 ].text == null && n[i].row > 0 && o[ n[i].row - 1 ].text == null &&
- n[ i - 1 ] == o[ n[i].row - 1 ]) {
-
- n[ i - 1 ] = {
- text: n[ i - 1 ],
- row: n[i].row - 1
- };
- o[ n[i].row - 1 ] = {
- text: o[ n[i].row - 1 ],
- row: i - 1
- };
- }
- }
-
- return {
- o: o,
- n: n
- };
- }
-
- return function( o, n ) {
- o = o.replace( /\s+$/, "" );
- n = n.replace( /\s+$/, "" );
-
- var i, pre,
- str = "",
- out = diff( o === "" ? [] : o.split(/\s+/), n === "" ? [] : n.split(/\s+/) ),
- oSpace = o.match(/\s+/g),
- nSpace = n.match(/\s+/g);
-
- if ( oSpace == null ) {
- oSpace = [ " " ];
- }
- else {
- oSpace.push( " " );
- }
-
- if ( nSpace == null ) {
- nSpace = [ " " ];
- }
- else {
- nSpace.push( " " );
- }
-
- if ( out.n.length === 0 ) {
- for ( i = 0; i < out.o.length; i++ ) {
- str += "" + out.o[i] + oSpace[i] + "";
- }
- }
- else {
- if ( out.n[0].text == null ) {
- for ( n = 0; n < out.o.length && out.o[n].text == null; n++ ) {
- str += "" + out.o[n] + oSpace[n] + "";
- }
- }
-
- for ( i = 0; i < out.n.length; i++ ) {
- if (out.n[i].text == null) {
- str += "" + out.n[i] + nSpace[i] + "";
- }
- else {
- // `pre` initialized at top of scope
- pre = "";
-
- for ( n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++ ) {
- pre += "" + out.o[n] + oSpace[n] + "";
- }
- str += " " + out.n[i].text + nSpace[i] + pre;
- }
- }
- }
-
- return str;
- };
-}());
-
-// for CommonJS enviroments, export everything
-if ( typeof exports !== "undefined" ) {
- extend( exports, QUnit );
-}
-
-// get at whatever the global object is, like window in browsers
-}( (function() {return this;}.call()) ));
diff --git a/test/lib/require.js b/test/lib/require.js
deleted file mode 100644
index 987f865..0000000
--- a/test/lib/require.js
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- RequireJS 2.1.5 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.
- Available via the MIT or new BSD license.
- see: http://github.com/jrburke/requirejs for details
-*/
-var requirejs,require,define;
-(function(aa){function I(b){return"[object Function]"===L.call(b)}function J(b){return"[object Array]"===L.call(b)}function y(b,c){if(b){var d;for(d=0;dthis.depCount&&!this.defined){if(I(n)){if(this.events.error)try{e=i.execCb(c,n,b,e)}catch(d){a=d}else e=i.execCb(c,n,b,e);this.map.isDefine&&((b=this.module)&&void 0!==b.exports&&b.exports!==this.exports?e=b.exports:void 0===e&&this.usingExports&&(e=this.exports));if(a)return a.requireMap=this.map,a.requireModules=[this.map.id],a.requireType="define",v(this.error=
-a)}else e=n;this.exports=e;if(this.map.isDefine&&!this.ignore&&(q[c]=e,l.onResourceLoad))l.onResourceLoad(i,this.map,this.depMaps);x(c);this.defined=!0}this.defining=!1;this.defined&&!this.defineEmitted&&(this.defineEmitted=!0,this.emit("defined",this.exports),this.defineEmitComplete=!0)}}else this.fetch()}},callPlugin:function(){var a=this.map,b=a.id,d=j(a.prefix);this.depMaps.push(d);t(d,"defined",u(this,function(e){var n,d;d=this.map.name;var g=this.map.parentMap?this.map.parentMap.name:null,h=
-i.makeRequire(a.parentMap,{enableBuildCallback:!0});if(this.map.unnormalized){if(e.normalize&&(d=e.normalize(d,function(a){return c(a,g,!0)})||""),e=j(a.prefix+"!"+d,this.map.parentMap),t(e,"defined",u(this,function(a){this.init([],function(){return a},null,{enabled:!0,ignore:!0})})),d=m(p,e.id)){this.depMaps.push(e);if(this.events.error)d.on("error",u(this,function(a){this.emit("error",a)}));d.enable()}}else n=u(this,function(a){this.init([],function(){return a},null,{enabled:!0})}),n.error=u(this,
-function(a){this.inited=!0;this.error=a;a.requireModules=[b];G(p,function(a){0===a.map.id.indexOf(b+"_unnormalized")&&x(a.map.id)});v(a)}),n.fromText=u(this,function(e,c){var d=a.name,g=j(d),C=O;c&&(e=c);C&&(O=!1);r(g);s(k.config,b)&&(k.config[d]=k.config[b]);try{l.exec(e)}catch(ca){return v(B("fromtexteval","fromText eval for "+b+" failed: "+ca,ca,[b]))}C&&(O=!0);this.depMaps.push(g);i.completeLoad(d);h([d],n)}),e.load(a.name,h,n,k)}));i.enable(d,this);this.pluginMaps[d.id]=d},enable:function(){V[this.map.id]=
-this;this.enabling=this.enabled=!0;y(this.depMaps,u(this,function(a,b){var c,e;if("string"===typeof a){a=j(a,this.map.isDefine?this.map:this.map.parentMap,!1,!this.skipMap);this.depMaps[b]=a;if(c=m(N,a.id)){this.depExports[b]=c(this);return}this.depCount+=1;t(a,"defined",u(this,function(a){this.defineDep(b,a);this.check()}));this.errback&&t(a,"error",this.errback)}c=a.id;e=p[c];!s(N,c)&&(e&&!e.enabled)&&i.enable(a,this)}));G(this.pluginMaps,u(this,function(a){var b=m(p,a.id);b&&!b.enabled&&i.enable(a,
-this)}));this.enabling=!1;this.check()},on:function(a,b){var c=this.events[a];c||(c=this.events[a]=[]);c.push(b)},emit:function(a,b){y(this.events[a],function(a){a(b)});"error"===a&&delete this.events[a]}};i={config:k,contextName:b,registry:p,defined:q,urlFetched:U,defQueue:H,Module:Z,makeModuleMap:j,nextTick:l.nextTick,onError:v,configure:function(a){a.baseUrl&&"/"!==a.baseUrl.charAt(a.baseUrl.length-1)&&(a.baseUrl+="/");var b=k.pkgs,c=k.shim,e={paths:!0,config:!0,map:!0};G(a,function(a,b){e[b]?
-"map"===b?(k.map||(k.map={}),R(k[b],a,!0,!0)):R(k[b],a,!0):k[b]=a});a.shim&&(G(a.shim,function(a,b){J(a)&&(a={deps:a});if((a.exports||a.init)&&!a.exportsFn)a.exportsFn=i.makeShimExports(a);c[b]=a}),k.shim=c);a.packages&&(y(a.packages,function(a){a="string"===typeof a?{name:a}:a;b[a.name]={name:a.name,location:a.location||a.name,main:(a.main||"main").replace(ja,"").replace(ea,"")}}),k.pkgs=b);G(p,function(a,b){!a.inited&&!a.map.unnormalized&&(a.map=j(b))});if(a.deps||a.callback)i.require(a.deps||[],
-a.callback)},makeShimExports:function(a){return function(){var b;a.init&&(b=a.init.apply(aa,arguments));return b||a.exports&&ba(a.exports)}},makeRequire:function(a,f){function d(e,c,h){var g,k;f.enableBuildCallback&&(c&&I(c))&&(c.__requireJsBuild=!0);if("string"===typeof e){if(I(c))return v(B("requireargs","Invalid require call"),h);if(a&&s(N,e))return N[e](p[a.id]);if(l.get)return l.get(i,e,a,d);g=j(e,a,!1,!0);g=g.id;return!s(q,g)?v(B("notloaded",'Module name "'+g+'" has not been loaded yet for context: '+
-b+(a?"":". Use require([])"))):q[g]}L();i.nextTick(function(){L();k=r(j(null,a));k.skipMap=f.skipMap;k.init(e,c,h,{enabled:!0});D()});return d}f=f||{};R(d,{isBrowser:A,toUrl:function(b){var d,f=b.lastIndexOf("."),g=b.split("/")[0];if(-1!==f&&(!("."===g||".."===g)||1h.attachEvent.toString().indexOf("[native code"))&&!Y?(O=!0,h.attachEvent("onreadystatechange",b.onScriptLoad)):(h.addEventListener("load",b.onScriptLoad,!1),h.addEventListener("error",b.onScriptError,!1)),h.src=d,K=h,D?x.insertBefore(h,D):x.appendChild(h),K=null,h;if(da)try{importScripts(d),b.completeLoad(c)}catch(j){b.onError(B("importscripts","importScripts failed for "+c+" at "+d,j,[c]))}};A&&M(document.getElementsByTagName("script"),function(b){x||(x=
-b.parentNode);if(t=b.getAttribute("data-main"))return r.baseUrl||(E=t.split("/"),Q=E.pop(),fa=E.length?E.join("/")+"/":"./",r.baseUrl=fa,t=Q),t=t.replace(ea,""),r.deps=r.deps?r.deps.concat(t):[t],!0});define=function(b,c,d){var l,h;"string"!==typeof b&&(d=c,c=b,b=null);J(c)||(d=c,c=[]);!c.length&&I(d)&&d.length&&(d.toString().replace(la,"").replace(ma,function(b,d){c.push(d)}),c=(1===d.length?["require"]:["require","exports","module"]).concat(c));if(O){if(!(l=K))P&&"interactive"===P.readyState||M(document.getElementsByTagName("script"),
-function(b){if("interactive"===b.readyState)return P=b}),l=P;l&&(b||(b=l.getAttribute("data-requiremodule")),h=F[l.getAttribute("data-requirecontext")])}(h?h.defQueue:T).push([b,c,d])};define.amd={jQuery:!0};l.exec=function(b){return eval(b)};l(r)}})(this);
diff --git a/test/lib/resemble.js b/test/lib/resemble.js
new file mode 100644
index 0000000..1cb8c29
--- /dev/null
+++ b/test/lib/resemble.js
@@ -0,0 +1,535 @@
+/*
+Author: James Cryer
+Company: Huddle
+Last updated date: 21 Feb 2013
+URL: https://github.com/Huddle/Resemble.js
+*/
+
+(function(_this){
+ 'use strict';
+
+ _this['resemble'] = function( fileData ){
+
+ var data = {};
+ var images = [];
+ var updateCallbackArray = [];
+
+ var tolerance = { // between 0 and 255
+ red: 16,
+ green: 16,
+ blue: 16,
+ minBrightness: 16,
+ maxBrightness: 240
+ };
+
+ var ignoreAntialiasing = false;
+ var ignoreColors = false;
+
+ function triggerDataUpdate(){
+ var len = updateCallbackArray.length;
+ var i;
+ for(i=0;i tolerance.maxBrightness;
+ }
+
+ function getHue(r,g,b){
+
+ r = r / 255;
+ g = g / 255;
+ b = b / 255;
+ var max = Math.max(r, g, b), min = Math.min(r, g, b);
+ var h;
+ var d;
+
+ if (max == min){
+ h = 0; // achromatic
+ } else{
+ d = max - min;
+ switch(max){
+ case r: h = (g - b) / d + (g < b ? 6 : 0); break;
+ case g: h = (b - r) / d + 2; break;
+ case b: h = (r - g) / d + 4; break;
+ }
+ h /= 6;
+ }
+
+ return h;
+ }
+
+ function isAntialiased(sourcePix, data, cacheSet, verticalPos, horizontalPos, width){
+ var offset;
+ var targetPix;
+ var distance = 1;
+ var i;
+ var j;
+ var hasHighContrastSibling = 0;
+ var hasSiblingWithDifferentHue = 0;
+ var hasEquivilantSibling = 0;
+
+ addHueInfo(sourcePix);
+
+ for (i = distance*-1; i <= distance; i++){
+ for (j = distance*-1; j <= distance; j++){
+
+ if(i===0 && j===0){
+ // ignore source pixel
+ } else {
+
+ offset = ((verticalPos+j)*width + (horizontalPos+i)) * 4;
+ targetPix = getPixelInfo(data, offset, cacheSet);
+
+ if(targetPix === null){
+ continue;
+ }
+
+ addBrightnessInfo(targetPix);
+ addHueInfo(targetPix);
+
+ if( isContrasting(sourcePix, targetPix) ){
+ hasHighContrastSibling++;
+ }
+
+ if( isRGBSame(sourcePix,targetPix) ){
+ hasEquivilantSibling++;
+ }
+
+ if( Math.abs(targetPix.h - sourcePix.h) > 0.3 ){
+ hasSiblingWithDifferentHue++;
+ }
+
+ if( hasSiblingWithDifferentHue > 1 || hasHighContrastSibling > 1){
+ return true;
+ }
+ }
+ }
+ }
+
+ if(hasEquivilantSibling < 2){
+ return true;
+ }
+
+ return false;
+ }
+
+ function errorPixel(px, offset){
+ px[offset] = 255; //r
+ px[offset + 1] = 0; //g
+ px[offset + 2] = 255; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyPixel(px, offset, data){
+ px[offset] = data.r; //r
+ px[offset + 1] = data.g; //g
+ px[offset + 2] = data.b; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyGrayScalePixel(px, offset, data){
+ px[offset] = data.brightness; //r
+ px[offset + 1] = data.brightness; //g
+ px[offset + 2] = data.brightness; //b
+ px[offset + 3] = 255; //a
+ }
+
+
+ function getPixelInfo(data, offset, cacheSet){
+ var r;
+ var g;
+ var b;
+ var d;
+
+ if(typeof data[offset] !== 'undefined'){
+ r = data[offset];
+ g = data[offset+1];
+ b = data[offset+2];
+ d = {
+ r: r,
+ g: g,
+ b: b
+ };
+
+ return d;
+ } else {
+ return null;
+ }
+ }
+
+ function addBrightnessInfo(data){
+ data.brightness = getBrightness(data.r,data.g,data.b); // 'corrected' lightness
+ }
+
+ function addHueInfo(data){
+ data.h = getHue(data.r,data.g,data.b);
+ }
+
+ function analyseImages(img1, img2, width, height){
+
+ var hiddenCanvas = document.createElement('canvas');
+
+ var data1 = img1.data;
+ var data2 = img2.data;
+
+ hiddenCanvas.width = width;
+ hiddenCanvas.height = height;
+
+ var context = hiddenCanvas.getContext('2d');
+ var imgd = context.createImageData(width,height);
+ var targetPix = imgd.data;
+
+ var mismatchCount = 0;
+
+ var time = Date.now();
+
+ var skip;
+
+ if( (width > 1200 || height > 1200) && ignoreAntialiasing){
+ skip = 6;
+ }
+
+ loop(height, width, function(verticalPos, horizontalPos){
+
+ if(skip){ // only skip if the image isn't small
+ if(verticalPos % skip === 0 || horizontalPos % skip === 0){
+ return;
+ }
+ }
+
+ var offset = (verticalPos*width + horizontalPos) * 4;
+ var pixel1 = getPixelInfo(data1, offset, 1);
+ var pixel2 = getPixelInfo(data2, offset, 2);
+
+ if(pixel1 === null || pixel2 === null){
+ return;
+ }
+
+ if (ignoreColors){
+
+ addBrightnessInfo(pixel1);
+ addBrightnessInfo(pixel2);
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ return;
+ }
+
+ if( isRGBSimilar(pixel1, pixel2) ){
+ copyPixel(targetPix, offset, pixel2);
+
+ } else if( ignoreAntialiasing && (
+ addBrightnessInfo(pixel1), // jit pixel info augmentation looks a little weird, sorry.
+ addBrightnessInfo(pixel2),
+ isAntialiased(pixel1, data1, 1, verticalPos, horizontalPos, width) ||
+ isAntialiased(pixel2, data2, 2, verticalPos, horizontalPos, width)
+ )){
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+
+ });
+
+ data.misMatchPercentage = (mismatchCount / (height*width) * 100).toFixed(2);
+ data.analysisTime = Date.now() - time;
+
+ data.getImageDataUrl = function(text){
+ var barHeight = 0;
+
+ if(text){
+ barHeight = addLabel(text,context,hiddenCanvas);
+ }
+
+ context.putImageData(imgd, 0, barHeight);
+
+ return hiddenCanvas.toDataURL("image/png");
+ };
+ }
+
+ function addLabel(text, context, hiddenCanvas){
+ var textPadding = 2;
+
+ context.font = '12px sans-serif';
+
+ var textWidth = context.measureText(text).width + textPadding*2;
+ var barHeight = 22;
+
+ if(textWidth > hiddenCanvas.width){
+ hiddenCanvas.width = textWidth;
+ }
+
+ hiddenCanvas.height += barHeight;
+
+ context.fillStyle = "#666";
+ context.fillRect(0,0,hiddenCanvas.width,barHeight -4);
+ context.fillStyle = "#fff";
+ context.fillRect(0,barHeight -4,hiddenCanvas.width, 4);
+
+ context.fillStyle = "#fff";
+ context.textBaseline = "top";
+ context.font = '12px sans-serif';
+ context.fillText(text, textPadding, 1);
+
+ return barHeight;
+ }
+
+ function normalise(img, w, h){
+ var c;
+ var context;
+
+ if(img.height < h || img.width < w){
+ c = document.createElement('canvas');
+ c.width = w;
+ c.height = h;
+ context = c.getContext('2d');
+ context.putImageData(img, 0, 0);
+ return context.getImageData(0, 0, w, h);
+ }
+
+ return img;
+ }
+
+ function compare(one, two){
+
+ function onceWeHaveBoth(){
+ var width;
+ var height;
+ if(images.length === 2){
+ width = images[0].width > images[1].width ? images[0].width : images[1].width;
+ height = images[0].height > images[1].height ? images[0].height : images[1].height;
+
+ if( (images[0].width === images[1].width) && (images[0].height === images[1].height) ){
+ data.isSameDimensions = true;
+ } else {
+ data.isSameDimensions = false;
+ }
+
+ analyseImages( normalise(images[0],width, height), normalise(images[1],width, height), width, height);
+
+ triggerDataUpdate();
+ }
+ }
+
+ images = [];
+ loadImageData(one, onceWeHaveBoth);
+ loadImageData(two, onceWeHaveBoth);
+ }
+
+ function getCompareApi(param){
+
+ var secondFileData,
+ hasMethod = typeof param === 'function';
+
+ if( !hasMethod ){
+ // assume it's file data
+ secondFileData = param;
+ }
+
+ var self = {
+ ignoreNothing: function(){
+
+ tolerance.red = 16;
+ tolerance.green = 16;
+ tolerance.blue = 16;
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreAntialiasing: function(){
+
+ tolerance.red = 32;
+ tolerance.green = 32;
+ tolerance.blue = 32;
+ tolerance.minBrightness = 64;
+ tolerance.maxBrightness = 96;
+
+ ignoreAntialiasing = true;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreColors: function(){
+
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = true;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ onComplete: function( callback ){
+
+ updateCallbackArray.push(callback);
+
+ var wrapper = function(){
+ compare(fileData, secondFileData);
+ };
+
+ wrapper();
+
+ return getCompareApi(wrapper);
+ }
+ };
+
+ return self;
+ }
+
+ return {
+ onComplete: function( callback ){
+ updateCallbackArray.push(callback);
+ loadImageData(fileData, function(imageData, width, height){
+ parseImage(imageData.data, width, height);
+ });
+ },
+ compareTo: function(secondFileData){
+ return getCompareApi(secondFileData);
+ }
+ };
+
+ };
+}(this));
\ No newline at end of file
diff --git a/test/testsuite.js b/test/testsuite.js
deleted file mode 100644
index b486acb..0000000
--- a/test/testsuite.js
+++ /dev/null
@@ -1,36 +0,0 @@
-requirejs.config({
- baseUrl: '/test/unit/'
-});
-
-define(function(require) {
- var testModules = [
- 'Pixi',
- 'Point',
- 'Rectangle',
- 'DisplayObject',
- 'DisplayObjectContainer',
- 'Sprite',
- 'MovieClip',
- 'InteractionManager',
- 'Stage',
- 'utils/Utils',
- 'utils/EventTarget',
- 'utils/Matrix',
- 'utils/Detector',
- 'renderers/WebGLShaders',
- 'renderers/WebGLRenderer',
- 'renderers/WebGLBatch',
- 'renderers/CanvasRenderer',
- 'extras/Strip',
- 'extras/Rope',
- 'textures/BaseTexture',
- 'textures/Texture',
- 'loaders/SpriteSheetLoader',
- 'loaders/AssetLoader'
- ];
-
- // Resolve all testModules and then start the Test Runner.
- require(testModules, function() {
- QUnit.start();
- });
-});
\ No newline at end of file
diff --git a/test/textures/SpriteSheet-Aliens.png b/test/textures/SpriteSheet-Aliens.png
new file mode 100644
index 0000000..210acb1
--- /dev/null
+++ b/test/textures/SpriteSheet-Aliens.png
Binary files differ
diff --git a/test/textures/SpriteSheet-Explosion.png b/test/textures/SpriteSheet-Explosion.png
new file mode 100755
index 0000000..79e1a69
--- /dev/null
+++ b/test/textures/SpriteSheet-Explosion.png
Binary files differ
diff --git a/test/textures/bunny.png b/test/textures/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/textures/bunny.png
Binary files differ
diff --git a/test/unit/DisplayObject.js b/test/unit/DisplayObject.js
deleted file mode 100644
index 5e7e72f..0000000
--- a/test/unit/DisplayObject.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObject');
-});
diff --git a/test/unit/DisplayObjectContainer.js b/test/unit/DisplayObjectContainer.js
deleted file mode 100644
index b323959..0000000
--- a/test/unit/DisplayObjectContainer.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObjectContainer');
-});
diff --git a/test/unit/InteractionManager.js b/test/unit/InteractionManager.js
deleted file mode 100644
index e751f52..0000000
--- a/test/unit/InteractionManager.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('InteractionManager');
-});
diff --git a/test/unit/MovieClip.js b/test/unit/MovieClip.js
deleted file mode 100644
index 37d9446..0000000
--- a/test/unit/MovieClip.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('MovieClip');
-});
diff --git a/test/unit/Pixi.js b/test/unit/Pixi.js
deleted file mode 100644
index 36eee73..0000000
--- a/test/unit/Pixi.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Pixi');
-});
diff --git a/test/unit/Point.js b/test/unit/Point.js
deleted file mode 100644
index 983ff6e..0000000
--- a/test/unit/Point.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Point');
-});
diff --git a/test/unit/Rectangle.js b/test/unit/Rectangle.js
deleted file mode 100644
index 3b439ba..0000000
--- a/test/unit/Rectangle.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Rectangle');
-});
diff --git a/test/unit/Sprite.js b/test/unit/Sprite.js
deleted file mode 100644
index ed4f596..0000000
--- a/test/unit/Sprite.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Sprite');
-});
diff --git a/test/unit/Stage.js b/test/unit/Stage.js
deleted file mode 100644
index 2d70291..0000000
--- a/test/unit/Stage.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Stage');
-});
diff --git a/test/unit/extras/Rope.js b/test/unit/extras/Rope.js
deleted file mode 100644
index 5606f14..0000000
--- a/test/unit/extras/Rope.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Rope');
-});
diff --git a/test/unit/extras/Strip.js b/test/unit/extras/Strip.js
deleted file mode 100644
index 0134d3a..0000000
--- a/test/unit/extras/Strip.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Strip');
-});
diff --git a/test/unit/loaders/AssetLoader.js b/test/unit/loaders/AssetLoader.js
deleted file mode 100644
index 13b8443..0000000
--- a/test/unit/loaders/AssetLoader.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('AssetLoader');
-});
diff --git a/test/unit/loaders/SpriteSheetLoader.js b/test/unit/loaders/SpriteSheetLoader.js
deleted file mode 100644
index 8bf0cb2..0000000
--- a/test/unit/loaders/SpriteSheetLoader.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('SpriteSheetLoader');
-});
diff --git a/test/unit/pixi/InteractionManager.js b/test/unit/pixi/InteractionManager.js
new file mode 100644
index 0000000..ed3001f
--- /dev/null
+++ b/test/unit/pixi/InteractionManager.js
@@ -0,0 +1,10 @@
+describe('pixi/InteractionManager', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var InteractionManager = PIXI.InteractionManager;
+
+ it('Module exists', function () {
+ expect(InteractionManager).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/Pixi.js b/test/unit/pixi/Pixi.js
new file mode 100644
index 0000000..27debc1
--- /dev/null
+++ b/test/unit/pixi/Pixi.js
@@ -0,0 +1,9 @@
+describe('pixi/Pixi', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+
+ it('Module exists', function () {
+ expect(global).to.have.property('PIXI').and.to.be.an('object');
+ });
+});
diff --git a/test/unit/pixi/core/Circle.js b/test/unit/pixi/core/Circle.js
new file mode 100644
index 0000000..93a4456
--- /dev/null
+++ b/test/unit/pixi/core/Circle.js
@@ -0,0 +1,22 @@
+describe('pixi/core/Circle', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Circle = PIXI.Circle;
+
+ it('Module exists', function () {
+ expect(Circle).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Circle();
+
+ expect(obj).to.be.an.instanceof(Circle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', 0);
+ expect(obj).to.have.property('y', 0);
+ expect(obj).to.have.property('radius', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Ellipse.js b/test/unit/pixi/core/Ellipse.js
new file mode 100644
index 0000000..026b56f
--- /dev/null
+++ b/test/unit/pixi/core/Ellipse.js
@@ -0,0 +1,24 @@
+describe('pixi/core/Ellipse', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Ellipse = PIXI.Ellipse;
+
+ it('Module exists', function () {
+ expect(Ellipse).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Ellipse();
+
+ expect(obj).to.be.an.instanceof(Ellipse);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+ expect(obj).to.respondTo('getBounds');
+
+ expect(obj).to.have.property('x', 0);
+ expect(obj).to.have.property('y', 0);
+ expect(obj).to.have.property('width', 0);
+ expect(obj).to.have.property('height', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Matrix.js b/test/unit/pixi/core/Matrix.js
new file mode 100644
index 0000000..b48989e
--- /dev/null
+++ b/test/unit/pixi/core/Matrix.js
@@ -0,0 +1,30 @@
+describe('pixi/core/Matrix', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var mat3 = PIXI.mat3;
+ var mat4 = PIXI.mat4;
+ var Matrix = PIXI.Matrix;
+
+ it('Ensure determineMatrixArrayType works', function () {
+ expect(Matrix).to.be.a('function');
+ });
+
+ it('mat3 exists', function () {
+ expect(mat3).to.be.an('object');
+ });
+
+ it('Confirm new mat3 matrix', function () {
+ var matrix = new mat3.create();
+ pixi_core_Matrix_confirmNewMat3(matrix);
+ });
+
+ it('mat3 exists', function () {
+ expect(mat4).to.be.an('object');
+ });
+
+ it('Confirm new mat4 matrix', function () {
+ var matrix = new mat4.create();
+ pixi_core_Matrix_confirmNewMat4(matrix);
+ });
+});
diff --git a/test/unit/pixi/core/Point.js b/test/unit/pixi/core/Point.js
new file mode 100644
index 0000000..c4d5163
--- /dev/null
+++ b/test/unit/pixi/core/Point.js
@@ -0,0 +1,15 @@
+describe('pixi/core/Point', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Point = PIXI.Point;
+
+ it('Module exists', function () {
+ expect(Point).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Point();
+ pixi_core_Point_confirm(obj, 0, 0);
+ });
+});
diff --git a/test/unit/pixi/core/Polygon.js b/test/unit/pixi/core/Polygon.js
new file mode 100644
index 0000000..dc8c918
--- /dev/null
+++ b/test/unit/pixi/core/Polygon.js
@@ -0,0 +1,20 @@
+describe('pixi/core/Polygon', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Polygon = PIXI.Polygon;
+
+ it('Module exists', function () {
+ expect(Polygon).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Polygon();
+
+ expect(obj).to.be.an.instanceof(Polygon);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.deep.property('points.length', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Rectangle.js b/test/unit/pixi/core/Rectangle.js
new file mode 100644
index 0000000..d43316e
--- /dev/null
+++ b/test/unit/pixi/core/Rectangle.js
@@ -0,0 +1,15 @@
+describe('pixi/core/Rectangle', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Rectangle = PIXI.Rectangle;
+
+ it('Module exists', function () {
+ expect(Rectangle).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var rect = new Rectangle();
+ pixi_core_Rectangle_confirm(rect, 0, 0, 0, 0);
+ });
+});
diff --git a/test/unit/pixi/display/DisplayObject.js b/test/unit/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..40c6fbc
--- /dev/null
+++ b/test/unit/pixi/display/DisplayObject.js
@@ -0,0 +1,21 @@
+describe('pixi/display/DisplayObject', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var DisplayObject = PIXI.DisplayObject;
+
+ it('Module exists', function () {
+ expect(DisplayObject).to.be.a('function');
+ expect(PIXI).to.have.property('visibleCount', 0);
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new DisplayObject();
+
+ pixi_display_DisplayObject_confirmNew(obj);
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', false);
+ expect(obj).to.have.property('stage', null);
+ });
+});
diff --git a/test/unit/pixi/display/DisplayObjectContainer.js b/test/unit/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..ce7f02f
--- /dev/null
+++ b/test/unit/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,20 @@
+describe('pixi/display/DisplayObjectContainer', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var DisplayObjectContainer = PIXI.DisplayObjectContainer;
+
+ it('Module exists', function () {
+ expect(DisplayObjectContainer).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new DisplayObjectContainer();
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', false);
+ expect(obj).to.have.property('stage', null);
+ });
+});
diff --git a/test/unit/pixi/display/MovieClip.js b/test/unit/pixi/display/MovieClip.js
new file mode 100644
index 0000000..f3c6c6a
--- /dev/null
+++ b/test/unit/pixi/display/MovieClip.js
@@ -0,0 +1,33 @@
+describe('pixi/display/MovieClip', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var MovieClip = PIXI.MovieClip;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(MovieClip).to.be.a('function');
+ });
+
+ it('Confirm new instance', function (done) {
+ var texture = Texture.fromImage('/base/test/textures/SpriteSheet-Explosion.png');
+ var obj = new MovieClip([texture]);
+
+ pixi_display_Sprite_confirmNew(obj, done);
+
+ expect(obj).to.be.an.instanceof(MovieClip);
+ expect(obj).to.respondTo('stop');
+ expect(obj).to.respondTo('play');
+ expect(obj).to.respondTo('gotoAndStop');
+ expect(obj).to.respondTo('gotoAndPlay');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('textures.length', 1);
+ expect(obj).to.have.deep.property('textures[0]', texture);
+ expect(obj).to.have.property('animationSpeed', 1);
+ expect(obj).to.have.property('loop', true);
+ expect(obj).to.have.property('onComplete', null);
+ expect(obj).to.have.property('currentFrame', 0);
+ expect(obj).to.have.property('playing', false);
+ });
+});
diff --git a/test/unit/pixi/display/Sprite.js b/test/unit/pixi/display/Sprite.js
new file mode 100644
index 0000000..54e914f
--- /dev/null
+++ b/test/unit/pixi/display/Sprite.js
@@ -0,0 +1,25 @@
+describe('pixi/display/Sprite', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Sprite = PIXI.Sprite;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(Sprite).to.be.a('function');
+ expect(PIXI).to.have.deep.property('blendModes.NORMAL', 0);
+ expect(PIXI).to.have.deep.property('blendModes.SCREEN', 1);
+ });
+
+ it('Members exist', function () {
+ expect(Sprite).itself.to.respondTo('fromImage');
+ expect(Sprite).itself.to.respondTo('fromFrame');
+ });
+
+ it('Confirm new instance', function (done) {
+ var texture = Texture.fromImage('/base/test/textures/SpriteSheet-Aliens.png');
+ var obj = new Sprite(texture);
+
+ pixi_display_Sprite_confirmNew(obj, done);
+ });
+});
diff --git a/test/unit/pixi/display/Stage.js b/test/unit/pixi/display/Stage.js
new file mode 100644
index 0000000..3cc2a4d
--- /dev/null
+++ b/test/unit/pixi/display/Stage.js
@@ -0,0 +1,49 @@
+describe('pixi/display/Stage', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Stage = PIXI.Stage;
+ var InteractionManager = PIXI.InteractionManager;
+ var Rectangle = PIXI.Rectangle;
+
+ it('Module exists', function () {
+ expect(Stage).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Stage(null, true);
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(Stage);
+ expect(obj).to.respondTo('updateTransform');
+ expect(obj).to.respondTo('setBackgroundColor');
+ expect(obj).to.respondTo('getMousePosition');
+
+ // FIXME: duplicate member in DisplayObject
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ // FIXME: convert arg to bool in constructor
+ expect(obj).to.have.property('interactive', true);
+
+ expect(obj).to.have.property('interactionManager')
+ .and.to.be.an.instanceof(InteractionManager)
+ .and.to.have.property('stage', obj);
+
+ expect(obj).to.have.property('dirty', true);
+
+ expect(obj).to.have.property('stage', obj);
+
+ expect(obj).to.have.property('hitArea')
+ .and.to.be.an.instanceof(Rectangle);
+ pixi_core_Rectangle_confirm(obj.hitArea, 0, 0, 100000, 100000);
+
+ expect(obj).to.have.property('backgroundColor', 0x000000);
+ expect(obj).to.have.deep.property('backgroundColorSplit.length', 3);
+ expect(obj).to.have.deep.property('backgroundColorSplit[0]', 0);
+ expect(obj).to.have.deep.property('backgroundColorSplit[1]', 0);
+ expect(obj).to.have.deep.property('backgroundColorSplit[2]', 0);
+ expect(obj).to.have.property('backgroundColorString', '#000000');
+
+ expect(obj).to.have.property('worldVisible', true);
+ });
+});
diff --git a/test/unit/pixi/extras/CustomRenderable.js b/test/unit/pixi/extras/CustomRenderable.js
new file mode 100644
index 0000000..8d83cf0
--- /dev/null
+++ b/test/unit/pixi/extras/CustomRenderable.js
@@ -0,0 +1,21 @@
+describe('pixi/extras/CustomRenderable', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var CustomRenderable = PIXI.CustomRenderable;
+
+ it('Module exists', function () {
+ expect(CustomRenderable).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new CustomRenderable();
+
+ pixi_display_DisplayObject_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(CustomRenderable);
+ expect(obj).to.respondTo('renderCanvas');
+ expect(obj).to.respondTo('initWebGL');
+ expect(obj).to.respondTo('renderWebGL');
+ });
+});
diff --git a/test/unit/pixi/extras/Rope.js b/test/unit/pixi/extras/Rope.js
new file mode 100644
index 0000000..6ddaf83
--- /dev/null
+++ b/test/unit/pixi/extras/Rope.js
@@ -0,0 +1,26 @@
+describe('pixi/extras/Rope', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Rope = PIXI.Rope;
+ var Texture = PIXI.Texture;
+ var Point = PIXI.Point;
+
+ it('Module exists', function () {
+ expect(Rope).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var texture = Texture.fromImage('/base/test/textures/bunny.png');
+ var obj = new Rope(texture, [new Point(), new Point(5, 10), new Point(10, 20)]);
+
+ pixi_extras_Strip_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(Rope);
+ expect(obj).to.respondTo('refresh');
+ expect(obj).to.respondTo('updateTransform');
+ expect(obj).to.respondTo('setTexture');
+
+ // TODO: Test properties
+ });
+});
diff --git a/test/unit/pixi/extras/Spine.js b/test/unit/pixi/extras/Spine.js
new file mode 100644
index 0000000..0708bc0
--- /dev/null
+++ b/test/unit/pixi/extras/Spine.js
@@ -0,0 +1,10 @@
+describe('pixi/extras/Spine', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Spine = PIXI.Spine;
+
+ it('Module exists', function () {
+ expect(Spine).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/extras/Strip.js b/test/unit/pixi/extras/Strip.js
new file mode 100644
index 0000000..8e564e1
--- /dev/null
+++ b/test/unit/pixi/extras/Strip.js
@@ -0,0 +1,18 @@
+describe('pixi/extras/Strip', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Strip = PIXI.Strip;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(Strip).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var texture = Texture.fromImage('/base/test/textures/bunny.png');
+ var obj = new Strip(texture, 20, 10000);
+
+ pixi_extras_Strip_confirmNew(obj);
+ });
+});
diff --git a/test/unit/pixi/extras/TilingSprite.js b/test/unit/pixi/extras/TilingSprite.js
new file mode 100644
index 0000000..56aea14
--- /dev/null
+++ b/test/unit/pixi/extras/TilingSprite.js
@@ -0,0 +1,24 @@
+describe('pixi/extras/TilingSprite', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var TilingSprite = PIXI.TilingSprite;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(TilingSprite).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var texture = Texture.fromImage('/base/test/textures/bunny.png');
+ var obj = new TilingSprite(texture, 6000, 12000);
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(TilingSprite);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ // TODO: Test properties
+ });
+});
diff --git a/test/unit/pixi/filters/FilterBlock.js b/test/unit/pixi/filters/FilterBlock.js
new file mode 100644
index 0000000..870cec0
--- /dev/null
+++ b/test/unit/pixi/filters/FilterBlock.js
@@ -0,0 +1,10 @@
+describe('pixi/filters/FilterBlock', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var FilterBlock = PIXI.FilterBlock;
+
+ it('Module exists', function () {
+ expect(FilterBlock).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/filters/MaskFilter.js b/test/unit/pixi/filters/MaskFilter.js
new file mode 100644
index 0000000..32d6a45
--- /dev/null
+++ b/test/unit/pixi/filters/MaskFilter.js
@@ -0,0 +1,10 @@
+describe('pixi/filters/MaskFilter', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ // var MaskFilter = PIXI.MaskFilter;
+
+ // it('Module exists', function () {
+ // expect(MaskFilter).to.be.a('function');
+ // });
+});
diff --git a/test/unit/pixi/loaders/AssetLoader.js b/test/unit/pixi/loaders/AssetLoader.js
new file mode 100644
index 0000000..a0aa0b5
--- /dev/null
+++ b/test/unit/pixi/loaders/AssetLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/AssetLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var AssetLoader = PIXI.AssetLoader;
+
+ it('Module exists', function () {
+ expect(AssetLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/BitmapFontLoader.js b/test/unit/pixi/loaders/BitmapFontLoader.js
new file mode 100644
index 0000000..6253c42
--- /dev/null
+++ b/test/unit/pixi/loaders/BitmapFontLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/BitmapFontLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var BitmapFontLoader = PIXI.BitmapFontLoader;
+
+ it('Module exists', function () {
+ expect(PIXI.BitmapFontLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/ImageLoader.js b/test/unit/pixi/loaders/ImageLoader.js
new file mode 100644
index 0000000..8b1f556
--- /dev/null
+++ b/test/unit/pixi/loaders/ImageLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/ImageLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var ImageLoader = PIXI.ImageLoader;
+
+ it('Module exists', function () {
+ expect(ImageLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/JsonLoader.js b/test/unit/pixi/loaders/JsonLoader.js
new file mode 100644
index 0000000..c577e83
--- /dev/null
+++ b/test/unit/pixi/loaders/JsonLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/JsonLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var JsonLoader = PIXI.JsonLoader;
+
+ it('Module exists', function () {
+ expect(JsonLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/SpineLoader.js b/test/unit/pixi/loaders/SpineLoader.js
new file mode 100644
index 0000000..fdcc0b8
--- /dev/null
+++ b/test/unit/pixi/loaders/SpineLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/SpineLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var SpineLoader = PIXI.SpineLoader;
+
+ it('Module exists', function () {
+ expect(SpineLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/SpriteSheetLoader.js b/test/unit/pixi/loaders/SpriteSheetLoader.js
new file mode 100644
index 0000000..57beb27
--- /dev/null
+++ b/test/unit/pixi/loaders/SpriteSheetLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/SpriteSheetLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var SpriteSheetLoader = PIXI.SpriteSheetLoader;
+
+ it('Module exists', function () {
+ expect(SpriteSheetLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/primitives/Graphics.js b/test/unit/pixi/primitives/Graphics.js
new file mode 100644
index 0000000..b8b3e5c
--- /dev/null
+++ b/test/unit/pixi/primitives/Graphics.js
@@ -0,0 +1,40 @@
+describe('pixi/primitives/Graphics', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Graphics = PIXI.Graphics;
+
+ it('Module exists', function () {
+ expect(Graphics).to.be.a('function');
+
+ expect(Graphics).itself.to.have.property('POLY', 0);
+ expect(Graphics).itself.to.have.property('RECT', 1);
+ expect(Graphics).itself.to.have.property('CIRC', 2);
+ expect(Graphics).itself.to.have.property('ELIP', 3);
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Graphics();
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(Graphics);
+ expect(obj).to.respondTo('lineStyle');
+ expect(obj).to.respondTo('lineStyle');
+ expect(obj).to.respondTo('moveTo');
+ expect(obj).to.respondTo('lineTo');
+ expect(obj).to.respondTo('beginFill');
+ expect(obj).to.respondTo('endFill');
+ expect(obj).to.respondTo('drawRect');
+ expect(obj).to.respondTo('drawCircle');
+ expect(obj).to.respondTo('drawElipse');
+ expect(obj).to.respondTo('clear');
+
+ expect(obj).to.have.property('renderable', true);
+ expect(obj).to.have.property('fillAlpha', 1);
+ expect(obj).to.have.property('lineWidth', 0);
+ expect(obj).to.have.property('lineColor', 'black');
+ expect(obj).to.have.deep.property('graphicsData.length', 0);
+ expect(obj).to.have.deep.property('currentPath.points.length', 0);
+ });
+});
diff --git a/test/unit/pixi/renderers/canvas/CanvasGraphics.js b/test/unit/pixi/renderers/canvas/CanvasGraphics.js
new file mode 100644
index 0000000..8f44472
--- /dev/null
+++ b/test/unit/pixi/renderers/canvas/CanvasGraphics.js
@@ -0,0 +1,15 @@
+describe('renders/canvas/CanvasGraphics', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var CanvasGraphics = PIXI.CanvasGraphics;
+
+ it('Module exists', function () {
+ expect(CanvasGraphics).to.be.a('function');
+ });
+
+ it('Members exist', function () {
+ expect(CanvasGraphics).itself.to.respondTo('renderGraphics');
+ expect(CanvasGraphics).itself.to.respondTo('renderGraphicsMask');
+ });
+});
diff --git a/test/unit/pixi/renderers/canvas/CanvasRenderer.js b/test/unit/pixi/renderers/canvas/CanvasRenderer.js
new file mode 100644
index 0000000..df3a12f
--- /dev/null
+++ b/test/unit/pixi/renderers/canvas/CanvasRenderer.js
@@ -0,0 +1,10 @@
+describe('renderers/canvas/CanvasRenderer', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var CanvasRenderer = PIXI.CanvasRenderer;
+
+ it('Module exists', function () {
+ expect(CanvasRenderer).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/renderers/webgl/WebGLBatch.js b/test/unit/pixi/renderers/webgl/WebGLBatch.js
new file mode 100644
index 0000000..75efd56
--- /dev/null
+++ b/test/unit/pixi/renderers/webgl/WebGLBatch.js
@@ -0,0 +1,10 @@
+describe('renderers/webgl/WebGLBatch', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var WebGLBatch = PIXI.WebGLBatch;
+
+ it('Module exists', function () {
+ expect(WebGLBatch).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/renderers/webgl/WebGLGraphics.js b/test/unit/pixi/renderers/webgl/WebGLGraphics.js
new file mode 100644
index 0000000..41bf941
--- /dev/null
+++ b/test/unit/pixi/renderers/webgl/WebGLGraphics.js
@@ -0,0 +1,19 @@
+describe('renderers/wegbl/WebGLGraphics', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var WebGLGraphics = PIXI.WebGLGraphics;
+
+ it('Module exists', function () {
+ expect(WebGLGraphics).to.be.a('function');
+ });
+
+ it('Members exist', function () {
+ expect(WebGLGraphics).itself.to.respondTo('renderGraphics');
+ expect(WebGLGraphics).itself.to.respondTo('updateGraphics');
+ expect(WebGLGraphics).itself.to.respondTo('buildRectangle');
+ expect(WebGLGraphics).itself.to.respondTo('buildCircle');
+ expect(WebGLGraphics).itself.to.respondTo('buildLine');
+ expect(WebGLGraphics).itself.to.respondTo('buildPoly');
+ });
+});
diff --git a/test/unit/pixi/renderers/webgl/WebGLRenderGroup.js b/test/unit/pixi/renderers/webgl/WebGLRenderGroup.js
new file mode 100644
index 0000000..f4ee366
--- /dev/null
+++ b/test/unit/pixi/renderers/webgl/WebGLRenderGroup.js
@@ -0,0 +1,10 @@
+describe('renderers/webgl/WebGLRenderGroup', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var WebGLRenderGroup = PIXI.WebGLRenderGroup;
+
+ it('Module exists', function () {
+ expect(WebGLRenderGroup).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/renderers/webgl/WebGLRenderer.js b/test/unit/pixi/renderers/webgl/WebGLRenderer.js
new file mode 100644
index 0000000..86533eb
--- /dev/null
+++ b/test/unit/pixi/renderers/webgl/WebGLRenderer.js
@@ -0,0 +1,10 @@
+describe('renderers/webgl/WebGLRenderer', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var WebGLRenderer = PIXI.WebGLRenderer;
+
+ it('Module exists', function () {
+ expect(WebGLRenderer).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/renderers/webgl/WebGLShaders.js b/test/unit/pixi/renderers/webgl/WebGLShaders.js
new file mode 100644
index 0000000..2872de8
--- /dev/null
+++ b/test/unit/pixi/renderers/webgl/WebGLShaders.js
@@ -0,0 +1,13 @@
+describe('renderers/webgl/WebGLShaders', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+
+ it('Module members exist', function () {
+ expect(PIXI).to.respondTo('initPrimitiveShader');
+ expect(PIXI).to.respondTo('initDefaultShader');
+ expect(PIXI).to.respondTo('initDefaultStripShader');
+ expect(PIXI).to.respondTo('activateDefaultShader');
+ expect(PIXI).to.respondTo('activatePrimitiveShader');
+ });
+});
diff --git a/test/unit/pixi/text/BitmapText.js b/test/unit/pixi/text/BitmapText.js
new file mode 100644
index 0000000..9388e3d
--- /dev/null
+++ b/test/unit/pixi/text/BitmapText.js
@@ -0,0 +1,10 @@
+describe('pixi/text/BitmapText', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var BitmapText = PIXI.BitmapText;
+
+ it('Module exists', function () {
+ expect(BitmapText).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/text/Text.js b/test/unit/pixi/text/Text.js
new file mode 100644
index 0000000..9bc9ac5
--- /dev/null
+++ b/test/unit/pixi/text/Text.js
@@ -0,0 +1,10 @@
+describe('pixi/text/Text', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Text = PIXI.Text;
+
+ it('Module exists', function () {
+ expect(Text).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/textures/BaseTexture.js b/test/unit/pixi/textures/BaseTexture.js
new file mode 100644
index 0000000..e34b64c
--- /dev/null
+++ b/test/unit/pixi/textures/BaseTexture.js
@@ -0,0 +1,13 @@
+describe('pixi/textures/BaseTexture', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var BaseTexture = PIXI.BaseTexture;
+
+ it('Module exists', function () {
+ expect(BaseTexture).to.be.a('function');
+ expect(PIXI).to.have.property('BaseTextureCache').and.to.be.an('object');
+ expect(PIXI).to.have.deep.property('texturesToUpdate.length');
+ expect(PIXI).to.have.deep.property('texturesToDestroy.length', 0);
+ });
+});
diff --git a/test/unit/pixi/textures/RenderTexture.js b/test/unit/pixi/textures/RenderTexture.js
new file mode 100644
index 0000000..4a69b44
--- /dev/null
+++ b/test/unit/pixi/textures/RenderTexture.js
@@ -0,0 +1,10 @@
+describe('pixi/textures/RenderTexture', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var RenderTexture = PIXI.RenderTexture;
+
+ it('Module exists', function () {
+ expect(RenderTexture).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/textures/Texture.js b/test/unit/pixi/textures/Texture.js
new file mode 100644
index 0000000..adb2875
--- /dev/null
+++ b/test/unit/pixi/textures/Texture.js
@@ -0,0 +1,26 @@
+describe('pixi/textures/Texture', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(Texture).to.be.a('function');
+ expect(PIXI).to.have.property('TextureCache').and.to.be.an('object');
+ });
+
+ it('Members exist', function () {
+ expect(Texture).itself.to.respondTo('fromImage');
+ expect(Texture).itself.to.respondTo('fromFrame');
+ expect(Texture).itself.to.respondTo('fromCanvas');
+ expect(Texture).itself.to.respondTo('addTextureToCache');
+ expect(Texture).itself.to.respondTo('removeTextureFromCache');
+
+ expect(Texture).itself.to.have.deep.property('frameUpdates.length', 0);
+ });
+
+ it('Confirm new instance', function (done) {
+ var texture = Texture.fromImage('/base/test/textures/bunny.png');
+ pixi_textures_Texture_confirmNew(texture, done);
+ });
+});
diff --git a/.gitignore b/.gitignore
index 12e1b62..0b88317 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
node_modules
.DS_Store
-.project
\ No newline at end of file
+.project
+*.log
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..63e4d7c
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,8 @@
+language: node_js
+node_js:
+ - 0.10
+
+before_script:
+ - npm install -g grunt-cli
+ - export DISPLAY=:99.0
+ - sh -e /etc/init.d/xvfb start
diff --git a/Gruntfile.js b/Gruntfile.js
index b083b49..103938c 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -1,10 +1,12 @@
+'use strict';
+
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-connect');
- grunt.loadNpmTasks('grunt-contrib-qunit');
grunt.loadNpmTasks('grunt-contrib-yuidoc');
+ grunt.loadTasks('tasks');
var root = 'src/pixi/',
debug = 'bin/pixi.dev.js',
@@ -79,7 +81,7 @@
},
files: {
srcBlob: '<%= dirs.src %>/**/*.js',
- testBlob: '<%= dirs.test %>/unit/**/*.js',
+ testBlob: '<%= dirs.test %>/{functional,lib/pixi,unit}/**/*.js',
build: '<%= dirs.build %>/pixi.dev.js',
buildMin: '<%= dirs.build %>/pixi.js'
},
@@ -94,7 +96,12 @@
},
jshint: {
beforeconcat: srcFiles,
- test: ['<%= files.testBlob %>'],
+ test: {
+ src: ['<%= files.testBlob %>'],
+ options: {
+ expr: true
+ }
+ },
options: {
asi: true,
smarttabs: true
@@ -128,12 +135,6 @@
]
},
connect: {
- qunit: {
- options: {
- port: grunt.option('port-test') || 9002,
- base: './'
- }
- },
test: {
options: {
port: grunt.option('port-test') || 9002,
@@ -142,13 +143,6 @@
}
}
},
- qunit: {
- all: {
- options: {
- urls: ['http://localhost:' + (grunt.option('port-test') || 9002) + '/test/index.html']
- }
- }
- },
yuidoc: {
compile: {
name: '<%= pkg.name %>',
@@ -161,6 +155,13 @@
outdir: '<%= dirs.docs %>'
}
}
+ },
+ karma: {
+ unit: {
+ configFile: 'test/karma.conf.js',
+ // browsers: ['Chrome'],
+ singleRun: true
+ }
}
});
@@ -182,9 +183,10 @@
}
)
- grunt.registerTask('default', ['concat', 'uglify', 'distribute']);
grunt.registerTask('build', ['concat', 'uglify', 'distribute']);
- grunt.registerTask('test', ['build', 'connect:qunit', 'qunit']);
+ grunt.registerTask('test', ['concat', 'jshint:test', 'karma']);
grunt.registerTask('docs', ['yuidoc']);
-
-}
\ No newline at end of file
+ grunt.registerTask('default', ['test', 'uglify', 'distribute']);
+ // Travis CI task.
+ grunt.registerTask('travis', ['test']);
+}
diff --git a/README.md b/README.md
index c62ef86..690cfe4 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,8 @@

+[](http://travis-ci.org/drkibitz/pixi.js)
+
#### JavaScript 2D Renderer ####
The aim of this project is to provide a fast lightweight 2D library that works
diff --git a/package.json b/package.json
index b373240..1246a68 100644
--- a/package.json
+++ b/package.json
@@ -18,14 +18,21 @@
"main": "bin/pixi.js",
+ "scripts": {
+ "test": "grunt travis --verbose"
+ },
+
"dependencies": {},
"devDependencies": {
"grunt": "~0.4.x",
- "grunt-contrib-jshint": "0.3.x",
+ "grunt-contrib-jshint": "0.6.x",
"grunt-contrib-uglify": "0.2.x",
- "grunt-contrib-connect": "0.2.x",
- "grunt-contrib-qunit": "0.2.x",
+ "grunt-contrib-connect": "0.3.x",
"grunt-contrib-yuidoc": "0.4.x",
- "grunt-contrib-concat": "0.1.x"
+ "grunt-contrib-concat": "0.3.x",
+ "chai": "~1.7.0",
+ "karma": "0.11.0",
+ "karma-firefox-launcher": "0.1.0",
+ "karma-mocha": "0.1.0"
}
}
diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js
index a7c520e..ee82bbd 100644
--- a/src/pixi/InteractionManager.js
+++ b/src/pixi/InteractionManager.js
@@ -62,7 +62,6 @@
this.onTouchEnd = this.onTouchEnd.bind(this);
this.onTouchMove = this.onTouchMove.bind(this);
-
this.last = 0;
}
diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js
index 1a95d20..eef1059 100644
--- a/src/pixi/core/Ellipse.js
+++ b/src/pixi/core/Ellipse.js
@@ -78,7 +78,7 @@
return (normx + normy < 0.25);
}
-PIXI.Ellipse.getBounds = function()
+PIXI.Ellipse.prototype.getBounds = function()
{
return new PIXI.Rectangle(this.x, this.y, this.width, this.height);
}
diff --git a/tasks/karma.js b/tasks/karma.js
new file mode 100644
index 0000000..c340485
--- /dev/null
+++ b/tasks/karma.js
@@ -0,0 +1,27 @@
+'use strict';
+
+var path = require('path');
+var server = require('karma').server;
+
+module.exports = function (grunt) {
+ grunt.registerMultiTask('karma', 'run karma.', function() {
+ var done = this.async();
+ var options = this.options({
+ background: false
+ });
+ var data = this.data;
+
+ //merge options onto data, with data taking precedence
+ data = grunt.util._.merge(options, data);
+ data.configFile = path.resolve(data.configFile);
+ if (data.configFile) {
+ data.configFile = grunt.template.process(data.configFile);
+ }
+
+ server.start(
+ data,
+ function(code) {
+ done(!code);
+ });
+ });
+};
diff --git a/test/functional/example-1-basics/bunny.png b/test/functional/example-1-basics/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/functional/example-1-basics/bunny.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-30.png b/test/functional/example-1-basics/frame-30.png
new file mode 100644
index 0000000..96e3409
--- /dev/null
+++ b/test/functional/example-1-basics/frame-30.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-60.png b/test/functional/example-1-basics/frame-60.png
new file mode 100644
index 0000000..af3f4ce
--- /dev/null
+++ b/test/functional/example-1-basics/frame-60.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-90.png b/test/functional/example-1-basics/frame-90.png
new file mode 100644
index 0000000..099b823
--- /dev/null
+++ b/test/functional/example-1-basics/frame-90.png
Binary files differ
diff --git a/test/functional/example-1-basics/index.js b/test/functional/example-1-basics/index.js
new file mode 100644
index 0000000..7ae7a98
--- /dev/null
+++ b/test/functional/example-1-basics/index.js
@@ -0,0 +1,133 @@
+describe('Example 1 - Basics', function () {
+ 'use strict';
+
+ var baseUri = '/base/test/functional/example-1-basics';
+ var expect = chai.expect;
+ var currentFrame = 0;
+ var frameEvents = {};
+ var stage;
+ var renderer;
+ var bunny;
+
+ function onFrame(frame, callback) {
+ frameEvents[frame] = callback;
+ }
+
+ function animate() {
+ currentFrame += 1;
+
+ requestAnimFrame( animate );
+
+ // just for fun, lets rotate mr rabbit a little
+ bunny.rotation += 0.1;
+
+ // render the stage
+ renderer.render(stage);
+
+ if (frameEvents[currentFrame])
+ frameEvents[currentFrame](currentFrame);
+ }
+
+ function initScene() {
+ // create an new instance of a pixi stage
+ stage = new PIXI.Stage(0x66FF99);
+
+ // create a renderer instance
+ renderer = PIXI.autoDetectRenderer(400, 300);
+ console.log('Is PIXI.WebGLRenderer: ' + (renderer instanceof PIXI.WebGLRenderer));
+
+ // add the renderer view element to the DOM
+ document.body.appendChild(renderer.view);
+
+ requestAnimFrame( animate );
+
+ // create a texture from an image path
+ var texture = PIXI.Texture.fromImage(baseUri + "/bunny.png");
+ // create a new Sprite using the texture
+ bunny = new PIXI.Sprite(texture);
+
+ // center the sprites anchor point
+ bunny.anchor.x = 0.5;
+ bunny.anchor.y = 0.5;
+
+ // move the sprite t the center of the screen
+ bunny.position.x = 200;
+ bunny.position.y = 150;
+
+ stage.addChild(bunny);
+ }
+
+ it('assets loaded', function (done) {
+ var loader = new PIXI.AssetLoader([
+ baseUri + '/bunny.png',
+ baseUri + '/frame-30.png',
+ baseUri + '/frame-60.png',
+ baseUri + '/frame-90.png'
+ ]);
+ // loader.on('onProgress', function (event) {
+ // console.log(event.content);
+ // });
+ loader.on('onComplete', function (event) {
+ done();
+ initScene();
+ });
+ loader.load();
+ });
+
+ it('frame 30 should match', function (done) {
+ this.timeout(700);
+ onFrame(30, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-30.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 60 should match', function (done) {
+ this.timeout(1200);
+ onFrame(60, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-60.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 90 should match', function (done) {
+ this.timeout(1700);
+ onFrame(90, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-90.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ // it('capture something', function (done) {
+ // this.timeout(2000000);
+ // onFrame(30, function () {
+ // var img = new Image();
+ // img.src = renderer.view.toDataURL('image/png');
+ // document.body.appendChild(img);
+ // });
+ // });
+});
diff --git a/test/index.html b/test/index.html
deleted file mode 100644
index 9cbcac5..0000000
--- a/test/index.html
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
- Pixi.js Test Suite
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/test/karma.conf.js b/test/karma.conf.js
new file mode 100644
index 0000000..c66a696
--- /dev/null
+++ b/test/karma.conf.js
@@ -0,0 +1,82 @@
+module.exports = function(config) {
+ config.set({
+
+ // base path, that will be used to resolve files and exclude
+ basePath : '../',
+
+ frameworks : ['mocha'],
+
+ // list of files / patterns to load in the browser
+ files : [
+ 'node_modules/chai/chai.js',
+ 'bin/pixi.dev.js',
+ 'test/lib/**/*.js',
+ 'test/unit/**/*.js',
+ // 'test/functional/**/*.js',
+ {pattern: 'test/**/*.png', watched: false, included: false, served: true}
+ ],
+
+ // list of files to exclude
+ exclude : [],
+
+ // use dolts reporter, as travis terminal does not support escaping sequences
+ // possible values: 'dots', 'progress', 'junit', 'teamcity'
+ // CLI --reporters progress
+ reporters : ['progress'],
+
+ // web server port
+ // CLI --port 9876
+ port : 9876,
+
+ // cli runner port
+ // CLI --runner-port 9100
+ runnerPort : 9100,
+
+ // enable / disable colors in the output (reporters and logs)
+ // CLI --colors --no-colors
+ colors : true,
+
+ // level of logging
+ // possible values: karma.LOG_DISABLE || karma.LOG_ERROR || karma.LOG_WARN || karma.LOG_INFO || karma.LOG_DEBUG
+ // CLI --log-level debug
+ logLevel : config.LOG_DEBUG,
+
+ // enable / disable watching file and executing tests whenever any file changes
+ // CLI --auto-watch --no-auto-watch
+ autoWatch : false,
+
+ // Start these browsers, currently available:
+ // - Chrome
+ // - ChromeCanary
+ // - Firefox
+ // - Opera
+ // - Safari (only Mac)
+ // - PhantomJS
+ // - IE (only Windows)
+ // CLI --browsers Chrome,Firefox,Safari
+ browsers : ['Firefox'],
+
+ // If browser does not capture in given timeout [ms], kill it
+ // CLI --capture-timeout 5000
+ captureTimeout : 5000,
+
+ // Auto run tests on start (when browsers are captured) and exit
+ // CLI --single-run --no-single-run
+ singleRun : true,
+
+ // report which specs are slower than 500ms
+ // CLI --report-slower-than 500
+ reportSlowerThan : 1000,
+
+ preprocessors : {
+ // '**/client/js/*.js': 'coverage'
+ },
+
+ plugins : [
+ 'karma-mocha',
+ // 'karma-chrome-launcher',
+ 'karma-firefox-launcher',
+ // 'karma-phantomjs-launcher'
+ ]
+ });
+};
diff --git a/test/lib/pixi/core/Matrix.js b/test/lib/pixi/core/Matrix.js
new file mode 100644
index 0000000..d26386b
--- /dev/null
+++ b/test/lib/pixi/core/Matrix.js
@@ -0,0 +1,40 @@
+
+function pixi_core_Matrix_confirmNewMat3(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(1);
+ expect(matrix[5]).to.equal(0);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(1);
+}
+
+function pixi_core_Matrix_confirmNewMat4(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[0]).to.equal(1);
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(0);
+ expect(matrix[5]).to.equal(1);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(0);
+ expect(matrix[9]).to.equal(0);
+ expect(matrix[10]).to.equal(1);
+ expect(matrix[11]).to.equal(0);
+ expect(matrix[12]).to.equal(0);
+ expect(matrix[13]).to.equal(0);
+ expect(matrix[14]).to.equal(0);
+ expect(matrix[15]).to.equal(1);
+}
diff --git a/test/lib/pixi/core/Point.js b/test/lib/pixi/core/Point.js
new file mode 100644
index 0000000..e5df07b
--- /dev/null
+++ b/test/lib/pixi/core/Point.js
@@ -0,0 +1,10 @@
+
+function pixi_core_Point_confirm(obj, x, y) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Point);
+ expect(obj).to.respondTo('clone');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+}
diff --git a/test/lib/pixi/core/Rectangle.js b/test/lib/pixi/core/Rectangle.js
new file mode 100644
index 0000000..23f0d12
--- /dev/null
+++ b/test/lib/pixi/core/Rectangle.js
@@ -0,0 +1,13 @@
+
+function pixi_core_Rectangle_confirm(obj, x, y, width, height) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Rectangle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+ expect(obj).to.have.property('width', width);
+ expect(obj).to.have.property('height', height);
+}
diff --git a/test/lib/pixi/display/DisplayObject.js b/test/lib/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..1388a7f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObject.js
@@ -0,0 +1,43 @@
+
+function pixi_display_DisplayObject_confirmNew(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObject);
+ expect(obj).to.respondTo('setInteractive');
+ expect(obj).to.respondTo('addFilter');
+ expect(obj).to.respondTo('removeFilter');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.property('last', obj);
+ expect(obj).to.have.property('first', obj);
+
+ expect(obj).to.contain.property('position');
+ pixi_core_Point_confirm(obj.position, 0, 0);
+ expect(obj).to.contain.property('scale');
+ pixi_core_Point_confirm(obj.scale, 1, 1);
+ expect(obj).to.contain.property('pivot');
+ pixi_core_Point_confirm(obj.pivot, 0, 0);
+
+ expect(obj).to.have.property('rotation', 0);
+ expect(obj).to.have.property('alpha', 1);
+ expect(obj).to.have.property('visible', true);
+ expect(obj).to.have.property('buttonMode', false);
+ expect(obj).to.have.property('parent', null);
+ expect(obj).to.have.property('worldAlpha', 1);
+
+ expect(obj).to.have.property('hitArea');
+ expect(obj).to.have.property('interactive'); // TODO: Have a better default value
+ expect('mask' in obj).to.be.true; // TODO: Have a better default value
+ expect(obj.mask).to.be.undefined;
+
+ expect(obj).to.have.property('renderable');
+ expect(obj).to.have.property('stage');
+
+ expect(obj).to.have.deep.property('worldTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ expect(obj).to.have.deep.property('localTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.localTransform);
+
+ expect(obj).to.have.deep.property('color.length', 0);
+ expect(obj).to.have.property('dynamic', true);
+}
diff --git a/test/lib/pixi/display/DisplayObjectContainer.js b/test/lib/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..085c59f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,16 @@
+
+function pixi_display_DisplayObjectContainer_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObject_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObjectContainer);
+ expect(obj).to.respondTo('addChild');
+ expect(obj).to.respondTo('addChildAt');
+ expect(obj).to.respondTo('swapChildren');
+ expect(obj).to.respondTo('getChildAt');
+ expect(obj).to.respondTo('removeChild');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('children.length', 0);
+}
diff --git a/test/lib/pixi/display/Sprite.js b/test/lib/pixi/display/Sprite.js
new file mode 100644
index 0000000..cc7a2d6
--- /dev/null
+++ b/test/lib/pixi/display/Sprite.js
@@ -0,0 +1,28 @@
+
+function pixi_display_Sprite_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Sprite);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', true);
+ expect(obj).to.have.property('stage', null);
+
+ expect(obj).to.have.property('anchor');
+ pixi_core_Point_confirm(obj.anchor, 0, 0);
+
+ expect(obj).to.have.property('blendMode', PIXI.blendModes.NORMAL);
+ expect(obj).to.have.property('width', 1); // TODO: is 1 expected
+ expect(obj).to.have.property('height', 1); // TODO: is 1 expected
+
+ // FIXME: Just make this a boolean that is always there
+ expect(!!obj.updateFrame).to.equal(obj.texture.baseTexture.hasLoaded);
+
+ expect(obj).to.have.property('texture');
+ pixi_textures_Texture_confirmNew(obj.texture, done);
+}
diff --git a/test/lib/pixi/extras/Strip.js b/test/lib/pixi/extras/Strip.js
new file mode 100644
index 0000000..8927a8a
--- /dev/null
+++ b/test/lib/pixi/extras/Strip.js
@@ -0,0 +1,12 @@
+
+function pixi_extras_Strip_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Strip);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ // TODO: Test properties
+}
diff --git a/test/lib/pixi/textures/Texture.js b/test/lib/pixi/textures/Texture.js
new file mode 100644
index 0000000..d5867b6
--- /dev/null
+++ b/test/lib/pixi/textures/Texture.js
@@ -0,0 +1,31 @@
+
+function pixi_textures_Texture_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ function confirmFrameDone() {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, obj.baseTexture.width, obj.baseTexture.height);
+
+ expect(obj).to.have.property('width', obj.baseTexture.width);
+ expect(obj).to.have.property('height', obj.baseTexture.height);
+ done();
+ }
+
+ expect(obj).to.be.an.instanceof(PIXI.Texture);
+ pixi_utils_EventTarget_like(obj);
+
+ expect(obj).to.have.property('baseTexture')
+ .and.to.be.an.instanceof(PIXI.BaseTexture);
+
+ expect(obj).to.have.property('scope', obj);
+
+ expect(obj).to.have.property('trim');
+ pixi_core_Point_confirm(obj.trim, 0, 0);
+
+ expect(obj).to.have.property('frame');
+ if (obj.baseTexture.hasLoaded) {
+ confirmFrameDone();
+ } else {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, 1, 1);
+ obj.addEventListener('update', confirmFrameDone);
+ }
+}
diff --git a/test/lib/pixi/utils/EventTarget.js b/test/lib/pixi/utils/EventTarget.js
new file mode 100644
index 0000000..7b1dcfa
--- /dev/null
+++ b/test/lib/pixi/utils/EventTarget.js
@@ -0,0 +1,8 @@
+
+function pixi_utils_EventTarget_like(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.respondTo('addEventListener');
+ expect(obj).to.respondTo('dispatchEvent');
+ expect(obj).to.respondTo('removeEventListener');
+}
diff --git a/test/lib/qunit-1.11.0.css b/test/lib/qunit-1.11.0.css
deleted file mode 100644
index d7fc0c8..0000000
--- a/test/lib/qunit-1.11.0.css
+++ /dev/null
@@ -1,244 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-/** Font Family and Sizes */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
- font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
-}
-
-#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
-#qunit-tests { font-size: smaller; }
-
-
-/** Resets */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter {
- margin: 0;
- padding: 0;
-}
-
-
-/** Header */
-
-#qunit-header {
- padding: 0.5em 0 0.5em 1em;
-
- color: #8699a4;
- background-color: #0d3349;
-
- font-size: 1.5em;
- line-height: 1em;
- font-weight: normal;
-
- border-radius: 5px 5px 0 0;
- -moz-border-radius: 5px 5px 0 0;
- -webkit-border-top-right-radius: 5px;
- -webkit-border-top-left-radius: 5px;
-}
-
-#qunit-header a {
- text-decoration: none;
- color: #c2ccd1;
-}
-
-#qunit-header a:hover,
-#qunit-header a:focus {
- color: #fff;
-}
-
-#qunit-testrunner-toolbar label {
- display: inline-block;
- padding: 0 .5em 0 .1em;
-}
-
-#qunit-banner {
- height: 5px;
-}
-
-#qunit-testrunner-toolbar {
- padding: 0.5em 0 0.5em 2em;
- color: #5E740B;
- background-color: #eee;
- overflow: hidden;
-}
-
-#qunit-userAgent {
- padding: 0.5em 0 0.5em 2.5em;
- background-color: #2b81af;
- color: #fff;
- text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
-}
-
-#qunit-modulefilter-container {
- float: right;
-}
-
-/** Tests: Pass/Fail */
-
-#qunit-tests {
- list-style-position: inside;
-}
-
-#qunit-tests li {
- padding: 0.4em 0.5em 0.4em 2.5em;
- border-bottom: 1px solid #fff;
- list-style-position: inside;
-}
-
-#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running {
- display: none;
-}
-
-#qunit-tests li strong {
- cursor: pointer;
-}
-
-#qunit-tests li a {
- padding: 0.5em;
- color: #c2ccd1;
- text-decoration: none;
-}
-#qunit-tests li a:hover,
-#qunit-tests li a:focus {
- color: #000;
-}
-
-#qunit-tests li .runtime {
- float: right;
- font-size: smaller;
-}
-
-.qunit-assert-list {
- margin-top: 0.5em;
- padding: 0.5em;
-
- background-color: #fff;
-
- border-radius: 5px;
- -moz-border-radius: 5px;
- -webkit-border-radius: 5px;
-}
-
-.qunit-collapsed {
- display: none;
-}
-
-#qunit-tests table {
- border-collapse: collapse;
- margin-top: .2em;
-}
-
-#qunit-tests th {
- text-align: right;
- vertical-align: top;
- padding: 0 .5em 0 0;
-}
-
-#qunit-tests td {
- vertical-align: top;
-}
-
-#qunit-tests pre {
- margin: 0;
- white-space: pre-wrap;
- word-wrap: break-word;
-}
-
-#qunit-tests del {
- background-color: #e0f2be;
- color: #374e0c;
- text-decoration: none;
-}
-
-#qunit-tests ins {
- background-color: #ffcaca;
- color: #500;
- text-decoration: none;
-}
-
-/*** Test Counts */
-
-#qunit-tests b.counts { color: black; }
-#qunit-tests b.passed { color: #5E740B; }
-#qunit-tests b.failed { color: #710909; }
-
-#qunit-tests li li {
- padding: 5px;
- background-color: #fff;
- border-bottom: none;
- list-style-position: inside;
-}
-
-/*** Passing Styles */
-
-#qunit-tests li li.pass {
- color: #3c510c;
- background-color: #fff;
- border-left: 10px solid #C6E746;
-}
-
-#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
-#qunit-tests .pass .test-name { color: #366097; }
-
-#qunit-tests .pass .test-actual,
-#qunit-tests .pass .test-expected { color: #999999; }
-
-#qunit-banner.qunit-pass { background-color: #C6E746; }
-
-/*** Failing Styles */
-
-#qunit-tests li li.fail {
- color: #710909;
- background-color: #fff;
- border-left: 10px solid #EE5757;
- white-space: pre;
-}
-
-#qunit-tests > li:last-child {
- border-radius: 0 0 5px 5px;
- -moz-border-radius: 0 0 5px 5px;
- -webkit-border-bottom-right-radius: 5px;
- -webkit-border-bottom-left-radius: 5px;
-}
-
-#qunit-tests .fail { color: #000000; background-color: #EE5757; }
-#qunit-tests .fail .test-name,
-#qunit-tests .fail .module-name { color: #000000; }
-
-#qunit-tests .fail .test-actual { color: #EE5757; }
-#qunit-tests .fail .test-expected { color: green; }
-
-#qunit-banner.qunit-fail { background-color: #EE5757; }
-
-
-/** Result */
-
-#qunit-testresult {
- padding: 0.5em 0.5em 0.5em 2.5em;
-
- color: #2b81af;
- background-color: #D2E0E6;
-
- border-bottom: 1px solid white;
-}
-#qunit-testresult .module-name {
- font-weight: bold;
-}
-
-/** Fixture */
-
-#qunit-fixture {
- position: absolute;
- top: -10000px;
- left: -10000px;
- width: 1000px;
- height: 1000px;
-}
diff --git a/test/lib/qunit-1.11.0.js b/test/lib/qunit-1.11.0.js
deleted file mode 100644
index 302545f..0000000
--- a/test/lib/qunit-1.11.0.js
+++ /dev/null
@@ -1,2152 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-(function( window ) {
-
-var QUnit,
- assert,
- config,
- onErrorFnPrev,
- testId = 0,
- fileName = (sourceFromStacktrace( 0 ) || "" ).replace(/(:\d+)+\)?/, "").replace(/.+\//, ""),
- toString = Object.prototype.toString,
- hasOwn = Object.prototype.hasOwnProperty,
- // Keep a local reference to Date (GH-283)
- Date = window.Date,
- defined = {
- setTimeout: typeof window.setTimeout !== "undefined",
- sessionStorage: (function() {
- var x = "qunit-test-string";
- try {
- sessionStorage.setItem( x, x );
- sessionStorage.removeItem( x );
- return true;
- } catch( e ) {
- return false;
- }
- }())
- },
- /**
- * Provides a normalized error string, correcting an issue
- * with IE 7 (and prior) where Error.prototype.toString is
- * not properly implemented
- *
- * Based on http://es5.github.com/#x15.11.4.4
- *
- * @param {String|Error} error
- * @return {String} error message
- */
- errorString = function( error ) {
- var name, message,
- errorString = error.toString();
- if ( errorString.substring( 0, 7 ) === "[object" ) {
- name = error.name ? error.name.toString() : "Error";
- message = error.message ? error.message.toString() : "";
- if ( name && message ) {
- return name + ": " + message;
- } else if ( name ) {
- return name;
- } else if ( message ) {
- return message;
- } else {
- return "Error";
- }
- } else {
- return errorString;
- }
- },
- /**
- * Makes a clone of an object using only Array or Object as base,
- * and copies over the own enumerable properties.
- *
- * @param {Object} obj
- * @return {Object} New object with only the own properties (recursively).
- */
- objectValues = function( obj ) {
- // Grunt 0.3.x uses an older version of jshint that still has jshint/jshint#392.
- /*jshint newcap: false */
- var key, val,
- vals = QUnit.is( "array", obj ) ? [] : {};
- for ( key in obj ) {
- if ( hasOwn.call( obj, key ) ) {
- val = obj[key];
- vals[key] = val === Object(val) ? objectValues(val) : val;
- }
- }
- return vals;
- };
-
-function Test( settings ) {
- extend( this, settings );
- this.assertions = [];
- this.testNumber = ++Test.count;
-}
-
-Test.count = 0;
-
-Test.prototype = {
- init: function() {
- var a, b, li,
- tests = id( "qunit-tests" );
-
- if ( tests ) {
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml;
-
- // `a` initialized at top of scope
- a = document.createElement( "a" );
- a.innerHTML = "Rerun";
- a.href = QUnit.url({ testNumber: this.testNumber });
-
- li = document.createElement( "li" );
- li.appendChild( b );
- li.appendChild( a );
- li.className = "running";
- li.id = this.id = "qunit-test-output" + testId++;
-
- tests.appendChild( li );
- }
- },
- setup: function() {
- if ( this.module !== config.previousModule ) {
- if ( config.previousModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.previousModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
- config.previousModule = this.module;
- config.moduleStats = { all: 0, bad: 0 };
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- } else if ( config.autorun ) {
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- }
-
- config.current = this;
-
- this.testEnvironment = extend({
- setup: function() {},
- teardown: function() {}
- }, this.moduleTestEnvironment );
-
- this.started = +new Date();
- runLoggingCallbacks( "testStart", QUnit, {
- name: this.testName,
- module: this.module
- });
-
- // allow utility functions to access the current test environment
- // TODO why??
- QUnit.current_testEnvironment = this.testEnvironment;
-
- if ( !config.pollution ) {
- saveGlobal();
- }
- if ( config.notrycatch ) {
- this.testEnvironment.setup.call( this.testEnvironment );
- return;
- }
- try {
- this.testEnvironment.setup.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Setup failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- },
- run: function() {
- config.current = this;
-
- var running = id( "qunit-testresult" );
-
- if ( running ) {
- running.innerHTML = "Running:
" + this.nameHtml;
- }
-
- if ( this.async ) {
- QUnit.stop();
- }
-
- this.callbackStarted = +new Date();
-
- if ( config.notrycatch ) {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- return;
- }
-
- try {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- } catch( e ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
-
- QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + " " + this.stack + ": " + ( e.message || e ), extractStacktrace( e, 0 ) );
- // else next test will carry the responsibility
- saveGlobal();
-
- // Restart the tests if they're blocking
- if ( config.blocking ) {
- QUnit.start();
- }
- }
- },
- teardown: function() {
- config.current = this;
- if ( config.notrycatch ) {
- if ( typeof this.callbackRuntime === "undefined" ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
- }
- this.testEnvironment.teardown.call( this.testEnvironment );
- return;
- } else {
- try {
- this.testEnvironment.teardown.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Teardown failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- }
- checkPollution();
- },
- finish: function() {
- config.current = this;
- if ( config.requireExpects && this.expected === null ) {
- QUnit.pushFailure( "Expected number of assertions to be defined, but expect() was not called.", this.stack );
- } else if ( this.expected !== null && this.expected !== this.assertions.length ) {
- QUnit.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack );
- } else if ( this.expected === null && !this.assertions.length ) {
- QUnit.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions.", this.stack );
- }
-
- var i, assertion, a, b, time, li, ol,
- test = this,
- good = 0,
- bad = 0,
- tests = id( "qunit-tests" );
-
- this.runtime = +new Date() - this.started;
- config.stats.all += this.assertions.length;
- config.moduleStats.all += this.assertions.length;
-
- if ( tests ) {
- ol = document.createElement( "ol" );
- ol.className = "qunit-assert-list";
-
- for ( i = 0; i < this.assertions.length; i++ ) {
- assertion = this.assertions[i];
-
- li = document.createElement( "li" );
- li.className = assertion.result ? "pass" : "fail";
- li.innerHTML = assertion.message || ( assertion.result ? "okay" : "failed" );
- ol.appendChild( li );
-
- if ( assertion.result ) {
- good++;
- } else {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
-
- // store result when possible
- if ( QUnit.config.reorder && defined.sessionStorage ) {
- if ( bad ) {
- sessionStorage.setItem( "qunit-test-" + this.module + "-" + this.testName, bad );
- } else {
- sessionStorage.removeItem( "qunit-test-" + this.module + "-" + this.testName );
- }
- }
-
- if ( bad === 0 ) {
- addClass( ol, "qunit-collapsed" );
- }
-
- // `b` initialized at top of scope
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml + " (" + bad + ", " + good + ", " + this.assertions.length + ")";
-
- addEvent(b, "click", function() {
- var next = b.parentNode.lastChild,
- collapsed = hasClass( next, "qunit-collapsed" );
- ( collapsed ? removeClass : addClass )( next, "qunit-collapsed" );
- });
-
- addEvent(b, "dblclick", function( e ) {
- var target = e && e.target ? e.target : window.event.srcElement;
- if ( target.nodeName.toLowerCase() === "span" || target.nodeName.toLowerCase() === "b" ) {
- target = target.parentNode;
- }
- if ( window.location && target.nodeName.toLowerCase() === "strong" ) {
- window.location = QUnit.url({ testNumber: test.testNumber });
- }
- });
-
- // `time` initialized at top of scope
- time = document.createElement( "span" );
- time.className = "runtime";
- time.innerHTML = this.runtime + " ms";
-
- // `li` initialized at top of scope
- li = id( this.id );
- li.className = bad ? "fail" : "pass";
- li.removeChild( li.firstChild );
- a = li.firstChild;
- li.appendChild( b );
- li.appendChild( a );
- li.appendChild( time );
- li.appendChild( ol );
-
- } else {
- for ( i = 0; i < this.assertions.length; i++ ) {
- if ( !this.assertions[i].result ) {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
- }
-
- runLoggingCallbacks( "testDone", QUnit, {
- name: this.testName,
- module: this.module,
- failed: bad,
- passed: this.assertions.length - bad,
- total: this.assertions.length,
- duration: this.runtime
- });
-
- QUnit.reset();
-
- config.current = undefined;
- },
-
- queue: function() {
- var bad,
- test = this;
-
- synchronize(function() {
- test.init();
- });
- function run() {
- // each of these can by async
- synchronize(function() {
- test.setup();
- });
- synchronize(function() {
- test.run();
- });
- synchronize(function() {
- test.teardown();
- });
- synchronize(function() {
- test.finish();
- });
- }
-
- // `bad` initialized at top of scope
- // defer when previous test run passed, if storage is available
- bad = QUnit.config.reorder && defined.sessionStorage &&
- +sessionStorage.getItem( "qunit-test-" + this.module + "-" + this.testName );
-
- if ( bad ) {
- run();
- } else {
- synchronize( run, true );
- }
- }
-};
-
-// Root QUnit object.
-// `QUnit` initialized at top of scope
-QUnit = {
-
- // call on start of module test to prepend name to all tests
- module: function( name, testEnvironment ) {
- config.currentModule = name;
- config.currentModuleTestEnvironment = testEnvironment;
- config.modules[name] = true;
- },
-
- asyncTest: function( testName, expected, callback ) {
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- QUnit.test( testName, expected, callback, true );
- },
-
- test: function( testName, expected, callback, async ) {
- var test,
- nameHtml = "" + escapeText( testName ) + "";
-
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- if ( config.currentModule ) {
- nameHtml = "" + escapeText( config.currentModule ) + ": " + nameHtml;
- }
-
- test = new Test({
- nameHtml: nameHtml,
- testName: testName,
- expected: expected,
- async: async,
- callback: callback,
- module: config.currentModule,
- moduleTestEnvironment: config.currentModuleTestEnvironment,
- stack: sourceFromStacktrace( 2 )
- });
-
- if ( !validTest( test ) ) {
- return;
- }
-
- test.queue();
- },
-
- // Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through.
- expect: function( asserts ) {
- if (arguments.length === 1) {
- config.current.expected = asserts;
- } else {
- return config.current.expected;
- }
- },
-
- start: function( count ) {
- // QUnit hasn't been initialized yet.
- // Note: RequireJS (et al) may delay onLoad
- if ( config.semaphore === undefined ) {
- QUnit.begin(function() {
- // This is triggered at the top of QUnit.load, push start() to the event loop, to allow QUnit.load to finish first
- setTimeout(function() {
- QUnit.start( count );
- });
- });
- return;
- }
-
- config.semaphore -= count || 1;
- // don't start until equal number of stop-calls
- if ( config.semaphore > 0 ) {
- return;
- }
- // ignore if start is called more often then stop
- if ( config.semaphore < 0 ) {
- config.semaphore = 0;
- QUnit.pushFailure( "Called start() while already started (QUnit.config.semaphore was 0 already)", null, sourceFromStacktrace(2) );
- return;
- }
- // A slight delay, to avoid any current callbacks
- if ( defined.setTimeout ) {
- window.setTimeout(function() {
- if ( config.semaphore > 0 ) {
- return;
- }
- if ( config.timeout ) {
- clearTimeout( config.timeout );
- }
-
- config.blocking = false;
- process( true );
- }, 13);
- } else {
- config.blocking = false;
- process( true );
- }
- },
-
- stop: function( count ) {
- config.semaphore += count || 1;
- config.blocking = true;
-
- if ( config.testTimeout && defined.setTimeout ) {
- clearTimeout( config.timeout );
- config.timeout = window.setTimeout(function() {
- QUnit.ok( false, "Test timed out" );
- config.semaphore = 1;
- QUnit.start();
- }, config.testTimeout );
- }
- }
-};
-
-// `assert` initialized at top of scope
-// Asssert helpers
-// All of these must either call QUnit.push() or manually do:
-// - runLoggingCallbacks( "log", .. );
-// - config.current.assertions.push({ .. });
-// We attach it to the QUnit object *after* we expose the public API,
-// otherwise `assert` will become a global variable in browsers (#341).
-assert = {
- /**
- * Asserts rough true-ish result.
- * @name ok
- * @function
- * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" );
- */
- ok: function( result, msg ) {
- if ( !config.current ) {
- throw new Error( "ok() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
- result = !!result;
-
- var source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: msg
- };
-
- msg = escapeText( msg || (result ? "okay" : "failed" ) );
- msg = "" + msg + "";
-
- if ( !result ) {
- source = sourceFromStacktrace( 2 );
- if ( source ) {
- details.source = source;
- msg += "Source: | " + escapeText( source ) + " |
---|
";
- }
- }
- runLoggingCallbacks( "log", QUnit, details );
- config.current.assertions.push({
- result: result,
- message: msg
- });
- },
-
- /**
- * Assert that the first two arguments are equal, with an optional message.
- * Prints out both actual and expected values.
- * @name equal
- * @function
- * @example equal( format( "Received {0} bytes.", 2), "Received 2 bytes.", "format() replaces {0} with next argument" );
- */
- equal: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected == actual, actual, expected, message );
- },
-
- /**
- * @name notEqual
- * @function
- */
- notEqual: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected != actual, actual, expected, message );
- },
-
- /**
- * @name propEqual
- * @function
- */
- propEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notPropEqual
- * @function
- */
- notPropEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name deepEqual
- * @function
- */
- deepEqual: function( actual, expected, message ) {
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notDeepEqual
- * @function
- */
- notDeepEqual: function( actual, expected, message ) {
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name strictEqual
- * @function
- */
- strictEqual: function( actual, expected, message ) {
- QUnit.push( expected === actual, actual, expected, message );
- },
-
- /**
- * @name notStrictEqual
- * @function
- */
- notStrictEqual: function( actual, expected, message ) {
- QUnit.push( expected !== actual, actual, expected, message );
- },
-
- "throws": function( block, expected, message ) {
- var actual,
- expectedOutput = expected,
- ok = false;
-
- // 'expected' is optional
- if ( typeof expected === "string" ) {
- message = expected;
- expected = null;
- }
-
- config.current.ignoreGlobalErrors = true;
- try {
- block.call( config.current.testEnvironment );
- } catch (e) {
- actual = e;
- }
- config.current.ignoreGlobalErrors = false;
-
- if ( actual ) {
- // we don't want to validate thrown error
- if ( !expected ) {
- ok = true;
- expectedOutput = null;
- // expected is a regexp
- } else if ( QUnit.objectType( expected ) === "regexp" ) {
- ok = expected.test( errorString( actual ) );
- // expected is a constructor
- } else if ( actual instanceof expected ) {
- ok = true;
- // expected is a validation function which returns true is validation passed
- } else if ( expected.call( {}, actual ) === true ) {
- expectedOutput = null;
- ok = true;
- }
-
- QUnit.push( ok, actual, expectedOutput, message );
- } else {
- QUnit.pushFailure( message, null, 'No exception was thrown.' );
- }
- }
-};
-
-/**
- * @deprecate since 1.8.0
- * Kept assertion helpers in root for backwards compatibility.
- */
-extend( QUnit, assert );
-
-/**
- * @deprecated since 1.9.0
- * Kept root "raises()" for backwards compatibility.
- * (Note that we don't introduce assert.raises).
- */
-QUnit.raises = assert[ "throws" ];
-
-/**
- * @deprecated since 1.0.0, replaced with error pushes since 1.3.0
- * Kept to avoid TypeErrors for undefined methods.
- */
-QUnit.equals = function() {
- QUnit.push( false, false, false, "QUnit.equals has been deprecated since 2009 (e88049a0), use QUnit.equal instead" );
-};
-QUnit.same = function() {
- QUnit.push( false, false, false, "QUnit.same has been deprecated since 2009 (e88049a0), use QUnit.deepEqual instead" );
-};
-
-// We want access to the constructor's prototype
-(function() {
- function F() {}
- F.prototype = QUnit;
- QUnit = new F();
- // Make F QUnit's constructor so that we can add to the prototype later
- QUnit.constructor = F;
-}());
-
-/**
- * Config object: Maintain internal state
- * Later exposed as QUnit.config
- * `config` initialized at top of scope
- */
-config = {
- // The queue of tests to run
- queue: [],
-
- // block until document ready
- blocking: true,
-
- // when enabled, show only failing tests
- // gets persisted through sessionStorage and can be changed in UI via checkbox
- hidepassed: false,
-
- // by default, run previously failed tests first
- // very useful in combination with "Hide passed tests" checked
- reorder: true,
-
- // by default, modify document.title when suite is done
- altertitle: true,
-
- // when enabled, all tests must call expect()
- requireExpects: false,
-
- // add checkboxes that are persisted in the query-string
- // when enabled, the id is set to `true` as a `QUnit.config` property
- urlConfig: [
- {
- id: "noglobals",
- label: "Check for Globals",
- tooltip: "Enabling this will test if any test introduces new properties on the `window` object. Stored as query-strings."
- },
- {
- id: "notrycatch",
- label: "No try-catch",
- tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging exceptions in IE reasonable. Stored as query-strings."
- }
- ],
-
- // Set of all modules.
- modules: {},
-
- // logging callback queues
- begin: [],
- done: [],
- log: [],
- testStart: [],
- testDone: [],
- moduleStart: [],
- moduleDone: []
-};
-
-// Export global variables, unless an 'exports' object exists,
-// in that case we assume we're in CommonJS (dealt with on the bottom of the script)
-if ( typeof exports === "undefined" ) {
- extend( window, QUnit );
-
- // Expose QUnit object
- window.QUnit = QUnit;
-}
-
-// Initialize more QUnit.config and QUnit.urlParams
-(function() {
- var i,
- location = window.location || { search: "", protocol: "file:" },
- params = location.search.slice( 1 ).split( "&" ),
- length = params.length,
- urlParams = {},
- current;
-
- if ( params[ 0 ] ) {
- for ( i = 0; i < length; i++ ) {
- current = params[ i ].split( "=" );
- current[ 0 ] = decodeURIComponent( current[ 0 ] );
- // allow just a key to turn on a flag, e.g., test.html?noglobals
- current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true;
- urlParams[ current[ 0 ] ] = current[ 1 ];
- }
- }
-
- QUnit.urlParams = urlParams;
-
- // String search anywhere in moduleName+testName
- config.filter = urlParams.filter;
-
- // Exact match of the module name
- config.module = urlParams.module;
-
- config.testNumber = parseInt( urlParams.testNumber, 10 ) || null;
-
- // Figure out if we're running the tests from a server or not
- QUnit.isLocal = location.protocol === "file:";
-}());
-
-// Extend QUnit object,
-// these after set here because they should not be exposed as global functions
-extend( QUnit, {
- assert: assert,
-
- config: config,
-
- // Initialize the configuration options
- init: function() {
- extend( config, {
- stats: { all: 0, bad: 0 },
- moduleStats: { all: 0, bad: 0 },
- started: +new Date(),
- updateRate: 1000,
- blocking: false,
- autostart: true,
- autorun: false,
- filter: "",
- queue: [],
- semaphore: 1
- });
-
- var tests, banner, result,
- qunit = id( "qunit" );
-
- if ( qunit ) {
- qunit.innerHTML =
- "" +
- "" +
- "" +
- "" +
- "
";
- }
-
- tests = id( "qunit-tests" );
- banner = id( "qunit-banner" );
- result = id( "qunit-testresult" );
-
- if ( tests ) {
- tests.innerHTML = "";
- }
-
- if ( banner ) {
- banner.className = "";
- }
-
- if ( result ) {
- result.parentNode.removeChild( result );
- }
-
- if ( tests ) {
- result = document.createElement( "p" );
- result.id = "qunit-testresult";
- result.className = "result";
- tests.parentNode.insertBefore( result, tests );
- result.innerHTML = "Running...
";
- }
- },
-
- // Resets the test setup. Useful for tests that modify the DOM.
- reset: function() {
- var fixture = id( "qunit-fixture" );
- if ( fixture ) {
- fixture.innerHTML = config.fixture;
- }
- },
-
- // Trigger an event on an element.
- // @example triggerEvent( document.body, "click" );
- triggerEvent: function( elem, type, event ) {
- if ( document.createEvent ) {
- event = document.createEvent( "MouseEvents" );
- event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView,
- 0, 0, 0, 0, 0, false, false, false, false, 0, null);
-
- elem.dispatchEvent( event );
- } else if ( elem.fireEvent ) {
- elem.fireEvent( "on" + type );
- }
- },
-
- // Safe object type checking
- is: function( type, obj ) {
- return QUnit.objectType( obj ) === type;
- },
-
- objectType: function( obj ) {
- if ( typeof obj === "undefined" ) {
- return "undefined";
- // consider: typeof null === object
- }
- if ( obj === null ) {
- return "null";
- }
-
- var match = toString.call( obj ).match(/^\[object\s(.*)\]$/),
- type = match && match[1] || "";
-
- switch ( type ) {
- case "Number":
- if ( isNaN(obj) ) {
- return "nan";
- }
- return "number";
- case "String":
- case "Boolean":
- case "Array":
- case "Date":
- case "RegExp":
- case "Function":
- return type.toLowerCase();
- }
- if ( typeof obj === "object" ) {
- return "object";
- }
- return undefined;
- },
-
- push: function( result, actual, expected, message ) {
- if ( !config.current ) {
- throw new Error( "assertion outside test context, was " + sourceFromStacktrace() );
- }
-
- var output, source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: message,
- actual: actual,
- expected: expected
- };
-
- message = escapeText( message ) || ( result ? "okay" : "failed" );
- message = "" + message + "";
- output = message;
-
- if ( !result ) {
- expected = escapeText( QUnit.jsDump.parse(expected) );
- actual = escapeText( QUnit.jsDump.parse(actual) );
- output += "Expected: | " + expected + " |
";
-
- if ( actual !== expected ) {
- output += "Result: | " + actual + " |
";
- output += "Diff: | " + QUnit.diff( expected, actual ) + " |
";
- }
-
- source = sourceFromStacktrace();
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
- }
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: !!result,
- message: output
- });
- },
-
- pushFailure: function( message, source, actual ) {
- if ( !config.current ) {
- throw new Error( "pushFailure() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
-
- var output,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: false,
- message: message
- };
-
- message = escapeText( message ) || "error";
- message = "" + message + "";
- output = message;
-
- output += "";
-
- if ( actual ) {
- output += "Result: | " + escapeText( actual ) + " |
";
- }
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: false,
- message: output
- });
- },
-
- url: function( params ) {
- params = extend( extend( {}, QUnit.urlParams ), params );
- var key,
- querystring = "?";
-
- for ( key in params ) {
- if ( !hasOwn.call( params, key ) ) {
- continue;
- }
- querystring += encodeURIComponent( key ) + "=" +
- encodeURIComponent( params[ key ] ) + "&";
- }
- return window.location.protocol + "//" + window.location.host +
- window.location.pathname + querystring.slice( 0, -1 );
- },
-
- extend: extend,
- id: id,
- addEvent: addEvent
- // load, equiv, jsDump, diff: Attached later
-});
-
-/**
- * @deprecated: Created for backwards compatibility with test runner that set the hook function
- * into QUnit.{hook}, instead of invoking it and passing the hook function.
- * QUnit.constructor is set to the empty F() above so that we can add to it's prototype here.
- * Doing this allows us to tell if the following methods have been overwritten on the actual
- * QUnit object.
- */
-extend( QUnit.constructor.prototype, {
-
- // Logging callbacks; all receive a single argument with the listed properties
- // run test/logs.html for any related changes
- begin: registerLoggingCallback( "begin" ),
-
- // done: { failed, passed, total, runtime }
- done: registerLoggingCallback( "done" ),
-
- // log: { result, actual, expected, message }
- log: registerLoggingCallback( "log" ),
-
- // testStart: { name }
- testStart: registerLoggingCallback( "testStart" ),
-
- // testDone: { name, failed, passed, total, duration }
- testDone: registerLoggingCallback( "testDone" ),
-
- // moduleStart: { name }
- moduleStart: registerLoggingCallback( "moduleStart" ),
-
- // moduleDone: { name, failed, passed, total }
- moduleDone: registerLoggingCallback( "moduleDone" )
-});
-
-if ( typeof document === "undefined" || document.readyState === "complete" ) {
- config.autorun = true;
-}
-
-QUnit.load = function() {
- runLoggingCallbacks( "begin", QUnit, {} );
-
- // Initialize the config, saving the execution queue
- var banner, filter, i, label, len, main, ol, toolbar, userAgent, val,
- urlConfigCheckboxesContainer, urlConfigCheckboxes, moduleFilter,
- numModules = 0,
- moduleFilterHtml = "",
- urlConfigHtml = "",
- oldconfig = extend( {}, config );
-
- QUnit.init();
- extend(config, oldconfig);
-
- config.blocking = false;
-
- len = config.urlConfig.length;
-
- for ( i = 0; i < len; i++ ) {
- val = config.urlConfig[i];
- if ( typeof val === "string" ) {
- val = {
- id: val,
- label: val,
- tooltip: "[no tooltip available]"
- };
- }
- config[ val.id ] = QUnit.urlParams[ val.id ];
- urlConfigHtml += "";
- }
-
- moduleFilterHtml += "";
-
- // `userAgent` initialized at top of scope
- userAgent = id( "qunit-userAgent" );
- if ( userAgent ) {
- userAgent.innerHTML = navigator.userAgent;
- }
-
- // `banner` initialized at top of scope
- banner = id( "qunit-header" );
- if ( banner ) {
- banner.innerHTML = "" + banner.innerHTML + " ";
- }
-
- // `toolbar` initialized at top of scope
- toolbar = id( "qunit-testrunner-toolbar" );
- if ( toolbar ) {
- // `filter` initialized at top of scope
- filter = document.createElement( "input" );
- filter.type = "checkbox";
- filter.id = "qunit-filter-pass";
-
- addEvent( filter, "click", function() {
- var tmp,
- ol = document.getElementById( "qunit-tests" );
-
- if ( filter.checked ) {
- ol.className = ol.className + " hidepass";
- } else {
- tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " ";
- ol.className = tmp.replace( / hidepass /, " " );
- }
- if ( defined.sessionStorage ) {
- if (filter.checked) {
- sessionStorage.setItem( "qunit-filter-passed-tests", "true" );
- } else {
- sessionStorage.removeItem( "qunit-filter-passed-tests" );
- }
- }
- });
-
- if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem( "qunit-filter-passed-tests" ) ) {
- filter.checked = true;
- // `ol` initialized at top of scope
- ol = document.getElementById( "qunit-tests" );
- ol.className = ol.className + " hidepass";
- }
- toolbar.appendChild( filter );
-
- // `label` initialized at top of scope
- label = document.createElement( "label" );
- label.setAttribute( "for", "qunit-filter-pass" );
- label.setAttribute( "title", "Only show tests and assertons that fail. Stored in sessionStorage." );
- label.innerHTML = "Hide passed tests";
- toolbar.appendChild( label );
-
- urlConfigCheckboxesContainer = document.createElement("span");
- urlConfigCheckboxesContainer.innerHTML = urlConfigHtml;
- urlConfigCheckboxes = urlConfigCheckboxesContainer.getElementsByTagName("input");
- // For oldIE support:
- // * Add handlers to the individual elements instead of the container
- // * Use "click" instead of "change"
- // * Fallback from event.target to event.srcElement
- addEvents( urlConfigCheckboxes, "click", function( event ) {
- var params = {},
- target = event.target || event.srcElement;
- params[ target.name ] = target.checked ? true : undefined;
- window.location = QUnit.url( params );
- });
- toolbar.appendChild( urlConfigCheckboxesContainer );
-
- if (numModules > 1) {
- moduleFilter = document.createElement( 'span' );
- moduleFilter.setAttribute( 'id', 'qunit-modulefilter-container' );
- moduleFilter.innerHTML = moduleFilterHtml;
- addEvent( moduleFilter.lastChild, "change", function() {
- var selectBox = moduleFilter.getElementsByTagName("select")[0],
- selectedModule = decodeURIComponent(selectBox.options[selectBox.selectedIndex].value);
-
- window.location = QUnit.url( { module: ( selectedModule === "" ) ? undefined : selectedModule } );
- });
- toolbar.appendChild(moduleFilter);
- }
- }
-
- // `main` initialized at top of scope
- main = id( "qunit-fixture" );
- if ( main ) {
- config.fixture = main.innerHTML;
- }
-
- if ( config.autostart ) {
- QUnit.start();
- }
-};
-
-addEvent( window, "load", QUnit.load );
-
-// `onErrorFnPrev` initialized at top of scope
-// Preserve other handlers
-onErrorFnPrev = window.onerror;
-
-// Cover uncaught exceptions
-// Returning true will surpress the default browser handler,
-// returning false will let it run.
-window.onerror = function ( error, filePath, linerNr ) {
- var ret = false;
- if ( onErrorFnPrev ) {
- ret = onErrorFnPrev( error, filePath, linerNr );
- }
-
- // Treat return value as window.onerror itself does,
- // Only do our handling if not surpressed.
- if ( ret !== true ) {
- if ( QUnit.config.current ) {
- if ( QUnit.config.current.ignoreGlobalErrors ) {
- return true;
- }
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- } else {
- QUnit.test( "global failure", extend( function() {
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- }, { validTest: validTest } ) );
- }
- return false;
- }
-
- return ret;
-};
-
-function done() {
- config.autorun = true;
-
- // Log the last module results
- if ( config.currentModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.currentModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
-
- var i, key,
- banner = id( "qunit-banner" ),
- tests = id( "qunit-tests" ),
- runtime = +new Date() - config.started,
- passed = config.stats.all - config.stats.bad,
- html = [
- "Tests completed in ",
- runtime,
- " milliseconds.
",
- "",
- passed,
- " assertions of ",
- config.stats.all,
- " passed, ",
- config.stats.bad,
- " failed."
- ].join( "" );
-
- if ( banner ) {
- banner.className = ( config.stats.bad ? "qunit-fail" : "qunit-pass" );
- }
-
- if ( tests ) {
- id( "qunit-testresult" ).innerHTML = html;
- }
-
- if ( config.altertitle && typeof document !== "undefined" && document.title ) {
- // show ✖ for good, ✔ for bad suite result in title
- // use escape sequences in case file gets loaded with non-utf-8-charset
- document.title = [
- ( config.stats.bad ? "\u2716" : "\u2714" ),
- document.title.replace( /^[\u2714\u2716] /i, "" )
- ].join( " " );
- }
-
- // clear own sessionStorage items if all tests passed
- if ( config.reorder && defined.sessionStorage && config.stats.bad === 0 ) {
- // `key` & `i` initialized at top of scope
- for ( i = 0; i < sessionStorage.length; i++ ) {
- key = sessionStorage.key( i++ );
- if ( key.indexOf( "qunit-test-" ) === 0 ) {
- sessionStorage.removeItem( key );
- }
- }
- }
-
- // scroll back to top to show results
- if ( window.scrollTo ) {
- window.scrollTo(0, 0);
- }
-
- runLoggingCallbacks( "done", QUnit, {
- failed: config.stats.bad,
- passed: passed,
- total: config.stats.all,
- runtime: runtime
- });
-}
-
-/** @return Boolean: true if this test should be ran */
-function validTest( test ) {
- var include,
- filter = config.filter && config.filter.toLowerCase(),
- module = config.module && config.module.toLowerCase(),
- fullName = (test.module + ": " + test.testName).toLowerCase();
-
- // Internally-generated tests are always valid
- if ( test.callback && test.callback.validTest === validTest ) {
- delete test.callback.validTest;
- return true;
- }
-
- if ( config.testNumber ) {
- return test.testNumber === config.testNumber;
- }
-
- if ( module && ( !test.module || test.module.toLowerCase() !== module ) ) {
- return false;
- }
-
- if ( !filter ) {
- return true;
- }
-
- include = filter.charAt( 0 ) !== "!";
- if ( !include ) {
- filter = filter.slice( 1 );
- }
-
- // If the filter matches, we need to honour include
- if ( fullName.indexOf( filter ) !== -1 ) {
- return include;
- }
-
- // Otherwise, do the opposite
- return !include;
-}
-
-// so far supports only Firefox, Chrome and Opera (buggy), Safari (for real exceptions)
-// Later Safari and IE10 are supposed to support error.stack as well
-// See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack
-function extractStacktrace( e, offset ) {
- offset = offset === undefined ? 3 : offset;
-
- var stack, include, i;
-
- if ( e.stacktrace ) {
- // Opera
- return e.stacktrace.split( "\n" )[ offset + 3 ];
- } else if ( e.stack ) {
- // Firefox, Chrome
- stack = e.stack.split( "\n" );
- if (/^error$/i.test( stack[0] ) ) {
- stack.shift();
- }
- if ( fileName ) {
- include = [];
- for ( i = offset; i < stack.length; i++ ) {
- if ( stack[ i ].indexOf( fileName ) !== -1 ) {
- break;
- }
- include.push( stack[ i ] );
- }
- if ( include.length ) {
- return include.join( "\n" );
- }
- }
- return stack[ offset ];
- } else if ( e.sourceURL ) {
- // Safari, PhantomJS
- // hopefully one day Safari provides actual stacktraces
- // exclude useless self-reference for generated Error objects
- if ( /qunit.js$/.test( e.sourceURL ) ) {
- return;
- }
- // for actual exceptions, this is useful
- return e.sourceURL + ":" + e.line;
- }
-}
-function sourceFromStacktrace( offset ) {
- try {
- throw new Error();
- } catch ( e ) {
- return extractStacktrace( e, offset );
- }
-}
-
-/**
- * Escape text for attribute or text content.
- */
-function escapeText( s ) {
- if ( !s ) {
- return "";
- }
- s = s + "";
- // Both single quotes and double quotes (for attributes)
- return s.replace( /['"<>&]/g, function( s ) {
- switch( s ) {
- case '\'':
- return ''';
- case '"':
- return '"';
- case '<':
- return '<';
- case '>':
- return '>';
- case '&':
- return '&';
- }
- });
-}
-
-function synchronize( callback, last ) {
- config.queue.push( callback );
-
- if ( config.autorun && !config.blocking ) {
- process( last );
- }
-}
-
-function process( last ) {
- function next() {
- process( last );
- }
- var start = new Date().getTime();
- config.depth = config.depth ? config.depth + 1 : 1;
-
- while ( config.queue.length && !config.blocking ) {
- if ( !defined.setTimeout || config.updateRate <= 0 || ( ( new Date().getTime() - start ) < config.updateRate ) ) {
- config.queue.shift()();
- } else {
- window.setTimeout( next, 13 );
- break;
- }
- }
- config.depth--;
- if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) {
- done();
- }
-}
-
-function saveGlobal() {
- config.pollution = [];
-
- if ( config.noglobals ) {
- for ( var key in window ) {
- // in Opera sometimes DOM element ids show up here, ignore them
- if ( !hasOwn.call( window, key ) || /^qunit-test-output/.test( key ) ) {
- continue;
- }
- config.pollution.push( key );
- }
- }
-}
-
-function checkPollution() {
- var newGlobals,
- deletedGlobals,
- old = config.pollution;
-
- saveGlobal();
-
- newGlobals = diff( config.pollution, old );
- if ( newGlobals.length > 0 ) {
- QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join(", ") );
- }
-
- deletedGlobals = diff( old, config.pollution );
- if ( deletedGlobals.length > 0 ) {
- QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join(", ") );
- }
-}
-
-// returns a new Array with the elements that are in a but not in b
-function diff( a, b ) {
- var i, j,
- result = a.slice();
-
- for ( i = 0; i < result.length; i++ ) {
- for ( j = 0; j < b.length; j++ ) {
- if ( result[i] === b[j] ) {
- result.splice( i, 1 );
- i--;
- break;
- }
- }
- }
- return result;
-}
-
-function extend( a, b ) {
- for ( var prop in b ) {
- if ( b[ prop ] === undefined ) {
- delete a[ prop ];
-
- // Avoid "Member not found" error in IE8 caused by setting window.constructor
- } else if ( prop !== "constructor" || a !== window ) {
- a[ prop ] = b[ prop ];
- }
- }
-
- return a;
-}
-
-/**
- * @param {HTMLElement} elem
- * @param {string} type
- * @param {Function} fn
- */
-function addEvent( elem, type, fn ) {
- // Standards-based browsers
- if ( elem.addEventListener ) {
- elem.addEventListener( type, fn, false );
- // IE
- } else {
- elem.attachEvent( "on" + type, fn );
- }
-}
-
-/**
- * @param {Array|NodeList} elems
- * @param {string} type
- * @param {Function} fn
- */
-function addEvents( elems, type, fn ) {
- var i = elems.length;
- while ( i-- ) {
- addEvent( elems[i], type, fn );
- }
-}
-
-function hasClass( elem, name ) {
- return (" " + elem.className + " ").indexOf(" " + name + " ") > -1;
-}
-
-function addClass( elem, name ) {
- if ( !hasClass( elem, name ) ) {
- elem.className += (elem.className ? " " : "") + name;
- }
-}
-
-function removeClass( elem, name ) {
- var set = " " + elem.className + " ";
- // Class name may appear multiple times
- while ( set.indexOf(" " + name + " ") > -1 ) {
- set = set.replace(" " + name + " " , " ");
- }
- // If possible, trim it for prettiness, but not neccecarily
- elem.className = window.jQuery ? jQuery.trim( set ) : ( set.trim ? set.trim() : set );
-}
-
-function id( name ) {
- return !!( typeof document !== "undefined" && document && document.getElementById ) &&
- document.getElementById( name );
-}
-
-function registerLoggingCallback( key ) {
- return function( callback ) {
- config[key].push( callback );
- };
-}
-
-// Supports deprecated method of completely overwriting logging callbacks
-function runLoggingCallbacks( key, scope, args ) {
- var i, callbacks;
- if ( QUnit.hasOwnProperty( key ) ) {
- QUnit[ key ].call(scope, args );
- } else {
- callbacks = config[ key ];
- for ( i = 0; i < callbacks.length; i++ ) {
- callbacks[ i ].call( scope, args );
- }
- }
-}
-
-// Test for equality any JavaScript type.
-// Author: Philippe Rathé
-QUnit.equiv = (function() {
-
- // Call the o related callback with the given arguments.
- function bindCallbacks( o, callbacks, args ) {
- var prop = QUnit.objectType( o );
- if ( prop ) {
- if ( QUnit.objectType( callbacks[ prop ] ) === "function" ) {
- return callbacks[ prop ].apply( callbacks, args );
- } else {
- return callbacks[ prop ]; // or undefined
- }
- }
- }
-
- // the real equiv function
- var innerEquiv,
- // stack to decide between skip/abort functions
- callers = [],
- // stack to avoiding loops from circular referencing
- parents = [],
-
- getProto = Object.getPrototypeOf || function ( obj ) {
- return obj.__proto__;
- },
- callbacks = (function () {
-
- // for string, boolean, number and null
- function useStrictEquality( b, a ) {
- /*jshint eqeqeq:false */
- if ( b instanceof a.constructor || a instanceof b.constructor ) {
- // to catch short annotaion VS 'new' annotation of a
- // declaration
- // e.g. var i = 1;
- // var j = new Number(1);
- return a == b;
- } else {
- return a === b;
- }
- }
-
- return {
- "string": useStrictEquality,
- "boolean": useStrictEquality,
- "number": useStrictEquality,
- "null": useStrictEquality,
- "undefined": useStrictEquality,
-
- "nan": function( b ) {
- return isNaN( b );
- },
-
- "date": function( b, a ) {
- return QUnit.objectType( b ) === "date" && a.valueOf() === b.valueOf();
- },
-
- "regexp": function( b, a ) {
- return QUnit.objectType( b ) === "regexp" &&
- // the regex itself
- a.source === b.source &&
- // and its modifers
- a.global === b.global &&
- // (gmi) ...
- a.ignoreCase === b.ignoreCase &&
- a.multiline === b.multiline &&
- a.sticky === b.sticky;
- },
-
- // - skip when the property is a method of an instance (OOP)
- // - abort otherwise,
- // initial === would have catch identical references anyway
- "function": function() {
- var caller = callers[callers.length - 1];
- return caller !== Object && typeof caller !== "undefined";
- },
-
- "array": function( b, a ) {
- var i, j, len, loop;
-
- // b could be an object literal here
- if ( QUnit.objectType( b ) !== "array" ) {
- return false;
- }
-
- len = a.length;
- if ( len !== b.length ) {
- // safe and faster
- return false;
- }
-
- // track reference to avoid circular references
- parents.push( a );
- for ( i = 0; i < len; i++ ) {
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- loop = true;// dont rewalk array
- }
- }
- if ( !loop && !innerEquiv(a[i], b[i]) ) {
- parents.pop();
- return false;
- }
- }
- parents.pop();
- return true;
- },
-
- "object": function( b, a ) {
- var i, j, loop,
- // Default to true
- eq = true,
- aProperties = [],
- bProperties = [];
-
- // comparing constructors is more strict than using
- // instanceof
- if ( a.constructor !== b.constructor ) {
- // Allow objects with no prototype to be equivalent to
- // objects with Object as their constructor.
- if ( !(( getProto(a) === null && getProto(b) === Object.prototype ) ||
- ( getProto(b) === null && getProto(a) === Object.prototype ) ) ) {
- return false;
- }
- }
-
- // stack constructor before traversing properties
- callers.push( a.constructor );
- // track reference to avoid circular references
- parents.push( a );
-
- for ( i in a ) { // be strict: don't ensures hasOwnProperty
- // and go deep
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- // don't go down the same path twice
- loop = true;
- }
- }
- aProperties.push(i); // collect a's properties
-
- if (!loop && !innerEquiv( a[i], b[i] ) ) {
- eq = false;
- break;
- }
- }
-
- callers.pop(); // unstack, we are done
- parents.pop();
-
- for ( i in b ) {
- bProperties.push( i ); // collect b's properties
- }
-
- // Ensures identical properties name
- return eq && innerEquiv( aProperties.sort(), bProperties.sort() );
- }
- };
- }());
-
- innerEquiv = function() { // can take multiple arguments
- var args = [].slice.apply( arguments );
- if ( args.length < 2 ) {
- return true; // end transition
- }
-
- return (function( a, b ) {
- if ( a === b ) {
- return true; // catch the most you can
- } else if ( a === null || b === null || typeof a === "undefined" ||
- typeof b === "undefined" ||
- QUnit.objectType(a) !== QUnit.objectType(b) ) {
- return false; // don't lose time with error prone cases
- } else {
- return bindCallbacks(a, callbacks, [ b, a ]);
- }
-
- // apply transition with (1..n) arguments
- }( args[0], args[1] ) && arguments.callee.apply( this, args.splice(1, args.length - 1 )) );
- };
-
- return innerEquiv;
-}());
-
-/**
- * jsDump Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com |
- * http://flesler.blogspot.com Licensed under BSD
- * (http://www.opensource.org/licenses/bsd-license.php) Date: 5/15/2008
- *
- * @projectDescription Advanced and extensible data dumping for Javascript.
- * @version 1.0.0
- * @author Ariel Flesler
- * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html}
- */
-QUnit.jsDump = (function() {
- function quote( str ) {
- return '"' + str.toString().replace( /"/g, '\\"' ) + '"';
- }
- function literal( o ) {
- return o + "";
- }
- function join( pre, arr, post ) {
- var s = jsDump.separator(),
- base = jsDump.indent(),
- inner = jsDump.indent(1);
- if ( arr.join ) {
- arr = arr.join( "," + s + inner );
- }
- if ( !arr ) {
- return pre + post;
- }
- return [ pre, inner + arr, base + post ].join(s);
- }
- function array( arr, stack ) {
- var i = arr.length, ret = new Array(i);
- this.up();
- while ( i-- ) {
- ret[i] = this.parse( arr[i] , undefined , stack);
- }
- this.down();
- return join( "[", ret, "]" );
- }
-
- var reName = /^function (\w+)/,
- jsDump = {
- // type is used mostly internally, you can fix a (custom)type in advance
- parse: function( obj, type, stack ) {
- stack = stack || [ ];
- var inStack, res,
- parser = this.parsers[ type || this.typeOf(obj) ];
-
- type = typeof parser;
- inStack = inArray( obj, stack );
-
- if ( inStack !== -1 ) {
- return "recursion(" + (inStack - stack.length) + ")";
- }
- if ( type === "function" ) {
- stack.push( obj );
- res = parser.call( this, obj, stack );
- stack.pop();
- return res;
- }
- return ( type === "string" ) ? parser : this.parsers.error;
- },
- typeOf: function( obj ) {
- var type;
- if ( obj === null ) {
- type = "null";
- } else if ( typeof obj === "undefined" ) {
- type = "undefined";
- } else if ( QUnit.is( "regexp", obj) ) {
- type = "regexp";
- } else if ( QUnit.is( "date", obj) ) {
- type = "date";
- } else if ( QUnit.is( "function", obj) ) {
- type = "function";
- } else if ( typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined" ) {
- type = "window";
- } else if ( obj.nodeType === 9 ) {
- type = "document";
- } else if ( obj.nodeType ) {
- type = "node";
- } else if (
- // native arrays
- toString.call( obj ) === "[object Array]" ||
- // NodeList objects
- ( typeof obj.length === "number" && typeof obj.item !== "undefined" && ( obj.length ? obj.item(0) === obj[0] : ( obj.item( 0 ) === null && typeof obj[0] === "undefined" ) ) )
- ) {
- type = "array";
- } else if ( obj.constructor === Error.prototype.constructor ) {
- type = "error";
- } else {
- type = typeof obj;
- }
- return type;
- },
- separator: function() {
- return this.multiline ? this.HTML ? "
" : "\n" : this.HTML ? " " : " ";
- },
- // extra can be a number, shortcut for increasing-calling-decreasing
- indent: function( extra ) {
- if ( !this.multiline ) {
- return "";
- }
- var chr = this.indentChar;
- if ( this.HTML ) {
- chr = chr.replace( /\t/g, " " ).replace( / /g, " " );
- }
- return new Array( this._depth_ + (extra||0) ).join(chr);
- },
- up: function( a ) {
- this._depth_ += a || 1;
- },
- down: function( a ) {
- this._depth_ -= a || 1;
- },
- setParser: function( name, parser ) {
- this.parsers[name] = parser;
- },
- // The next 3 are exposed so you can use them
- quote: quote,
- literal: literal,
- join: join,
- //
- _depth_: 1,
- // This is the list of parsers, to modify them, use jsDump.setParser
- parsers: {
- window: "[Window]",
- document: "[Document]",
- error: function(error) {
- return "Error(\"" + error.message + "\")";
- },
- unknown: "[Unknown]",
- "null": "null",
- "undefined": "undefined",
- "function": function( fn ) {
- var ret = "function",
- // functions never have name in IE
- name = "name" in fn ? fn.name : (reName.exec(fn) || [])[1];
-
- if ( name ) {
- ret += " " + name;
- }
- ret += "( ";
-
- ret = [ ret, QUnit.jsDump.parse( fn, "functionArgs" ), "){" ].join( "" );
- return join( ret, QUnit.jsDump.parse(fn,"functionCode" ), "}" );
- },
- array: array,
- nodelist: array,
- "arguments": array,
- object: function( map, stack ) {
- var ret = [ ], keys, key, val, i;
- QUnit.jsDump.up();
- keys = [];
- for ( key in map ) {
- keys.push( key );
- }
- keys.sort();
- for ( i = 0; i < keys.length; i++ ) {
- key = keys[ i ];
- val = map[ key ];
- ret.push( QUnit.jsDump.parse( key, "key" ) + ": " + QUnit.jsDump.parse( val, undefined, stack ) );
- }
- QUnit.jsDump.down();
- return join( "{", ret, "}" );
- },
- node: function( node ) {
- var len, i, val,
- open = QUnit.jsDump.HTML ? "<" : "<",
- close = QUnit.jsDump.HTML ? ">" : ">",
- tag = node.nodeName.toLowerCase(),
- ret = open + tag,
- attrs = node.attributes;
-
- if ( attrs ) {
- for ( i = 0, len = attrs.length; i < len; i++ ) {
- val = attrs[i].nodeValue;
- // IE6 includes all attributes in .attributes, even ones not explicitly set.
- // Those have values like undefined, null, 0, false, "" or "inherit".
- if ( val && val !== "inherit" ) {
- ret += " " + attrs[i].nodeName + "=" + QUnit.jsDump.parse( val, "attribute" );
- }
- }
- }
- ret += close;
-
- // Show content of TextNode or CDATASection
- if ( node.nodeType === 3 || node.nodeType === 4 ) {
- ret += node.nodeValue;
- }
-
- return ret + open + "/" + tag + close;
- },
- // function calls it internally, it's the arguments part of the function
- functionArgs: function( fn ) {
- var args,
- l = fn.length;
-
- if ( !l ) {
- return "";
- }
-
- args = new Array(l);
- while ( l-- ) {
- // 97 is 'a'
- args[l] = String.fromCharCode(97+l);
- }
- return " " + args.join( ", " ) + " ";
- },
- // object calls it internally, the key part of an item in a map
- key: quote,
- // function calls it internally, it's the content of the function
- functionCode: "[code]",
- // node calls it internally, it's an html attribute value
- attribute: quote,
- string: quote,
- date: quote,
- regexp: literal,
- number: literal,
- "boolean": literal
- },
- // if true, entities are escaped ( <, >, \t, space and \n )
- HTML: false,
- // indentation unit
- indentChar: " ",
- // if true, items in a collection, are separated by a \n, else just a space.
- multiline: true
- };
-
- return jsDump;
-}());
-
-// from jquery.js
-function inArray( elem, array ) {
- if ( array.indexOf ) {
- return array.indexOf( elem );
- }
-
- for ( var i = 0, length = array.length; i < length; i++ ) {
- if ( array[ i ] === elem ) {
- return i;
- }
- }
-
- return -1;
-}
-
-/*
- * Javascript Diff Algorithm
- * By John Resig (http://ejohn.org/)
- * Modified by Chu Alan "sprite"
- *
- * Released under the MIT license.
- *
- * More Info:
- * http://ejohn.org/projects/javascript-diff-algorithm/
- *
- * Usage: QUnit.diff(expected, actual)
- *
- * QUnit.diff( "the quick brown fox jumped over", "the quick fox jumps over" ) == "the quick brown fox jumped jumps over"
- */
-QUnit.diff = (function() {
- /*jshint eqeqeq:false, eqnull:true */
- function diff( o, n ) {
- var i,
- ns = {},
- os = {};
-
- for ( i = 0; i < n.length; i++ ) {
- if ( !hasOwn.call( ns, n[i] ) ) {
- ns[ n[i] ] = {
- rows: [],
- o: null
- };
- }
- ns[ n[i] ].rows.push( i );
- }
-
- for ( i = 0; i < o.length; i++ ) {
- if ( !hasOwn.call( os, o[i] ) ) {
- os[ o[i] ] = {
- rows: [],
- n: null
- };
- }
- os[ o[i] ].rows.push( i );
- }
-
- for ( i in ns ) {
- if ( !hasOwn.call( ns, i ) ) {
- continue;
- }
- if ( ns[i].rows.length === 1 && hasOwn.call( os, i ) && os[i].rows.length === 1 ) {
- n[ ns[i].rows[0] ] = {
- text: n[ ns[i].rows[0] ],
- row: os[i].rows[0]
- };
- o[ os[i].rows[0] ] = {
- text: o[ os[i].rows[0] ],
- row: ns[i].rows[0]
- };
- }
- }
-
- for ( i = 0; i < n.length - 1; i++ ) {
- if ( n[i].text != null && n[ i + 1 ].text == null && n[i].row + 1 < o.length && o[ n[i].row + 1 ].text == null &&
- n[ i + 1 ] == o[ n[i].row + 1 ] ) {
-
- n[ i + 1 ] = {
- text: n[ i + 1 ],
- row: n[i].row + 1
- };
- o[ n[i].row + 1 ] = {
- text: o[ n[i].row + 1 ],
- row: i + 1
- };
- }
- }
-
- for ( i = n.length - 1; i > 0; i-- ) {
- if ( n[i].text != null && n[ i - 1 ].text == null && n[i].row > 0 && o[ n[i].row - 1 ].text == null &&
- n[ i - 1 ] == o[ n[i].row - 1 ]) {
-
- n[ i - 1 ] = {
- text: n[ i - 1 ],
- row: n[i].row - 1
- };
- o[ n[i].row - 1 ] = {
- text: o[ n[i].row - 1 ],
- row: i - 1
- };
- }
- }
-
- return {
- o: o,
- n: n
- };
- }
-
- return function( o, n ) {
- o = o.replace( /\s+$/, "" );
- n = n.replace( /\s+$/, "" );
-
- var i, pre,
- str = "",
- out = diff( o === "" ? [] : o.split(/\s+/), n === "" ? [] : n.split(/\s+/) ),
- oSpace = o.match(/\s+/g),
- nSpace = n.match(/\s+/g);
-
- if ( oSpace == null ) {
- oSpace = [ " " ];
- }
- else {
- oSpace.push( " " );
- }
-
- if ( nSpace == null ) {
- nSpace = [ " " ];
- }
- else {
- nSpace.push( " " );
- }
-
- if ( out.n.length === 0 ) {
- for ( i = 0; i < out.o.length; i++ ) {
- str += "" + out.o[i] + oSpace[i] + "";
- }
- }
- else {
- if ( out.n[0].text == null ) {
- for ( n = 0; n < out.o.length && out.o[n].text == null; n++ ) {
- str += "" + out.o[n] + oSpace[n] + "";
- }
- }
-
- for ( i = 0; i < out.n.length; i++ ) {
- if (out.n[i].text == null) {
- str += "" + out.n[i] + nSpace[i] + "";
- }
- else {
- // `pre` initialized at top of scope
- pre = "";
-
- for ( n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++ ) {
- pre += "" + out.o[n] + oSpace[n] + "";
- }
- str += " " + out.n[i].text + nSpace[i] + pre;
- }
- }
- }
-
- return str;
- };
-}());
-
-// for CommonJS enviroments, export everything
-if ( typeof exports !== "undefined" ) {
- extend( exports, QUnit );
-}
-
-// get at whatever the global object is, like window in browsers
-}( (function() {return this;}.call()) ));
diff --git a/test/lib/require.js b/test/lib/require.js
deleted file mode 100644
index 987f865..0000000
--- a/test/lib/require.js
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- RequireJS 2.1.5 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.
- Available via the MIT or new BSD license.
- see: http://github.com/jrburke/requirejs for details
-*/
-var requirejs,require,define;
-(function(aa){function I(b){return"[object Function]"===L.call(b)}function J(b){return"[object Array]"===L.call(b)}function y(b,c){if(b){var d;for(d=0;dthis.depCount&&!this.defined){if(I(n)){if(this.events.error)try{e=i.execCb(c,n,b,e)}catch(d){a=d}else e=i.execCb(c,n,b,e);this.map.isDefine&&((b=this.module)&&void 0!==b.exports&&b.exports!==this.exports?e=b.exports:void 0===e&&this.usingExports&&(e=this.exports));if(a)return a.requireMap=this.map,a.requireModules=[this.map.id],a.requireType="define",v(this.error=
-a)}else e=n;this.exports=e;if(this.map.isDefine&&!this.ignore&&(q[c]=e,l.onResourceLoad))l.onResourceLoad(i,this.map,this.depMaps);x(c);this.defined=!0}this.defining=!1;this.defined&&!this.defineEmitted&&(this.defineEmitted=!0,this.emit("defined",this.exports),this.defineEmitComplete=!0)}}else this.fetch()}},callPlugin:function(){var a=this.map,b=a.id,d=j(a.prefix);this.depMaps.push(d);t(d,"defined",u(this,function(e){var n,d;d=this.map.name;var g=this.map.parentMap?this.map.parentMap.name:null,h=
-i.makeRequire(a.parentMap,{enableBuildCallback:!0});if(this.map.unnormalized){if(e.normalize&&(d=e.normalize(d,function(a){return c(a,g,!0)})||""),e=j(a.prefix+"!"+d,this.map.parentMap),t(e,"defined",u(this,function(a){this.init([],function(){return a},null,{enabled:!0,ignore:!0})})),d=m(p,e.id)){this.depMaps.push(e);if(this.events.error)d.on("error",u(this,function(a){this.emit("error",a)}));d.enable()}}else n=u(this,function(a){this.init([],function(){return a},null,{enabled:!0})}),n.error=u(this,
-function(a){this.inited=!0;this.error=a;a.requireModules=[b];G(p,function(a){0===a.map.id.indexOf(b+"_unnormalized")&&x(a.map.id)});v(a)}),n.fromText=u(this,function(e,c){var d=a.name,g=j(d),C=O;c&&(e=c);C&&(O=!1);r(g);s(k.config,b)&&(k.config[d]=k.config[b]);try{l.exec(e)}catch(ca){return v(B("fromtexteval","fromText eval for "+b+" failed: "+ca,ca,[b]))}C&&(O=!0);this.depMaps.push(g);i.completeLoad(d);h([d],n)}),e.load(a.name,h,n,k)}));i.enable(d,this);this.pluginMaps[d.id]=d},enable:function(){V[this.map.id]=
-this;this.enabling=this.enabled=!0;y(this.depMaps,u(this,function(a,b){var c,e;if("string"===typeof a){a=j(a,this.map.isDefine?this.map:this.map.parentMap,!1,!this.skipMap);this.depMaps[b]=a;if(c=m(N,a.id)){this.depExports[b]=c(this);return}this.depCount+=1;t(a,"defined",u(this,function(a){this.defineDep(b,a);this.check()}));this.errback&&t(a,"error",this.errback)}c=a.id;e=p[c];!s(N,c)&&(e&&!e.enabled)&&i.enable(a,this)}));G(this.pluginMaps,u(this,function(a){var b=m(p,a.id);b&&!b.enabled&&i.enable(a,
-this)}));this.enabling=!1;this.check()},on:function(a,b){var c=this.events[a];c||(c=this.events[a]=[]);c.push(b)},emit:function(a,b){y(this.events[a],function(a){a(b)});"error"===a&&delete this.events[a]}};i={config:k,contextName:b,registry:p,defined:q,urlFetched:U,defQueue:H,Module:Z,makeModuleMap:j,nextTick:l.nextTick,onError:v,configure:function(a){a.baseUrl&&"/"!==a.baseUrl.charAt(a.baseUrl.length-1)&&(a.baseUrl+="/");var b=k.pkgs,c=k.shim,e={paths:!0,config:!0,map:!0};G(a,function(a,b){e[b]?
-"map"===b?(k.map||(k.map={}),R(k[b],a,!0,!0)):R(k[b],a,!0):k[b]=a});a.shim&&(G(a.shim,function(a,b){J(a)&&(a={deps:a});if((a.exports||a.init)&&!a.exportsFn)a.exportsFn=i.makeShimExports(a);c[b]=a}),k.shim=c);a.packages&&(y(a.packages,function(a){a="string"===typeof a?{name:a}:a;b[a.name]={name:a.name,location:a.location||a.name,main:(a.main||"main").replace(ja,"").replace(ea,"")}}),k.pkgs=b);G(p,function(a,b){!a.inited&&!a.map.unnormalized&&(a.map=j(b))});if(a.deps||a.callback)i.require(a.deps||[],
-a.callback)},makeShimExports:function(a){return function(){var b;a.init&&(b=a.init.apply(aa,arguments));return b||a.exports&&ba(a.exports)}},makeRequire:function(a,f){function d(e,c,h){var g,k;f.enableBuildCallback&&(c&&I(c))&&(c.__requireJsBuild=!0);if("string"===typeof e){if(I(c))return v(B("requireargs","Invalid require call"),h);if(a&&s(N,e))return N[e](p[a.id]);if(l.get)return l.get(i,e,a,d);g=j(e,a,!1,!0);g=g.id;return!s(q,g)?v(B("notloaded",'Module name "'+g+'" has not been loaded yet for context: '+
-b+(a?"":". Use require([])"))):q[g]}L();i.nextTick(function(){L();k=r(j(null,a));k.skipMap=f.skipMap;k.init(e,c,h,{enabled:!0});D()});return d}f=f||{};R(d,{isBrowser:A,toUrl:function(b){var d,f=b.lastIndexOf("."),g=b.split("/")[0];if(-1!==f&&(!("."===g||".."===g)||1h.attachEvent.toString().indexOf("[native code"))&&!Y?(O=!0,h.attachEvent("onreadystatechange",b.onScriptLoad)):(h.addEventListener("load",b.onScriptLoad,!1),h.addEventListener("error",b.onScriptError,!1)),h.src=d,K=h,D?x.insertBefore(h,D):x.appendChild(h),K=null,h;if(da)try{importScripts(d),b.completeLoad(c)}catch(j){b.onError(B("importscripts","importScripts failed for "+c+" at "+d,j,[c]))}};A&&M(document.getElementsByTagName("script"),function(b){x||(x=
-b.parentNode);if(t=b.getAttribute("data-main"))return r.baseUrl||(E=t.split("/"),Q=E.pop(),fa=E.length?E.join("/")+"/":"./",r.baseUrl=fa,t=Q),t=t.replace(ea,""),r.deps=r.deps?r.deps.concat(t):[t],!0});define=function(b,c,d){var l,h;"string"!==typeof b&&(d=c,c=b,b=null);J(c)||(d=c,c=[]);!c.length&&I(d)&&d.length&&(d.toString().replace(la,"").replace(ma,function(b,d){c.push(d)}),c=(1===d.length?["require"]:["require","exports","module"]).concat(c));if(O){if(!(l=K))P&&"interactive"===P.readyState||M(document.getElementsByTagName("script"),
-function(b){if("interactive"===b.readyState)return P=b}),l=P;l&&(b||(b=l.getAttribute("data-requiremodule")),h=F[l.getAttribute("data-requirecontext")])}(h?h.defQueue:T).push([b,c,d])};define.amd={jQuery:!0};l.exec=function(b){return eval(b)};l(r)}})(this);
diff --git a/test/lib/resemble.js b/test/lib/resemble.js
new file mode 100644
index 0000000..1cb8c29
--- /dev/null
+++ b/test/lib/resemble.js
@@ -0,0 +1,535 @@
+/*
+Author: James Cryer
+Company: Huddle
+Last updated date: 21 Feb 2013
+URL: https://github.com/Huddle/Resemble.js
+*/
+
+(function(_this){
+ 'use strict';
+
+ _this['resemble'] = function( fileData ){
+
+ var data = {};
+ var images = [];
+ var updateCallbackArray = [];
+
+ var tolerance = { // between 0 and 255
+ red: 16,
+ green: 16,
+ blue: 16,
+ minBrightness: 16,
+ maxBrightness: 240
+ };
+
+ var ignoreAntialiasing = false;
+ var ignoreColors = false;
+
+ function triggerDataUpdate(){
+ var len = updateCallbackArray.length;
+ var i;
+ for(i=0;i tolerance.maxBrightness;
+ }
+
+ function getHue(r,g,b){
+
+ r = r / 255;
+ g = g / 255;
+ b = b / 255;
+ var max = Math.max(r, g, b), min = Math.min(r, g, b);
+ var h;
+ var d;
+
+ if (max == min){
+ h = 0; // achromatic
+ } else{
+ d = max - min;
+ switch(max){
+ case r: h = (g - b) / d + (g < b ? 6 : 0); break;
+ case g: h = (b - r) / d + 2; break;
+ case b: h = (r - g) / d + 4; break;
+ }
+ h /= 6;
+ }
+
+ return h;
+ }
+
+ function isAntialiased(sourcePix, data, cacheSet, verticalPos, horizontalPos, width){
+ var offset;
+ var targetPix;
+ var distance = 1;
+ var i;
+ var j;
+ var hasHighContrastSibling = 0;
+ var hasSiblingWithDifferentHue = 0;
+ var hasEquivilantSibling = 0;
+
+ addHueInfo(sourcePix);
+
+ for (i = distance*-1; i <= distance; i++){
+ for (j = distance*-1; j <= distance; j++){
+
+ if(i===0 && j===0){
+ // ignore source pixel
+ } else {
+
+ offset = ((verticalPos+j)*width + (horizontalPos+i)) * 4;
+ targetPix = getPixelInfo(data, offset, cacheSet);
+
+ if(targetPix === null){
+ continue;
+ }
+
+ addBrightnessInfo(targetPix);
+ addHueInfo(targetPix);
+
+ if( isContrasting(sourcePix, targetPix) ){
+ hasHighContrastSibling++;
+ }
+
+ if( isRGBSame(sourcePix,targetPix) ){
+ hasEquivilantSibling++;
+ }
+
+ if( Math.abs(targetPix.h - sourcePix.h) > 0.3 ){
+ hasSiblingWithDifferentHue++;
+ }
+
+ if( hasSiblingWithDifferentHue > 1 || hasHighContrastSibling > 1){
+ return true;
+ }
+ }
+ }
+ }
+
+ if(hasEquivilantSibling < 2){
+ return true;
+ }
+
+ return false;
+ }
+
+ function errorPixel(px, offset){
+ px[offset] = 255; //r
+ px[offset + 1] = 0; //g
+ px[offset + 2] = 255; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyPixel(px, offset, data){
+ px[offset] = data.r; //r
+ px[offset + 1] = data.g; //g
+ px[offset + 2] = data.b; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyGrayScalePixel(px, offset, data){
+ px[offset] = data.brightness; //r
+ px[offset + 1] = data.brightness; //g
+ px[offset + 2] = data.brightness; //b
+ px[offset + 3] = 255; //a
+ }
+
+
+ function getPixelInfo(data, offset, cacheSet){
+ var r;
+ var g;
+ var b;
+ var d;
+
+ if(typeof data[offset] !== 'undefined'){
+ r = data[offset];
+ g = data[offset+1];
+ b = data[offset+2];
+ d = {
+ r: r,
+ g: g,
+ b: b
+ };
+
+ return d;
+ } else {
+ return null;
+ }
+ }
+
+ function addBrightnessInfo(data){
+ data.brightness = getBrightness(data.r,data.g,data.b); // 'corrected' lightness
+ }
+
+ function addHueInfo(data){
+ data.h = getHue(data.r,data.g,data.b);
+ }
+
+ function analyseImages(img1, img2, width, height){
+
+ var hiddenCanvas = document.createElement('canvas');
+
+ var data1 = img1.data;
+ var data2 = img2.data;
+
+ hiddenCanvas.width = width;
+ hiddenCanvas.height = height;
+
+ var context = hiddenCanvas.getContext('2d');
+ var imgd = context.createImageData(width,height);
+ var targetPix = imgd.data;
+
+ var mismatchCount = 0;
+
+ var time = Date.now();
+
+ var skip;
+
+ if( (width > 1200 || height > 1200) && ignoreAntialiasing){
+ skip = 6;
+ }
+
+ loop(height, width, function(verticalPos, horizontalPos){
+
+ if(skip){ // only skip if the image isn't small
+ if(verticalPos % skip === 0 || horizontalPos % skip === 0){
+ return;
+ }
+ }
+
+ var offset = (verticalPos*width + horizontalPos) * 4;
+ var pixel1 = getPixelInfo(data1, offset, 1);
+ var pixel2 = getPixelInfo(data2, offset, 2);
+
+ if(pixel1 === null || pixel2 === null){
+ return;
+ }
+
+ if (ignoreColors){
+
+ addBrightnessInfo(pixel1);
+ addBrightnessInfo(pixel2);
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ return;
+ }
+
+ if( isRGBSimilar(pixel1, pixel2) ){
+ copyPixel(targetPix, offset, pixel2);
+
+ } else if( ignoreAntialiasing && (
+ addBrightnessInfo(pixel1), // jit pixel info augmentation looks a little weird, sorry.
+ addBrightnessInfo(pixel2),
+ isAntialiased(pixel1, data1, 1, verticalPos, horizontalPos, width) ||
+ isAntialiased(pixel2, data2, 2, verticalPos, horizontalPos, width)
+ )){
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+
+ });
+
+ data.misMatchPercentage = (mismatchCount / (height*width) * 100).toFixed(2);
+ data.analysisTime = Date.now() - time;
+
+ data.getImageDataUrl = function(text){
+ var barHeight = 0;
+
+ if(text){
+ barHeight = addLabel(text,context,hiddenCanvas);
+ }
+
+ context.putImageData(imgd, 0, barHeight);
+
+ return hiddenCanvas.toDataURL("image/png");
+ };
+ }
+
+ function addLabel(text, context, hiddenCanvas){
+ var textPadding = 2;
+
+ context.font = '12px sans-serif';
+
+ var textWidth = context.measureText(text).width + textPadding*2;
+ var barHeight = 22;
+
+ if(textWidth > hiddenCanvas.width){
+ hiddenCanvas.width = textWidth;
+ }
+
+ hiddenCanvas.height += barHeight;
+
+ context.fillStyle = "#666";
+ context.fillRect(0,0,hiddenCanvas.width,barHeight -4);
+ context.fillStyle = "#fff";
+ context.fillRect(0,barHeight -4,hiddenCanvas.width, 4);
+
+ context.fillStyle = "#fff";
+ context.textBaseline = "top";
+ context.font = '12px sans-serif';
+ context.fillText(text, textPadding, 1);
+
+ return barHeight;
+ }
+
+ function normalise(img, w, h){
+ var c;
+ var context;
+
+ if(img.height < h || img.width < w){
+ c = document.createElement('canvas');
+ c.width = w;
+ c.height = h;
+ context = c.getContext('2d');
+ context.putImageData(img, 0, 0);
+ return context.getImageData(0, 0, w, h);
+ }
+
+ return img;
+ }
+
+ function compare(one, two){
+
+ function onceWeHaveBoth(){
+ var width;
+ var height;
+ if(images.length === 2){
+ width = images[0].width > images[1].width ? images[0].width : images[1].width;
+ height = images[0].height > images[1].height ? images[0].height : images[1].height;
+
+ if( (images[0].width === images[1].width) && (images[0].height === images[1].height) ){
+ data.isSameDimensions = true;
+ } else {
+ data.isSameDimensions = false;
+ }
+
+ analyseImages( normalise(images[0],width, height), normalise(images[1],width, height), width, height);
+
+ triggerDataUpdate();
+ }
+ }
+
+ images = [];
+ loadImageData(one, onceWeHaveBoth);
+ loadImageData(two, onceWeHaveBoth);
+ }
+
+ function getCompareApi(param){
+
+ var secondFileData,
+ hasMethod = typeof param === 'function';
+
+ if( !hasMethod ){
+ // assume it's file data
+ secondFileData = param;
+ }
+
+ var self = {
+ ignoreNothing: function(){
+
+ tolerance.red = 16;
+ tolerance.green = 16;
+ tolerance.blue = 16;
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreAntialiasing: function(){
+
+ tolerance.red = 32;
+ tolerance.green = 32;
+ tolerance.blue = 32;
+ tolerance.minBrightness = 64;
+ tolerance.maxBrightness = 96;
+
+ ignoreAntialiasing = true;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreColors: function(){
+
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = true;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ onComplete: function( callback ){
+
+ updateCallbackArray.push(callback);
+
+ var wrapper = function(){
+ compare(fileData, secondFileData);
+ };
+
+ wrapper();
+
+ return getCompareApi(wrapper);
+ }
+ };
+
+ return self;
+ }
+
+ return {
+ onComplete: function( callback ){
+ updateCallbackArray.push(callback);
+ loadImageData(fileData, function(imageData, width, height){
+ parseImage(imageData.data, width, height);
+ });
+ },
+ compareTo: function(secondFileData){
+ return getCompareApi(secondFileData);
+ }
+ };
+
+ };
+}(this));
\ No newline at end of file
diff --git a/test/testsuite.js b/test/testsuite.js
deleted file mode 100644
index b486acb..0000000
--- a/test/testsuite.js
+++ /dev/null
@@ -1,36 +0,0 @@
-requirejs.config({
- baseUrl: '/test/unit/'
-});
-
-define(function(require) {
- var testModules = [
- 'Pixi',
- 'Point',
- 'Rectangle',
- 'DisplayObject',
- 'DisplayObjectContainer',
- 'Sprite',
- 'MovieClip',
- 'InteractionManager',
- 'Stage',
- 'utils/Utils',
- 'utils/EventTarget',
- 'utils/Matrix',
- 'utils/Detector',
- 'renderers/WebGLShaders',
- 'renderers/WebGLRenderer',
- 'renderers/WebGLBatch',
- 'renderers/CanvasRenderer',
- 'extras/Strip',
- 'extras/Rope',
- 'textures/BaseTexture',
- 'textures/Texture',
- 'loaders/SpriteSheetLoader',
- 'loaders/AssetLoader'
- ];
-
- // Resolve all testModules and then start the Test Runner.
- require(testModules, function() {
- QUnit.start();
- });
-});
\ No newline at end of file
diff --git a/test/textures/SpriteSheet-Aliens.png b/test/textures/SpriteSheet-Aliens.png
new file mode 100644
index 0000000..210acb1
--- /dev/null
+++ b/test/textures/SpriteSheet-Aliens.png
Binary files differ
diff --git a/test/textures/SpriteSheet-Explosion.png b/test/textures/SpriteSheet-Explosion.png
new file mode 100755
index 0000000..79e1a69
--- /dev/null
+++ b/test/textures/SpriteSheet-Explosion.png
Binary files differ
diff --git a/test/textures/bunny.png b/test/textures/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/textures/bunny.png
Binary files differ
diff --git a/test/unit/DisplayObject.js b/test/unit/DisplayObject.js
deleted file mode 100644
index 5e7e72f..0000000
--- a/test/unit/DisplayObject.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObject');
-});
diff --git a/test/unit/DisplayObjectContainer.js b/test/unit/DisplayObjectContainer.js
deleted file mode 100644
index b323959..0000000
--- a/test/unit/DisplayObjectContainer.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObjectContainer');
-});
diff --git a/test/unit/InteractionManager.js b/test/unit/InteractionManager.js
deleted file mode 100644
index e751f52..0000000
--- a/test/unit/InteractionManager.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('InteractionManager');
-});
diff --git a/test/unit/MovieClip.js b/test/unit/MovieClip.js
deleted file mode 100644
index 37d9446..0000000
--- a/test/unit/MovieClip.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('MovieClip');
-});
diff --git a/test/unit/Pixi.js b/test/unit/Pixi.js
deleted file mode 100644
index 36eee73..0000000
--- a/test/unit/Pixi.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Pixi');
-});
diff --git a/test/unit/Point.js b/test/unit/Point.js
deleted file mode 100644
index 983ff6e..0000000
--- a/test/unit/Point.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Point');
-});
diff --git a/test/unit/Rectangle.js b/test/unit/Rectangle.js
deleted file mode 100644
index 3b439ba..0000000
--- a/test/unit/Rectangle.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Rectangle');
-});
diff --git a/test/unit/Sprite.js b/test/unit/Sprite.js
deleted file mode 100644
index ed4f596..0000000
--- a/test/unit/Sprite.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Sprite');
-});
diff --git a/test/unit/Stage.js b/test/unit/Stage.js
deleted file mode 100644
index 2d70291..0000000
--- a/test/unit/Stage.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Stage');
-});
diff --git a/test/unit/extras/Rope.js b/test/unit/extras/Rope.js
deleted file mode 100644
index 5606f14..0000000
--- a/test/unit/extras/Rope.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Rope');
-});
diff --git a/test/unit/extras/Strip.js b/test/unit/extras/Strip.js
deleted file mode 100644
index 0134d3a..0000000
--- a/test/unit/extras/Strip.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Strip');
-});
diff --git a/test/unit/loaders/AssetLoader.js b/test/unit/loaders/AssetLoader.js
deleted file mode 100644
index 13b8443..0000000
--- a/test/unit/loaders/AssetLoader.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('AssetLoader');
-});
diff --git a/test/unit/loaders/SpriteSheetLoader.js b/test/unit/loaders/SpriteSheetLoader.js
deleted file mode 100644
index 8bf0cb2..0000000
--- a/test/unit/loaders/SpriteSheetLoader.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('SpriteSheetLoader');
-});
diff --git a/test/unit/pixi/InteractionManager.js b/test/unit/pixi/InteractionManager.js
new file mode 100644
index 0000000..ed3001f
--- /dev/null
+++ b/test/unit/pixi/InteractionManager.js
@@ -0,0 +1,10 @@
+describe('pixi/InteractionManager', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var InteractionManager = PIXI.InteractionManager;
+
+ it('Module exists', function () {
+ expect(InteractionManager).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/Pixi.js b/test/unit/pixi/Pixi.js
new file mode 100644
index 0000000..27debc1
--- /dev/null
+++ b/test/unit/pixi/Pixi.js
@@ -0,0 +1,9 @@
+describe('pixi/Pixi', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+
+ it('Module exists', function () {
+ expect(global).to.have.property('PIXI').and.to.be.an('object');
+ });
+});
diff --git a/test/unit/pixi/core/Circle.js b/test/unit/pixi/core/Circle.js
new file mode 100644
index 0000000..93a4456
--- /dev/null
+++ b/test/unit/pixi/core/Circle.js
@@ -0,0 +1,22 @@
+describe('pixi/core/Circle', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Circle = PIXI.Circle;
+
+ it('Module exists', function () {
+ expect(Circle).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Circle();
+
+ expect(obj).to.be.an.instanceof(Circle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', 0);
+ expect(obj).to.have.property('y', 0);
+ expect(obj).to.have.property('radius', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Ellipse.js b/test/unit/pixi/core/Ellipse.js
new file mode 100644
index 0000000..026b56f
--- /dev/null
+++ b/test/unit/pixi/core/Ellipse.js
@@ -0,0 +1,24 @@
+describe('pixi/core/Ellipse', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Ellipse = PIXI.Ellipse;
+
+ it('Module exists', function () {
+ expect(Ellipse).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Ellipse();
+
+ expect(obj).to.be.an.instanceof(Ellipse);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+ expect(obj).to.respondTo('getBounds');
+
+ expect(obj).to.have.property('x', 0);
+ expect(obj).to.have.property('y', 0);
+ expect(obj).to.have.property('width', 0);
+ expect(obj).to.have.property('height', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Matrix.js b/test/unit/pixi/core/Matrix.js
new file mode 100644
index 0000000..b48989e
--- /dev/null
+++ b/test/unit/pixi/core/Matrix.js
@@ -0,0 +1,30 @@
+describe('pixi/core/Matrix', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var mat3 = PIXI.mat3;
+ var mat4 = PIXI.mat4;
+ var Matrix = PIXI.Matrix;
+
+ it('Ensure determineMatrixArrayType works', function () {
+ expect(Matrix).to.be.a('function');
+ });
+
+ it('mat3 exists', function () {
+ expect(mat3).to.be.an('object');
+ });
+
+ it('Confirm new mat3 matrix', function () {
+ var matrix = new mat3.create();
+ pixi_core_Matrix_confirmNewMat3(matrix);
+ });
+
+ it('mat3 exists', function () {
+ expect(mat4).to.be.an('object');
+ });
+
+ it('Confirm new mat4 matrix', function () {
+ var matrix = new mat4.create();
+ pixi_core_Matrix_confirmNewMat4(matrix);
+ });
+});
diff --git a/test/unit/pixi/core/Point.js b/test/unit/pixi/core/Point.js
new file mode 100644
index 0000000..c4d5163
--- /dev/null
+++ b/test/unit/pixi/core/Point.js
@@ -0,0 +1,15 @@
+describe('pixi/core/Point', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Point = PIXI.Point;
+
+ it('Module exists', function () {
+ expect(Point).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Point();
+ pixi_core_Point_confirm(obj, 0, 0);
+ });
+});
diff --git a/test/unit/pixi/core/Polygon.js b/test/unit/pixi/core/Polygon.js
new file mode 100644
index 0000000..dc8c918
--- /dev/null
+++ b/test/unit/pixi/core/Polygon.js
@@ -0,0 +1,20 @@
+describe('pixi/core/Polygon', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Polygon = PIXI.Polygon;
+
+ it('Module exists', function () {
+ expect(Polygon).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Polygon();
+
+ expect(obj).to.be.an.instanceof(Polygon);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.deep.property('points.length', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Rectangle.js b/test/unit/pixi/core/Rectangle.js
new file mode 100644
index 0000000..d43316e
--- /dev/null
+++ b/test/unit/pixi/core/Rectangle.js
@@ -0,0 +1,15 @@
+describe('pixi/core/Rectangle', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Rectangle = PIXI.Rectangle;
+
+ it('Module exists', function () {
+ expect(Rectangle).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var rect = new Rectangle();
+ pixi_core_Rectangle_confirm(rect, 0, 0, 0, 0);
+ });
+});
diff --git a/test/unit/pixi/display/DisplayObject.js b/test/unit/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..40c6fbc
--- /dev/null
+++ b/test/unit/pixi/display/DisplayObject.js
@@ -0,0 +1,21 @@
+describe('pixi/display/DisplayObject', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var DisplayObject = PIXI.DisplayObject;
+
+ it('Module exists', function () {
+ expect(DisplayObject).to.be.a('function');
+ expect(PIXI).to.have.property('visibleCount', 0);
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new DisplayObject();
+
+ pixi_display_DisplayObject_confirmNew(obj);
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', false);
+ expect(obj).to.have.property('stage', null);
+ });
+});
diff --git a/test/unit/pixi/display/DisplayObjectContainer.js b/test/unit/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..ce7f02f
--- /dev/null
+++ b/test/unit/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,20 @@
+describe('pixi/display/DisplayObjectContainer', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var DisplayObjectContainer = PIXI.DisplayObjectContainer;
+
+ it('Module exists', function () {
+ expect(DisplayObjectContainer).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new DisplayObjectContainer();
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', false);
+ expect(obj).to.have.property('stage', null);
+ });
+});
diff --git a/test/unit/pixi/display/MovieClip.js b/test/unit/pixi/display/MovieClip.js
new file mode 100644
index 0000000..f3c6c6a
--- /dev/null
+++ b/test/unit/pixi/display/MovieClip.js
@@ -0,0 +1,33 @@
+describe('pixi/display/MovieClip', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var MovieClip = PIXI.MovieClip;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(MovieClip).to.be.a('function');
+ });
+
+ it('Confirm new instance', function (done) {
+ var texture = Texture.fromImage('/base/test/textures/SpriteSheet-Explosion.png');
+ var obj = new MovieClip([texture]);
+
+ pixi_display_Sprite_confirmNew(obj, done);
+
+ expect(obj).to.be.an.instanceof(MovieClip);
+ expect(obj).to.respondTo('stop');
+ expect(obj).to.respondTo('play');
+ expect(obj).to.respondTo('gotoAndStop');
+ expect(obj).to.respondTo('gotoAndPlay');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('textures.length', 1);
+ expect(obj).to.have.deep.property('textures[0]', texture);
+ expect(obj).to.have.property('animationSpeed', 1);
+ expect(obj).to.have.property('loop', true);
+ expect(obj).to.have.property('onComplete', null);
+ expect(obj).to.have.property('currentFrame', 0);
+ expect(obj).to.have.property('playing', false);
+ });
+});
diff --git a/test/unit/pixi/display/Sprite.js b/test/unit/pixi/display/Sprite.js
new file mode 100644
index 0000000..54e914f
--- /dev/null
+++ b/test/unit/pixi/display/Sprite.js
@@ -0,0 +1,25 @@
+describe('pixi/display/Sprite', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Sprite = PIXI.Sprite;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(Sprite).to.be.a('function');
+ expect(PIXI).to.have.deep.property('blendModes.NORMAL', 0);
+ expect(PIXI).to.have.deep.property('blendModes.SCREEN', 1);
+ });
+
+ it('Members exist', function () {
+ expect(Sprite).itself.to.respondTo('fromImage');
+ expect(Sprite).itself.to.respondTo('fromFrame');
+ });
+
+ it('Confirm new instance', function (done) {
+ var texture = Texture.fromImage('/base/test/textures/SpriteSheet-Aliens.png');
+ var obj = new Sprite(texture);
+
+ pixi_display_Sprite_confirmNew(obj, done);
+ });
+});
diff --git a/test/unit/pixi/display/Stage.js b/test/unit/pixi/display/Stage.js
new file mode 100644
index 0000000..3cc2a4d
--- /dev/null
+++ b/test/unit/pixi/display/Stage.js
@@ -0,0 +1,49 @@
+describe('pixi/display/Stage', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Stage = PIXI.Stage;
+ var InteractionManager = PIXI.InteractionManager;
+ var Rectangle = PIXI.Rectangle;
+
+ it('Module exists', function () {
+ expect(Stage).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Stage(null, true);
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(Stage);
+ expect(obj).to.respondTo('updateTransform');
+ expect(obj).to.respondTo('setBackgroundColor');
+ expect(obj).to.respondTo('getMousePosition');
+
+ // FIXME: duplicate member in DisplayObject
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ // FIXME: convert arg to bool in constructor
+ expect(obj).to.have.property('interactive', true);
+
+ expect(obj).to.have.property('interactionManager')
+ .and.to.be.an.instanceof(InteractionManager)
+ .and.to.have.property('stage', obj);
+
+ expect(obj).to.have.property('dirty', true);
+
+ expect(obj).to.have.property('stage', obj);
+
+ expect(obj).to.have.property('hitArea')
+ .and.to.be.an.instanceof(Rectangle);
+ pixi_core_Rectangle_confirm(obj.hitArea, 0, 0, 100000, 100000);
+
+ expect(obj).to.have.property('backgroundColor', 0x000000);
+ expect(obj).to.have.deep.property('backgroundColorSplit.length', 3);
+ expect(obj).to.have.deep.property('backgroundColorSplit[0]', 0);
+ expect(obj).to.have.deep.property('backgroundColorSplit[1]', 0);
+ expect(obj).to.have.deep.property('backgroundColorSplit[2]', 0);
+ expect(obj).to.have.property('backgroundColorString', '#000000');
+
+ expect(obj).to.have.property('worldVisible', true);
+ });
+});
diff --git a/test/unit/pixi/extras/CustomRenderable.js b/test/unit/pixi/extras/CustomRenderable.js
new file mode 100644
index 0000000..8d83cf0
--- /dev/null
+++ b/test/unit/pixi/extras/CustomRenderable.js
@@ -0,0 +1,21 @@
+describe('pixi/extras/CustomRenderable', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var CustomRenderable = PIXI.CustomRenderable;
+
+ it('Module exists', function () {
+ expect(CustomRenderable).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new CustomRenderable();
+
+ pixi_display_DisplayObject_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(CustomRenderable);
+ expect(obj).to.respondTo('renderCanvas');
+ expect(obj).to.respondTo('initWebGL');
+ expect(obj).to.respondTo('renderWebGL');
+ });
+});
diff --git a/test/unit/pixi/extras/Rope.js b/test/unit/pixi/extras/Rope.js
new file mode 100644
index 0000000..6ddaf83
--- /dev/null
+++ b/test/unit/pixi/extras/Rope.js
@@ -0,0 +1,26 @@
+describe('pixi/extras/Rope', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Rope = PIXI.Rope;
+ var Texture = PIXI.Texture;
+ var Point = PIXI.Point;
+
+ it('Module exists', function () {
+ expect(Rope).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var texture = Texture.fromImage('/base/test/textures/bunny.png');
+ var obj = new Rope(texture, [new Point(), new Point(5, 10), new Point(10, 20)]);
+
+ pixi_extras_Strip_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(Rope);
+ expect(obj).to.respondTo('refresh');
+ expect(obj).to.respondTo('updateTransform');
+ expect(obj).to.respondTo('setTexture');
+
+ // TODO: Test properties
+ });
+});
diff --git a/test/unit/pixi/extras/Spine.js b/test/unit/pixi/extras/Spine.js
new file mode 100644
index 0000000..0708bc0
--- /dev/null
+++ b/test/unit/pixi/extras/Spine.js
@@ -0,0 +1,10 @@
+describe('pixi/extras/Spine', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Spine = PIXI.Spine;
+
+ it('Module exists', function () {
+ expect(Spine).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/extras/Strip.js b/test/unit/pixi/extras/Strip.js
new file mode 100644
index 0000000..8e564e1
--- /dev/null
+++ b/test/unit/pixi/extras/Strip.js
@@ -0,0 +1,18 @@
+describe('pixi/extras/Strip', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Strip = PIXI.Strip;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(Strip).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var texture = Texture.fromImage('/base/test/textures/bunny.png');
+ var obj = new Strip(texture, 20, 10000);
+
+ pixi_extras_Strip_confirmNew(obj);
+ });
+});
diff --git a/test/unit/pixi/extras/TilingSprite.js b/test/unit/pixi/extras/TilingSprite.js
new file mode 100644
index 0000000..56aea14
--- /dev/null
+++ b/test/unit/pixi/extras/TilingSprite.js
@@ -0,0 +1,24 @@
+describe('pixi/extras/TilingSprite', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var TilingSprite = PIXI.TilingSprite;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(TilingSprite).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var texture = Texture.fromImage('/base/test/textures/bunny.png');
+ var obj = new TilingSprite(texture, 6000, 12000);
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(TilingSprite);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ // TODO: Test properties
+ });
+});
diff --git a/test/unit/pixi/filters/FilterBlock.js b/test/unit/pixi/filters/FilterBlock.js
new file mode 100644
index 0000000..870cec0
--- /dev/null
+++ b/test/unit/pixi/filters/FilterBlock.js
@@ -0,0 +1,10 @@
+describe('pixi/filters/FilterBlock', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var FilterBlock = PIXI.FilterBlock;
+
+ it('Module exists', function () {
+ expect(FilterBlock).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/filters/MaskFilter.js b/test/unit/pixi/filters/MaskFilter.js
new file mode 100644
index 0000000..32d6a45
--- /dev/null
+++ b/test/unit/pixi/filters/MaskFilter.js
@@ -0,0 +1,10 @@
+describe('pixi/filters/MaskFilter', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ // var MaskFilter = PIXI.MaskFilter;
+
+ // it('Module exists', function () {
+ // expect(MaskFilter).to.be.a('function');
+ // });
+});
diff --git a/test/unit/pixi/loaders/AssetLoader.js b/test/unit/pixi/loaders/AssetLoader.js
new file mode 100644
index 0000000..a0aa0b5
--- /dev/null
+++ b/test/unit/pixi/loaders/AssetLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/AssetLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var AssetLoader = PIXI.AssetLoader;
+
+ it('Module exists', function () {
+ expect(AssetLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/BitmapFontLoader.js b/test/unit/pixi/loaders/BitmapFontLoader.js
new file mode 100644
index 0000000..6253c42
--- /dev/null
+++ b/test/unit/pixi/loaders/BitmapFontLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/BitmapFontLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var BitmapFontLoader = PIXI.BitmapFontLoader;
+
+ it('Module exists', function () {
+ expect(PIXI.BitmapFontLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/ImageLoader.js b/test/unit/pixi/loaders/ImageLoader.js
new file mode 100644
index 0000000..8b1f556
--- /dev/null
+++ b/test/unit/pixi/loaders/ImageLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/ImageLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var ImageLoader = PIXI.ImageLoader;
+
+ it('Module exists', function () {
+ expect(ImageLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/JsonLoader.js b/test/unit/pixi/loaders/JsonLoader.js
new file mode 100644
index 0000000..c577e83
--- /dev/null
+++ b/test/unit/pixi/loaders/JsonLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/JsonLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var JsonLoader = PIXI.JsonLoader;
+
+ it('Module exists', function () {
+ expect(JsonLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/SpineLoader.js b/test/unit/pixi/loaders/SpineLoader.js
new file mode 100644
index 0000000..fdcc0b8
--- /dev/null
+++ b/test/unit/pixi/loaders/SpineLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/SpineLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var SpineLoader = PIXI.SpineLoader;
+
+ it('Module exists', function () {
+ expect(SpineLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/SpriteSheetLoader.js b/test/unit/pixi/loaders/SpriteSheetLoader.js
new file mode 100644
index 0000000..57beb27
--- /dev/null
+++ b/test/unit/pixi/loaders/SpriteSheetLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/SpriteSheetLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var SpriteSheetLoader = PIXI.SpriteSheetLoader;
+
+ it('Module exists', function () {
+ expect(SpriteSheetLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/primitives/Graphics.js b/test/unit/pixi/primitives/Graphics.js
new file mode 100644
index 0000000..b8b3e5c
--- /dev/null
+++ b/test/unit/pixi/primitives/Graphics.js
@@ -0,0 +1,40 @@
+describe('pixi/primitives/Graphics', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Graphics = PIXI.Graphics;
+
+ it('Module exists', function () {
+ expect(Graphics).to.be.a('function');
+
+ expect(Graphics).itself.to.have.property('POLY', 0);
+ expect(Graphics).itself.to.have.property('RECT', 1);
+ expect(Graphics).itself.to.have.property('CIRC', 2);
+ expect(Graphics).itself.to.have.property('ELIP', 3);
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Graphics();
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(Graphics);
+ expect(obj).to.respondTo('lineStyle');
+ expect(obj).to.respondTo('lineStyle');
+ expect(obj).to.respondTo('moveTo');
+ expect(obj).to.respondTo('lineTo');
+ expect(obj).to.respondTo('beginFill');
+ expect(obj).to.respondTo('endFill');
+ expect(obj).to.respondTo('drawRect');
+ expect(obj).to.respondTo('drawCircle');
+ expect(obj).to.respondTo('drawElipse');
+ expect(obj).to.respondTo('clear');
+
+ expect(obj).to.have.property('renderable', true);
+ expect(obj).to.have.property('fillAlpha', 1);
+ expect(obj).to.have.property('lineWidth', 0);
+ expect(obj).to.have.property('lineColor', 'black');
+ expect(obj).to.have.deep.property('graphicsData.length', 0);
+ expect(obj).to.have.deep.property('currentPath.points.length', 0);
+ });
+});
diff --git a/test/unit/pixi/renderers/canvas/CanvasGraphics.js b/test/unit/pixi/renderers/canvas/CanvasGraphics.js
new file mode 100644
index 0000000..8f44472
--- /dev/null
+++ b/test/unit/pixi/renderers/canvas/CanvasGraphics.js
@@ -0,0 +1,15 @@
+describe('renders/canvas/CanvasGraphics', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var CanvasGraphics = PIXI.CanvasGraphics;
+
+ it('Module exists', function () {
+ expect(CanvasGraphics).to.be.a('function');
+ });
+
+ it('Members exist', function () {
+ expect(CanvasGraphics).itself.to.respondTo('renderGraphics');
+ expect(CanvasGraphics).itself.to.respondTo('renderGraphicsMask');
+ });
+});
diff --git a/test/unit/pixi/renderers/canvas/CanvasRenderer.js b/test/unit/pixi/renderers/canvas/CanvasRenderer.js
new file mode 100644
index 0000000..df3a12f
--- /dev/null
+++ b/test/unit/pixi/renderers/canvas/CanvasRenderer.js
@@ -0,0 +1,10 @@
+describe('renderers/canvas/CanvasRenderer', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var CanvasRenderer = PIXI.CanvasRenderer;
+
+ it('Module exists', function () {
+ expect(CanvasRenderer).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/renderers/webgl/WebGLBatch.js b/test/unit/pixi/renderers/webgl/WebGLBatch.js
new file mode 100644
index 0000000..75efd56
--- /dev/null
+++ b/test/unit/pixi/renderers/webgl/WebGLBatch.js
@@ -0,0 +1,10 @@
+describe('renderers/webgl/WebGLBatch', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var WebGLBatch = PIXI.WebGLBatch;
+
+ it('Module exists', function () {
+ expect(WebGLBatch).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/renderers/webgl/WebGLGraphics.js b/test/unit/pixi/renderers/webgl/WebGLGraphics.js
new file mode 100644
index 0000000..41bf941
--- /dev/null
+++ b/test/unit/pixi/renderers/webgl/WebGLGraphics.js
@@ -0,0 +1,19 @@
+describe('renderers/wegbl/WebGLGraphics', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var WebGLGraphics = PIXI.WebGLGraphics;
+
+ it('Module exists', function () {
+ expect(WebGLGraphics).to.be.a('function');
+ });
+
+ it('Members exist', function () {
+ expect(WebGLGraphics).itself.to.respondTo('renderGraphics');
+ expect(WebGLGraphics).itself.to.respondTo('updateGraphics');
+ expect(WebGLGraphics).itself.to.respondTo('buildRectangle');
+ expect(WebGLGraphics).itself.to.respondTo('buildCircle');
+ expect(WebGLGraphics).itself.to.respondTo('buildLine');
+ expect(WebGLGraphics).itself.to.respondTo('buildPoly');
+ });
+});
diff --git a/test/unit/pixi/renderers/webgl/WebGLRenderGroup.js b/test/unit/pixi/renderers/webgl/WebGLRenderGroup.js
new file mode 100644
index 0000000..f4ee366
--- /dev/null
+++ b/test/unit/pixi/renderers/webgl/WebGLRenderGroup.js
@@ -0,0 +1,10 @@
+describe('renderers/webgl/WebGLRenderGroup', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var WebGLRenderGroup = PIXI.WebGLRenderGroup;
+
+ it('Module exists', function () {
+ expect(WebGLRenderGroup).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/renderers/webgl/WebGLRenderer.js b/test/unit/pixi/renderers/webgl/WebGLRenderer.js
new file mode 100644
index 0000000..86533eb
--- /dev/null
+++ b/test/unit/pixi/renderers/webgl/WebGLRenderer.js
@@ -0,0 +1,10 @@
+describe('renderers/webgl/WebGLRenderer', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var WebGLRenderer = PIXI.WebGLRenderer;
+
+ it('Module exists', function () {
+ expect(WebGLRenderer).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/renderers/webgl/WebGLShaders.js b/test/unit/pixi/renderers/webgl/WebGLShaders.js
new file mode 100644
index 0000000..2872de8
--- /dev/null
+++ b/test/unit/pixi/renderers/webgl/WebGLShaders.js
@@ -0,0 +1,13 @@
+describe('renderers/webgl/WebGLShaders', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+
+ it('Module members exist', function () {
+ expect(PIXI).to.respondTo('initPrimitiveShader');
+ expect(PIXI).to.respondTo('initDefaultShader');
+ expect(PIXI).to.respondTo('initDefaultStripShader');
+ expect(PIXI).to.respondTo('activateDefaultShader');
+ expect(PIXI).to.respondTo('activatePrimitiveShader');
+ });
+});
diff --git a/test/unit/pixi/text/BitmapText.js b/test/unit/pixi/text/BitmapText.js
new file mode 100644
index 0000000..9388e3d
--- /dev/null
+++ b/test/unit/pixi/text/BitmapText.js
@@ -0,0 +1,10 @@
+describe('pixi/text/BitmapText', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var BitmapText = PIXI.BitmapText;
+
+ it('Module exists', function () {
+ expect(BitmapText).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/text/Text.js b/test/unit/pixi/text/Text.js
new file mode 100644
index 0000000..9bc9ac5
--- /dev/null
+++ b/test/unit/pixi/text/Text.js
@@ -0,0 +1,10 @@
+describe('pixi/text/Text', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Text = PIXI.Text;
+
+ it('Module exists', function () {
+ expect(Text).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/textures/BaseTexture.js b/test/unit/pixi/textures/BaseTexture.js
new file mode 100644
index 0000000..e34b64c
--- /dev/null
+++ b/test/unit/pixi/textures/BaseTexture.js
@@ -0,0 +1,13 @@
+describe('pixi/textures/BaseTexture', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var BaseTexture = PIXI.BaseTexture;
+
+ it('Module exists', function () {
+ expect(BaseTexture).to.be.a('function');
+ expect(PIXI).to.have.property('BaseTextureCache').and.to.be.an('object');
+ expect(PIXI).to.have.deep.property('texturesToUpdate.length');
+ expect(PIXI).to.have.deep.property('texturesToDestroy.length', 0);
+ });
+});
diff --git a/test/unit/pixi/textures/RenderTexture.js b/test/unit/pixi/textures/RenderTexture.js
new file mode 100644
index 0000000..4a69b44
--- /dev/null
+++ b/test/unit/pixi/textures/RenderTexture.js
@@ -0,0 +1,10 @@
+describe('pixi/textures/RenderTexture', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var RenderTexture = PIXI.RenderTexture;
+
+ it('Module exists', function () {
+ expect(RenderTexture).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/textures/Texture.js b/test/unit/pixi/textures/Texture.js
new file mode 100644
index 0000000..adb2875
--- /dev/null
+++ b/test/unit/pixi/textures/Texture.js
@@ -0,0 +1,26 @@
+describe('pixi/textures/Texture', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(Texture).to.be.a('function');
+ expect(PIXI).to.have.property('TextureCache').and.to.be.an('object');
+ });
+
+ it('Members exist', function () {
+ expect(Texture).itself.to.respondTo('fromImage');
+ expect(Texture).itself.to.respondTo('fromFrame');
+ expect(Texture).itself.to.respondTo('fromCanvas');
+ expect(Texture).itself.to.respondTo('addTextureToCache');
+ expect(Texture).itself.to.respondTo('removeTextureFromCache');
+
+ expect(Texture).itself.to.have.deep.property('frameUpdates.length', 0);
+ });
+
+ it('Confirm new instance', function (done) {
+ var texture = Texture.fromImage('/base/test/textures/bunny.png');
+ pixi_textures_Texture_confirmNew(texture, done);
+ });
+});
diff --git a/test/unit/pixi/utils/Detector.js b/test/unit/pixi/utils/Detector.js
new file mode 100644
index 0000000..4cf6008
--- /dev/null
+++ b/test/unit/pixi/utils/Detector.js
@@ -0,0 +1,10 @@
+describe('pixi/utils/Detector', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var autoDetectRenderer = PIXI.autoDetectRenderer;
+
+ it('Module exists', function () {
+ expect(autoDetectRenderer).to.be.a('function');
+ });
+});
diff --git a/.gitignore b/.gitignore
index 12e1b62..0b88317 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
node_modules
.DS_Store
-.project
\ No newline at end of file
+.project
+*.log
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..63e4d7c
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,8 @@
+language: node_js
+node_js:
+ - 0.10
+
+before_script:
+ - npm install -g grunt-cli
+ - export DISPLAY=:99.0
+ - sh -e /etc/init.d/xvfb start
diff --git a/Gruntfile.js b/Gruntfile.js
index b083b49..103938c 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -1,10 +1,12 @@
+'use strict';
+
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-connect');
- grunt.loadNpmTasks('grunt-contrib-qunit');
grunt.loadNpmTasks('grunt-contrib-yuidoc');
+ grunt.loadTasks('tasks');
var root = 'src/pixi/',
debug = 'bin/pixi.dev.js',
@@ -79,7 +81,7 @@
},
files: {
srcBlob: '<%= dirs.src %>/**/*.js',
- testBlob: '<%= dirs.test %>/unit/**/*.js',
+ testBlob: '<%= dirs.test %>/{functional,lib/pixi,unit}/**/*.js',
build: '<%= dirs.build %>/pixi.dev.js',
buildMin: '<%= dirs.build %>/pixi.js'
},
@@ -94,7 +96,12 @@
},
jshint: {
beforeconcat: srcFiles,
- test: ['<%= files.testBlob %>'],
+ test: {
+ src: ['<%= files.testBlob %>'],
+ options: {
+ expr: true
+ }
+ },
options: {
asi: true,
smarttabs: true
@@ -128,12 +135,6 @@
]
},
connect: {
- qunit: {
- options: {
- port: grunt.option('port-test') || 9002,
- base: './'
- }
- },
test: {
options: {
port: grunt.option('port-test') || 9002,
@@ -142,13 +143,6 @@
}
}
},
- qunit: {
- all: {
- options: {
- urls: ['http://localhost:' + (grunt.option('port-test') || 9002) + '/test/index.html']
- }
- }
- },
yuidoc: {
compile: {
name: '<%= pkg.name %>',
@@ -161,6 +155,13 @@
outdir: '<%= dirs.docs %>'
}
}
+ },
+ karma: {
+ unit: {
+ configFile: 'test/karma.conf.js',
+ // browsers: ['Chrome'],
+ singleRun: true
+ }
}
});
@@ -182,9 +183,10 @@
}
)
- grunt.registerTask('default', ['concat', 'uglify', 'distribute']);
grunt.registerTask('build', ['concat', 'uglify', 'distribute']);
- grunt.registerTask('test', ['build', 'connect:qunit', 'qunit']);
+ grunt.registerTask('test', ['concat', 'jshint:test', 'karma']);
grunt.registerTask('docs', ['yuidoc']);
-
-}
\ No newline at end of file
+ grunt.registerTask('default', ['test', 'uglify', 'distribute']);
+ // Travis CI task.
+ grunt.registerTask('travis', ['test']);
+}
diff --git a/README.md b/README.md
index c62ef86..690cfe4 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,8 @@

+[](http://travis-ci.org/drkibitz/pixi.js)
+
#### JavaScript 2D Renderer ####
The aim of this project is to provide a fast lightweight 2D library that works
diff --git a/package.json b/package.json
index b373240..1246a68 100644
--- a/package.json
+++ b/package.json
@@ -18,14 +18,21 @@
"main": "bin/pixi.js",
+ "scripts": {
+ "test": "grunt travis --verbose"
+ },
+
"dependencies": {},
"devDependencies": {
"grunt": "~0.4.x",
- "grunt-contrib-jshint": "0.3.x",
+ "grunt-contrib-jshint": "0.6.x",
"grunt-contrib-uglify": "0.2.x",
- "grunt-contrib-connect": "0.2.x",
- "grunt-contrib-qunit": "0.2.x",
+ "grunt-contrib-connect": "0.3.x",
"grunt-contrib-yuidoc": "0.4.x",
- "grunt-contrib-concat": "0.1.x"
+ "grunt-contrib-concat": "0.3.x",
+ "chai": "~1.7.0",
+ "karma": "0.11.0",
+ "karma-firefox-launcher": "0.1.0",
+ "karma-mocha": "0.1.0"
}
}
diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js
index a7c520e..ee82bbd 100644
--- a/src/pixi/InteractionManager.js
+++ b/src/pixi/InteractionManager.js
@@ -62,7 +62,6 @@
this.onTouchEnd = this.onTouchEnd.bind(this);
this.onTouchMove = this.onTouchMove.bind(this);
-
this.last = 0;
}
diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js
index 1a95d20..eef1059 100644
--- a/src/pixi/core/Ellipse.js
+++ b/src/pixi/core/Ellipse.js
@@ -78,7 +78,7 @@
return (normx + normy < 0.25);
}
-PIXI.Ellipse.getBounds = function()
+PIXI.Ellipse.prototype.getBounds = function()
{
return new PIXI.Rectangle(this.x, this.y, this.width, this.height);
}
diff --git a/tasks/karma.js b/tasks/karma.js
new file mode 100644
index 0000000..c340485
--- /dev/null
+++ b/tasks/karma.js
@@ -0,0 +1,27 @@
+'use strict';
+
+var path = require('path');
+var server = require('karma').server;
+
+module.exports = function (grunt) {
+ grunt.registerMultiTask('karma', 'run karma.', function() {
+ var done = this.async();
+ var options = this.options({
+ background: false
+ });
+ var data = this.data;
+
+ //merge options onto data, with data taking precedence
+ data = grunt.util._.merge(options, data);
+ data.configFile = path.resolve(data.configFile);
+ if (data.configFile) {
+ data.configFile = grunt.template.process(data.configFile);
+ }
+
+ server.start(
+ data,
+ function(code) {
+ done(!code);
+ });
+ });
+};
diff --git a/test/functional/example-1-basics/bunny.png b/test/functional/example-1-basics/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/functional/example-1-basics/bunny.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-30.png b/test/functional/example-1-basics/frame-30.png
new file mode 100644
index 0000000..96e3409
--- /dev/null
+++ b/test/functional/example-1-basics/frame-30.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-60.png b/test/functional/example-1-basics/frame-60.png
new file mode 100644
index 0000000..af3f4ce
--- /dev/null
+++ b/test/functional/example-1-basics/frame-60.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-90.png b/test/functional/example-1-basics/frame-90.png
new file mode 100644
index 0000000..099b823
--- /dev/null
+++ b/test/functional/example-1-basics/frame-90.png
Binary files differ
diff --git a/test/functional/example-1-basics/index.js b/test/functional/example-1-basics/index.js
new file mode 100644
index 0000000..7ae7a98
--- /dev/null
+++ b/test/functional/example-1-basics/index.js
@@ -0,0 +1,133 @@
+describe('Example 1 - Basics', function () {
+ 'use strict';
+
+ var baseUri = '/base/test/functional/example-1-basics';
+ var expect = chai.expect;
+ var currentFrame = 0;
+ var frameEvents = {};
+ var stage;
+ var renderer;
+ var bunny;
+
+ function onFrame(frame, callback) {
+ frameEvents[frame] = callback;
+ }
+
+ function animate() {
+ currentFrame += 1;
+
+ requestAnimFrame( animate );
+
+ // just for fun, lets rotate mr rabbit a little
+ bunny.rotation += 0.1;
+
+ // render the stage
+ renderer.render(stage);
+
+ if (frameEvents[currentFrame])
+ frameEvents[currentFrame](currentFrame);
+ }
+
+ function initScene() {
+ // create an new instance of a pixi stage
+ stage = new PIXI.Stage(0x66FF99);
+
+ // create a renderer instance
+ renderer = PIXI.autoDetectRenderer(400, 300);
+ console.log('Is PIXI.WebGLRenderer: ' + (renderer instanceof PIXI.WebGLRenderer));
+
+ // add the renderer view element to the DOM
+ document.body.appendChild(renderer.view);
+
+ requestAnimFrame( animate );
+
+ // create a texture from an image path
+ var texture = PIXI.Texture.fromImage(baseUri + "/bunny.png");
+ // create a new Sprite using the texture
+ bunny = new PIXI.Sprite(texture);
+
+ // center the sprites anchor point
+ bunny.anchor.x = 0.5;
+ bunny.anchor.y = 0.5;
+
+ // move the sprite t the center of the screen
+ bunny.position.x = 200;
+ bunny.position.y = 150;
+
+ stage.addChild(bunny);
+ }
+
+ it('assets loaded', function (done) {
+ var loader = new PIXI.AssetLoader([
+ baseUri + '/bunny.png',
+ baseUri + '/frame-30.png',
+ baseUri + '/frame-60.png',
+ baseUri + '/frame-90.png'
+ ]);
+ // loader.on('onProgress', function (event) {
+ // console.log(event.content);
+ // });
+ loader.on('onComplete', function (event) {
+ done();
+ initScene();
+ });
+ loader.load();
+ });
+
+ it('frame 30 should match', function (done) {
+ this.timeout(700);
+ onFrame(30, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-30.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 60 should match', function (done) {
+ this.timeout(1200);
+ onFrame(60, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-60.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 90 should match', function (done) {
+ this.timeout(1700);
+ onFrame(90, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-90.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ // it('capture something', function (done) {
+ // this.timeout(2000000);
+ // onFrame(30, function () {
+ // var img = new Image();
+ // img.src = renderer.view.toDataURL('image/png');
+ // document.body.appendChild(img);
+ // });
+ // });
+});
diff --git a/test/index.html b/test/index.html
deleted file mode 100644
index 9cbcac5..0000000
--- a/test/index.html
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
- Pixi.js Test Suite
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/test/karma.conf.js b/test/karma.conf.js
new file mode 100644
index 0000000..c66a696
--- /dev/null
+++ b/test/karma.conf.js
@@ -0,0 +1,82 @@
+module.exports = function(config) {
+ config.set({
+
+ // base path, that will be used to resolve files and exclude
+ basePath : '../',
+
+ frameworks : ['mocha'],
+
+ // list of files / patterns to load in the browser
+ files : [
+ 'node_modules/chai/chai.js',
+ 'bin/pixi.dev.js',
+ 'test/lib/**/*.js',
+ 'test/unit/**/*.js',
+ // 'test/functional/**/*.js',
+ {pattern: 'test/**/*.png', watched: false, included: false, served: true}
+ ],
+
+ // list of files to exclude
+ exclude : [],
+
+ // use dolts reporter, as travis terminal does not support escaping sequences
+ // possible values: 'dots', 'progress', 'junit', 'teamcity'
+ // CLI --reporters progress
+ reporters : ['progress'],
+
+ // web server port
+ // CLI --port 9876
+ port : 9876,
+
+ // cli runner port
+ // CLI --runner-port 9100
+ runnerPort : 9100,
+
+ // enable / disable colors in the output (reporters and logs)
+ // CLI --colors --no-colors
+ colors : true,
+
+ // level of logging
+ // possible values: karma.LOG_DISABLE || karma.LOG_ERROR || karma.LOG_WARN || karma.LOG_INFO || karma.LOG_DEBUG
+ // CLI --log-level debug
+ logLevel : config.LOG_DEBUG,
+
+ // enable / disable watching file and executing tests whenever any file changes
+ // CLI --auto-watch --no-auto-watch
+ autoWatch : false,
+
+ // Start these browsers, currently available:
+ // - Chrome
+ // - ChromeCanary
+ // - Firefox
+ // - Opera
+ // - Safari (only Mac)
+ // - PhantomJS
+ // - IE (only Windows)
+ // CLI --browsers Chrome,Firefox,Safari
+ browsers : ['Firefox'],
+
+ // If browser does not capture in given timeout [ms], kill it
+ // CLI --capture-timeout 5000
+ captureTimeout : 5000,
+
+ // Auto run tests on start (when browsers are captured) and exit
+ // CLI --single-run --no-single-run
+ singleRun : true,
+
+ // report which specs are slower than 500ms
+ // CLI --report-slower-than 500
+ reportSlowerThan : 1000,
+
+ preprocessors : {
+ // '**/client/js/*.js': 'coverage'
+ },
+
+ plugins : [
+ 'karma-mocha',
+ // 'karma-chrome-launcher',
+ 'karma-firefox-launcher',
+ // 'karma-phantomjs-launcher'
+ ]
+ });
+};
diff --git a/test/lib/pixi/core/Matrix.js b/test/lib/pixi/core/Matrix.js
new file mode 100644
index 0000000..d26386b
--- /dev/null
+++ b/test/lib/pixi/core/Matrix.js
@@ -0,0 +1,40 @@
+
+function pixi_core_Matrix_confirmNewMat3(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(1);
+ expect(matrix[5]).to.equal(0);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(1);
+}
+
+function pixi_core_Matrix_confirmNewMat4(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[0]).to.equal(1);
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(0);
+ expect(matrix[5]).to.equal(1);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(0);
+ expect(matrix[9]).to.equal(0);
+ expect(matrix[10]).to.equal(1);
+ expect(matrix[11]).to.equal(0);
+ expect(matrix[12]).to.equal(0);
+ expect(matrix[13]).to.equal(0);
+ expect(matrix[14]).to.equal(0);
+ expect(matrix[15]).to.equal(1);
+}
diff --git a/test/lib/pixi/core/Point.js b/test/lib/pixi/core/Point.js
new file mode 100644
index 0000000..e5df07b
--- /dev/null
+++ b/test/lib/pixi/core/Point.js
@@ -0,0 +1,10 @@
+
+function pixi_core_Point_confirm(obj, x, y) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Point);
+ expect(obj).to.respondTo('clone');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+}
diff --git a/test/lib/pixi/core/Rectangle.js b/test/lib/pixi/core/Rectangle.js
new file mode 100644
index 0000000..23f0d12
--- /dev/null
+++ b/test/lib/pixi/core/Rectangle.js
@@ -0,0 +1,13 @@
+
+function pixi_core_Rectangle_confirm(obj, x, y, width, height) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Rectangle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+ expect(obj).to.have.property('width', width);
+ expect(obj).to.have.property('height', height);
+}
diff --git a/test/lib/pixi/display/DisplayObject.js b/test/lib/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..1388a7f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObject.js
@@ -0,0 +1,43 @@
+
+function pixi_display_DisplayObject_confirmNew(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObject);
+ expect(obj).to.respondTo('setInteractive');
+ expect(obj).to.respondTo('addFilter');
+ expect(obj).to.respondTo('removeFilter');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.property('last', obj);
+ expect(obj).to.have.property('first', obj);
+
+ expect(obj).to.contain.property('position');
+ pixi_core_Point_confirm(obj.position, 0, 0);
+ expect(obj).to.contain.property('scale');
+ pixi_core_Point_confirm(obj.scale, 1, 1);
+ expect(obj).to.contain.property('pivot');
+ pixi_core_Point_confirm(obj.pivot, 0, 0);
+
+ expect(obj).to.have.property('rotation', 0);
+ expect(obj).to.have.property('alpha', 1);
+ expect(obj).to.have.property('visible', true);
+ expect(obj).to.have.property('buttonMode', false);
+ expect(obj).to.have.property('parent', null);
+ expect(obj).to.have.property('worldAlpha', 1);
+
+ expect(obj).to.have.property('hitArea');
+ expect(obj).to.have.property('interactive'); // TODO: Have a better default value
+ expect('mask' in obj).to.be.true; // TODO: Have a better default value
+ expect(obj.mask).to.be.undefined;
+
+ expect(obj).to.have.property('renderable');
+ expect(obj).to.have.property('stage');
+
+ expect(obj).to.have.deep.property('worldTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ expect(obj).to.have.deep.property('localTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.localTransform);
+
+ expect(obj).to.have.deep.property('color.length', 0);
+ expect(obj).to.have.property('dynamic', true);
+}
diff --git a/test/lib/pixi/display/DisplayObjectContainer.js b/test/lib/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..085c59f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,16 @@
+
+function pixi_display_DisplayObjectContainer_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObject_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObjectContainer);
+ expect(obj).to.respondTo('addChild');
+ expect(obj).to.respondTo('addChildAt');
+ expect(obj).to.respondTo('swapChildren');
+ expect(obj).to.respondTo('getChildAt');
+ expect(obj).to.respondTo('removeChild');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('children.length', 0);
+}
diff --git a/test/lib/pixi/display/Sprite.js b/test/lib/pixi/display/Sprite.js
new file mode 100644
index 0000000..cc7a2d6
--- /dev/null
+++ b/test/lib/pixi/display/Sprite.js
@@ -0,0 +1,28 @@
+
+function pixi_display_Sprite_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Sprite);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', true);
+ expect(obj).to.have.property('stage', null);
+
+ expect(obj).to.have.property('anchor');
+ pixi_core_Point_confirm(obj.anchor, 0, 0);
+
+ expect(obj).to.have.property('blendMode', PIXI.blendModes.NORMAL);
+ expect(obj).to.have.property('width', 1); // TODO: is 1 expected
+ expect(obj).to.have.property('height', 1); // TODO: is 1 expected
+
+ // FIXME: Just make this a boolean that is always there
+ expect(!!obj.updateFrame).to.equal(obj.texture.baseTexture.hasLoaded);
+
+ expect(obj).to.have.property('texture');
+ pixi_textures_Texture_confirmNew(obj.texture, done);
+}
diff --git a/test/lib/pixi/extras/Strip.js b/test/lib/pixi/extras/Strip.js
new file mode 100644
index 0000000..8927a8a
--- /dev/null
+++ b/test/lib/pixi/extras/Strip.js
@@ -0,0 +1,12 @@
+
+function pixi_extras_Strip_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Strip);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ // TODO: Test properties
+}
diff --git a/test/lib/pixi/textures/Texture.js b/test/lib/pixi/textures/Texture.js
new file mode 100644
index 0000000..d5867b6
--- /dev/null
+++ b/test/lib/pixi/textures/Texture.js
@@ -0,0 +1,31 @@
+
+function pixi_textures_Texture_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ function confirmFrameDone() {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, obj.baseTexture.width, obj.baseTexture.height);
+
+ expect(obj).to.have.property('width', obj.baseTexture.width);
+ expect(obj).to.have.property('height', obj.baseTexture.height);
+ done();
+ }
+
+ expect(obj).to.be.an.instanceof(PIXI.Texture);
+ pixi_utils_EventTarget_like(obj);
+
+ expect(obj).to.have.property('baseTexture')
+ .and.to.be.an.instanceof(PIXI.BaseTexture);
+
+ expect(obj).to.have.property('scope', obj);
+
+ expect(obj).to.have.property('trim');
+ pixi_core_Point_confirm(obj.trim, 0, 0);
+
+ expect(obj).to.have.property('frame');
+ if (obj.baseTexture.hasLoaded) {
+ confirmFrameDone();
+ } else {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, 1, 1);
+ obj.addEventListener('update', confirmFrameDone);
+ }
+}
diff --git a/test/lib/pixi/utils/EventTarget.js b/test/lib/pixi/utils/EventTarget.js
new file mode 100644
index 0000000..7b1dcfa
--- /dev/null
+++ b/test/lib/pixi/utils/EventTarget.js
@@ -0,0 +1,8 @@
+
+function pixi_utils_EventTarget_like(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.respondTo('addEventListener');
+ expect(obj).to.respondTo('dispatchEvent');
+ expect(obj).to.respondTo('removeEventListener');
+}
diff --git a/test/lib/qunit-1.11.0.css b/test/lib/qunit-1.11.0.css
deleted file mode 100644
index d7fc0c8..0000000
--- a/test/lib/qunit-1.11.0.css
+++ /dev/null
@@ -1,244 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-/** Font Family and Sizes */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
- font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
-}
-
-#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
-#qunit-tests { font-size: smaller; }
-
-
-/** Resets */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter {
- margin: 0;
- padding: 0;
-}
-
-
-/** Header */
-
-#qunit-header {
- padding: 0.5em 0 0.5em 1em;
-
- color: #8699a4;
- background-color: #0d3349;
-
- font-size: 1.5em;
- line-height: 1em;
- font-weight: normal;
-
- border-radius: 5px 5px 0 0;
- -moz-border-radius: 5px 5px 0 0;
- -webkit-border-top-right-radius: 5px;
- -webkit-border-top-left-radius: 5px;
-}
-
-#qunit-header a {
- text-decoration: none;
- color: #c2ccd1;
-}
-
-#qunit-header a:hover,
-#qunit-header a:focus {
- color: #fff;
-}
-
-#qunit-testrunner-toolbar label {
- display: inline-block;
- padding: 0 .5em 0 .1em;
-}
-
-#qunit-banner {
- height: 5px;
-}
-
-#qunit-testrunner-toolbar {
- padding: 0.5em 0 0.5em 2em;
- color: #5E740B;
- background-color: #eee;
- overflow: hidden;
-}
-
-#qunit-userAgent {
- padding: 0.5em 0 0.5em 2.5em;
- background-color: #2b81af;
- color: #fff;
- text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
-}
-
-#qunit-modulefilter-container {
- float: right;
-}
-
-/** Tests: Pass/Fail */
-
-#qunit-tests {
- list-style-position: inside;
-}
-
-#qunit-tests li {
- padding: 0.4em 0.5em 0.4em 2.5em;
- border-bottom: 1px solid #fff;
- list-style-position: inside;
-}
-
-#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running {
- display: none;
-}
-
-#qunit-tests li strong {
- cursor: pointer;
-}
-
-#qunit-tests li a {
- padding: 0.5em;
- color: #c2ccd1;
- text-decoration: none;
-}
-#qunit-tests li a:hover,
-#qunit-tests li a:focus {
- color: #000;
-}
-
-#qunit-tests li .runtime {
- float: right;
- font-size: smaller;
-}
-
-.qunit-assert-list {
- margin-top: 0.5em;
- padding: 0.5em;
-
- background-color: #fff;
-
- border-radius: 5px;
- -moz-border-radius: 5px;
- -webkit-border-radius: 5px;
-}
-
-.qunit-collapsed {
- display: none;
-}
-
-#qunit-tests table {
- border-collapse: collapse;
- margin-top: .2em;
-}
-
-#qunit-tests th {
- text-align: right;
- vertical-align: top;
- padding: 0 .5em 0 0;
-}
-
-#qunit-tests td {
- vertical-align: top;
-}
-
-#qunit-tests pre {
- margin: 0;
- white-space: pre-wrap;
- word-wrap: break-word;
-}
-
-#qunit-tests del {
- background-color: #e0f2be;
- color: #374e0c;
- text-decoration: none;
-}
-
-#qunit-tests ins {
- background-color: #ffcaca;
- color: #500;
- text-decoration: none;
-}
-
-/*** Test Counts */
-
-#qunit-tests b.counts { color: black; }
-#qunit-tests b.passed { color: #5E740B; }
-#qunit-tests b.failed { color: #710909; }
-
-#qunit-tests li li {
- padding: 5px;
- background-color: #fff;
- border-bottom: none;
- list-style-position: inside;
-}
-
-/*** Passing Styles */
-
-#qunit-tests li li.pass {
- color: #3c510c;
- background-color: #fff;
- border-left: 10px solid #C6E746;
-}
-
-#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
-#qunit-tests .pass .test-name { color: #366097; }
-
-#qunit-tests .pass .test-actual,
-#qunit-tests .pass .test-expected { color: #999999; }
-
-#qunit-banner.qunit-pass { background-color: #C6E746; }
-
-/*** Failing Styles */
-
-#qunit-tests li li.fail {
- color: #710909;
- background-color: #fff;
- border-left: 10px solid #EE5757;
- white-space: pre;
-}
-
-#qunit-tests > li:last-child {
- border-radius: 0 0 5px 5px;
- -moz-border-radius: 0 0 5px 5px;
- -webkit-border-bottom-right-radius: 5px;
- -webkit-border-bottom-left-radius: 5px;
-}
-
-#qunit-tests .fail { color: #000000; background-color: #EE5757; }
-#qunit-tests .fail .test-name,
-#qunit-tests .fail .module-name { color: #000000; }
-
-#qunit-tests .fail .test-actual { color: #EE5757; }
-#qunit-tests .fail .test-expected { color: green; }
-
-#qunit-banner.qunit-fail { background-color: #EE5757; }
-
-
-/** Result */
-
-#qunit-testresult {
- padding: 0.5em 0.5em 0.5em 2.5em;
-
- color: #2b81af;
- background-color: #D2E0E6;
-
- border-bottom: 1px solid white;
-}
-#qunit-testresult .module-name {
- font-weight: bold;
-}
-
-/** Fixture */
-
-#qunit-fixture {
- position: absolute;
- top: -10000px;
- left: -10000px;
- width: 1000px;
- height: 1000px;
-}
diff --git a/test/lib/qunit-1.11.0.js b/test/lib/qunit-1.11.0.js
deleted file mode 100644
index 302545f..0000000
--- a/test/lib/qunit-1.11.0.js
+++ /dev/null
@@ -1,2152 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-(function( window ) {
-
-var QUnit,
- assert,
- config,
- onErrorFnPrev,
- testId = 0,
- fileName = (sourceFromStacktrace( 0 ) || "" ).replace(/(:\d+)+\)?/, "").replace(/.+\//, ""),
- toString = Object.prototype.toString,
- hasOwn = Object.prototype.hasOwnProperty,
- // Keep a local reference to Date (GH-283)
- Date = window.Date,
- defined = {
- setTimeout: typeof window.setTimeout !== "undefined",
- sessionStorage: (function() {
- var x = "qunit-test-string";
- try {
- sessionStorage.setItem( x, x );
- sessionStorage.removeItem( x );
- return true;
- } catch( e ) {
- return false;
- }
- }())
- },
- /**
- * Provides a normalized error string, correcting an issue
- * with IE 7 (and prior) where Error.prototype.toString is
- * not properly implemented
- *
- * Based on http://es5.github.com/#x15.11.4.4
- *
- * @param {String|Error} error
- * @return {String} error message
- */
- errorString = function( error ) {
- var name, message,
- errorString = error.toString();
- if ( errorString.substring( 0, 7 ) === "[object" ) {
- name = error.name ? error.name.toString() : "Error";
- message = error.message ? error.message.toString() : "";
- if ( name && message ) {
- return name + ": " + message;
- } else if ( name ) {
- return name;
- } else if ( message ) {
- return message;
- } else {
- return "Error";
- }
- } else {
- return errorString;
- }
- },
- /**
- * Makes a clone of an object using only Array or Object as base,
- * and copies over the own enumerable properties.
- *
- * @param {Object} obj
- * @return {Object} New object with only the own properties (recursively).
- */
- objectValues = function( obj ) {
- // Grunt 0.3.x uses an older version of jshint that still has jshint/jshint#392.
- /*jshint newcap: false */
- var key, val,
- vals = QUnit.is( "array", obj ) ? [] : {};
- for ( key in obj ) {
- if ( hasOwn.call( obj, key ) ) {
- val = obj[key];
- vals[key] = val === Object(val) ? objectValues(val) : val;
- }
- }
- return vals;
- };
-
-function Test( settings ) {
- extend( this, settings );
- this.assertions = [];
- this.testNumber = ++Test.count;
-}
-
-Test.count = 0;
-
-Test.prototype = {
- init: function() {
- var a, b, li,
- tests = id( "qunit-tests" );
-
- if ( tests ) {
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml;
-
- // `a` initialized at top of scope
- a = document.createElement( "a" );
- a.innerHTML = "Rerun";
- a.href = QUnit.url({ testNumber: this.testNumber });
-
- li = document.createElement( "li" );
- li.appendChild( b );
- li.appendChild( a );
- li.className = "running";
- li.id = this.id = "qunit-test-output" + testId++;
-
- tests.appendChild( li );
- }
- },
- setup: function() {
- if ( this.module !== config.previousModule ) {
- if ( config.previousModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.previousModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
- config.previousModule = this.module;
- config.moduleStats = { all: 0, bad: 0 };
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- } else if ( config.autorun ) {
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- }
-
- config.current = this;
-
- this.testEnvironment = extend({
- setup: function() {},
- teardown: function() {}
- }, this.moduleTestEnvironment );
-
- this.started = +new Date();
- runLoggingCallbacks( "testStart", QUnit, {
- name: this.testName,
- module: this.module
- });
-
- // allow utility functions to access the current test environment
- // TODO why??
- QUnit.current_testEnvironment = this.testEnvironment;
-
- if ( !config.pollution ) {
- saveGlobal();
- }
- if ( config.notrycatch ) {
- this.testEnvironment.setup.call( this.testEnvironment );
- return;
- }
- try {
- this.testEnvironment.setup.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Setup failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- },
- run: function() {
- config.current = this;
-
- var running = id( "qunit-testresult" );
-
- if ( running ) {
- running.innerHTML = "Running:
" + this.nameHtml;
- }
-
- if ( this.async ) {
- QUnit.stop();
- }
-
- this.callbackStarted = +new Date();
-
- if ( config.notrycatch ) {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- return;
- }
-
- try {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- } catch( e ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
-
- QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + " " + this.stack + ": " + ( e.message || e ), extractStacktrace( e, 0 ) );
- // else next test will carry the responsibility
- saveGlobal();
-
- // Restart the tests if they're blocking
- if ( config.blocking ) {
- QUnit.start();
- }
- }
- },
- teardown: function() {
- config.current = this;
- if ( config.notrycatch ) {
- if ( typeof this.callbackRuntime === "undefined" ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
- }
- this.testEnvironment.teardown.call( this.testEnvironment );
- return;
- } else {
- try {
- this.testEnvironment.teardown.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Teardown failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- }
- checkPollution();
- },
- finish: function() {
- config.current = this;
- if ( config.requireExpects && this.expected === null ) {
- QUnit.pushFailure( "Expected number of assertions to be defined, but expect() was not called.", this.stack );
- } else if ( this.expected !== null && this.expected !== this.assertions.length ) {
- QUnit.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack );
- } else if ( this.expected === null && !this.assertions.length ) {
- QUnit.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions.", this.stack );
- }
-
- var i, assertion, a, b, time, li, ol,
- test = this,
- good = 0,
- bad = 0,
- tests = id( "qunit-tests" );
-
- this.runtime = +new Date() - this.started;
- config.stats.all += this.assertions.length;
- config.moduleStats.all += this.assertions.length;
-
- if ( tests ) {
- ol = document.createElement( "ol" );
- ol.className = "qunit-assert-list";
-
- for ( i = 0; i < this.assertions.length; i++ ) {
- assertion = this.assertions[i];
-
- li = document.createElement( "li" );
- li.className = assertion.result ? "pass" : "fail";
- li.innerHTML = assertion.message || ( assertion.result ? "okay" : "failed" );
- ol.appendChild( li );
-
- if ( assertion.result ) {
- good++;
- } else {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
-
- // store result when possible
- if ( QUnit.config.reorder && defined.sessionStorage ) {
- if ( bad ) {
- sessionStorage.setItem( "qunit-test-" + this.module + "-" + this.testName, bad );
- } else {
- sessionStorage.removeItem( "qunit-test-" + this.module + "-" + this.testName );
- }
- }
-
- if ( bad === 0 ) {
- addClass( ol, "qunit-collapsed" );
- }
-
- // `b` initialized at top of scope
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml + " (" + bad + ", " + good + ", " + this.assertions.length + ")";
-
- addEvent(b, "click", function() {
- var next = b.parentNode.lastChild,
- collapsed = hasClass( next, "qunit-collapsed" );
- ( collapsed ? removeClass : addClass )( next, "qunit-collapsed" );
- });
-
- addEvent(b, "dblclick", function( e ) {
- var target = e && e.target ? e.target : window.event.srcElement;
- if ( target.nodeName.toLowerCase() === "span" || target.nodeName.toLowerCase() === "b" ) {
- target = target.parentNode;
- }
- if ( window.location && target.nodeName.toLowerCase() === "strong" ) {
- window.location = QUnit.url({ testNumber: test.testNumber });
- }
- });
-
- // `time` initialized at top of scope
- time = document.createElement( "span" );
- time.className = "runtime";
- time.innerHTML = this.runtime + " ms";
-
- // `li` initialized at top of scope
- li = id( this.id );
- li.className = bad ? "fail" : "pass";
- li.removeChild( li.firstChild );
- a = li.firstChild;
- li.appendChild( b );
- li.appendChild( a );
- li.appendChild( time );
- li.appendChild( ol );
-
- } else {
- for ( i = 0; i < this.assertions.length; i++ ) {
- if ( !this.assertions[i].result ) {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
- }
-
- runLoggingCallbacks( "testDone", QUnit, {
- name: this.testName,
- module: this.module,
- failed: bad,
- passed: this.assertions.length - bad,
- total: this.assertions.length,
- duration: this.runtime
- });
-
- QUnit.reset();
-
- config.current = undefined;
- },
-
- queue: function() {
- var bad,
- test = this;
-
- synchronize(function() {
- test.init();
- });
- function run() {
- // each of these can by async
- synchronize(function() {
- test.setup();
- });
- synchronize(function() {
- test.run();
- });
- synchronize(function() {
- test.teardown();
- });
- synchronize(function() {
- test.finish();
- });
- }
-
- // `bad` initialized at top of scope
- // defer when previous test run passed, if storage is available
- bad = QUnit.config.reorder && defined.sessionStorage &&
- +sessionStorage.getItem( "qunit-test-" + this.module + "-" + this.testName );
-
- if ( bad ) {
- run();
- } else {
- synchronize( run, true );
- }
- }
-};
-
-// Root QUnit object.
-// `QUnit` initialized at top of scope
-QUnit = {
-
- // call on start of module test to prepend name to all tests
- module: function( name, testEnvironment ) {
- config.currentModule = name;
- config.currentModuleTestEnvironment = testEnvironment;
- config.modules[name] = true;
- },
-
- asyncTest: function( testName, expected, callback ) {
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- QUnit.test( testName, expected, callback, true );
- },
-
- test: function( testName, expected, callback, async ) {
- var test,
- nameHtml = "" + escapeText( testName ) + "";
-
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- if ( config.currentModule ) {
- nameHtml = "" + escapeText( config.currentModule ) + ": " + nameHtml;
- }
-
- test = new Test({
- nameHtml: nameHtml,
- testName: testName,
- expected: expected,
- async: async,
- callback: callback,
- module: config.currentModule,
- moduleTestEnvironment: config.currentModuleTestEnvironment,
- stack: sourceFromStacktrace( 2 )
- });
-
- if ( !validTest( test ) ) {
- return;
- }
-
- test.queue();
- },
-
- // Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through.
- expect: function( asserts ) {
- if (arguments.length === 1) {
- config.current.expected = asserts;
- } else {
- return config.current.expected;
- }
- },
-
- start: function( count ) {
- // QUnit hasn't been initialized yet.
- // Note: RequireJS (et al) may delay onLoad
- if ( config.semaphore === undefined ) {
- QUnit.begin(function() {
- // This is triggered at the top of QUnit.load, push start() to the event loop, to allow QUnit.load to finish first
- setTimeout(function() {
- QUnit.start( count );
- });
- });
- return;
- }
-
- config.semaphore -= count || 1;
- // don't start until equal number of stop-calls
- if ( config.semaphore > 0 ) {
- return;
- }
- // ignore if start is called more often then stop
- if ( config.semaphore < 0 ) {
- config.semaphore = 0;
- QUnit.pushFailure( "Called start() while already started (QUnit.config.semaphore was 0 already)", null, sourceFromStacktrace(2) );
- return;
- }
- // A slight delay, to avoid any current callbacks
- if ( defined.setTimeout ) {
- window.setTimeout(function() {
- if ( config.semaphore > 0 ) {
- return;
- }
- if ( config.timeout ) {
- clearTimeout( config.timeout );
- }
-
- config.blocking = false;
- process( true );
- }, 13);
- } else {
- config.blocking = false;
- process( true );
- }
- },
-
- stop: function( count ) {
- config.semaphore += count || 1;
- config.blocking = true;
-
- if ( config.testTimeout && defined.setTimeout ) {
- clearTimeout( config.timeout );
- config.timeout = window.setTimeout(function() {
- QUnit.ok( false, "Test timed out" );
- config.semaphore = 1;
- QUnit.start();
- }, config.testTimeout );
- }
- }
-};
-
-// `assert` initialized at top of scope
-// Asssert helpers
-// All of these must either call QUnit.push() or manually do:
-// - runLoggingCallbacks( "log", .. );
-// - config.current.assertions.push({ .. });
-// We attach it to the QUnit object *after* we expose the public API,
-// otherwise `assert` will become a global variable in browsers (#341).
-assert = {
- /**
- * Asserts rough true-ish result.
- * @name ok
- * @function
- * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" );
- */
- ok: function( result, msg ) {
- if ( !config.current ) {
- throw new Error( "ok() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
- result = !!result;
-
- var source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: msg
- };
-
- msg = escapeText( msg || (result ? "okay" : "failed" ) );
- msg = "" + msg + "";
-
- if ( !result ) {
- source = sourceFromStacktrace( 2 );
- if ( source ) {
- details.source = source;
- msg += "Source: | " + escapeText( source ) + " |
---|
";
- }
- }
- runLoggingCallbacks( "log", QUnit, details );
- config.current.assertions.push({
- result: result,
- message: msg
- });
- },
-
- /**
- * Assert that the first two arguments are equal, with an optional message.
- * Prints out both actual and expected values.
- * @name equal
- * @function
- * @example equal( format( "Received {0} bytes.", 2), "Received 2 bytes.", "format() replaces {0} with next argument" );
- */
- equal: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected == actual, actual, expected, message );
- },
-
- /**
- * @name notEqual
- * @function
- */
- notEqual: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected != actual, actual, expected, message );
- },
-
- /**
- * @name propEqual
- * @function
- */
- propEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notPropEqual
- * @function
- */
- notPropEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name deepEqual
- * @function
- */
- deepEqual: function( actual, expected, message ) {
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notDeepEqual
- * @function
- */
- notDeepEqual: function( actual, expected, message ) {
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name strictEqual
- * @function
- */
- strictEqual: function( actual, expected, message ) {
- QUnit.push( expected === actual, actual, expected, message );
- },
-
- /**
- * @name notStrictEqual
- * @function
- */
- notStrictEqual: function( actual, expected, message ) {
- QUnit.push( expected !== actual, actual, expected, message );
- },
-
- "throws": function( block, expected, message ) {
- var actual,
- expectedOutput = expected,
- ok = false;
-
- // 'expected' is optional
- if ( typeof expected === "string" ) {
- message = expected;
- expected = null;
- }
-
- config.current.ignoreGlobalErrors = true;
- try {
- block.call( config.current.testEnvironment );
- } catch (e) {
- actual = e;
- }
- config.current.ignoreGlobalErrors = false;
-
- if ( actual ) {
- // we don't want to validate thrown error
- if ( !expected ) {
- ok = true;
- expectedOutput = null;
- // expected is a regexp
- } else if ( QUnit.objectType( expected ) === "regexp" ) {
- ok = expected.test( errorString( actual ) );
- // expected is a constructor
- } else if ( actual instanceof expected ) {
- ok = true;
- // expected is a validation function which returns true is validation passed
- } else if ( expected.call( {}, actual ) === true ) {
- expectedOutput = null;
- ok = true;
- }
-
- QUnit.push( ok, actual, expectedOutput, message );
- } else {
- QUnit.pushFailure( message, null, 'No exception was thrown.' );
- }
- }
-};
-
-/**
- * @deprecate since 1.8.0
- * Kept assertion helpers in root for backwards compatibility.
- */
-extend( QUnit, assert );
-
-/**
- * @deprecated since 1.9.0
- * Kept root "raises()" for backwards compatibility.
- * (Note that we don't introduce assert.raises).
- */
-QUnit.raises = assert[ "throws" ];
-
-/**
- * @deprecated since 1.0.0, replaced with error pushes since 1.3.0
- * Kept to avoid TypeErrors for undefined methods.
- */
-QUnit.equals = function() {
- QUnit.push( false, false, false, "QUnit.equals has been deprecated since 2009 (e88049a0), use QUnit.equal instead" );
-};
-QUnit.same = function() {
- QUnit.push( false, false, false, "QUnit.same has been deprecated since 2009 (e88049a0), use QUnit.deepEqual instead" );
-};
-
-// We want access to the constructor's prototype
-(function() {
- function F() {}
- F.prototype = QUnit;
- QUnit = new F();
- // Make F QUnit's constructor so that we can add to the prototype later
- QUnit.constructor = F;
-}());
-
-/**
- * Config object: Maintain internal state
- * Later exposed as QUnit.config
- * `config` initialized at top of scope
- */
-config = {
- // The queue of tests to run
- queue: [],
-
- // block until document ready
- blocking: true,
-
- // when enabled, show only failing tests
- // gets persisted through sessionStorage and can be changed in UI via checkbox
- hidepassed: false,
-
- // by default, run previously failed tests first
- // very useful in combination with "Hide passed tests" checked
- reorder: true,
-
- // by default, modify document.title when suite is done
- altertitle: true,
-
- // when enabled, all tests must call expect()
- requireExpects: false,
-
- // add checkboxes that are persisted in the query-string
- // when enabled, the id is set to `true` as a `QUnit.config` property
- urlConfig: [
- {
- id: "noglobals",
- label: "Check for Globals",
- tooltip: "Enabling this will test if any test introduces new properties on the `window` object. Stored as query-strings."
- },
- {
- id: "notrycatch",
- label: "No try-catch",
- tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging exceptions in IE reasonable. Stored as query-strings."
- }
- ],
-
- // Set of all modules.
- modules: {},
-
- // logging callback queues
- begin: [],
- done: [],
- log: [],
- testStart: [],
- testDone: [],
- moduleStart: [],
- moduleDone: []
-};
-
-// Export global variables, unless an 'exports' object exists,
-// in that case we assume we're in CommonJS (dealt with on the bottom of the script)
-if ( typeof exports === "undefined" ) {
- extend( window, QUnit );
-
- // Expose QUnit object
- window.QUnit = QUnit;
-}
-
-// Initialize more QUnit.config and QUnit.urlParams
-(function() {
- var i,
- location = window.location || { search: "", protocol: "file:" },
- params = location.search.slice( 1 ).split( "&" ),
- length = params.length,
- urlParams = {},
- current;
-
- if ( params[ 0 ] ) {
- for ( i = 0; i < length; i++ ) {
- current = params[ i ].split( "=" );
- current[ 0 ] = decodeURIComponent( current[ 0 ] );
- // allow just a key to turn on a flag, e.g., test.html?noglobals
- current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true;
- urlParams[ current[ 0 ] ] = current[ 1 ];
- }
- }
-
- QUnit.urlParams = urlParams;
-
- // String search anywhere in moduleName+testName
- config.filter = urlParams.filter;
-
- // Exact match of the module name
- config.module = urlParams.module;
-
- config.testNumber = parseInt( urlParams.testNumber, 10 ) || null;
-
- // Figure out if we're running the tests from a server or not
- QUnit.isLocal = location.protocol === "file:";
-}());
-
-// Extend QUnit object,
-// these after set here because they should not be exposed as global functions
-extend( QUnit, {
- assert: assert,
-
- config: config,
-
- // Initialize the configuration options
- init: function() {
- extend( config, {
- stats: { all: 0, bad: 0 },
- moduleStats: { all: 0, bad: 0 },
- started: +new Date(),
- updateRate: 1000,
- blocking: false,
- autostart: true,
- autorun: false,
- filter: "",
- queue: [],
- semaphore: 1
- });
-
- var tests, banner, result,
- qunit = id( "qunit" );
-
- if ( qunit ) {
- qunit.innerHTML =
- "" +
- "" +
- "" +
- "" +
- "
";
- }
-
- tests = id( "qunit-tests" );
- banner = id( "qunit-banner" );
- result = id( "qunit-testresult" );
-
- if ( tests ) {
- tests.innerHTML = "";
- }
-
- if ( banner ) {
- banner.className = "";
- }
-
- if ( result ) {
- result.parentNode.removeChild( result );
- }
-
- if ( tests ) {
- result = document.createElement( "p" );
- result.id = "qunit-testresult";
- result.className = "result";
- tests.parentNode.insertBefore( result, tests );
- result.innerHTML = "Running...
";
- }
- },
-
- // Resets the test setup. Useful for tests that modify the DOM.
- reset: function() {
- var fixture = id( "qunit-fixture" );
- if ( fixture ) {
- fixture.innerHTML = config.fixture;
- }
- },
-
- // Trigger an event on an element.
- // @example triggerEvent( document.body, "click" );
- triggerEvent: function( elem, type, event ) {
- if ( document.createEvent ) {
- event = document.createEvent( "MouseEvents" );
- event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView,
- 0, 0, 0, 0, 0, false, false, false, false, 0, null);
-
- elem.dispatchEvent( event );
- } else if ( elem.fireEvent ) {
- elem.fireEvent( "on" + type );
- }
- },
-
- // Safe object type checking
- is: function( type, obj ) {
- return QUnit.objectType( obj ) === type;
- },
-
- objectType: function( obj ) {
- if ( typeof obj === "undefined" ) {
- return "undefined";
- // consider: typeof null === object
- }
- if ( obj === null ) {
- return "null";
- }
-
- var match = toString.call( obj ).match(/^\[object\s(.*)\]$/),
- type = match && match[1] || "";
-
- switch ( type ) {
- case "Number":
- if ( isNaN(obj) ) {
- return "nan";
- }
- return "number";
- case "String":
- case "Boolean":
- case "Array":
- case "Date":
- case "RegExp":
- case "Function":
- return type.toLowerCase();
- }
- if ( typeof obj === "object" ) {
- return "object";
- }
- return undefined;
- },
-
- push: function( result, actual, expected, message ) {
- if ( !config.current ) {
- throw new Error( "assertion outside test context, was " + sourceFromStacktrace() );
- }
-
- var output, source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: message,
- actual: actual,
- expected: expected
- };
-
- message = escapeText( message ) || ( result ? "okay" : "failed" );
- message = "" + message + "";
- output = message;
-
- if ( !result ) {
- expected = escapeText( QUnit.jsDump.parse(expected) );
- actual = escapeText( QUnit.jsDump.parse(actual) );
- output += "Expected: | " + expected + " |
";
-
- if ( actual !== expected ) {
- output += "Result: | " + actual + " |
";
- output += "Diff: | " + QUnit.diff( expected, actual ) + " |
";
- }
-
- source = sourceFromStacktrace();
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
- }
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: !!result,
- message: output
- });
- },
-
- pushFailure: function( message, source, actual ) {
- if ( !config.current ) {
- throw new Error( "pushFailure() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
-
- var output,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: false,
- message: message
- };
-
- message = escapeText( message ) || "error";
- message = "" + message + "";
- output = message;
-
- output += "";
-
- if ( actual ) {
- output += "Result: | " + escapeText( actual ) + " |
";
- }
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: false,
- message: output
- });
- },
-
- url: function( params ) {
- params = extend( extend( {}, QUnit.urlParams ), params );
- var key,
- querystring = "?";
-
- for ( key in params ) {
- if ( !hasOwn.call( params, key ) ) {
- continue;
- }
- querystring += encodeURIComponent( key ) + "=" +
- encodeURIComponent( params[ key ] ) + "&";
- }
- return window.location.protocol + "//" + window.location.host +
- window.location.pathname + querystring.slice( 0, -1 );
- },
-
- extend: extend,
- id: id,
- addEvent: addEvent
- // load, equiv, jsDump, diff: Attached later
-});
-
-/**
- * @deprecated: Created for backwards compatibility with test runner that set the hook function
- * into QUnit.{hook}, instead of invoking it and passing the hook function.
- * QUnit.constructor is set to the empty F() above so that we can add to it's prototype here.
- * Doing this allows us to tell if the following methods have been overwritten on the actual
- * QUnit object.
- */
-extend( QUnit.constructor.prototype, {
-
- // Logging callbacks; all receive a single argument with the listed properties
- // run test/logs.html for any related changes
- begin: registerLoggingCallback( "begin" ),
-
- // done: { failed, passed, total, runtime }
- done: registerLoggingCallback( "done" ),
-
- // log: { result, actual, expected, message }
- log: registerLoggingCallback( "log" ),
-
- // testStart: { name }
- testStart: registerLoggingCallback( "testStart" ),
-
- // testDone: { name, failed, passed, total, duration }
- testDone: registerLoggingCallback( "testDone" ),
-
- // moduleStart: { name }
- moduleStart: registerLoggingCallback( "moduleStart" ),
-
- // moduleDone: { name, failed, passed, total }
- moduleDone: registerLoggingCallback( "moduleDone" )
-});
-
-if ( typeof document === "undefined" || document.readyState === "complete" ) {
- config.autorun = true;
-}
-
-QUnit.load = function() {
- runLoggingCallbacks( "begin", QUnit, {} );
-
- // Initialize the config, saving the execution queue
- var banner, filter, i, label, len, main, ol, toolbar, userAgent, val,
- urlConfigCheckboxesContainer, urlConfigCheckboxes, moduleFilter,
- numModules = 0,
- moduleFilterHtml = "",
- urlConfigHtml = "",
- oldconfig = extend( {}, config );
-
- QUnit.init();
- extend(config, oldconfig);
-
- config.blocking = false;
-
- len = config.urlConfig.length;
-
- for ( i = 0; i < len; i++ ) {
- val = config.urlConfig[i];
- if ( typeof val === "string" ) {
- val = {
- id: val,
- label: val,
- tooltip: "[no tooltip available]"
- };
- }
- config[ val.id ] = QUnit.urlParams[ val.id ];
- urlConfigHtml += "";
- }
-
- moduleFilterHtml += "";
-
- // `userAgent` initialized at top of scope
- userAgent = id( "qunit-userAgent" );
- if ( userAgent ) {
- userAgent.innerHTML = navigator.userAgent;
- }
-
- // `banner` initialized at top of scope
- banner = id( "qunit-header" );
- if ( banner ) {
- banner.innerHTML = "" + banner.innerHTML + " ";
- }
-
- // `toolbar` initialized at top of scope
- toolbar = id( "qunit-testrunner-toolbar" );
- if ( toolbar ) {
- // `filter` initialized at top of scope
- filter = document.createElement( "input" );
- filter.type = "checkbox";
- filter.id = "qunit-filter-pass";
-
- addEvent( filter, "click", function() {
- var tmp,
- ol = document.getElementById( "qunit-tests" );
-
- if ( filter.checked ) {
- ol.className = ol.className + " hidepass";
- } else {
- tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " ";
- ol.className = tmp.replace( / hidepass /, " " );
- }
- if ( defined.sessionStorage ) {
- if (filter.checked) {
- sessionStorage.setItem( "qunit-filter-passed-tests", "true" );
- } else {
- sessionStorage.removeItem( "qunit-filter-passed-tests" );
- }
- }
- });
-
- if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem( "qunit-filter-passed-tests" ) ) {
- filter.checked = true;
- // `ol` initialized at top of scope
- ol = document.getElementById( "qunit-tests" );
- ol.className = ol.className + " hidepass";
- }
- toolbar.appendChild( filter );
-
- // `label` initialized at top of scope
- label = document.createElement( "label" );
- label.setAttribute( "for", "qunit-filter-pass" );
- label.setAttribute( "title", "Only show tests and assertons that fail. Stored in sessionStorage." );
- label.innerHTML = "Hide passed tests";
- toolbar.appendChild( label );
-
- urlConfigCheckboxesContainer = document.createElement("span");
- urlConfigCheckboxesContainer.innerHTML = urlConfigHtml;
- urlConfigCheckboxes = urlConfigCheckboxesContainer.getElementsByTagName("input");
- // For oldIE support:
- // * Add handlers to the individual elements instead of the container
- // * Use "click" instead of "change"
- // * Fallback from event.target to event.srcElement
- addEvents( urlConfigCheckboxes, "click", function( event ) {
- var params = {},
- target = event.target || event.srcElement;
- params[ target.name ] = target.checked ? true : undefined;
- window.location = QUnit.url( params );
- });
- toolbar.appendChild( urlConfigCheckboxesContainer );
-
- if (numModules > 1) {
- moduleFilter = document.createElement( 'span' );
- moduleFilter.setAttribute( 'id', 'qunit-modulefilter-container' );
- moduleFilter.innerHTML = moduleFilterHtml;
- addEvent( moduleFilter.lastChild, "change", function() {
- var selectBox = moduleFilter.getElementsByTagName("select")[0],
- selectedModule = decodeURIComponent(selectBox.options[selectBox.selectedIndex].value);
-
- window.location = QUnit.url( { module: ( selectedModule === "" ) ? undefined : selectedModule } );
- });
- toolbar.appendChild(moduleFilter);
- }
- }
-
- // `main` initialized at top of scope
- main = id( "qunit-fixture" );
- if ( main ) {
- config.fixture = main.innerHTML;
- }
-
- if ( config.autostart ) {
- QUnit.start();
- }
-};
-
-addEvent( window, "load", QUnit.load );
-
-// `onErrorFnPrev` initialized at top of scope
-// Preserve other handlers
-onErrorFnPrev = window.onerror;
-
-// Cover uncaught exceptions
-// Returning true will surpress the default browser handler,
-// returning false will let it run.
-window.onerror = function ( error, filePath, linerNr ) {
- var ret = false;
- if ( onErrorFnPrev ) {
- ret = onErrorFnPrev( error, filePath, linerNr );
- }
-
- // Treat return value as window.onerror itself does,
- // Only do our handling if not surpressed.
- if ( ret !== true ) {
- if ( QUnit.config.current ) {
- if ( QUnit.config.current.ignoreGlobalErrors ) {
- return true;
- }
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- } else {
- QUnit.test( "global failure", extend( function() {
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- }, { validTest: validTest } ) );
- }
- return false;
- }
-
- return ret;
-};
-
-function done() {
- config.autorun = true;
-
- // Log the last module results
- if ( config.currentModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.currentModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
-
- var i, key,
- banner = id( "qunit-banner" ),
- tests = id( "qunit-tests" ),
- runtime = +new Date() - config.started,
- passed = config.stats.all - config.stats.bad,
- html = [
- "Tests completed in ",
- runtime,
- " milliseconds.
",
- "",
- passed,
- " assertions of ",
- config.stats.all,
- " passed, ",
- config.stats.bad,
- " failed."
- ].join( "" );
-
- if ( banner ) {
- banner.className = ( config.stats.bad ? "qunit-fail" : "qunit-pass" );
- }
-
- if ( tests ) {
- id( "qunit-testresult" ).innerHTML = html;
- }
-
- if ( config.altertitle && typeof document !== "undefined" && document.title ) {
- // show ✖ for good, ✔ for bad suite result in title
- // use escape sequences in case file gets loaded with non-utf-8-charset
- document.title = [
- ( config.stats.bad ? "\u2716" : "\u2714" ),
- document.title.replace( /^[\u2714\u2716] /i, "" )
- ].join( " " );
- }
-
- // clear own sessionStorage items if all tests passed
- if ( config.reorder && defined.sessionStorage && config.stats.bad === 0 ) {
- // `key` & `i` initialized at top of scope
- for ( i = 0; i < sessionStorage.length; i++ ) {
- key = sessionStorage.key( i++ );
- if ( key.indexOf( "qunit-test-" ) === 0 ) {
- sessionStorage.removeItem( key );
- }
- }
- }
-
- // scroll back to top to show results
- if ( window.scrollTo ) {
- window.scrollTo(0, 0);
- }
-
- runLoggingCallbacks( "done", QUnit, {
- failed: config.stats.bad,
- passed: passed,
- total: config.stats.all,
- runtime: runtime
- });
-}
-
-/** @return Boolean: true if this test should be ran */
-function validTest( test ) {
- var include,
- filter = config.filter && config.filter.toLowerCase(),
- module = config.module && config.module.toLowerCase(),
- fullName = (test.module + ": " + test.testName).toLowerCase();
-
- // Internally-generated tests are always valid
- if ( test.callback && test.callback.validTest === validTest ) {
- delete test.callback.validTest;
- return true;
- }
-
- if ( config.testNumber ) {
- return test.testNumber === config.testNumber;
- }
-
- if ( module && ( !test.module || test.module.toLowerCase() !== module ) ) {
- return false;
- }
-
- if ( !filter ) {
- return true;
- }
-
- include = filter.charAt( 0 ) !== "!";
- if ( !include ) {
- filter = filter.slice( 1 );
- }
-
- // If the filter matches, we need to honour include
- if ( fullName.indexOf( filter ) !== -1 ) {
- return include;
- }
-
- // Otherwise, do the opposite
- return !include;
-}
-
-// so far supports only Firefox, Chrome and Opera (buggy), Safari (for real exceptions)
-// Later Safari and IE10 are supposed to support error.stack as well
-// See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack
-function extractStacktrace( e, offset ) {
- offset = offset === undefined ? 3 : offset;
-
- var stack, include, i;
-
- if ( e.stacktrace ) {
- // Opera
- return e.stacktrace.split( "\n" )[ offset + 3 ];
- } else if ( e.stack ) {
- // Firefox, Chrome
- stack = e.stack.split( "\n" );
- if (/^error$/i.test( stack[0] ) ) {
- stack.shift();
- }
- if ( fileName ) {
- include = [];
- for ( i = offset; i < stack.length; i++ ) {
- if ( stack[ i ].indexOf( fileName ) !== -1 ) {
- break;
- }
- include.push( stack[ i ] );
- }
- if ( include.length ) {
- return include.join( "\n" );
- }
- }
- return stack[ offset ];
- } else if ( e.sourceURL ) {
- // Safari, PhantomJS
- // hopefully one day Safari provides actual stacktraces
- // exclude useless self-reference for generated Error objects
- if ( /qunit.js$/.test( e.sourceURL ) ) {
- return;
- }
- // for actual exceptions, this is useful
- return e.sourceURL + ":" + e.line;
- }
-}
-function sourceFromStacktrace( offset ) {
- try {
- throw new Error();
- } catch ( e ) {
- return extractStacktrace( e, offset );
- }
-}
-
-/**
- * Escape text for attribute or text content.
- */
-function escapeText( s ) {
- if ( !s ) {
- return "";
- }
- s = s + "";
- // Both single quotes and double quotes (for attributes)
- return s.replace( /['"<>&]/g, function( s ) {
- switch( s ) {
- case '\'':
- return ''';
- case '"':
- return '"';
- case '<':
- return '<';
- case '>':
- return '>';
- case '&':
- return '&';
- }
- });
-}
-
-function synchronize( callback, last ) {
- config.queue.push( callback );
-
- if ( config.autorun && !config.blocking ) {
- process( last );
- }
-}
-
-function process( last ) {
- function next() {
- process( last );
- }
- var start = new Date().getTime();
- config.depth = config.depth ? config.depth + 1 : 1;
-
- while ( config.queue.length && !config.blocking ) {
- if ( !defined.setTimeout || config.updateRate <= 0 || ( ( new Date().getTime() - start ) < config.updateRate ) ) {
- config.queue.shift()();
- } else {
- window.setTimeout( next, 13 );
- break;
- }
- }
- config.depth--;
- if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) {
- done();
- }
-}
-
-function saveGlobal() {
- config.pollution = [];
-
- if ( config.noglobals ) {
- for ( var key in window ) {
- // in Opera sometimes DOM element ids show up here, ignore them
- if ( !hasOwn.call( window, key ) || /^qunit-test-output/.test( key ) ) {
- continue;
- }
- config.pollution.push( key );
- }
- }
-}
-
-function checkPollution() {
- var newGlobals,
- deletedGlobals,
- old = config.pollution;
-
- saveGlobal();
-
- newGlobals = diff( config.pollution, old );
- if ( newGlobals.length > 0 ) {
- QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join(", ") );
- }
-
- deletedGlobals = diff( old, config.pollution );
- if ( deletedGlobals.length > 0 ) {
- QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join(", ") );
- }
-}
-
-// returns a new Array with the elements that are in a but not in b
-function diff( a, b ) {
- var i, j,
- result = a.slice();
-
- for ( i = 0; i < result.length; i++ ) {
- for ( j = 0; j < b.length; j++ ) {
- if ( result[i] === b[j] ) {
- result.splice( i, 1 );
- i--;
- break;
- }
- }
- }
- return result;
-}
-
-function extend( a, b ) {
- for ( var prop in b ) {
- if ( b[ prop ] === undefined ) {
- delete a[ prop ];
-
- // Avoid "Member not found" error in IE8 caused by setting window.constructor
- } else if ( prop !== "constructor" || a !== window ) {
- a[ prop ] = b[ prop ];
- }
- }
-
- return a;
-}
-
-/**
- * @param {HTMLElement} elem
- * @param {string} type
- * @param {Function} fn
- */
-function addEvent( elem, type, fn ) {
- // Standards-based browsers
- if ( elem.addEventListener ) {
- elem.addEventListener( type, fn, false );
- // IE
- } else {
- elem.attachEvent( "on" + type, fn );
- }
-}
-
-/**
- * @param {Array|NodeList} elems
- * @param {string} type
- * @param {Function} fn
- */
-function addEvents( elems, type, fn ) {
- var i = elems.length;
- while ( i-- ) {
- addEvent( elems[i], type, fn );
- }
-}
-
-function hasClass( elem, name ) {
- return (" " + elem.className + " ").indexOf(" " + name + " ") > -1;
-}
-
-function addClass( elem, name ) {
- if ( !hasClass( elem, name ) ) {
- elem.className += (elem.className ? " " : "") + name;
- }
-}
-
-function removeClass( elem, name ) {
- var set = " " + elem.className + " ";
- // Class name may appear multiple times
- while ( set.indexOf(" " + name + " ") > -1 ) {
- set = set.replace(" " + name + " " , " ");
- }
- // If possible, trim it for prettiness, but not neccecarily
- elem.className = window.jQuery ? jQuery.trim( set ) : ( set.trim ? set.trim() : set );
-}
-
-function id( name ) {
- return !!( typeof document !== "undefined" && document && document.getElementById ) &&
- document.getElementById( name );
-}
-
-function registerLoggingCallback( key ) {
- return function( callback ) {
- config[key].push( callback );
- };
-}
-
-// Supports deprecated method of completely overwriting logging callbacks
-function runLoggingCallbacks( key, scope, args ) {
- var i, callbacks;
- if ( QUnit.hasOwnProperty( key ) ) {
- QUnit[ key ].call(scope, args );
- } else {
- callbacks = config[ key ];
- for ( i = 0; i < callbacks.length; i++ ) {
- callbacks[ i ].call( scope, args );
- }
- }
-}
-
-// Test for equality any JavaScript type.
-// Author: Philippe Rathé
-QUnit.equiv = (function() {
-
- // Call the o related callback with the given arguments.
- function bindCallbacks( o, callbacks, args ) {
- var prop = QUnit.objectType( o );
- if ( prop ) {
- if ( QUnit.objectType( callbacks[ prop ] ) === "function" ) {
- return callbacks[ prop ].apply( callbacks, args );
- } else {
- return callbacks[ prop ]; // or undefined
- }
- }
- }
-
- // the real equiv function
- var innerEquiv,
- // stack to decide between skip/abort functions
- callers = [],
- // stack to avoiding loops from circular referencing
- parents = [],
-
- getProto = Object.getPrototypeOf || function ( obj ) {
- return obj.__proto__;
- },
- callbacks = (function () {
-
- // for string, boolean, number and null
- function useStrictEquality( b, a ) {
- /*jshint eqeqeq:false */
- if ( b instanceof a.constructor || a instanceof b.constructor ) {
- // to catch short annotaion VS 'new' annotation of a
- // declaration
- // e.g. var i = 1;
- // var j = new Number(1);
- return a == b;
- } else {
- return a === b;
- }
- }
-
- return {
- "string": useStrictEquality,
- "boolean": useStrictEquality,
- "number": useStrictEquality,
- "null": useStrictEquality,
- "undefined": useStrictEquality,
-
- "nan": function( b ) {
- return isNaN( b );
- },
-
- "date": function( b, a ) {
- return QUnit.objectType( b ) === "date" && a.valueOf() === b.valueOf();
- },
-
- "regexp": function( b, a ) {
- return QUnit.objectType( b ) === "regexp" &&
- // the regex itself
- a.source === b.source &&
- // and its modifers
- a.global === b.global &&
- // (gmi) ...
- a.ignoreCase === b.ignoreCase &&
- a.multiline === b.multiline &&
- a.sticky === b.sticky;
- },
-
- // - skip when the property is a method of an instance (OOP)
- // - abort otherwise,
- // initial === would have catch identical references anyway
- "function": function() {
- var caller = callers[callers.length - 1];
- return caller !== Object && typeof caller !== "undefined";
- },
-
- "array": function( b, a ) {
- var i, j, len, loop;
-
- // b could be an object literal here
- if ( QUnit.objectType( b ) !== "array" ) {
- return false;
- }
-
- len = a.length;
- if ( len !== b.length ) {
- // safe and faster
- return false;
- }
-
- // track reference to avoid circular references
- parents.push( a );
- for ( i = 0; i < len; i++ ) {
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- loop = true;// dont rewalk array
- }
- }
- if ( !loop && !innerEquiv(a[i], b[i]) ) {
- parents.pop();
- return false;
- }
- }
- parents.pop();
- return true;
- },
-
- "object": function( b, a ) {
- var i, j, loop,
- // Default to true
- eq = true,
- aProperties = [],
- bProperties = [];
-
- // comparing constructors is more strict than using
- // instanceof
- if ( a.constructor !== b.constructor ) {
- // Allow objects with no prototype to be equivalent to
- // objects with Object as their constructor.
- if ( !(( getProto(a) === null && getProto(b) === Object.prototype ) ||
- ( getProto(b) === null && getProto(a) === Object.prototype ) ) ) {
- return false;
- }
- }
-
- // stack constructor before traversing properties
- callers.push( a.constructor );
- // track reference to avoid circular references
- parents.push( a );
-
- for ( i in a ) { // be strict: don't ensures hasOwnProperty
- // and go deep
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- // don't go down the same path twice
- loop = true;
- }
- }
- aProperties.push(i); // collect a's properties
-
- if (!loop && !innerEquiv( a[i], b[i] ) ) {
- eq = false;
- break;
- }
- }
-
- callers.pop(); // unstack, we are done
- parents.pop();
-
- for ( i in b ) {
- bProperties.push( i ); // collect b's properties
- }
-
- // Ensures identical properties name
- return eq && innerEquiv( aProperties.sort(), bProperties.sort() );
- }
- };
- }());
-
- innerEquiv = function() { // can take multiple arguments
- var args = [].slice.apply( arguments );
- if ( args.length < 2 ) {
- return true; // end transition
- }
-
- return (function( a, b ) {
- if ( a === b ) {
- return true; // catch the most you can
- } else if ( a === null || b === null || typeof a === "undefined" ||
- typeof b === "undefined" ||
- QUnit.objectType(a) !== QUnit.objectType(b) ) {
- return false; // don't lose time with error prone cases
- } else {
- return bindCallbacks(a, callbacks, [ b, a ]);
- }
-
- // apply transition with (1..n) arguments
- }( args[0], args[1] ) && arguments.callee.apply( this, args.splice(1, args.length - 1 )) );
- };
-
- return innerEquiv;
-}());
-
-/**
- * jsDump Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com |
- * http://flesler.blogspot.com Licensed under BSD
- * (http://www.opensource.org/licenses/bsd-license.php) Date: 5/15/2008
- *
- * @projectDescription Advanced and extensible data dumping for Javascript.
- * @version 1.0.0
- * @author Ariel Flesler
- * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html}
- */
-QUnit.jsDump = (function() {
- function quote( str ) {
- return '"' + str.toString().replace( /"/g, '\\"' ) + '"';
- }
- function literal( o ) {
- return o + "";
- }
- function join( pre, arr, post ) {
- var s = jsDump.separator(),
- base = jsDump.indent(),
- inner = jsDump.indent(1);
- if ( arr.join ) {
- arr = arr.join( "," + s + inner );
- }
- if ( !arr ) {
- return pre + post;
- }
- return [ pre, inner + arr, base + post ].join(s);
- }
- function array( arr, stack ) {
- var i = arr.length, ret = new Array(i);
- this.up();
- while ( i-- ) {
- ret[i] = this.parse( arr[i] , undefined , stack);
- }
- this.down();
- return join( "[", ret, "]" );
- }
-
- var reName = /^function (\w+)/,
- jsDump = {
- // type is used mostly internally, you can fix a (custom)type in advance
- parse: function( obj, type, stack ) {
- stack = stack || [ ];
- var inStack, res,
- parser = this.parsers[ type || this.typeOf(obj) ];
-
- type = typeof parser;
- inStack = inArray( obj, stack );
-
- if ( inStack !== -1 ) {
- return "recursion(" + (inStack - stack.length) + ")";
- }
- if ( type === "function" ) {
- stack.push( obj );
- res = parser.call( this, obj, stack );
- stack.pop();
- return res;
- }
- return ( type === "string" ) ? parser : this.parsers.error;
- },
- typeOf: function( obj ) {
- var type;
- if ( obj === null ) {
- type = "null";
- } else if ( typeof obj === "undefined" ) {
- type = "undefined";
- } else if ( QUnit.is( "regexp", obj) ) {
- type = "regexp";
- } else if ( QUnit.is( "date", obj) ) {
- type = "date";
- } else if ( QUnit.is( "function", obj) ) {
- type = "function";
- } else if ( typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined" ) {
- type = "window";
- } else if ( obj.nodeType === 9 ) {
- type = "document";
- } else if ( obj.nodeType ) {
- type = "node";
- } else if (
- // native arrays
- toString.call( obj ) === "[object Array]" ||
- // NodeList objects
- ( typeof obj.length === "number" && typeof obj.item !== "undefined" && ( obj.length ? obj.item(0) === obj[0] : ( obj.item( 0 ) === null && typeof obj[0] === "undefined" ) ) )
- ) {
- type = "array";
- } else if ( obj.constructor === Error.prototype.constructor ) {
- type = "error";
- } else {
- type = typeof obj;
- }
- return type;
- },
- separator: function() {
- return this.multiline ? this.HTML ? "
" : "\n" : this.HTML ? " " : " ";
- },
- // extra can be a number, shortcut for increasing-calling-decreasing
- indent: function( extra ) {
- if ( !this.multiline ) {
- return "";
- }
- var chr = this.indentChar;
- if ( this.HTML ) {
- chr = chr.replace( /\t/g, " " ).replace( / /g, " " );
- }
- return new Array( this._depth_ + (extra||0) ).join(chr);
- },
- up: function( a ) {
- this._depth_ += a || 1;
- },
- down: function( a ) {
- this._depth_ -= a || 1;
- },
- setParser: function( name, parser ) {
- this.parsers[name] = parser;
- },
- // The next 3 are exposed so you can use them
- quote: quote,
- literal: literal,
- join: join,
- //
- _depth_: 1,
- // This is the list of parsers, to modify them, use jsDump.setParser
- parsers: {
- window: "[Window]",
- document: "[Document]",
- error: function(error) {
- return "Error(\"" + error.message + "\")";
- },
- unknown: "[Unknown]",
- "null": "null",
- "undefined": "undefined",
- "function": function( fn ) {
- var ret = "function",
- // functions never have name in IE
- name = "name" in fn ? fn.name : (reName.exec(fn) || [])[1];
-
- if ( name ) {
- ret += " " + name;
- }
- ret += "( ";
-
- ret = [ ret, QUnit.jsDump.parse( fn, "functionArgs" ), "){" ].join( "" );
- return join( ret, QUnit.jsDump.parse(fn,"functionCode" ), "}" );
- },
- array: array,
- nodelist: array,
- "arguments": array,
- object: function( map, stack ) {
- var ret = [ ], keys, key, val, i;
- QUnit.jsDump.up();
- keys = [];
- for ( key in map ) {
- keys.push( key );
- }
- keys.sort();
- for ( i = 0; i < keys.length; i++ ) {
- key = keys[ i ];
- val = map[ key ];
- ret.push( QUnit.jsDump.parse( key, "key" ) + ": " + QUnit.jsDump.parse( val, undefined, stack ) );
- }
- QUnit.jsDump.down();
- return join( "{", ret, "}" );
- },
- node: function( node ) {
- var len, i, val,
- open = QUnit.jsDump.HTML ? "<" : "<",
- close = QUnit.jsDump.HTML ? ">" : ">",
- tag = node.nodeName.toLowerCase(),
- ret = open + tag,
- attrs = node.attributes;
-
- if ( attrs ) {
- for ( i = 0, len = attrs.length; i < len; i++ ) {
- val = attrs[i].nodeValue;
- // IE6 includes all attributes in .attributes, even ones not explicitly set.
- // Those have values like undefined, null, 0, false, "" or "inherit".
- if ( val && val !== "inherit" ) {
- ret += " " + attrs[i].nodeName + "=" + QUnit.jsDump.parse( val, "attribute" );
- }
- }
- }
- ret += close;
-
- // Show content of TextNode or CDATASection
- if ( node.nodeType === 3 || node.nodeType === 4 ) {
- ret += node.nodeValue;
- }
-
- return ret + open + "/" + tag + close;
- },
- // function calls it internally, it's the arguments part of the function
- functionArgs: function( fn ) {
- var args,
- l = fn.length;
-
- if ( !l ) {
- return "";
- }
-
- args = new Array(l);
- while ( l-- ) {
- // 97 is 'a'
- args[l] = String.fromCharCode(97+l);
- }
- return " " + args.join( ", " ) + " ";
- },
- // object calls it internally, the key part of an item in a map
- key: quote,
- // function calls it internally, it's the content of the function
- functionCode: "[code]",
- // node calls it internally, it's an html attribute value
- attribute: quote,
- string: quote,
- date: quote,
- regexp: literal,
- number: literal,
- "boolean": literal
- },
- // if true, entities are escaped ( <, >, \t, space and \n )
- HTML: false,
- // indentation unit
- indentChar: " ",
- // if true, items in a collection, are separated by a \n, else just a space.
- multiline: true
- };
-
- return jsDump;
-}());
-
-// from jquery.js
-function inArray( elem, array ) {
- if ( array.indexOf ) {
- return array.indexOf( elem );
- }
-
- for ( var i = 0, length = array.length; i < length; i++ ) {
- if ( array[ i ] === elem ) {
- return i;
- }
- }
-
- return -1;
-}
-
-/*
- * Javascript Diff Algorithm
- * By John Resig (http://ejohn.org/)
- * Modified by Chu Alan "sprite"
- *
- * Released under the MIT license.
- *
- * More Info:
- * http://ejohn.org/projects/javascript-diff-algorithm/
- *
- * Usage: QUnit.diff(expected, actual)
- *
- * QUnit.diff( "the quick brown fox jumped over", "the quick fox jumps over" ) == "the quick brown fox jumped jumps over"
- */
-QUnit.diff = (function() {
- /*jshint eqeqeq:false, eqnull:true */
- function diff( o, n ) {
- var i,
- ns = {},
- os = {};
-
- for ( i = 0; i < n.length; i++ ) {
- if ( !hasOwn.call( ns, n[i] ) ) {
- ns[ n[i] ] = {
- rows: [],
- o: null
- };
- }
- ns[ n[i] ].rows.push( i );
- }
-
- for ( i = 0; i < o.length; i++ ) {
- if ( !hasOwn.call( os, o[i] ) ) {
- os[ o[i] ] = {
- rows: [],
- n: null
- };
- }
- os[ o[i] ].rows.push( i );
- }
-
- for ( i in ns ) {
- if ( !hasOwn.call( ns, i ) ) {
- continue;
- }
- if ( ns[i].rows.length === 1 && hasOwn.call( os, i ) && os[i].rows.length === 1 ) {
- n[ ns[i].rows[0] ] = {
- text: n[ ns[i].rows[0] ],
- row: os[i].rows[0]
- };
- o[ os[i].rows[0] ] = {
- text: o[ os[i].rows[0] ],
- row: ns[i].rows[0]
- };
- }
- }
-
- for ( i = 0; i < n.length - 1; i++ ) {
- if ( n[i].text != null && n[ i + 1 ].text == null && n[i].row + 1 < o.length && o[ n[i].row + 1 ].text == null &&
- n[ i + 1 ] == o[ n[i].row + 1 ] ) {
-
- n[ i + 1 ] = {
- text: n[ i + 1 ],
- row: n[i].row + 1
- };
- o[ n[i].row + 1 ] = {
- text: o[ n[i].row + 1 ],
- row: i + 1
- };
- }
- }
-
- for ( i = n.length - 1; i > 0; i-- ) {
- if ( n[i].text != null && n[ i - 1 ].text == null && n[i].row > 0 && o[ n[i].row - 1 ].text == null &&
- n[ i - 1 ] == o[ n[i].row - 1 ]) {
-
- n[ i - 1 ] = {
- text: n[ i - 1 ],
- row: n[i].row - 1
- };
- o[ n[i].row - 1 ] = {
- text: o[ n[i].row - 1 ],
- row: i - 1
- };
- }
- }
-
- return {
- o: o,
- n: n
- };
- }
-
- return function( o, n ) {
- o = o.replace( /\s+$/, "" );
- n = n.replace( /\s+$/, "" );
-
- var i, pre,
- str = "",
- out = diff( o === "" ? [] : o.split(/\s+/), n === "" ? [] : n.split(/\s+/) ),
- oSpace = o.match(/\s+/g),
- nSpace = n.match(/\s+/g);
-
- if ( oSpace == null ) {
- oSpace = [ " " ];
- }
- else {
- oSpace.push( " " );
- }
-
- if ( nSpace == null ) {
- nSpace = [ " " ];
- }
- else {
- nSpace.push( " " );
- }
-
- if ( out.n.length === 0 ) {
- for ( i = 0; i < out.o.length; i++ ) {
- str += "" + out.o[i] + oSpace[i] + "";
- }
- }
- else {
- if ( out.n[0].text == null ) {
- for ( n = 0; n < out.o.length && out.o[n].text == null; n++ ) {
- str += "" + out.o[n] + oSpace[n] + "";
- }
- }
-
- for ( i = 0; i < out.n.length; i++ ) {
- if (out.n[i].text == null) {
- str += "" + out.n[i] + nSpace[i] + "";
- }
- else {
- // `pre` initialized at top of scope
- pre = "";
-
- for ( n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++ ) {
- pre += "" + out.o[n] + oSpace[n] + "";
- }
- str += " " + out.n[i].text + nSpace[i] + pre;
- }
- }
- }
-
- return str;
- };
-}());
-
-// for CommonJS enviroments, export everything
-if ( typeof exports !== "undefined" ) {
- extend( exports, QUnit );
-}
-
-// get at whatever the global object is, like window in browsers
-}( (function() {return this;}.call()) ));
diff --git a/test/lib/require.js b/test/lib/require.js
deleted file mode 100644
index 987f865..0000000
--- a/test/lib/require.js
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- RequireJS 2.1.5 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.
- Available via the MIT or new BSD license.
- see: http://github.com/jrburke/requirejs for details
-*/
-var requirejs,require,define;
-(function(aa){function I(b){return"[object Function]"===L.call(b)}function J(b){return"[object Array]"===L.call(b)}function y(b,c){if(b){var d;for(d=0;dthis.depCount&&!this.defined){if(I(n)){if(this.events.error)try{e=i.execCb(c,n,b,e)}catch(d){a=d}else e=i.execCb(c,n,b,e);this.map.isDefine&&((b=this.module)&&void 0!==b.exports&&b.exports!==this.exports?e=b.exports:void 0===e&&this.usingExports&&(e=this.exports));if(a)return a.requireMap=this.map,a.requireModules=[this.map.id],a.requireType="define",v(this.error=
-a)}else e=n;this.exports=e;if(this.map.isDefine&&!this.ignore&&(q[c]=e,l.onResourceLoad))l.onResourceLoad(i,this.map,this.depMaps);x(c);this.defined=!0}this.defining=!1;this.defined&&!this.defineEmitted&&(this.defineEmitted=!0,this.emit("defined",this.exports),this.defineEmitComplete=!0)}}else this.fetch()}},callPlugin:function(){var a=this.map,b=a.id,d=j(a.prefix);this.depMaps.push(d);t(d,"defined",u(this,function(e){var n,d;d=this.map.name;var g=this.map.parentMap?this.map.parentMap.name:null,h=
-i.makeRequire(a.parentMap,{enableBuildCallback:!0});if(this.map.unnormalized){if(e.normalize&&(d=e.normalize(d,function(a){return c(a,g,!0)})||""),e=j(a.prefix+"!"+d,this.map.parentMap),t(e,"defined",u(this,function(a){this.init([],function(){return a},null,{enabled:!0,ignore:!0})})),d=m(p,e.id)){this.depMaps.push(e);if(this.events.error)d.on("error",u(this,function(a){this.emit("error",a)}));d.enable()}}else n=u(this,function(a){this.init([],function(){return a},null,{enabled:!0})}),n.error=u(this,
-function(a){this.inited=!0;this.error=a;a.requireModules=[b];G(p,function(a){0===a.map.id.indexOf(b+"_unnormalized")&&x(a.map.id)});v(a)}),n.fromText=u(this,function(e,c){var d=a.name,g=j(d),C=O;c&&(e=c);C&&(O=!1);r(g);s(k.config,b)&&(k.config[d]=k.config[b]);try{l.exec(e)}catch(ca){return v(B("fromtexteval","fromText eval for "+b+" failed: "+ca,ca,[b]))}C&&(O=!0);this.depMaps.push(g);i.completeLoad(d);h([d],n)}),e.load(a.name,h,n,k)}));i.enable(d,this);this.pluginMaps[d.id]=d},enable:function(){V[this.map.id]=
-this;this.enabling=this.enabled=!0;y(this.depMaps,u(this,function(a,b){var c,e;if("string"===typeof a){a=j(a,this.map.isDefine?this.map:this.map.parentMap,!1,!this.skipMap);this.depMaps[b]=a;if(c=m(N,a.id)){this.depExports[b]=c(this);return}this.depCount+=1;t(a,"defined",u(this,function(a){this.defineDep(b,a);this.check()}));this.errback&&t(a,"error",this.errback)}c=a.id;e=p[c];!s(N,c)&&(e&&!e.enabled)&&i.enable(a,this)}));G(this.pluginMaps,u(this,function(a){var b=m(p,a.id);b&&!b.enabled&&i.enable(a,
-this)}));this.enabling=!1;this.check()},on:function(a,b){var c=this.events[a];c||(c=this.events[a]=[]);c.push(b)},emit:function(a,b){y(this.events[a],function(a){a(b)});"error"===a&&delete this.events[a]}};i={config:k,contextName:b,registry:p,defined:q,urlFetched:U,defQueue:H,Module:Z,makeModuleMap:j,nextTick:l.nextTick,onError:v,configure:function(a){a.baseUrl&&"/"!==a.baseUrl.charAt(a.baseUrl.length-1)&&(a.baseUrl+="/");var b=k.pkgs,c=k.shim,e={paths:!0,config:!0,map:!0};G(a,function(a,b){e[b]?
-"map"===b?(k.map||(k.map={}),R(k[b],a,!0,!0)):R(k[b],a,!0):k[b]=a});a.shim&&(G(a.shim,function(a,b){J(a)&&(a={deps:a});if((a.exports||a.init)&&!a.exportsFn)a.exportsFn=i.makeShimExports(a);c[b]=a}),k.shim=c);a.packages&&(y(a.packages,function(a){a="string"===typeof a?{name:a}:a;b[a.name]={name:a.name,location:a.location||a.name,main:(a.main||"main").replace(ja,"").replace(ea,"")}}),k.pkgs=b);G(p,function(a,b){!a.inited&&!a.map.unnormalized&&(a.map=j(b))});if(a.deps||a.callback)i.require(a.deps||[],
-a.callback)},makeShimExports:function(a){return function(){var b;a.init&&(b=a.init.apply(aa,arguments));return b||a.exports&&ba(a.exports)}},makeRequire:function(a,f){function d(e,c,h){var g,k;f.enableBuildCallback&&(c&&I(c))&&(c.__requireJsBuild=!0);if("string"===typeof e){if(I(c))return v(B("requireargs","Invalid require call"),h);if(a&&s(N,e))return N[e](p[a.id]);if(l.get)return l.get(i,e,a,d);g=j(e,a,!1,!0);g=g.id;return!s(q,g)?v(B("notloaded",'Module name "'+g+'" has not been loaded yet for context: '+
-b+(a?"":". Use require([])"))):q[g]}L();i.nextTick(function(){L();k=r(j(null,a));k.skipMap=f.skipMap;k.init(e,c,h,{enabled:!0});D()});return d}f=f||{};R(d,{isBrowser:A,toUrl:function(b){var d,f=b.lastIndexOf("."),g=b.split("/")[0];if(-1!==f&&(!("."===g||".."===g)||1h.attachEvent.toString().indexOf("[native code"))&&!Y?(O=!0,h.attachEvent("onreadystatechange",b.onScriptLoad)):(h.addEventListener("load",b.onScriptLoad,!1),h.addEventListener("error",b.onScriptError,!1)),h.src=d,K=h,D?x.insertBefore(h,D):x.appendChild(h),K=null,h;if(da)try{importScripts(d),b.completeLoad(c)}catch(j){b.onError(B("importscripts","importScripts failed for "+c+" at "+d,j,[c]))}};A&&M(document.getElementsByTagName("script"),function(b){x||(x=
-b.parentNode);if(t=b.getAttribute("data-main"))return r.baseUrl||(E=t.split("/"),Q=E.pop(),fa=E.length?E.join("/")+"/":"./",r.baseUrl=fa,t=Q),t=t.replace(ea,""),r.deps=r.deps?r.deps.concat(t):[t],!0});define=function(b,c,d){var l,h;"string"!==typeof b&&(d=c,c=b,b=null);J(c)||(d=c,c=[]);!c.length&&I(d)&&d.length&&(d.toString().replace(la,"").replace(ma,function(b,d){c.push(d)}),c=(1===d.length?["require"]:["require","exports","module"]).concat(c));if(O){if(!(l=K))P&&"interactive"===P.readyState||M(document.getElementsByTagName("script"),
-function(b){if("interactive"===b.readyState)return P=b}),l=P;l&&(b||(b=l.getAttribute("data-requiremodule")),h=F[l.getAttribute("data-requirecontext")])}(h?h.defQueue:T).push([b,c,d])};define.amd={jQuery:!0};l.exec=function(b){return eval(b)};l(r)}})(this);
diff --git a/test/lib/resemble.js b/test/lib/resemble.js
new file mode 100644
index 0000000..1cb8c29
--- /dev/null
+++ b/test/lib/resemble.js
@@ -0,0 +1,535 @@
+/*
+Author: James Cryer
+Company: Huddle
+Last updated date: 21 Feb 2013
+URL: https://github.com/Huddle/Resemble.js
+*/
+
+(function(_this){
+ 'use strict';
+
+ _this['resemble'] = function( fileData ){
+
+ var data = {};
+ var images = [];
+ var updateCallbackArray = [];
+
+ var tolerance = { // between 0 and 255
+ red: 16,
+ green: 16,
+ blue: 16,
+ minBrightness: 16,
+ maxBrightness: 240
+ };
+
+ var ignoreAntialiasing = false;
+ var ignoreColors = false;
+
+ function triggerDataUpdate(){
+ var len = updateCallbackArray.length;
+ var i;
+ for(i=0;i tolerance.maxBrightness;
+ }
+
+ function getHue(r,g,b){
+
+ r = r / 255;
+ g = g / 255;
+ b = b / 255;
+ var max = Math.max(r, g, b), min = Math.min(r, g, b);
+ var h;
+ var d;
+
+ if (max == min){
+ h = 0; // achromatic
+ } else{
+ d = max - min;
+ switch(max){
+ case r: h = (g - b) / d + (g < b ? 6 : 0); break;
+ case g: h = (b - r) / d + 2; break;
+ case b: h = (r - g) / d + 4; break;
+ }
+ h /= 6;
+ }
+
+ return h;
+ }
+
+ function isAntialiased(sourcePix, data, cacheSet, verticalPos, horizontalPos, width){
+ var offset;
+ var targetPix;
+ var distance = 1;
+ var i;
+ var j;
+ var hasHighContrastSibling = 0;
+ var hasSiblingWithDifferentHue = 0;
+ var hasEquivilantSibling = 0;
+
+ addHueInfo(sourcePix);
+
+ for (i = distance*-1; i <= distance; i++){
+ for (j = distance*-1; j <= distance; j++){
+
+ if(i===0 && j===0){
+ // ignore source pixel
+ } else {
+
+ offset = ((verticalPos+j)*width + (horizontalPos+i)) * 4;
+ targetPix = getPixelInfo(data, offset, cacheSet);
+
+ if(targetPix === null){
+ continue;
+ }
+
+ addBrightnessInfo(targetPix);
+ addHueInfo(targetPix);
+
+ if( isContrasting(sourcePix, targetPix) ){
+ hasHighContrastSibling++;
+ }
+
+ if( isRGBSame(sourcePix,targetPix) ){
+ hasEquivilantSibling++;
+ }
+
+ if( Math.abs(targetPix.h - sourcePix.h) > 0.3 ){
+ hasSiblingWithDifferentHue++;
+ }
+
+ if( hasSiblingWithDifferentHue > 1 || hasHighContrastSibling > 1){
+ return true;
+ }
+ }
+ }
+ }
+
+ if(hasEquivilantSibling < 2){
+ return true;
+ }
+
+ return false;
+ }
+
+ function errorPixel(px, offset){
+ px[offset] = 255; //r
+ px[offset + 1] = 0; //g
+ px[offset + 2] = 255; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyPixel(px, offset, data){
+ px[offset] = data.r; //r
+ px[offset + 1] = data.g; //g
+ px[offset + 2] = data.b; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyGrayScalePixel(px, offset, data){
+ px[offset] = data.brightness; //r
+ px[offset + 1] = data.brightness; //g
+ px[offset + 2] = data.brightness; //b
+ px[offset + 3] = 255; //a
+ }
+
+
+ function getPixelInfo(data, offset, cacheSet){
+ var r;
+ var g;
+ var b;
+ var d;
+
+ if(typeof data[offset] !== 'undefined'){
+ r = data[offset];
+ g = data[offset+1];
+ b = data[offset+2];
+ d = {
+ r: r,
+ g: g,
+ b: b
+ };
+
+ return d;
+ } else {
+ return null;
+ }
+ }
+
+ function addBrightnessInfo(data){
+ data.brightness = getBrightness(data.r,data.g,data.b); // 'corrected' lightness
+ }
+
+ function addHueInfo(data){
+ data.h = getHue(data.r,data.g,data.b);
+ }
+
+ function analyseImages(img1, img2, width, height){
+
+ var hiddenCanvas = document.createElement('canvas');
+
+ var data1 = img1.data;
+ var data2 = img2.data;
+
+ hiddenCanvas.width = width;
+ hiddenCanvas.height = height;
+
+ var context = hiddenCanvas.getContext('2d');
+ var imgd = context.createImageData(width,height);
+ var targetPix = imgd.data;
+
+ var mismatchCount = 0;
+
+ var time = Date.now();
+
+ var skip;
+
+ if( (width > 1200 || height > 1200) && ignoreAntialiasing){
+ skip = 6;
+ }
+
+ loop(height, width, function(verticalPos, horizontalPos){
+
+ if(skip){ // only skip if the image isn't small
+ if(verticalPos % skip === 0 || horizontalPos % skip === 0){
+ return;
+ }
+ }
+
+ var offset = (verticalPos*width + horizontalPos) * 4;
+ var pixel1 = getPixelInfo(data1, offset, 1);
+ var pixel2 = getPixelInfo(data2, offset, 2);
+
+ if(pixel1 === null || pixel2 === null){
+ return;
+ }
+
+ if (ignoreColors){
+
+ addBrightnessInfo(pixel1);
+ addBrightnessInfo(pixel2);
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ return;
+ }
+
+ if( isRGBSimilar(pixel1, pixel2) ){
+ copyPixel(targetPix, offset, pixel2);
+
+ } else if( ignoreAntialiasing && (
+ addBrightnessInfo(pixel1), // jit pixel info augmentation looks a little weird, sorry.
+ addBrightnessInfo(pixel2),
+ isAntialiased(pixel1, data1, 1, verticalPos, horizontalPos, width) ||
+ isAntialiased(pixel2, data2, 2, verticalPos, horizontalPos, width)
+ )){
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+
+ });
+
+ data.misMatchPercentage = (mismatchCount / (height*width) * 100).toFixed(2);
+ data.analysisTime = Date.now() - time;
+
+ data.getImageDataUrl = function(text){
+ var barHeight = 0;
+
+ if(text){
+ barHeight = addLabel(text,context,hiddenCanvas);
+ }
+
+ context.putImageData(imgd, 0, barHeight);
+
+ return hiddenCanvas.toDataURL("image/png");
+ };
+ }
+
+ function addLabel(text, context, hiddenCanvas){
+ var textPadding = 2;
+
+ context.font = '12px sans-serif';
+
+ var textWidth = context.measureText(text).width + textPadding*2;
+ var barHeight = 22;
+
+ if(textWidth > hiddenCanvas.width){
+ hiddenCanvas.width = textWidth;
+ }
+
+ hiddenCanvas.height += barHeight;
+
+ context.fillStyle = "#666";
+ context.fillRect(0,0,hiddenCanvas.width,barHeight -4);
+ context.fillStyle = "#fff";
+ context.fillRect(0,barHeight -4,hiddenCanvas.width, 4);
+
+ context.fillStyle = "#fff";
+ context.textBaseline = "top";
+ context.font = '12px sans-serif';
+ context.fillText(text, textPadding, 1);
+
+ return barHeight;
+ }
+
+ function normalise(img, w, h){
+ var c;
+ var context;
+
+ if(img.height < h || img.width < w){
+ c = document.createElement('canvas');
+ c.width = w;
+ c.height = h;
+ context = c.getContext('2d');
+ context.putImageData(img, 0, 0);
+ return context.getImageData(0, 0, w, h);
+ }
+
+ return img;
+ }
+
+ function compare(one, two){
+
+ function onceWeHaveBoth(){
+ var width;
+ var height;
+ if(images.length === 2){
+ width = images[0].width > images[1].width ? images[0].width : images[1].width;
+ height = images[0].height > images[1].height ? images[0].height : images[1].height;
+
+ if( (images[0].width === images[1].width) && (images[0].height === images[1].height) ){
+ data.isSameDimensions = true;
+ } else {
+ data.isSameDimensions = false;
+ }
+
+ analyseImages( normalise(images[0],width, height), normalise(images[1],width, height), width, height);
+
+ triggerDataUpdate();
+ }
+ }
+
+ images = [];
+ loadImageData(one, onceWeHaveBoth);
+ loadImageData(two, onceWeHaveBoth);
+ }
+
+ function getCompareApi(param){
+
+ var secondFileData,
+ hasMethod = typeof param === 'function';
+
+ if( !hasMethod ){
+ // assume it's file data
+ secondFileData = param;
+ }
+
+ var self = {
+ ignoreNothing: function(){
+
+ tolerance.red = 16;
+ tolerance.green = 16;
+ tolerance.blue = 16;
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreAntialiasing: function(){
+
+ tolerance.red = 32;
+ tolerance.green = 32;
+ tolerance.blue = 32;
+ tolerance.minBrightness = 64;
+ tolerance.maxBrightness = 96;
+
+ ignoreAntialiasing = true;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreColors: function(){
+
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = true;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ onComplete: function( callback ){
+
+ updateCallbackArray.push(callback);
+
+ var wrapper = function(){
+ compare(fileData, secondFileData);
+ };
+
+ wrapper();
+
+ return getCompareApi(wrapper);
+ }
+ };
+
+ return self;
+ }
+
+ return {
+ onComplete: function( callback ){
+ updateCallbackArray.push(callback);
+ loadImageData(fileData, function(imageData, width, height){
+ parseImage(imageData.data, width, height);
+ });
+ },
+ compareTo: function(secondFileData){
+ return getCompareApi(secondFileData);
+ }
+ };
+
+ };
+}(this));
\ No newline at end of file
diff --git a/test/testsuite.js b/test/testsuite.js
deleted file mode 100644
index b486acb..0000000
--- a/test/testsuite.js
+++ /dev/null
@@ -1,36 +0,0 @@
-requirejs.config({
- baseUrl: '/test/unit/'
-});
-
-define(function(require) {
- var testModules = [
- 'Pixi',
- 'Point',
- 'Rectangle',
- 'DisplayObject',
- 'DisplayObjectContainer',
- 'Sprite',
- 'MovieClip',
- 'InteractionManager',
- 'Stage',
- 'utils/Utils',
- 'utils/EventTarget',
- 'utils/Matrix',
- 'utils/Detector',
- 'renderers/WebGLShaders',
- 'renderers/WebGLRenderer',
- 'renderers/WebGLBatch',
- 'renderers/CanvasRenderer',
- 'extras/Strip',
- 'extras/Rope',
- 'textures/BaseTexture',
- 'textures/Texture',
- 'loaders/SpriteSheetLoader',
- 'loaders/AssetLoader'
- ];
-
- // Resolve all testModules and then start the Test Runner.
- require(testModules, function() {
- QUnit.start();
- });
-});
\ No newline at end of file
diff --git a/test/textures/SpriteSheet-Aliens.png b/test/textures/SpriteSheet-Aliens.png
new file mode 100644
index 0000000..210acb1
--- /dev/null
+++ b/test/textures/SpriteSheet-Aliens.png
Binary files differ
diff --git a/test/textures/SpriteSheet-Explosion.png b/test/textures/SpriteSheet-Explosion.png
new file mode 100755
index 0000000..79e1a69
--- /dev/null
+++ b/test/textures/SpriteSheet-Explosion.png
Binary files differ
diff --git a/test/textures/bunny.png b/test/textures/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/textures/bunny.png
Binary files differ
diff --git a/test/unit/DisplayObject.js b/test/unit/DisplayObject.js
deleted file mode 100644
index 5e7e72f..0000000
--- a/test/unit/DisplayObject.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObject');
-});
diff --git a/test/unit/DisplayObjectContainer.js b/test/unit/DisplayObjectContainer.js
deleted file mode 100644
index b323959..0000000
--- a/test/unit/DisplayObjectContainer.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObjectContainer');
-});
diff --git a/test/unit/InteractionManager.js b/test/unit/InteractionManager.js
deleted file mode 100644
index e751f52..0000000
--- a/test/unit/InteractionManager.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('InteractionManager');
-});
diff --git a/test/unit/MovieClip.js b/test/unit/MovieClip.js
deleted file mode 100644
index 37d9446..0000000
--- a/test/unit/MovieClip.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('MovieClip');
-});
diff --git a/test/unit/Pixi.js b/test/unit/Pixi.js
deleted file mode 100644
index 36eee73..0000000
--- a/test/unit/Pixi.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Pixi');
-});
diff --git a/test/unit/Point.js b/test/unit/Point.js
deleted file mode 100644
index 983ff6e..0000000
--- a/test/unit/Point.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Point');
-});
diff --git a/test/unit/Rectangle.js b/test/unit/Rectangle.js
deleted file mode 100644
index 3b439ba..0000000
--- a/test/unit/Rectangle.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Rectangle');
-});
diff --git a/test/unit/Sprite.js b/test/unit/Sprite.js
deleted file mode 100644
index ed4f596..0000000
--- a/test/unit/Sprite.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Sprite');
-});
diff --git a/test/unit/Stage.js b/test/unit/Stage.js
deleted file mode 100644
index 2d70291..0000000
--- a/test/unit/Stage.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Stage');
-});
diff --git a/test/unit/extras/Rope.js b/test/unit/extras/Rope.js
deleted file mode 100644
index 5606f14..0000000
--- a/test/unit/extras/Rope.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Rope');
-});
diff --git a/test/unit/extras/Strip.js b/test/unit/extras/Strip.js
deleted file mode 100644
index 0134d3a..0000000
--- a/test/unit/extras/Strip.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Strip');
-});
diff --git a/test/unit/loaders/AssetLoader.js b/test/unit/loaders/AssetLoader.js
deleted file mode 100644
index 13b8443..0000000
--- a/test/unit/loaders/AssetLoader.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('AssetLoader');
-});
diff --git a/test/unit/loaders/SpriteSheetLoader.js b/test/unit/loaders/SpriteSheetLoader.js
deleted file mode 100644
index 8bf0cb2..0000000
--- a/test/unit/loaders/SpriteSheetLoader.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('SpriteSheetLoader');
-});
diff --git a/test/unit/pixi/InteractionManager.js b/test/unit/pixi/InteractionManager.js
new file mode 100644
index 0000000..ed3001f
--- /dev/null
+++ b/test/unit/pixi/InteractionManager.js
@@ -0,0 +1,10 @@
+describe('pixi/InteractionManager', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var InteractionManager = PIXI.InteractionManager;
+
+ it('Module exists', function () {
+ expect(InteractionManager).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/Pixi.js b/test/unit/pixi/Pixi.js
new file mode 100644
index 0000000..27debc1
--- /dev/null
+++ b/test/unit/pixi/Pixi.js
@@ -0,0 +1,9 @@
+describe('pixi/Pixi', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+
+ it('Module exists', function () {
+ expect(global).to.have.property('PIXI').and.to.be.an('object');
+ });
+});
diff --git a/test/unit/pixi/core/Circle.js b/test/unit/pixi/core/Circle.js
new file mode 100644
index 0000000..93a4456
--- /dev/null
+++ b/test/unit/pixi/core/Circle.js
@@ -0,0 +1,22 @@
+describe('pixi/core/Circle', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Circle = PIXI.Circle;
+
+ it('Module exists', function () {
+ expect(Circle).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Circle();
+
+ expect(obj).to.be.an.instanceof(Circle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', 0);
+ expect(obj).to.have.property('y', 0);
+ expect(obj).to.have.property('radius', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Ellipse.js b/test/unit/pixi/core/Ellipse.js
new file mode 100644
index 0000000..026b56f
--- /dev/null
+++ b/test/unit/pixi/core/Ellipse.js
@@ -0,0 +1,24 @@
+describe('pixi/core/Ellipse', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Ellipse = PIXI.Ellipse;
+
+ it('Module exists', function () {
+ expect(Ellipse).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Ellipse();
+
+ expect(obj).to.be.an.instanceof(Ellipse);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+ expect(obj).to.respondTo('getBounds');
+
+ expect(obj).to.have.property('x', 0);
+ expect(obj).to.have.property('y', 0);
+ expect(obj).to.have.property('width', 0);
+ expect(obj).to.have.property('height', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Matrix.js b/test/unit/pixi/core/Matrix.js
new file mode 100644
index 0000000..b48989e
--- /dev/null
+++ b/test/unit/pixi/core/Matrix.js
@@ -0,0 +1,30 @@
+describe('pixi/core/Matrix', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var mat3 = PIXI.mat3;
+ var mat4 = PIXI.mat4;
+ var Matrix = PIXI.Matrix;
+
+ it('Ensure determineMatrixArrayType works', function () {
+ expect(Matrix).to.be.a('function');
+ });
+
+ it('mat3 exists', function () {
+ expect(mat3).to.be.an('object');
+ });
+
+ it('Confirm new mat3 matrix', function () {
+ var matrix = new mat3.create();
+ pixi_core_Matrix_confirmNewMat3(matrix);
+ });
+
+ it('mat3 exists', function () {
+ expect(mat4).to.be.an('object');
+ });
+
+ it('Confirm new mat4 matrix', function () {
+ var matrix = new mat4.create();
+ pixi_core_Matrix_confirmNewMat4(matrix);
+ });
+});
diff --git a/test/unit/pixi/core/Point.js b/test/unit/pixi/core/Point.js
new file mode 100644
index 0000000..c4d5163
--- /dev/null
+++ b/test/unit/pixi/core/Point.js
@@ -0,0 +1,15 @@
+describe('pixi/core/Point', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Point = PIXI.Point;
+
+ it('Module exists', function () {
+ expect(Point).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Point();
+ pixi_core_Point_confirm(obj, 0, 0);
+ });
+});
diff --git a/test/unit/pixi/core/Polygon.js b/test/unit/pixi/core/Polygon.js
new file mode 100644
index 0000000..dc8c918
--- /dev/null
+++ b/test/unit/pixi/core/Polygon.js
@@ -0,0 +1,20 @@
+describe('pixi/core/Polygon', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Polygon = PIXI.Polygon;
+
+ it('Module exists', function () {
+ expect(Polygon).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Polygon();
+
+ expect(obj).to.be.an.instanceof(Polygon);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.deep.property('points.length', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Rectangle.js b/test/unit/pixi/core/Rectangle.js
new file mode 100644
index 0000000..d43316e
--- /dev/null
+++ b/test/unit/pixi/core/Rectangle.js
@@ -0,0 +1,15 @@
+describe('pixi/core/Rectangle', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Rectangle = PIXI.Rectangle;
+
+ it('Module exists', function () {
+ expect(Rectangle).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var rect = new Rectangle();
+ pixi_core_Rectangle_confirm(rect, 0, 0, 0, 0);
+ });
+});
diff --git a/test/unit/pixi/display/DisplayObject.js b/test/unit/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..40c6fbc
--- /dev/null
+++ b/test/unit/pixi/display/DisplayObject.js
@@ -0,0 +1,21 @@
+describe('pixi/display/DisplayObject', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var DisplayObject = PIXI.DisplayObject;
+
+ it('Module exists', function () {
+ expect(DisplayObject).to.be.a('function');
+ expect(PIXI).to.have.property('visibleCount', 0);
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new DisplayObject();
+
+ pixi_display_DisplayObject_confirmNew(obj);
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', false);
+ expect(obj).to.have.property('stage', null);
+ });
+});
diff --git a/test/unit/pixi/display/DisplayObjectContainer.js b/test/unit/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..ce7f02f
--- /dev/null
+++ b/test/unit/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,20 @@
+describe('pixi/display/DisplayObjectContainer', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var DisplayObjectContainer = PIXI.DisplayObjectContainer;
+
+ it('Module exists', function () {
+ expect(DisplayObjectContainer).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new DisplayObjectContainer();
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', false);
+ expect(obj).to.have.property('stage', null);
+ });
+});
diff --git a/test/unit/pixi/display/MovieClip.js b/test/unit/pixi/display/MovieClip.js
new file mode 100644
index 0000000..f3c6c6a
--- /dev/null
+++ b/test/unit/pixi/display/MovieClip.js
@@ -0,0 +1,33 @@
+describe('pixi/display/MovieClip', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var MovieClip = PIXI.MovieClip;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(MovieClip).to.be.a('function');
+ });
+
+ it('Confirm new instance', function (done) {
+ var texture = Texture.fromImage('/base/test/textures/SpriteSheet-Explosion.png');
+ var obj = new MovieClip([texture]);
+
+ pixi_display_Sprite_confirmNew(obj, done);
+
+ expect(obj).to.be.an.instanceof(MovieClip);
+ expect(obj).to.respondTo('stop');
+ expect(obj).to.respondTo('play');
+ expect(obj).to.respondTo('gotoAndStop');
+ expect(obj).to.respondTo('gotoAndPlay');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('textures.length', 1);
+ expect(obj).to.have.deep.property('textures[0]', texture);
+ expect(obj).to.have.property('animationSpeed', 1);
+ expect(obj).to.have.property('loop', true);
+ expect(obj).to.have.property('onComplete', null);
+ expect(obj).to.have.property('currentFrame', 0);
+ expect(obj).to.have.property('playing', false);
+ });
+});
diff --git a/test/unit/pixi/display/Sprite.js b/test/unit/pixi/display/Sprite.js
new file mode 100644
index 0000000..54e914f
--- /dev/null
+++ b/test/unit/pixi/display/Sprite.js
@@ -0,0 +1,25 @@
+describe('pixi/display/Sprite', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Sprite = PIXI.Sprite;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(Sprite).to.be.a('function');
+ expect(PIXI).to.have.deep.property('blendModes.NORMAL', 0);
+ expect(PIXI).to.have.deep.property('blendModes.SCREEN', 1);
+ });
+
+ it('Members exist', function () {
+ expect(Sprite).itself.to.respondTo('fromImage');
+ expect(Sprite).itself.to.respondTo('fromFrame');
+ });
+
+ it('Confirm new instance', function (done) {
+ var texture = Texture.fromImage('/base/test/textures/SpriteSheet-Aliens.png');
+ var obj = new Sprite(texture);
+
+ pixi_display_Sprite_confirmNew(obj, done);
+ });
+});
diff --git a/test/unit/pixi/display/Stage.js b/test/unit/pixi/display/Stage.js
new file mode 100644
index 0000000..3cc2a4d
--- /dev/null
+++ b/test/unit/pixi/display/Stage.js
@@ -0,0 +1,49 @@
+describe('pixi/display/Stage', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Stage = PIXI.Stage;
+ var InteractionManager = PIXI.InteractionManager;
+ var Rectangle = PIXI.Rectangle;
+
+ it('Module exists', function () {
+ expect(Stage).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Stage(null, true);
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(Stage);
+ expect(obj).to.respondTo('updateTransform');
+ expect(obj).to.respondTo('setBackgroundColor');
+ expect(obj).to.respondTo('getMousePosition');
+
+ // FIXME: duplicate member in DisplayObject
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ // FIXME: convert arg to bool in constructor
+ expect(obj).to.have.property('interactive', true);
+
+ expect(obj).to.have.property('interactionManager')
+ .and.to.be.an.instanceof(InteractionManager)
+ .and.to.have.property('stage', obj);
+
+ expect(obj).to.have.property('dirty', true);
+
+ expect(obj).to.have.property('stage', obj);
+
+ expect(obj).to.have.property('hitArea')
+ .and.to.be.an.instanceof(Rectangle);
+ pixi_core_Rectangle_confirm(obj.hitArea, 0, 0, 100000, 100000);
+
+ expect(obj).to.have.property('backgroundColor', 0x000000);
+ expect(obj).to.have.deep.property('backgroundColorSplit.length', 3);
+ expect(obj).to.have.deep.property('backgroundColorSplit[0]', 0);
+ expect(obj).to.have.deep.property('backgroundColorSplit[1]', 0);
+ expect(obj).to.have.deep.property('backgroundColorSplit[2]', 0);
+ expect(obj).to.have.property('backgroundColorString', '#000000');
+
+ expect(obj).to.have.property('worldVisible', true);
+ });
+});
diff --git a/test/unit/pixi/extras/CustomRenderable.js b/test/unit/pixi/extras/CustomRenderable.js
new file mode 100644
index 0000000..8d83cf0
--- /dev/null
+++ b/test/unit/pixi/extras/CustomRenderable.js
@@ -0,0 +1,21 @@
+describe('pixi/extras/CustomRenderable', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var CustomRenderable = PIXI.CustomRenderable;
+
+ it('Module exists', function () {
+ expect(CustomRenderable).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new CustomRenderable();
+
+ pixi_display_DisplayObject_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(CustomRenderable);
+ expect(obj).to.respondTo('renderCanvas');
+ expect(obj).to.respondTo('initWebGL');
+ expect(obj).to.respondTo('renderWebGL');
+ });
+});
diff --git a/test/unit/pixi/extras/Rope.js b/test/unit/pixi/extras/Rope.js
new file mode 100644
index 0000000..6ddaf83
--- /dev/null
+++ b/test/unit/pixi/extras/Rope.js
@@ -0,0 +1,26 @@
+describe('pixi/extras/Rope', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Rope = PIXI.Rope;
+ var Texture = PIXI.Texture;
+ var Point = PIXI.Point;
+
+ it('Module exists', function () {
+ expect(Rope).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var texture = Texture.fromImage('/base/test/textures/bunny.png');
+ var obj = new Rope(texture, [new Point(), new Point(5, 10), new Point(10, 20)]);
+
+ pixi_extras_Strip_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(Rope);
+ expect(obj).to.respondTo('refresh');
+ expect(obj).to.respondTo('updateTransform');
+ expect(obj).to.respondTo('setTexture');
+
+ // TODO: Test properties
+ });
+});
diff --git a/test/unit/pixi/extras/Spine.js b/test/unit/pixi/extras/Spine.js
new file mode 100644
index 0000000..0708bc0
--- /dev/null
+++ b/test/unit/pixi/extras/Spine.js
@@ -0,0 +1,10 @@
+describe('pixi/extras/Spine', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Spine = PIXI.Spine;
+
+ it('Module exists', function () {
+ expect(Spine).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/extras/Strip.js b/test/unit/pixi/extras/Strip.js
new file mode 100644
index 0000000..8e564e1
--- /dev/null
+++ b/test/unit/pixi/extras/Strip.js
@@ -0,0 +1,18 @@
+describe('pixi/extras/Strip', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Strip = PIXI.Strip;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(Strip).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var texture = Texture.fromImage('/base/test/textures/bunny.png');
+ var obj = new Strip(texture, 20, 10000);
+
+ pixi_extras_Strip_confirmNew(obj);
+ });
+});
diff --git a/test/unit/pixi/extras/TilingSprite.js b/test/unit/pixi/extras/TilingSprite.js
new file mode 100644
index 0000000..56aea14
--- /dev/null
+++ b/test/unit/pixi/extras/TilingSprite.js
@@ -0,0 +1,24 @@
+describe('pixi/extras/TilingSprite', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var TilingSprite = PIXI.TilingSprite;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(TilingSprite).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var texture = Texture.fromImage('/base/test/textures/bunny.png');
+ var obj = new TilingSprite(texture, 6000, 12000);
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(TilingSprite);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ // TODO: Test properties
+ });
+});
diff --git a/test/unit/pixi/filters/FilterBlock.js b/test/unit/pixi/filters/FilterBlock.js
new file mode 100644
index 0000000..870cec0
--- /dev/null
+++ b/test/unit/pixi/filters/FilterBlock.js
@@ -0,0 +1,10 @@
+describe('pixi/filters/FilterBlock', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var FilterBlock = PIXI.FilterBlock;
+
+ it('Module exists', function () {
+ expect(FilterBlock).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/filters/MaskFilter.js b/test/unit/pixi/filters/MaskFilter.js
new file mode 100644
index 0000000..32d6a45
--- /dev/null
+++ b/test/unit/pixi/filters/MaskFilter.js
@@ -0,0 +1,10 @@
+describe('pixi/filters/MaskFilter', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ // var MaskFilter = PIXI.MaskFilter;
+
+ // it('Module exists', function () {
+ // expect(MaskFilter).to.be.a('function');
+ // });
+});
diff --git a/test/unit/pixi/loaders/AssetLoader.js b/test/unit/pixi/loaders/AssetLoader.js
new file mode 100644
index 0000000..a0aa0b5
--- /dev/null
+++ b/test/unit/pixi/loaders/AssetLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/AssetLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var AssetLoader = PIXI.AssetLoader;
+
+ it('Module exists', function () {
+ expect(AssetLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/BitmapFontLoader.js b/test/unit/pixi/loaders/BitmapFontLoader.js
new file mode 100644
index 0000000..6253c42
--- /dev/null
+++ b/test/unit/pixi/loaders/BitmapFontLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/BitmapFontLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var BitmapFontLoader = PIXI.BitmapFontLoader;
+
+ it('Module exists', function () {
+ expect(PIXI.BitmapFontLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/ImageLoader.js b/test/unit/pixi/loaders/ImageLoader.js
new file mode 100644
index 0000000..8b1f556
--- /dev/null
+++ b/test/unit/pixi/loaders/ImageLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/ImageLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var ImageLoader = PIXI.ImageLoader;
+
+ it('Module exists', function () {
+ expect(ImageLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/JsonLoader.js b/test/unit/pixi/loaders/JsonLoader.js
new file mode 100644
index 0000000..c577e83
--- /dev/null
+++ b/test/unit/pixi/loaders/JsonLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/JsonLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var JsonLoader = PIXI.JsonLoader;
+
+ it('Module exists', function () {
+ expect(JsonLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/SpineLoader.js b/test/unit/pixi/loaders/SpineLoader.js
new file mode 100644
index 0000000..fdcc0b8
--- /dev/null
+++ b/test/unit/pixi/loaders/SpineLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/SpineLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var SpineLoader = PIXI.SpineLoader;
+
+ it('Module exists', function () {
+ expect(SpineLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/SpriteSheetLoader.js b/test/unit/pixi/loaders/SpriteSheetLoader.js
new file mode 100644
index 0000000..57beb27
--- /dev/null
+++ b/test/unit/pixi/loaders/SpriteSheetLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/SpriteSheetLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var SpriteSheetLoader = PIXI.SpriteSheetLoader;
+
+ it('Module exists', function () {
+ expect(SpriteSheetLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/primitives/Graphics.js b/test/unit/pixi/primitives/Graphics.js
new file mode 100644
index 0000000..b8b3e5c
--- /dev/null
+++ b/test/unit/pixi/primitives/Graphics.js
@@ -0,0 +1,40 @@
+describe('pixi/primitives/Graphics', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Graphics = PIXI.Graphics;
+
+ it('Module exists', function () {
+ expect(Graphics).to.be.a('function');
+
+ expect(Graphics).itself.to.have.property('POLY', 0);
+ expect(Graphics).itself.to.have.property('RECT', 1);
+ expect(Graphics).itself.to.have.property('CIRC', 2);
+ expect(Graphics).itself.to.have.property('ELIP', 3);
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Graphics();
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(Graphics);
+ expect(obj).to.respondTo('lineStyle');
+ expect(obj).to.respondTo('lineStyle');
+ expect(obj).to.respondTo('moveTo');
+ expect(obj).to.respondTo('lineTo');
+ expect(obj).to.respondTo('beginFill');
+ expect(obj).to.respondTo('endFill');
+ expect(obj).to.respondTo('drawRect');
+ expect(obj).to.respondTo('drawCircle');
+ expect(obj).to.respondTo('drawElipse');
+ expect(obj).to.respondTo('clear');
+
+ expect(obj).to.have.property('renderable', true);
+ expect(obj).to.have.property('fillAlpha', 1);
+ expect(obj).to.have.property('lineWidth', 0);
+ expect(obj).to.have.property('lineColor', 'black');
+ expect(obj).to.have.deep.property('graphicsData.length', 0);
+ expect(obj).to.have.deep.property('currentPath.points.length', 0);
+ });
+});
diff --git a/test/unit/pixi/renderers/canvas/CanvasGraphics.js b/test/unit/pixi/renderers/canvas/CanvasGraphics.js
new file mode 100644
index 0000000..8f44472
--- /dev/null
+++ b/test/unit/pixi/renderers/canvas/CanvasGraphics.js
@@ -0,0 +1,15 @@
+describe('renders/canvas/CanvasGraphics', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var CanvasGraphics = PIXI.CanvasGraphics;
+
+ it('Module exists', function () {
+ expect(CanvasGraphics).to.be.a('function');
+ });
+
+ it('Members exist', function () {
+ expect(CanvasGraphics).itself.to.respondTo('renderGraphics');
+ expect(CanvasGraphics).itself.to.respondTo('renderGraphicsMask');
+ });
+});
diff --git a/test/unit/pixi/renderers/canvas/CanvasRenderer.js b/test/unit/pixi/renderers/canvas/CanvasRenderer.js
new file mode 100644
index 0000000..df3a12f
--- /dev/null
+++ b/test/unit/pixi/renderers/canvas/CanvasRenderer.js
@@ -0,0 +1,10 @@
+describe('renderers/canvas/CanvasRenderer', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var CanvasRenderer = PIXI.CanvasRenderer;
+
+ it('Module exists', function () {
+ expect(CanvasRenderer).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/renderers/webgl/WebGLBatch.js b/test/unit/pixi/renderers/webgl/WebGLBatch.js
new file mode 100644
index 0000000..75efd56
--- /dev/null
+++ b/test/unit/pixi/renderers/webgl/WebGLBatch.js
@@ -0,0 +1,10 @@
+describe('renderers/webgl/WebGLBatch', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var WebGLBatch = PIXI.WebGLBatch;
+
+ it('Module exists', function () {
+ expect(WebGLBatch).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/renderers/webgl/WebGLGraphics.js b/test/unit/pixi/renderers/webgl/WebGLGraphics.js
new file mode 100644
index 0000000..41bf941
--- /dev/null
+++ b/test/unit/pixi/renderers/webgl/WebGLGraphics.js
@@ -0,0 +1,19 @@
+describe('renderers/wegbl/WebGLGraphics', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var WebGLGraphics = PIXI.WebGLGraphics;
+
+ it('Module exists', function () {
+ expect(WebGLGraphics).to.be.a('function');
+ });
+
+ it('Members exist', function () {
+ expect(WebGLGraphics).itself.to.respondTo('renderGraphics');
+ expect(WebGLGraphics).itself.to.respondTo('updateGraphics');
+ expect(WebGLGraphics).itself.to.respondTo('buildRectangle');
+ expect(WebGLGraphics).itself.to.respondTo('buildCircle');
+ expect(WebGLGraphics).itself.to.respondTo('buildLine');
+ expect(WebGLGraphics).itself.to.respondTo('buildPoly');
+ });
+});
diff --git a/test/unit/pixi/renderers/webgl/WebGLRenderGroup.js b/test/unit/pixi/renderers/webgl/WebGLRenderGroup.js
new file mode 100644
index 0000000..f4ee366
--- /dev/null
+++ b/test/unit/pixi/renderers/webgl/WebGLRenderGroup.js
@@ -0,0 +1,10 @@
+describe('renderers/webgl/WebGLRenderGroup', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var WebGLRenderGroup = PIXI.WebGLRenderGroup;
+
+ it('Module exists', function () {
+ expect(WebGLRenderGroup).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/renderers/webgl/WebGLRenderer.js b/test/unit/pixi/renderers/webgl/WebGLRenderer.js
new file mode 100644
index 0000000..86533eb
--- /dev/null
+++ b/test/unit/pixi/renderers/webgl/WebGLRenderer.js
@@ -0,0 +1,10 @@
+describe('renderers/webgl/WebGLRenderer', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var WebGLRenderer = PIXI.WebGLRenderer;
+
+ it('Module exists', function () {
+ expect(WebGLRenderer).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/renderers/webgl/WebGLShaders.js b/test/unit/pixi/renderers/webgl/WebGLShaders.js
new file mode 100644
index 0000000..2872de8
--- /dev/null
+++ b/test/unit/pixi/renderers/webgl/WebGLShaders.js
@@ -0,0 +1,13 @@
+describe('renderers/webgl/WebGLShaders', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+
+ it('Module members exist', function () {
+ expect(PIXI).to.respondTo('initPrimitiveShader');
+ expect(PIXI).to.respondTo('initDefaultShader');
+ expect(PIXI).to.respondTo('initDefaultStripShader');
+ expect(PIXI).to.respondTo('activateDefaultShader');
+ expect(PIXI).to.respondTo('activatePrimitiveShader');
+ });
+});
diff --git a/test/unit/pixi/text/BitmapText.js b/test/unit/pixi/text/BitmapText.js
new file mode 100644
index 0000000..9388e3d
--- /dev/null
+++ b/test/unit/pixi/text/BitmapText.js
@@ -0,0 +1,10 @@
+describe('pixi/text/BitmapText', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var BitmapText = PIXI.BitmapText;
+
+ it('Module exists', function () {
+ expect(BitmapText).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/text/Text.js b/test/unit/pixi/text/Text.js
new file mode 100644
index 0000000..9bc9ac5
--- /dev/null
+++ b/test/unit/pixi/text/Text.js
@@ -0,0 +1,10 @@
+describe('pixi/text/Text', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Text = PIXI.Text;
+
+ it('Module exists', function () {
+ expect(Text).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/textures/BaseTexture.js b/test/unit/pixi/textures/BaseTexture.js
new file mode 100644
index 0000000..e34b64c
--- /dev/null
+++ b/test/unit/pixi/textures/BaseTexture.js
@@ -0,0 +1,13 @@
+describe('pixi/textures/BaseTexture', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var BaseTexture = PIXI.BaseTexture;
+
+ it('Module exists', function () {
+ expect(BaseTexture).to.be.a('function');
+ expect(PIXI).to.have.property('BaseTextureCache').and.to.be.an('object');
+ expect(PIXI).to.have.deep.property('texturesToUpdate.length');
+ expect(PIXI).to.have.deep.property('texturesToDestroy.length', 0);
+ });
+});
diff --git a/test/unit/pixi/textures/RenderTexture.js b/test/unit/pixi/textures/RenderTexture.js
new file mode 100644
index 0000000..4a69b44
--- /dev/null
+++ b/test/unit/pixi/textures/RenderTexture.js
@@ -0,0 +1,10 @@
+describe('pixi/textures/RenderTexture', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var RenderTexture = PIXI.RenderTexture;
+
+ it('Module exists', function () {
+ expect(RenderTexture).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/textures/Texture.js b/test/unit/pixi/textures/Texture.js
new file mode 100644
index 0000000..adb2875
--- /dev/null
+++ b/test/unit/pixi/textures/Texture.js
@@ -0,0 +1,26 @@
+describe('pixi/textures/Texture', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(Texture).to.be.a('function');
+ expect(PIXI).to.have.property('TextureCache').and.to.be.an('object');
+ });
+
+ it('Members exist', function () {
+ expect(Texture).itself.to.respondTo('fromImage');
+ expect(Texture).itself.to.respondTo('fromFrame');
+ expect(Texture).itself.to.respondTo('fromCanvas');
+ expect(Texture).itself.to.respondTo('addTextureToCache');
+ expect(Texture).itself.to.respondTo('removeTextureFromCache');
+
+ expect(Texture).itself.to.have.deep.property('frameUpdates.length', 0);
+ });
+
+ it('Confirm new instance', function (done) {
+ var texture = Texture.fromImage('/base/test/textures/bunny.png');
+ pixi_textures_Texture_confirmNew(texture, done);
+ });
+});
diff --git a/test/unit/pixi/utils/Detector.js b/test/unit/pixi/utils/Detector.js
new file mode 100644
index 0000000..4cf6008
--- /dev/null
+++ b/test/unit/pixi/utils/Detector.js
@@ -0,0 +1,10 @@
+describe('pixi/utils/Detector', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var autoDetectRenderer = PIXI.autoDetectRenderer;
+
+ it('Module exists', function () {
+ expect(autoDetectRenderer).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/utils/EventTarget.js b/test/unit/pixi/utils/EventTarget.js
new file mode 100644
index 0000000..dc4ebd9
--- /dev/null
+++ b/test/unit/pixi/utils/EventTarget.js
@@ -0,0 +1,96 @@
+describe('pixi/utils/EventTarget', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var EventTarget = PIXI.EventTarget;
+
+ it('Module exists', function () {
+ expect(EventTarget).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = {}; EventTarget.call(obj);
+ pixi_utils_EventTarget_like(obj);
+ });
+
+ it('addEventListener and dispatchEvent works', function (done) {
+ var myData = {},
+ obj = {}; EventTarget.call(obj);
+
+ obj.addEventListener('myevent', function (event) {
+ expect(event).to.be.an('object');
+ expect(event).to.have.property('type', 'myevent');
+ expect(event).to.have.property('data', myData);
+ done();
+ });
+
+ obj.dispatchEvent({type: 'myevent', data: myData});
+ });
+
+ it('removeEventListener works', function (done) {
+ var obj = {}; EventTarget.call(obj);
+
+ function onMyEvent() {
+ done(new Error('addEventListener should not have been called'));
+ }
+
+ obj.addEventListener('myevent', onMyEvent);
+ obj.removeEventListener('myevent', onMyEvent);
+ obj.dispatchEvent({type: 'myevent'});
+ done();
+ });
+
+ it('multiple dispatches', function () {
+ var called = 0,
+ obj = {}; EventTarget.call(obj);
+
+ function onMyEvent() {
+ called++;
+ }
+
+ obj.addEventListener('myevent', onMyEvent);
+ obj.dispatchEvent({type: 'myevent'});
+ obj.dispatchEvent({type: 'myevent'});
+ obj.dispatchEvent({type: 'myevent'});
+ obj.dispatchEvent({type: 'myevent'});
+ expect(called).to.equal(4);
+ });
+
+ it('multiple events', function () {
+ var called = 0,
+ obj = {}; EventTarget.call(obj);
+
+ function onMyEvent() {
+ called++;
+ }
+
+ obj.addEventListener('myevent1', onMyEvent);
+ obj.addEventListener('myevent2', onMyEvent);
+ obj.addEventListener('myevent3', onMyEvent);
+ obj.dispatchEvent({type: 'myevent1'});
+ obj.dispatchEvent({type: 'myevent2'});
+ obj.dispatchEvent({type: 'myevent3'});
+ expect(called).to.equal(3);
+ });
+
+ it('multiple events one removed', function () {
+ var called = 0,
+ obj = {}; EventTarget.call(obj);
+
+ function onMyEvent() {
+ called++;
+ }
+
+ obj.addEventListener('myevent1', onMyEvent);
+ obj.addEventListener('myevent2', onMyEvent);
+ obj.addEventListener('myevent3', onMyEvent);
+ obj.dispatchEvent({type: 'myevent1'});
+ obj.dispatchEvent({type: 'myevent2'});
+ obj.dispatchEvent({type: 'myevent3'});
+ obj.removeEventListener('myevent2', onMyEvent);
+ obj.dispatchEvent({type: 'myevent1'});
+ obj.dispatchEvent({type: 'myevent2'});
+ obj.dispatchEvent({type: 'myevent3'});
+ expect(called).to.equal(5);
+ });
+});
diff --git a/.gitignore b/.gitignore
index 12e1b62..0b88317 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
node_modules
.DS_Store
-.project
\ No newline at end of file
+.project
+*.log
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..63e4d7c
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,8 @@
+language: node_js
+node_js:
+ - 0.10
+
+before_script:
+ - npm install -g grunt-cli
+ - export DISPLAY=:99.0
+ - sh -e /etc/init.d/xvfb start
diff --git a/Gruntfile.js b/Gruntfile.js
index b083b49..103938c 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -1,10 +1,12 @@
+'use strict';
+
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-connect');
- grunt.loadNpmTasks('grunt-contrib-qunit');
grunt.loadNpmTasks('grunt-contrib-yuidoc');
+ grunt.loadTasks('tasks');
var root = 'src/pixi/',
debug = 'bin/pixi.dev.js',
@@ -79,7 +81,7 @@
},
files: {
srcBlob: '<%= dirs.src %>/**/*.js',
- testBlob: '<%= dirs.test %>/unit/**/*.js',
+ testBlob: '<%= dirs.test %>/{functional,lib/pixi,unit}/**/*.js',
build: '<%= dirs.build %>/pixi.dev.js',
buildMin: '<%= dirs.build %>/pixi.js'
},
@@ -94,7 +96,12 @@
},
jshint: {
beforeconcat: srcFiles,
- test: ['<%= files.testBlob %>'],
+ test: {
+ src: ['<%= files.testBlob %>'],
+ options: {
+ expr: true
+ }
+ },
options: {
asi: true,
smarttabs: true
@@ -128,12 +135,6 @@
]
},
connect: {
- qunit: {
- options: {
- port: grunt.option('port-test') || 9002,
- base: './'
- }
- },
test: {
options: {
port: grunt.option('port-test') || 9002,
@@ -142,13 +143,6 @@
}
}
},
- qunit: {
- all: {
- options: {
- urls: ['http://localhost:' + (grunt.option('port-test') || 9002) + '/test/index.html']
- }
- }
- },
yuidoc: {
compile: {
name: '<%= pkg.name %>',
@@ -161,6 +155,13 @@
outdir: '<%= dirs.docs %>'
}
}
+ },
+ karma: {
+ unit: {
+ configFile: 'test/karma.conf.js',
+ // browsers: ['Chrome'],
+ singleRun: true
+ }
}
});
@@ -182,9 +183,10 @@
}
)
- grunt.registerTask('default', ['concat', 'uglify', 'distribute']);
grunt.registerTask('build', ['concat', 'uglify', 'distribute']);
- grunt.registerTask('test', ['build', 'connect:qunit', 'qunit']);
+ grunt.registerTask('test', ['concat', 'jshint:test', 'karma']);
grunt.registerTask('docs', ['yuidoc']);
-
-}
\ No newline at end of file
+ grunt.registerTask('default', ['test', 'uglify', 'distribute']);
+ // Travis CI task.
+ grunt.registerTask('travis', ['test']);
+}
diff --git a/README.md b/README.md
index c62ef86..690cfe4 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,8 @@

+[](http://travis-ci.org/drkibitz/pixi.js)
+
#### JavaScript 2D Renderer ####
The aim of this project is to provide a fast lightweight 2D library that works
diff --git a/package.json b/package.json
index b373240..1246a68 100644
--- a/package.json
+++ b/package.json
@@ -18,14 +18,21 @@
"main": "bin/pixi.js",
+ "scripts": {
+ "test": "grunt travis --verbose"
+ },
+
"dependencies": {},
"devDependencies": {
"grunt": "~0.4.x",
- "grunt-contrib-jshint": "0.3.x",
+ "grunt-contrib-jshint": "0.6.x",
"grunt-contrib-uglify": "0.2.x",
- "grunt-contrib-connect": "0.2.x",
- "grunt-contrib-qunit": "0.2.x",
+ "grunt-contrib-connect": "0.3.x",
"grunt-contrib-yuidoc": "0.4.x",
- "grunt-contrib-concat": "0.1.x"
+ "grunt-contrib-concat": "0.3.x",
+ "chai": "~1.7.0",
+ "karma": "0.11.0",
+ "karma-firefox-launcher": "0.1.0",
+ "karma-mocha": "0.1.0"
}
}
diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js
index a7c520e..ee82bbd 100644
--- a/src/pixi/InteractionManager.js
+++ b/src/pixi/InteractionManager.js
@@ -62,7 +62,6 @@
this.onTouchEnd = this.onTouchEnd.bind(this);
this.onTouchMove = this.onTouchMove.bind(this);
-
this.last = 0;
}
diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js
index 1a95d20..eef1059 100644
--- a/src/pixi/core/Ellipse.js
+++ b/src/pixi/core/Ellipse.js
@@ -78,7 +78,7 @@
return (normx + normy < 0.25);
}
-PIXI.Ellipse.getBounds = function()
+PIXI.Ellipse.prototype.getBounds = function()
{
return new PIXI.Rectangle(this.x, this.y, this.width, this.height);
}
diff --git a/tasks/karma.js b/tasks/karma.js
new file mode 100644
index 0000000..c340485
--- /dev/null
+++ b/tasks/karma.js
@@ -0,0 +1,27 @@
+'use strict';
+
+var path = require('path');
+var server = require('karma').server;
+
+module.exports = function (grunt) {
+ grunt.registerMultiTask('karma', 'run karma.', function() {
+ var done = this.async();
+ var options = this.options({
+ background: false
+ });
+ var data = this.data;
+
+ //merge options onto data, with data taking precedence
+ data = grunt.util._.merge(options, data);
+ data.configFile = path.resolve(data.configFile);
+ if (data.configFile) {
+ data.configFile = grunt.template.process(data.configFile);
+ }
+
+ server.start(
+ data,
+ function(code) {
+ done(!code);
+ });
+ });
+};
diff --git a/test/functional/example-1-basics/bunny.png b/test/functional/example-1-basics/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/functional/example-1-basics/bunny.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-30.png b/test/functional/example-1-basics/frame-30.png
new file mode 100644
index 0000000..96e3409
--- /dev/null
+++ b/test/functional/example-1-basics/frame-30.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-60.png b/test/functional/example-1-basics/frame-60.png
new file mode 100644
index 0000000..af3f4ce
--- /dev/null
+++ b/test/functional/example-1-basics/frame-60.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-90.png b/test/functional/example-1-basics/frame-90.png
new file mode 100644
index 0000000..099b823
--- /dev/null
+++ b/test/functional/example-1-basics/frame-90.png
Binary files differ
diff --git a/test/functional/example-1-basics/index.js b/test/functional/example-1-basics/index.js
new file mode 100644
index 0000000..7ae7a98
--- /dev/null
+++ b/test/functional/example-1-basics/index.js
@@ -0,0 +1,133 @@
+describe('Example 1 - Basics', function () {
+ 'use strict';
+
+ var baseUri = '/base/test/functional/example-1-basics';
+ var expect = chai.expect;
+ var currentFrame = 0;
+ var frameEvents = {};
+ var stage;
+ var renderer;
+ var bunny;
+
+ function onFrame(frame, callback) {
+ frameEvents[frame] = callback;
+ }
+
+ function animate() {
+ currentFrame += 1;
+
+ requestAnimFrame( animate );
+
+ // just for fun, lets rotate mr rabbit a little
+ bunny.rotation += 0.1;
+
+ // render the stage
+ renderer.render(stage);
+
+ if (frameEvents[currentFrame])
+ frameEvents[currentFrame](currentFrame);
+ }
+
+ function initScene() {
+ // create an new instance of a pixi stage
+ stage = new PIXI.Stage(0x66FF99);
+
+ // create a renderer instance
+ renderer = PIXI.autoDetectRenderer(400, 300);
+ console.log('Is PIXI.WebGLRenderer: ' + (renderer instanceof PIXI.WebGLRenderer));
+
+ // add the renderer view element to the DOM
+ document.body.appendChild(renderer.view);
+
+ requestAnimFrame( animate );
+
+ // create a texture from an image path
+ var texture = PIXI.Texture.fromImage(baseUri + "/bunny.png");
+ // create a new Sprite using the texture
+ bunny = new PIXI.Sprite(texture);
+
+ // center the sprites anchor point
+ bunny.anchor.x = 0.5;
+ bunny.anchor.y = 0.5;
+
+ // move the sprite t the center of the screen
+ bunny.position.x = 200;
+ bunny.position.y = 150;
+
+ stage.addChild(bunny);
+ }
+
+ it('assets loaded', function (done) {
+ var loader = new PIXI.AssetLoader([
+ baseUri + '/bunny.png',
+ baseUri + '/frame-30.png',
+ baseUri + '/frame-60.png',
+ baseUri + '/frame-90.png'
+ ]);
+ // loader.on('onProgress', function (event) {
+ // console.log(event.content);
+ // });
+ loader.on('onComplete', function (event) {
+ done();
+ initScene();
+ });
+ loader.load();
+ });
+
+ it('frame 30 should match', function (done) {
+ this.timeout(700);
+ onFrame(30, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-30.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 60 should match', function (done) {
+ this.timeout(1200);
+ onFrame(60, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-60.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 90 should match', function (done) {
+ this.timeout(1700);
+ onFrame(90, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-90.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ // it('capture something', function (done) {
+ // this.timeout(2000000);
+ // onFrame(30, function () {
+ // var img = new Image();
+ // img.src = renderer.view.toDataURL('image/png');
+ // document.body.appendChild(img);
+ // });
+ // });
+});
diff --git a/test/index.html b/test/index.html
deleted file mode 100644
index 9cbcac5..0000000
--- a/test/index.html
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
- Pixi.js Test Suite
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/test/karma.conf.js b/test/karma.conf.js
new file mode 100644
index 0000000..c66a696
--- /dev/null
+++ b/test/karma.conf.js
@@ -0,0 +1,82 @@
+module.exports = function(config) {
+ config.set({
+
+ // base path, that will be used to resolve files and exclude
+ basePath : '../',
+
+ frameworks : ['mocha'],
+
+ // list of files / patterns to load in the browser
+ files : [
+ 'node_modules/chai/chai.js',
+ 'bin/pixi.dev.js',
+ 'test/lib/**/*.js',
+ 'test/unit/**/*.js',
+ // 'test/functional/**/*.js',
+ {pattern: 'test/**/*.png', watched: false, included: false, served: true}
+ ],
+
+ // list of files to exclude
+ exclude : [],
+
+ // use dolts reporter, as travis terminal does not support escaping sequences
+ // possible values: 'dots', 'progress', 'junit', 'teamcity'
+ // CLI --reporters progress
+ reporters : ['progress'],
+
+ // web server port
+ // CLI --port 9876
+ port : 9876,
+
+ // cli runner port
+ // CLI --runner-port 9100
+ runnerPort : 9100,
+
+ // enable / disable colors in the output (reporters and logs)
+ // CLI --colors --no-colors
+ colors : true,
+
+ // level of logging
+ // possible values: karma.LOG_DISABLE || karma.LOG_ERROR || karma.LOG_WARN || karma.LOG_INFO || karma.LOG_DEBUG
+ // CLI --log-level debug
+ logLevel : config.LOG_DEBUG,
+
+ // enable / disable watching file and executing tests whenever any file changes
+ // CLI --auto-watch --no-auto-watch
+ autoWatch : false,
+
+ // Start these browsers, currently available:
+ // - Chrome
+ // - ChromeCanary
+ // - Firefox
+ // - Opera
+ // - Safari (only Mac)
+ // - PhantomJS
+ // - IE (only Windows)
+ // CLI --browsers Chrome,Firefox,Safari
+ browsers : ['Firefox'],
+
+ // If browser does not capture in given timeout [ms], kill it
+ // CLI --capture-timeout 5000
+ captureTimeout : 5000,
+
+ // Auto run tests on start (when browsers are captured) and exit
+ // CLI --single-run --no-single-run
+ singleRun : true,
+
+ // report which specs are slower than 500ms
+ // CLI --report-slower-than 500
+ reportSlowerThan : 1000,
+
+ preprocessors : {
+ // '**/client/js/*.js': 'coverage'
+ },
+
+ plugins : [
+ 'karma-mocha',
+ // 'karma-chrome-launcher',
+ 'karma-firefox-launcher',
+ // 'karma-phantomjs-launcher'
+ ]
+ });
+};
diff --git a/test/lib/pixi/core/Matrix.js b/test/lib/pixi/core/Matrix.js
new file mode 100644
index 0000000..d26386b
--- /dev/null
+++ b/test/lib/pixi/core/Matrix.js
@@ -0,0 +1,40 @@
+
+function pixi_core_Matrix_confirmNewMat3(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(1);
+ expect(matrix[5]).to.equal(0);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(1);
+}
+
+function pixi_core_Matrix_confirmNewMat4(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[0]).to.equal(1);
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(0);
+ expect(matrix[5]).to.equal(1);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(0);
+ expect(matrix[9]).to.equal(0);
+ expect(matrix[10]).to.equal(1);
+ expect(matrix[11]).to.equal(0);
+ expect(matrix[12]).to.equal(0);
+ expect(matrix[13]).to.equal(0);
+ expect(matrix[14]).to.equal(0);
+ expect(matrix[15]).to.equal(1);
+}
diff --git a/test/lib/pixi/core/Point.js b/test/lib/pixi/core/Point.js
new file mode 100644
index 0000000..e5df07b
--- /dev/null
+++ b/test/lib/pixi/core/Point.js
@@ -0,0 +1,10 @@
+
+function pixi_core_Point_confirm(obj, x, y) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Point);
+ expect(obj).to.respondTo('clone');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+}
diff --git a/test/lib/pixi/core/Rectangle.js b/test/lib/pixi/core/Rectangle.js
new file mode 100644
index 0000000..23f0d12
--- /dev/null
+++ b/test/lib/pixi/core/Rectangle.js
@@ -0,0 +1,13 @@
+
+function pixi_core_Rectangle_confirm(obj, x, y, width, height) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Rectangle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+ expect(obj).to.have.property('width', width);
+ expect(obj).to.have.property('height', height);
+}
diff --git a/test/lib/pixi/display/DisplayObject.js b/test/lib/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..1388a7f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObject.js
@@ -0,0 +1,43 @@
+
+function pixi_display_DisplayObject_confirmNew(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObject);
+ expect(obj).to.respondTo('setInteractive');
+ expect(obj).to.respondTo('addFilter');
+ expect(obj).to.respondTo('removeFilter');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.property('last', obj);
+ expect(obj).to.have.property('first', obj);
+
+ expect(obj).to.contain.property('position');
+ pixi_core_Point_confirm(obj.position, 0, 0);
+ expect(obj).to.contain.property('scale');
+ pixi_core_Point_confirm(obj.scale, 1, 1);
+ expect(obj).to.contain.property('pivot');
+ pixi_core_Point_confirm(obj.pivot, 0, 0);
+
+ expect(obj).to.have.property('rotation', 0);
+ expect(obj).to.have.property('alpha', 1);
+ expect(obj).to.have.property('visible', true);
+ expect(obj).to.have.property('buttonMode', false);
+ expect(obj).to.have.property('parent', null);
+ expect(obj).to.have.property('worldAlpha', 1);
+
+ expect(obj).to.have.property('hitArea');
+ expect(obj).to.have.property('interactive'); // TODO: Have a better default value
+ expect('mask' in obj).to.be.true; // TODO: Have a better default value
+ expect(obj.mask).to.be.undefined;
+
+ expect(obj).to.have.property('renderable');
+ expect(obj).to.have.property('stage');
+
+ expect(obj).to.have.deep.property('worldTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ expect(obj).to.have.deep.property('localTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.localTransform);
+
+ expect(obj).to.have.deep.property('color.length', 0);
+ expect(obj).to.have.property('dynamic', true);
+}
diff --git a/test/lib/pixi/display/DisplayObjectContainer.js b/test/lib/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..085c59f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,16 @@
+
+function pixi_display_DisplayObjectContainer_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObject_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObjectContainer);
+ expect(obj).to.respondTo('addChild');
+ expect(obj).to.respondTo('addChildAt');
+ expect(obj).to.respondTo('swapChildren');
+ expect(obj).to.respondTo('getChildAt');
+ expect(obj).to.respondTo('removeChild');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('children.length', 0);
+}
diff --git a/test/lib/pixi/display/Sprite.js b/test/lib/pixi/display/Sprite.js
new file mode 100644
index 0000000..cc7a2d6
--- /dev/null
+++ b/test/lib/pixi/display/Sprite.js
@@ -0,0 +1,28 @@
+
+function pixi_display_Sprite_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Sprite);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', true);
+ expect(obj).to.have.property('stage', null);
+
+ expect(obj).to.have.property('anchor');
+ pixi_core_Point_confirm(obj.anchor, 0, 0);
+
+ expect(obj).to.have.property('blendMode', PIXI.blendModes.NORMAL);
+ expect(obj).to.have.property('width', 1); // TODO: is 1 expected
+ expect(obj).to.have.property('height', 1); // TODO: is 1 expected
+
+ // FIXME: Just make this a boolean that is always there
+ expect(!!obj.updateFrame).to.equal(obj.texture.baseTexture.hasLoaded);
+
+ expect(obj).to.have.property('texture');
+ pixi_textures_Texture_confirmNew(obj.texture, done);
+}
diff --git a/test/lib/pixi/extras/Strip.js b/test/lib/pixi/extras/Strip.js
new file mode 100644
index 0000000..8927a8a
--- /dev/null
+++ b/test/lib/pixi/extras/Strip.js
@@ -0,0 +1,12 @@
+
+function pixi_extras_Strip_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Strip);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ // TODO: Test properties
+}
diff --git a/test/lib/pixi/textures/Texture.js b/test/lib/pixi/textures/Texture.js
new file mode 100644
index 0000000..d5867b6
--- /dev/null
+++ b/test/lib/pixi/textures/Texture.js
@@ -0,0 +1,31 @@
+
+function pixi_textures_Texture_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ function confirmFrameDone() {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, obj.baseTexture.width, obj.baseTexture.height);
+
+ expect(obj).to.have.property('width', obj.baseTexture.width);
+ expect(obj).to.have.property('height', obj.baseTexture.height);
+ done();
+ }
+
+ expect(obj).to.be.an.instanceof(PIXI.Texture);
+ pixi_utils_EventTarget_like(obj);
+
+ expect(obj).to.have.property('baseTexture')
+ .and.to.be.an.instanceof(PIXI.BaseTexture);
+
+ expect(obj).to.have.property('scope', obj);
+
+ expect(obj).to.have.property('trim');
+ pixi_core_Point_confirm(obj.trim, 0, 0);
+
+ expect(obj).to.have.property('frame');
+ if (obj.baseTexture.hasLoaded) {
+ confirmFrameDone();
+ } else {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, 1, 1);
+ obj.addEventListener('update', confirmFrameDone);
+ }
+}
diff --git a/test/lib/pixi/utils/EventTarget.js b/test/lib/pixi/utils/EventTarget.js
new file mode 100644
index 0000000..7b1dcfa
--- /dev/null
+++ b/test/lib/pixi/utils/EventTarget.js
@@ -0,0 +1,8 @@
+
+function pixi_utils_EventTarget_like(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.respondTo('addEventListener');
+ expect(obj).to.respondTo('dispatchEvent');
+ expect(obj).to.respondTo('removeEventListener');
+}
diff --git a/test/lib/qunit-1.11.0.css b/test/lib/qunit-1.11.0.css
deleted file mode 100644
index d7fc0c8..0000000
--- a/test/lib/qunit-1.11.0.css
+++ /dev/null
@@ -1,244 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-/** Font Family and Sizes */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
- font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
-}
-
-#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
-#qunit-tests { font-size: smaller; }
-
-
-/** Resets */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter {
- margin: 0;
- padding: 0;
-}
-
-
-/** Header */
-
-#qunit-header {
- padding: 0.5em 0 0.5em 1em;
-
- color: #8699a4;
- background-color: #0d3349;
-
- font-size: 1.5em;
- line-height: 1em;
- font-weight: normal;
-
- border-radius: 5px 5px 0 0;
- -moz-border-radius: 5px 5px 0 0;
- -webkit-border-top-right-radius: 5px;
- -webkit-border-top-left-radius: 5px;
-}
-
-#qunit-header a {
- text-decoration: none;
- color: #c2ccd1;
-}
-
-#qunit-header a:hover,
-#qunit-header a:focus {
- color: #fff;
-}
-
-#qunit-testrunner-toolbar label {
- display: inline-block;
- padding: 0 .5em 0 .1em;
-}
-
-#qunit-banner {
- height: 5px;
-}
-
-#qunit-testrunner-toolbar {
- padding: 0.5em 0 0.5em 2em;
- color: #5E740B;
- background-color: #eee;
- overflow: hidden;
-}
-
-#qunit-userAgent {
- padding: 0.5em 0 0.5em 2.5em;
- background-color: #2b81af;
- color: #fff;
- text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
-}
-
-#qunit-modulefilter-container {
- float: right;
-}
-
-/** Tests: Pass/Fail */
-
-#qunit-tests {
- list-style-position: inside;
-}
-
-#qunit-tests li {
- padding: 0.4em 0.5em 0.4em 2.5em;
- border-bottom: 1px solid #fff;
- list-style-position: inside;
-}
-
-#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running {
- display: none;
-}
-
-#qunit-tests li strong {
- cursor: pointer;
-}
-
-#qunit-tests li a {
- padding: 0.5em;
- color: #c2ccd1;
- text-decoration: none;
-}
-#qunit-tests li a:hover,
-#qunit-tests li a:focus {
- color: #000;
-}
-
-#qunit-tests li .runtime {
- float: right;
- font-size: smaller;
-}
-
-.qunit-assert-list {
- margin-top: 0.5em;
- padding: 0.5em;
-
- background-color: #fff;
-
- border-radius: 5px;
- -moz-border-radius: 5px;
- -webkit-border-radius: 5px;
-}
-
-.qunit-collapsed {
- display: none;
-}
-
-#qunit-tests table {
- border-collapse: collapse;
- margin-top: .2em;
-}
-
-#qunit-tests th {
- text-align: right;
- vertical-align: top;
- padding: 0 .5em 0 0;
-}
-
-#qunit-tests td {
- vertical-align: top;
-}
-
-#qunit-tests pre {
- margin: 0;
- white-space: pre-wrap;
- word-wrap: break-word;
-}
-
-#qunit-tests del {
- background-color: #e0f2be;
- color: #374e0c;
- text-decoration: none;
-}
-
-#qunit-tests ins {
- background-color: #ffcaca;
- color: #500;
- text-decoration: none;
-}
-
-/*** Test Counts */
-
-#qunit-tests b.counts { color: black; }
-#qunit-tests b.passed { color: #5E740B; }
-#qunit-tests b.failed { color: #710909; }
-
-#qunit-tests li li {
- padding: 5px;
- background-color: #fff;
- border-bottom: none;
- list-style-position: inside;
-}
-
-/*** Passing Styles */
-
-#qunit-tests li li.pass {
- color: #3c510c;
- background-color: #fff;
- border-left: 10px solid #C6E746;
-}
-
-#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
-#qunit-tests .pass .test-name { color: #366097; }
-
-#qunit-tests .pass .test-actual,
-#qunit-tests .pass .test-expected { color: #999999; }
-
-#qunit-banner.qunit-pass { background-color: #C6E746; }
-
-/*** Failing Styles */
-
-#qunit-tests li li.fail {
- color: #710909;
- background-color: #fff;
- border-left: 10px solid #EE5757;
- white-space: pre;
-}
-
-#qunit-tests > li:last-child {
- border-radius: 0 0 5px 5px;
- -moz-border-radius: 0 0 5px 5px;
- -webkit-border-bottom-right-radius: 5px;
- -webkit-border-bottom-left-radius: 5px;
-}
-
-#qunit-tests .fail { color: #000000; background-color: #EE5757; }
-#qunit-tests .fail .test-name,
-#qunit-tests .fail .module-name { color: #000000; }
-
-#qunit-tests .fail .test-actual { color: #EE5757; }
-#qunit-tests .fail .test-expected { color: green; }
-
-#qunit-banner.qunit-fail { background-color: #EE5757; }
-
-
-/** Result */
-
-#qunit-testresult {
- padding: 0.5em 0.5em 0.5em 2.5em;
-
- color: #2b81af;
- background-color: #D2E0E6;
-
- border-bottom: 1px solid white;
-}
-#qunit-testresult .module-name {
- font-weight: bold;
-}
-
-/** Fixture */
-
-#qunit-fixture {
- position: absolute;
- top: -10000px;
- left: -10000px;
- width: 1000px;
- height: 1000px;
-}
diff --git a/test/lib/qunit-1.11.0.js b/test/lib/qunit-1.11.0.js
deleted file mode 100644
index 302545f..0000000
--- a/test/lib/qunit-1.11.0.js
+++ /dev/null
@@ -1,2152 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-(function( window ) {
-
-var QUnit,
- assert,
- config,
- onErrorFnPrev,
- testId = 0,
- fileName = (sourceFromStacktrace( 0 ) || "" ).replace(/(:\d+)+\)?/, "").replace(/.+\//, ""),
- toString = Object.prototype.toString,
- hasOwn = Object.prototype.hasOwnProperty,
- // Keep a local reference to Date (GH-283)
- Date = window.Date,
- defined = {
- setTimeout: typeof window.setTimeout !== "undefined",
- sessionStorage: (function() {
- var x = "qunit-test-string";
- try {
- sessionStorage.setItem( x, x );
- sessionStorage.removeItem( x );
- return true;
- } catch( e ) {
- return false;
- }
- }())
- },
- /**
- * Provides a normalized error string, correcting an issue
- * with IE 7 (and prior) where Error.prototype.toString is
- * not properly implemented
- *
- * Based on http://es5.github.com/#x15.11.4.4
- *
- * @param {String|Error} error
- * @return {String} error message
- */
- errorString = function( error ) {
- var name, message,
- errorString = error.toString();
- if ( errorString.substring( 0, 7 ) === "[object" ) {
- name = error.name ? error.name.toString() : "Error";
- message = error.message ? error.message.toString() : "";
- if ( name && message ) {
- return name + ": " + message;
- } else if ( name ) {
- return name;
- } else if ( message ) {
- return message;
- } else {
- return "Error";
- }
- } else {
- return errorString;
- }
- },
- /**
- * Makes a clone of an object using only Array or Object as base,
- * and copies over the own enumerable properties.
- *
- * @param {Object} obj
- * @return {Object} New object with only the own properties (recursively).
- */
- objectValues = function( obj ) {
- // Grunt 0.3.x uses an older version of jshint that still has jshint/jshint#392.
- /*jshint newcap: false */
- var key, val,
- vals = QUnit.is( "array", obj ) ? [] : {};
- for ( key in obj ) {
- if ( hasOwn.call( obj, key ) ) {
- val = obj[key];
- vals[key] = val === Object(val) ? objectValues(val) : val;
- }
- }
- return vals;
- };
-
-function Test( settings ) {
- extend( this, settings );
- this.assertions = [];
- this.testNumber = ++Test.count;
-}
-
-Test.count = 0;
-
-Test.prototype = {
- init: function() {
- var a, b, li,
- tests = id( "qunit-tests" );
-
- if ( tests ) {
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml;
-
- // `a` initialized at top of scope
- a = document.createElement( "a" );
- a.innerHTML = "Rerun";
- a.href = QUnit.url({ testNumber: this.testNumber });
-
- li = document.createElement( "li" );
- li.appendChild( b );
- li.appendChild( a );
- li.className = "running";
- li.id = this.id = "qunit-test-output" + testId++;
-
- tests.appendChild( li );
- }
- },
- setup: function() {
- if ( this.module !== config.previousModule ) {
- if ( config.previousModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.previousModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
- config.previousModule = this.module;
- config.moduleStats = { all: 0, bad: 0 };
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- } else if ( config.autorun ) {
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- }
-
- config.current = this;
-
- this.testEnvironment = extend({
- setup: function() {},
- teardown: function() {}
- }, this.moduleTestEnvironment );
-
- this.started = +new Date();
- runLoggingCallbacks( "testStart", QUnit, {
- name: this.testName,
- module: this.module
- });
-
- // allow utility functions to access the current test environment
- // TODO why??
- QUnit.current_testEnvironment = this.testEnvironment;
-
- if ( !config.pollution ) {
- saveGlobal();
- }
- if ( config.notrycatch ) {
- this.testEnvironment.setup.call( this.testEnvironment );
- return;
- }
- try {
- this.testEnvironment.setup.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Setup failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- },
- run: function() {
- config.current = this;
-
- var running = id( "qunit-testresult" );
-
- if ( running ) {
- running.innerHTML = "Running:
" + this.nameHtml;
- }
-
- if ( this.async ) {
- QUnit.stop();
- }
-
- this.callbackStarted = +new Date();
-
- if ( config.notrycatch ) {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- return;
- }
-
- try {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- } catch( e ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
-
- QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + " " + this.stack + ": " + ( e.message || e ), extractStacktrace( e, 0 ) );
- // else next test will carry the responsibility
- saveGlobal();
-
- // Restart the tests if they're blocking
- if ( config.blocking ) {
- QUnit.start();
- }
- }
- },
- teardown: function() {
- config.current = this;
- if ( config.notrycatch ) {
- if ( typeof this.callbackRuntime === "undefined" ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
- }
- this.testEnvironment.teardown.call( this.testEnvironment );
- return;
- } else {
- try {
- this.testEnvironment.teardown.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Teardown failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- }
- checkPollution();
- },
- finish: function() {
- config.current = this;
- if ( config.requireExpects && this.expected === null ) {
- QUnit.pushFailure( "Expected number of assertions to be defined, but expect() was not called.", this.stack );
- } else if ( this.expected !== null && this.expected !== this.assertions.length ) {
- QUnit.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack );
- } else if ( this.expected === null && !this.assertions.length ) {
- QUnit.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions.", this.stack );
- }
-
- var i, assertion, a, b, time, li, ol,
- test = this,
- good = 0,
- bad = 0,
- tests = id( "qunit-tests" );
-
- this.runtime = +new Date() - this.started;
- config.stats.all += this.assertions.length;
- config.moduleStats.all += this.assertions.length;
-
- if ( tests ) {
- ol = document.createElement( "ol" );
- ol.className = "qunit-assert-list";
-
- for ( i = 0; i < this.assertions.length; i++ ) {
- assertion = this.assertions[i];
-
- li = document.createElement( "li" );
- li.className = assertion.result ? "pass" : "fail";
- li.innerHTML = assertion.message || ( assertion.result ? "okay" : "failed" );
- ol.appendChild( li );
-
- if ( assertion.result ) {
- good++;
- } else {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
-
- // store result when possible
- if ( QUnit.config.reorder && defined.sessionStorage ) {
- if ( bad ) {
- sessionStorage.setItem( "qunit-test-" + this.module + "-" + this.testName, bad );
- } else {
- sessionStorage.removeItem( "qunit-test-" + this.module + "-" + this.testName );
- }
- }
-
- if ( bad === 0 ) {
- addClass( ol, "qunit-collapsed" );
- }
-
- // `b` initialized at top of scope
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml + " (" + bad + ", " + good + ", " + this.assertions.length + ")";
-
- addEvent(b, "click", function() {
- var next = b.parentNode.lastChild,
- collapsed = hasClass( next, "qunit-collapsed" );
- ( collapsed ? removeClass : addClass )( next, "qunit-collapsed" );
- });
-
- addEvent(b, "dblclick", function( e ) {
- var target = e && e.target ? e.target : window.event.srcElement;
- if ( target.nodeName.toLowerCase() === "span" || target.nodeName.toLowerCase() === "b" ) {
- target = target.parentNode;
- }
- if ( window.location && target.nodeName.toLowerCase() === "strong" ) {
- window.location = QUnit.url({ testNumber: test.testNumber });
- }
- });
-
- // `time` initialized at top of scope
- time = document.createElement( "span" );
- time.className = "runtime";
- time.innerHTML = this.runtime + " ms";
-
- // `li` initialized at top of scope
- li = id( this.id );
- li.className = bad ? "fail" : "pass";
- li.removeChild( li.firstChild );
- a = li.firstChild;
- li.appendChild( b );
- li.appendChild( a );
- li.appendChild( time );
- li.appendChild( ol );
-
- } else {
- for ( i = 0; i < this.assertions.length; i++ ) {
- if ( !this.assertions[i].result ) {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
- }
-
- runLoggingCallbacks( "testDone", QUnit, {
- name: this.testName,
- module: this.module,
- failed: bad,
- passed: this.assertions.length - bad,
- total: this.assertions.length,
- duration: this.runtime
- });
-
- QUnit.reset();
-
- config.current = undefined;
- },
-
- queue: function() {
- var bad,
- test = this;
-
- synchronize(function() {
- test.init();
- });
- function run() {
- // each of these can by async
- synchronize(function() {
- test.setup();
- });
- synchronize(function() {
- test.run();
- });
- synchronize(function() {
- test.teardown();
- });
- synchronize(function() {
- test.finish();
- });
- }
-
- // `bad` initialized at top of scope
- // defer when previous test run passed, if storage is available
- bad = QUnit.config.reorder && defined.sessionStorage &&
- +sessionStorage.getItem( "qunit-test-" + this.module + "-" + this.testName );
-
- if ( bad ) {
- run();
- } else {
- synchronize( run, true );
- }
- }
-};
-
-// Root QUnit object.
-// `QUnit` initialized at top of scope
-QUnit = {
-
- // call on start of module test to prepend name to all tests
- module: function( name, testEnvironment ) {
- config.currentModule = name;
- config.currentModuleTestEnvironment = testEnvironment;
- config.modules[name] = true;
- },
-
- asyncTest: function( testName, expected, callback ) {
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- QUnit.test( testName, expected, callback, true );
- },
-
- test: function( testName, expected, callback, async ) {
- var test,
- nameHtml = "" + escapeText( testName ) + "";
-
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- if ( config.currentModule ) {
- nameHtml = "" + escapeText( config.currentModule ) + ": " + nameHtml;
- }
-
- test = new Test({
- nameHtml: nameHtml,
- testName: testName,
- expected: expected,
- async: async,
- callback: callback,
- module: config.currentModule,
- moduleTestEnvironment: config.currentModuleTestEnvironment,
- stack: sourceFromStacktrace( 2 )
- });
-
- if ( !validTest( test ) ) {
- return;
- }
-
- test.queue();
- },
-
- // Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through.
- expect: function( asserts ) {
- if (arguments.length === 1) {
- config.current.expected = asserts;
- } else {
- return config.current.expected;
- }
- },
-
- start: function( count ) {
- // QUnit hasn't been initialized yet.
- // Note: RequireJS (et al) may delay onLoad
- if ( config.semaphore === undefined ) {
- QUnit.begin(function() {
- // This is triggered at the top of QUnit.load, push start() to the event loop, to allow QUnit.load to finish first
- setTimeout(function() {
- QUnit.start( count );
- });
- });
- return;
- }
-
- config.semaphore -= count || 1;
- // don't start until equal number of stop-calls
- if ( config.semaphore > 0 ) {
- return;
- }
- // ignore if start is called more often then stop
- if ( config.semaphore < 0 ) {
- config.semaphore = 0;
- QUnit.pushFailure( "Called start() while already started (QUnit.config.semaphore was 0 already)", null, sourceFromStacktrace(2) );
- return;
- }
- // A slight delay, to avoid any current callbacks
- if ( defined.setTimeout ) {
- window.setTimeout(function() {
- if ( config.semaphore > 0 ) {
- return;
- }
- if ( config.timeout ) {
- clearTimeout( config.timeout );
- }
-
- config.blocking = false;
- process( true );
- }, 13);
- } else {
- config.blocking = false;
- process( true );
- }
- },
-
- stop: function( count ) {
- config.semaphore += count || 1;
- config.blocking = true;
-
- if ( config.testTimeout && defined.setTimeout ) {
- clearTimeout( config.timeout );
- config.timeout = window.setTimeout(function() {
- QUnit.ok( false, "Test timed out" );
- config.semaphore = 1;
- QUnit.start();
- }, config.testTimeout );
- }
- }
-};
-
-// `assert` initialized at top of scope
-// Asssert helpers
-// All of these must either call QUnit.push() or manually do:
-// - runLoggingCallbacks( "log", .. );
-// - config.current.assertions.push({ .. });
-// We attach it to the QUnit object *after* we expose the public API,
-// otherwise `assert` will become a global variable in browsers (#341).
-assert = {
- /**
- * Asserts rough true-ish result.
- * @name ok
- * @function
- * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" );
- */
- ok: function( result, msg ) {
- if ( !config.current ) {
- throw new Error( "ok() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
- result = !!result;
-
- var source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: msg
- };
-
- msg = escapeText( msg || (result ? "okay" : "failed" ) );
- msg = "" + msg + "";
-
- if ( !result ) {
- source = sourceFromStacktrace( 2 );
- if ( source ) {
- details.source = source;
- msg += "Source: | " + escapeText( source ) + " |
---|
";
- }
- }
- runLoggingCallbacks( "log", QUnit, details );
- config.current.assertions.push({
- result: result,
- message: msg
- });
- },
-
- /**
- * Assert that the first two arguments are equal, with an optional message.
- * Prints out both actual and expected values.
- * @name equal
- * @function
- * @example equal( format( "Received {0} bytes.", 2), "Received 2 bytes.", "format() replaces {0} with next argument" );
- */
- equal: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected == actual, actual, expected, message );
- },
-
- /**
- * @name notEqual
- * @function
- */
- notEqual: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected != actual, actual, expected, message );
- },
-
- /**
- * @name propEqual
- * @function
- */
- propEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notPropEqual
- * @function
- */
- notPropEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name deepEqual
- * @function
- */
- deepEqual: function( actual, expected, message ) {
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notDeepEqual
- * @function
- */
- notDeepEqual: function( actual, expected, message ) {
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name strictEqual
- * @function
- */
- strictEqual: function( actual, expected, message ) {
- QUnit.push( expected === actual, actual, expected, message );
- },
-
- /**
- * @name notStrictEqual
- * @function
- */
- notStrictEqual: function( actual, expected, message ) {
- QUnit.push( expected !== actual, actual, expected, message );
- },
-
- "throws": function( block, expected, message ) {
- var actual,
- expectedOutput = expected,
- ok = false;
-
- // 'expected' is optional
- if ( typeof expected === "string" ) {
- message = expected;
- expected = null;
- }
-
- config.current.ignoreGlobalErrors = true;
- try {
- block.call( config.current.testEnvironment );
- } catch (e) {
- actual = e;
- }
- config.current.ignoreGlobalErrors = false;
-
- if ( actual ) {
- // we don't want to validate thrown error
- if ( !expected ) {
- ok = true;
- expectedOutput = null;
- // expected is a regexp
- } else if ( QUnit.objectType( expected ) === "regexp" ) {
- ok = expected.test( errorString( actual ) );
- // expected is a constructor
- } else if ( actual instanceof expected ) {
- ok = true;
- // expected is a validation function which returns true is validation passed
- } else if ( expected.call( {}, actual ) === true ) {
- expectedOutput = null;
- ok = true;
- }
-
- QUnit.push( ok, actual, expectedOutput, message );
- } else {
- QUnit.pushFailure( message, null, 'No exception was thrown.' );
- }
- }
-};
-
-/**
- * @deprecate since 1.8.0
- * Kept assertion helpers in root for backwards compatibility.
- */
-extend( QUnit, assert );
-
-/**
- * @deprecated since 1.9.0
- * Kept root "raises()" for backwards compatibility.
- * (Note that we don't introduce assert.raises).
- */
-QUnit.raises = assert[ "throws" ];
-
-/**
- * @deprecated since 1.0.0, replaced with error pushes since 1.3.0
- * Kept to avoid TypeErrors for undefined methods.
- */
-QUnit.equals = function() {
- QUnit.push( false, false, false, "QUnit.equals has been deprecated since 2009 (e88049a0), use QUnit.equal instead" );
-};
-QUnit.same = function() {
- QUnit.push( false, false, false, "QUnit.same has been deprecated since 2009 (e88049a0), use QUnit.deepEqual instead" );
-};
-
-// We want access to the constructor's prototype
-(function() {
- function F() {}
- F.prototype = QUnit;
- QUnit = new F();
- // Make F QUnit's constructor so that we can add to the prototype later
- QUnit.constructor = F;
-}());
-
-/**
- * Config object: Maintain internal state
- * Later exposed as QUnit.config
- * `config` initialized at top of scope
- */
-config = {
- // The queue of tests to run
- queue: [],
-
- // block until document ready
- blocking: true,
-
- // when enabled, show only failing tests
- // gets persisted through sessionStorage and can be changed in UI via checkbox
- hidepassed: false,
-
- // by default, run previously failed tests first
- // very useful in combination with "Hide passed tests" checked
- reorder: true,
-
- // by default, modify document.title when suite is done
- altertitle: true,
-
- // when enabled, all tests must call expect()
- requireExpects: false,
-
- // add checkboxes that are persisted in the query-string
- // when enabled, the id is set to `true` as a `QUnit.config` property
- urlConfig: [
- {
- id: "noglobals",
- label: "Check for Globals",
- tooltip: "Enabling this will test if any test introduces new properties on the `window` object. Stored as query-strings."
- },
- {
- id: "notrycatch",
- label: "No try-catch",
- tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging exceptions in IE reasonable. Stored as query-strings."
- }
- ],
-
- // Set of all modules.
- modules: {},
-
- // logging callback queues
- begin: [],
- done: [],
- log: [],
- testStart: [],
- testDone: [],
- moduleStart: [],
- moduleDone: []
-};
-
-// Export global variables, unless an 'exports' object exists,
-// in that case we assume we're in CommonJS (dealt with on the bottom of the script)
-if ( typeof exports === "undefined" ) {
- extend( window, QUnit );
-
- // Expose QUnit object
- window.QUnit = QUnit;
-}
-
-// Initialize more QUnit.config and QUnit.urlParams
-(function() {
- var i,
- location = window.location || { search: "", protocol: "file:" },
- params = location.search.slice( 1 ).split( "&" ),
- length = params.length,
- urlParams = {},
- current;
-
- if ( params[ 0 ] ) {
- for ( i = 0; i < length; i++ ) {
- current = params[ i ].split( "=" );
- current[ 0 ] = decodeURIComponent( current[ 0 ] );
- // allow just a key to turn on a flag, e.g., test.html?noglobals
- current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true;
- urlParams[ current[ 0 ] ] = current[ 1 ];
- }
- }
-
- QUnit.urlParams = urlParams;
-
- // String search anywhere in moduleName+testName
- config.filter = urlParams.filter;
-
- // Exact match of the module name
- config.module = urlParams.module;
-
- config.testNumber = parseInt( urlParams.testNumber, 10 ) || null;
-
- // Figure out if we're running the tests from a server or not
- QUnit.isLocal = location.protocol === "file:";
-}());
-
-// Extend QUnit object,
-// these after set here because they should not be exposed as global functions
-extend( QUnit, {
- assert: assert,
-
- config: config,
-
- // Initialize the configuration options
- init: function() {
- extend( config, {
- stats: { all: 0, bad: 0 },
- moduleStats: { all: 0, bad: 0 },
- started: +new Date(),
- updateRate: 1000,
- blocking: false,
- autostart: true,
- autorun: false,
- filter: "",
- queue: [],
- semaphore: 1
- });
-
- var tests, banner, result,
- qunit = id( "qunit" );
-
- if ( qunit ) {
- qunit.innerHTML =
- "" +
- "" +
- "" +
- "" +
- "
";
- }
-
- tests = id( "qunit-tests" );
- banner = id( "qunit-banner" );
- result = id( "qunit-testresult" );
-
- if ( tests ) {
- tests.innerHTML = "";
- }
-
- if ( banner ) {
- banner.className = "";
- }
-
- if ( result ) {
- result.parentNode.removeChild( result );
- }
-
- if ( tests ) {
- result = document.createElement( "p" );
- result.id = "qunit-testresult";
- result.className = "result";
- tests.parentNode.insertBefore( result, tests );
- result.innerHTML = "Running...
";
- }
- },
-
- // Resets the test setup. Useful for tests that modify the DOM.
- reset: function() {
- var fixture = id( "qunit-fixture" );
- if ( fixture ) {
- fixture.innerHTML = config.fixture;
- }
- },
-
- // Trigger an event on an element.
- // @example triggerEvent( document.body, "click" );
- triggerEvent: function( elem, type, event ) {
- if ( document.createEvent ) {
- event = document.createEvent( "MouseEvents" );
- event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView,
- 0, 0, 0, 0, 0, false, false, false, false, 0, null);
-
- elem.dispatchEvent( event );
- } else if ( elem.fireEvent ) {
- elem.fireEvent( "on" + type );
- }
- },
-
- // Safe object type checking
- is: function( type, obj ) {
- return QUnit.objectType( obj ) === type;
- },
-
- objectType: function( obj ) {
- if ( typeof obj === "undefined" ) {
- return "undefined";
- // consider: typeof null === object
- }
- if ( obj === null ) {
- return "null";
- }
-
- var match = toString.call( obj ).match(/^\[object\s(.*)\]$/),
- type = match && match[1] || "";
-
- switch ( type ) {
- case "Number":
- if ( isNaN(obj) ) {
- return "nan";
- }
- return "number";
- case "String":
- case "Boolean":
- case "Array":
- case "Date":
- case "RegExp":
- case "Function":
- return type.toLowerCase();
- }
- if ( typeof obj === "object" ) {
- return "object";
- }
- return undefined;
- },
-
- push: function( result, actual, expected, message ) {
- if ( !config.current ) {
- throw new Error( "assertion outside test context, was " + sourceFromStacktrace() );
- }
-
- var output, source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: message,
- actual: actual,
- expected: expected
- };
-
- message = escapeText( message ) || ( result ? "okay" : "failed" );
- message = "" + message + "";
- output = message;
-
- if ( !result ) {
- expected = escapeText( QUnit.jsDump.parse(expected) );
- actual = escapeText( QUnit.jsDump.parse(actual) );
- output += "Expected: | " + expected + " |
";
-
- if ( actual !== expected ) {
- output += "Result: | " + actual + " |
";
- output += "Diff: | " + QUnit.diff( expected, actual ) + " |
";
- }
-
- source = sourceFromStacktrace();
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
- }
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: !!result,
- message: output
- });
- },
-
- pushFailure: function( message, source, actual ) {
- if ( !config.current ) {
- throw new Error( "pushFailure() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
-
- var output,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: false,
- message: message
- };
-
- message = escapeText( message ) || "error";
- message = "" + message + "";
- output = message;
-
- output += "";
-
- if ( actual ) {
- output += "Result: | " + escapeText( actual ) + " |
";
- }
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: false,
- message: output
- });
- },
-
- url: function( params ) {
- params = extend( extend( {}, QUnit.urlParams ), params );
- var key,
- querystring = "?";
-
- for ( key in params ) {
- if ( !hasOwn.call( params, key ) ) {
- continue;
- }
- querystring += encodeURIComponent( key ) + "=" +
- encodeURIComponent( params[ key ] ) + "&";
- }
- return window.location.protocol + "//" + window.location.host +
- window.location.pathname + querystring.slice( 0, -1 );
- },
-
- extend: extend,
- id: id,
- addEvent: addEvent
- // load, equiv, jsDump, diff: Attached later
-});
-
-/**
- * @deprecated: Created for backwards compatibility with test runner that set the hook function
- * into QUnit.{hook}, instead of invoking it and passing the hook function.
- * QUnit.constructor is set to the empty F() above so that we can add to it's prototype here.
- * Doing this allows us to tell if the following methods have been overwritten on the actual
- * QUnit object.
- */
-extend( QUnit.constructor.prototype, {
-
- // Logging callbacks; all receive a single argument with the listed properties
- // run test/logs.html for any related changes
- begin: registerLoggingCallback( "begin" ),
-
- // done: { failed, passed, total, runtime }
- done: registerLoggingCallback( "done" ),
-
- // log: { result, actual, expected, message }
- log: registerLoggingCallback( "log" ),
-
- // testStart: { name }
- testStart: registerLoggingCallback( "testStart" ),
-
- // testDone: { name, failed, passed, total, duration }
- testDone: registerLoggingCallback( "testDone" ),
-
- // moduleStart: { name }
- moduleStart: registerLoggingCallback( "moduleStart" ),
-
- // moduleDone: { name, failed, passed, total }
- moduleDone: registerLoggingCallback( "moduleDone" )
-});
-
-if ( typeof document === "undefined" || document.readyState === "complete" ) {
- config.autorun = true;
-}
-
-QUnit.load = function() {
- runLoggingCallbacks( "begin", QUnit, {} );
-
- // Initialize the config, saving the execution queue
- var banner, filter, i, label, len, main, ol, toolbar, userAgent, val,
- urlConfigCheckboxesContainer, urlConfigCheckboxes, moduleFilter,
- numModules = 0,
- moduleFilterHtml = "",
- urlConfigHtml = "",
- oldconfig = extend( {}, config );
-
- QUnit.init();
- extend(config, oldconfig);
-
- config.blocking = false;
-
- len = config.urlConfig.length;
-
- for ( i = 0; i < len; i++ ) {
- val = config.urlConfig[i];
- if ( typeof val === "string" ) {
- val = {
- id: val,
- label: val,
- tooltip: "[no tooltip available]"
- };
- }
- config[ val.id ] = QUnit.urlParams[ val.id ];
- urlConfigHtml += "";
- }
-
- moduleFilterHtml += "";
-
- // `userAgent` initialized at top of scope
- userAgent = id( "qunit-userAgent" );
- if ( userAgent ) {
- userAgent.innerHTML = navigator.userAgent;
- }
-
- // `banner` initialized at top of scope
- banner = id( "qunit-header" );
- if ( banner ) {
- banner.innerHTML = "" + banner.innerHTML + " ";
- }
-
- // `toolbar` initialized at top of scope
- toolbar = id( "qunit-testrunner-toolbar" );
- if ( toolbar ) {
- // `filter` initialized at top of scope
- filter = document.createElement( "input" );
- filter.type = "checkbox";
- filter.id = "qunit-filter-pass";
-
- addEvent( filter, "click", function() {
- var tmp,
- ol = document.getElementById( "qunit-tests" );
-
- if ( filter.checked ) {
- ol.className = ol.className + " hidepass";
- } else {
- tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " ";
- ol.className = tmp.replace( / hidepass /, " " );
- }
- if ( defined.sessionStorage ) {
- if (filter.checked) {
- sessionStorage.setItem( "qunit-filter-passed-tests", "true" );
- } else {
- sessionStorage.removeItem( "qunit-filter-passed-tests" );
- }
- }
- });
-
- if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem( "qunit-filter-passed-tests" ) ) {
- filter.checked = true;
- // `ol` initialized at top of scope
- ol = document.getElementById( "qunit-tests" );
- ol.className = ol.className + " hidepass";
- }
- toolbar.appendChild( filter );
-
- // `label` initialized at top of scope
- label = document.createElement( "label" );
- label.setAttribute( "for", "qunit-filter-pass" );
- label.setAttribute( "title", "Only show tests and assertons that fail. Stored in sessionStorage." );
- label.innerHTML = "Hide passed tests";
- toolbar.appendChild( label );
-
- urlConfigCheckboxesContainer = document.createElement("span");
- urlConfigCheckboxesContainer.innerHTML = urlConfigHtml;
- urlConfigCheckboxes = urlConfigCheckboxesContainer.getElementsByTagName("input");
- // For oldIE support:
- // * Add handlers to the individual elements instead of the container
- // * Use "click" instead of "change"
- // * Fallback from event.target to event.srcElement
- addEvents( urlConfigCheckboxes, "click", function( event ) {
- var params = {},
- target = event.target || event.srcElement;
- params[ target.name ] = target.checked ? true : undefined;
- window.location = QUnit.url( params );
- });
- toolbar.appendChild( urlConfigCheckboxesContainer );
-
- if (numModules > 1) {
- moduleFilter = document.createElement( 'span' );
- moduleFilter.setAttribute( 'id', 'qunit-modulefilter-container' );
- moduleFilter.innerHTML = moduleFilterHtml;
- addEvent( moduleFilter.lastChild, "change", function() {
- var selectBox = moduleFilter.getElementsByTagName("select")[0],
- selectedModule = decodeURIComponent(selectBox.options[selectBox.selectedIndex].value);
-
- window.location = QUnit.url( { module: ( selectedModule === "" ) ? undefined : selectedModule } );
- });
- toolbar.appendChild(moduleFilter);
- }
- }
-
- // `main` initialized at top of scope
- main = id( "qunit-fixture" );
- if ( main ) {
- config.fixture = main.innerHTML;
- }
-
- if ( config.autostart ) {
- QUnit.start();
- }
-};
-
-addEvent( window, "load", QUnit.load );
-
-// `onErrorFnPrev` initialized at top of scope
-// Preserve other handlers
-onErrorFnPrev = window.onerror;
-
-// Cover uncaught exceptions
-// Returning true will surpress the default browser handler,
-// returning false will let it run.
-window.onerror = function ( error, filePath, linerNr ) {
- var ret = false;
- if ( onErrorFnPrev ) {
- ret = onErrorFnPrev( error, filePath, linerNr );
- }
-
- // Treat return value as window.onerror itself does,
- // Only do our handling if not surpressed.
- if ( ret !== true ) {
- if ( QUnit.config.current ) {
- if ( QUnit.config.current.ignoreGlobalErrors ) {
- return true;
- }
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- } else {
- QUnit.test( "global failure", extend( function() {
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- }, { validTest: validTest } ) );
- }
- return false;
- }
-
- return ret;
-};
-
-function done() {
- config.autorun = true;
-
- // Log the last module results
- if ( config.currentModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.currentModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
-
- var i, key,
- banner = id( "qunit-banner" ),
- tests = id( "qunit-tests" ),
- runtime = +new Date() - config.started,
- passed = config.stats.all - config.stats.bad,
- html = [
- "Tests completed in ",
- runtime,
- " milliseconds.
",
- "",
- passed,
- " assertions of ",
- config.stats.all,
- " passed, ",
- config.stats.bad,
- " failed."
- ].join( "" );
-
- if ( banner ) {
- banner.className = ( config.stats.bad ? "qunit-fail" : "qunit-pass" );
- }
-
- if ( tests ) {
- id( "qunit-testresult" ).innerHTML = html;
- }
-
- if ( config.altertitle && typeof document !== "undefined" && document.title ) {
- // show ✖ for good, ✔ for bad suite result in title
- // use escape sequences in case file gets loaded with non-utf-8-charset
- document.title = [
- ( config.stats.bad ? "\u2716" : "\u2714" ),
- document.title.replace( /^[\u2714\u2716] /i, "" )
- ].join( " " );
- }
-
- // clear own sessionStorage items if all tests passed
- if ( config.reorder && defined.sessionStorage && config.stats.bad === 0 ) {
- // `key` & `i` initialized at top of scope
- for ( i = 0; i < sessionStorage.length; i++ ) {
- key = sessionStorage.key( i++ );
- if ( key.indexOf( "qunit-test-" ) === 0 ) {
- sessionStorage.removeItem( key );
- }
- }
- }
-
- // scroll back to top to show results
- if ( window.scrollTo ) {
- window.scrollTo(0, 0);
- }
-
- runLoggingCallbacks( "done", QUnit, {
- failed: config.stats.bad,
- passed: passed,
- total: config.stats.all,
- runtime: runtime
- });
-}
-
-/** @return Boolean: true if this test should be ran */
-function validTest( test ) {
- var include,
- filter = config.filter && config.filter.toLowerCase(),
- module = config.module && config.module.toLowerCase(),
- fullName = (test.module + ": " + test.testName).toLowerCase();
-
- // Internally-generated tests are always valid
- if ( test.callback && test.callback.validTest === validTest ) {
- delete test.callback.validTest;
- return true;
- }
-
- if ( config.testNumber ) {
- return test.testNumber === config.testNumber;
- }
-
- if ( module && ( !test.module || test.module.toLowerCase() !== module ) ) {
- return false;
- }
-
- if ( !filter ) {
- return true;
- }
-
- include = filter.charAt( 0 ) !== "!";
- if ( !include ) {
- filter = filter.slice( 1 );
- }
-
- // If the filter matches, we need to honour include
- if ( fullName.indexOf( filter ) !== -1 ) {
- return include;
- }
-
- // Otherwise, do the opposite
- return !include;
-}
-
-// so far supports only Firefox, Chrome and Opera (buggy), Safari (for real exceptions)
-// Later Safari and IE10 are supposed to support error.stack as well
-// See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack
-function extractStacktrace( e, offset ) {
- offset = offset === undefined ? 3 : offset;
-
- var stack, include, i;
-
- if ( e.stacktrace ) {
- // Opera
- return e.stacktrace.split( "\n" )[ offset + 3 ];
- } else if ( e.stack ) {
- // Firefox, Chrome
- stack = e.stack.split( "\n" );
- if (/^error$/i.test( stack[0] ) ) {
- stack.shift();
- }
- if ( fileName ) {
- include = [];
- for ( i = offset; i < stack.length; i++ ) {
- if ( stack[ i ].indexOf( fileName ) !== -1 ) {
- break;
- }
- include.push( stack[ i ] );
- }
- if ( include.length ) {
- return include.join( "\n" );
- }
- }
- return stack[ offset ];
- } else if ( e.sourceURL ) {
- // Safari, PhantomJS
- // hopefully one day Safari provides actual stacktraces
- // exclude useless self-reference for generated Error objects
- if ( /qunit.js$/.test( e.sourceURL ) ) {
- return;
- }
- // for actual exceptions, this is useful
- return e.sourceURL + ":" + e.line;
- }
-}
-function sourceFromStacktrace( offset ) {
- try {
- throw new Error();
- } catch ( e ) {
- return extractStacktrace( e, offset );
- }
-}
-
-/**
- * Escape text for attribute or text content.
- */
-function escapeText( s ) {
- if ( !s ) {
- return "";
- }
- s = s + "";
- // Both single quotes and double quotes (for attributes)
- return s.replace( /['"<>&]/g, function( s ) {
- switch( s ) {
- case '\'':
- return ''';
- case '"':
- return '"';
- case '<':
- return '<';
- case '>':
- return '>';
- case '&':
- return '&';
- }
- });
-}
-
-function synchronize( callback, last ) {
- config.queue.push( callback );
-
- if ( config.autorun && !config.blocking ) {
- process( last );
- }
-}
-
-function process( last ) {
- function next() {
- process( last );
- }
- var start = new Date().getTime();
- config.depth = config.depth ? config.depth + 1 : 1;
-
- while ( config.queue.length && !config.blocking ) {
- if ( !defined.setTimeout || config.updateRate <= 0 || ( ( new Date().getTime() - start ) < config.updateRate ) ) {
- config.queue.shift()();
- } else {
- window.setTimeout( next, 13 );
- break;
- }
- }
- config.depth--;
- if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) {
- done();
- }
-}
-
-function saveGlobal() {
- config.pollution = [];
-
- if ( config.noglobals ) {
- for ( var key in window ) {
- // in Opera sometimes DOM element ids show up here, ignore them
- if ( !hasOwn.call( window, key ) || /^qunit-test-output/.test( key ) ) {
- continue;
- }
- config.pollution.push( key );
- }
- }
-}
-
-function checkPollution() {
- var newGlobals,
- deletedGlobals,
- old = config.pollution;
-
- saveGlobal();
-
- newGlobals = diff( config.pollution, old );
- if ( newGlobals.length > 0 ) {
- QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join(", ") );
- }
-
- deletedGlobals = diff( old, config.pollution );
- if ( deletedGlobals.length > 0 ) {
- QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join(", ") );
- }
-}
-
-// returns a new Array with the elements that are in a but not in b
-function diff( a, b ) {
- var i, j,
- result = a.slice();
-
- for ( i = 0; i < result.length; i++ ) {
- for ( j = 0; j < b.length; j++ ) {
- if ( result[i] === b[j] ) {
- result.splice( i, 1 );
- i--;
- break;
- }
- }
- }
- return result;
-}
-
-function extend( a, b ) {
- for ( var prop in b ) {
- if ( b[ prop ] === undefined ) {
- delete a[ prop ];
-
- // Avoid "Member not found" error in IE8 caused by setting window.constructor
- } else if ( prop !== "constructor" || a !== window ) {
- a[ prop ] = b[ prop ];
- }
- }
-
- return a;
-}
-
-/**
- * @param {HTMLElement} elem
- * @param {string} type
- * @param {Function} fn
- */
-function addEvent( elem, type, fn ) {
- // Standards-based browsers
- if ( elem.addEventListener ) {
- elem.addEventListener( type, fn, false );
- // IE
- } else {
- elem.attachEvent( "on" + type, fn );
- }
-}
-
-/**
- * @param {Array|NodeList} elems
- * @param {string} type
- * @param {Function} fn
- */
-function addEvents( elems, type, fn ) {
- var i = elems.length;
- while ( i-- ) {
- addEvent( elems[i], type, fn );
- }
-}
-
-function hasClass( elem, name ) {
- return (" " + elem.className + " ").indexOf(" " + name + " ") > -1;
-}
-
-function addClass( elem, name ) {
- if ( !hasClass( elem, name ) ) {
- elem.className += (elem.className ? " " : "") + name;
- }
-}
-
-function removeClass( elem, name ) {
- var set = " " + elem.className + " ";
- // Class name may appear multiple times
- while ( set.indexOf(" " + name + " ") > -1 ) {
- set = set.replace(" " + name + " " , " ");
- }
- // If possible, trim it for prettiness, but not neccecarily
- elem.className = window.jQuery ? jQuery.trim( set ) : ( set.trim ? set.trim() : set );
-}
-
-function id( name ) {
- return !!( typeof document !== "undefined" && document && document.getElementById ) &&
- document.getElementById( name );
-}
-
-function registerLoggingCallback( key ) {
- return function( callback ) {
- config[key].push( callback );
- };
-}
-
-// Supports deprecated method of completely overwriting logging callbacks
-function runLoggingCallbacks( key, scope, args ) {
- var i, callbacks;
- if ( QUnit.hasOwnProperty( key ) ) {
- QUnit[ key ].call(scope, args );
- } else {
- callbacks = config[ key ];
- for ( i = 0; i < callbacks.length; i++ ) {
- callbacks[ i ].call( scope, args );
- }
- }
-}
-
-// Test for equality any JavaScript type.
-// Author: Philippe Rathé
-QUnit.equiv = (function() {
-
- // Call the o related callback with the given arguments.
- function bindCallbacks( o, callbacks, args ) {
- var prop = QUnit.objectType( o );
- if ( prop ) {
- if ( QUnit.objectType( callbacks[ prop ] ) === "function" ) {
- return callbacks[ prop ].apply( callbacks, args );
- } else {
- return callbacks[ prop ]; // or undefined
- }
- }
- }
-
- // the real equiv function
- var innerEquiv,
- // stack to decide between skip/abort functions
- callers = [],
- // stack to avoiding loops from circular referencing
- parents = [],
-
- getProto = Object.getPrototypeOf || function ( obj ) {
- return obj.__proto__;
- },
- callbacks = (function () {
-
- // for string, boolean, number and null
- function useStrictEquality( b, a ) {
- /*jshint eqeqeq:false */
- if ( b instanceof a.constructor || a instanceof b.constructor ) {
- // to catch short annotaion VS 'new' annotation of a
- // declaration
- // e.g. var i = 1;
- // var j = new Number(1);
- return a == b;
- } else {
- return a === b;
- }
- }
-
- return {
- "string": useStrictEquality,
- "boolean": useStrictEquality,
- "number": useStrictEquality,
- "null": useStrictEquality,
- "undefined": useStrictEquality,
-
- "nan": function( b ) {
- return isNaN( b );
- },
-
- "date": function( b, a ) {
- return QUnit.objectType( b ) === "date" && a.valueOf() === b.valueOf();
- },
-
- "regexp": function( b, a ) {
- return QUnit.objectType( b ) === "regexp" &&
- // the regex itself
- a.source === b.source &&
- // and its modifers
- a.global === b.global &&
- // (gmi) ...
- a.ignoreCase === b.ignoreCase &&
- a.multiline === b.multiline &&
- a.sticky === b.sticky;
- },
-
- // - skip when the property is a method of an instance (OOP)
- // - abort otherwise,
- // initial === would have catch identical references anyway
- "function": function() {
- var caller = callers[callers.length - 1];
- return caller !== Object && typeof caller !== "undefined";
- },
-
- "array": function( b, a ) {
- var i, j, len, loop;
-
- // b could be an object literal here
- if ( QUnit.objectType( b ) !== "array" ) {
- return false;
- }
-
- len = a.length;
- if ( len !== b.length ) {
- // safe and faster
- return false;
- }
-
- // track reference to avoid circular references
- parents.push( a );
- for ( i = 0; i < len; i++ ) {
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- loop = true;// dont rewalk array
- }
- }
- if ( !loop && !innerEquiv(a[i], b[i]) ) {
- parents.pop();
- return false;
- }
- }
- parents.pop();
- return true;
- },
-
- "object": function( b, a ) {
- var i, j, loop,
- // Default to true
- eq = true,
- aProperties = [],
- bProperties = [];
-
- // comparing constructors is more strict than using
- // instanceof
- if ( a.constructor !== b.constructor ) {
- // Allow objects with no prototype to be equivalent to
- // objects with Object as their constructor.
- if ( !(( getProto(a) === null && getProto(b) === Object.prototype ) ||
- ( getProto(b) === null && getProto(a) === Object.prototype ) ) ) {
- return false;
- }
- }
-
- // stack constructor before traversing properties
- callers.push( a.constructor );
- // track reference to avoid circular references
- parents.push( a );
-
- for ( i in a ) { // be strict: don't ensures hasOwnProperty
- // and go deep
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- // don't go down the same path twice
- loop = true;
- }
- }
- aProperties.push(i); // collect a's properties
-
- if (!loop && !innerEquiv( a[i], b[i] ) ) {
- eq = false;
- break;
- }
- }
-
- callers.pop(); // unstack, we are done
- parents.pop();
-
- for ( i in b ) {
- bProperties.push( i ); // collect b's properties
- }
-
- // Ensures identical properties name
- return eq && innerEquiv( aProperties.sort(), bProperties.sort() );
- }
- };
- }());
-
- innerEquiv = function() { // can take multiple arguments
- var args = [].slice.apply( arguments );
- if ( args.length < 2 ) {
- return true; // end transition
- }
-
- return (function( a, b ) {
- if ( a === b ) {
- return true; // catch the most you can
- } else if ( a === null || b === null || typeof a === "undefined" ||
- typeof b === "undefined" ||
- QUnit.objectType(a) !== QUnit.objectType(b) ) {
- return false; // don't lose time with error prone cases
- } else {
- return bindCallbacks(a, callbacks, [ b, a ]);
- }
-
- // apply transition with (1..n) arguments
- }( args[0], args[1] ) && arguments.callee.apply( this, args.splice(1, args.length - 1 )) );
- };
-
- return innerEquiv;
-}());
-
-/**
- * jsDump Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com |
- * http://flesler.blogspot.com Licensed under BSD
- * (http://www.opensource.org/licenses/bsd-license.php) Date: 5/15/2008
- *
- * @projectDescription Advanced and extensible data dumping for Javascript.
- * @version 1.0.0
- * @author Ariel Flesler
- * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html}
- */
-QUnit.jsDump = (function() {
- function quote( str ) {
- return '"' + str.toString().replace( /"/g, '\\"' ) + '"';
- }
- function literal( o ) {
- return o + "";
- }
- function join( pre, arr, post ) {
- var s = jsDump.separator(),
- base = jsDump.indent(),
- inner = jsDump.indent(1);
- if ( arr.join ) {
- arr = arr.join( "," + s + inner );
- }
- if ( !arr ) {
- return pre + post;
- }
- return [ pre, inner + arr, base + post ].join(s);
- }
- function array( arr, stack ) {
- var i = arr.length, ret = new Array(i);
- this.up();
- while ( i-- ) {
- ret[i] = this.parse( arr[i] , undefined , stack);
- }
- this.down();
- return join( "[", ret, "]" );
- }
-
- var reName = /^function (\w+)/,
- jsDump = {
- // type is used mostly internally, you can fix a (custom)type in advance
- parse: function( obj, type, stack ) {
- stack = stack || [ ];
- var inStack, res,
- parser = this.parsers[ type || this.typeOf(obj) ];
-
- type = typeof parser;
- inStack = inArray( obj, stack );
-
- if ( inStack !== -1 ) {
- return "recursion(" + (inStack - stack.length) + ")";
- }
- if ( type === "function" ) {
- stack.push( obj );
- res = parser.call( this, obj, stack );
- stack.pop();
- return res;
- }
- return ( type === "string" ) ? parser : this.parsers.error;
- },
- typeOf: function( obj ) {
- var type;
- if ( obj === null ) {
- type = "null";
- } else if ( typeof obj === "undefined" ) {
- type = "undefined";
- } else if ( QUnit.is( "regexp", obj) ) {
- type = "regexp";
- } else if ( QUnit.is( "date", obj) ) {
- type = "date";
- } else if ( QUnit.is( "function", obj) ) {
- type = "function";
- } else if ( typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined" ) {
- type = "window";
- } else if ( obj.nodeType === 9 ) {
- type = "document";
- } else if ( obj.nodeType ) {
- type = "node";
- } else if (
- // native arrays
- toString.call( obj ) === "[object Array]" ||
- // NodeList objects
- ( typeof obj.length === "number" && typeof obj.item !== "undefined" && ( obj.length ? obj.item(0) === obj[0] : ( obj.item( 0 ) === null && typeof obj[0] === "undefined" ) ) )
- ) {
- type = "array";
- } else if ( obj.constructor === Error.prototype.constructor ) {
- type = "error";
- } else {
- type = typeof obj;
- }
- return type;
- },
- separator: function() {
- return this.multiline ? this.HTML ? "
" : "\n" : this.HTML ? " " : " ";
- },
- // extra can be a number, shortcut for increasing-calling-decreasing
- indent: function( extra ) {
- if ( !this.multiline ) {
- return "";
- }
- var chr = this.indentChar;
- if ( this.HTML ) {
- chr = chr.replace( /\t/g, " " ).replace( / /g, " " );
- }
- return new Array( this._depth_ + (extra||0) ).join(chr);
- },
- up: function( a ) {
- this._depth_ += a || 1;
- },
- down: function( a ) {
- this._depth_ -= a || 1;
- },
- setParser: function( name, parser ) {
- this.parsers[name] = parser;
- },
- // The next 3 are exposed so you can use them
- quote: quote,
- literal: literal,
- join: join,
- //
- _depth_: 1,
- // This is the list of parsers, to modify them, use jsDump.setParser
- parsers: {
- window: "[Window]",
- document: "[Document]",
- error: function(error) {
- return "Error(\"" + error.message + "\")";
- },
- unknown: "[Unknown]",
- "null": "null",
- "undefined": "undefined",
- "function": function( fn ) {
- var ret = "function",
- // functions never have name in IE
- name = "name" in fn ? fn.name : (reName.exec(fn) || [])[1];
-
- if ( name ) {
- ret += " " + name;
- }
- ret += "( ";
-
- ret = [ ret, QUnit.jsDump.parse( fn, "functionArgs" ), "){" ].join( "" );
- return join( ret, QUnit.jsDump.parse(fn,"functionCode" ), "}" );
- },
- array: array,
- nodelist: array,
- "arguments": array,
- object: function( map, stack ) {
- var ret = [ ], keys, key, val, i;
- QUnit.jsDump.up();
- keys = [];
- for ( key in map ) {
- keys.push( key );
- }
- keys.sort();
- for ( i = 0; i < keys.length; i++ ) {
- key = keys[ i ];
- val = map[ key ];
- ret.push( QUnit.jsDump.parse( key, "key" ) + ": " + QUnit.jsDump.parse( val, undefined, stack ) );
- }
- QUnit.jsDump.down();
- return join( "{", ret, "}" );
- },
- node: function( node ) {
- var len, i, val,
- open = QUnit.jsDump.HTML ? "<" : "<",
- close = QUnit.jsDump.HTML ? ">" : ">",
- tag = node.nodeName.toLowerCase(),
- ret = open + tag,
- attrs = node.attributes;
-
- if ( attrs ) {
- for ( i = 0, len = attrs.length; i < len; i++ ) {
- val = attrs[i].nodeValue;
- // IE6 includes all attributes in .attributes, even ones not explicitly set.
- // Those have values like undefined, null, 0, false, "" or "inherit".
- if ( val && val !== "inherit" ) {
- ret += " " + attrs[i].nodeName + "=" + QUnit.jsDump.parse( val, "attribute" );
- }
- }
- }
- ret += close;
-
- // Show content of TextNode or CDATASection
- if ( node.nodeType === 3 || node.nodeType === 4 ) {
- ret += node.nodeValue;
- }
-
- return ret + open + "/" + tag + close;
- },
- // function calls it internally, it's the arguments part of the function
- functionArgs: function( fn ) {
- var args,
- l = fn.length;
-
- if ( !l ) {
- return "";
- }
-
- args = new Array(l);
- while ( l-- ) {
- // 97 is 'a'
- args[l] = String.fromCharCode(97+l);
- }
- return " " + args.join( ", " ) + " ";
- },
- // object calls it internally, the key part of an item in a map
- key: quote,
- // function calls it internally, it's the content of the function
- functionCode: "[code]",
- // node calls it internally, it's an html attribute value
- attribute: quote,
- string: quote,
- date: quote,
- regexp: literal,
- number: literal,
- "boolean": literal
- },
- // if true, entities are escaped ( <, >, \t, space and \n )
- HTML: false,
- // indentation unit
- indentChar: " ",
- // if true, items in a collection, are separated by a \n, else just a space.
- multiline: true
- };
-
- return jsDump;
-}());
-
-// from jquery.js
-function inArray( elem, array ) {
- if ( array.indexOf ) {
- return array.indexOf( elem );
- }
-
- for ( var i = 0, length = array.length; i < length; i++ ) {
- if ( array[ i ] === elem ) {
- return i;
- }
- }
-
- return -1;
-}
-
-/*
- * Javascript Diff Algorithm
- * By John Resig (http://ejohn.org/)
- * Modified by Chu Alan "sprite"
- *
- * Released under the MIT license.
- *
- * More Info:
- * http://ejohn.org/projects/javascript-diff-algorithm/
- *
- * Usage: QUnit.diff(expected, actual)
- *
- * QUnit.diff( "the quick brown fox jumped over", "the quick fox jumps over" ) == "the quick brown fox jumped jumps over"
- */
-QUnit.diff = (function() {
- /*jshint eqeqeq:false, eqnull:true */
- function diff( o, n ) {
- var i,
- ns = {},
- os = {};
-
- for ( i = 0; i < n.length; i++ ) {
- if ( !hasOwn.call( ns, n[i] ) ) {
- ns[ n[i] ] = {
- rows: [],
- o: null
- };
- }
- ns[ n[i] ].rows.push( i );
- }
-
- for ( i = 0; i < o.length; i++ ) {
- if ( !hasOwn.call( os, o[i] ) ) {
- os[ o[i] ] = {
- rows: [],
- n: null
- };
- }
- os[ o[i] ].rows.push( i );
- }
-
- for ( i in ns ) {
- if ( !hasOwn.call( ns, i ) ) {
- continue;
- }
- if ( ns[i].rows.length === 1 && hasOwn.call( os, i ) && os[i].rows.length === 1 ) {
- n[ ns[i].rows[0] ] = {
- text: n[ ns[i].rows[0] ],
- row: os[i].rows[0]
- };
- o[ os[i].rows[0] ] = {
- text: o[ os[i].rows[0] ],
- row: ns[i].rows[0]
- };
- }
- }
-
- for ( i = 0; i < n.length - 1; i++ ) {
- if ( n[i].text != null && n[ i + 1 ].text == null && n[i].row + 1 < o.length && o[ n[i].row + 1 ].text == null &&
- n[ i + 1 ] == o[ n[i].row + 1 ] ) {
-
- n[ i + 1 ] = {
- text: n[ i + 1 ],
- row: n[i].row + 1
- };
- o[ n[i].row + 1 ] = {
- text: o[ n[i].row + 1 ],
- row: i + 1
- };
- }
- }
-
- for ( i = n.length - 1; i > 0; i-- ) {
- if ( n[i].text != null && n[ i - 1 ].text == null && n[i].row > 0 && o[ n[i].row - 1 ].text == null &&
- n[ i - 1 ] == o[ n[i].row - 1 ]) {
-
- n[ i - 1 ] = {
- text: n[ i - 1 ],
- row: n[i].row - 1
- };
- o[ n[i].row - 1 ] = {
- text: o[ n[i].row - 1 ],
- row: i - 1
- };
- }
- }
-
- return {
- o: o,
- n: n
- };
- }
-
- return function( o, n ) {
- o = o.replace( /\s+$/, "" );
- n = n.replace( /\s+$/, "" );
-
- var i, pre,
- str = "",
- out = diff( o === "" ? [] : o.split(/\s+/), n === "" ? [] : n.split(/\s+/) ),
- oSpace = o.match(/\s+/g),
- nSpace = n.match(/\s+/g);
-
- if ( oSpace == null ) {
- oSpace = [ " " ];
- }
- else {
- oSpace.push( " " );
- }
-
- if ( nSpace == null ) {
- nSpace = [ " " ];
- }
- else {
- nSpace.push( " " );
- }
-
- if ( out.n.length === 0 ) {
- for ( i = 0; i < out.o.length; i++ ) {
- str += "" + out.o[i] + oSpace[i] + "";
- }
- }
- else {
- if ( out.n[0].text == null ) {
- for ( n = 0; n < out.o.length && out.o[n].text == null; n++ ) {
- str += "" + out.o[n] + oSpace[n] + "";
- }
- }
-
- for ( i = 0; i < out.n.length; i++ ) {
- if (out.n[i].text == null) {
- str += "" + out.n[i] + nSpace[i] + "";
- }
- else {
- // `pre` initialized at top of scope
- pre = "";
-
- for ( n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++ ) {
- pre += "" + out.o[n] + oSpace[n] + "";
- }
- str += " " + out.n[i].text + nSpace[i] + pre;
- }
- }
- }
-
- return str;
- };
-}());
-
-// for CommonJS enviroments, export everything
-if ( typeof exports !== "undefined" ) {
- extend( exports, QUnit );
-}
-
-// get at whatever the global object is, like window in browsers
-}( (function() {return this;}.call()) ));
diff --git a/test/lib/require.js b/test/lib/require.js
deleted file mode 100644
index 987f865..0000000
--- a/test/lib/require.js
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- RequireJS 2.1.5 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.
- Available via the MIT or new BSD license.
- see: http://github.com/jrburke/requirejs for details
-*/
-var requirejs,require,define;
-(function(aa){function I(b){return"[object Function]"===L.call(b)}function J(b){return"[object Array]"===L.call(b)}function y(b,c){if(b){var d;for(d=0;dthis.depCount&&!this.defined){if(I(n)){if(this.events.error)try{e=i.execCb(c,n,b,e)}catch(d){a=d}else e=i.execCb(c,n,b,e);this.map.isDefine&&((b=this.module)&&void 0!==b.exports&&b.exports!==this.exports?e=b.exports:void 0===e&&this.usingExports&&(e=this.exports));if(a)return a.requireMap=this.map,a.requireModules=[this.map.id],a.requireType="define",v(this.error=
-a)}else e=n;this.exports=e;if(this.map.isDefine&&!this.ignore&&(q[c]=e,l.onResourceLoad))l.onResourceLoad(i,this.map,this.depMaps);x(c);this.defined=!0}this.defining=!1;this.defined&&!this.defineEmitted&&(this.defineEmitted=!0,this.emit("defined",this.exports),this.defineEmitComplete=!0)}}else this.fetch()}},callPlugin:function(){var a=this.map,b=a.id,d=j(a.prefix);this.depMaps.push(d);t(d,"defined",u(this,function(e){var n,d;d=this.map.name;var g=this.map.parentMap?this.map.parentMap.name:null,h=
-i.makeRequire(a.parentMap,{enableBuildCallback:!0});if(this.map.unnormalized){if(e.normalize&&(d=e.normalize(d,function(a){return c(a,g,!0)})||""),e=j(a.prefix+"!"+d,this.map.parentMap),t(e,"defined",u(this,function(a){this.init([],function(){return a},null,{enabled:!0,ignore:!0})})),d=m(p,e.id)){this.depMaps.push(e);if(this.events.error)d.on("error",u(this,function(a){this.emit("error",a)}));d.enable()}}else n=u(this,function(a){this.init([],function(){return a},null,{enabled:!0})}),n.error=u(this,
-function(a){this.inited=!0;this.error=a;a.requireModules=[b];G(p,function(a){0===a.map.id.indexOf(b+"_unnormalized")&&x(a.map.id)});v(a)}),n.fromText=u(this,function(e,c){var d=a.name,g=j(d),C=O;c&&(e=c);C&&(O=!1);r(g);s(k.config,b)&&(k.config[d]=k.config[b]);try{l.exec(e)}catch(ca){return v(B("fromtexteval","fromText eval for "+b+" failed: "+ca,ca,[b]))}C&&(O=!0);this.depMaps.push(g);i.completeLoad(d);h([d],n)}),e.load(a.name,h,n,k)}));i.enable(d,this);this.pluginMaps[d.id]=d},enable:function(){V[this.map.id]=
-this;this.enabling=this.enabled=!0;y(this.depMaps,u(this,function(a,b){var c,e;if("string"===typeof a){a=j(a,this.map.isDefine?this.map:this.map.parentMap,!1,!this.skipMap);this.depMaps[b]=a;if(c=m(N,a.id)){this.depExports[b]=c(this);return}this.depCount+=1;t(a,"defined",u(this,function(a){this.defineDep(b,a);this.check()}));this.errback&&t(a,"error",this.errback)}c=a.id;e=p[c];!s(N,c)&&(e&&!e.enabled)&&i.enable(a,this)}));G(this.pluginMaps,u(this,function(a){var b=m(p,a.id);b&&!b.enabled&&i.enable(a,
-this)}));this.enabling=!1;this.check()},on:function(a,b){var c=this.events[a];c||(c=this.events[a]=[]);c.push(b)},emit:function(a,b){y(this.events[a],function(a){a(b)});"error"===a&&delete this.events[a]}};i={config:k,contextName:b,registry:p,defined:q,urlFetched:U,defQueue:H,Module:Z,makeModuleMap:j,nextTick:l.nextTick,onError:v,configure:function(a){a.baseUrl&&"/"!==a.baseUrl.charAt(a.baseUrl.length-1)&&(a.baseUrl+="/");var b=k.pkgs,c=k.shim,e={paths:!0,config:!0,map:!0};G(a,function(a,b){e[b]?
-"map"===b?(k.map||(k.map={}),R(k[b],a,!0,!0)):R(k[b],a,!0):k[b]=a});a.shim&&(G(a.shim,function(a,b){J(a)&&(a={deps:a});if((a.exports||a.init)&&!a.exportsFn)a.exportsFn=i.makeShimExports(a);c[b]=a}),k.shim=c);a.packages&&(y(a.packages,function(a){a="string"===typeof a?{name:a}:a;b[a.name]={name:a.name,location:a.location||a.name,main:(a.main||"main").replace(ja,"").replace(ea,"")}}),k.pkgs=b);G(p,function(a,b){!a.inited&&!a.map.unnormalized&&(a.map=j(b))});if(a.deps||a.callback)i.require(a.deps||[],
-a.callback)},makeShimExports:function(a){return function(){var b;a.init&&(b=a.init.apply(aa,arguments));return b||a.exports&&ba(a.exports)}},makeRequire:function(a,f){function d(e,c,h){var g,k;f.enableBuildCallback&&(c&&I(c))&&(c.__requireJsBuild=!0);if("string"===typeof e){if(I(c))return v(B("requireargs","Invalid require call"),h);if(a&&s(N,e))return N[e](p[a.id]);if(l.get)return l.get(i,e,a,d);g=j(e,a,!1,!0);g=g.id;return!s(q,g)?v(B("notloaded",'Module name "'+g+'" has not been loaded yet for context: '+
-b+(a?"":". Use require([])"))):q[g]}L();i.nextTick(function(){L();k=r(j(null,a));k.skipMap=f.skipMap;k.init(e,c,h,{enabled:!0});D()});return d}f=f||{};R(d,{isBrowser:A,toUrl:function(b){var d,f=b.lastIndexOf("."),g=b.split("/")[0];if(-1!==f&&(!("."===g||".."===g)||1h.attachEvent.toString().indexOf("[native code"))&&!Y?(O=!0,h.attachEvent("onreadystatechange",b.onScriptLoad)):(h.addEventListener("load",b.onScriptLoad,!1),h.addEventListener("error",b.onScriptError,!1)),h.src=d,K=h,D?x.insertBefore(h,D):x.appendChild(h),K=null,h;if(da)try{importScripts(d),b.completeLoad(c)}catch(j){b.onError(B("importscripts","importScripts failed for "+c+" at "+d,j,[c]))}};A&&M(document.getElementsByTagName("script"),function(b){x||(x=
-b.parentNode);if(t=b.getAttribute("data-main"))return r.baseUrl||(E=t.split("/"),Q=E.pop(),fa=E.length?E.join("/")+"/":"./",r.baseUrl=fa,t=Q),t=t.replace(ea,""),r.deps=r.deps?r.deps.concat(t):[t],!0});define=function(b,c,d){var l,h;"string"!==typeof b&&(d=c,c=b,b=null);J(c)||(d=c,c=[]);!c.length&&I(d)&&d.length&&(d.toString().replace(la,"").replace(ma,function(b,d){c.push(d)}),c=(1===d.length?["require"]:["require","exports","module"]).concat(c));if(O){if(!(l=K))P&&"interactive"===P.readyState||M(document.getElementsByTagName("script"),
-function(b){if("interactive"===b.readyState)return P=b}),l=P;l&&(b||(b=l.getAttribute("data-requiremodule")),h=F[l.getAttribute("data-requirecontext")])}(h?h.defQueue:T).push([b,c,d])};define.amd={jQuery:!0};l.exec=function(b){return eval(b)};l(r)}})(this);
diff --git a/test/lib/resemble.js b/test/lib/resemble.js
new file mode 100644
index 0000000..1cb8c29
--- /dev/null
+++ b/test/lib/resemble.js
@@ -0,0 +1,535 @@
+/*
+Author: James Cryer
+Company: Huddle
+Last updated date: 21 Feb 2013
+URL: https://github.com/Huddle/Resemble.js
+*/
+
+(function(_this){
+ 'use strict';
+
+ _this['resemble'] = function( fileData ){
+
+ var data = {};
+ var images = [];
+ var updateCallbackArray = [];
+
+ var tolerance = { // between 0 and 255
+ red: 16,
+ green: 16,
+ blue: 16,
+ minBrightness: 16,
+ maxBrightness: 240
+ };
+
+ var ignoreAntialiasing = false;
+ var ignoreColors = false;
+
+ function triggerDataUpdate(){
+ var len = updateCallbackArray.length;
+ var i;
+ for(i=0;i tolerance.maxBrightness;
+ }
+
+ function getHue(r,g,b){
+
+ r = r / 255;
+ g = g / 255;
+ b = b / 255;
+ var max = Math.max(r, g, b), min = Math.min(r, g, b);
+ var h;
+ var d;
+
+ if (max == min){
+ h = 0; // achromatic
+ } else{
+ d = max - min;
+ switch(max){
+ case r: h = (g - b) / d + (g < b ? 6 : 0); break;
+ case g: h = (b - r) / d + 2; break;
+ case b: h = (r - g) / d + 4; break;
+ }
+ h /= 6;
+ }
+
+ return h;
+ }
+
+ function isAntialiased(sourcePix, data, cacheSet, verticalPos, horizontalPos, width){
+ var offset;
+ var targetPix;
+ var distance = 1;
+ var i;
+ var j;
+ var hasHighContrastSibling = 0;
+ var hasSiblingWithDifferentHue = 0;
+ var hasEquivilantSibling = 0;
+
+ addHueInfo(sourcePix);
+
+ for (i = distance*-1; i <= distance; i++){
+ for (j = distance*-1; j <= distance; j++){
+
+ if(i===0 && j===0){
+ // ignore source pixel
+ } else {
+
+ offset = ((verticalPos+j)*width + (horizontalPos+i)) * 4;
+ targetPix = getPixelInfo(data, offset, cacheSet);
+
+ if(targetPix === null){
+ continue;
+ }
+
+ addBrightnessInfo(targetPix);
+ addHueInfo(targetPix);
+
+ if( isContrasting(sourcePix, targetPix) ){
+ hasHighContrastSibling++;
+ }
+
+ if( isRGBSame(sourcePix,targetPix) ){
+ hasEquivilantSibling++;
+ }
+
+ if( Math.abs(targetPix.h - sourcePix.h) > 0.3 ){
+ hasSiblingWithDifferentHue++;
+ }
+
+ if( hasSiblingWithDifferentHue > 1 || hasHighContrastSibling > 1){
+ return true;
+ }
+ }
+ }
+ }
+
+ if(hasEquivilantSibling < 2){
+ return true;
+ }
+
+ return false;
+ }
+
+ function errorPixel(px, offset){
+ px[offset] = 255; //r
+ px[offset + 1] = 0; //g
+ px[offset + 2] = 255; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyPixel(px, offset, data){
+ px[offset] = data.r; //r
+ px[offset + 1] = data.g; //g
+ px[offset + 2] = data.b; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyGrayScalePixel(px, offset, data){
+ px[offset] = data.brightness; //r
+ px[offset + 1] = data.brightness; //g
+ px[offset + 2] = data.brightness; //b
+ px[offset + 3] = 255; //a
+ }
+
+
+ function getPixelInfo(data, offset, cacheSet){
+ var r;
+ var g;
+ var b;
+ var d;
+
+ if(typeof data[offset] !== 'undefined'){
+ r = data[offset];
+ g = data[offset+1];
+ b = data[offset+2];
+ d = {
+ r: r,
+ g: g,
+ b: b
+ };
+
+ return d;
+ } else {
+ return null;
+ }
+ }
+
+ function addBrightnessInfo(data){
+ data.brightness = getBrightness(data.r,data.g,data.b); // 'corrected' lightness
+ }
+
+ function addHueInfo(data){
+ data.h = getHue(data.r,data.g,data.b);
+ }
+
+ function analyseImages(img1, img2, width, height){
+
+ var hiddenCanvas = document.createElement('canvas');
+
+ var data1 = img1.data;
+ var data2 = img2.data;
+
+ hiddenCanvas.width = width;
+ hiddenCanvas.height = height;
+
+ var context = hiddenCanvas.getContext('2d');
+ var imgd = context.createImageData(width,height);
+ var targetPix = imgd.data;
+
+ var mismatchCount = 0;
+
+ var time = Date.now();
+
+ var skip;
+
+ if( (width > 1200 || height > 1200) && ignoreAntialiasing){
+ skip = 6;
+ }
+
+ loop(height, width, function(verticalPos, horizontalPos){
+
+ if(skip){ // only skip if the image isn't small
+ if(verticalPos % skip === 0 || horizontalPos % skip === 0){
+ return;
+ }
+ }
+
+ var offset = (verticalPos*width + horizontalPos) * 4;
+ var pixel1 = getPixelInfo(data1, offset, 1);
+ var pixel2 = getPixelInfo(data2, offset, 2);
+
+ if(pixel1 === null || pixel2 === null){
+ return;
+ }
+
+ if (ignoreColors){
+
+ addBrightnessInfo(pixel1);
+ addBrightnessInfo(pixel2);
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ return;
+ }
+
+ if( isRGBSimilar(pixel1, pixel2) ){
+ copyPixel(targetPix, offset, pixel2);
+
+ } else if( ignoreAntialiasing && (
+ addBrightnessInfo(pixel1), // jit pixel info augmentation looks a little weird, sorry.
+ addBrightnessInfo(pixel2),
+ isAntialiased(pixel1, data1, 1, verticalPos, horizontalPos, width) ||
+ isAntialiased(pixel2, data2, 2, verticalPos, horizontalPos, width)
+ )){
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+
+ });
+
+ data.misMatchPercentage = (mismatchCount / (height*width) * 100).toFixed(2);
+ data.analysisTime = Date.now() - time;
+
+ data.getImageDataUrl = function(text){
+ var barHeight = 0;
+
+ if(text){
+ barHeight = addLabel(text,context,hiddenCanvas);
+ }
+
+ context.putImageData(imgd, 0, barHeight);
+
+ return hiddenCanvas.toDataURL("image/png");
+ };
+ }
+
+ function addLabel(text, context, hiddenCanvas){
+ var textPadding = 2;
+
+ context.font = '12px sans-serif';
+
+ var textWidth = context.measureText(text).width + textPadding*2;
+ var barHeight = 22;
+
+ if(textWidth > hiddenCanvas.width){
+ hiddenCanvas.width = textWidth;
+ }
+
+ hiddenCanvas.height += barHeight;
+
+ context.fillStyle = "#666";
+ context.fillRect(0,0,hiddenCanvas.width,barHeight -4);
+ context.fillStyle = "#fff";
+ context.fillRect(0,barHeight -4,hiddenCanvas.width, 4);
+
+ context.fillStyle = "#fff";
+ context.textBaseline = "top";
+ context.font = '12px sans-serif';
+ context.fillText(text, textPadding, 1);
+
+ return barHeight;
+ }
+
+ function normalise(img, w, h){
+ var c;
+ var context;
+
+ if(img.height < h || img.width < w){
+ c = document.createElement('canvas');
+ c.width = w;
+ c.height = h;
+ context = c.getContext('2d');
+ context.putImageData(img, 0, 0);
+ return context.getImageData(0, 0, w, h);
+ }
+
+ return img;
+ }
+
+ function compare(one, two){
+
+ function onceWeHaveBoth(){
+ var width;
+ var height;
+ if(images.length === 2){
+ width = images[0].width > images[1].width ? images[0].width : images[1].width;
+ height = images[0].height > images[1].height ? images[0].height : images[1].height;
+
+ if( (images[0].width === images[1].width) && (images[0].height === images[1].height) ){
+ data.isSameDimensions = true;
+ } else {
+ data.isSameDimensions = false;
+ }
+
+ analyseImages( normalise(images[0],width, height), normalise(images[1],width, height), width, height);
+
+ triggerDataUpdate();
+ }
+ }
+
+ images = [];
+ loadImageData(one, onceWeHaveBoth);
+ loadImageData(two, onceWeHaveBoth);
+ }
+
+ function getCompareApi(param){
+
+ var secondFileData,
+ hasMethod = typeof param === 'function';
+
+ if( !hasMethod ){
+ // assume it's file data
+ secondFileData = param;
+ }
+
+ var self = {
+ ignoreNothing: function(){
+
+ tolerance.red = 16;
+ tolerance.green = 16;
+ tolerance.blue = 16;
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreAntialiasing: function(){
+
+ tolerance.red = 32;
+ tolerance.green = 32;
+ tolerance.blue = 32;
+ tolerance.minBrightness = 64;
+ tolerance.maxBrightness = 96;
+
+ ignoreAntialiasing = true;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreColors: function(){
+
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = true;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ onComplete: function( callback ){
+
+ updateCallbackArray.push(callback);
+
+ var wrapper = function(){
+ compare(fileData, secondFileData);
+ };
+
+ wrapper();
+
+ return getCompareApi(wrapper);
+ }
+ };
+
+ return self;
+ }
+
+ return {
+ onComplete: function( callback ){
+ updateCallbackArray.push(callback);
+ loadImageData(fileData, function(imageData, width, height){
+ parseImage(imageData.data, width, height);
+ });
+ },
+ compareTo: function(secondFileData){
+ return getCompareApi(secondFileData);
+ }
+ };
+
+ };
+}(this));
\ No newline at end of file
diff --git a/test/testsuite.js b/test/testsuite.js
deleted file mode 100644
index b486acb..0000000
--- a/test/testsuite.js
+++ /dev/null
@@ -1,36 +0,0 @@
-requirejs.config({
- baseUrl: '/test/unit/'
-});
-
-define(function(require) {
- var testModules = [
- 'Pixi',
- 'Point',
- 'Rectangle',
- 'DisplayObject',
- 'DisplayObjectContainer',
- 'Sprite',
- 'MovieClip',
- 'InteractionManager',
- 'Stage',
- 'utils/Utils',
- 'utils/EventTarget',
- 'utils/Matrix',
- 'utils/Detector',
- 'renderers/WebGLShaders',
- 'renderers/WebGLRenderer',
- 'renderers/WebGLBatch',
- 'renderers/CanvasRenderer',
- 'extras/Strip',
- 'extras/Rope',
- 'textures/BaseTexture',
- 'textures/Texture',
- 'loaders/SpriteSheetLoader',
- 'loaders/AssetLoader'
- ];
-
- // Resolve all testModules and then start the Test Runner.
- require(testModules, function() {
- QUnit.start();
- });
-});
\ No newline at end of file
diff --git a/test/textures/SpriteSheet-Aliens.png b/test/textures/SpriteSheet-Aliens.png
new file mode 100644
index 0000000..210acb1
--- /dev/null
+++ b/test/textures/SpriteSheet-Aliens.png
Binary files differ
diff --git a/test/textures/SpriteSheet-Explosion.png b/test/textures/SpriteSheet-Explosion.png
new file mode 100755
index 0000000..79e1a69
--- /dev/null
+++ b/test/textures/SpriteSheet-Explosion.png
Binary files differ
diff --git a/test/textures/bunny.png b/test/textures/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/textures/bunny.png
Binary files differ
diff --git a/test/unit/DisplayObject.js b/test/unit/DisplayObject.js
deleted file mode 100644
index 5e7e72f..0000000
--- a/test/unit/DisplayObject.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObject');
-});
diff --git a/test/unit/DisplayObjectContainer.js b/test/unit/DisplayObjectContainer.js
deleted file mode 100644
index b323959..0000000
--- a/test/unit/DisplayObjectContainer.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObjectContainer');
-});
diff --git a/test/unit/InteractionManager.js b/test/unit/InteractionManager.js
deleted file mode 100644
index e751f52..0000000
--- a/test/unit/InteractionManager.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('InteractionManager');
-});
diff --git a/test/unit/MovieClip.js b/test/unit/MovieClip.js
deleted file mode 100644
index 37d9446..0000000
--- a/test/unit/MovieClip.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('MovieClip');
-});
diff --git a/test/unit/Pixi.js b/test/unit/Pixi.js
deleted file mode 100644
index 36eee73..0000000
--- a/test/unit/Pixi.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Pixi');
-});
diff --git a/test/unit/Point.js b/test/unit/Point.js
deleted file mode 100644
index 983ff6e..0000000
--- a/test/unit/Point.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Point');
-});
diff --git a/test/unit/Rectangle.js b/test/unit/Rectangle.js
deleted file mode 100644
index 3b439ba..0000000
--- a/test/unit/Rectangle.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Rectangle');
-});
diff --git a/test/unit/Sprite.js b/test/unit/Sprite.js
deleted file mode 100644
index ed4f596..0000000
--- a/test/unit/Sprite.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Sprite');
-});
diff --git a/test/unit/Stage.js b/test/unit/Stage.js
deleted file mode 100644
index 2d70291..0000000
--- a/test/unit/Stage.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Stage');
-});
diff --git a/test/unit/extras/Rope.js b/test/unit/extras/Rope.js
deleted file mode 100644
index 5606f14..0000000
--- a/test/unit/extras/Rope.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Rope');
-});
diff --git a/test/unit/extras/Strip.js b/test/unit/extras/Strip.js
deleted file mode 100644
index 0134d3a..0000000
--- a/test/unit/extras/Strip.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Strip');
-});
diff --git a/test/unit/loaders/AssetLoader.js b/test/unit/loaders/AssetLoader.js
deleted file mode 100644
index 13b8443..0000000
--- a/test/unit/loaders/AssetLoader.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('AssetLoader');
-});
diff --git a/test/unit/loaders/SpriteSheetLoader.js b/test/unit/loaders/SpriteSheetLoader.js
deleted file mode 100644
index 8bf0cb2..0000000
--- a/test/unit/loaders/SpriteSheetLoader.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('SpriteSheetLoader');
-});
diff --git a/test/unit/pixi/InteractionManager.js b/test/unit/pixi/InteractionManager.js
new file mode 100644
index 0000000..ed3001f
--- /dev/null
+++ b/test/unit/pixi/InteractionManager.js
@@ -0,0 +1,10 @@
+describe('pixi/InteractionManager', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var InteractionManager = PIXI.InteractionManager;
+
+ it('Module exists', function () {
+ expect(InteractionManager).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/Pixi.js b/test/unit/pixi/Pixi.js
new file mode 100644
index 0000000..27debc1
--- /dev/null
+++ b/test/unit/pixi/Pixi.js
@@ -0,0 +1,9 @@
+describe('pixi/Pixi', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+
+ it('Module exists', function () {
+ expect(global).to.have.property('PIXI').and.to.be.an('object');
+ });
+});
diff --git a/test/unit/pixi/core/Circle.js b/test/unit/pixi/core/Circle.js
new file mode 100644
index 0000000..93a4456
--- /dev/null
+++ b/test/unit/pixi/core/Circle.js
@@ -0,0 +1,22 @@
+describe('pixi/core/Circle', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Circle = PIXI.Circle;
+
+ it('Module exists', function () {
+ expect(Circle).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Circle();
+
+ expect(obj).to.be.an.instanceof(Circle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', 0);
+ expect(obj).to.have.property('y', 0);
+ expect(obj).to.have.property('radius', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Ellipse.js b/test/unit/pixi/core/Ellipse.js
new file mode 100644
index 0000000..026b56f
--- /dev/null
+++ b/test/unit/pixi/core/Ellipse.js
@@ -0,0 +1,24 @@
+describe('pixi/core/Ellipse', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Ellipse = PIXI.Ellipse;
+
+ it('Module exists', function () {
+ expect(Ellipse).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Ellipse();
+
+ expect(obj).to.be.an.instanceof(Ellipse);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+ expect(obj).to.respondTo('getBounds');
+
+ expect(obj).to.have.property('x', 0);
+ expect(obj).to.have.property('y', 0);
+ expect(obj).to.have.property('width', 0);
+ expect(obj).to.have.property('height', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Matrix.js b/test/unit/pixi/core/Matrix.js
new file mode 100644
index 0000000..b48989e
--- /dev/null
+++ b/test/unit/pixi/core/Matrix.js
@@ -0,0 +1,30 @@
+describe('pixi/core/Matrix', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var mat3 = PIXI.mat3;
+ var mat4 = PIXI.mat4;
+ var Matrix = PIXI.Matrix;
+
+ it('Ensure determineMatrixArrayType works', function () {
+ expect(Matrix).to.be.a('function');
+ });
+
+ it('mat3 exists', function () {
+ expect(mat3).to.be.an('object');
+ });
+
+ it('Confirm new mat3 matrix', function () {
+ var matrix = new mat3.create();
+ pixi_core_Matrix_confirmNewMat3(matrix);
+ });
+
+ it('mat3 exists', function () {
+ expect(mat4).to.be.an('object');
+ });
+
+ it('Confirm new mat4 matrix', function () {
+ var matrix = new mat4.create();
+ pixi_core_Matrix_confirmNewMat4(matrix);
+ });
+});
diff --git a/test/unit/pixi/core/Point.js b/test/unit/pixi/core/Point.js
new file mode 100644
index 0000000..c4d5163
--- /dev/null
+++ b/test/unit/pixi/core/Point.js
@@ -0,0 +1,15 @@
+describe('pixi/core/Point', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Point = PIXI.Point;
+
+ it('Module exists', function () {
+ expect(Point).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Point();
+ pixi_core_Point_confirm(obj, 0, 0);
+ });
+});
diff --git a/test/unit/pixi/core/Polygon.js b/test/unit/pixi/core/Polygon.js
new file mode 100644
index 0000000..dc8c918
--- /dev/null
+++ b/test/unit/pixi/core/Polygon.js
@@ -0,0 +1,20 @@
+describe('pixi/core/Polygon', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Polygon = PIXI.Polygon;
+
+ it('Module exists', function () {
+ expect(Polygon).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Polygon();
+
+ expect(obj).to.be.an.instanceof(Polygon);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.deep.property('points.length', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Rectangle.js b/test/unit/pixi/core/Rectangle.js
new file mode 100644
index 0000000..d43316e
--- /dev/null
+++ b/test/unit/pixi/core/Rectangle.js
@@ -0,0 +1,15 @@
+describe('pixi/core/Rectangle', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Rectangle = PIXI.Rectangle;
+
+ it('Module exists', function () {
+ expect(Rectangle).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var rect = new Rectangle();
+ pixi_core_Rectangle_confirm(rect, 0, 0, 0, 0);
+ });
+});
diff --git a/test/unit/pixi/display/DisplayObject.js b/test/unit/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..40c6fbc
--- /dev/null
+++ b/test/unit/pixi/display/DisplayObject.js
@@ -0,0 +1,21 @@
+describe('pixi/display/DisplayObject', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var DisplayObject = PIXI.DisplayObject;
+
+ it('Module exists', function () {
+ expect(DisplayObject).to.be.a('function');
+ expect(PIXI).to.have.property('visibleCount', 0);
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new DisplayObject();
+
+ pixi_display_DisplayObject_confirmNew(obj);
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', false);
+ expect(obj).to.have.property('stage', null);
+ });
+});
diff --git a/test/unit/pixi/display/DisplayObjectContainer.js b/test/unit/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..ce7f02f
--- /dev/null
+++ b/test/unit/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,20 @@
+describe('pixi/display/DisplayObjectContainer', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var DisplayObjectContainer = PIXI.DisplayObjectContainer;
+
+ it('Module exists', function () {
+ expect(DisplayObjectContainer).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new DisplayObjectContainer();
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', false);
+ expect(obj).to.have.property('stage', null);
+ });
+});
diff --git a/test/unit/pixi/display/MovieClip.js b/test/unit/pixi/display/MovieClip.js
new file mode 100644
index 0000000..f3c6c6a
--- /dev/null
+++ b/test/unit/pixi/display/MovieClip.js
@@ -0,0 +1,33 @@
+describe('pixi/display/MovieClip', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var MovieClip = PIXI.MovieClip;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(MovieClip).to.be.a('function');
+ });
+
+ it('Confirm new instance', function (done) {
+ var texture = Texture.fromImage('/base/test/textures/SpriteSheet-Explosion.png');
+ var obj = new MovieClip([texture]);
+
+ pixi_display_Sprite_confirmNew(obj, done);
+
+ expect(obj).to.be.an.instanceof(MovieClip);
+ expect(obj).to.respondTo('stop');
+ expect(obj).to.respondTo('play');
+ expect(obj).to.respondTo('gotoAndStop');
+ expect(obj).to.respondTo('gotoAndPlay');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('textures.length', 1);
+ expect(obj).to.have.deep.property('textures[0]', texture);
+ expect(obj).to.have.property('animationSpeed', 1);
+ expect(obj).to.have.property('loop', true);
+ expect(obj).to.have.property('onComplete', null);
+ expect(obj).to.have.property('currentFrame', 0);
+ expect(obj).to.have.property('playing', false);
+ });
+});
diff --git a/test/unit/pixi/display/Sprite.js b/test/unit/pixi/display/Sprite.js
new file mode 100644
index 0000000..54e914f
--- /dev/null
+++ b/test/unit/pixi/display/Sprite.js
@@ -0,0 +1,25 @@
+describe('pixi/display/Sprite', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Sprite = PIXI.Sprite;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(Sprite).to.be.a('function');
+ expect(PIXI).to.have.deep.property('blendModes.NORMAL', 0);
+ expect(PIXI).to.have.deep.property('blendModes.SCREEN', 1);
+ });
+
+ it('Members exist', function () {
+ expect(Sprite).itself.to.respondTo('fromImage');
+ expect(Sprite).itself.to.respondTo('fromFrame');
+ });
+
+ it('Confirm new instance', function (done) {
+ var texture = Texture.fromImage('/base/test/textures/SpriteSheet-Aliens.png');
+ var obj = new Sprite(texture);
+
+ pixi_display_Sprite_confirmNew(obj, done);
+ });
+});
diff --git a/test/unit/pixi/display/Stage.js b/test/unit/pixi/display/Stage.js
new file mode 100644
index 0000000..3cc2a4d
--- /dev/null
+++ b/test/unit/pixi/display/Stage.js
@@ -0,0 +1,49 @@
+describe('pixi/display/Stage', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Stage = PIXI.Stage;
+ var InteractionManager = PIXI.InteractionManager;
+ var Rectangle = PIXI.Rectangle;
+
+ it('Module exists', function () {
+ expect(Stage).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Stage(null, true);
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(Stage);
+ expect(obj).to.respondTo('updateTransform');
+ expect(obj).to.respondTo('setBackgroundColor');
+ expect(obj).to.respondTo('getMousePosition');
+
+ // FIXME: duplicate member in DisplayObject
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ // FIXME: convert arg to bool in constructor
+ expect(obj).to.have.property('interactive', true);
+
+ expect(obj).to.have.property('interactionManager')
+ .and.to.be.an.instanceof(InteractionManager)
+ .and.to.have.property('stage', obj);
+
+ expect(obj).to.have.property('dirty', true);
+
+ expect(obj).to.have.property('stage', obj);
+
+ expect(obj).to.have.property('hitArea')
+ .and.to.be.an.instanceof(Rectangle);
+ pixi_core_Rectangle_confirm(obj.hitArea, 0, 0, 100000, 100000);
+
+ expect(obj).to.have.property('backgroundColor', 0x000000);
+ expect(obj).to.have.deep.property('backgroundColorSplit.length', 3);
+ expect(obj).to.have.deep.property('backgroundColorSplit[0]', 0);
+ expect(obj).to.have.deep.property('backgroundColorSplit[1]', 0);
+ expect(obj).to.have.deep.property('backgroundColorSplit[2]', 0);
+ expect(obj).to.have.property('backgroundColorString', '#000000');
+
+ expect(obj).to.have.property('worldVisible', true);
+ });
+});
diff --git a/test/unit/pixi/extras/CustomRenderable.js b/test/unit/pixi/extras/CustomRenderable.js
new file mode 100644
index 0000000..8d83cf0
--- /dev/null
+++ b/test/unit/pixi/extras/CustomRenderable.js
@@ -0,0 +1,21 @@
+describe('pixi/extras/CustomRenderable', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var CustomRenderable = PIXI.CustomRenderable;
+
+ it('Module exists', function () {
+ expect(CustomRenderable).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new CustomRenderable();
+
+ pixi_display_DisplayObject_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(CustomRenderable);
+ expect(obj).to.respondTo('renderCanvas');
+ expect(obj).to.respondTo('initWebGL');
+ expect(obj).to.respondTo('renderWebGL');
+ });
+});
diff --git a/test/unit/pixi/extras/Rope.js b/test/unit/pixi/extras/Rope.js
new file mode 100644
index 0000000..6ddaf83
--- /dev/null
+++ b/test/unit/pixi/extras/Rope.js
@@ -0,0 +1,26 @@
+describe('pixi/extras/Rope', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Rope = PIXI.Rope;
+ var Texture = PIXI.Texture;
+ var Point = PIXI.Point;
+
+ it('Module exists', function () {
+ expect(Rope).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var texture = Texture.fromImage('/base/test/textures/bunny.png');
+ var obj = new Rope(texture, [new Point(), new Point(5, 10), new Point(10, 20)]);
+
+ pixi_extras_Strip_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(Rope);
+ expect(obj).to.respondTo('refresh');
+ expect(obj).to.respondTo('updateTransform');
+ expect(obj).to.respondTo('setTexture');
+
+ // TODO: Test properties
+ });
+});
diff --git a/test/unit/pixi/extras/Spine.js b/test/unit/pixi/extras/Spine.js
new file mode 100644
index 0000000..0708bc0
--- /dev/null
+++ b/test/unit/pixi/extras/Spine.js
@@ -0,0 +1,10 @@
+describe('pixi/extras/Spine', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Spine = PIXI.Spine;
+
+ it('Module exists', function () {
+ expect(Spine).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/extras/Strip.js b/test/unit/pixi/extras/Strip.js
new file mode 100644
index 0000000..8e564e1
--- /dev/null
+++ b/test/unit/pixi/extras/Strip.js
@@ -0,0 +1,18 @@
+describe('pixi/extras/Strip', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Strip = PIXI.Strip;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(Strip).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var texture = Texture.fromImage('/base/test/textures/bunny.png');
+ var obj = new Strip(texture, 20, 10000);
+
+ pixi_extras_Strip_confirmNew(obj);
+ });
+});
diff --git a/test/unit/pixi/extras/TilingSprite.js b/test/unit/pixi/extras/TilingSprite.js
new file mode 100644
index 0000000..56aea14
--- /dev/null
+++ b/test/unit/pixi/extras/TilingSprite.js
@@ -0,0 +1,24 @@
+describe('pixi/extras/TilingSprite', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var TilingSprite = PIXI.TilingSprite;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(TilingSprite).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var texture = Texture.fromImage('/base/test/textures/bunny.png');
+ var obj = new TilingSprite(texture, 6000, 12000);
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(TilingSprite);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ // TODO: Test properties
+ });
+});
diff --git a/test/unit/pixi/filters/FilterBlock.js b/test/unit/pixi/filters/FilterBlock.js
new file mode 100644
index 0000000..870cec0
--- /dev/null
+++ b/test/unit/pixi/filters/FilterBlock.js
@@ -0,0 +1,10 @@
+describe('pixi/filters/FilterBlock', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var FilterBlock = PIXI.FilterBlock;
+
+ it('Module exists', function () {
+ expect(FilterBlock).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/filters/MaskFilter.js b/test/unit/pixi/filters/MaskFilter.js
new file mode 100644
index 0000000..32d6a45
--- /dev/null
+++ b/test/unit/pixi/filters/MaskFilter.js
@@ -0,0 +1,10 @@
+describe('pixi/filters/MaskFilter', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ // var MaskFilter = PIXI.MaskFilter;
+
+ // it('Module exists', function () {
+ // expect(MaskFilter).to.be.a('function');
+ // });
+});
diff --git a/test/unit/pixi/loaders/AssetLoader.js b/test/unit/pixi/loaders/AssetLoader.js
new file mode 100644
index 0000000..a0aa0b5
--- /dev/null
+++ b/test/unit/pixi/loaders/AssetLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/AssetLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var AssetLoader = PIXI.AssetLoader;
+
+ it('Module exists', function () {
+ expect(AssetLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/BitmapFontLoader.js b/test/unit/pixi/loaders/BitmapFontLoader.js
new file mode 100644
index 0000000..6253c42
--- /dev/null
+++ b/test/unit/pixi/loaders/BitmapFontLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/BitmapFontLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var BitmapFontLoader = PIXI.BitmapFontLoader;
+
+ it('Module exists', function () {
+ expect(PIXI.BitmapFontLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/ImageLoader.js b/test/unit/pixi/loaders/ImageLoader.js
new file mode 100644
index 0000000..8b1f556
--- /dev/null
+++ b/test/unit/pixi/loaders/ImageLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/ImageLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var ImageLoader = PIXI.ImageLoader;
+
+ it('Module exists', function () {
+ expect(ImageLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/JsonLoader.js b/test/unit/pixi/loaders/JsonLoader.js
new file mode 100644
index 0000000..c577e83
--- /dev/null
+++ b/test/unit/pixi/loaders/JsonLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/JsonLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var JsonLoader = PIXI.JsonLoader;
+
+ it('Module exists', function () {
+ expect(JsonLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/SpineLoader.js b/test/unit/pixi/loaders/SpineLoader.js
new file mode 100644
index 0000000..fdcc0b8
--- /dev/null
+++ b/test/unit/pixi/loaders/SpineLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/SpineLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var SpineLoader = PIXI.SpineLoader;
+
+ it('Module exists', function () {
+ expect(SpineLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/SpriteSheetLoader.js b/test/unit/pixi/loaders/SpriteSheetLoader.js
new file mode 100644
index 0000000..57beb27
--- /dev/null
+++ b/test/unit/pixi/loaders/SpriteSheetLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/SpriteSheetLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var SpriteSheetLoader = PIXI.SpriteSheetLoader;
+
+ it('Module exists', function () {
+ expect(SpriteSheetLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/primitives/Graphics.js b/test/unit/pixi/primitives/Graphics.js
new file mode 100644
index 0000000..b8b3e5c
--- /dev/null
+++ b/test/unit/pixi/primitives/Graphics.js
@@ -0,0 +1,40 @@
+describe('pixi/primitives/Graphics', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Graphics = PIXI.Graphics;
+
+ it('Module exists', function () {
+ expect(Graphics).to.be.a('function');
+
+ expect(Graphics).itself.to.have.property('POLY', 0);
+ expect(Graphics).itself.to.have.property('RECT', 1);
+ expect(Graphics).itself.to.have.property('CIRC', 2);
+ expect(Graphics).itself.to.have.property('ELIP', 3);
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Graphics();
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(Graphics);
+ expect(obj).to.respondTo('lineStyle');
+ expect(obj).to.respondTo('lineStyle');
+ expect(obj).to.respondTo('moveTo');
+ expect(obj).to.respondTo('lineTo');
+ expect(obj).to.respondTo('beginFill');
+ expect(obj).to.respondTo('endFill');
+ expect(obj).to.respondTo('drawRect');
+ expect(obj).to.respondTo('drawCircle');
+ expect(obj).to.respondTo('drawElipse');
+ expect(obj).to.respondTo('clear');
+
+ expect(obj).to.have.property('renderable', true);
+ expect(obj).to.have.property('fillAlpha', 1);
+ expect(obj).to.have.property('lineWidth', 0);
+ expect(obj).to.have.property('lineColor', 'black');
+ expect(obj).to.have.deep.property('graphicsData.length', 0);
+ expect(obj).to.have.deep.property('currentPath.points.length', 0);
+ });
+});
diff --git a/test/unit/pixi/renderers/canvas/CanvasGraphics.js b/test/unit/pixi/renderers/canvas/CanvasGraphics.js
new file mode 100644
index 0000000..8f44472
--- /dev/null
+++ b/test/unit/pixi/renderers/canvas/CanvasGraphics.js
@@ -0,0 +1,15 @@
+describe('renders/canvas/CanvasGraphics', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var CanvasGraphics = PIXI.CanvasGraphics;
+
+ it('Module exists', function () {
+ expect(CanvasGraphics).to.be.a('function');
+ });
+
+ it('Members exist', function () {
+ expect(CanvasGraphics).itself.to.respondTo('renderGraphics');
+ expect(CanvasGraphics).itself.to.respondTo('renderGraphicsMask');
+ });
+});
diff --git a/test/unit/pixi/renderers/canvas/CanvasRenderer.js b/test/unit/pixi/renderers/canvas/CanvasRenderer.js
new file mode 100644
index 0000000..df3a12f
--- /dev/null
+++ b/test/unit/pixi/renderers/canvas/CanvasRenderer.js
@@ -0,0 +1,10 @@
+describe('renderers/canvas/CanvasRenderer', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var CanvasRenderer = PIXI.CanvasRenderer;
+
+ it('Module exists', function () {
+ expect(CanvasRenderer).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/renderers/webgl/WebGLBatch.js b/test/unit/pixi/renderers/webgl/WebGLBatch.js
new file mode 100644
index 0000000..75efd56
--- /dev/null
+++ b/test/unit/pixi/renderers/webgl/WebGLBatch.js
@@ -0,0 +1,10 @@
+describe('renderers/webgl/WebGLBatch', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var WebGLBatch = PIXI.WebGLBatch;
+
+ it('Module exists', function () {
+ expect(WebGLBatch).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/renderers/webgl/WebGLGraphics.js b/test/unit/pixi/renderers/webgl/WebGLGraphics.js
new file mode 100644
index 0000000..41bf941
--- /dev/null
+++ b/test/unit/pixi/renderers/webgl/WebGLGraphics.js
@@ -0,0 +1,19 @@
+describe('renderers/wegbl/WebGLGraphics', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var WebGLGraphics = PIXI.WebGLGraphics;
+
+ it('Module exists', function () {
+ expect(WebGLGraphics).to.be.a('function');
+ });
+
+ it('Members exist', function () {
+ expect(WebGLGraphics).itself.to.respondTo('renderGraphics');
+ expect(WebGLGraphics).itself.to.respondTo('updateGraphics');
+ expect(WebGLGraphics).itself.to.respondTo('buildRectangle');
+ expect(WebGLGraphics).itself.to.respondTo('buildCircle');
+ expect(WebGLGraphics).itself.to.respondTo('buildLine');
+ expect(WebGLGraphics).itself.to.respondTo('buildPoly');
+ });
+});
diff --git a/test/unit/pixi/renderers/webgl/WebGLRenderGroup.js b/test/unit/pixi/renderers/webgl/WebGLRenderGroup.js
new file mode 100644
index 0000000..f4ee366
--- /dev/null
+++ b/test/unit/pixi/renderers/webgl/WebGLRenderGroup.js
@@ -0,0 +1,10 @@
+describe('renderers/webgl/WebGLRenderGroup', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var WebGLRenderGroup = PIXI.WebGLRenderGroup;
+
+ it('Module exists', function () {
+ expect(WebGLRenderGroup).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/renderers/webgl/WebGLRenderer.js b/test/unit/pixi/renderers/webgl/WebGLRenderer.js
new file mode 100644
index 0000000..86533eb
--- /dev/null
+++ b/test/unit/pixi/renderers/webgl/WebGLRenderer.js
@@ -0,0 +1,10 @@
+describe('renderers/webgl/WebGLRenderer', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var WebGLRenderer = PIXI.WebGLRenderer;
+
+ it('Module exists', function () {
+ expect(WebGLRenderer).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/renderers/webgl/WebGLShaders.js b/test/unit/pixi/renderers/webgl/WebGLShaders.js
new file mode 100644
index 0000000..2872de8
--- /dev/null
+++ b/test/unit/pixi/renderers/webgl/WebGLShaders.js
@@ -0,0 +1,13 @@
+describe('renderers/webgl/WebGLShaders', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+
+ it('Module members exist', function () {
+ expect(PIXI).to.respondTo('initPrimitiveShader');
+ expect(PIXI).to.respondTo('initDefaultShader');
+ expect(PIXI).to.respondTo('initDefaultStripShader');
+ expect(PIXI).to.respondTo('activateDefaultShader');
+ expect(PIXI).to.respondTo('activatePrimitiveShader');
+ });
+});
diff --git a/test/unit/pixi/text/BitmapText.js b/test/unit/pixi/text/BitmapText.js
new file mode 100644
index 0000000..9388e3d
--- /dev/null
+++ b/test/unit/pixi/text/BitmapText.js
@@ -0,0 +1,10 @@
+describe('pixi/text/BitmapText', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var BitmapText = PIXI.BitmapText;
+
+ it('Module exists', function () {
+ expect(BitmapText).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/text/Text.js b/test/unit/pixi/text/Text.js
new file mode 100644
index 0000000..9bc9ac5
--- /dev/null
+++ b/test/unit/pixi/text/Text.js
@@ -0,0 +1,10 @@
+describe('pixi/text/Text', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Text = PIXI.Text;
+
+ it('Module exists', function () {
+ expect(Text).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/textures/BaseTexture.js b/test/unit/pixi/textures/BaseTexture.js
new file mode 100644
index 0000000..e34b64c
--- /dev/null
+++ b/test/unit/pixi/textures/BaseTexture.js
@@ -0,0 +1,13 @@
+describe('pixi/textures/BaseTexture', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var BaseTexture = PIXI.BaseTexture;
+
+ it('Module exists', function () {
+ expect(BaseTexture).to.be.a('function');
+ expect(PIXI).to.have.property('BaseTextureCache').and.to.be.an('object');
+ expect(PIXI).to.have.deep.property('texturesToUpdate.length');
+ expect(PIXI).to.have.deep.property('texturesToDestroy.length', 0);
+ });
+});
diff --git a/test/unit/pixi/textures/RenderTexture.js b/test/unit/pixi/textures/RenderTexture.js
new file mode 100644
index 0000000..4a69b44
--- /dev/null
+++ b/test/unit/pixi/textures/RenderTexture.js
@@ -0,0 +1,10 @@
+describe('pixi/textures/RenderTexture', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var RenderTexture = PIXI.RenderTexture;
+
+ it('Module exists', function () {
+ expect(RenderTexture).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/textures/Texture.js b/test/unit/pixi/textures/Texture.js
new file mode 100644
index 0000000..adb2875
--- /dev/null
+++ b/test/unit/pixi/textures/Texture.js
@@ -0,0 +1,26 @@
+describe('pixi/textures/Texture', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(Texture).to.be.a('function');
+ expect(PIXI).to.have.property('TextureCache').and.to.be.an('object');
+ });
+
+ it('Members exist', function () {
+ expect(Texture).itself.to.respondTo('fromImage');
+ expect(Texture).itself.to.respondTo('fromFrame');
+ expect(Texture).itself.to.respondTo('fromCanvas');
+ expect(Texture).itself.to.respondTo('addTextureToCache');
+ expect(Texture).itself.to.respondTo('removeTextureFromCache');
+
+ expect(Texture).itself.to.have.deep.property('frameUpdates.length', 0);
+ });
+
+ it('Confirm new instance', function (done) {
+ var texture = Texture.fromImage('/base/test/textures/bunny.png');
+ pixi_textures_Texture_confirmNew(texture, done);
+ });
+});
diff --git a/test/unit/pixi/utils/Detector.js b/test/unit/pixi/utils/Detector.js
new file mode 100644
index 0000000..4cf6008
--- /dev/null
+++ b/test/unit/pixi/utils/Detector.js
@@ -0,0 +1,10 @@
+describe('pixi/utils/Detector', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var autoDetectRenderer = PIXI.autoDetectRenderer;
+
+ it('Module exists', function () {
+ expect(autoDetectRenderer).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/utils/EventTarget.js b/test/unit/pixi/utils/EventTarget.js
new file mode 100644
index 0000000..dc4ebd9
--- /dev/null
+++ b/test/unit/pixi/utils/EventTarget.js
@@ -0,0 +1,96 @@
+describe('pixi/utils/EventTarget', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var EventTarget = PIXI.EventTarget;
+
+ it('Module exists', function () {
+ expect(EventTarget).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = {}; EventTarget.call(obj);
+ pixi_utils_EventTarget_like(obj);
+ });
+
+ it('addEventListener and dispatchEvent works', function (done) {
+ var myData = {},
+ obj = {}; EventTarget.call(obj);
+
+ obj.addEventListener('myevent', function (event) {
+ expect(event).to.be.an('object');
+ expect(event).to.have.property('type', 'myevent');
+ expect(event).to.have.property('data', myData);
+ done();
+ });
+
+ obj.dispatchEvent({type: 'myevent', data: myData});
+ });
+
+ it('removeEventListener works', function (done) {
+ var obj = {}; EventTarget.call(obj);
+
+ function onMyEvent() {
+ done(new Error('addEventListener should not have been called'));
+ }
+
+ obj.addEventListener('myevent', onMyEvent);
+ obj.removeEventListener('myevent', onMyEvent);
+ obj.dispatchEvent({type: 'myevent'});
+ done();
+ });
+
+ it('multiple dispatches', function () {
+ var called = 0,
+ obj = {}; EventTarget.call(obj);
+
+ function onMyEvent() {
+ called++;
+ }
+
+ obj.addEventListener('myevent', onMyEvent);
+ obj.dispatchEvent({type: 'myevent'});
+ obj.dispatchEvent({type: 'myevent'});
+ obj.dispatchEvent({type: 'myevent'});
+ obj.dispatchEvent({type: 'myevent'});
+ expect(called).to.equal(4);
+ });
+
+ it('multiple events', function () {
+ var called = 0,
+ obj = {}; EventTarget.call(obj);
+
+ function onMyEvent() {
+ called++;
+ }
+
+ obj.addEventListener('myevent1', onMyEvent);
+ obj.addEventListener('myevent2', onMyEvent);
+ obj.addEventListener('myevent3', onMyEvent);
+ obj.dispatchEvent({type: 'myevent1'});
+ obj.dispatchEvent({type: 'myevent2'});
+ obj.dispatchEvent({type: 'myevent3'});
+ expect(called).to.equal(3);
+ });
+
+ it('multiple events one removed', function () {
+ var called = 0,
+ obj = {}; EventTarget.call(obj);
+
+ function onMyEvent() {
+ called++;
+ }
+
+ obj.addEventListener('myevent1', onMyEvent);
+ obj.addEventListener('myevent2', onMyEvent);
+ obj.addEventListener('myevent3', onMyEvent);
+ obj.dispatchEvent({type: 'myevent1'});
+ obj.dispatchEvent({type: 'myevent2'});
+ obj.dispatchEvent({type: 'myevent3'});
+ obj.removeEventListener('myevent2', onMyEvent);
+ obj.dispatchEvent({type: 'myevent1'});
+ obj.dispatchEvent({type: 'myevent2'});
+ obj.dispatchEvent({type: 'myevent3'});
+ expect(called).to.equal(5);
+ });
+});
diff --git a/test/unit/pixi/utils/Polyk.js b/test/unit/pixi/utils/Polyk.js
new file mode 100644
index 0000000..dfc7128
--- /dev/null
+++ b/test/unit/pixi/utils/Polyk.js
@@ -0,0 +1,14 @@
+describe('pixi/utils/Polyk', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var PolyK = PIXI.PolyK;
+
+ it('Module exists', function () {
+ expect(PolyK).to.be.an('object');
+ });
+
+ it('Members exist', function () {
+ expect(PolyK).to.respondTo('Triangulate');
+ });
+});
diff --git a/.gitignore b/.gitignore
index 12e1b62..0b88317 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
node_modules
.DS_Store
-.project
\ No newline at end of file
+.project
+*.log
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..63e4d7c
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,8 @@
+language: node_js
+node_js:
+ - 0.10
+
+before_script:
+ - npm install -g grunt-cli
+ - export DISPLAY=:99.0
+ - sh -e /etc/init.d/xvfb start
diff --git a/Gruntfile.js b/Gruntfile.js
index b083b49..103938c 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -1,10 +1,12 @@
+'use strict';
+
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-connect');
- grunt.loadNpmTasks('grunt-contrib-qunit');
grunt.loadNpmTasks('grunt-contrib-yuidoc');
+ grunt.loadTasks('tasks');
var root = 'src/pixi/',
debug = 'bin/pixi.dev.js',
@@ -79,7 +81,7 @@
},
files: {
srcBlob: '<%= dirs.src %>/**/*.js',
- testBlob: '<%= dirs.test %>/unit/**/*.js',
+ testBlob: '<%= dirs.test %>/{functional,lib/pixi,unit}/**/*.js',
build: '<%= dirs.build %>/pixi.dev.js',
buildMin: '<%= dirs.build %>/pixi.js'
},
@@ -94,7 +96,12 @@
},
jshint: {
beforeconcat: srcFiles,
- test: ['<%= files.testBlob %>'],
+ test: {
+ src: ['<%= files.testBlob %>'],
+ options: {
+ expr: true
+ }
+ },
options: {
asi: true,
smarttabs: true
@@ -128,12 +135,6 @@
]
},
connect: {
- qunit: {
- options: {
- port: grunt.option('port-test') || 9002,
- base: './'
- }
- },
test: {
options: {
port: grunt.option('port-test') || 9002,
@@ -142,13 +143,6 @@
}
}
},
- qunit: {
- all: {
- options: {
- urls: ['http://localhost:' + (grunt.option('port-test') || 9002) + '/test/index.html']
- }
- }
- },
yuidoc: {
compile: {
name: '<%= pkg.name %>',
@@ -161,6 +155,13 @@
outdir: '<%= dirs.docs %>'
}
}
+ },
+ karma: {
+ unit: {
+ configFile: 'test/karma.conf.js',
+ // browsers: ['Chrome'],
+ singleRun: true
+ }
}
});
@@ -182,9 +183,10 @@
}
)
- grunt.registerTask('default', ['concat', 'uglify', 'distribute']);
grunt.registerTask('build', ['concat', 'uglify', 'distribute']);
- grunt.registerTask('test', ['build', 'connect:qunit', 'qunit']);
+ grunt.registerTask('test', ['concat', 'jshint:test', 'karma']);
grunt.registerTask('docs', ['yuidoc']);
-
-}
\ No newline at end of file
+ grunt.registerTask('default', ['test', 'uglify', 'distribute']);
+ // Travis CI task.
+ grunt.registerTask('travis', ['test']);
+}
diff --git a/README.md b/README.md
index c62ef86..690cfe4 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,8 @@

+[](http://travis-ci.org/drkibitz/pixi.js)
+
#### JavaScript 2D Renderer ####
The aim of this project is to provide a fast lightweight 2D library that works
diff --git a/package.json b/package.json
index b373240..1246a68 100644
--- a/package.json
+++ b/package.json
@@ -18,14 +18,21 @@
"main": "bin/pixi.js",
+ "scripts": {
+ "test": "grunt travis --verbose"
+ },
+
"dependencies": {},
"devDependencies": {
"grunt": "~0.4.x",
- "grunt-contrib-jshint": "0.3.x",
+ "grunt-contrib-jshint": "0.6.x",
"grunt-contrib-uglify": "0.2.x",
- "grunt-contrib-connect": "0.2.x",
- "grunt-contrib-qunit": "0.2.x",
+ "grunt-contrib-connect": "0.3.x",
"grunt-contrib-yuidoc": "0.4.x",
- "grunt-contrib-concat": "0.1.x"
+ "grunt-contrib-concat": "0.3.x",
+ "chai": "~1.7.0",
+ "karma": "0.11.0",
+ "karma-firefox-launcher": "0.1.0",
+ "karma-mocha": "0.1.0"
}
}
diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js
index a7c520e..ee82bbd 100644
--- a/src/pixi/InteractionManager.js
+++ b/src/pixi/InteractionManager.js
@@ -62,7 +62,6 @@
this.onTouchEnd = this.onTouchEnd.bind(this);
this.onTouchMove = this.onTouchMove.bind(this);
-
this.last = 0;
}
diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js
index 1a95d20..eef1059 100644
--- a/src/pixi/core/Ellipse.js
+++ b/src/pixi/core/Ellipse.js
@@ -78,7 +78,7 @@
return (normx + normy < 0.25);
}
-PIXI.Ellipse.getBounds = function()
+PIXI.Ellipse.prototype.getBounds = function()
{
return new PIXI.Rectangle(this.x, this.y, this.width, this.height);
}
diff --git a/tasks/karma.js b/tasks/karma.js
new file mode 100644
index 0000000..c340485
--- /dev/null
+++ b/tasks/karma.js
@@ -0,0 +1,27 @@
+'use strict';
+
+var path = require('path');
+var server = require('karma').server;
+
+module.exports = function (grunt) {
+ grunt.registerMultiTask('karma', 'run karma.', function() {
+ var done = this.async();
+ var options = this.options({
+ background: false
+ });
+ var data = this.data;
+
+ //merge options onto data, with data taking precedence
+ data = grunt.util._.merge(options, data);
+ data.configFile = path.resolve(data.configFile);
+ if (data.configFile) {
+ data.configFile = grunt.template.process(data.configFile);
+ }
+
+ server.start(
+ data,
+ function(code) {
+ done(!code);
+ });
+ });
+};
diff --git a/test/functional/example-1-basics/bunny.png b/test/functional/example-1-basics/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/functional/example-1-basics/bunny.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-30.png b/test/functional/example-1-basics/frame-30.png
new file mode 100644
index 0000000..96e3409
--- /dev/null
+++ b/test/functional/example-1-basics/frame-30.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-60.png b/test/functional/example-1-basics/frame-60.png
new file mode 100644
index 0000000..af3f4ce
--- /dev/null
+++ b/test/functional/example-1-basics/frame-60.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-90.png b/test/functional/example-1-basics/frame-90.png
new file mode 100644
index 0000000..099b823
--- /dev/null
+++ b/test/functional/example-1-basics/frame-90.png
Binary files differ
diff --git a/test/functional/example-1-basics/index.js b/test/functional/example-1-basics/index.js
new file mode 100644
index 0000000..7ae7a98
--- /dev/null
+++ b/test/functional/example-1-basics/index.js
@@ -0,0 +1,133 @@
+describe('Example 1 - Basics', function () {
+ 'use strict';
+
+ var baseUri = '/base/test/functional/example-1-basics';
+ var expect = chai.expect;
+ var currentFrame = 0;
+ var frameEvents = {};
+ var stage;
+ var renderer;
+ var bunny;
+
+ function onFrame(frame, callback) {
+ frameEvents[frame] = callback;
+ }
+
+ function animate() {
+ currentFrame += 1;
+
+ requestAnimFrame( animate );
+
+ // just for fun, lets rotate mr rabbit a little
+ bunny.rotation += 0.1;
+
+ // render the stage
+ renderer.render(stage);
+
+ if (frameEvents[currentFrame])
+ frameEvents[currentFrame](currentFrame);
+ }
+
+ function initScene() {
+ // create an new instance of a pixi stage
+ stage = new PIXI.Stage(0x66FF99);
+
+ // create a renderer instance
+ renderer = PIXI.autoDetectRenderer(400, 300);
+ console.log('Is PIXI.WebGLRenderer: ' + (renderer instanceof PIXI.WebGLRenderer));
+
+ // add the renderer view element to the DOM
+ document.body.appendChild(renderer.view);
+
+ requestAnimFrame( animate );
+
+ // create a texture from an image path
+ var texture = PIXI.Texture.fromImage(baseUri + "/bunny.png");
+ // create a new Sprite using the texture
+ bunny = new PIXI.Sprite(texture);
+
+ // center the sprites anchor point
+ bunny.anchor.x = 0.5;
+ bunny.anchor.y = 0.5;
+
+ // move the sprite t the center of the screen
+ bunny.position.x = 200;
+ bunny.position.y = 150;
+
+ stage.addChild(bunny);
+ }
+
+ it('assets loaded', function (done) {
+ var loader = new PIXI.AssetLoader([
+ baseUri + '/bunny.png',
+ baseUri + '/frame-30.png',
+ baseUri + '/frame-60.png',
+ baseUri + '/frame-90.png'
+ ]);
+ // loader.on('onProgress', function (event) {
+ // console.log(event.content);
+ // });
+ loader.on('onComplete', function (event) {
+ done();
+ initScene();
+ });
+ loader.load();
+ });
+
+ it('frame 30 should match', function (done) {
+ this.timeout(700);
+ onFrame(30, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-30.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 60 should match', function (done) {
+ this.timeout(1200);
+ onFrame(60, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-60.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 90 should match', function (done) {
+ this.timeout(1700);
+ onFrame(90, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-90.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ // it('capture something', function (done) {
+ // this.timeout(2000000);
+ // onFrame(30, function () {
+ // var img = new Image();
+ // img.src = renderer.view.toDataURL('image/png');
+ // document.body.appendChild(img);
+ // });
+ // });
+});
diff --git a/test/index.html b/test/index.html
deleted file mode 100644
index 9cbcac5..0000000
--- a/test/index.html
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
- Pixi.js Test Suite
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/test/karma.conf.js b/test/karma.conf.js
new file mode 100644
index 0000000..c66a696
--- /dev/null
+++ b/test/karma.conf.js
@@ -0,0 +1,82 @@
+module.exports = function(config) {
+ config.set({
+
+ // base path, that will be used to resolve files and exclude
+ basePath : '../',
+
+ frameworks : ['mocha'],
+
+ // list of files / patterns to load in the browser
+ files : [
+ 'node_modules/chai/chai.js',
+ 'bin/pixi.dev.js',
+ 'test/lib/**/*.js',
+ 'test/unit/**/*.js',
+ // 'test/functional/**/*.js',
+ {pattern: 'test/**/*.png', watched: false, included: false, served: true}
+ ],
+
+ // list of files to exclude
+ exclude : [],
+
+ // use dolts reporter, as travis terminal does not support escaping sequences
+ // possible values: 'dots', 'progress', 'junit', 'teamcity'
+ // CLI --reporters progress
+ reporters : ['progress'],
+
+ // web server port
+ // CLI --port 9876
+ port : 9876,
+
+ // cli runner port
+ // CLI --runner-port 9100
+ runnerPort : 9100,
+
+ // enable / disable colors in the output (reporters and logs)
+ // CLI --colors --no-colors
+ colors : true,
+
+ // level of logging
+ // possible values: karma.LOG_DISABLE || karma.LOG_ERROR || karma.LOG_WARN || karma.LOG_INFO || karma.LOG_DEBUG
+ // CLI --log-level debug
+ logLevel : config.LOG_DEBUG,
+
+ // enable / disable watching file and executing tests whenever any file changes
+ // CLI --auto-watch --no-auto-watch
+ autoWatch : false,
+
+ // Start these browsers, currently available:
+ // - Chrome
+ // - ChromeCanary
+ // - Firefox
+ // - Opera
+ // - Safari (only Mac)
+ // - PhantomJS
+ // - IE (only Windows)
+ // CLI --browsers Chrome,Firefox,Safari
+ browsers : ['Firefox'],
+
+ // If browser does not capture in given timeout [ms], kill it
+ // CLI --capture-timeout 5000
+ captureTimeout : 5000,
+
+ // Auto run tests on start (when browsers are captured) and exit
+ // CLI --single-run --no-single-run
+ singleRun : true,
+
+ // report which specs are slower than 500ms
+ // CLI --report-slower-than 500
+ reportSlowerThan : 1000,
+
+ preprocessors : {
+ // '**/client/js/*.js': 'coverage'
+ },
+
+ plugins : [
+ 'karma-mocha',
+ // 'karma-chrome-launcher',
+ 'karma-firefox-launcher',
+ // 'karma-phantomjs-launcher'
+ ]
+ });
+};
diff --git a/test/lib/pixi/core/Matrix.js b/test/lib/pixi/core/Matrix.js
new file mode 100644
index 0000000..d26386b
--- /dev/null
+++ b/test/lib/pixi/core/Matrix.js
@@ -0,0 +1,40 @@
+
+function pixi_core_Matrix_confirmNewMat3(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(1);
+ expect(matrix[5]).to.equal(0);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(1);
+}
+
+function pixi_core_Matrix_confirmNewMat4(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[0]).to.equal(1);
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(0);
+ expect(matrix[5]).to.equal(1);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(0);
+ expect(matrix[9]).to.equal(0);
+ expect(matrix[10]).to.equal(1);
+ expect(matrix[11]).to.equal(0);
+ expect(matrix[12]).to.equal(0);
+ expect(matrix[13]).to.equal(0);
+ expect(matrix[14]).to.equal(0);
+ expect(matrix[15]).to.equal(1);
+}
diff --git a/test/lib/pixi/core/Point.js b/test/lib/pixi/core/Point.js
new file mode 100644
index 0000000..e5df07b
--- /dev/null
+++ b/test/lib/pixi/core/Point.js
@@ -0,0 +1,10 @@
+
+function pixi_core_Point_confirm(obj, x, y) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Point);
+ expect(obj).to.respondTo('clone');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+}
diff --git a/test/lib/pixi/core/Rectangle.js b/test/lib/pixi/core/Rectangle.js
new file mode 100644
index 0000000..23f0d12
--- /dev/null
+++ b/test/lib/pixi/core/Rectangle.js
@@ -0,0 +1,13 @@
+
+function pixi_core_Rectangle_confirm(obj, x, y, width, height) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Rectangle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+ expect(obj).to.have.property('width', width);
+ expect(obj).to.have.property('height', height);
+}
diff --git a/test/lib/pixi/display/DisplayObject.js b/test/lib/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..1388a7f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObject.js
@@ -0,0 +1,43 @@
+
+function pixi_display_DisplayObject_confirmNew(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObject);
+ expect(obj).to.respondTo('setInteractive');
+ expect(obj).to.respondTo('addFilter');
+ expect(obj).to.respondTo('removeFilter');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.property('last', obj);
+ expect(obj).to.have.property('first', obj);
+
+ expect(obj).to.contain.property('position');
+ pixi_core_Point_confirm(obj.position, 0, 0);
+ expect(obj).to.contain.property('scale');
+ pixi_core_Point_confirm(obj.scale, 1, 1);
+ expect(obj).to.contain.property('pivot');
+ pixi_core_Point_confirm(obj.pivot, 0, 0);
+
+ expect(obj).to.have.property('rotation', 0);
+ expect(obj).to.have.property('alpha', 1);
+ expect(obj).to.have.property('visible', true);
+ expect(obj).to.have.property('buttonMode', false);
+ expect(obj).to.have.property('parent', null);
+ expect(obj).to.have.property('worldAlpha', 1);
+
+ expect(obj).to.have.property('hitArea');
+ expect(obj).to.have.property('interactive'); // TODO: Have a better default value
+ expect('mask' in obj).to.be.true; // TODO: Have a better default value
+ expect(obj.mask).to.be.undefined;
+
+ expect(obj).to.have.property('renderable');
+ expect(obj).to.have.property('stage');
+
+ expect(obj).to.have.deep.property('worldTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ expect(obj).to.have.deep.property('localTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.localTransform);
+
+ expect(obj).to.have.deep.property('color.length', 0);
+ expect(obj).to.have.property('dynamic', true);
+}
diff --git a/test/lib/pixi/display/DisplayObjectContainer.js b/test/lib/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..085c59f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,16 @@
+
+function pixi_display_DisplayObjectContainer_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObject_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObjectContainer);
+ expect(obj).to.respondTo('addChild');
+ expect(obj).to.respondTo('addChildAt');
+ expect(obj).to.respondTo('swapChildren');
+ expect(obj).to.respondTo('getChildAt');
+ expect(obj).to.respondTo('removeChild');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('children.length', 0);
+}
diff --git a/test/lib/pixi/display/Sprite.js b/test/lib/pixi/display/Sprite.js
new file mode 100644
index 0000000..cc7a2d6
--- /dev/null
+++ b/test/lib/pixi/display/Sprite.js
@@ -0,0 +1,28 @@
+
+function pixi_display_Sprite_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Sprite);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', true);
+ expect(obj).to.have.property('stage', null);
+
+ expect(obj).to.have.property('anchor');
+ pixi_core_Point_confirm(obj.anchor, 0, 0);
+
+ expect(obj).to.have.property('blendMode', PIXI.blendModes.NORMAL);
+ expect(obj).to.have.property('width', 1); // TODO: is 1 expected
+ expect(obj).to.have.property('height', 1); // TODO: is 1 expected
+
+ // FIXME: Just make this a boolean that is always there
+ expect(!!obj.updateFrame).to.equal(obj.texture.baseTexture.hasLoaded);
+
+ expect(obj).to.have.property('texture');
+ pixi_textures_Texture_confirmNew(obj.texture, done);
+}
diff --git a/test/lib/pixi/extras/Strip.js b/test/lib/pixi/extras/Strip.js
new file mode 100644
index 0000000..8927a8a
--- /dev/null
+++ b/test/lib/pixi/extras/Strip.js
@@ -0,0 +1,12 @@
+
+function pixi_extras_Strip_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Strip);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ // TODO: Test properties
+}
diff --git a/test/lib/pixi/textures/Texture.js b/test/lib/pixi/textures/Texture.js
new file mode 100644
index 0000000..d5867b6
--- /dev/null
+++ b/test/lib/pixi/textures/Texture.js
@@ -0,0 +1,31 @@
+
+function pixi_textures_Texture_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ function confirmFrameDone() {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, obj.baseTexture.width, obj.baseTexture.height);
+
+ expect(obj).to.have.property('width', obj.baseTexture.width);
+ expect(obj).to.have.property('height', obj.baseTexture.height);
+ done();
+ }
+
+ expect(obj).to.be.an.instanceof(PIXI.Texture);
+ pixi_utils_EventTarget_like(obj);
+
+ expect(obj).to.have.property('baseTexture')
+ .and.to.be.an.instanceof(PIXI.BaseTexture);
+
+ expect(obj).to.have.property('scope', obj);
+
+ expect(obj).to.have.property('trim');
+ pixi_core_Point_confirm(obj.trim, 0, 0);
+
+ expect(obj).to.have.property('frame');
+ if (obj.baseTexture.hasLoaded) {
+ confirmFrameDone();
+ } else {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, 1, 1);
+ obj.addEventListener('update', confirmFrameDone);
+ }
+}
diff --git a/test/lib/pixi/utils/EventTarget.js b/test/lib/pixi/utils/EventTarget.js
new file mode 100644
index 0000000..7b1dcfa
--- /dev/null
+++ b/test/lib/pixi/utils/EventTarget.js
@@ -0,0 +1,8 @@
+
+function pixi_utils_EventTarget_like(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.respondTo('addEventListener');
+ expect(obj).to.respondTo('dispatchEvent');
+ expect(obj).to.respondTo('removeEventListener');
+}
diff --git a/test/lib/qunit-1.11.0.css b/test/lib/qunit-1.11.0.css
deleted file mode 100644
index d7fc0c8..0000000
--- a/test/lib/qunit-1.11.0.css
+++ /dev/null
@@ -1,244 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-/** Font Family and Sizes */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
- font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
-}
-
-#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
-#qunit-tests { font-size: smaller; }
-
-
-/** Resets */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter {
- margin: 0;
- padding: 0;
-}
-
-
-/** Header */
-
-#qunit-header {
- padding: 0.5em 0 0.5em 1em;
-
- color: #8699a4;
- background-color: #0d3349;
-
- font-size: 1.5em;
- line-height: 1em;
- font-weight: normal;
-
- border-radius: 5px 5px 0 0;
- -moz-border-radius: 5px 5px 0 0;
- -webkit-border-top-right-radius: 5px;
- -webkit-border-top-left-radius: 5px;
-}
-
-#qunit-header a {
- text-decoration: none;
- color: #c2ccd1;
-}
-
-#qunit-header a:hover,
-#qunit-header a:focus {
- color: #fff;
-}
-
-#qunit-testrunner-toolbar label {
- display: inline-block;
- padding: 0 .5em 0 .1em;
-}
-
-#qunit-banner {
- height: 5px;
-}
-
-#qunit-testrunner-toolbar {
- padding: 0.5em 0 0.5em 2em;
- color: #5E740B;
- background-color: #eee;
- overflow: hidden;
-}
-
-#qunit-userAgent {
- padding: 0.5em 0 0.5em 2.5em;
- background-color: #2b81af;
- color: #fff;
- text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
-}
-
-#qunit-modulefilter-container {
- float: right;
-}
-
-/** Tests: Pass/Fail */
-
-#qunit-tests {
- list-style-position: inside;
-}
-
-#qunit-tests li {
- padding: 0.4em 0.5em 0.4em 2.5em;
- border-bottom: 1px solid #fff;
- list-style-position: inside;
-}
-
-#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running {
- display: none;
-}
-
-#qunit-tests li strong {
- cursor: pointer;
-}
-
-#qunit-tests li a {
- padding: 0.5em;
- color: #c2ccd1;
- text-decoration: none;
-}
-#qunit-tests li a:hover,
-#qunit-tests li a:focus {
- color: #000;
-}
-
-#qunit-tests li .runtime {
- float: right;
- font-size: smaller;
-}
-
-.qunit-assert-list {
- margin-top: 0.5em;
- padding: 0.5em;
-
- background-color: #fff;
-
- border-radius: 5px;
- -moz-border-radius: 5px;
- -webkit-border-radius: 5px;
-}
-
-.qunit-collapsed {
- display: none;
-}
-
-#qunit-tests table {
- border-collapse: collapse;
- margin-top: .2em;
-}
-
-#qunit-tests th {
- text-align: right;
- vertical-align: top;
- padding: 0 .5em 0 0;
-}
-
-#qunit-tests td {
- vertical-align: top;
-}
-
-#qunit-tests pre {
- margin: 0;
- white-space: pre-wrap;
- word-wrap: break-word;
-}
-
-#qunit-tests del {
- background-color: #e0f2be;
- color: #374e0c;
- text-decoration: none;
-}
-
-#qunit-tests ins {
- background-color: #ffcaca;
- color: #500;
- text-decoration: none;
-}
-
-/*** Test Counts */
-
-#qunit-tests b.counts { color: black; }
-#qunit-tests b.passed { color: #5E740B; }
-#qunit-tests b.failed { color: #710909; }
-
-#qunit-tests li li {
- padding: 5px;
- background-color: #fff;
- border-bottom: none;
- list-style-position: inside;
-}
-
-/*** Passing Styles */
-
-#qunit-tests li li.pass {
- color: #3c510c;
- background-color: #fff;
- border-left: 10px solid #C6E746;
-}
-
-#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
-#qunit-tests .pass .test-name { color: #366097; }
-
-#qunit-tests .pass .test-actual,
-#qunit-tests .pass .test-expected { color: #999999; }
-
-#qunit-banner.qunit-pass { background-color: #C6E746; }
-
-/*** Failing Styles */
-
-#qunit-tests li li.fail {
- color: #710909;
- background-color: #fff;
- border-left: 10px solid #EE5757;
- white-space: pre;
-}
-
-#qunit-tests > li:last-child {
- border-radius: 0 0 5px 5px;
- -moz-border-radius: 0 0 5px 5px;
- -webkit-border-bottom-right-radius: 5px;
- -webkit-border-bottom-left-radius: 5px;
-}
-
-#qunit-tests .fail { color: #000000; background-color: #EE5757; }
-#qunit-tests .fail .test-name,
-#qunit-tests .fail .module-name { color: #000000; }
-
-#qunit-tests .fail .test-actual { color: #EE5757; }
-#qunit-tests .fail .test-expected { color: green; }
-
-#qunit-banner.qunit-fail { background-color: #EE5757; }
-
-
-/** Result */
-
-#qunit-testresult {
- padding: 0.5em 0.5em 0.5em 2.5em;
-
- color: #2b81af;
- background-color: #D2E0E6;
-
- border-bottom: 1px solid white;
-}
-#qunit-testresult .module-name {
- font-weight: bold;
-}
-
-/** Fixture */
-
-#qunit-fixture {
- position: absolute;
- top: -10000px;
- left: -10000px;
- width: 1000px;
- height: 1000px;
-}
diff --git a/test/lib/qunit-1.11.0.js b/test/lib/qunit-1.11.0.js
deleted file mode 100644
index 302545f..0000000
--- a/test/lib/qunit-1.11.0.js
+++ /dev/null
@@ -1,2152 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-(function( window ) {
-
-var QUnit,
- assert,
- config,
- onErrorFnPrev,
- testId = 0,
- fileName = (sourceFromStacktrace( 0 ) || "" ).replace(/(:\d+)+\)?/, "").replace(/.+\//, ""),
- toString = Object.prototype.toString,
- hasOwn = Object.prototype.hasOwnProperty,
- // Keep a local reference to Date (GH-283)
- Date = window.Date,
- defined = {
- setTimeout: typeof window.setTimeout !== "undefined",
- sessionStorage: (function() {
- var x = "qunit-test-string";
- try {
- sessionStorage.setItem( x, x );
- sessionStorage.removeItem( x );
- return true;
- } catch( e ) {
- return false;
- }
- }())
- },
- /**
- * Provides a normalized error string, correcting an issue
- * with IE 7 (and prior) where Error.prototype.toString is
- * not properly implemented
- *
- * Based on http://es5.github.com/#x15.11.4.4
- *
- * @param {String|Error} error
- * @return {String} error message
- */
- errorString = function( error ) {
- var name, message,
- errorString = error.toString();
- if ( errorString.substring( 0, 7 ) === "[object" ) {
- name = error.name ? error.name.toString() : "Error";
- message = error.message ? error.message.toString() : "";
- if ( name && message ) {
- return name + ": " + message;
- } else if ( name ) {
- return name;
- } else if ( message ) {
- return message;
- } else {
- return "Error";
- }
- } else {
- return errorString;
- }
- },
- /**
- * Makes a clone of an object using only Array or Object as base,
- * and copies over the own enumerable properties.
- *
- * @param {Object} obj
- * @return {Object} New object with only the own properties (recursively).
- */
- objectValues = function( obj ) {
- // Grunt 0.3.x uses an older version of jshint that still has jshint/jshint#392.
- /*jshint newcap: false */
- var key, val,
- vals = QUnit.is( "array", obj ) ? [] : {};
- for ( key in obj ) {
- if ( hasOwn.call( obj, key ) ) {
- val = obj[key];
- vals[key] = val === Object(val) ? objectValues(val) : val;
- }
- }
- return vals;
- };
-
-function Test( settings ) {
- extend( this, settings );
- this.assertions = [];
- this.testNumber = ++Test.count;
-}
-
-Test.count = 0;
-
-Test.prototype = {
- init: function() {
- var a, b, li,
- tests = id( "qunit-tests" );
-
- if ( tests ) {
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml;
-
- // `a` initialized at top of scope
- a = document.createElement( "a" );
- a.innerHTML = "Rerun";
- a.href = QUnit.url({ testNumber: this.testNumber });
-
- li = document.createElement( "li" );
- li.appendChild( b );
- li.appendChild( a );
- li.className = "running";
- li.id = this.id = "qunit-test-output" + testId++;
-
- tests.appendChild( li );
- }
- },
- setup: function() {
- if ( this.module !== config.previousModule ) {
- if ( config.previousModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.previousModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
- config.previousModule = this.module;
- config.moduleStats = { all: 0, bad: 0 };
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- } else if ( config.autorun ) {
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- }
-
- config.current = this;
-
- this.testEnvironment = extend({
- setup: function() {},
- teardown: function() {}
- }, this.moduleTestEnvironment );
-
- this.started = +new Date();
- runLoggingCallbacks( "testStart", QUnit, {
- name: this.testName,
- module: this.module
- });
-
- // allow utility functions to access the current test environment
- // TODO why??
- QUnit.current_testEnvironment = this.testEnvironment;
-
- if ( !config.pollution ) {
- saveGlobal();
- }
- if ( config.notrycatch ) {
- this.testEnvironment.setup.call( this.testEnvironment );
- return;
- }
- try {
- this.testEnvironment.setup.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Setup failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- },
- run: function() {
- config.current = this;
-
- var running = id( "qunit-testresult" );
-
- if ( running ) {
- running.innerHTML = "Running:
" + this.nameHtml;
- }
-
- if ( this.async ) {
- QUnit.stop();
- }
-
- this.callbackStarted = +new Date();
-
- if ( config.notrycatch ) {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- return;
- }
-
- try {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- } catch( e ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
-
- QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + " " + this.stack + ": " + ( e.message || e ), extractStacktrace( e, 0 ) );
- // else next test will carry the responsibility
- saveGlobal();
-
- // Restart the tests if they're blocking
- if ( config.blocking ) {
- QUnit.start();
- }
- }
- },
- teardown: function() {
- config.current = this;
- if ( config.notrycatch ) {
- if ( typeof this.callbackRuntime === "undefined" ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
- }
- this.testEnvironment.teardown.call( this.testEnvironment );
- return;
- } else {
- try {
- this.testEnvironment.teardown.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Teardown failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- }
- checkPollution();
- },
- finish: function() {
- config.current = this;
- if ( config.requireExpects && this.expected === null ) {
- QUnit.pushFailure( "Expected number of assertions to be defined, but expect() was not called.", this.stack );
- } else if ( this.expected !== null && this.expected !== this.assertions.length ) {
- QUnit.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack );
- } else if ( this.expected === null && !this.assertions.length ) {
- QUnit.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions.", this.stack );
- }
-
- var i, assertion, a, b, time, li, ol,
- test = this,
- good = 0,
- bad = 0,
- tests = id( "qunit-tests" );
-
- this.runtime = +new Date() - this.started;
- config.stats.all += this.assertions.length;
- config.moduleStats.all += this.assertions.length;
-
- if ( tests ) {
- ol = document.createElement( "ol" );
- ol.className = "qunit-assert-list";
-
- for ( i = 0; i < this.assertions.length; i++ ) {
- assertion = this.assertions[i];
-
- li = document.createElement( "li" );
- li.className = assertion.result ? "pass" : "fail";
- li.innerHTML = assertion.message || ( assertion.result ? "okay" : "failed" );
- ol.appendChild( li );
-
- if ( assertion.result ) {
- good++;
- } else {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
-
- // store result when possible
- if ( QUnit.config.reorder && defined.sessionStorage ) {
- if ( bad ) {
- sessionStorage.setItem( "qunit-test-" + this.module + "-" + this.testName, bad );
- } else {
- sessionStorage.removeItem( "qunit-test-" + this.module + "-" + this.testName );
- }
- }
-
- if ( bad === 0 ) {
- addClass( ol, "qunit-collapsed" );
- }
-
- // `b` initialized at top of scope
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml + " (" + bad + ", " + good + ", " + this.assertions.length + ")";
-
- addEvent(b, "click", function() {
- var next = b.parentNode.lastChild,
- collapsed = hasClass( next, "qunit-collapsed" );
- ( collapsed ? removeClass : addClass )( next, "qunit-collapsed" );
- });
-
- addEvent(b, "dblclick", function( e ) {
- var target = e && e.target ? e.target : window.event.srcElement;
- if ( target.nodeName.toLowerCase() === "span" || target.nodeName.toLowerCase() === "b" ) {
- target = target.parentNode;
- }
- if ( window.location && target.nodeName.toLowerCase() === "strong" ) {
- window.location = QUnit.url({ testNumber: test.testNumber });
- }
- });
-
- // `time` initialized at top of scope
- time = document.createElement( "span" );
- time.className = "runtime";
- time.innerHTML = this.runtime + " ms";
-
- // `li` initialized at top of scope
- li = id( this.id );
- li.className = bad ? "fail" : "pass";
- li.removeChild( li.firstChild );
- a = li.firstChild;
- li.appendChild( b );
- li.appendChild( a );
- li.appendChild( time );
- li.appendChild( ol );
-
- } else {
- for ( i = 0; i < this.assertions.length; i++ ) {
- if ( !this.assertions[i].result ) {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
- }
-
- runLoggingCallbacks( "testDone", QUnit, {
- name: this.testName,
- module: this.module,
- failed: bad,
- passed: this.assertions.length - bad,
- total: this.assertions.length,
- duration: this.runtime
- });
-
- QUnit.reset();
-
- config.current = undefined;
- },
-
- queue: function() {
- var bad,
- test = this;
-
- synchronize(function() {
- test.init();
- });
- function run() {
- // each of these can by async
- synchronize(function() {
- test.setup();
- });
- synchronize(function() {
- test.run();
- });
- synchronize(function() {
- test.teardown();
- });
- synchronize(function() {
- test.finish();
- });
- }
-
- // `bad` initialized at top of scope
- // defer when previous test run passed, if storage is available
- bad = QUnit.config.reorder && defined.sessionStorage &&
- +sessionStorage.getItem( "qunit-test-" + this.module + "-" + this.testName );
-
- if ( bad ) {
- run();
- } else {
- synchronize( run, true );
- }
- }
-};
-
-// Root QUnit object.
-// `QUnit` initialized at top of scope
-QUnit = {
-
- // call on start of module test to prepend name to all tests
- module: function( name, testEnvironment ) {
- config.currentModule = name;
- config.currentModuleTestEnvironment = testEnvironment;
- config.modules[name] = true;
- },
-
- asyncTest: function( testName, expected, callback ) {
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- QUnit.test( testName, expected, callback, true );
- },
-
- test: function( testName, expected, callback, async ) {
- var test,
- nameHtml = "" + escapeText( testName ) + "";
-
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- if ( config.currentModule ) {
- nameHtml = "" + escapeText( config.currentModule ) + ": " + nameHtml;
- }
-
- test = new Test({
- nameHtml: nameHtml,
- testName: testName,
- expected: expected,
- async: async,
- callback: callback,
- module: config.currentModule,
- moduleTestEnvironment: config.currentModuleTestEnvironment,
- stack: sourceFromStacktrace( 2 )
- });
-
- if ( !validTest( test ) ) {
- return;
- }
-
- test.queue();
- },
-
- // Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through.
- expect: function( asserts ) {
- if (arguments.length === 1) {
- config.current.expected = asserts;
- } else {
- return config.current.expected;
- }
- },
-
- start: function( count ) {
- // QUnit hasn't been initialized yet.
- // Note: RequireJS (et al) may delay onLoad
- if ( config.semaphore === undefined ) {
- QUnit.begin(function() {
- // This is triggered at the top of QUnit.load, push start() to the event loop, to allow QUnit.load to finish first
- setTimeout(function() {
- QUnit.start( count );
- });
- });
- return;
- }
-
- config.semaphore -= count || 1;
- // don't start until equal number of stop-calls
- if ( config.semaphore > 0 ) {
- return;
- }
- // ignore if start is called more often then stop
- if ( config.semaphore < 0 ) {
- config.semaphore = 0;
- QUnit.pushFailure( "Called start() while already started (QUnit.config.semaphore was 0 already)", null, sourceFromStacktrace(2) );
- return;
- }
- // A slight delay, to avoid any current callbacks
- if ( defined.setTimeout ) {
- window.setTimeout(function() {
- if ( config.semaphore > 0 ) {
- return;
- }
- if ( config.timeout ) {
- clearTimeout( config.timeout );
- }
-
- config.blocking = false;
- process( true );
- }, 13);
- } else {
- config.blocking = false;
- process( true );
- }
- },
-
- stop: function( count ) {
- config.semaphore += count || 1;
- config.blocking = true;
-
- if ( config.testTimeout && defined.setTimeout ) {
- clearTimeout( config.timeout );
- config.timeout = window.setTimeout(function() {
- QUnit.ok( false, "Test timed out" );
- config.semaphore = 1;
- QUnit.start();
- }, config.testTimeout );
- }
- }
-};
-
-// `assert` initialized at top of scope
-// Asssert helpers
-// All of these must either call QUnit.push() or manually do:
-// - runLoggingCallbacks( "log", .. );
-// - config.current.assertions.push({ .. });
-// We attach it to the QUnit object *after* we expose the public API,
-// otherwise `assert` will become a global variable in browsers (#341).
-assert = {
- /**
- * Asserts rough true-ish result.
- * @name ok
- * @function
- * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" );
- */
- ok: function( result, msg ) {
- if ( !config.current ) {
- throw new Error( "ok() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
- result = !!result;
-
- var source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: msg
- };
-
- msg = escapeText( msg || (result ? "okay" : "failed" ) );
- msg = "" + msg + "";
-
- if ( !result ) {
- source = sourceFromStacktrace( 2 );
- if ( source ) {
- details.source = source;
- msg += "Source: | " + escapeText( source ) + " |
---|
";
- }
- }
- runLoggingCallbacks( "log", QUnit, details );
- config.current.assertions.push({
- result: result,
- message: msg
- });
- },
-
- /**
- * Assert that the first two arguments are equal, with an optional message.
- * Prints out both actual and expected values.
- * @name equal
- * @function
- * @example equal( format( "Received {0} bytes.", 2), "Received 2 bytes.", "format() replaces {0} with next argument" );
- */
- equal: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected == actual, actual, expected, message );
- },
-
- /**
- * @name notEqual
- * @function
- */
- notEqual: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected != actual, actual, expected, message );
- },
-
- /**
- * @name propEqual
- * @function
- */
- propEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notPropEqual
- * @function
- */
- notPropEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name deepEqual
- * @function
- */
- deepEqual: function( actual, expected, message ) {
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notDeepEqual
- * @function
- */
- notDeepEqual: function( actual, expected, message ) {
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name strictEqual
- * @function
- */
- strictEqual: function( actual, expected, message ) {
- QUnit.push( expected === actual, actual, expected, message );
- },
-
- /**
- * @name notStrictEqual
- * @function
- */
- notStrictEqual: function( actual, expected, message ) {
- QUnit.push( expected !== actual, actual, expected, message );
- },
-
- "throws": function( block, expected, message ) {
- var actual,
- expectedOutput = expected,
- ok = false;
-
- // 'expected' is optional
- if ( typeof expected === "string" ) {
- message = expected;
- expected = null;
- }
-
- config.current.ignoreGlobalErrors = true;
- try {
- block.call( config.current.testEnvironment );
- } catch (e) {
- actual = e;
- }
- config.current.ignoreGlobalErrors = false;
-
- if ( actual ) {
- // we don't want to validate thrown error
- if ( !expected ) {
- ok = true;
- expectedOutput = null;
- // expected is a regexp
- } else if ( QUnit.objectType( expected ) === "regexp" ) {
- ok = expected.test( errorString( actual ) );
- // expected is a constructor
- } else if ( actual instanceof expected ) {
- ok = true;
- // expected is a validation function which returns true is validation passed
- } else if ( expected.call( {}, actual ) === true ) {
- expectedOutput = null;
- ok = true;
- }
-
- QUnit.push( ok, actual, expectedOutput, message );
- } else {
- QUnit.pushFailure( message, null, 'No exception was thrown.' );
- }
- }
-};
-
-/**
- * @deprecate since 1.8.0
- * Kept assertion helpers in root for backwards compatibility.
- */
-extend( QUnit, assert );
-
-/**
- * @deprecated since 1.9.0
- * Kept root "raises()" for backwards compatibility.
- * (Note that we don't introduce assert.raises).
- */
-QUnit.raises = assert[ "throws" ];
-
-/**
- * @deprecated since 1.0.0, replaced with error pushes since 1.3.0
- * Kept to avoid TypeErrors for undefined methods.
- */
-QUnit.equals = function() {
- QUnit.push( false, false, false, "QUnit.equals has been deprecated since 2009 (e88049a0), use QUnit.equal instead" );
-};
-QUnit.same = function() {
- QUnit.push( false, false, false, "QUnit.same has been deprecated since 2009 (e88049a0), use QUnit.deepEqual instead" );
-};
-
-// We want access to the constructor's prototype
-(function() {
- function F() {}
- F.prototype = QUnit;
- QUnit = new F();
- // Make F QUnit's constructor so that we can add to the prototype later
- QUnit.constructor = F;
-}());
-
-/**
- * Config object: Maintain internal state
- * Later exposed as QUnit.config
- * `config` initialized at top of scope
- */
-config = {
- // The queue of tests to run
- queue: [],
-
- // block until document ready
- blocking: true,
-
- // when enabled, show only failing tests
- // gets persisted through sessionStorage and can be changed in UI via checkbox
- hidepassed: false,
-
- // by default, run previously failed tests first
- // very useful in combination with "Hide passed tests" checked
- reorder: true,
-
- // by default, modify document.title when suite is done
- altertitle: true,
-
- // when enabled, all tests must call expect()
- requireExpects: false,
-
- // add checkboxes that are persisted in the query-string
- // when enabled, the id is set to `true` as a `QUnit.config` property
- urlConfig: [
- {
- id: "noglobals",
- label: "Check for Globals",
- tooltip: "Enabling this will test if any test introduces new properties on the `window` object. Stored as query-strings."
- },
- {
- id: "notrycatch",
- label: "No try-catch",
- tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging exceptions in IE reasonable. Stored as query-strings."
- }
- ],
-
- // Set of all modules.
- modules: {},
-
- // logging callback queues
- begin: [],
- done: [],
- log: [],
- testStart: [],
- testDone: [],
- moduleStart: [],
- moduleDone: []
-};
-
-// Export global variables, unless an 'exports' object exists,
-// in that case we assume we're in CommonJS (dealt with on the bottom of the script)
-if ( typeof exports === "undefined" ) {
- extend( window, QUnit );
-
- // Expose QUnit object
- window.QUnit = QUnit;
-}
-
-// Initialize more QUnit.config and QUnit.urlParams
-(function() {
- var i,
- location = window.location || { search: "", protocol: "file:" },
- params = location.search.slice( 1 ).split( "&" ),
- length = params.length,
- urlParams = {},
- current;
-
- if ( params[ 0 ] ) {
- for ( i = 0; i < length; i++ ) {
- current = params[ i ].split( "=" );
- current[ 0 ] = decodeURIComponent( current[ 0 ] );
- // allow just a key to turn on a flag, e.g., test.html?noglobals
- current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true;
- urlParams[ current[ 0 ] ] = current[ 1 ];
- }
- }
-
- QUnit.urlParams = urlParams;
-
- // String search anywhere in moduleName+testName
- config.filter = urlParams.filter;
-
- // Exact match of the module name
- config.module = urlParams.module;
-
- config.testNumber = parseInt( urlParams.testNumber, 10 ) || null;
-
- // Figure out if we're running the tests from a server or not
- QUnit.isLocal = location.protocol === "file:";
-}());
-
-// Extend QUnit object,
-// these after set here because they should not be exposed as global functions
-extend( QUnit, {
- assert: assert,
-
- config: config,
-
- // Initialize the configuration options
- init: function() {
- extend( config, {
- stats: { all: 0, bad: 0 },
- moduleStats: { all: 0, bad: 0 },
- started: +new Date(),
- updateRate: 1000,
- blocking: false,
- autostart: true,
- autorun: false,
- filter: "",
- queue: [],
- semaphore: 1
- });
-
- var tests, banner, result,
- qunit = id( "qunit" );
-
- if ( qunit ) {
- qunit.innerHTML =
- "" +
- "" +
- "" +
- "" +
- "
";
- }
-
- tests = id( "qunit-tests" );
- banner = id( "qunit-banner" );
- result = id( "qunit-testresult" );
-
- if ( tests ) {
- tests.innerHTML = "";
- }
-
- if ( banner ) {
- banner.className = "";
- }
-
- if ( result ) {
- result.parentNode.removeChild( result );
- }
-
- if ( tests ) {
- result = document.createElement( "p" );
- result.id = "qunit-testresult";
- result.className = "result";
- tests.parentNode.insertBefore( result, tests );
- result.innerHTML = "Running...
";
- }
- },
-
- // Resets the test setup. Useful for tests that modify the DOM.
- reset: function() {
- var fixture = id( "qunit-fixture" );
- if ( fixture ) {
- fixture.innerHTML = config.fixture;
- }
- },
-
- // Trigger an event on an element.
- // @example triggerEvent( document.body, "click" );
- triggerEvent: function( elem, type, event ) {
- if ( document.createEvent ) {
- event = document.createEvent( "MouseEvents" );
- event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView,
- 0, 0, 0, 0, 0, false, false, false, false, 0, null);
-
- elem.dispatchEvent( event );
- } else if ( elem.fireEvent ) {
- elem.fireEvent( "on" + type );
- }
- },
-
- // Safe object type checking
- is: function( type, obj ) {
- return QUnit.objectType( obj ) === type;
- },
-
- objectType: function( obj ) {
- if ( typeof obj === "undefined" ) {
- return "undefined";
- // consider: typeof null === object
- }
- if ( obj === null ) {
- return "null";
- }
-
- var match = toString.call( obj ).match(/^\[object\s(.*)\]$/),
- type = match && match[1] || "";
-
- switch ( type ) {
- case "Number":
- if ( isNaN(obj) ) {
- return "nan";
- }
- return "number";
- case "String":
- case "Boolean":
- case "Array":
- case "Date":
- case "RegExp":
- case "Function":
- return type.toLowerCase();
- }
- if ( typeof obj === "object" ) {
- return "object";
- }
- return undefined;
- },
-
- push: function( result, actual, expected, message ) {
- if ( !config.current ) {
- throw new Error( "assertion outside test context, was " + sourceFromStacktrace() );
- }
-
- var output, source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: message,
- actual: actual,
- expected: expected
- };
-
- message = escapeText( message ) || ( result ? "okay" : "failed" );
- message = "" + message + "";
- output = message;
-
- if ( !result ) {
- expected = escapeText( QUnit.jsDump.parse(expected) );
- actual = escapeText( QUnit.jsDump.parse(actual) );
- output += "Expected: | " + expected + " |
";
-
- if ( actual !== expected ) {
- output += "Result: | " + actual + " |
";
- output += "Diff: | " + QUnit.diff( expected, actual ) + " |
";
- }
-
- source = sourceFromStacktrace();
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
- }
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: !!result,
- message: output
- });
- },
-
- pushFailure: function( message, source, actual ) {
- if ( !config.current ) {
- throw new Error( "pushFailure() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
-
- var output,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: false,
- message: message
- };
-
- message = escapeText( message ) || "error";
- message = "" + message + "";
- output = message;
-
- output += "";
-
- if ( actual ) {
- output += "Result: | " + escapeText( actual ) + " |
";
- }
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: false,
- message: output
- });
- },
-
- url: function( params ) {
- params = extend( extend( {}, QUnit.urlParams ), params );
- var key,
- querystring = "?";
-
- for ( key in params ) {
- if ( !hasOwn.call( params, key ) ) {
- continue;
- }
- querystring += encodeURIComponent( key ) + "=" +
- encodeURIComponent( params[ key ] ) + "&";
- }
- return window.location.protocol + "//" + window.location.host +
- window.location.pathname + querystring.slice( 0, -1 );
- },
-
- extend: extend,
- id: id,
- addEvent: addEvent
- // load, equiv, jsDump, diff: Attached later
-});
-
-/**
- * @deprecated: Created for backwards compatibility with test runner that set the hook function
- * into QUnit.{hook}, instead of invoking it and passing the hook function.
- * QUnit.constructor is set to the empty F() above so that we can add to it's prototype here.
- * Doing this allows us to tell if the following methods have been overwritten on the actual
- * QUnit object.
- */
-extend( QUnit.constructor.prototype, {
-
- // Logging callbacks; all receive a single argument with the listed properties
- // run test/logs.html for any related changes
- begin: registerLoggingCallback( "begin" ),
-
- // done: { failed, passed, total, runtime }
- done: registerLoggingCallback( "done" ),
-
- // log: { result, actual, expected, message }
- log: registerLoggingCallback( "log" ),
-
- // testStart: { name }
- testStart: registerLoggingCallback( "testStart" ),
-
- // testDone: { name, failed, passed, total, duration }
- testDone: registerLoggingCallback( "testDone" ),
-
- // moduleStart: { name }
- moduleStart: registerLoggingCallback( "moduleStart" ),
-
- // moduleDone: { name, failed, passed, total }
- moduleDone: registerLoggingCallback( "moduleDone" )
-});
-
-if ( typeof document === "undefined" || document.readyState === "complete" ) {
- config.autorun = true;
-}
-
-QUnit.load = function() {
- runLoggingCallbacks( "begin", QUnit, {} );
-
- // Initialize the config, saving the execution queue
- var banner, filter, i, label, len, main, ol, toolbar, userAgent, val,
- urlConfigCheckboxesContainer, urlConfigCheckboxes, moduleFilter,
- numModules = 0,
- moduleFilterHtml = "",
- urlConfigHtml = "",
- oldconfig = extend( {}, config );
-
- QUnit.init();
- extend(config, oldconfig);
-
- config.blocking = false;
-
- len = config.urlConfig.length;
-
- for ( i = 0; i < len; i++ ) {
- val = config.urlConfig[i];
- if ( typeof val === "string" ) {
- val = {
- id: val,
- label: val,
- tooltip: "[no tooltip available]"
- };
- }
- config[ val.id ] = QUnit.urlParams[ val.id ];
- urlConfigHtml += "";
- }
-
- moduleFilterHtml += "";
-
- // `userAgent` initialized at top of scope
- userAgent = id( "qunit-userAgent" );
- if ( userAgent ) {
- userAgent.innerHTML = navigator.userAgent;
- }
-
- // `banner` initialized at top of scope
- banner = id( "qunit-header" );
- if ( banner ) {
- banner.innerHTML = "" + banner.innerHTML + " ";
- }
-
- // `toolbar` initialized at top of scope
- toolbar = id( "qunit-testrunner-toolbar" );
- if ( toolbar ) {
- // `filter` initialized at top of scope
- filter = document.createElement( "input" );
- filter.type = "checkbox";
- filter.id = "qunit-filter-pass";
-
- addEvent( filter, "click", function() {
- var tmp,
- ol = document.getElementById( "qunit-tests" );
-
- if ( filter.checked ) {
- ol.className = ol.className + " hidepass";
- } else {
- tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " ";
- ol.className = tmp.replace( / hidepass /, " " );
- }
- if ( defined.sessionStorage ) {
- if (filter.checked) {
- sessionStorage.setItem( "qunit-filter-passed-tests", "true" );
- } else {
- sessionStorage.removeItem( "qunit-filter-passed-tests" );
- }
- }
- });
-
- if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem( "qunit-filter-passed-tests" ) ) {
- filter.checked = true;
- // `ol` initialized at top of scope
- ol = document.getElementById( "qunit-tests" );
- ol.className = ol.className + " hidepass";
- }
- toolbar.appendChild( filter );
-
- // `label` initialized at top of scope
- label = document.createElement( "label" );
- label.setAttribute( "for", "qunit-filter-pass" );
- label.setAttribute( "title", "Only show tests and assertons that fail. Stored in sessionStorage." );
- label.innerHTML = "Hide passed tests";
- toolbar.appendChild( label );
-
- urlConfigCheckboxesContainer = document.createElement("span");
- urlConfigCheckboxesContainer.innerHTML = urlConfigHtml;
- urlConfigCheckboxes = urlConfigCheckboxesContainer.getElementsByTagName("input");
- // For oldIE support:
- // * Add handlers to the individual elements instead of the container
- // * Use "click" instead of "change"
- // * Fallback from event.target to event.srcElement
- addEvents( urlConfigCheckboxes, "click", function( event ) {
- var params = {},
- target = event.target || event.srcElement;
- params[ target.name ] = target.checked ? true : undefined;
- window.location = QUnit.url( params );
- });
- toolbar.appendChild( urlConfigCheckboxesContainer );
-
- if (numModules > 1) {
- moduleFilter = document.createElement( 'span' );
- moduleFilter.setAttribute( 'id', 'qunit-modulefilter-container' );
- moduleFilter.innerHTML = moduleFilterHtml;
- addEvent( moduleFilter.lastChild, "change", function() {
- var selectBox = moduleFilter.getElementsByTagName("select")[0],
- selectedModule = decodeURIComponent(selectBox.options[selectBox.selectedIndex].value);
-
- window.location = QUnit.url( { module: ( selectedModule === "" ) ? undefined : selectedModule } );
- });
- toolbar.appendChild(moduleFilter);
- }
- }
-
- // `main` initialized at top of scope
- main = id( "qunit-fixture" );
- if ( main ) {
- config.fixture = main.innerHTML;
- }
-
- if ( config.autostart ) {
- QUnit.start();
- }
-};
-
-addEvent( window, "load", QUnit.load );
-
-// `onErrorFnPrev` initialized at top of scope
-// Preserve other handlers
-onErrorFnPrev = window.onerror;
-
-// Cover uncaught exceptions
-// Returning true will surpress the default browser handler,
-// returning false will let it run.
-window.onerror = function ( error, filePath, linerNr ) {
- var ret = false;
- if ( onErrorFnPrev ) {
- ret = onErrorFnPrev( error, filePath, linerNr );
- }
-
- // Treat return value as window.onerror itself does,
- // Only do our handling if not surpressed.
- if ( ret !== true ) {
- if ( QUnit.config.current ) {
- if ( QUnit.config.current.ignoreGlobalErrors ) {
- return true;
- }
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- } else {
- QUnit.test( "global failure", extend( function() {
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- }, { validTest: validTest } ) );
- }
- return false;
- }
-
- return ret;
-};
-
-function done() {
- config.autorun = true;
-
- // Log the last module results
- if ( config.currentModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.currentModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
-
- var i, key,
- banner = id( "qunit-banner" ),
- tests = id( "qunit-tests" ),
- runtime = +new Date() - config.started,
- passed = config.stats.all - config.stats.bad,
- html = [
- "Tests completed in ",
- runtime,
- " milliseconds.
",
- "",
- passed,
- " assertions of ",
- config.stats.all,
- " passed, ",
- config.stats.bad,
- " failed."
- ].join( "" );
-
- if ( banner ) {
- banner.className = ( config.stats.bad ? "qunit-fail" : "qunit-pass" );
- }
-
- if ( tests ) {
- id( "qunit-testresult" ).innerHTML = html;
- }
-
- if ( config.altertitle && typeof document !== "undefined" && document.title ) {
- // show ✖ for good, ✔ for bad suite result in title
- // use escape sequences in case file gets loaded with non-utf-8-charset
- document.title = [
- ( config.stats.bad ? "\u2716" : "\u2714" ),
- document.title.replace( /^[\u2714\u2716] /i, "" )
- ].join( " " );
- }
-
- // clear own sessionStorage items if all tests passed
- if ( config.reorder && defined.sessionStorage && config.stats.bad === 0 ) {
- // `key` & `i` initialized at top of scope
- for ( i = 0; i < sessionStorage.length; i++ ) {
- key = sessionStorage.key( i++ );
- if ( key.indexOf( "qunit-test-" ) === 0 ) {
- sessionStorage.removeItem( key );
- }
- }
- }
-
- // scroll back to top to show results
- if ( window.scrollTo ) {
- window.scrollTo(0, 0);
- }
-
- runLoggingCallbacks( "done", QUnit, {
- failed: config.stats.bad,
- passed: passed,
- total: config.stats.all,
- runtime: runtime
- });
-}
-
-/** @return Boolean: true if this test should be ran */
-function validTest( test ) {
- var include,
- filter = config.filter && config.filter.toLowerCase(),
- module = config.module && config.module.toLowerCase(),
- fullName = (test.module + ": " + test.testName).toLowerCase();
-
- // Internally-generated tests are always valid
- if ( test.callback && test.callback.validTest === validTest ) {
- delete test.callback.validTest;
- return true;
- }
-
- if ( config.testNumber ) {
- return test.testNumber === config.testNumber;
- }
-
- if ( module && ( !test.module || test.module.toLowerCase() !== module ) ) {
- return false;
- }
-
- if ( !filter ) {
- return true;
- }
-
- include = filter.charAt( 0 ) !== "!";
- if ( !include ) {
- filter = filter.slice( 1 );
- }
-
- // If the filter matches, we need to honour include
- if ( fullName.indexOf( filter ) !== -1 ) {
- return include;
- }
-
- // Otherwise, do the opposite
- return !include;
-}
-
-// so far supports only Firefox, Chrome and Opera (buggy), Safari (for real exceptions)
-// Later Safari and IE10 are supposed to support error.stack as well
-// See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack
-function extractStacktrace( e, offset ) {
- offset = offset === undefined ? 3 : offset;
-
- var stack, include, i;
-
- if ( e.stacktrace ) {
- // Opera
- return e.stacktrace.split( "\n" )[ offset + 3 ];
- } else if ( e.stack ) {
- // Firefox, Chrome
- stack = e.stack.split( "\n" );
- if (/^error$/i.test( stack[0] ) ) {
- stack.shift();
- }
- if ( fileName ) {
- include = [];
- for ( i = offset; i < stack.length; i++ ) {
- if ( stack[ i ].indexOf( fileName ) !== -1 ) {
- break;
- }
- include.push( stack[ i ] );
- }
- if ( include.length ) {
- return include.join( "\n" );
- }
- }
- return stack[ offset ];
- } else if ( e.sourceURL ) {
- // Safari, PhantomJS
- // hopefully one day Safari provides actual stacktraces
- // exclude useless self-reference for generated Error objects
- if ( /qunit.js$/.test( e.sourceURL ) ) {
- return;
- }
- // for actual exceptions, this is useful
- return e.sourceURL + ":" + e.line;
- }
-}
-function sourceFromStacktrace( offset ) {
- try {
- throw new Error();
- } catch ( e ) {
- return extractStacktrace( e, offset );
- }
-}
-
-/**
- * Escape text for attribute or text content.
- */
-function escapeText( s ) {
- if ( !s ) {
- return "";
- }
- s = s + "";
- // Both single quotes and double quotes (for attributes)
- return s.replace( /['"<>&]/g, function( s ) {
- switch( s ) {
- case '\'':
- return ''';
- case '"':
- return '"';
- case '<':
- return '<';
- case '>':
- return '>';
- case '&':
- return '&';
- }
- });
-}
-
-function synchronize( callback, last ) {
- config.queue.push( callback );
-
- if ( config.autorun && !config.blocking ) {
- process( last );
- }
-}
-
-function process( last ) {
- function next() {
- process( last );
- }
- var start = new Date().getTime();
- config.depth = config.depth ? config.depth + 1 : 1;
-
- while ( config.queue.length && !config.blocking ) {
- if ( !defined.setTimeout || config.updateRate <= 0 || ( ( new Date().getTime() - start ) < config.updateRate ) ) {
- config.queue.shift()();
- } else {
- window.setTimeout( next, 13 );
- break;
- }
- }
- config.depth--;
- if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) {
- done();
- }
-}
-
-function saveGlobal() {
- config.pollution = [];
-
- if ( config.noglobals ) {
- for ( var key in window ) {
- // in Opera sometimes DOM element ids show up here, ignore them
- if ( !hasOwn.call( window, key ) || /^qunit-test-output/.test( key ) ) {
- continue;
- }
- config.pollution.push( key );
- }
- }
-}
-
-function checkPollution() {
- var newGlobals,
- deletedGlobals,
- old = config.pollution;
-
- saveGlobal();
-
- newGlobals = diff( config.pollution, old );
- if ( newGlobals.length > 0 ) {
- QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join(", ") );
- }
-
- deletedGlobals = diff( old, config.pollution );
- if ( deletedGlobals.length > 0 ) {
- QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join(", ") );
- }
-}
-
-// returns a new Array with the elements that are in a but not in b
-function diff( a, b ) {
- var i, j,
- result = a.slice();
-
- for ( i = 0; i < result.length; i++ ) {
- for ( j = 0; j < b.length; j++ ) {
- if ( result[i] === b[j] ) {
- result.splice( i, 1 );
- i--;
- break;
- }
- }
- }
- return result;
-}
-
-function extend( a, b ) {
- for ( var prop in b ) {
- if ( b[ prop ] === undefined ) {
- delete a[ prop ];
-
- // Avoid "Member not found" error in IE8 caused by setting window.constructor
- } else if ( prop !== "constructor" || a !== window ) {
- a[ prop ] = b[ prop ];
- }
- }
-
- return a;
-}
-
-/**
- * @param {HTMLElement} elem
- * @param {string} type
- * @param {Function} fn
- */
-function addEvent( elem, type, fn ) {
- // Standards-based browsers
- if ( elem.addEventListener ) {
- elem.addEventListener( type, fn, false );
- // IE
- } else {
- elem.attachEvent( "on" + type, fn );
- }
-}
-
-/**
- * @param {Array|NodeList} elems
- * @param {string} type
- * @param {Function} fn
- */
-function addEvents( elems, type, fn ) {
- var i = elems.length;
- while ( i-- ) {
- addEvent( elems[i], type, fn );
- }
-}
-
-function hasClass( elem, name ) {
- return (" " + elem.className + " ").indexOf(" " + name + " ") > -1;
-}
-
-function addClass( elem, name ) {
- if ( !hasClass( elem, name ) ) {
- elem.className += (elem.className ? " " : "") + name;
- }
-}
-
-function removeClass( elem, name ) {
- var set = " " + elem.className + " ";
- // Class name may appear multiple times
- while ( set.indexOf(" " + name + " ") > -1 ) {
- set = set.replace(" " + name + " " , " ");
- }
- // If possible, trim it for prettiness, but not neccecarily
- elem.className = window.jQuery ? jQuery.trim( set ) : ( set.trim ? set.trim() : set );
-}
-
-function id( name ) {
- return !!( typeof document !== "undefined" && document && document.getElementById ) &&
- document.getElementById( name );
-}
-
-function registerLoggingCallback( key ) {
- return function( callback ) {
- config[key].push( callback );
- };
-}
-
-// Supports deprecated method of completely overwriting logging callbacks
-function runLoggingCallbacks( key, scope, args ) {
- var i, callbacks;
- if ( QUnit.hasOwnProperty( key ) ) {
- QUnit[ key ].call(scope, args );
- } else {
- callbacks = config[ key ];
- for ( i = 0; i < callbacks.length; i++ ) {
- callbacks[ i ].call( scope, args );
- }
- }
-}
-
-// Test for equality any JavaScript type.
-// Author: Philippe Rathé
-QUnit.equiv = (function() {
-
- // Call the o related callback with the given arguments.
- function bindCallbacks( o, callbacks, args ) {
- var prop = QUnit.objectType( o );
- if ( prop ) {
- if ( QUnit.objectType( callbacks[ prop ] ) === "function" ) {
- return callbacks[ prop ].apply( callbacks, args );
- } else {
- return callbacks[ prop ]; // or undefined
- }
- }
- }
-
- // the real equiv function
- var innerEquiv,
- // stack to decide between skip/abort functions
- callers = [],
- // stack to avoiding loops from circular referencing
- parents = [],
-
- getProto = Object.getPrototypeOf || function ( obj ) {
- return obj.__proto__;
- },
- callbacks = (function () {
-
- // for string, boolean, number and null
- function useStrictEquality( b, a ) {
- /*jshint eqeqeq:false */
- if ( b instanceof a.constructor || a instanceof b.constructor ) {
- // to catch short annotaion VS 'new' annotation of a
- // declaration
- // e.g. var i = 1;
- // var j = new Number(1);
- return a == b;
- } else {
- return a === b;
- }
- }
-
- return {
- "string": useStrictEquality,
- "boolean": useStrictEquality,
- "number": useStrictEquality,
- "null": useStrictEquality,
- "undefined": useStrictEquality,
-
- "nan": function( b ) {
- return isNaN( b );
- },
-
- "date": function( b, a ) {
- return QUnit.objectType( b ) === "date" && a.valueOf() === b.valueOf();
- },
-
- "regexp": function( b, a ) {
- return QUnit.objectType( b ) === "regexp" &&
- // the regex itself
- a.source === b.source &&
- // and its modifers
- a.global === b.global &&
- // (gmi) ...
- a.ignoreCase === b.ignoreCase &&
- a.multiline === b.multiline &&
- a.sticky === b.sticky;
- },
-
- // - skip when the property is a method of an instance (OOP)
- // - abort otherwise,
- // initial === would have catch identical references anyway
- "function": function() {
- var caller = callers[callers.length - 1];
- return caller !== Object && typeof caller !== "undefined";
- },
-
- "array": function( b, a ) {
- var i, j, len, loop;
-
- // b could be an object literal here
- if ( QUnit.objectType( b ) !== "array" ) {
- return false;
- }
-
- len = a.length;
- if ( len !== b.length ) {
- // safe and faster
- return false;
- }
-
- // track reference to avoid circular references
- parents.push( a );
- for ( i = 0; i < len; i++ ) {
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- loop = true;// dont rewalk array
- }
- }
- if ( !loop && !innerEquiv(a[i], b[i]) ) {
- parents.pop();
- return false;
- }
- }
- parents.pop();
- return true;
- },
-
- "object": function( b, a ) {
- var i, j, loop,
- // Default to true
- eq = true,
- aProperties = [],
- bProperties = [];
-
- // comparing constructors is more strict than using
- // instanceof
- if ( a.constructor !== b.constructor ) {
- // Allow objects with no prototype to be equivalent to
- // objects with Object as their constructor.
- if ( !(( getProto(a) === null && getProto(b) === Object.prototype ) ||
- ( getProto(b) === null && getProto(a) === Object.prototype ) ) ) {
- return false;
- }
- }
-
- // stack constructor before traversing properties
- callers.push( a.constructor );
- // track reference to avoid circular references
- parents.push( a );
-
- for ( i in a ) { // be strict: don't ensures hasOwnProperty
- // and go deep
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- // don't go down the same path twice
- loop = true;
- }
- }
- aProperties.push(i); // collect a's properties
-
- if (!loop && !innerEquiv( a[i], b[i] ) ) {
- eq = false;
- break;
- }
- }
-
- callers.pop(); // unstack, we are done
- parents.pop();
-
- for ( i in b ) {
- bProperties.push( i ); // collect b's properties
- }
-
- // Ensures identical properties name
- return eq && innerEquiv( aProperties.sort(), bProperties.sort() );
- }
- };
- }());
-
- innerEquiv = function() { // can take multiple arguments
- var args = [].slice.apply( arguments );
- if ( args.length < 2 ) {
- return true; // end transition
- }
-
- return (function( a, b ) {
- if ( a === b ) {
- return true; // catch the most you can
- } else if ( a === null || b === null || typeof a === "undefined" ||
- typeof b === "undefined" ||
- QUnit.objectType(a) !== QUnit.objectType(b) ) {
- return false; // don't lose time with error prone cases
- } else {
- return bindCallbacks(a, callbacks, [ b, a ]);
- }
-
- // apply transition with (1..n) arguments
- }( args[0], args[1] ) && arguments.callee.apply( this, args.splice(1, args.length - 1 )) );
- };
-
- return innerEquiv;
-}());
-
-/**
- * jsDump Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com |
- * http://flesler.blogspot.com Licensed under BSD
- * (http://www.opensource.org/licenses/bsd-license.php) Date: 5/15/2008
- *
- * @projectDescription Advanced and extensible data dumping for Javascript.
- * @version 1.0.0
- * @author Ariel Flesler
- * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html}
- */
-QUnit.jsDump = (function() {
- function quote( str ) {
- return '"' + str.toString().replace( /"/g, '\\"' ) + '"';
- }
- function literal( o ) {
- return o + "";
- }
- function join( pre, arr, post ) {
- var s = jsDump.separator(),
- base = jsDump.indent(),
- inner = jsDump.indent(1);
- if ( arr.join ) {
- arr = arr.join( "," + s + inner );
- }
- if ( !arr ) {
- return pre + post;
- }
- return [ pre, inner + arr, base + post ].join(s);
- }
- function array( arr, stack ) {
- var i = arr.length, ret = new Array(i);
- this.up();
- while ( i-- ) {
- ret[i] = this.parse( arr[i] , undefined , stack);
- }
- this.down();
- return join( "[", ret, "]" );
- }
-
- var reName = /^function (\w+)/,
- jsDump = {
- // type is used mostly internally, you can fix a (custom)type in advance
- parse: function( obj, type, stack ) {
- stack = stack || [ ];
- var inStack, res,
- parser = this.parsers[ type || this.typeOf(obj) ];
-
- type = typeof parser;
- inStack = inArray( obj, stack );
-
- if ( inStack !== -1 ) {
- return "recursion(" + (inStack - stack.length) + ")";
- }
- if ( type === "function" ) {
- stack.push( obj );
- res = parser.call( this, obj, stack );
- stack.pop();
- return res;
- }
- return ( type === "string" ) ? parser : this.parsers.error;
- },
- typeOf: function( obj ) {
- var type;
- if ( obj === null ) {
- type = "null";
- } else if ( typeof obj === "undefined" ) {
- type = "undefined";
- } else if ( QUnit.is( "regexp", obj) ) {
- type = "regexp";
- } else if ( QUnit.is( "date", obj) ) {
- type = "date";
- } else if ( QUnit.is( "function", obj) ) {
- type = "function";
- } else if ( typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined" ) {
- type = "window";
- } else if ( obj.nodeType === 9 ) {
- type = "document";
- } else if ( obj.nodeType ) {
- type = "node";
- } else if (
- // native arrays
- toString.call( obj ) === "[object Array]" ||
- // NodeList objects
- ( typeof obj.length === "number" && typeof obj.item !== "undefined" && ( obj.length ? obj.item(0) === obj[0] : ( obj.item( 0 ) === null && typeof obj[0] === "undefined" ) ) )
- ) {
- type = "array";
- } else if ( obj.constructor === Error.prototype.constructor ) {
- type = "error";
- } else {
- type = typeof obj;
- }
- return type;
- },
- separator: function() {
- return this.multiline ? this.HTML ? "
" : "\n" : this.HTML ? " " : " ";
- },
- // extra can be a number, shortcut for increasing-calling-decreasing
- indent: function( extra ) {
- if ( !this.multiline ) {
- return "";
- }
- var chr = this.indentChar;
- if ( this.HTML ) {
- chr = chr.replace( /\t/g, " " ).replace( / /g, " " );
- }
- return new Array( this._depth_ + (extra||0) ).join(chr);
- },
- up: function( a ) {
- this._depth_ += a || 1;
- },
- down: function( a ) {
- this._depth_ -= a || 1;
- },
- setParser: function( name, parser ) {
- this.parsers[name] = parser;
- },
- // The next 3 are exposed so you can use them
- quote: quote,
- literal: literal,
- join: join,
- //
- _depth_: 1,
- // This is the list of parsers, to modify them, use jsDump.setParser
- parsers: {
- window: "[Window]",
- document: "[Document]",
- error: function(error) {
- return "Error(\"" + error.message + "\")";
- },
- unknown: "[Unknown]",
- "null": "null",
- "undefined": "undefined",
- "function": function( fn ) {
- var ret = "function",
- // functions never have name in IE
- name = "name" in fn ? fn.name : (reName.exec(fn) || [])[1];
-
- if ( name ) {
- ret += " " + name;
- }
- ret += "( ";
-
- ret = [ ret, QUnit.jsDump.parse( fn, "functionArgs" ), "){" ].join( "" );
- return join( ret, QUnit.jsDump.parse(fn,"functionCode" ), "}" );
- },
- array: array,
- nodelist: array,
- "arguments": array,
- object: function( map, stack ) {
- var ret = [ ], keys, key, val, i;
- QUnit.jsDump.up();
- keys = [];
- for ( key in map ) {
- keys.push( key );
- }
- keys.sort();
- for ( i = 0; i < keys.length; i++ ) {
- key = keys[ i ];
- val = map[ key ];
- ret.push( QUnit.jsDump.parse( key, "key" ) + ": " + QUnit.jsDump.parse( val, undefined, stack ) );
- }
- QUnit.jsDump.down();
- return join( "{", ret, "}" );
- },
- node: function( node ) {
- var len, i, val,
- open = QUnit.jsDump.HTML ? "<" : "<",
- close = QUnit.jsDump.HTML ? ">" : ">",
- tag = node.nodeName.toLowerCase(),
- ret = open + tag,
- attrs = node.attributes;
-
- if ( attrs ) {
- for ( i = 0, len = attrs.length; i < len; i++ ) {
- val = attrs[i].nodeValue;
- // IE6 includes all attributes in .attributes, even ones not explicitly set.
- // Those have values like undefined, null, 0, false, "" or "inherit".
- if ( val && val !== "inherit" ) {
- ret += " " + attrs[i].nodeName + "=" + QUnit.jsDump.parse( val, "attribute" );
- }
- }
- }
- ret += close;
-
- // Show content of TextNode or CDATASection
- if ( node.nodeType === 3 || node.nodeType === 4 ) {
- ret += node.nodeValue;
- }
-
- return ret + open + "/" + tag + close;
- },
- // function calls it internally, it's the arguments part of the function
- functionArgs: function( fn ) {
- var args,
- l = fn.length;
-
- if ( !l ) {
- return "";
- }
-
- args = new Array(l);
- while ( l-- ) {
- // 97 is 'a'
- args[l] = String.fromCharCode(97+l);
- }
- return " " + args.join( ", " ) + " ";
- },
- // object calls it internally, the key part of an item in a map
- key: quote,
- // function calls it internally, it's the content of the function
- functionCode: "[code]",
- // node calls it internally, it's an html attribute value
- attribute: quote,
- string: quote,
- date: quote,
- regexp: literal,
- number: literal,
- "boolean": literal
- },
- // if true, entities are escaped ( <, >, \t, space and \n )
- HTML: false,
- // indentation unit
- indentChar: " ",
- // if true, items in a collection, are separated by a \n, else just a space.
- multiline: true
- };
-
- return jsDump;
-}());
-
-// from jquery.js
-function inArray( elem, array ) {
- if ( array.indexOf ) {
- return array.indexOf( elem );
- }
-
- for ( var i = 0, length = array.length; i < length; i++ ) {
- if ( array[ i ] === elem ) {
- return i;
- }
- }
-
- return -1;
-}
-
-/*
- * Javascript Diff Algorithm
- * By John Resig (http://ejohn.org/)
- * Modified by Chu Alan "sprite"
- *
- * Released under the MIT license.
- *
- * More Info:
- * http://ejohn.org/projects/javascript-diff-algorithm/
- *
- * Usage: QUnit.diff(expected, actual)
- *
- * QUnit.diff( "the quick brown fox jumped over", "the quick fox jumps over" ) == "the quick brown fox jumped jumps over"
- */
-QUnit.diff = (function() {
- /*jshint eqeqeq:false, eqnull:true */
- function diff( o, n ) {
- var i,
- ns = {},
- os = {};
-
- for ( i = 0; i < n.length; i++ ) {
- if ( !hasOwn.call( ns, n[i] ) ) {
- ns[ n[i] ] = {
- rows: [],
- o: null
- };
- }
- ns[ n[i] ].rows.push( i );
- }
-
- for ( i = 0; i < o.length; i++ ) {
- if ( !hasOwn.call( os, o[i] ) ) {
- os[ o[i] ] = {
- rows: [],
- n: null
- };
- }
- os[ o[i] ].rows.push( i );
- }
-
- for ( i in ns ) {
- if ( !hasOwn.call( ns, i ) ) {
- continue;
- }
- if ( ns[i].rows.length === 1 && hasOwn.call( os, i ) && os[i].rows.length === 1 ) {
- n[ ns[i].rows[0] ] = {
- text: n[ ns[i].rows[0] ],
- row: os[i].rows[0]
- };
- o[ os[i].rows[0] ] = {
- text: o[ os[i].rows[0] ],
- row: ns[i].rows[0]
- };
- }
- }
-
- for ( i = 0; i < n.length - 1; i++ ) {
- if ( n[i].text != null && n[ i + 1 ].text == null && n[i].row + 1 < o.length && o[ n[i].row + 1 ].text == null &&
- n[ i + 1 ] == o[ n[i].row + 1 ] ) {
-
- n[ i + 1 ] = {
- text: n[ i + 1 ],
- row: n[i].row + 1
- };
- o[ n[i].row + 1 ] = {
- text: o[ n[i].row + 1 ],
- row: i + 1
- };
- }
- }
-
- for ( i = n.length - 1; i > 0; i-- ) {
- if ( n[i].text != null && n[ i - 1 ].text == null && n[i].row > 0 && o[ n[i].row - 1 ].text == null &&
- n[ i - 1 ] == o[ n[i].row - 1 ]) {
-
- n[ i - 1 ] = {
- text: n[ i - 1 ],
- row: n[i].row - 1
- };
- o[ n[i].row - 1 ] = {
- text: o[ n[i].row - 1 ],
- row: i - 1
- };
- }
- }
-
- return {
- o: o,
- n: n
- };
- }
-
- return function( o, n ) {
- o = o.replace( /\s+$/, "" );
- n = n.replace( /\s+$/, "" );
-
- var i, pre,
- str = "",
- out = diff( o === "" ? [] : o.split(/\s+/), n === "" ? [] : n.split(/\s+/) ),
- oSpace = o.match(/\s+/g),
- nSpace = n.match(/\s+/g);
-
- if ( oSpace == null ) {
- oSpace = [ " " ];
- }
- else {
- oSpace.push( " " );
- }
-
- if ( nSpace == null ) {
- nSpace = [ " " ];
- }
- else {
- nSpace.push( " " );
- }
-
- if ( out.n.length === 0 ) {
- for ( i = 0; i < out.o.length; i++ ) {
- str += "" + out.o[i] + oSpace[i] + "";
- }
- }
- else {
- if ( out.n[0].text == null ) {
- for ( n = 0; n < out.o.length && out.o[n].text == null; n++ ) {
- str += "" + out.o[n] + oSpace[n] + "";
- }
- }
-
- for ( i = 0; i < out.n.length; i++ ) {
- if (out.n[i].text == null) {
- str += "" + out.n[i] + nSpace[i] + "";
- }
- else {
- // `pre` initialized at top of scope
- pre = "";
-
- for ( n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++ ) {
- pre += "" + out.o[n] + oSpace[n] + "";
- }
- str += " " + out.n[i].text + nSpace[i] + pre;
- }
- }
- }
-
- return str;
- };
-}());
-
-// for CommonJS enviroments, export everything
-if ( typeof exports !== "undefined" ) {
- extend( exports, QUnit );
-}
-
-// get at whatever the global object is, like window in browsers
-}( (function() {return this;}.call()) ));
diff --git a/test/lib/require.js b/test/lib/require.js
deleted file mode 100644
index 987f865..0000000
--- a/test/lib/require.js
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- RequireJS 2.1.5 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.
- Available via the MIT or new BSD license.
- see: http://github.com/jrburke/requirejs for details
-*/
-var requirejs,require,define;
-(function(aa){function I(b){return"[object Function]"===L.call(b)}function J(b){return"[object Array]"===L.call(b)}function y(b,c){if(b){var d;for(d=0;dthis.depCount&&!this.defined){if(I(n)){if(this.events.error)try{e=i.execCb(c,n,b,e)}catch(d){a=d}else e=i.execCb(c,n,b,e);this.map.isDefine&&((b=this.module)&&void 0!==b.exports&&b.exports!==this.exports?e=b.exports:void 0===e&&this.usingExports&&(e=this.exports));if(a)return a.requireMap=this.map,a.requireModules=[this.map.id],a.requireType="define",v(this.error=
-a)}else e=n;this.exports=e;if(this.map.isDefine&&!this.ignore&&(q[c]=e,l.onResourceLoad))l.onResourceLoad(i,this.map,this.depMaps);x(c);this.defined=!0}this.defining=!1;this.defined&&!this.defineEmitted&&(this.defineEmitted=!0,this.emit("defined",this.exports),this.defineEmitComplete=!0)}}else this.fetch()}},callPlugin:function(){var a=this.map,b=a.id,d=j(a.prefix);this.depMaps.push(d);t(d,"defined",u(this,function(e){var n,d;d=this.map.name;var g=this.map.parentMap?this.map.parentMap.name:null,h=
-i.makeRequire(a.parentMap,{enableBuildCallback:!0});if(this.map.unnormalized){if(e.normalize&&(d=e.normalize(d,function(a){return c(a,g,!0)})||""),e=j(a.prefix+"!"+d,this.map.parentMap),t(e,"defined",u(this,function(a){this.init([],function(){return a},null,{enabled:!0,ignore:!0})})),d=m(p,e.id)){this.depMaps.push(e);if(this.events.error)d.on("error",u(this,function(a){this.emit("error",a)}));d.enable()}}else n=u(this,function(a){this.init([],function(){return a},null,{enabled:!0})}),n.error=u(this,
-function(a){this.inited=!0;this.error=a;a.requireModules=[b];G(p,function(a){0===a.map.id.indexOf(b+"_unnormalized")&&x(a.map.id)});v(a)}),n.fromText=u(this,function(e,c){var d=a.name,g=j(d),C=O;c&&(e=c);C&&(O=!1);r(g);s(k.config,b)&&(k.config[d]=k.config[b]);try{l.exec(e)}catch(ca){return v(B("fromtexteval","fromText eval for "+b+" failed: "+ca,ca,[b]))}C&&(O=!0);this.depMaps.push(g);i.completeLoad(d);h([d],n)}),e.load(a.name,h,n,k)}));i.enable(d,this);this.pluginMaps[d.id]=d},enable:function(){V[this.map.id]=
-this;this.enabling=this.enabled=!0;y(this.depMaps,u(this,function(a,b){var c,e;if("string"===typeof a){a=j(a,this.map.isDefine?this.map:this.map.parentMap,!1,!this.skipMap);this.depMaps[b]=a;if(c=m(N,a.id)){this.depExports[b]=c(this);return}this.depCount+=1;t(a,"defined",u(this,function(a){this.defineDep(b,a);this.check()}));this.errback&&t(a,"error",this.errback)}c=a.id;e=p[c];!s(N,c)&&(e&&!e.enabled)&&i.enable(a,this)}));G(this.pluginMaps,u(this,function(a){var b=m(p,a.id);b&&!b.enabled&&i.enable(a,
-this)}));this.enabling=!1;this.check()},on:function(a,b){var c=this.events[a];c||(c=this.events[a]=[]);c.push(b)},emit:function(a,b){y(this.events[a],function(a){a(b)});"error"===a&&delete this.events[a]}};i={config:k,contextName:b,registry:p,defined:q,urlFetched:U,defQueue:H,Module:Z,makeModuleMap:j,nextTick:l.nextTick,onError:v,configure:function(a){a.baseUrl&&"/"!==a.baseUrl.charAt(a.baseUrl.length-1)&&(a.baseUrl+="/");var b=k.pkgs,c=k.shim,e={paths:!0,config:!0,map:!0};G(a,function(a,b){e[b]?
-"map"===b?(k.map||(k.map={}),R(k[b],a,!0,!0)):R(k[b],a,!0):k[b]=a});a.shim&&(G(a.shim,function(a,b){J(a)&&(a={deps:a});if((a.exports||a.init)&&!a.exportsFn)a.exportsFn=i.makeShimExports(a);c[b]=a}),k.shim=c);a.packages&&(y(a.packages,function(a){a="string"===typeof a?{name:a}:a;b[a.name]={name:a.name,location:a.location||a.name,main:(a.main||"main").replace(ja,"").replace(ea,"")}}),k.pkgs=b);G(p,function(a,b){!a.inited&&!a.map.unnormalized&&(a.map=j(b))});if(a.deps||a.callback)i.require(a.deps||[],
-a.callback)},makeShimExports:function(a){return function(){var b;a.init&&(b=a.init.apply(aa,arguments));return b||a.exports&&ba(a.exports)}},makeRequire:function(a,f){function d(e,c,h){var g,k;f.enableBuildCallback&&(c&&I(c))&&(c.__requireJsBuild=!0);if("string"===typeof e){if(I(c))return v(B("requireargs","Invalid require call"),h);if(a&&s(N,e))return N[e](p[a.id]);if(l.get)return l.get(i,e,a,d);g=j(e,a,!1,!0);g=g.id;return!s(q,g)?v(B("notloaded",'Module name "'+g+'" has not been loaded yet for context: '+
-b+(a?"":". Use require([])"))):q[g]}L();i.nextTick(function(){L();k=r(j(null,a));k.skipMap=f.skipMap;k.init(e,c,h,{enabled:!0});D()});return d}f=f||{};R(d,{isBrowser:A,toUrl:function(b){var d,f=b.lastIndexOf("."),g=b.split("/")[0];if(-1!==f&&(!("."===g||".."===g)||1h.attachEvent.toString().indexOf("[native code"))&&!Y?(O=!0,h.attachEvent("onreadystatechange",b.onScriptLoad)):(h.addEventListener("load",b.onScriptLoad,!1),h.addEventListener("error",b.onScriptError,!1)),h.src=d,K=h,D?x.insertBefore(h,D):x.appendChild(h),K=null,h;if(da)try{importScripts(d),b.completeLoad(c)}catch(j){b.onError(B("importscripts","importScripts failed for "+c+" at "+d,j,[c]))}};A&&M(document.getElementsByTagName("script"),function(b){x||(x=
-b.parentNode);if(t=b.getAttribute("data-main"))return r.baseUrl||(E=t.split("/"),Q=E.pop(),fa=E.length?E.join("/")+"/":"./",r.baseUrl=fa,t=Q),t=t.replace(ea,""),r.deps=r.deps?r.deps.concat(t):[t],!0});define=function(b,c,d){var l,h;"string"!==typeof b&&(d=c,c=b,b=null);J(c)||(d=c,c=[]);!c.length&&I(d)&&d.length&&(d.toString().replace(la,"").replace(ma,function(b,d){c.push(d)}),c=(1===d.length?["require"]:["require","exports","module"]).concat(c));if(O){if(!(l=K))P&&"interactive"===P.readyState||M(document.getElementsByTagName("script"),
-function(b){if("interactive"===b.readyState)return P=b}),l=P;l&&(b||(b=l.getAttribute("data-requiremodule")),h=F[l.getAttribute("data-requirecontext")])}(h?h.defQueue:T).push([b,c,d])};define.amd={jQuery:!0};l.exec=function(b){return eval(b)};l(r)}})(this);
diff --git a/test/lib/resemble.js b/test/lib/resemble.js
new file mode 100644
index 0000000..1cb8c29
--- /dev/null
+++ b/test/lib/resemble.js
@@ -0,0 +1,535 @@
+/*
+Author: James Cryer
+Company: Huddle
+Last updated date: 21 Feb 2013
+URL: https://github.com/Huddle/Resemble.js
+*/
+
+(function(_this){
+ 'use strict';
+
+ _this['resemble'] = function( fileData ){
+
+ var data = {};
+ var images = [];
+ var updateCallbackArray = [];
+
+ var tolerance = { // between 0 and 255
+ red: 16,
+ green: 16,
+ blue: 16,
+ minBrightness: 16,
+ maxBrightness: 240
+ };
+
+ var ignoreAntialiasing = false;
+ var ignoreColors = false;
+
+ function triggerDataUpdate(){
+ var len = updateCallbackArray.length;
+ var i;
+ for(i=0;i tolerance.maxBrightness;
+ }
+
+ function getHue(r,g,b){
+
+ r = r / 255;
+ g = g / 255;
+ b = b / 255;
+ var max = Math.max(r, g, b), min = Math.min(r, g, b);
+ var h;
+ var d;
+
+ if (max == min){
+ h = 0; // achromatic
+ } else{
+ d = max - min;
+ switch(max){
+ case r: h = (g - b) / d + (g < b ? 6 : 0); break;
+ case g: h = (b - r) / d + 2; break;
+ case b: h = (r - g) / d + 4; break;
+ }
+ h /= 6;
+ }
+
+ return h;
+ }
+
+ function isAntialiased(sourcePix, data, cacheSet, verticalPos, horizontalPos, width){
+ var offset;
+ var targetPix;
+ var distance = 1;
+ var i;
+ var j;
+ var hasHighContrastSibling = 0;
+ var hasSiblingWithDifferentHue = 0;
+ var hasEquivilantSibling = 0;
+
+ addHueInfo(sourcePix);
+
+ for (i = distance*-1; i <= distance; i++){
+ for (j = distance*-1; j <= distance; j++){
+
+ if(i===0 && j===0){
+ // ignore source pixel
+ } else {
+
+ offset = ((verticalPos+j)*width + (horizontalPos+i)) * 4;
+ targetPix = getPixelInfo(data, offset, cacheSet);
+
+ if(targetPix === null){
+ continue;
+ }
+
+ addBrightnessInfo(targetPix);
+ addHueInfo(targetPix);
+
+ if( isContrasting(sourcePix, targetPix) ){
+ hasHighContrastSibling++;
+ }
+
+ if( isRGBSame(sourcePix,targetPix) ){
+ hasEquivilantSibling++;
+ }
+
+ if( Math.abs(targetPix.h - sourcePix.h) > 0.3 ){
+ hasSiblingWithDifferentHue++;
+ }
+
+ if( hasSiblingWithDifferentHue > 1 || hasHighContrastSibling > 1){
+ return true;
+ }
+ }
+ }
+ }
+
+ if(hasEquivilantSibling < 2){
+ return true;
+ }
+
+ return false;
+ }
+
+ function errorPixel(px, offset){
+ px[offset] = 255; //r
+ px[offset + 1] = 0; //g
+ px[offset + 2] = 255; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyPixel(px, offset, data){
+ px[offset] = data.r; //r
+ px[offset + 1] = data.g; //g
+ px[offset + 2] = data.b; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyGrayScalePixel(px, offset, data){
+ px[offset] = data.brightness; //r
+ px[offset + 1] = data.brightness; //g
+ px[offset + 2] = data.brightness; //b
+ px[offset + 3] = 255; //a
+ }
+
+
+ function getPixelInfo(data, offset, cacheSet){
+ var r;
+ var g;
+ var b;
+ var d;
+
+ if(typeof data[offset] !== 'undefined'){
+ r = data[offset];
+ g = data[offset+1];
+ b = data[offset+2];
+ d = {
+ r: r,
+ g: g,
+ b: b
+ };
+
+ return d;
+ } else {
+ return null;
+ }
+ }
+
+ function addBrightnessInfo(data){
+ data.brightness = getBrightness(data.r,data.g,data.b); // 'corrected' lightness
+ }
+
+ function addHueInfo(data){
+ data.h = getHue(data.r,data.g,data.b);
+ }
+
+ function analyseImages(img1, img2, width, height){
+
+ var hiddenCanvas = document.createElement('canvas');
+
+ var data1 = img1.data;
+ var data2 = img2.data;
+
+ hiddenCanvas.width = width;
+ hiddenCanvas.height = height;
+
+ var context = hiddenCanvas.getContext('2d');
+ var imgd = context.createImageData(width,height);
+ var targetPix = imgd.data;
+
+ var mismatchCount = 0;
+
+ var time = Date.now();
+
+ var skip;
+
+ if( (width > 1200 || height > 1200) && ignoreAntialiasing){
+ skip = 6;
+ }
+
+ loop(height, width, function(verticalPos, horizontalPos){
+
+ if(skip){ // only skip if the image isn't small
+ if(verticalPos % skip === 0 || horizontalPos % skip === 0){
+ return;
+ }
+ }
+
+ var offset = (verticalPos*width + horizontalPos) * 4;
+ var pixel1 = getPixelInfo(data1, offset, 1);
+ var pixel2 = getPixelInfo(data2, offset, 2);
+
+ if(pixel1 === null || pixel2 === null){
+ return;
+ }
+
+ if (ignoreColors){
+
+ addBrightnessInfo(pixel1);
+ addBrightnessInfo(pixel2);
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ return;
+ }
+
+ if( isRGBSimilar(pixel1, pixel2) ){
+ copyPixel(targetPix, offset, pixel2);
+
+ } else if( ignoreAntialiasing && (
+ addBrightnessInfo(pixel1), // jit pixel info augmentation looks a little weird, sorry.
+ addBrightnessInfo(pixel2),
+ isAntialiased(pixel1, data1, 1, verticalPos, horizontalPos, width) ||
+ isAntialiased(pixel2, data2, 2, verticalPos, horizontalPos, width)
+ )){
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+
+ });
+
+ data.misMatchPercentage = (mismatchCount / (height*width) * 100).toFixed(2);
+ data.analysisTime = Date.now() - time;
+
+ data.getImageDataUrl = function(text){
+ var barHeight = 0;
+
+ if(text){
+ barHeight = addLabel(text,context,hiddenCanvas);
+ }
+
+ context.putImageData(imgd, 0, barHeight);
+
+ return hiddenCanvas.toDataURL("image/png");
+ };
+ }
+
+ function addLabel(text, context, hiddenCanvas){
+ var textPadding = 2;
+
+ context.font = '12px sans-serif';
+
+ var textWidth = context.measureText(text).width + textPadding*2;
+ var barHeight = 22;
+
+ if(textWidth > hiddenCanvas.width){
+ hiddenCanvas.width = textWidth;
+ }
+
+ hiddenCanvas.height += barHeight;
+
+ context.fillStyle = "#666";
+ context.fillRect(0,0,hiddenCanvas.width,barHeight -4);
+ context.fillStyle = "#fff";
+ context.fillRect(0,barHeight -4,hiddenCanvas.width, 4);
+
+ context.fillStyle = "#fff";
+ context.textBaseline = "top";
+ context.font = '12px sans-serif';
+ context.fillText(text, textPadding, 1);
+
+ return barHeight;
+ }
+
+ function normalise(img, w, h){
+ var c;
+ var context;
+
+ if(img.height < h || img.width < w){
+ c = document.createElement('canvas');
+ c.width = w;
+ c.height = h;
+ context = c.getContext('2d');
+ context.putImageData(img, 0, 0);
+ return context.getImageData(0, 0, w, h);
+ }
+
+ return img;
+ }
+
+ function compare(one, two){
+
+ function onceWeHaveBoth(){
+ var width;
+ var height;
+ if(images.length === 2){
+ width = images[0].width > images[1].width ? images[0].width : images[1].width;
+ height = images[0].height > images[1].height ? images[0].height : images[1].height;
+
+ if( (images[0].width === images[1].width) && (images[0].height === images[1].height) ){
+ data.isSameDimensions = true;
+ } else {
+ data.isSameDimensions = false;
+ }
+
+ analyseImages( normalise(images[0],width, height), normalise(images[1],width, height), width, height);
+
+ triggerDataUpdate();
+ }
+ }
+
+ images = [];
+ loadImageData(one, onceWeHaveBoth);
+ loadImageData(two, onceWeHaveBoth);
+ }
+
+ function getCompareApi(param){
+
+ var secondFileData,
+ hasMethod = typeof param === 'function';
+
+ if( !hasMethod ){
+ // assume it's file data
+ secondFileData = param;
+ }
+
+ var self = {
+ ignoreNothing: function(){
+
+ tolerance.red = 16;
+ tolerance.green = 16;
+ tolerance.blue = 16;
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreAntialiasing: function(){
+
+ tolerance.red = 32;
+ tolerance.green = 32;
+ tolerance.blue = 32;
+ tolerance.minBrightness = 64;
+ tolerance.maxBrightness = 96;
+
+ ignoreAntialiasing = true;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreColors: function(){
+
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = true;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ onComplete: function( callback ){
+
+ updateCallbackArray.push(callback);
+
+ var wrapper = function(){
+ compare(fileData, secondFileData);
+ };
+
+ wrapper();
+
+ return getCompareApi(wrapper);
+ }
+ };
+
+ return self;
+ }
+
+ return {
+ onComplete: function( callback ){
+ updateCallbackArray.push(callback);
+ loadImageData(fileData, function(imageData, width, height){
+ parseImage(imageData.data, width, height);
+ });
+ },
+ compareTo: function(secondFileData){
+ return getCompareApi(secondFileData);
+ }
+ };
+
+ };
+}(this));
\ No newline at end of file
diff --git a/test/testsuite.js b/test/testsuite.js
deleted file mode 100644
index b486acb..0000000
--- a/test/testsuite.js
+++ /dev/null
@@ -1,36 +0,0 @@
-requirejs.config({
- baseUrl: '/test/unit/'
-});
-
-define(function(require) {
- var testModules = [
- 'Pixi',
- 'Point',
- 'Rectangle',
- 'DisplayObject',
- 'DisplayObjectContainer',
- 'Sprite',
- 'MovieClip',
- 'InteractionManager',
- 'Stage',
- 'utils/Utils',
- 'utils/EventTarget',
- 'utils/Matrix',
- 'utils/Detector',
- 'renderers/WebGLShaders',
- 'renderers/WebGLRenderer',
- 'renderers/WebGLBatch',
- 'renderers/CanvasRenderer',
- 'extras/Strip',
- 'extras/Rope',
- 'textures/BaseTexture',
- 'textures/Texture',
- 'loaders/SpriteSheetLoader',
- 'loaders/AssetLoader'
- ];
-
- // Resolve all testModules and then start the Test Runner.
- require(testModules, function() {
- QUnit.start();
- });
-});
\ No newline at end of file
diff --git a/test/textures/SpriteSheet-Aliens.png b/test/textures/SpriteSheet-Aliens.png
new file mode 100644
index 0000000..210acb1
--- /dev/null
+++ b/test/textures/SpriteSheet-Aliens.png
Binary files differ
diff --git a/test/textures/SpriteSheet-Explosion.png b/test/textures/SpriteSheet-Explosion.png
new file mode 100755
index 0000000..79e1a69
--- /dev/null
+++ b/test/textures/SpriteSheet-Explosion.png
Binary files differ
diff --git a/test/textures/bunny.png b/test/textures/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/textures/bunny.png
Binary files differ
diff --git a/test/unit/DisplayObject.js b/test/unit/DisplayObject.js
deleted file mode 100644
index 5e7e72f..0000000
--- a/test/unit/DisplayObject.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObject');
-});
diff --git a/test/unit/DisplayObjectContainer.js b/test/unit/DisplayObjectContainer.js
deleted file mode 100644
index b323959..0000000
--- a/test/unit/DisplayObjectContainer.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObjectContainer');
-});
diff --git a/test/unit/InteractionManager.js b/test/unit/InteractionManager.js
deleted file mode 100644
index e751f52..0000000
--- a/test/unit/InteractionManager.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('InteractionManager');
-});
diff --git a/test/unit/MovieClip.js b/test/unit/MovieClip.js
deleted file mode 100644
index 37d9446..0000000
--- a/test/unit/MovieClip.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('MovieClip');
-});
diff --git a/test/unit/Pixi.js b/test/unit/Pixi.js
deleted file mode 100644
index 36eee73..0000000
--- a/test/unit/Pixi.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Pixi');
-});
diff --git a/test/unit/Point.js b/test/unit/Point.js
deleted file mode 100644
index 983ff6e..0000000
--- a/test/unit/Point.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Point');
-});
diff --git a/test/unit/Rectangle.js b/test/unit/Rectangle.js
deleted file mode 100644
index 3b439ba..0000000
--- a/test/unit/Rectangle.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Rectangle');
-});
diff --git a/test/unit/Sprite.js b/test/unit/Sprite.js
deleted file mode 100644
index ed4f596..0000000
--- a/test/unit/Sprite.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Sprite');
-});
diff --git a/test/unit/Stage.js b/test/unit/Stage.js
deleted file mode 100644
index 2d70291..0000000
--- a/test/unit/Stage.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Stage');
-});
diff --git a/test/unit/extras/Rope.js b/test/unit/extras/Rope.js
deleted file mode 100644
index 5606f14..0000000
--- a/test/unit/extras/Rope.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Rope');
-});
diff --git a/test/unit/extras/Strip.js b/test/unit/extras/Strip.js
deleted file mode 100644
index 0134d3a..0000000
--- a/test/unit/extras/Strip.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Strip');
-});
diff --git a/test/unit/loaders/AssetLoader.js b/test/unit/loaders/AssetLoader.js
deleted file mode 100644
index 13b8443..0000000
--- a/test/unit/loaders/AssetLoader.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('AssetLoader');
-});
diff --git a/test/unit/loaders/SpriteSheetLoader.js b/test/unit/loaders/SpriteSheetLoader.js
deleted file mode 100644
index 8bf0cb2..0000000
--- a/test/unit/loaders/SpriteSheetLoader.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('SpriteSheetLoader');
-});
diff --git a/test/unit/pixi/InteractionManager.js b/test/unit/pixi/InteractionManager.js
new file mode 100644
index 0000000..ed3001f
--- /dev/null
+++ b/test/unit/pixi/InteractionManager.js
@@ -0,0 +1,10 @@
+describe('pixi/InteractionManager', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var InteractionManager = PIXI.InteractionManager;
+
+ it('Module exists', function () {
+ expect(InteractionManager).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/Pixi.js b/test/unit/pixi/Pixi.js
new file mode 100644
index 0000000..27debc1
--- /dev/null
+++ b/test/unit/pixi/Pixi.js
@@ -0,0 +1,9 @@
+describe('pixi/Pixi', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+
+ it('Module exists', function () {
+ expect(global).to.have.property('PIXI').and.to.be.an('object');
+ });
+});
diff --git a/test/unit/pixi/core/Circle.js b/test/unit/pixi/core/Circle.js
new file mode 100644
index 0000000..93a4456
--- /dev/null
+++ b/test/unit/pixi/core/Circle.js
@@ -0,0 +1,22 @@
+describe('pixi/core/Circle', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Circle = PIXI.Circle;
+
+ it('Module exists', function () {
+ expect(Circle).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Circle();
+
+ expect(obj).to.be.an.instanceof(Circle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', 0);
+ expect(obj).to.have.property('y', 0);
+ expect(obj).to.have.property('radius', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Ellipse.js b/test/unit/pixi/core/Ellipse.js
new file mode 100644
index 0000000..026b56f
--- /dev/null
+++ b/test/unit/pixi/core/Ellipse.js
@@ -0,0 +1,24 @@
+describe('pixi/core/Ellipse', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Ellipse = PIXI.Ellipse;
+
+ it('Module exists', function () {
+ expect(Ellipse).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Ellipse();
+
+ expect(obj).to.be.an.instanceof(Ellipse);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+ expect(obj).to.respondTo('getBounds');
+
+ expect(obj).to.have.property('x', 0);
+ expect(obj).to.have.property('y', 0);
+ expect(obj).to.have.property('width', 0);
+ expect(obj).to.have.property('height', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Matrix.js b/test/unit/pixi/core/Matrix.js
new file mode 100644
index 0000000..b48989e
--- /dev/null
+++ b/test/unit/pixi/core/Matrix.js
@@ -0,0 +1,30 @@
+describe('pixi/core/Matrix', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var mat3 = PIXI.mat3;
+ var mat4 = PIXI.mat4;
+ var Matrix = PIXI.Matrix;
+
+ it('Ensure determineMatrixArrayType works', function () {
+ expect(Matrix).to.be.a('function');
+ });
+
+ it('mat3 exists', function () {
+ expect(mat3).to.be.an('object');
+ });
+
+ it('Confirm new mat3 matrix', function () {
+ var matrix = new mat3.create();
+ pixi_core_Matrix_confirmNewMat3(matrix);
+ });
+
+ it('mat3 exists', function () {
+ expect(mat4).to.be.an('object');
+ });
+
+ it('Confirm new mat4 matrix', function () {
+ var matrix = new mat4.create();
+ pixi_core_Matrix_confirmNewMat4(matrix);
+ });
+});
diff --git a/test/unit/pixi/core/Point.js b/test/unit/pixi/core/Point.js
new file mode 100644
index 0000000..c4d5163
--- /dev/null
+++ b/test/unit/pixi/core/Point.js
@@ -0,0 +1,15 @@
+describe('pixi/core/Point', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Point = PIXI.Point;
+
+ it('Module exists', function () {
+ expect(Point).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Point();
+ pixi_core_Point_confirm(obj, 0, 0);
+ });
+});
diff --git a/test/unit/pixi/core/Polygon.js b/test/unit/pixi/core/Polygon.js
new file mode 100644
index 0000000..dc8c918
--- /dev/null
+++ b/test/unit/pixi/core/Polygon.js
@@ -0,0 +1,20 @@
+describe('pixi/core/Polygon', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Polygon = PIXI.Polygon;
+
+ it('Module exists', function () {
+ expect(Polygon).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Polygon();
+
+ expect(obj).to.be.an.instanceof(Polygon);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.deep.property('points.length', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Rectangle.js b/test/unit/pixi/core/Rectangle.js
new file mode 100644
index 0000000..d43316e
--- /dev/null
+++ b/test/unit/pixi/core/Rectangle.js
@@ -0,0 +1,15 @@
+describe('pixi/core/Rectangle', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Rectangle = PIXI.Rectangle;
+
+ it('Module exists', function () {
+ expect(Rectangle).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var rect = new Rectangle();
+ pixi_core_Rectangle_confirm(rect, 0, 0, 0, 0);
+ });
+});
diff --git a/test/unit/pixi/display/DisplayObject.js b/test/unit/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..40c6fbc
--- /dev/null
+++ b/test/unit/pixi/display/DisplayObject.js
@@ -0,0 +1,21 @@
+describe('pixi/display/DisplayObject', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var DisplayObject = PIXI.DisplayObject;
+
+ it('Module exists', function () {
+ expect(DisplayObject).to.be.a('function');
+ expect(PIXI).to.have.property('visibleCount', 0);
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new DisplayObject();
+
+ pixi_display_DisplayObject_confirmNew(obj);
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', false);
+ expect(obj).to.have.property('stage', null);
+ });
+});
diff --git a/test/unit/pixi/display/DisplayObjectContainer.js b/test/unit/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..ce7f02f
--- /dev/null
+++ b/test/unit/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,20 @@
+describe('pixi/display/DisplayObjectContainer', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var DisplayObjectContainer = PIXI.DisplayObjectContainer;
+
+ it('Module exists', function () {
+ expect(DisplayObjectContainer).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new DisplayObjectContainer();
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', false);
+ expect(obj).to.have.property('stage', null);
+ });
+});
diff --git a/test/unit/pixi/display/MovieClip.js b/test/unit/pixi/display/MovieClip.js
new file mode 100644
index 0000000..f3c6c6a
--- /dev/null
+++ b/test/unit/pixi/display/MovieClip.js
@@ -0,0 +1,33 @@
+describe('pixi/display/MovieClip', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var MovieClip = PIXI.MovieClip;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(MovieClip).to.be.a('function');
+ });
+
+ it('Confirm new instance', function (done) {
+ var texture = Texture.fromImage('/base/test/textures/SpriteSheet-Explosion.png');
+ var obj = new MovieClip([texture]);
+
+ pixi_display_Sprite_confirmNew(obj, done);
+
+ expect(obj).to.be.an.instanceof(MovieClip);
+ expect(obj).to.respondTo('stop');
+ expect(obj).to.respondTo('play');
+ expect(obj).to.respondTo('gotoAndStop');
+ expect(obj).to.respondTo('gotoAndPlay');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('textures.length', 1);
+ expect(obj).to.have.deep.property('textures[0]', texture);
+ expect(obj).to.have.property('animationSpeed', 1);
+ expect(obj).to.have.property('loop', true);
+ expect(obj).to.have.property('onComplete', null);
+ expect(obj).to.have.property('currentFrame', 0);
+ expect(obj).to.have.property('playing', false);
+ });
+});
diff --git a/test/unit/pixi/display/Sprite.js b/test/unit/pixi/display/Sprite.js
new file mode 100644
index 0000000..54e914f
--- /dev/null
+++ b/test/unit/pixi/display/Sprite.js
@@ -0,0 +1,25 @@
+describe('pixi/display/Sprite', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Sprite = PIXI.Sprite;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(Sprite).to.be.a('function');
+ expect(PIXI).to.have.deep.property('blendModes.NORMAL', 0);
+ expect(PIXI).to.have.deep.property('blendModes.SCREEN', 1);
+ });
+
+ it('Members exist', function () {
+ expect(Sprite).itself.to.respondTo('fromImage');
+ expect(Sprite).itself.to.respondTo('fromFrame');
+ });
+
+ it('Confirm new instance', function (done) {
+ var texture = Texture.fromImage('/base/test/textures/SpriteSheet-Aliens.png');
+ var obj = new Sprite(texture);
+
+ pixi_display_Sprite_confirmNew(obj, done);
+ });
+});
diff --git a/test/unit/pixi/display/Stage.js b/test/unit/pixi/display/Stage.js
new file mode 100644
index 0000000..3cc2a4d
--- /dev/null
+++ b/test/unit/pixi/display/Stage.js
@@ -0,0 +1,49 @@
+describe('pixi/display/Stage', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Stage = PIXI.Stage;
+ var InteractionManager = PIXI.InteractionManager;
+ var Rectangle = PIXI.Rectangle;
+
+ it('Module exists', function () {
+ expect(Stage).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Stage(null, true);
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(Stage);
+ expect(obj).to.respondTo('updateTransform');
+ expect(obj).to.respondTo('setBackgroundColor');
+ expect(obj).to.respondTo('getMousePosition');
+
+ // FIXME: duplicate member in DisplayObject
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ // FIXME: convert arg to bool in constructor
+ expect(obj).to.have.property('interactive', true);
+
+ expect(obj).to.have.property('interactionManager')
+ .and.to.be.an.instanceof(InteractionManager)
+ .and.to.have.property('stage', obj);
+
+ expect(obj).to.have.property('dirty', true);
+
+ expect(obj).to.have.property('stage', obj);
+
+ expect(obj).to.have.property('hitArea')
+ .and.to.be.an.instanceof(Rectangle);
+ pixi_core_Rectangle_confirm(obj.hitArea, 0, 0, 100000, 100000);
+
+ expect(obj).to.have.property('backgroundColor', 0x000000);
+ expect(obj).to.have.deep.property('backgroundColorSplit.length', 3);
+ expect(obj).to.have.deep.property('backgroundColorSplit[0]', 0);
+ expect(obj).to.have.deep.property('backgroundColorSplit[1]', 0);
+ expect(obj).to.have.deep.property('backgroundColorSplit[2]', 0);
+ expect(obj).to.have.property('backgroundColorString', '#000000');
+
+ expect(obj).to.have.property('worldVisible', true);
+ });
+});
diff --git a/test/unit/pixi/extras/CustomRenderable.js b/test/unit/pixi/extras/CustomRenderable.js
new file mode 100644
index 0000000..8d83cf0
--- /dev/null
+++ b/test/unit/pixi/extras/CustomRenderable.js
@@ -0,0 +1,21 @@
+describe('pixi/extras/CustomRenderable', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var CustomRenderable = PIXI.CustomRenderable;
+
+ it('Module exists', function () {
+ expect(CustomRenderable).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new CustomRenderable();
+
+ pixi_display_DisplayObject_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(CustomRenderable);
+ expect(obj).to.respondTo('renderCanvas');
+ expect(obj).to.respondTo('initWebGL');
+ expect(obj).to.respondTo('renderWebGL');
+ });
+});
diff --git a/test/unit/pixi/extras/Rope.js b/test/unit/pixi/extras/Rope.js
new file mode 100644
index 0000000..6ddaf83
--- /dev/null
+++ b/test/unit/pixi/extras/Rope.js
@@ -0,0 +1,26 @@
+describe('pixi/extras/Rope', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Rope = PIXI.Rope;
+ var Texture = PIXI.Texture;
+ var Point = PIXI.Point;
+
+ it('Module exists', function () {
+ expect(Rope).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var texture = Texture.fromImage('/base/test/textures/bunny.png');
+ var obj = new Rope(texture, [new Point(), new Point(5, 10), new Point(10, 20)]);
+
+ pixi_extras_Strip_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(Rope);
+ expect(obj).to.respondTo('refresh');
+ expect(obj).to.respondTo('updateTransform');
+ expect(obj).to.respondTo('setTexture');
+
+ // TODO: Test properties
+ });
+});
diff --git a/test/unit/pixi/extras/Spine.js b/test/unit/pixi/extras/Spine.js
new file mode 100644
index 0000000..0708bc0
--- /dev/null
+++ b/test/unit/pixi/extras/Spine.js
@@ -0,0 +1,10 @@
+describe('pixi/extras/Spine', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Spine = PIXI.Spine;
+
+ it('Module exists', function () {
+ expect(Spine).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/extras/Strip.js b/test/unit/pixi/extras/Strip.js
new file mode 100644
index 0000000..8e564e1
--- /dev/null
+++ b/test/unit/pixi/extras/Strip.js
@@ -0,0 +1,18 @@
+describe('pixi/extras/Strip', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Strip = PIXI.Strip;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(Strip).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var texture = Texture.fromImage('/base/test/textures/bunny.png');
+ var obj = new Strip(texture, 20, 10000);
+
+ pixi_extras_Strip_confirmNew(obj);
+ });
+});
diff --git a/test/unit/pixi/extras/TilingSprite.js b/test/unit/pixi/extras/TilingSprite.js
new file mode 100644
index 0000000..56aea14
--- /dev/null
+++ b/test/unit/pixi/extras/TilingSprite.js
@@ -0,0 +1,24 @@
+describe('pixi/extras/TilingSprite', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var TilingSprite = PIXI.TilingSprite;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(TilingSprite).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var texture = Texture.fromImage('/base/test/textures/bunny.png');
+ var obj = new TilingSprite(texture, 6000, 12000);
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(TilingSprite);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ // TODO: Test properties
+ });
+});
diff --git a/test/unit/pixi/filters/FilterBlock.js b/test/unit/pixi/filters/FilterBlock.js
new file mode 100644
index 0000000..870cec0
--- /dev/null
+++ b/test/unit/pixi/filters/FilterBlock.js
@@ -0,0 +1,10 @@
+describe('pixi/filters/FilterBlock', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var FilterBlock = PIXI.FilterBlock;
+
+ it('Module exists', function () {
+ expect(FilterBlock).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/filters/MaskFilter.js b/test/unit/pixi/filters/MaskFilter.js
new file mode 100644
index 0000000..32d6a45
--- /dev/null
+++ b/test/unit/pixi/filters/MaskFilter.js
@@ -0,0 +1,10 @@
+describe('pixi/filters/MaskFilter', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ // var MaskFilter = PIXI.MaskFilter;
+
+ // it('Module exists', function () {
+ // expect(MaskFilter).to.be.a('function');
+ // });
+});
diff --git a/test/unit/pixi/loaders/AssetLoader.js b/test/unit/pixi/loaders/AssetLoader.js
new file mode 100644
index 0000000..a0aa0b5
--- /dev/null
+++ b/test/unit/pixi/loaders/AssetLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/AssetLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var AssetLoader = PIXI.AssetLoader;
+
+ it('Module exists', function () {
+ expect(AssetLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/BitmapFontLoader.js b/test/unit/pixi/loaders/BitmapFontLoader.js
new file mode 100644
index 0000000..6253c42
--- /dev/null
+++ b/test/unit/pixi/loaders/BitmapFontLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/BitmapFontLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var BitmapFontLoader = PIXI.BitmapFontLoader;
+
+ it('Module exists', function () {
+ expect(PIXI.BitmapFontLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/ImageLoader.js b/test/unit/pixi/loaders/ImageLoader.js
new file mode 100644
index 0000000..8b1f556
--- /dev/null
+++ b/test/unit/pixi/loaders/ImageLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/ImageLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var ImageLoader = PIXI.ImageLoader;
+
+ it('Module exists', function () {
+ expect(ImageLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/JsonLoader.js b/test/unit/pixi/loaders/JsonLoader.js
new file mode 100644
index 0000000..c577e83
--- /dev/null
+++ b/test/unit/pixi/loaders/JsonLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/JsonLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var JsonLoader = PIXI.JsonLoader;
+
+ it('Module exists', function () {
+ expect(JsonLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/SpineLoader.js b/test/unit/pixi/loaders/SpineLoader.js
new file mode 100644
index 0000000..fdcc0b8
--- /dev/null
+++ b/test/unit/pixi/loaders/SpineLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/SpineLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var SpineLoader = PIXI.SpineLoader;
+
+ it('Module exists', function () {
+ expect(SpineLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/SpriteSheetLoader.js b/test/unit/pixi/loaders/SpriteSheetLoader.js
new file mode 100644
index 0000000..57beb27
--- /dev/null
+++ b/test/unit/pixi/loaders/SpriteSheetLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/SpriteSheetLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var SpriteSheetLoader = PIXI.SpriteSheetLoader;
+
+ it('Module exists', function () {
+ expect(SpriteSheetLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/primitives/Graphics.js b/test/unit/pixi/primitives/Graphics.js
new file mode 100644
index 0000000..b8b3e5c
--- /dev/null
+++ b/test/unit/pixi/primitives/Graphics.js
@@ -0,0 +1,40 @@
+describe('pixi/primitives/Graphics', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Graphics = PIXI.Graphics;
+
+ it('Module exists', function () {
+ expect(Graphics).to.be.a('function');
+
+ expect(Graphics).itself.to.have.property('POLY', 0);
+ expect(Graphics).itself.to.have.property('RECT', 1);
+ expect(Graphics).itself.to.have.property('CIRC', 2);
+ expect(Graphics).itself.to.have.property('ELIP', 3);
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Graphics();
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(Graphics);
+ expect(obj).to.respondTo('lineStyle');
+ expect(obj).to.respondTo('lineStyle');
+ expect(obj).to.respondTo('moveTo');
+ expect(obj).to.respondTo('lineTo');
+ expect(obj).to.respondTo('beginFill');
+ expect(obj).to.respondTo('endFill');
+ expect(obj).to.respondTo('drawRect');
+ expect(obj).to.respondTo('drawCircle');
+ expect(obj).to.respondTo('drawElipse');
+ expect(obj).to.respondTo('clear');
+
+ expect(obj).to.have.property('renderable', true);
+ expect(obj).to.have.property('fillAlpha', 1);
+ expect(obj).to.have.property('lineWidth', 0);
+ expect(obj).to.have.property('lineColor', 'black');
+ expect(obj).to.have.deep.property('graphicsData.length', 0);
+ expect(obj).to.have.deep.property('currentPath.points.length', 0);
+ });
+});
diff --git a/test/unit/pixi/renderers/canvas/CanvasGraphics.js b/test/unit/pixi/renderers/canvas/CanvasGraphics.js
new file mode 100644
index 0000000..8f44472
--- /dev/null
+++ b/test/unit/pixi/renderers/canvas/CanvasGraphics.js
@@ -0,0 +1,15 @@
+describe('renders/canvas/CanvasGraphics', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var CanvasGraphics = PIXI.CanvasGraphics;
+
+ it('Module exists', function () {
+ expect(CanvasGraphics).to.be.a('function');
+ });
+
+ it('Members exist', function () {
+ expect(CanvasGraphics).itself.to.respondTo('renderGraphics');
+ expect(CanvasGraphics).itself.to.respondTo('renderGraphicsMask');
+ });
+});
diff --git a/test/unit/pixi/renderers/canvas/CanvasRenderer.js b/test/unit/pixi/renderers/canvas/CanvasRenderer.js
new file mode 100644
index 0000000..df3a12f
--- /dev/null
+++ b/test/unit/pixi/renderers/canvas/CanvasRenderer.js
@@ -0,0 +1,10 @@
+describe('renderers/canvas/CanvasRenderer', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var CanvasRenderer = PIXI.CanvasRenderer;
+
+ it('Module exists', function () {
+ expect(CanvasRenderer).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/renderers/webgl/WebGLBatch.js b/test/unit/pixi/renderers/webgl/WebGLBatch.js
new file mode 100644
index 0000000..75efd56
--- /dev/null
+++ b/test/unit/pixi/renderers/webgl/WebGLBatch.js
@@ -0,0 +1,10 @@
+describe('renderers/webgl/WebGLBatch', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var WebGLBatch = PIXI.WebGLBatch;
+
+ it('Module exists', function () {
+ expect(WebGLBatch).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/renderers/webgl/WebGLGraphics.js b/test/unit/pixi/renderers/webgl/WebGLGraphics.js
new file mode 100644
index 0000000..41bf941
--- /dev/null
+++ b/test/unit/pixi/renderers/webgl/WebGLGraphics.js
@@ -0,0 +1,19 @@
+describe('renderers/wegbl/WebGLGraphics', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var WebGLGraphics = PIXI.WebGLGraphics;
+
+ it('Module exists', function () {
+ expect(WebGLGraphics).to.be.a('function');
+ });
+
+ it('Members exist', function () {
+ expect(WebGLGraphics).itself.to.respondTo('renderGraphics');
+ expect(WebGLGraphics).itself.to.respondTo('updateGraphics');
+ expect(WebGLGraphics).itself.to.respondTo('buildRectangle');
+ expect(WebGLGraphics).itself.to.respondTo('buildCircle');
+ expect(WebGLGraphics).itself.to.respondTo('buildLine');
+ expect(WebGLGraphics).itself.to.respondTo('buildPoly');
+ });
+});
diff --git a/test/unit/pixi/renderers/webgl/WebGLRenderGroup.js b/test/unit/pixi/renderers/webgl/WebGLRenderGroup.js
new file mode 100644
index 0000000..f4ee366
--- /dev/null
+++ b/test/unit/pixi/renderers/webgl/WebGLRenderGroup.js
@@ -0,0 +1,10 @@
+describe('renderers/webgl/WebGLRenderGroup', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var WebGLRenderGroup = PIXI.WebGLRenderGroup;
+
+ it('Module exists', function () {
+ expect(WebGLRenderGroup).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/renderers/webgl/WebGLRenderer.js b/test/unit/pixi/renderers/webgl/WebGLRenderer.js
new file mode 100644
index 0000000..86533eb
--- /dev/null
+++ b/test/unit/pixi/renderers/webgl/WebGLRenderer.js
@@ -0,0 +1,10 @@
+describe('renderers/webgl/WebGLRenderer', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var WebGLRenderer = PIXI.WebGLRenderer;
+
+ it('Module exists', function () {
+ expect(WebGLRenderer).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/renderers/webgl/WebGLShaders.js b/test/unit/pixi/renderers/webgl/WebGLShaders.js
new file mode 100644
index 0000000..2872de8
--- /dev/null
+++ b/test/unit/pixi/renderers/webgl/WebGLShaders.js
@@ -0,0 +1,13 @@
+describe('renderers/webgl/WebGLShaders', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+
+ it('Module members exist', function () {
+ expect(PIXI).to.respondTo('initPrimitiveShader');
+ expect(PIXI).to.respondTo('initDefaultShader');
+ expect(PIXI).to.respondTo('initDefaultStripShader');
+ expect(PIXI).to.respondTo('activateDefaultShader');
+ expect(PIXI).to.respondTo('activatePrimitiveShader');
+ });
+});
diff --git a/test/unit/pixi/text/BitmapText.js b/test/unit/pixi/text/BitmapText.js
new file mode 100644
index 0000000..9388e3d
--- /dev/null
+++ b/test/unit/pixi/text/BitmapText.js
@@ -0,0 +1,10 @@
+describe('pixi/text/BitmapText', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var BitmapText = PIXI.BitmapText;
+
+ it('Module exists', function () {
+ expect(BitmapText).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/text/Text.js b/test/unit/pixi/text/Text.js
new file mode 100644
index 0000000..9bc9ac5
--- /dev/null
+++ b/test/unit/pixi/text/Text.js
@@ -0,0 +1,10 @@
+describe('pixi/text/Text', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Text = PIXI.Text;
+
+ it('Module exists', function () {
+ expect(Text).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/textures/BaseTexture.js b/test/unit/pixi/textures/BaseTexture.js
new file mode 100644
index 0000000..e34b64c
--- /dev/null
+++ b/test/unit/pixi/textures/BaseTexture.js
@@ -0,0 +1,13 @@
+describe('pixi/textures/BaseTexture', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var BaseTexture = PIXI.BaseTexture;
+
+ it('Module exists', function () {
+ expect(BaseTexture).to.be.a('function');
+ expect(PIXI).to.have.property('BaseTextureCache').and.to.be.an('object');
+ expect(PIXI).to.have.deep.property('texturesToUpdate.length');
+ expect(PIXI).to.have.deep.property('texturesToDestroy.length', 0);
+ });
+});
diff --git a/test/unit/pixi/textures/RenderTexture.js b/test/unit/pixi/textures/RenderTexture.js
new file mode 100644
index 0000000..4a69b44
--- /dev/null
+++ b/test/unit/pixi/textures/RenderTexture.js
@@ -0,0 +1,10 @@
+describe('pixi/textures/RenderTexture', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var RenderTexture = PIXI.RenderTexture;
+
+ it('Module exists', function () {
+ expect(RenderTexture).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/textures/Texture.js b/test/unit/pixi/textures/Texture.js
new file mode 100644
index 0000000..adb2875
--- /dev/null
+++ b/test/unit/pixi/textures/Texture.js
@@ -0,0 +1,26 @@
+describe('pixi/textures/Texture', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(Texture).to.be.a('function');
+ expect(PIXI).to.have.property('TextureCache').and.to.be.an('object');
+ });
+
+ it('Members exist', function () {
+ expect(Texture).itself.to.respondTo('fromImage');
+ expect(Texture).itself.to.respondTo('fromFrame');
+ expect(Texture).itself.to.respondTo('fromCanvas');
+ expect(Texture).itself.to.respondTo('addTextureToCache');
+ expect(Texture).itself.to.respondTo('removeTextureFromCache');
+
+ expect(Texture).itself.to.have.deep.property('frameUpdates.length', 0);
+ });
+
+ it('Confirm new instance', function (done) {
+ var texture = Texture.fromImage('/base/test/textures/bunny.png');
+ pixi_textures_Texture_confirmNew(texture, done);
+ });
+});
diff --git a/test/unit/pixi/utils/Detector.js b/test/unit/pixi/utils/Detector.js
new file mode 100644
index 0000000..4cf6008
--- /dev/null
+++ b/test/unit/pixi/utils/Detector.js
@@ -0,0 +1,10 @@
+describe('pixi/utils/Detector', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var autoDetectRenderer = PIXI.autoDetectRenderer;
+
+ it('Module exists', function () {
+ expect(autoDetectRenderer).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/utils/EventTarget.js b/test/unit/pixi/utils/EventTarget.js
new file mode 100644
index 0000000..dc4ebd9
--- /dev/null
+++ b/test/unit/pixi/utils/EventTarget.js
@@ -0,0 +1,96 @@
+describe('pixi/utils/EventTarget', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var EventTarget = PIXI.EventTarget;
+
+ it('Module exists', function () {
+ expect(EventTarget).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = {}; EventTarget.call(obj);
+ pixi_utils_EventTarget_like(obj);
+ });
+
+ it('addEventListener and dispatchEvent works', function (done) {
+ var myData = {},
+ obj = {}; EventTarget.call(obj);
+
+ obj.addEventListener('myevent', function (event) {
+ expect(event).to.be.an('object');
+ expect(event).to.have.property('type', 'myevent');
+ expect(event).to.have.property('data', myData);
+ done();
+ });
+
+ obj.dispatchEvent({type: 'myevent', data: myData});
+ });
+
+ it('removeEventListener works', function (done) {
+ var obj = {}; EventTarget.call(obj);
+
+ function onMyEvent() {
+ done(new Error('addEventListener should not have been called'));
+ }
+
+ obj.addEventListener('myevent', onMyEvent);
+ obj.removeEventListener('myevent', onMyEvent);
+ obj.dispatchEvent({type: 'myevent'});
+ done();
+ });
+
+ it('multiple dispatches', function () {
+ var called = 0,
+ obj = {}; EventTarget.call(obj);
+
+ function onMyEvent() {
+ called++;
+ }
+
+ obj.addEventListener('myevent', onMyEvent);
+ obj.dispatchEvent({type: 'myevent'});
+ obj.dispatchEvent({type: 'myevent'});
+ obj.dispatchEvent({type: 'myevent'});
+ obj.dispatchEvent({type: 'myevent'});
+ expect(called).to.equal(4);
+ });
+
+ it('multiple events', function () {
+ var called = 0,
+ obj = {}; EventTarget.call(obj);
+
+ function onMyEvent() {
+ called++;
+ }
+
+ obj.addEventListener('myevent1', onMyEvent);
+ obj.addEventListener('myevent2', onMyEvent);
+ obj.addEventListener('myevent3', onMyEvent);
+ obj.dispatchEvent({type: 'myevent1'});
+ obj.dispatchEvent({type: 'myevent2'});
+ obj.dispatchEvent({type: 'myevent3'});
+ expect(called).to.equal(3);
+ });
+
+ it('multiple events one removed', function () {
+ var called = 0,
+ obj = {}; EventTarget.call(obj);
+
+ function onMyEvent() {
+ called++;
+ }
+
+ obj.addEventListener('myevent1', onMyEvent);
+ obj.addEventListener('myevent2', onMyEvent);
+ obj.addEventListener('myevent3', onMyEvent);
+ obj.dispatchEvent({type: 'myevent1'});
+ obj.dispatchEvent({type: 'myevent2'});
+ obj.dispatchEvent({type: 'myevent3'});
+ obj.removeEventListener('myevent2', onMyEvent);
+ obj.dispatchEvent({type: 'myevent1'});
+ obj.dispatchEvent({type: 'myevent2'});
+ obj.dispatchEvent({type: 'myevent3'});
+ expect(called).to.equal(5);
+ });
+});
diff --git a/test/unit/pixi/utils/Polyk.js b/test/unit/pixi/utils/Polyk.js
new file mode 100644
index 0000000..dfc7128
--- /dev/null
+++ b/test/unit/pixi/utils/Polyk.js
@@ -0,0 +1,14 @@
+describe('pixi/utils/Polyk', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var PolyK = PIXI.PolyK;
+
+ it('Module exists', function () {
+ expect(PolyK).to.be.an('object');
+ });
+
+ it('Members exist', function () {
+ expect(PolyK).to.respondTo('Triangulate');
+ });
+});
diff --git a/test/unit/pixi/utils/Utils.js b/test/unit/pixi/utils/Utils.js
new file mode 100644
index 0000000..c97b3c6
--- /dev/null
+++ b/test/unit/pixi/utils/Utils.js
@@ -0,0 +1,17 @@
+describe('Utils', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+
+ it('requestAnimationFrame exists', function () {
+ expect(global).to.respondTo('requestAnimationFrame');
+ });
+
+ it('cancelAnimationFrame exists', function () {
+ expect(global).to.respondTo('cancelAnimationFrame');
+ });
+
+ it('requestAnimFrame exists', function () {
+ expect(global).to.respondTo('requestAnimFrame');
+ });
+});
diff --git a/.gitignore b/.gitignore
index 12e1b62..0b88317 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
node_modules
.DS_Store
-.project
\ No newline at end of file
+.project
+*.log
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..63e4d7c
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,8 @@
+language: node_js
+node_js:
+ - 0.10
+
+before_script:
+ - npm install -g grunt-cli
+ - export DISPLAY=:99.0
+ - sh -e /etc/init.d/xvfb start
diff --git a/Gruntfile.js b/Gruntfile.js
index b083b49..103938c 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -1,10 +1,12 @@
+'use strict';
+
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-connect');
- grunt.loadNpmTasks('grunt-contrib-qunit');
grunt.loadNpmTasks('grunt-contrib-yuidoc');
+ grunt.loadTasks('tasks');
var root = 'src/pixi/',
debug = 'bin/pixi.dev.js',
@@ -79,7 +81,7 @@
},
files: {
srcBlob: '<%= dirs.src %>/**/*.js',
- testBlob: '<%= dirs.test %>/unit/**/*.js',
+ testBlob: '<%= dirs.test %>/{functional,lib/pixi,unit}/**/*.js',
build: '<%= dirs.build %>/pixi.dev.js',
buildMin: '<%= dirs.build %>/pixi.js'
},
@@ -94,7 +96,12 @@
},
jshint: {
beforeconcat: srcFiles,
- test: ['<%= files.testBlob %>'],
+ test: {
+ src: ['<%= files.testBlob %>'],
+ options: {
+ expr: true
+ }
+ },
options: {
asi: true,
smarttabs: true
@@ -128,12 +135,6 @@
]
},
connect: {
- qunit: {
- options: {
- port: grunt.option('port-test') || 9002,
- base: './'
- }
- },
test: {
options: {
port: grunt.option('port-test') || 9002,
@@ -142,13 +143,6 @@
}
}
},
- qunit: {
- all: {
- options: {
- urls: ['http://localhost:' + (grunt.option('port-test') || 9002) + '/test/index.html']
- }
- }
- },
yuidoc: {
compile: {
name: '<%= pkg.name %>',
@@ -161,6 +155,13 @@
outdir: '<%= dirs.docs %>'
}
}
+ },
+ karma: {
+ unit: {
+ configFile: 'test/karma.conf.js',
+ // browsers: ['Chrome'],
+ singleRun: true
+ }
}
});
@@ -182,9 +183,10 @@
}
)
- grunt.registerTask('default', ['concat', 'uglify', 'distribute']);
grunt.registerTask('build', ['concat', 'uglify', 'distribute']);
- grunt.registerTask('test', ['build', 'connect:qunit', 'qunit']);
+ grunt.registerTask('test', ['concat', 'jshint:test', 'karma']);
grunt.registerTask('docs', ['yuidoc']);
-
-}
\ No newline at end of file
+ grunt.registerTask('default', ['test', 'uglify', 'distribute']);
+ // Travis CI task.
+ grunt.registerTask('travis', ['test']);
+}
diff --git a/README.md b/README.md
index c62ef86..690cfe4 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,8 @@

+[](http://travis-ci.org/drkibitz/pixi.js)
+
#### JavaScript 2D Renderer ####
The aim of this project is to provide a fast lightweight 2D library that works
diff --git a/package.json b/package.json
index b373240..1246a68 100644
--- a/package.json
+++ b/package.json
@@ -18,14 +18,21 @@
"main": "bin/pixi.js",
+ "scripts": {
+ "test": "grunt travis --verbose"
+ },
+
"dependencies": {},
"devDependencies": {
"grunt": "~0.4.x",
- "grunt-contrib-jshint": "0.3.x",
+ "grunt-contrib-jshint": "0.6.x",
"grunt-contrib-uglify": "0.2.x",
- "grunt-contrib-connect": "0.2.x",
- "grunt-contrib-qunit": "0.2.x",
+ "grunt-contrib-connect": "0.3.x",
"grunt-contrib-yuidoc": "0.4.x",
- "grunt-contrib-concat": "0.1.x"
+ "grunt-contrib-concat": "0.3.x",
+ "chai": "~1.7.0",
+ "karma": "0.11.0",
+ "karma-firefox-launcher": "0.1.0",
+ "karma-mocha": "0.1.0"
}
}
diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js
index a7c520e..ee82bbd 100644
--- a/src/pixi/InteractionManager.js
+++ b/src/pixi/InteractionManager.js
@@ -62,7 +62,6 @@
this.onTouchEnd = this.onTouchEnd.bind(this);
this.onTouchMove = this.onTouchMove.bind(this);
-
this.last = 0;
}
diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js
index 1a95d20..eef1059 100644
--- a/src/pixi/core/Ellipse.js
+++ b/src/pixi/core/Ellipse.js
@@ -78,7 +78,7 @@
return (normx + normy < 0.25);
}
-PIXI.Ellipse.getBounds = function()
+PIXI.Ellipse.prototype.getBounds = function()
{
return new PIXI.Rectangle(this.x, this.y, this.width, this.height);
}
diff --git a/tasks/karma.js b/tasks/karma.js
new file mode 100644
index 0000000..c340485
--- /dev/null
+++ b/tasks/karma.js
@@ -0,0 +1,27 @@
+'use strict';
+
+var path = require('path');
+var server = require('karma').server;
+
+module.exports = function (grunt) {
+ grunt.registerMultiTask('karma', 'run karma.', function() {
+ var done = this.async();
+ var options = this.options({
+ background: false
+ });
+ var data = this.data;
+
+ //merge options onto data, with data taking precedence
+ data = grunt.util._.merge(options, data);
+ data.configFile = path.resolve(data.configFile);
+ if (data.configFile) {
+ data.configFile = grunt.template.process(data.configFile);
+ }
+
+ server.start(
+ data,
+ function(code) {
+ done(!code);
+ });
+ });
+};
diff --git a/test/functional/example-1-basics/bunny.png b/test/functional/example-1-basics/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/functional/example-1-basics/bunny.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-30.png b/test/functional/example-1-basics/frame-30.png
new file mode 100644
index 0000000..96e3409
--- /dev/null
+++ b/test/functional/example-1-basics/frame-30.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-60.png b/test/functional/example-1-basics/frame-60.png
new file mode 100644
index 0000000..af3f4ce
--- /dev/null
+++ b/test/functional/example-1-basics/frame-60.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-90.png b/test/functional/example-1-basics/frame-90.png
new file mode 100644
index 0000000..099b823
--- /dev/null
+++ b/test/functional/example-1-basics/frame-90.png
Binary files differ
diff --git a/test/functional/example-1-basics/index.js b/test/functional/example-1-basics/index.js
new file mode 100644
index 0000000..7ae7a98
--- /dev/null
+++ b/test/functional/example-1-basics/index.js
@@ -0,0 +1,133 @@
+describe('Example 1 - Basics', function () {
+ 'use strict';
+
+ var baseUri = '/base/test/functional/example-1-basics';
+ var expect = chai.expect;
+ var currentFrame = 0;
+ var frameEvents = {};
+ var stage;
+ var renderer;
+ var bunny;
+
+ function onFrame(frame, callback) {
+ frameEvents[frame] = callback;
+ }
+
+ function animate() {
+ currentFrame += 1;
+
+ requestAnimFrame( animate );
+
+ // just for fun, lets rotate mr rabbit a little
+ bunny.rotation += 0.1;
+
+ // render the stage
+ renderer.render(stage);
+
+ if (frameEvents[currentFrame])
+ frameEvents[currentFrame](currentFrame);
+ }
+
+ function initScene() {
+ // create an new instance of a pixi stage
+ stage = new PIXI.Stage(0x66FF99);
+
+ // create a renderer instance
+ renderer = PIXI.autoDetectRenderer(400, 300);
+ console.log('Is PIXI.WebGLRenderer: ' + (renderer instanceof PIXI.WebGLRenderer));
+
+ // add the renderer view element to the DOM
+ document.body.appendChild(renderer.view);
+
+ requestAnimFrame( animate );
+
+ // create a texture from an image path
+ var texture = PIXI.Texture.fromImage(baseUri + "/bunny.png");
+ // create a new Sprite using the texture
+ bunny = new PIXI.Sprite(texture);
+
+ // center the sprites anchor point
+ bunny.anchor.x = 0.5;
+ bunny.anchor.y = 0.5;
+
+ // move the sprite t the center of the screen
+ bunny.position.x = 200;
+ bunny.position.y = 150;
+
+ stage.addChild(bunny);
+ }
+
+ it('assets loaded', function (done) {
+ var loader = new PIXI.AssetLoader([
+ baseUri + '/bunny.png',
+ baseUri + '/frame-30.png',
+ baseUri + '/frame-60.png',
+ baseUri + '/frame-90.png'
+ ]);
+ // loader.on('onProgress', function (event) {
+ // console.log(event.content);
+ // });
+ loader.on('onComplete', function (event) {
+ done();
+ initScene();
+ });
+ loader.load();
+ });
+
+ it('frame 30 should match', function (done) {
+ this.timeout(700);
+ onFrame(30, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-30.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 60 should match', function (done) {
+ this.timeout(1200);
+ onFrame(60, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-60.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 90 should match', function (done) {
+ this.timeout(1700);
+ onFrame(90, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-90.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ // it('capture something', function (done) {
+ // this.timeout(2000000);
+ // onFrame(30, function () {
+ // var img = new Image();
+ // img.src = renderer.view.toDataURL('image/png');
+ // document.body.appendChild(img);
+ // });
+ // });
+});
diff --git a/test/index.html b/test/index.html
deleted file mode 100644
index 9cbcac5..0000000
--- a/test/index.html
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
- Pixi.js Test Suite
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/test/karma.conf.js b/test/karma.conf.js
new file mode 100644
index 0000000..c66a696
--- /dev/null
+++ b/test/karma.conf.js
@@ -0,0 +1,82 @@
+module.exports = function(config) {
+ config.set({
+
+ // base path, that will be used to resolve files and exclude
+ basePath : '../',
+
+ frameworks : ['mocha'],
+
+ // list of files / patterns to load in the browser
+ files : [
+ 'node_modules/chai/chai.js',
+ 'bin/pixi.dev.js',
+ 'test/lib/**/*.js',
+ 'test/unit/**/*.js',
+ // 'test/functional/**/*.js',
+ {pattern: 'test/**/*.png', watched: false, included: false, served: true}
+ ],
+
+ // list of files to exclude
+ exclude : [],
+
+ // use dolts reporter, as travis terminal does not support escaping sequences
+ // possible values: 'dots', 'progress', 'junit', 'teamcity'
+ // CLI --reporters progress
+ reporters : ['progress'],
+
+ // web server port
+ // CLI --port 9876
+ port : 9876,
+
+ // cli runner port
+ // CLI --runner-port 9100
+ runnerPort : 9100,
+
+ // enable / disable colors in the output (reporters and logs)
+ // CLI --colors --no-colors
+ colors : true,
+
+ // level of logging
+ // possible values: karma.LOG_DISABLE || karma.LOG_ERROR || karma.LOG_WARN || karma.LOG_INFO || karma.LOG_DEBUG
+ // CLI --log-level debug
+ logLevel : config.LOG_DEBUG,
+
+ // enable / disable watching file and executing tests whenever any file changes
+ // CLI --auto-watch --no-auto-watch
+ autoWatch : false,
+
+ // Start these browsers, currently available:
+ // - Chrome
+ // - ChromeCanary
+ // - Firefox
+ // - Opera
+ // - Safari (only Mac)
+ // - PhantomJS
+ // - IE (only Windows)
+ // CLI --browsers Chrome,Firefox,Safari
+ browsers : ['Firefox'],
+
+ // If browser does not capture in given timeout [ms], kill it
+ // CLI --capture-timeout 5000
+ captureTimeout : 5000,
+
+ // Auto run tests on start (when browsers are captured) and exit
+ // CLI --single-run --no-single-run
+ singleRun : true,
+
+ // report which specs are slower than 500ms
+ // CLI --report-slower-than 500
+ reportSlowerThan : 1000,
+
+ preprocessors : {
+ // '**/client/js/*.js': 'coverage'
+ },
+
+ plugins : [
+ 'karma-mocha',
+ // 'karma-chrome-launcher',
+ 'karma-firefox-launcher',
+ // 'karma-phantomjs-launcher'
+ ]
+ });
+};
diff --git a/test/lib/pixi/core/Matrix.js b/test/lib/pixi/core/Matrix.js
new file mode 100644
index 0000000..d26386b
--- /dev/null
+++ b/test/lib/pixi/core/Matrix.js
@@ -0,0 +1,40 @@
+
+function pixi_core_Matrix_confirmNewMat3(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(1);
+ expect(matrix[5]).to.equal(0);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(1);
+}
+
+function pixi_core_Matrix_confirmNewMat4(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[0]).to.equal(1);
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(0);
+ expect(matrix[5]).to.equal(1);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(0);
+ expect(matrix[9]).to.equal(0);
+ expect(matrix[10]).to.equal(1);
+ expect(matrix[11]).to.equal(0);
+ expect(matrix[12]).to.equal(0);
+ expect(matrix[13]).to.equal(0);
+ expect(matrix[14]).to.equal(0);
+ expect(matrix[15]).to.equal(1);
+}
diff --git a/test/lib/pixi/core/Point.js b/test/lib/pixi/core/Point.js
new file mode 100644
index 0000000..e5df07b
--- /dev/null
+++ b/test/lib/pixi/core/Point.js
@@ -0,0 +1,10 @@
+
+function pixi_core_Point_confirm(obj, x, y) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Point);
+ expect(obj).to.respondTo('clone');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+}
diff --git a/test/lib/pixi/core/Rectangle.js b/test/lib/pixi/core/Rectangle.js
new file mode 100644
index 0000000..23f0d12
--- /dev/null
+++ b/test/lib/pixi/core/Rectangle.js
@@ -0,0 +1,13 @@
+
+function pixi_core_Rectangle_confirm(obj, x, y, width, height) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Rectangle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+ expect(obj).to.have.property('width', width);
+ expect(obj).to.have.property('height', height);
+}
diff --git a/test/lib/pixi/display/DisplayObject.js b/test/lib/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..1388a7f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObject.js
@@ -0,0 +1,43 @@
+
+function pixi_display_DisplayObject_confirmNew(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObject);
+ expect(obj).to.respondTo('setInteractive');
+ expect(obj).to.respondTo('addFilter');
+ expect(obj).to.respondTo('removeFilter');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.property('last', obj);
+ expect(obj).to.have.property('first', obj);
+
+ expect(obj).to.contain.property('position');
+ pixi_core_Point_confirm(obj.position, 0, 0);
+ expect(obj).to.contain.property('scale');
+ pixi_core_Point_confirm(obj.scale, 1, 1);
+ expect(obj).to.contain.property('pivot');
+ pixi_core_Point_confirm(obj.pivot, 0, 0);
+
+ expect(obj).to.have.property('rotation', 0);
+ expect(obj).to.have.property('alpha', 1);
+ expect(obj).to.have.property('visible', true);
+ expect(obj).to.have.property('buttonMode', false);
+ expect(obj).to.have.property('parent', null);
+ expect(obj).to.have.property('worldAlpha', 1);
+
+ expect(obj).to.have.property('hitArea');
+ expect(obj).to.have.property('interactive'); // TODO: Have a better default value
+ expect('mask' in obj).to.be.true; // TODO: Have a better default value
+ expect(obj.mask).to.be.undefined;
+
+ expect(obj).to.have.property('renderable');
+ expect(obj).to.have.property('stage');
+
+ expect(obj).to.have.deep.property('worldTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ expect(obj).to.have.deep.property('localTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.localTransform);
+
+ expect(obj).to.have.deep.property('color.length', 0);
+ expect(obj).to.have.property('dynamic', true);
+}
diff --git a/test/lib/pixi/display/DisplayObjectContainer.js b/test/lib/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..085c59f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,16 @@
+
+function pixi_display_DisplayObjectContainer_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObject_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObjectContainer);
+ expect(obj).to.respondTo('addChild');
+ expect(obj).to.respondTo('addChildAt');
+ expect(obj).to.respondTo('swapChildren');
+ expect(obj).to.respondTo('getChildAt');
+ expect(obj).to.respondTo('removeChild');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('children.length', 0);
+}
diff --git a/test/lib/pixi/display/Sprite.js b/test/lib/pixi/display/Sprite.js
new file mode 100644
index 0000000..cc7a2d6
--- /dev/null
+++ b/test/lib/pixi/display/Sprite.js
@@ -0,0 +1,28 @@
+
+function pixi_display_Sprite_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Sprite);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', true);
+ expect(obj).to.have.property('stage', null);
+
+ expect(obj).to.have.property('anchor');
+ pixi_core_Point_confirm(obj.anchor, 0, 0);
+
+ expect(obj).to.have.property('blendMode', PIXI.blendModes.NORMAL);
+ expect(obj).to.have.property('width', 1); // TODO: is 1 expected
+ expect(obj).to.have.property('height', 1); // TODO: is 1 expected
+
+ // FIXME: Just make this a boolean that is always there
+ expect(!!obj.updateFrame).to.equal(obj.texture.baseTexture.hasLoaded);
+
+ expect(obj).to.have.property('texture');
+ pixi_textures_Texture_confirmNew(obj.texture, done);
+}
diff --git a/test/lib/pixi/extras/Strip.js b/test/lib/pixi/extras/Strip.js
new file mode 100644
index 0000000..8927a8a
--- /dev/null
+++ b/test/lib/pixi/extras/Strip.js
@@ -0,0 +1,12 @@
+
+function pixi_extras_Strip_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Strip);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ // TODO: Test properties
+}
diff --git a/test/lib/pixi/textures/Texture.js b/test/lib/pixi/textures/Texture.js
new file mode 100644
index 0000000..d5867b6
--- /dev/null
+++ b/test/lib/pixi/textures/Texture.js
@@ -0,0 +1,31 @@
+
+function pixi_textures_Texture_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ function confirmFrameDone() {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, obj.baseTexture.width, obj.baseTexture.height);
+
+ expect(obj).to.have.property('width', obj.baseTexture.width);
+ expect(obj).to.have.property('height', obj.baseTexture.height);
+ done();
+ }
+
+ expect(obj).to.be.an.instanceof(PIXI.Texture);
+ pixi_utils_EventTarget_like(obj);
+
+ expect(obj).to.have.property('baseTexture')
+ .and.to.be.an.instanceof(PIXI.BaseTexture);
+
+ expect(obj).to.have.property('scope', obj);
+
+ expect(obj).to.have.property('trim');
+ pixi_core_Point_confirm(obj.trim, 0, 0);
+
+ expect(obj).to.have.property('frame');
+ if (obj.baseTexture.hasLoaded) {
+ confirmFrameDone();
+ } else {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, 1, 1);
+ obj.addEventListener('update', confirmFrameDone);
+ }
+}
diff --git a/test/lib/pixi/utils/EventTarget.js b/test/lib/pixi/utils/EventTarget.js
new file mode 100644
index 0000000..7b1dcfa
--- /dev/null
+++ b/test/lib/pixi/utils/EventTarget.js
@@ -0,0 +1,8 @@
+
+function pixi_utils_EventTarget_like(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.respondTo('addEventListener');
+ expect(obj).to.respondTo('dispatchEvent');
+ expect(obj).to.respondTo('removeEventListener');
+}
diff --git a/test/lib/qunit-1.11.0.css b/test/lib/qunit-1.11.0.css
deleted file mode 100644
index d7fc0c8..0000000
--- a/test/lib/qunit-1.11.0.css
+++ /dev/null
@@ -1,244 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-/** Font Family and Sizes */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
- font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
-}
-
-#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
-#qunit-tests { font-size: smaller; }
-
-
-/** Resets */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter {
- margin: 0;
- padding: 0;
-}
-
-
-/** Header */
-
-#qunit-header {
- padding: 0.5em 0 0.5em 1em;
-
- color: #8699a4;
- background-color: #0d3349;
-
- font-size: 1.5em;
- line-height: 1em;
- font-weight: normal;
-
- border-radius: 5px 5px 0 0;
- -moz-border-radius: 5px 5px 0 0;
- -webkit-border-top-right-radius: 5px;
- -webkit-border-top-left-radius: 5px;
-}
-
-#qunit-header a {
- text-decoration: none;
- color: #c2ccd1;
-}
-
-#qunit-header a:hover,
-#qunit-header a:focus {
- color: #fff;
-}
-
-#qunit-testrunner-toolbar label {
- display: inline-block;
- padding: 0 .5em 0 .1em;
-}
-
-#qunit-banner {
- height: 5px;
-}
-
-#qunit-testrunner-toolbar {
- padding: 0.5em 0 0.5em 2em;
- color: #5E740B;
- background-color: #eee;
- overflow: hidden;
-}
-
-#qunit-userAgent {
- padding: 0.5em 0 0.5em 2.5em;
- background-color: #2b81af;
- color: #fff;
- text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
-}
-
-#qunit-modulefilter-container {
- float: right;
-}
-
-/** Tests: Pass/Fail */
-
-#qunit-tests {
- list-style-position: inside;
-}
-
-#qunit-tests li {
- padding: 0.4em 0.5em 0.4em 2.5em;
- border-bottom: 1px solid #fff;
- list-style-position: inside;
-}
-
-#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running {
- display: none;
-}
-
-#qunit-tests li strong {
- cursor: pointer;
-}
-
-#qunit-tests li a {
- padding: 0.5em;
- color: #c2ccd1;
- text-decoration: none;
-}
-#qunit-tests li a:hover,
-#qunit-tests li a:focus {
- color: #000;
-}
-
-#qunit-tests li .runtime {
- float: right;
- font-size: smaller;
-}
-
-.qunit-assert-list {
- margin-top: 0.5em;
- padding: 0.5em;
-
- background-color: #fff;
-
- border-radius: 5px;
- -moz-border-radius: 5px;
- -webkit-border-radius: 5px;
-}
-
-.qunit-collapsed {
- display: none;
-}
-
-#qunit-tests table {
- border-collapse: collapse;
- margin-top: .2em;
-}
-
-#qunit-tests th {
- text-align: right;
- vertical-align: top;
- padding: 0 .5em 0 0;
-}
-
-#qunit-tests td {
- vertical-align: top;
-}
-
-#qunit-tests pre {
- margin: 0;
- white-space: pre-wrap;
- word-wrap: break-word;
-}
-
-#qunit-tests del {
- background-color: #e0f2be;
- color: #374e0c;
- text-decoration: none;
-}
-
-#qunit-tests ins {
- background-color: #ffcaca;
- color: #500;
- text-decoration: none;
-}
-
-/*** Test Counts */
-
-#qunit-tests b.counts { color: black; }
-#qunit-tests b.passed { color: #5E740B; }
-#qunit-tests b.failed { color: #710909; }
-
-#qunit-tests li li {
- padding: 5px;
- background-color: #fff;
- border-bottom: none;
- list-style-position: inside;
-}
-
-/*** Passing Styles */
-
-#qunit-tests li li.pass {
- color: #3c510c;
- background-color: #fff;
- border-left: 10px solid #C6E746;
-}
-
-#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
-#qunit-tests .pass .test-name { color: #366097; }
-
-#qunit-tests .pass .test-actual,
-#qunit-tests .pass .test-expected { color: #999999; }
-
-#qunit-banner.qunit-pass { background-color: #C6E746; }
-
-/*** Failing Styles */
-
-#qunit-tests li li.fail {
- color: #710909;
- background-color: #fff;
- border-left: 10px solid #EE5757;
- white-space: pre;
-}
-
-#qunit-tests > li:last-child {
- border-radius: 0 0 5px 5px;
- -moz-border-radius: 0 0 5px 5px;
- -webkit-border-bottom-right-radius: 5px;
- -webkit-border-bottom-left-radius: 5px;
-}
-
-#qunit-tests .fail { color: #000000; background-color: #EE5757; }
-#qunit-tests .fail .test-name,
-#qunit-tests .fail .module-name { color: #000000; }
-
-#qunit-tests .fail .test-actual { color: #EE5757; }
-#qunit-tests .fail .test-expected { color: green; }
-
-#qunit-banner.qunit-fail { background-color: #EE5757; }
-
-
-/** Result */
-
-#qunit-testresult {
- padding: 0.5em 0.5em 0.5em 2.5em;
-
- color: #2b81af;
- background-color: #D2E0E6;
-
- border-bottom: 1px solid white;
-}
-#qunit-testresult .module-name {
- font-weight: bold;
-}
-
-/** Fixture */
-
-#qunit-fixture {
- position: absolute;
- top: -10000px;
- left: -10000px;
- width: 1000px;
- height: 1000px;
-}
diff --git a/test/lib/qunit-1.11.0.js b/test/lib/qunit-1.11.0.js
deleted file mode 100644
index 302545f..0000000
--- a/test/lib/qunit-1.11.0.js
+++ /dev/null
@@ -1,2152 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-(function( window ) {
-
-var QUnit,
- assert,
- config,
- onErrorFnPrev,
- testId = 0,
- fileName = (sourceFromStacktrace( 0 ) || "" ).replace(/(:\d+)+\)?/, "").replace(/.+\//, ""),
- toString = Object.prototype.toString,
- hasOwn = Object.prototype.hasOwnProperty,
- // Keep a local reference to Date (GH-283)
- Date = window.Date,
- defined = {
- setTimeout: typeof window.setTimeout !== "undefined",
- sessionStorage: (function() {
- var x = "qunit-test-string";
- try {
- sessionStorage.setItem( x, x );
- sessionStorage.removeItem( x );
- return true;
- } catch( e ) {
- return false;
- }
- }())
- },
- /**
- * Provides a normalized error string, correcting an issue
- * with IE 7 (and prior) where Error.prototype.toString is
- * not properly implemented
- *
- * Based on http://es5.github.com/#x15.11.4.4
- *
- * @param {String|Error} error
- * @return {String} error message
- */
- errorString = function( error ) {
- var name, message,
- errorString = error.toString();
- if ( errorString.substring( 0, 7 ) === "[object" ) {
- name = error.name ? error.name.toString() : "Error";
- message = error.message ? error.message.toString() : "";
- if ( name && message ) {
- return name + ": " + message;
- } else if ( name ) {
- return name;
- } else if ( message ) {
- return message;
- } else {
- return "Error";
- }
- } else {
- return errorString;
- }
- },
- /**
- * Makes a clone of an object using only Array or Object as base,
- * and copies over the own enumerable properties.
- *
- * @param {Object} obj
- * @return {Object} New object with only the own properties (recursively).
- */
- objectValues = function( obj ) {
- // Grunt 0.3.x uses an older version of jshint that still has jshint/jshint#392.
- /*jshint newcap: false */
- var key, val,
- vals = QUnit.is( "array", obj ) ? [] : {};
- for ( key in obj ) {
- if ( hasOwn.call( obj, key ) ) {
- val = obj[key];
- vals[key] = val === Object(val) ? objectValues(val) : val;
- }
- }
- return vals;
- };
-
-function Test( settings ) {
- extend( this, settings );
- this.assertions = [];
- this.testNumber = ++Test.count;
-}
-
-Test.count = 0;
-
-Test.prototype = {
- init: function() {
- var a, b, li,
- tests = id( "qunit-tests" );
-
- if ( tests ) {
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml;
-
- // `a` initialized at top of scope
- a = document.createElement( "a" );
- a.innerHTML = "Rerun";
- a.href = QUnit.url({ testNumber: this.testNumber });
-
- li = document.createElement( "li" );
- li.appendChild( b );
- li.appendChild( a );
- li.className = "running";
- li.id = this.id = "qunit-test-output" + testId++;
-
- tests.appendChild( li );
- }
- },
- setup: function() {
- if ( this.module !== config.previousModule ) {
- if ( config.previousModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.previousModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
- config.previousModule = this.module;
- config.moduleStats = { all: 0, bad: 0 };
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- } else if ( config.autorun ) {
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- }
-
- config.current = this;
-
- this.testEnvironment = extend({
- setup: function() {},
- teardown: function() {}
- }, this.moduleTestEnvironment );
-
- this.started = +new Date();
- runLoggingCallbacks( "testStart", QUnit, {
- name: this.testName,
- module: this.module
- });
-
- // allow utility functions to access the current test environment
- // TODO why??
- QUnit.current_testEnvironment = this.testEnvironment;
-
- if ( !config.pollution ) {
- saveGlobal();
- }
- if ( config.notrycatch ) {
- this.testEnvironment.setup.call( this.testEnvironment );
- return;
- }
- try {
- this.testEnvironment.setup.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Setup failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- },
- run: function() {
- config.current = this;
-
- var running = id( "qunit-testresult" );
-
- if ( running ) {
- running.innerHTML = "Running:
" + this.nameHtml;
- }
-
- if ( this.async ) {
- QUnit.stop();
- }
-
- this.callbackStarted = +new Date();
-
- if ( config.notrycatch ) {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- return;
- }
-
- try {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- } catch( e ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
-
- QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + " " + this.stack + ": " + ( e.message || e ), extractStacktrace( e, 0 ) );
- // else next test will carry the responsibility
- saveGlobal();
-
- // Restart the tests if they're blocking
- if ( config.blocking ) {
- QUnit.start();
- }
- }
- },
- teardown: function() {
- config.current = this;
- if ( config.notrycatch ) {
- if ( typeof this.callbackRuntime === "undefined" ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
- }
- this.testEnvironment.teardown.call( this.testEnvironment );
- return;
- } else {
- try {
- this.testEnvironment.teardown.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Teardown failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- }
- checkPollution();
- },
- finish: function() {
- config.current = this;
- if ( config.requireExpects && this.expected === null ) {
- QUnit.pushFailure( "Expected number of assertions to be defined, but expect() was not called.", this.stack );
- } else if ( this.expected !== null && this.expected !== this.assertions.length ) {
- QUnit.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack );
- } else if ( this.expected === null && !this.assertions.length ) {
- QUnit.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions.", this.stack );
- }
-
- var i, assertion, a, b, time, li, ol,
- test = this,
- good = 0,
- bad = 0,
- tests = id( "qunit-tests" );
-
- this.runtime = +new Date() - this.started;
- config.stats.all += this.assertions.length;
- config.moduleStats.all += this.assertions.length;
-
- if ( tests ) {
- ol = document.createElement( "ol" );
- ol.className = "qunit-assert-list";
-
- for ( i = 0; i < this.assertions.length; i++ ) {
- assertion = this.assertions[i];
-
- li = document.createElement( "li" );
- li.className = assertion.result ? "pass" : "fail";
- li.innerHTML = assertion.message || ( assertion.result ? "okay" : "failed" );
- ol.appendChild( li );
-
- if ( assertion.result ) {
- good++;
- } else {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
-
- // store result when possible
- if ( QUnit.config.reorder && defined.sessionStorage ) {
- if ( bad ) {
- sessionStorage.setItem( "qunit-test-" + this.module + "-" + this.testName, bad );
- } else {
- sessionStorage.removeItem( "qunit-test-" + this.module + "-" + this.testName );
- }
- }
-
- if ( bad === 0 ) {
- addClass( ol, "qunit-collapsed" );
- }
-
- // `b` initialized at top of scope
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml + " (" + bad + ", " + good + ", " + this.assertions.length + ")";
-
- addEvent(b, "click", function() {
- var next = b.parentNode.lastChild,
- collapsed = hasClass( next, "qunit-collapsed" );
- ( collapsed ? removeClass : addClass )( next, "qunit-collapsed" );
- });
-
- addEvent(b, "dblclick", function( e ) {
- var target = e && e.target ? e.target : window.event.srcElement;
- if ( target.nodeName.toLowerCase() === "span" || target.nodeName.toLowerCase() === "b" ) {
- target = target.parentNode;
- }
- if ( window.location && target.nodeName.toLowerCase() === "strong" ) {
- window.location = QUnit.url({ testNumber: test.testNumber });
- }
- });
-
- // `time` initialized at top of scope
- time = document.createElement( "span" );
- time.className = "runtime";
- time.innerHTML = this.runtime + " ms";
-
- // `li` initialized at top of scope
- li = id( this.id );
- li.className = bad ? "fail" : "pass";
- li.removeChild( li.firstChild );
- a = li.firstChild;
- li.appendChild( b );
- li.appendChild( a );
- li.appendChild( time );
- li.appendChild( ol );
-
- } else {
- for ( i = 0; i < this.assertions.length; i++ ) {
- if ( !this.assertions[i].result ) {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
- }
-
- runLoggingCallbacks( "testDone", QUnit, {
- name: this.testName,
- module: this.module,
- failed: bad,
- passed: this.assertions.length - bad,
- total: this.assertions.length,
- duration: this.runtime
- });
-
- QUnit.reset();
-
- config.current = undefined;
- },
-
- queue: function() {
- var bad,
- test = this;
-
- synchronize(function() {
- test.init();
- });
- function run() {
- // each of these can by async
- synchronize(function() {
- test.setup();
- });
- synchronize(function() {
- test.run();
- });
- synchronize(function() {
- test.teardown();
- });
- synchronize(function() {
- test.finish();
- });
- }
-
- // `bad` initialized at top of scope
- // defer when previous test run passed, if storage is available
- bad = QUnit.config.reorder && defined.sessionStorage &&
- +sessionStorage.getItem( "qunit-test-" + this.module + "-" + this.testName );
-
- if ( bad ) {
- run();
- } else {
- synchronize( run, true );
- }
- }
-};
-
-// Root QUnit object.
-// `QUnit` initialized at top of scope
-QUnit = {
-
- // call on start of module test to prepend name to all tests
- module: function( name, testEnvironment ) {
- config.currentModule = name;
- config.currentModuleTestEnvironment = testEnvironment;
- config.modules[name] = true;
- },
-
- asyncTest: function( testName, expected, callback ) {
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- QUnit.test( testName, expected, callback, true );
- },
-
- test: function( testName, expected, callback, async ) {
- var test,
- nameHtml = "" + escapeText( testName ) + "";
-
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- if ( config.currentModule ) {
- nameHtml = "" + escapeText( config.currentModule ) + ": " + nameHtml;
- }
-
- test = new Test({
- nameHtml: nameHtml,
- testName: testName,
- expected: expected,
- async: async,
- callback: callback,
- module: config.currentModule,
- moduleTestEnvironment: config.currentModuleTestEnvironment,
- stack: sourceFromStacktrace( 2 )
- });
-
- if ( !validTest( test ) ) {
- return;
- }
-
- test.queue();
- },
-
- // Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through.
- expect: function( asserts ) {
- if (arguments.length === 1) {
- config.current.expected = asserts;
- } else {
- return config.current.expected;
- }
- },
-
- start: function( count ) {
- // QUnit hasn't been initialized yet.
- // Note: RequireJS (et al) may delay onLoad
- if ( config.semaphore === undefined ) {
- QUnit.begin(function() {
- // This is triggered at the top of QUnit.load, push start() to the event loop, to allow QUnit.load to finish first
- setTimeout(function() {
- QUnit.start( count );
- });
- });
- return;
- }
-
- config.semaphore -= count || 1;
- // don't start until equal number of stop-calls
- if ( config.semaphore > 0 ) {
- return;
- }
- // ignore if start is called more often then stop
- if ( config.semaphore < 0 ) {
- config.semaphore = 0;
- QUnit.pushFailure( "Called start() while already started (QUnit.config.semaphore was 0 already)", null, sourceFromStacktrace(2) );
- return;
- }
- // A slight delay, to avoid any current callbacks
- if ( defined.setTimeout ) {
- window.setTimeout(function() {
- if ( config.semaphore > 0 ) {
- return;
- }
- if ( config.timeout ) {
- clearTimeout( config.timeout );
- }
-
- config.blocking = false;
- process( true );
- }, 13);
- } else {
- config.blocking = false;
- process( true );
- }
- },
-
- stop: function( count ) {
- config.semaphore += count || 1;
- config.blocking = true;
-
- if ( config.testTimeout && defined.setTimeout ) {
- clearTimeout( config.timeout );
- config.timeout = window.setTimeout(function() {
- QUnit.ok( false, "Test timed out" );
- config.semaphore = 1;
- QUnit.start();
- }, config.testTimeout );
- }
- }
-};
-
-// `assert` initialized at top of scope
-// Asssert helpers
-// All of these must either call QUnit.push() or manually do:
-// - runLoggingCallbacks( "log", .. );
-// - config.current.assertions.push({ .. });
-// We attach it to the QUnit object *after* we expose the public API,
-// otherwise `assert` will become a global variable in browsers (#341).
-assert = {
- /**
- * Asserts rough true-ish result.
- * @name ok
- * @function
- * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" );
- */
- ok: function( result, msg ) {
- if ( !config.current ) {
- throw new Error( "ok() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
- result = !!result;
-
- var source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: msg
- };
-
- msg = escapeText( msg || (result ? "okay" : "failed" ) );
- msg = "" + msg + "";
-
- if ( !result ) {
- source = sourceFromStacktrace( 2 );
- if ( source ) {
- details.source = source;
- msg += "Source: | " + escapeText( source ) + " |
---|
";
- }
- }
- runLoggingCallbacks( "log", QUnit, details );
- config.current.assertions.push({
- result: result,
- message: msg
- });
- },
-
- /**
- * Assert that the first two arguments are equal, with an optional message.
- * Prints out both actual and expected values.
- * @name equal
- * @function
- * @example equal( format( "Received {0} bytes.", 2), "Received 2 bytes.", "format() replaces {0} with next argument" );
- */
- equal: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected == actual, actual, expected, message );
- },
-
- /**
- * @name notEqual
- * @function
- */
- notEqual: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected != actual, actual, expected, message );
- },
-
- /**
- * @name propEqual
- * @function
- */
- propEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notPropEqual
- * @function
- */
- notPropEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name deepEqual
- * @function
- */
- deepEqual: function( actual, expected, message ) {
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notDeepEqual
- * @function
- */
- notDeepEqual: function( actual, expected, message ) {
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name strictEqual
- * @function
- */
- strictEqual: function( actual, expected, message ) {
- QUnit.push( expected === actual, actual, expected, message );
- },
-
- /**
- * @name notStrictEqual
- * @function
- */
- notStrictEqual: function( actual, expected, message ) {
- QUnit.push( expected !== actual, actual, expected, message );
- },
-
- "throws": function( block, expected, message ) {
- var actual,
- expectedOutput = expected,
- ok = false;
-
- // 'expected' is optional
- if ( typeof expected === "string" ) {
- message = expected;
- expected = null;
- }
-
- config.current.ignoreGlobalErrors = true;
- try {
- block.call( config.current.testEnvironment );
- } catch (e) {
- actual = e;
- }
- config.current.ignoreGlobalErrors = false;
-
- if ( actual ) {
- // we don't want to validate thrown error
- if ( !expected ) {
- ok = true;
- expectedOutput = null;
- // expected is a regexp
- } else if ( QUnit.objectType( expected ) === "regexp" ) {
- ok = expected.test( errorString( actual ) );
- // expected is a constructor
- } else if ( actual instanceof expected ) {
- ok = true;
- // expected is a validation function which returns true is validation passed
- } else if ( expected.call( {}, actual ) === true ) {
- expectedOutput = null;
- ok = true;
- }
-
- QUnit.push( ok, actual, expectedOutput, message );
- } else {
- QUnit.pushFailure( message, null, 'No exception was thrown.' );
- }
- }
-};
-
-/**
- * @deprecate since 1.8.0
- * Kept assertion helpers in root for backwards compatibility.
- */
-extend( QUnit, assert );
-
-/**
- * @deprecated since 1.9.0
- * Kept root "raises()" for backwards compatibility.
- * (Note that we don't introduce assert.raises).
- */
-QUnit.raises = assert[ "throws" ];
-
-/**
- * @deprecated since 1.0.0, replaced with error pushes since 1.3.0
- * Kept to avoid TypeErrors for undefined methods.
- */
-QUnit.equals = function() {
- QUnit.push( false, false, false, "QUnit.equals has been deprecated since 2009 (e88049a0), use QUnit.equal instead" );
-};
-QUnit.same = function() {
- QUnit.push( false, false, false, "QUnit.same has been deprecated since 2009 (e88049a0), use QUnit.deepEqual instead" );
-};
-
-// We want access to the constructor's prototype
-(function() {
- function F() {}
- F.prototype = QUnit;
- QUnit = new F();
- // Make F QUnit's constructor so that we can add to the prototype later
- QUnit.constructor = F;
-}());
-
-/**
- * Config object: Maintain internal state
- * Later exposed as QUnit.config
- * `config` initialized at top of scope
- */
-config = {
- // The queue of tests to run
- queue: [],
-
- // block until document ready
- blocking: true,
-
- // when enabled, show only failing tests
- // gets persisted through sessionStorage and can be changed in UI via checkbox
- hidepassed: false,
-
- // by default, run previously failed tests first
- // very useful in combination with "Hide passed tests" checked
- reorder: true,
-
- // by default, modify document.title when suite is done
- altertitle: true,
-
- // when enabled, all tests must call expect()
- requireExpects: false,
-
- // add checkboxes that are persisted in the query-string
- // when enabled, the id is set to `true` as a `QUnit.config` property
- urlConfig: [
- {
- id: "noglobals",
- label: "Check for Globals",
- tooltip: "Enabling this will test if any test introduces new properties on the `window` object. Stored as query-strings."
- },
- {
- id: "notrycatch",
- label: "No try-catch",
- tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging exceptions in IE reasonable. Stored as query-strings."
- }
- ],
-
- // Set of all modules.
- modules: {},
-
- // logging callback queues
- begin: [],
- done: [],
- log: [],
- testStart: [],
- testDone: [],
- moduleStart: [],
- moduleDone: []
-};
-
-// Export global variables, unless an 'exports' object exists,
-// in that case we assume we're in CommonJS (dealt with on the bottom of the script)
-if ( typeof exports === "undefined" ) {
- extend( window, QUnit );
-
- // Expose QUnit object
- window.QUnit = QUnit;
-}
-
-// Initialize more QUnit.config and QUnit.urlParams
-(function() {
- var i,
- location = window.location || { search: "", protocol: "file:" },
- params = location.search.slice( 1 ).split( "&" ),
- length = params.length,
- urlParams = {},
- current;
-
- if ( params[ 0 ] ) {
- for ( i = 0; i < length; i++ ) {
- current = params[ i ].split( "=" );
- current[ 0 ] = decodeURIComponent( current[ 0 ] );
- // allow just a key to turn on a flag, e.g., test.html?noglobals
- current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true;
- urlParams[ current[ 0 ] ] = current[ 1 ];
- }
- }
-
- QUnit.urlParams = urlParams;
-
- // String search anywhere in moduleName+testName
- config.filter = urlParams.filter;
-
- // Exact match of the module name
- config.module = urlParams.module;
-
- config.testNumber = parseInt( urlParams.testNumber, 10 ) || null;
-
- // Figure out if we're running the tests from a server or not
- QUnit.isLocal = location.protocol === "file:";
-}());
-
-// Extend QUnit object,
-// these after set here because they should not be exposed as global functions
-extend( QUnit, {
- assert: assert,
-
- config: config,
-
- // Initialize the configuration options
- init: function() {
- extend( config, {
- stats: { all: 0, bad: 0 },
- moduleStats: { all: 0, bad: 0 },
- started: +new Date(),
- updateRate: 1000,
- blocking: false,
- autostart: true,
- autorun: false,
- filter: "",
- queue: [],
- semaphore: 1
- });
-
- var tests, banner, result,
- qunit = id( "qunit" );
-
- if ( qunit ) {
- qunit.innerHTML =
- "" +
- "" +
- "" +
- "" +
- "
";
- }
-
- tests = id( "qunit-tests" );
- banner = id( "qunit-banner" );
- result = id( "qunit-testresult" );
-
- if ( tests ) {
- tests.innerHTML = "";
- }
-
- if ( banner ) {
- banner.className = "";
- }
-
- if ( result ) {
- result.parentNode.removeChild( result );
- }
-
- if ( tests ) {
- result = document.createElement( "p" );
- result.id = "qunit-testresult";
- result.className = "result";
- tests.parentNode.insertBefore( result, tests );
- result.innerHTML = "Running...
";
- }
- },
-
- // Resets the test setup. Useful for tests that modify the DOM.
- reset: function() {
- var fixture = id( "qunit-fixture" );
- if ( fixture ) {
- fixture.innerHTML = config.fixture;
- }
- },
-
- // Trigger an event on an element.
- // @example triggerEvent( document.body, "click" );
- triggerEvent: function( elem, type, event ) {
- if ( document.createEvent ) {
- event = document.createEvent( "MouseEvents" );
- event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView,
- 0, 0, 0, 0, 0, false, false, false, false, 0, null);
-
- elem.dispatchEvent( event );
- } else if ( elem.fireEvent ) {
- elem.fireEvent( "on" + type );
- }
- },
-
- // Safe object type checking
- is: function( type, obj ) {
- return QUnit.objectType( obj ) === type;
- },
-
- objectType: function( obj ) {
- if ( typeof obj === "undefined" ) {
- return "undefined";
- // consider: typeof null === object
- }
- if ( obj === null ) {
- return "null";
- }
-
- var match = toString.call( obj ).match(/^\[object\s(.*)\]$/),
- type = match && match[1] || "";
-
- switch ( type ) {
- case "Number":
- if ( isNaN(obj) ) {
- return "nan";
- }
- return "number";
- case "String":
- case "Boolean":
- case "Array":
- case "Date":
- case "RegExp":
- case "Function":
- return type.toLowerCase();
- }
- if ( typeof obj === "object" ) {
- return "object";
- }
- return undefined;
- },
-
- push: function( result, actual, expected, message ) {
- if ( !config.current ) {
- throw new Error( "assertion outside test context, was " + sourceFromStacktrace() );
- }
-
- var output, source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: message,
- actual: actual,
- expected: expected
- };
-
- message = escapeText( message ) || ( result ? "okay" : "failed" );
- message = "" + message + "";
- output = message;
-
- if ( !result ) {
- expected = escapeText( QUnit.jsDump.parse(expected) );
- actual = escapeText( QUnit.jsDump.parse(actual) );
- output += "Expected: | " + expected + " |
";
-
- if ( actual !== expected ) {
- output += "Result: | " + actual + " |
";
- output += "Diff: | " + QUnit.diff( expected, actual ) + " |
";
- }
-
- source = sourceFromStacktrace();
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
- }
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: !!result,
- message: output
- });
- },
-
- pushFailure: function( message, source, actual ) {
- if ( !config.current ) {
- throw new Error( "pushFailure() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
-
- var output,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: false,
- message: message
- };
-
- message = escapeText( message ) || "error";
- message = "" + message + "";
- output = message;
-
- output += "";
-
- if ( actual ) {
- output += "Result: | " + escapeText( actual ) + " |
";
- }
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: false,
- message: output
- });
- },
-
- url: function( params ) {
- params = extend( extend( {}, QUnit.urlParams ), params );
- var key,
- querystring = "?";
-
- for ( key in params ) {
- if ( !hasOwn.call( params, key ) ) {
- continue;
- }
- querystring += encodeURIComponent( key ) + "=" +
- encodeURIComponent( params[ key ] ) + "&";
- }
- return window.location.protocol + "//" + window.location.host +
- window.location.pathname + querystring.slice( 0, -1 );
- },
-
- extend: extend,
- id: id,
- addEvent: addEvent
- // load, equiv, jsDump, diff: Attached later
-});
-
-/**
- * @deprecated: Created for backwards compatibility with test runner that set the hook function
- * into QUnit.{hook}, instead of invoking it and passing the hook function.
- * QUnit.constructor is set to the empty F() above so that we can add to it's prototype here.
- * Doing this allows us to tell if the following methods have been overwritten on the actual
- * QUnit object.
- */
-extend( QUnit.constructor.prototype, {
-
- // Logging callbacks; all receive a single argument with the listed properties
- // run test/logs.html for any related changes
- begin: registerLoggingCallback( "begin" ),
-
- // done: { failed, passed, total, runtime }
- done: registerLoggingCallback( "done" ),
-
- // log: { result, actual, expected, message }
- log: registerLoggingCallback( "log" ),
-
- // testStart: { name }
- testStart: registerLoggingCallback( "testStart" ),
-
- // testDone: { name, failed, passed, total, duration }
- testDone: registerLoggingCallback( "testDone" ),
-
- // moduleStart: { name }
- moduleStart: registerLoggingCallback( "moduleStart" ),
-
- // moduleDone: { name, failed, passed, total }
- moduleDone: registerLoggingCallback( "moduleDone" )
-});
-
-if ( typeof document === "undefined" || document.readyState === "complete" ) {
- config.autorun = true;
-}
-
-QUnit.load = function() {
- runLoggingCallbacks( "begin", QUnit, {} );
-
- // Initialize the config, saving the execution queue
- var banner, filter, i, label, len, main, ol, toolbar, userAgent, val,
- urlConfigCheckboxesContainer, urlConfigCheckboxes, moduleFilter,
- numModules = 0,
- moduleFilterHtml = "",
- urlConfigHtml = "",
- oldconfig = extend( {}, config );
-
- QUnit.init();
- extend(config, oldconfig);
-
- config.blocking = false;
-
- len = config.urlConfig.length;
-
- for ( i = 0; i < len; i++ ) {
- val = config.urlConfig[i];
- if ( typeof val === "string" ) {
- val = {
- id: val,
- label: val,
- tooltip: "[no tooltip available]"
- };
- }
- config[ val.id ] = QUnit.urlParams[ val.id ];
- urlConfigHtml += "";
- }
-
- moduleFilterHtml += "";
-
- // `userAgent` initialized at top of scope
- userAgent = id( "qunit-userAgent" );
- if ( userAgent ) {
- userAgent.innerHTML = navigator.userAgent;
- }
-
- // `banner` initialized at top of scope
- banner = id( "qunit-header" );
- if ( banner ) {
- banner.innerHTML = "" + banner.innerHTML + " ";
- }
-
- // `toolbar` initialized at top of scope
- toolbar = id( "qunit-testrunner-toolbar" );
- if ( toolbar ) {
- // `filter` initialized at top of scope
- filter = document.createElement( "input" );
- filter.type = "checkbox";
- filter.id = "qunit-filter-pass";
-
- addEvent( filter, "click", function() {
- var tmp,
- ol = document.getElementById( "qunit-tests" );
-
- if ( filter.checked ) {
- ol.className = ol.className + " hidepass";
- } else {
- tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " ";
- ol.className = tmp.replace( / hidepass /, " " );
- }
- if ( defined.sessionStorage ) {
- if (filter.checked) {
- sessionStorage.setItem( "qunit-filter-passed-tests", "true" );
- } else {
- sessionStorage.removeItem( "qunit-filter-passed-tests" );
- }
- }
- });
-
- if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem( "qunit-filter-passed-tests" ) ) {
- filter.checked = true;
- // `ol` initialized at top of scope
- ol = document.getElementById( "qunit-tests" );
- ol.className = ol.className + " hidepass";
- }
- toolbar.appendChild( filter );
-
- // `label` initialized at top of scope
- label = document.createElement( "label" );
- label.setAttribute( "for", "qunit-filter-pass" );
- label.setAttribute( "title", "Only show tests and assertons that fail. Stored in sessionStorage." );
- label.innerHTML = "Hide passed tests";
- toolbar.appendChild( label );
-
- urlConfigCheckboxesContainer = document.createElement("span");
- urlConfigCheckboxesContainer.innerHTML = urlConfigHtml;
- urlConfigCheckboxes = urlConfigCheckboxesContainer.getElementsByTagName("input");
- // For oldIE support:
- // * Add handlers to the individual elements instead of the container
- // * Use "click" instead of "change"
- // * Fallback from event.target to event.srcElement
- addEvents( urlConfigCheckboxes, "click", function( event ) {
- var params = {},
- target = event.target || event.srcElement;
- params[ target.name ] = target.checked ? true : undefined;
- window.location = QUnit.url( params );
- });
- toolbar.appendChild( urlConfigCheckboxesContainer );
-
- if (numModules > 1) {
- moduleFilter = document.createElement( 'span' );
- moduleFilter.setAttribute( 'id', 'qunit-modulefilter-container' );
- moduleFilter.innerHTML = moduleFilterHtml;
- addEvent( moduleFilter.lastChild, "change", function() {
- var selectBox = moduleFilter.getElementsByTagName("select")[0],
- selectedModule = decodeURIComponent(selectBox.options[selectBox.selectedIndex].value);
-
- window.location = QUnit.url( { module: ( selectedModule === "" ) ? undefined : selectedModule } );
- });
- toolbar.appendChild(moduleFilter);
- }
- }
-
- // `main` initialized at top of scope
- main = id( "qunit-fixture" );
- if ( main ) {
- config.fixture = main.innerHTML;
- }
-
- if ( config.autostart ) {
- QUnit.start();
- }
-};
-
-addEvent( window, "load", QUnit.load );
-
-// `onErrorFnPrev` initialized at top of scope
-// Preserve other handlers
-onErrorFnPrev = window.onerror;
-
-// Cover uncaught exceptions
-// Returning true will surpress the default browser handler,
-// returning false will let it run.
-window.onerror = function ( error, filePath, linerNr ) {
- var ret = false;
- if ( onErrorFnPrev ) {
- ret = onErrorFnPrev( error, filePath, linerNr );
- }
-
- // Treat return value as window.onerror itself does,
- // Only do our handling if not surpressed.
- if ( ret !== true ) {
- if ( QUnit.config.current ) {
- if ( QUnit.config.current.ignoreGlobalErrors ) {
- return true;
- }
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- } else {
- QUnit.test( "global failure", extend( function() {
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- }, { validTest: validTest } ) );
- }
- return false;
- }
-
- return ret;
-};
-
-function done() {
- config.autorun = true;
-
- // Log the last module results
- if ( config.currentModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.currentModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
-
- var i, key,
- banner = id( "qunit-banner" ),
- tests = id( "qunit-tests" ),
- runtime = +new Date() - config.started,
- passed = config.stats.all - config.stats.bad,
- html = [
- "Tests completed in ",
- runtime,
- " milliseconds.
",
- "",
- passed,
- " assertions of ",
- config.stats.all,
- " passed, ",
- config.stats.bad,
- " failed."
- ].join( "" );
-
- if ( banner ) {
- banner.className = ( config.stats.bad ? "qunit-fail" : "qunit-pass" );
- }
-
- if ( tests ) {
- id( "qunit-testresult" ).innerHTML = html;
- }
-
- if ( config.altertitle && typeof document !== "undefined" && document.title ) {
- // show ✖ for good, ✔ for bad suite result in title
- // use escape sequences in case file gets loaded with non-utf-8-charset
- document.title = [
- ( config.stats.bad ? "\u2716" : "\u2714" ),
- document.title.replace( /^[\u2714\u2716] /i, "" )
- ].join( " " );
- }
-
- // clear own sessionStorage items if all tests passed
- if ( config.reorder && defined.sessionStorage && config.stats.bad === 0 ) {
- // `key` & `i` initialized at top of scope
- for ( i = 0; i < sessionStorage.length; i++ ) {
- key = sessionStorage.key( i++ );
- if ( key.indexOf( "qunit-test-" ) === 0 ) {
- sessionStorage.removeItem( key );
- }
- }
- }
-
- // scroll back to top to show results
- if ( window.scrollTo ) {
- window.scrollTo(0, 0);
- }
-
- runLoggingCallbacks( "done", QUnit, {
- failed: config.stats.bad,
- passed: passed,
- total: config.stats.all,
- runtime: runtime
- });
-}
-
-/** @return Boolean: true if this test should be ran */
-function validTest( test ) {
- var include,
- filter = config.filter && config.filter.toLowerCase(),
- module = config.module && config.module.toLowerCase(),
- fullName = (test.module + ": " + test.testName).toLowerCase();
-
- // Internally-generated tests are always valid
- if ( test.callback && test.callback.validTest === validTest ) {
- delete test.callback.validTest;
- return true;
- }
-
- if ( config.testNumber ) {
- return test.testNumber === config.testNumber;
- }
-
- if ( module && ( !test.module || test.module.toLowerCase() !== module ) ) {
- return false;
- }
-
- if ( !filter ) {
- return true;
- }
-
- include = filter.charAt( 0 ) !== "!";
- if ( !include ) {
- filter = filter.slice( 1 );
- }
-
- // If the filter matches, we need to honour include
- if ( fullName.indexOf( filter ) !== -1 ) {
- return include;
- }
-
- // Otherwise, do the opposite
- return !include;
-}
-
-// so far supports only Firefox, Chrome and Opera (buggy), Safari (for real exceptions)
-// Later Safari and IE10 are supposed to support error.stack as well
-// See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack
-function extractStacktrace( e, offset ) {
- offset = offset === undefined ? 3 : offset;
-
- var stack, include, i;
-
- if ( e.stacktrace ) {
- // Opera
- return e.stacktrace.split( "\n" )[ offset + 3 ];
- } else if ( e.stack ) {
- // Firefox, Chrome
- stack = e.stack.split( "\n" );
- if (/^error$/i.test( stack[0] ) ) {
- stack.shift();
- }
- if ( fileName ) {
- include = [];
- for ( i = offset; i < stack.length; i++ ) {
- if ( stack[ i ].indexOf( fileName ) !== -1 ) {
- break;
- }
- include.push( stack[ i ] );
- }
- if ( include.length ) {
- return include.join( "\n" );
- }
- }
- return stack[ offset ];
- } else if ( e.sourceURL ) {
- // Safari, PhantomJS
- // hopefully one day Safari provides actual stacktraces
- // exclude useless self-reference for generated Error objects
- if ( /qunit.js$/.test( e.sourceURL ) ) {
- return;
- }
- // for actual exceptions, this is useful
- return e.sourceURL + ":" + e.line;
- }
-}
-function sourceFromStacktrace( offset ) {
- try {
- throw new Error();
- } catch ( e ) {
- return extractStacktrace( e, offset );
- }
-}
-
-/**
- * Escape text for attribute or text content.
- */
-function escapeText( s ) {
- if ( !s ) {
- return "";
- }
- s = s + "";
- // Both single quotes and double quotes (for attributes)
- return s.replace( /['"<>&]/g, function( s ) {
- switch( s ) {
- case '\'':
- return ''';
- case '"':
- return '"';
- case '<':
- return '<';
- case '>':
- return '>';
- case '&':
- return '&';
- }
- });
-}
-
-function synchronize( callback, last ) {
- config.queue.push( callback );
-
- if ( config.autorun && !config.blocking ) {
- process( last );
- }
-}
-
-function process( last ) {
- function next() {
- process( last );
- }
- var start = new Date().getTime();
- config.depth = config.depth ? config.depth + 1 : 1;
-
- while ( config.queue.length && !config.blocking ) {
- if ( !defined.setTimeout || config.updateRate <= 0 || ( ( new Date().getTime() - start ) < config.updateRate ) ) {
- config.queue.shift()();
- } else {
- window.setTimeout( next, 13 );
- break;
- }
- }
- config.depth--;
- if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) {
- done();
- }
-}
-
-function saveGlobal() {
- config.pollution = [];
-
- if ( config.noglobals ) {
- for ( var key in window ) {
- // in Opera sometimes DOM element ids show up here, ignore them
- if ( !hasOwn.call( window, key ) || /^qunit-test-output/.test( key ) ) {
- continue;
- }
- config.pollution.push( key );
- }
- }
-}
-
-function checkPollution() {
- var newGlobals,
- deletedGlobals,
- old = config.pollution;
-
- saveGlobal();
-
- newGlobals = diff( config.pollution, old );
- if ( newGlobals.length > 0 ) {
- QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join(", ") );
- }
-
- deletedGlobals = diff( old, config.pollution );
- if ( deletedGlobals.length > 0 ) {
- QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join(", ") );
- }
-}
-
-// returns a new Array with the elements that are in a but not in b
-function diff( a, b ) {
- var i, j,
- result = a.slice();
-
- for ( i = 0; i < result.length; i++ ) {
- for ( j = 0; j < b.length; j++ ) {
- if ( result[i] === b[j] ) {
- result.splice( i, 1 );
- i--;
- break;
- }
- }
- }
- return result;
-}
-
-function extend( a, b ) {
- for ( var prop in b ) {
- if ( b[ prop ] === undefined ) {
- delete a[ prop ];
-
- // Avoid "Member not found" error in IE8 caused by setting window.constructor
- } else if ( prop !== "constructor" || a !== window ) {
- a[ prop ] = b[ prop ];
- }
- }
-
- return a;
-}
-
-/**
- * @param {HTMLElement} elem
- * @param {string} type
- * @param {Function} fn
- */
-function addEvent( elem, type, fn ) {
- // Standards-based browsers
- if ( elem.addEventListener ) {
- elem.addEventListener( type, fn, false );
- // IE
- } else {
- elem.attachEvent( "on" + type, fn );
- }
-}
-
-/**
- * @param {Array|NodeList} elems
- * @param {string} type
- * @param {Function} fn
- */
-function addEvents( elems, type, fn ) {
- var i = elems.length;
- while ( i-- ) {
- addEvent( elems[i], type, fn );
- }
-}
-
-function hasClass( elem, name ) {
- return (" " + elem.className + " ").indexOf(" " + name + " ") > -1;
-}
-
-function addClass( elem, name ) {
- if ( !hasClass( elem, name ) ) {
- elem.className += (elem.className ? " " : "") + name;
- }
-}
-
-function removeClass( elem, name ) {
- var set = " " + elem.className + " ";
- // Class name may appear multiple times
- while ( set.indexOf(" " + name + " ") > -1 ) {
- set = set.replace(" " + name + " " , " ");
- }
- // If possible, trim it for prettiness, but not neccecarily
- elem.className = window.jQuery ? jQuery.trim( set ) : ( set.trim ? set.trim() : set );
-}
-
-function id( name ) {
- return !!( typeof document !== "undefined" && document && document.getElementById ) &&
- document.getElementById( name );
-}
-
-function registerLoggingCallback( key ) {
- return function( callback ) {
- config[key].push( callback );
- };
-}
-
-// Supports deprecated method of completely overwriting logging callbacks
-function runLoggingCallbacks( key, scope, args ) {
- var i, callbacks;
- if ( QUnit.hasOwnProperty( key ) ) {
- QUnit[ key ].call(scope, args );
- } else {
- callbacks = config[ key ];
- for ( i = 0; i < callbacks.length; i++ ) {
- callbacks[ i ].call( scope, args );
- }
- }
-}
-
-// Test for equality any JavaScript type.
-// Author: Philippe Rathé
-QUnit.equiv = (function() {
-
- // Call the o related callback with the given arguments.
- function bindCallbacks( o, callbacks, args ) {
- var prop = QUnit.objectType( o );
- if ( prop ) {
- if ( QUnit.objectType( callbacks[ prop ] ) === "function" ) {
- return callbacks[ prop ].apply( callbacks, args );
- } else {
- return callbacks[ prop ]; // or undefined
- }
- }
- }
-
- // the real equiv function
- var innerEquiv,
- // stack to decide between skip/abort functions
- callers = [],
- // stack to avoiding loops from circular referencing
- parents = [],
-
- getProto = Object.getPrototypeOf || function ( obj ) {
- return obj.__proto__;
- },
- callbacks = (function () {
-
- // for string, boolean, number and null
- function useStrictEquality( b, a ) {
- /*jshint eqeqeq:false */
- if ( b instanceof a.constructor || a instanceof b.constructor ) {
- // to catch short annotaion VS 'new' annotation of a
- // declaration
- // e.g. var i = 1;
- // var j = new Number(1);
- return a == b;
- } else {
- return a === b;
- }
- }
-
- return {
- "string": useStrictEquality,
- "boolean": useStrictEquality,
- "number": useStrictEquality,
- "null": useStrictEquality,
- "undefined": useStrictEquality,
-
- "nan": function( b ) {
- return isNaN( b );
- },
-
- "date": function( b, a ) {
- return QUnit.objectType( b ) === "date" && a.valueOf() === b.valueOf();
- },
-
- "regexp": function( b, a ) {
- return QUnit.objectType( b ) === "regexp" &&
- // the regex itself
- a.source === b.source &&
- // and its modifers
- a.global === b.global &&
- // (gmi) ...
- a.ignoreCase === b.ignoreCase &&
- a.multiline === b.multiline &&
- a.sticky === b.sticky;
- },
-
- // - skip when the property is a method of an instance (OOP)
- // - abort otherwise,
- // initial === would have catch identical references anyway
- "function": function() {
- var caller = callers[callers.length - 1];
- return caller !== Object && typeof caller !== "undefined";
- },
-
- "array": function( b, a ) {
- var i, j, len, loop;
-
- // b could be an object literal here
- if ( QUnit.objectType( b ) !== "array" ) {
- return false;
- }
-
- len = a.length;
- if ( len !== b.length ) {
- // safe and faster
- return false;
- }
-
- // track reference to avoid circular references
- parents.push( a );
- for ( i = 0; i < len; i++ ) {
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- loop = true;// dont rewalk array
- }
- }
- if ( !loop && !innerEquiv(a[i], b[i]) ) {
- parents.pop();
- return false;
- }
- }
- parents.pop();
- return true;
- },
-
- "object": function( b, a ) {
- var i, j, loop,
- // Default to true
- eq = true,
- aProperties = [],
- bProperties = [];
-
- // comparing constructors is more strict than using
- // instanceof
- if ( a.constructor !== b.constructor ) {
- // Allow objects with no prototype to be equivalent to
- // objects with Object as their constructor.
- if ( !(( getProto(a) === null && getProto(b) === Object.prototype ) ||
- ( getProto(b) === null && getProto(a) === Object.prototype ) ) ) {
- return false;
- }
- }
-
- // stack constructor before traversing properties
- callers.push( a.constructor );
- // track reference to avoid circular references
- parents.push( a );
-
- for ( i in a ) { // be strict: don't ensures hasOwnProperty
- // and go deep
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- // don't go down the same path twice
- loop = true;
- }
- }
- aProperties.push(i); // collect a's properties
-
- if (!loop && !innerEquiv( a[i], b[i] ) ) {
- eq = false;
- break;
- }
- }
-
- callers.pop(); // unstack, we are done
- parents.pop();
-
- for ( i in b ) {
- bProperties.push( i ); // collect b's properties
- }
-
- // Ensures identical properties name
- return eq && innerEquiv( aProperties.sort(), bProperties.sort() );
- }
- };
- }());
-
- innerEquiv = function() { // can take multiple arguments
- var args = [].slice.apply( arguments );
- if ( args.length < 2 ) {
- return true; // end transition
- }
-
- return (function( a, b ) {
- if ( a === b ) {
- return true; // catch the most you can
- } else if ( a === null || b === null || typeof a === "undefined" ||
- typeof b === "undefined" ||
- QUnit.objectType(a) !== QUnit.objectType(b) ) {
- return false; // don't lose time with error prone cases
- } else {
- return bindCallbacks(a, callbacks, [ b, a ]);
- }
-
- // apply transition with (1..n) arguments
- }( args[0], args[1] ) && arguments.callee.apply( this, args.splice(1, args.length - 1 )) );
- };
-
- return innerEquiv;
-}());
-
-/**
- * jsDump Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com |
- * http://flesler.blogspot.com Licensed under BSD
- * (http://www.opensource.org/licenses/bsd-license.php) Date: 5/15/2008
- *
- * @projectDescription Advanced and extensible data dumping for Javascript.
- * @version 1.0.0
- * @author Ariel Flesler
- * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html}
- */
-QUnit.jsDump = (function() {
- function quote( str ) {
- return '"' + str.toString().replace( /"/g, '\\"' ) + '"';
- }
- function literal( o ) {
- return o + "";
- }
- function join( pre, arr, post ) {
- var s = jsDump.separator(),
- base = jsDump.indent(),
- inner = jsDump.indent(1);
- if ( arr.join ) {
- arr = arr.join( "," + s + inner );
- }
- if ( !arr ) {
- return pre + post;
- }
- return [ pre, inner + arr, base + post ].join(s);
- }
- function array( arr, stack ) {
- var i = arr.length, ret = new Array(i);
- this.up();
- while ( i-- ) {
- ret[i] = this.parse( arr[i] , undefined , stack);
- }
- this.down();
- return join( "[", ret, "]" );
- }
-
- var reName = /^function (\w+)/,
- jsDump = {
- // type is used mostly internally, you can fix a (custom)type in advance
- parse: function( obj, type, stack ) {
- stack = stack || [ ];
- var inStack, res,
- parser = this.parsers[ type || this.typeOf(obj) ];
-
- type = typeof parser;
- inStack = inArray( obj, stack );
-
- if ( inStack !== -1 ) {
- return "recursion(" + (inStack - stack.length) + ")";
- }
- if ( type === "function" ) {
- stack.push( obj );
- res = parser.call( this, obj, stack );
- stack.pop();
- return res;
- }
- return ( type === "string" ) ? parser : this.parsers.error;
- },
- typeOf: function( obj ) {
- var type;
- if ( obj === null ) {
- type = "null";
- } else if ( typeof obj === "undefined" ) {
- type = "undefined";
- } else if ( QUnit.is( "regexp", obj) ) {
- type = "regexp";
- } else if ( QUnit.is( "date", obj) ) {
- type = "date";
- } else if ( QUnit.is( "function", obj) ) {
- type = "function";
- } else if ( typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined" ) {
- type = "window";
- } else if ( obj.nodeType === 9 ) {
- type = "document";
- } else if ( obj.nodeType ) {
- type = "node";
- } else if (
- // native arrays
- toString.call( obj ) === "[object Array]" ||
- // NodeList objects
- ( typeof obj.length === "number" && typeof obj.item !== "undefined" && ( obj.length ? obj.item(0) === obj[0] : ( obj.item( 0 ) === null && typeof obj[0] === "undefined" ) ) )
- ) {
- type = "array";
- } else if ( obj.constructor === Error.prototype.constructor ) {
- type = "error";
- } else {
- type = typeof obj;
- }
- return type;
- },
- separator: function() {
- return this.multiline ? this.HTML ? "
" : "\n" : this.HTML ? " " : " ";
- },
- // extra can be a number, shortcut for increasing-calling-decreasing
- indent: function( extra ) {
- if ( !this.multiline ) {
- return "";
- }
- var chr = this.indentChar;
- if ( this.HTML ) {
- chr = chr.replace( /\t/g, " " ).replace( / /g, " " );
- }
- return new Array( this._depth_ + (extra||0) ).join(chr);
- },
- up: function( a ) {
- this._depth_ += a || 1;
- },
- down: function( a ) {
- this._depth_ -= a || 1;
- },
- setParser: function( name, parser ) {
- this.parsers[name] = parser;
- },
- // The next 3 are exposed so you can use them
- quote: quote,
- literal: literal,
- join: join,
- //
- _depth_: 1,
- // This is the list of parsers, to modify them, use jsDump.setParser
- parsers: {
- window: "[Window]",
- document: "[Document]",
- error: function(error) {
- return "Error(\"" + error.message + "\")";
- },
- unknown: "[Unknown]",
- "null": "null",
- "undefined": "undefined",
- "function": function( fn ) {
- var ret = "function",
- // functions never have name in IE
- name = "name" in fn ? fn.name : (reName.exec(fn) || [])[1];
-
- if ( name ) {
- ret += " " + name;
- }
- ret += "( ";
-
- ret = [ ret, QUnit.jsDump.parse( fn, "functionArgs" ), "){" ].join( "" );
- return join( ret, QUnit.jsDump.parse(fn,"functionCode" ), "}" );
- },
- array: array,
- nodelist: array,
- "arguments": array,
- object: function( map, stack ) {
- var ret = [ ], keys, key, val, i;
- QUnit.jsDump.up();
- keys = [];
- for ( key in map ) {
- keys.push( key );
- }
- keys.sort();
- for ( i = 0; i < keys.length; i++ ) {
- key = keys[ i ];
- val = map[ key ];
- ret.push( QUnit.jsDump.parse( key, "key" ) + ": " + QUnit.jsDump.parse( val, undefined, stack ) );
- }
- QUnit.jsDump.down();
- return join( "{", ret, "}" );
- },
- node: function( node ) {
- var len, i, val,
- open = QUnit.jsDump.HTML ? "<" : "<",
- close = QUnit.jsDump.HTML ? ">" : ">",
- tag = node.nodeName.toLowerCase(),
- ret = open + tag,
- attrs = node.attributes;
-
- if ( attrs ) {
- for ( i = 0, len = attrs.length; i < len; i++ ) {
- val = attrs[i].nodeValue;
- // IE6 includes all attributes in .attributes, even ones not explicitly set.
- // Those have values like undefined, null, 0, false, "" or "inherit".
- if ( val && val !== "inherit" ) {
- ret += " " + attrs[i].nodeName + "=" + QUnit.jsDump.parse( val, "attribute" );
- }
- }
- }
- ret += close;
-
- // Show content of TextNode or CDATASection
- if ( node.nodeType === 3 || node.nodeType === 4 ) {
- ret += node.nodeValue;
- }
-
- return ret + open + "/" + tag + close;
- },
- // function calls it internally, it's the arguments part of the function
- functionArgs: function( fn ) {
- var args,
- l = fn.length;
-
- if ( !l ) {
- return "";
- }
-
- args = new Array(l);
- while ( l-- ) {
- // 97 is 'a'
- args[l] = String.fromCharCode(97+l);
- }
- return " " + args.join( ", " ) + " ";
- },
- // object calls it internally, the key part of an item in a map
- key: quote,
- // function calls it internally, it's the content of the function
- functionCode: "[code]",
- // node calls it internally, it's an html attribute value
- attribute: quote,
- string: quote,
- date: quote,
- regexp: literal,
- number: literal,
- "boolean": literal
- },
- // if true, entities are escaped ( <, >, \t, space and \n )
- HTML: false,
- // indentation unit
- indentChar: " ",
- // if true, items in a collection, are separated by a \n, else just a space.
- multiline: true
- };
-
- return jsDump;
-}());
-
-// from jquery.js
-function inArray( elem, array ) {
- if ( array.indexOf ) {
- return array.indexOf( elem );
- }
-
- for ( var i = 0, length = array.length; i < length; i++ ) {
- if ( array[ i ] === elem ) {
- return i;
- }
- }
-
- return -1;
-}
-
-/*
- * Javascript Diff Algorithm
- * By John Resig (http://ejohn.org/)
- * Modified by Chu Alan "sprite"
- *
- * Released under the MIT license.
- *
- * More Info:
- * http://ejohn.org/projects/javascript-diff-algorithm/
- *
- * Usage: QUnit.diff(expected, actual)
- *
- * QUnit.diff( "the quick brown fox jumped over", "the quick fox jumps over" ) == "the quick brown fox jumped jumps over"
- */
-QUnit.diff = (function() {
- /*jshint eqeqeq:false, eqnull:true */
- function diff( o, n ) {
- var i,
- ns = {},
- os = {};
-
- for ( i = 0; i < n.length; i++ ) {
- if ( !hasOwn.call( ns, n[i] ) ) {
- ns[ n[i] ] = {
- rows: [],
- o: null
- };
- }
- ns[ n[i] ].rows.push( i );
- }
-
- for ( i = 0; i < o.length; i++ ) {
- if ( !hasOwn.call( os, o[i] ) ) {
- os[ o[i] ] = {
- rows: [],
- n: null
- };
- }
- os[ o[i] ].rows.push( i );
- }
-
- for ( i in ns ) {
- if ( !hasOwn.call( ns, i ) ) {
- continue;
- }
- if ( ns[i].rows.length === 1 && hasOwn.call( os, i ) && os[i].rows.length === 1 ) {
- n[ ns[i].rows[0] ] = {
- text: n[ ns[i].rows[0] ],
- row: os[i].rows[0]
- };
- o[ os[i].rows[0] ] = {
- text: o[ os[i].rows[0] ],
- row: ns[i].rows[0]
- };
- }
- }
-
- for ( i = 0; i < n.length - 1; i++ ) {
- if ( n[i].text != null && n[ i + 1 ].text == null && n[i].row + 1 < o.length && o[ n[i].row + 1 ].text == null &&
- n[ i + 1 ] == o[ n[i].row + 1 ] ) {
-
- n[ i + 1 ] = {
- text: n[ i + 1 ],
- row: n[i].row + 1
- };
- o[ n[i].row + 1 ] = {
- text: o[ n[i].row + 1 ],
- row: i + 1
- };
- }
- }
-
- for ( i = n.length - 1; i > 0; i-- ) {
- if ( n[i].text != null && n[ i - 1 ].text == null && n[i].row > 0 && o[ n[i].row - 1 ].text == null &&
- n[ i - 1 ] == o[ n[i].row - 1 ]) {
-
- n[ i - 1 ] = {
- text: n[ i - 1 ],
- row: n[i].row - 1
- };
- o[ n[i].row - 1 ] = {
- text: o[ n[i].row - 1 ],
- row: i - 1
- };
- }
- }
-
- return {
- o: o,
- n: n
- };
- }
-
- return function( o, n ) {
- o = o.replace( /\s+$/, "" );
- n = n.replace( /\s+$/, "" );
-
- var i, pre,
- str = "",
- out = diff( o === "" ? [] : o.split(/\s+/), n === "" ? [] : n.split(/\s+/) ),
- oSpace = o.match(/\s+/g),
- nSpace = n.match(/\s+/g);
-
- if ( oSpace == null ) {
- oSpace = [ " " ];
- }
- else {
- oSpace.push( " " );
- }
-
- if ( nSpace == null ) {
- nSpace = [ " " ];
- }
- else {
- nSpace.push( " " );
- }
-
- if ( out.n.length === 0 ) {
- for ( i = 0; i < out.o.length; i++ ) {
- str += "" + out.o[i] + oSpace[i] + "";
- }
- }
- else {
- if ( out.n[0].text == null ) {
- for ( n = 0; n < out.o.length && out.o[n].text == null; n++ ) {
- str += "" + out.o[n] + oSpace[n] + "";
- }
- }
-
- for ( i = 0; i < out.n.length; i++ ) {
- if (out.n[i].text == null) {
- str += "" + out.n[i] + nSpace[i] + "";
- }
- else {
- // `pre` initialized at top of scope
- pre = "";
-
- for ( n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++ ) {
- pre += "" + out.o[n] + oSpace[n] + "";
- }
- str += " " + out.n[i].text + nSpace[i] + pre;
- }
- }
- }
-
- return str;
- };
-}());
-
-// for CommonJS enviroments, export everything
-if ( typeof exports !== "undefined" ) {
- extend( exports, QUnit );
-}
-
-// get at whatever the global object is, like window in browsers
-}( (function() {return this;}.call()) ));
diff --git a/test/lib/require.js b/test/lib/require.js
deleted file mode 100644
index 987f865..0000000
--- a/test/lib/require.js
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- RequireJS 2.1.5 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.
- Available via the MIT or new BSD license.
- see: http://github.com/jrburke/requirejs for details
-*/
-var requirejs,require,define;
-(function(aa){function I(b){return"[object Function]"===L.call(b)}function J(b){return"[object Array]"===L.call(b)}function y(b,c){if(b){var d;for(d=0;dthis.depCount&&!this.defined){if(I(n)){if(this.events.error)try{e=i.execCb(c,n,b,e)}catch(d){a=d}else e=i.execCb(c,n,b,e);this.map.isDefine&&((b=this.module)&&void 0!==b.exports&&b.exports!==this.exports?e=b.exports:void 0===e&&this.usingExports&&(e=this.exports));if(a)return a.requireMap=this.map,a.requireModules=[this.map.id],a.requireType="define",v(this.error=
-a)}else e=n;this.exports=e;if(this.map.isDefine&&!this.ignore&&(q[c]=e,l.onResourceLoad))l.onResourceLoad(i,this.map,this.depMaps);x(c);this.defined=!0}this.defining=!1;this.defined&&!this.defineEmitted&&(this.defineEmitted=!0,this.emit("defined",this.exports),this.defineEmitComplete=!0)}}else this.fetch()}},callPlugin:function(){var a=this.map,b=a.id,d=j(a.prefix);this.depMaps.push(d);t(d,"defined",u(this,function(e){var n,d;d=this.map.name;var g=this.map.parentMap?this.map.parentMap.name:null,h=
-i.makeRequire(a.parentMap,{enableBuildCallback:!0});if(this.map.unnormalized){if(e.normalize&&(d=e.normalize(d,function(a){return c(a,g,!0)})||""),e=j(a.prefix+"!"+d,this.map.parentMap),t(e,"defined",u(this,function(a){this.init([],function(){return a},null,{enabled:!0,ignore:!0})})),d=m(p,e.id)){this.depMaps.push(e);if(this.events.error)d.on("error",u(this,function(a){this.emit("error",a)}));d.enable()}}else n=u(this,function(a){this.init([],function(){return a},null,{enabled:!0})}),n.error=u(this,
-function(a){this.inited=!0;this.error=a;a.requireModules=[b];G(p,function(a){0===a.map.id.indexOf(b+"_unnormalized")&&x(a.map.id)});v(a)}),n.fromText=u(this,function(e,c){var d=a.name,g=j(d),C=O;c&&(e=c);C&&(O=!1);r(g);s(k.config,b)&&(k.config[d]=k.config[b]);try{l.exec(e)}catch(ca){return v(B("fromtexteval","fromText eval for "+b+" failed: "+ca,ca,[b]))}C&&(O=!0);this.depMaps.push(g);i.completeLoad(d);h([d],n)}),e.load(a.name,h,n,k)}));i.enable(d,this);this.pluginMaps[d.id]=d},enable:function(){V[this.map.id]=
-this;this.enabling=this.enabled=!0;y(this.depMaps,u(this,function(a,b){var c,e;if("string"===typeof a){a=j(a,this.map.isDefine?this.map:this.map.parentMap,!1,!this.skipMap);this.depMaps[b]=a;if(c=m(N,a.id)){this.depExports[b]=c(this);return}this.depCount+=1;t(a,"defined",u(this,function(a){this.defineDep(b,a);this.check()}));this.errback&&t(a,"error",this.errback)}c=a.id;e=p[c];!s(N,c)&&(e&&!e.enabled)&&i.enable(a,this)}));G(this.pluginMaps,u(this,function(a){var b=m(p,a.id);b&&!b.enabled&&i.enable(a,
-this)}));this.enabling=!1;this.check()},on:function(a,b){var c=this.events[a];c||(c=this.events[a]=[]);c.push(b)},emit:function(a,b){y(this.events[a],function(a){a(b)});"error"===a&&delete this.events[a]}};i={config:k,contextName:b,registry:p,defined:q,urlFetched:U,defQueue:H,Module:Z,makeModuleMap:j,nextTick:l.nextTick,onError:v,configure:function(a){a.baseUrl&&"/"!==a.baseUrl.charAt(a.baseUrl.length-1)&&(a.baseUrl+="/");var b=k.pkgs,c=k.shim,e={paths:!0,config:!0,map:!0};G(a,function(a,b){e[b]?
-"map"===b?(k.map||(k.map={}),R(k[b],a,!0,!0)):R(k[b],a,!0):k[b]=a});a.shim&&(G(a.shim,function(a,b){J(a)&&(a={deps:a});if((a.exports||a.init)&&!a.exportsFn)a.exportsFn=i.makeShimExports(a);c[b]=a}),k.shim=c);a.packages&&(y(a.packages,function(a){a="string"===typeof a?{name:a}:a;b[a.name]={name:a.name,location:a.location||a.name,main:(a.main||"main").replace(ja,"").replace(ea,"")}}),k.pkgs=b);G(p,function(a,b){!a.inited&&!a.map.unnormalized&&(a.map=j(b))});if(a.deps||a.callback)i.require(a.deps||[],
-a.callback)},makeShimExports:function(a){return function(){var b;a.init&&(b=a.init.apply(aa,arguments));return b||a.exports&&ba(a.exports)}},makeRequire:function(a,f){function d(e,c,h){var g,k;f.enableBuildCallback&&(c&&I(c))&&(c.__requireJsBuild=!0);if("string"===typeof e){if(I(c))return v(B("requireargs","Invalid require call"),h);if(a&&s(N,e))return N[e](p[a.id]);if(l.get)return l.get(i,e,a,d);g=j(e,a,!1,!0);g=g.id;return!s(q,g)?v(B("notloaded",'Module name "'+g+'" has not been loaded yet for context: '+
-b+(a?"":". Use require([])"))):q[g]}L();i.nextTick(function(){L();k=r(j(null,a));k.skipMap=f.skipMap;k.init(e,c,h,{enabled:!0});D()});return d}f=f||{};R(d,{isBrowser:A,toUrl:function(b){var d,f=b.lastIndexOf("."),g=b.split("/")[0];if(-1!==f&&(!("."===g||".."===g)||1h.attachEvent.toString().indexOf("[native code"))&&!Y?(O=!0,h.attachEvent("onreadystatechange",b.onScriptLoad)):(h.addEventListener("load",b.onScriptLoad,!1),h.addEventListener("error",b.onScriptError,!1)),h.src=d,K=h,D?x.insertBefore(h,D):x.appendChild(h),K=null,h;if(da)try{importScripts(d),b.completeLoad(c)}catch(j){b.onError(B("importscripts","importScripts failed for "+c+" at "+d,j,[c]))}};A&&M(document.getElementsByTagName("script"),function(b){x||(x=
-b.parentNode);if(t=b.getAttribute("data-main"))return r.baseUrl||(E=t.split("/"),Q=E.pop(),fa=E.length?E.join("/")+"/":"./",r.baseUrl=fa,t=Q),t=t.replace(ea,""),r.deps=r.deps?r.deps.concat(t):[t],!0});define=function(b,c,d){var l,h;"string"!==typeof b&&(d=c,c=b,b=null);J(c)||(d=c,c=[]);!c.length&&I(d)&&d.length&&(d.toString().replace(la,"").replace(ma,function(b,d){c.push(d)}),c=(1===d.length?["require"]:["require","exports","module"]).concat(c));if(O){if(!(l=K))P&&"interactive"===P.readyState||M(document.getElementsByTagName("script"),
-function(b){if("interactive"===b.readyState)return P=b}),l=P;l&&(b||(b=l.getAttribute("data-requiremodule")),h=F[l.getAttribute("data-requirecontext")])}(h?h.defQueue:T).push([b,c,d])};define.amd={jQuery:!0};l.exec=function(b){return eval(b)};l(r)}})(this);
diff --git a/test/lib/resemble.js b/test/lib/resemble.js
new file mode 100644
index 0000000..1cb8c29
--- /dev/null
+++ b/test/lib/resemble.js
@@ -0,0 +1,535 @@
+/*
+Author: James Cryer
+Company: Huddle
+Last updated date: 21 Feb 2013
+URL: https://github.com/Huddle/Resemble.js
+*/
+
+(function(_this){
+ 'use strict';
+
+ _this['resemble'] = function( fileData ){
+
+ var data = {};
+ var images = [];
+ var updateCallbackArray = [];
+
+ var tolerance = { // between 0 and 255
+ red: 16,
+ green: 16,
+ blue: 16,
+ minBrightness: 16,
+ maxBrightness: 240
+ };
+
+ var ignoreAntialiasing = false;
+ var ignoreColors = false;
+
+ function triggerDataUpdate(){
+ var len = updateCallbackArray.length;
+ var i;
+ for(i=0;i tolerance.maxBrightness;
+ }
+
+ function getHue(r,g,b){
+
+ r = r / 255;
+ g = g / 255;
+ b = b / 255;
+ var max = Math.max(r, g, b), min = Math.min(r, g, b);
+ var h;
+ var d;
+
+ if (max == min){
+ h = 0; // achromatic
+ } else{
+ d = max - min;
+ switch(max){
+ case r: h = (g - b) / d + (g < b ? 6 : 0); break;
+ case g: h = (b - r) / d + 2; break;
+ case b: h = (r - g) / d + 4; break;
+ }
+ h /= 6;
+ }
+
+ return h;
+ }
+
+ function isAntialiased(sourcePix, data, cacheSet, verticalPos, horizontalPos, width){
+ var offset;
+ var targetPix;
+ var distance = 1;
+ var i;
+ var j;
+ var hasHighContrastSibling = 0;
+ var hasSiblingWithDifferentHue = 0;
+ var hasEquivilantSibling = 0;
+
+ addHueInfo(sourcePix);
+
+ for (i = distance*-1; i <= distance; i++){
+ for (j = distance*-1; j <= distance; j++){
+
+ if(i===0 && j===0){
+ // ignore source pixel
+ } else {
+
+ offset = ((verticalPos+j)*width + (horizontalPos+i)) * 4;
+ targetPix = getPixelInfo(data, offset, cacheSet);
+
+ if(targetPix === null){
+ continue;
+ }
+
+ addBrightnessInfo(targetPix);
+ addHueInfo(targetPix);
+
+ if( isContrasting(sourcePix, targetPix) ){
+ hasHighContrastSibling++;
+ }
+
+ if( isRGBSame(sourcePix,targetPix) ){
+ hasEquivilantSibling++;
+ }
+
+ if( Math.abs(targetPix.h - sourcePix.h) > 0.3 ){
+ hasSiblingWithDifferentHue++;
+ }
+
+ if( hasSiblingWithDifferentHue > 1 || hasHighContrastSibling > 1){
+ return true;
+ }
+ }
+ }
+ }
+
+ if(hasEquivilantSibling < 2){
+ return true;
+ }
+
+ return false;
+ }
+
+ function errorPixel(px, offset){
+ px[offset] = 255; //r
+ px[offset + 1] = 0; //g
+ px[offset + 2] = 255; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyPixel(px, offset, data){
+ px[offset] = data.r; //r
+ px[offset + 1] = data.g; //g
+ px[offset + 2] = data.b; //b
+ px[offset + 3] = 255; //a
+ }
+
+ function copyGrayScalePixel(px, offset, data){
+ px[offset] = data.brightness; //r
+ px[offset + 1] = data.brightness; //g
+ px[offset + 2] = data.brightness; //b
+ px[offset + 3] = 255; //a
+ }
+
+
+ function getPixelInfo(data, offset, cacheSet){
+ var r;
+ var g;
+ var b;
+ var d;
+
+ if(typeof data[offset] !== 'undefined'){
+ r = data[offset];
+ g = data[offset+1];
+ b = data[offset+2];
+ d = {
+ r: r,
+ g: g,
+ b: b
+ };
+
+ return d;
+ } else {
+ return null;
+ }
+ }
+
+ function addBrightnessInfo(data){
+ data.brightness = getBrightness(data.r,data.g,data.b); // 'corrected' lightness
+ }
+
+ function addHueInfo(data){
+ data.h = getHue(data.r,data.g,data.b);
+ }
+
+ function analyseImages(img1, img2, width, height){
+
+ var hiddenCanvas = document.createElement('canvas');
+
+ var data1 = img1.data;
+ var data2 = img2.data;
+
+ hiddenCanvas.width = width;
+ hiddenCanvas.height = height;
+
+ var context = hiddenCanvas.getContext('2d');
+ var imgd = context.createImageData(width,height);
+ var targetPix = imgd.data;
+
+ var mismatchCount = 0;
+
+ var time = Date.now();
+
+ var skip;
+
+ if( (width > 1200 || height > 1200) && ignoreAntialiasing){
+ skip = 6;
+ }
+
+ loop(height, width, function(verticalPos, horizontalPos){
+
+ if(skip){ // only skip if the image isn't small
+ if(verticalPos % skip === 0 || horizontalPos % skip === 0){
+ return;
+ }
+ }
+
+ var offset = (verticalPos*width + horizontalPos) * 4;
+ var pixel1 = getPixelInfo(data1, offset, 1);
+ var pixel2 = getPixelInfo(data2, offset, 2);
+
+ if(pixel1 === null || pixel2 === null){
+ return;
+ }
+
+ if (ignoreColors){
+
+ addBrightnessInfo(pixel1);
+ addBrightnessInfo(pixel2);
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ return;
+ }
+
+ if( isRGBSimilar(pixel1, pixel2) ){
+ copyPixel(targetPix, offset, pixel2);
+
+ } else if( ignoreAntialiasing && (
+ addBrightnessInfo(pixel1), // jit pixel info augmentation looks a little weird, sorry.
+ addBrightnessInfo(pixel2),
+ isAntialiased(pixel1, data1, 1, verticalPos, horizontalPos, width) ||
+ isAntialiased(pixel2, data2, 2, verticalPos, horizontalPos, width)
+ )){
+
+ if( isPixelBrightnessSimilar(pixel1, pixel2) ){
+ copyGrayScalePixel(targetPix, offset, pixel2);
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+ } else {
+ errorPixel(targetPix, offset);
+ mismatchCount++;
+ }
+
+ });
+
+ data.misMatchPercentage = (mismatchCount / (height*width) * 100).toFixed(2);
+ data.analysisTime = Date.now() - time;
+
+ data.getImageDataUrl = function(text){
+ var barHeight = 0;
+
+ if(text){
+ barHeight = addLabel(text,context,hiddenCanvas);
+ }
+
+ context.putImageData(imgd, 0, barHeight);
+
+ return hiddenCanvas.toDataURL("image/png");
+ };
+ }
+
+ function addLabel(text, context, hiddenCanvas){
+ var textPadding = 2;
+
+ context.font = '12px sans-serif';
+
+ var textWidth = context.measureText(text).width + textPadding*2;
+ var barHeight = 22;
+
+ if(textWidth > hiddenCanvas.width){
+ hiddenCanvas.width = textWidth;
+ }
+
+ hiddenCanvas.height += barHeight;
+
+ context.fillStyle = "#666";
+ context.fillRect(0,0,hiddenCanvas.width,barHeight -4);
+ context.fillStyle = "#fff";
+ context.fillRect(0,barHeight -4,hiddenCanvas.width, 4);
+
+ context.fillStyle = "#fff";
+ context.textBaseline = "top";
+ context.font = '12px sans-serif';
+ context.fillText(text, textPadding, 1);
+
+ return barHeight;
+ }
+
+ function normalise(img, w, h){
+ var c;
+ var context;
+
+ if(img.height < h || img.width < w){
+ c = document.createElement('canvas');
+ c.width = w;
+ c.height = h;
+ context = c.getContext('2d');
+ context.putImageData(img, 0, 0);
+ return context.getImageData(0, 0, w, h);
+ }
+
+ return img;
+ }
+
+ function compare(one, two){
+
+ function onceWeHaveBoth(){
+ var width;
+ var height;
+ if(images.length === 2){
+ width = images[0].width > images[1].width ? images[0].width : images[1].width;
+ height = images[0].height > images[1].height ? images[0].height : images[1].height;
+
+ if( (images[0].width === images[1].width) && (images[0].height === images[1].height) ){
+ data.isSameDimensions = true;
+ } else {
+ data.isSameDimensions = false;
+ }
+
+ analyseImages( normalise(images[0],width, height), normalise(images[1],width, height), width, height);
+
+ triggerDataUpdate();
+ }
+ }
+
+ images = [];
+ loadImageData(one, onceWeHaveBoth);
+ loadImageData(two, onceWeHaveBoth);
+ }
+
+ function getCompareApi(param){
+
+ var secondFileData,
+ hasMethod = typeof param === 'function';
+
+ if( !hasMethod ){
+ // assume it's file data
+ secondFileData = param;
+ }
+
+ var self = {
+ ignoreNothing: function(){
+
+ tolerance.red = 16;
+ tolerance.green = 16;
+ tolerance.blue = 16;
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreAntialiasing: function(){
+
+ tolerance.red = 32;
+ tolerance.green = 32;
+ tolerance.blue = 32;
+ tolerance.minBrightness = 64;
+ tolerance.maxBrightness = 96;
+
+ ignoreAntialiasing = true;
+ ignoreColors = false;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ ignoreColors: function(){
+
+ tolerance.minBrightness = 16;
+ tolerance.maxBrightness = 240;
+
+ ignoreAntialiasing = false;
+ ignoreColors = true;
+
+ if(hasMethod) { param(); }
+ return self;
+ },
+ onComplete: function( callback ){
+
+ updateCallbackArray.push(callback);
+
+ var wrapper = function(){
+ compare(fileData, secondFileData);
+ };
+
+ wrapper();
+
+ return getCompareApi(wrapper);
+ }
+ };
+
+ return self;
+ }
+
+ return {
+ onComplete: function( callback ){
+ updateCallbackArray.push(callback);
+ loadImageData(fileData, function(imageData, width, height){
+ parseImage(imageData.data, width, height);
+ });
+ },
+ compareTo: function(secondFileData){
+ return getCompareApi(secondFileData);
+ }
+ };
+
+ };
+}(this));
\ No newline at end of file
diff --git a/test/testsuite.js b/test/testsuite.js
deleted file mode 100644
index b486acb..0000000
--- a/test/testsuite.js
+++ /dev/null
@@ -1,36 +0,0 @@
-requirejs.config({
- baseUrl: '/test/unit/'
-});
-
-define(function(require) {
- var testModules = [
- 'Pixi',
- 'Point',
- 'Rectangle',
- 'DisplayObject',
- 'DisplayObjectContainer',
- 'Sprite',
- 'MovieClip',
- 'InteractionManager',
- 'Stage',
- 'utils/Utils',
- 'utils/EventTarget',
- 'utils/Matrix',
- 'utils/Detector',
- 'renderers/WebGLShaders',
- 'renderers/WebGLRenderer',
- 'renderers/WebGLBatch',
- 'renderers/CanvasRenderer',
- 'extras/Strip',
- 'extras/Rope',
- 'textures/BaseTexture',
- 'textures/Texture',
- 'loaders/SpriteSheetLoader',
- 'loaders/AssetLoader'
- ];
-
- // Resolve all testModules and then start the Test Runner.
- require(testModules, function() {
- QUnit.start();
- });
-});
\ No newline at end of file
diff --git a/test/textures/SpriteSheet-Aliens.png b/test/textures/SpriteSheet-Aliens.png
new file mode 100644
index 0000000..210acb1
--- /dev/null
+++ b/test/textures/SpriteSheet-Aliens.png
Binary files differ
diff --git a/test/textures/SpriteSheet-Explosion.png b/test/textures/SpriteSheet-Explosion.png
new file mode 100755
index 0000000..79e1a69
--- /dev/null
+++ b/test/textures/SpriteSheet-Explosion.png
Binary files differ
diff --git a/test/textures/bunny.png b/test/textures/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/textures/bunny.png
Binary files differ
diff --git a/test/unit/DisplayObject.js b/test/unit/DisplayObject.js
deleted file mode 100644
index 5e7e72f..0000000
--- a/test/unit/DisplayObject.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObject');
-});
diff --git a/test/unit/DisplayObjectContainer.js b/test/unit/DisplayObjectContainer.js
deleted file mode 100644
index b323959..0000000
--- a/test/unit/DisplayObjectContainer.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('DisplayObjectContainer');
-});
diff --git a/test/unit/InteractionManager.js b/test/unit/InteractionManager.js
deleted file mode 100644
index e751f52..0000000
--- a/test/unit/InteractionManager.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('InteractionManager');
-});
diff --git a/test/unit/MovieClip.js b/test/unit/MovieClip.js
deleted file mode 100644
index 37d9446..0000000
--- a/test/unit/MovieClip.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('MovieClip');
-});
diff --git a/test/unit/Pixi.js b/test/unit/Pixi.js
deleted file mode 100644
index 36eee73..0000000
--- a/test/unit/Pixi.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Pixi');
-});
diff --git a/test/unit/Point.js b/test/unit/Point.js
deleted file mode 100644
index 983ff6e..0000000
--- a/test/unit/Point.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Point');
-});
diff --git a/test/unit/Rectangle.js b/test/unit/Rectangle.js
deleted file mode 100644
index 3b439ba..0000000
--- a/test/unit/Rectangle.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Rectangle');
-});
diff --git a/test/unit/Sprite.js b/test/unit/Sprite.js
deleted file mode 100644
index ed4f596..0000000
--- a/test/unit/Sprite.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Sprite');
-});
diff --git a/test/unit/Stage.js b/test/unit/Stage.js
deleted file mode 100644
index 2d70291..0000000
--- a/test/unit/Stage.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Stage');
-});
diff --git a/test/unit/extras/Rope.js b/test/unit/extras/Rope.js
deleted file mode 100644
index 5606f14..0000000
--- a/test/unit/extras/Rope.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Rope');
-});
diff --git a/test/unit/extras/Strip.js b/test/unit/extras/Strip.js
deleted file mode 100644
index 0134d3a..0000000
--- a/test/unit/extras/Strip.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('Strip');
-});
diff --git a/test/unit/loaders/AssetLoader.js b/test/unit/loaders/AssetLoader.js
deleted file mode 100644
index 13b8443..0000000
--- a/test/unit/loaders/AssetLoader.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('AssetLoader');
-});
diff --git a/test/unit/loaders/SpriteSheetLoader.js b/test/unit/loaders/SpriteSheetLoader.js
deleted file mode 100644
index 8bf0cb2..0000000
--- a/test/unit/loaders/SpriteSheetLoader.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('SpriteSheetLoader');
-});
diff --git a/test/unit/pixi/InteractionManager.js b/test/unit/pixi/InteractionManager.js
new file mode 100644
index 0000000..ed3001f
--- /dev/null
+++ b/test/unit/pixi/InteractionManager.js
@@ -0,0 +1,10 @@
+describe('pixi/InteractionManager', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var InteractionManager = PIXI.InteractionManager;
+
+ it('Module exists', function () {
+ expect(InteractionManager).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/Pixi.js b/test/unit/pixi/Pixi.js
new file mode 100644
index 0000000..27debc1
--- /dev/null
+++ b/test/unit/pixi/Pixi.js
@@ -0,0 +1,9 @@
+describe('pixi/Pixi', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+
+ it('Module exists', function () {
+ expect(global).to.have.property('PIXI').and.to.be.an('object');
+ });
+});
diff --git a/test/unit/pixi/core/Circle.js b/test/unit/pixi/core/Circle.js
new file mode 100644
index 0000000..93a4456
--- /dev/null
+++ b/test/unit/pixi/core/Circle.js
@@ -0,0 +1,22 @@
+describe('pixi/core/Circle', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Circle = PIXI.Circle;
+
+ it('Module exists', function () {
+ expect(Circle).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Circle();
+
+ expect(obj).to.be.an.instanceof(Circle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', 0);
+ expect(obj).to.have.property('y', 0);
+ expect(obj).to.have.property('radius', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Ellipse.js b/test/unit/pixi/core/Ellipse.js
new file mode 100644
index 0000000..026b56f
--- /dev/null
+++ b/test/unit/pixi/core/Ellipse.js
@@ -0,0 +1,24 @@
+describe('pixi/core/Ellipse', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Ellipse = PIXI.Ellipse;
+
+ it('Module exists', function () {
+ expect(Ellipse).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Ellipse();
+
+ expect(obj).to.be.an.instanceof(Ellipse);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+ expect(obj).to.respondTo('getBounds');
+
+ expect(obj).to.have.property('x', 0);
+ expect(obj).to.have.property('y', 0);
+ expect(obj).to.have.property('width', 0);
+ expect(obj).to.have.property('height', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Matrix.js b/test/unit/pixi/core/Matrix.js
new file mode 100644
index 0000000..b48989e
--- /dev/null
+++ b/test/unit/pixi/core/Matrix.js
@@ -0,0 +1,30 @@
+describe('pixi/core/Matrix', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var mat3 = PIXI.mat3;
+ var mat4 = PIXI.mat4;
+ var Matrix = PIXI.Matrix;
+
+ it('Ensure determineMatrixArrayType works', function () {
+ expect(Matrix).to.be.a('function');
+ });
+
+ it('mat3 exists', function () {
+ expect(mat3).to.be.an('object');
+ });
+
+ it('Confirm new mat3 matrix', function () {
+ var matrix = new mat3.create();
+ pixi_core_Matrix_confirmNewMat3(matrix);
+ });
+
+ it('mat3 exists', function () {
+ expect(mat4).to.be.an('object');
+ });
+
+ it('Confirm new mat4 matrix', function () {
+ var matrix = new mat4.create();
+ pixi_core_Matrix_confirmNewMat4(matrix);
+ });
+});
diff --git a/test/unit/pixi/core/Point.js b/test/unit/pixi/core/Point.js
new file mode 100644
index 0000000..c4d5163
--- /dev/null
+++ b/test/unit/pixi/core/Point.js
@@ -0,0 +1,15 @@
+describe('pixi/core/Point', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Point = PIXI.Point;
+
+ it('Module exists', function () {
+ expect(Point).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Point();
+ pixi_core_Point_confirm(obj, 0, 0);
+ });
+});
diff --git a/test/unit/pixi/core/Polygon.js b/test/unit/pixi/core/Polygon.js
new file mode 100644
index 0000000..dc8c918
--- /dev/null
+++ b/test/unit/pixi/core/Polygon.js
@@ -0,0 +1,20 @@
+describe('pixi/core/Polygon', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Polygon = PIXI.Polygon;
+
+ it('Module exists', function () {
+ expect(Polygon).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Polygon();
+
+ expect(obj).to.be.an.instanceof(Polygon);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.deep.property('points.length', 0);
+ });
+});
diff --git a/test/unit/pixi/core/Rectangle.js b/test/unit/pixi/core/Rectangle.js
new file mode 100644
index 0000000..d43316e
--- /dev/null
+++ b/test/unit/pixi/core/Rectangle.js
@@ -0,0 +1,15 @@
+describe('pixi/core/Rectangle', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Rectangle = PIXI.Rectangle;
+
+ it('Module exists', function () {
+ expect(Rectangle).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var rect = new Rectangle();
+ pixi_core_Rectangle_confirm(rect, 0, 0, 0, 0);
+ });
+});
diff --git a/test/unit/pixi/display/DisplayObject.js b/test/unit/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..40c6fbc
--- /dev/null
+++ b/test/unit/pixi/display/DisplayObject.js
@@ -0,0 +1,21 @@
+describe('pixi/display/DisplayObject', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var DisplayObject = PIXI.DisplayObject;
+
+ it('Module exists', function () {
+ expect(DisplayObject).to.be.a('function');
+ expect(PIXI).to.have.property('visibleCount', 0);
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new DisplayObject();
+
+ pixi_display_DisplayObject_confirmNew(obj);
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', false);
+ expect(obj).to.have.property('stage', null);
+ });
+});
diff --git a/test/unit/pixi/display/DisplayObjectContainer.js b/test/unit/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..ce7f02f
--- /dev/null
+++ b/test/unit/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,20 @@
+describe('pixi/display/DisplayObjectContainer', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var DisplayObjectContainer = PIXI.DisplayObjectContainer;
+
+ it('Module exists', function () {
+ expect(DisplayObjectContainer).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new DisplayObjectContainer();
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', false);
+ expect(obj).to.have.property('stage', null);
+ });
+});
diff --git a/test/unit/pixi/display/MovieClip.js b/test/unit/pixi/display/MovieClip.js
new file mode 100644
index 0000000..f3c6c6a
--- /dev/null
+++ b/test/unit/pixi/display/MovieClip.js
@@ -0,0 +1,33 @@
+describe('pixi/display/MovieClip', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var MovieClip = PIXI.MovieClip;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(MovieClip).to.be.a('function');
+ });
+
+ it('Confirm new instance', function (done) {
+ var texture = Texture.fromImage('/base/test/textures/SpriteSheet-Explosion.png');
+ var obj = new MovieClip([texture]);
+
+ pixi_display_Sprite_confirmNew(obj, done);
+
+ expect(obj).to.be.an.instanceof(MovieClip);
+ expect(obj).to.respondTo('stop');
+ expect(obj).to.respondTo('play');
+ expect(obj).to.respondTo('gotoAndStop');
+ expect(obj).to.respondTo('gotoAndPlay');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('textures.length', 1);
+ expect(obj).to.have.deep.property('textures[0]', texture);
+ expect(obj).to.have.property('animationSpeed', 1);
+ expect(obj).to.have.property('loop', true);
+ expect(obj).to.have.property('onComplete', null);
+ expect(obj).to.have.property('currentFrame', 0);
+ expect(obj).to.have.property('playing', false);
+ });
+});
diff --git a/test/unit/pixi/display/Sprite.js b/test/unit/pixi/display/Sprite.js
new file mode 100644
index 0000000..54e914f
--- /dev/null
+++ b/test/unit/pixi/display/Sprite.js
@@ -0,0 +1,25 @@
+describe('pixi/display/Sprite', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Sprite = PIXI.Sprite;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(Sprite).to.be.a('function');
+ expect(PIXI).to.have.deep.property('blendModes.NORMAL', 0);
+ expect(PIXI).to.have.deep.property('blendModes.SCREEN', 1);
+ });
+
+ it('Members exist', function () {
+ expect(Sprite).itself.to.respondTo('fromImage');
+ expect(Sprite).itself.to.respondTo('fromFrame');
+ });
+
+ it('Confirm new instance', function (done) {
+ var texture = Texture.fromImage('/base/test/textures/SpriteSheet-Aliens.png');
+ var obj = new Sprite(texture);
+
+ pixi_display_Sprite_confirmNew(obj, done);
+ });
+});
diff --git a/test/unit/pixi/display/Stage.js b/test/unit/pixi/display/Stage.js
new file mode 100644
index 0000000..3cc2a4d
--- /dev/null
+++ b/test/unit/pixi/display/Stage.js
@@ -0,0 +1,49 @@
+describe('pixi/display/Stage', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Stage = PIXI.Stage;
+ var InteractionManager = PIXI.InteractionManager;
+ var Rectangle = PIXI.Rectangle;
+
+ it('Module exists', function () {
+ expect(Stage).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Stage(null, true);
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(Stage);
+ expect(obj).to.respondTo('updateTransform');
+ expect(obj).to.respondTo('setBackgroundColor');
+ expect(obj).to.respondTo('getMousePosition');
+
+ // FIXME: duplicate member in DisplayObject
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ // FIXME: convert arg to bool in constructor
+ expect(obj).to.have.property('interactive', true);
+
+ expect(obj).to.have.property('interactionManager')
+ .and.to.be.an.instanceof(InteractionManager)
+ .and.to.have.property('stage', obj);
+
+ expect(obj).to.have.property('dirty', true);
+
+ expect(obj).to.have.property('stage', obj);
+
+ expect(obj).to.have.property('hitArea')
+ .and.to.be.an.instanceof(Rectangle);
+ pixi_core_Rectangle_confirm(obj.hitArea, 0, 0, 100000, 100000);
+
+ expect(obj).to.have.property('backgroundColor', 0x000000);
+ expect(obj).to.have.deep.property('backgroundColorSplit.length', 3);
+ expect(obj).to.have.deep.property('backgroundColorSplit[0]', 0);
+ expect(obj).to.have.deep.property('backgroundColorSplit[1]', 0);
+ expect(obj).to.have.deep.property('backgroundColorSplit[2]', 0);
+ expect(obj).to.have.property('backgroundColorString', '#000000');
+
+ expect(obj).to.have.property('worldVisible', true);
+ });
+});
diff --git a/test/unit/pixi/extras/CustomRenderable.js b/test/unit/pixi/extras/CustomRenderable.js
new file mode 100644
index 0000000..8d83cf0
--- /dev/null
+++ b/test/unit/pixi/extras/CustomRenderable.js
@@ -0,0 +1,21 @@
+describe('pixi/extras/CustomRenderable', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var CustomRenderable = PIXI.CustomRenderable;
+
+ it('Module exists', function () {
+ expect(CustomRenderable).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new CustomRenderable();
+
+ pixi_display_DisplayObject_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(CustomRenderable);
+ expect(obj).to.respondTo('renderCanvas');
+ expect(obj).to.respondTo('initWebGL');
+ expect(obj).to.respondTo('renderWebGL');
+ });
+});
diff --git a/test/unit/pixi/extras/Rope.js b/test/unit/pixi/extras/Rope.js
new file mode 100644
index 0000000..6ddaf83
--- /dev/null
+++ b/test/unit/pixi/extras/Rope.js
@@ -0,0 +1,26 @@
+describe('pixi/extras/Rope', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Rope = PIXI.Rope;
+ var Texture = PIXI.Texture;
+ var Point = PIXI.Point;
+
+ it('Module exists', function () {
+ expect(Rope).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var texture = Texture.fromImage('/base/test/textures/bunny.png');
+ var obj = new Rope(texture, [new Point(), new Point(5, 10), new Point(10, 20)]);
+
+ pixi_extras_Strip_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(Rope);
+ expect(obj).to.respondTo('refresh');
+ expect(obj).to.respondTo('updateTransform');
+ expect(obj).to.respondTo('setTexture');
+
+ // TODO: Test properties
+ });
+});
diff --git a/test/unit/pixi/extras/Spine.js b/test/unit/pixi/extras/Spine.js
new file mode 100644
index 0000000..0708bc0
--- /dev/null
+++ b/test/unit/pixi/extras/Spine.js
@@ -0,0 +1,10 @@
+describe('pixi/extras/Spine', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Spine = PIXI.Spine;
+
+ it('Module exists', function () {
+ expect(Spine).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/extras/Strip.js b/test/unit/pixi/extras/Strip.js
new file mode 100644
index 0000000..8e564e1
--- /dev/null
+++ b/test/unit/pixi/extras/Strip.js
@@ -0,0 +1,18 @@
+describe('pixi/extras/Strip', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Strip = PIXI.Strip;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(Strip).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var texture = Texture.fromImage('/base/test/textures/bunny.png');
+ var obj = new Strip(texture, 20, 10000);
+
+ pixi_extras_Strip_confirmNew(obj);
+ });
+});
diff --git a/test/unit/pixi/extras/TilingSprite.js b/test/unit/pixi/extras/TilingSprite.js
new file mode 100644
index 0000000..56aea14
--- /dev/null
+++ b/test/unit/pixi/extras/TilingSprite.js
@@ -0,0 +1,24 @@
+describe('pixi/extras/TilingSprite', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var TilingSprite = PIXI.TilingSprite;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(TilingSprite).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var texture = Texture.fromImage('/base/test/textures/bunny.png');
+ var obj = new TilingSprite(texture, 6000, 12000);
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(TilingSprite);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ // TODO: Test properties
+ });
+});
diff --git a/test/unit/pixi/filters/FilterBlock.js b/test/unit/pixi/filters/FilterBlock.js
new file mode 100644
index 0000000..870cec0
--- /dev/null
+++ b/test/unit/pixi/filters/FilterBlock.js
@@ -0,0 +1,10 @@
+describe('pixi/filters/FilterBlock', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var FilterBlock = PIXI.FilterBlock;
+
+ it('Module exists', function () {
+ expect(FilterBlock).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/filters/MaskFilter.js b/test/unit/pixi/filters/MaskFilter.js
new file mode 100644
index 0000000..32d6a45
--- /dev/null
+++ b/test/unit/pixi/filters/MaskFilter.js
@@ -0,0 +1,10 @@
+describe('pixi/filters/MaskFilter', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ // var MaskFilter = PIXI.MaskFilter;
+
+ // it('Module exists', function () {
+ // expect(MaskFilter).to.be.a('function');
+ // });
+});
diff --git a/test/unit/pixi/loaders/AssetLoader.js b/test/unit/pixi/loaders/AssetLoader.js
new file mode 100644
index 0000000..a0aa0b5
--- /dev/null
+++ b/test/unit/pixi/loaders/AssetLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/AssetLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var AssetLoader = PIXI.AssetLoader;
+
+ it('Module exists', function () {
+ expect(AssetLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/BitmapFontLoader.js b/test/unit/pixi/loaders/BitmapFontLoader.js
new file mode 100644
index 0000000..6253c42
--- /dev/null
+++ b/test/unit/pixi/loaders/BitmapFontLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/BitmapFontLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var BitmapFontLoader = PIXI.BitmapFontLoader;
+
+ it('Module exists', function () {
+ expect(PIXI.BitmapFontLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/ImageLoader.js b/test/unit/pixi/loaders/ImageLoader.js
new file mode 100644
index 0000000..8b1f556
--- /dev/null
+++ b/test/unit/pixi/loaders/ImageLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/ImageLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var ImageLoader = PIXI.ImageLoader;
+
+ it('Module exists', function () {
+ expect(ImageLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/JsonLoader.js b/test/unit/pixi/loaders/JsonLoader.js
new file mode 100644
index 0000000..c577e83
--- /dev/null
+++ b/test/unit/pixi/loaders/JsonLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/JsonLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var JsonLoader = PIXI.JsonLoader;
+
+ it('Module exists', function () {
+ expect(JsonLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/SpineLoader.js b/test/unit/pixi/loaders/SpineLoader.js
new file mode 100644
index 0000000..fdcc0b8
--- /dev/null
+++ b/test/unit/pixi/loaders/SpineLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/SpineLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var SpineLoader = PIXI.SpineLoader;
+
+ it('Module exists', function () {
+ expect(SpineLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/loaders/SpriteSheetLoader.js b/test/unit/pixi/loaders/SpriteSheetLoader.js
new file mode 100644
index 0000000..57beb27
--- /dev/null
+++ b/test/unit/pixi/loaders/SpriteSheetLoader.js
@@ -0,0 +1,10 @@
+describe('pixi/loaders/SpriteSheetLoader', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var SpriteSheetLoader = PIXI.SpriteSheetLoader;
+
+ it('Module exists', function () {
+ expect(SpriteSheetLoader).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/primitives/Graphics.js b/test/unit/pixi/primitives/Graphics.js
new file mode 100644
index 0000000..b8b3e5c
--- /dev/null
+++ b/test/unit/pixi/primitives/Graphics.js
@@ -0,0 +1,40 @@
+describe('pixi/primitives/Graphics', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Graphics = PIXI.Graphics;
+
+ it('Module exists', function () {
+ expect(Graphics).to.be.a('function');
+
+ expect(Graphics).itself.to.have.property('POLY', 0);
+ expect(Graphics).itself.to.have.property('RECT', 1);
+ expect(Graphics).itself.to.have.property('CIRC', 2);
+ expect(Graphics).itself.to.have.property('ELIP', 3);
+ });
+
+ it('Confirm new instance', function () {
+ var obj = new Graphics();
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(Graphics);
+ expect(obj).to.respondTo('lineStyle');
+ expect(obj).to.respondTo('lineStyle');
+ expect(obj).to.respondTo('moveTo');
+ expect(obj).to.respondTo('lineTo');
+ expect(obj).to.respondTo('beginFill');
+ expect(obj).to.respondTo('endFill');
+ expect(obj).to.respondTo('drawRect');
+ expect(obj).to.respondTo('drawCircle');
+ expect(obj).to.respondTo('drawElipse');
+ expect(obj).to.respondTo('clear');
+
+ expect(obj).to.have.property('renderable', true);
+ expect(obj).to.have.property('fillAlpha', 1);
+ expect(obj).to.have.property('lineWidth', 0);
+ expect(obj).to.have.property('lineColor', 'black');
+ expect(obj).to.have.deep.property('graphicsData.length', 0);
+ expect(obj).to.have.deep.property('currentPath.points.length', 0);
+ });
+});
diff --git a/test/unit/pixi/renderers/canvas/CanvasGraphics.js b/test/unit/pixi/renderers/canvas/CanvasGraphics.js
new file mode 100644
index 0000000..8f44472
--- /dev/null
+++ b/test/unit/pixi/renderers/canvas/CanvasGraphics.js
@@ -0,0 +1,15 @@
+describe('renders/canvas/CanvasGraphics', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var CanvasGraphics = PIXI.CanvasGraphics;
+
+ it('Module exists', function () {
+ expect(CanvasGraphics).to.be.a('function');
+ });
+
+ it('Members exist', function () {
+ expect(CanvasGraphics).itself.to.respondTo('renderGraphics');
+ expect(CanvasGraphics).itself.to.respondTo('renderGraphicsMask');
+ });
+});
diff --git a/test/unit/pixi/renderers/canvas/CanvasRenderer.js b/test/unit/pixi/renderers/canvas/CanvasRenderer.js
new file mode 100644
index 0000000..df3a12f
--- /dev/null
+++ b/test/unit/pixi/renderers/canvas/CanvasRenderer.js
@@ -0,0 +1,10 @@
+describe('renderers/canvas/CanvasRenderer', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var CanvasRenderer = PIXI.CanvasRenderer;
+
+ it('Module exists', function () {
+ expect(CanvasRenderer).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/renderers/webgl/WebGLBatch.js b/test/unit/pixi/renderers/webgl/WebGLBatch.js
new file mode 100644
index 0000000..75efd56
--- /dev/null
+++ b/test/unit/pixi/renderers/webgl/WebGLBatch.js
@@ -0,0 +1,10 @@
+describe('renderers/webgl/WebGLBatch', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var WebGLBatch = PIXI.WebGLBatch;
+
+ it('Module exists', function () {
+ expect(WebGLBatch).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/renderers/webgl/WebGLGraphics.js b/test/unit/pixi/renderers/webgl/WebGLGraphics.js
new file mode 100644
index 0000000..41bf941
--- /dev/null
+++ b/test/unit/pixi/renderers/webgl/WebGLGraphics.js
@@ -0,0 +1,19 @@
+describe('renderers/wegbl/WebGLGraphics', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var WebGLGraphics = PIXI.WebGLGraphics;
+
+ it('Module exists', function () {
+ expect(WebGLGraphics).to.be.a('function');
+ });
+
+ it('Members exist', function () {
+ expect(WebGLGraphics).itself.to.respondTo('renderGraphics');
+ expect(WebGLGraphics).itself.to.respondTo('updateGraphics');
+ expect(WebGLGraphics).itself.to.respondTo('buildRectangle');
+ expect(WebGLGraphics).itself.to.respondTo('buildCircle');
+ expect(WebGLGraphics).itself.to.respondTo('buildLine');
+ expect(WebGLGraphics).itself.to.respondTo('buildPoly');
+ });
+});
diff --git a/test/unit/pixi/renderers/webgl/WebGLRenderGroup.js b/test/unit/pixi/renderers/webgl/WebGLRenderGroup.js
new file mode 100644
index 0000000..f4ee366
--- /dev/null
+++ b/test/unit/pixi/renderers/webgl/WebGLRenderGroup.js
@@ -0,0 +1,10 @@
+describe('renderers/webgl/WebGLRenderGroup', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var WebGLRenderGroup = PIXI.WebGLRenderGroup;
+
+ it('Module exists', function () {
+ expect(WebGLRenderGroup).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/renderers/webgl/WebGLRenderer.js b/test/unit/pixi/renderers/webgl/WebGLRenderer.js
new file mode 100644
index 0000000..86533eb
--- /dev/null
+++ b/test/unit/pixi/renderers/webgl/WebGLRenderer.js
@@ -0,0 +1,10 @@
+describe('renderers/webgl/WebGLRenderer', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var WebGLRenderer = PIXI.WebGLRenderer;
+
+ it('Module exists', function () {
+ expect(WebGLRenderer).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/renderers/webgl/WebGLShaders.js b/test/unit/pixi/renderers/webgl/WebGLShaders.js
new file mode 100644
index 0000000..2872de8
--- /dev/null
+++ b/test/unit/pixi/renderers/webgl/WebGLShaders.js
@@ -0,0 +1,13 @@
+describe('renderers/webgl/WebGLShaders', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+
+ it('Module members exist', function () {
+ expect(PIXI).to.respondTo('initPrimitiveShader');
+ expect(PIXI).to.respondTo('initDefaultShader');
+ expect(PIXI).to.respondTo('initDefaultStripShader');
+ expect(PIXI).to.respondTo('activateDefaultShader');
+ expect(PIXI).to.respondTo('activatePrimitiveShader');
+ });
+});
diff --git a/test/unit/pixi/text/BitmapText.js b/test/unit/pixi/text/BitmapText.js
new file mode 100644
index 0000000..9388e3d
--- /dev/null
+++ b/test/unit/pixi/text/BitmapText.js
@@ -0,0 +1,10 @@
+describe('pixi/text/BitmapText', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var BitmapText = PIXI.BitmapText;
+
+ it('Module exists', function () {
+ expect(BitmapText).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/text/Text.js b/test/unit/pixi/text/Text.js
new file mode 100644
index 0000000..9bc9ac5
--- /dev/null
+++ b/test/unit/pixi/text/Text.js
@@ -0,0 +1,10 @@
+describe('pixi/text/Text', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Text = PIXI.Text;
+
+ it('Module exists', function () {
+ expect(Text).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/textures/BaseTexture.js b/test/unit/pixi/textures/BaseTexture.js
new file mode 100644
index 0000000..e34b64c
--- /dev/null
+++ b/test/unit/pixi/textures/BaseTexture.js
@@ -0,0 +1,13 @@
+describe('pixi/textures/BaseTexture', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var BaseTexture = PIXI.BaseTexture;
+
+ it('Module exists', function () {
+ expect(BaseTexture).to.be.a('function');
+ expect(PIXI).to.have.property('BaseTextureCache').and.to.be.an('object');
+ expect(PIXI).to.have.deep.property('texturesToUpdate.length');
+ expect(PIXI).to.have.deep.property('texturesToDestroy.length', 0);
+ });
+});
diff --git a/test/unit/pixi/textures/RenderTexture.js b/test/unit/pixi/textures/RenderTexture.js
new file mode 100644
index 0000000..4a69b44
--- /dev/null
+++ b/test/unit/pixi/textures/RenderTexture.js
@@ -0,0 +1,10 @@
+describe('pixi/textures/RenderTexture', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var RenderTexture = PIXI.RenderTexture;
+
+ it('Module exists', function () {
+ expect(RenderTexture).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/textures/Texture.js b/test/unit/pixi/textures/Texture.js
new file mode 100644
index 0000000..adb2875
--- /dev/null
+++ b/test/unit/pixi/textures/Texture.js
@@ -0,0 +1,26 @@
+describe('pixi/textures/Texture', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var Texture = PIXI.Texture;
+
+ it('Module exists', function () {
+ expect(Texture).to.be.a('function');
+ expect(PIXI).to.have.property('TextureCache').and.to.be.an('object');
+ });
+
+ it('Members exist', function () {
+ expect(Texture).itself.to.respondTo('fromImage');
+ expect(Texture).itself.to.respondTo('fromFrame');
+ expect(Texture).itself.to.respondTo('fromCanvas');
+ expect(Texture).itself.to.respondTo('addTextureToCache');
+ expect(Texture).itself.to.respondTo('removeTextureFromCache');
+
+ expect(Texture).itself.to.have.deep.property('frameUpdates.length', 0);
+ });
+
+ it('Confirm new instance', function (done) {
+ var texture = Texture.fromImage('/base/test/textures/bunny.png');
+ pixi_textures_Texture_confirmNew(texture, done);
+ });
+});
diff --git a/test/unit/pixi/utils/Detector.js b/test/unit/pixi/utils/Detector.js
new file mode 100644
index 0000000..4cf6008
--- /dev/null
+++ b/test/unit/pixi/utils/Detector.js
@@ -0,0 +1,10 @@
+describe('pixi/utils/Detector', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var autoDetectRenderer = PIXI.autoDetectRenderer;
+
+ it('Module exists', function () {
+ expect(autoDetectRenderer).to.be.a('function');
+ });
+});
diff --git a/test/unit/pixi/utils/EventTarget.js b/test/unit/pixi/utils/EventTarget.js
new file mode 100644
index 0000000..dc4ebd9
--- /dev/null
+++ b/test/unit/pixi/utils/EventTarget.js
@@ -0,0 +1,96 @@
+describe('pixi/utils/EventTarget', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var EventTarget = PIXI.EventTarget;
+
+ it('Module exists', function () {
+ expect(EventTarget).to.be.a('function');
+ });
+
+ it('Confirm new instance', function () {
+ var obj = {}; EventTarget.call(obj);
+ pixi_utils_EventTarget_like(obj);
+ });
+
+ it('addEventListener and dispatchEvent works', function (done) {
+ var myData = {},
+ obj = {}; EventTarget.call(obj);
+
+ obj.addEventListener('myevent', function (event) {
+ expect(event).to.be.an('object');
+ expect(event).to.have.property('type', 'myevent');
+ expect(event).to.have.property('data', myData);
+ done();
+ });
+
+ obj.dispatchEvent({type: 'myevent', data: myData});
+ });
+
+ it('removeEventListener works', function (done) {
+ var obj = {}; EventTarget.call(obj);
+
+ function onMyEvent() {
+ done(new Error('addEventListener should not have been called'));
+ }
+
+ obj.addEventListener('myevent', onMyEvent);
+ obj.removeEventListener('myevent', onMyEvent);
+ obj.dispatchEvent({type: 'myevent'});
+ done();
+ });
+
+ it('multiple dispatches', function () {
+ var called = 0,
+ obj = {}; EventTarget.call(obj);
+
+ function onMyEvent() {
+ called++;
+ }
+
+ obj.addEventListener('myevent', onMyEvent);
+ obj.dispatchEvent({type: 'myevent'});
+ obj.dispatchEvent({type: 'myevent'});
+ obj.dispatchEvent({type: 'myevent'});
+ obj.dispatchEvent({type: 'myevent'});
+ expect(called).to.equal(4);
+ });
+
+ it('multiple events', function () {
+ var called = 0,
+ obj = {}; EventTarget.call(obj);
+
+ function onMyEvent() {
+ called++;
+ }
+
+ obj.addEventListener('myevent1', onMyEvent);
+ obj.addEventListener('myevent2', onMyEvent);
+ obj.addEventListener('myevent3', onMyEvent);
+ obj.dispatchEvent({type: 'myevent1'});
+ obj.dispatchEvent({type: 'myevent2'});
+ obj.dispatchEvent({type: 'myevent3'});
+ expect(called).to.equal(3);
+ });
+
+ it('multiple events one removed', function () {
+ var called = 0,
+ obj = {}; EventTarget.call(obj);
+
+ function onMyEvent() {
+ called++;
+ }
+
+ obj.addEventListener('myevent1', onMyEvent);
+ obj.addEventListener('myevent2', onMyEvent);
+ obj.addEventListener('myevent3', onMyEvent);
+ obj.dispatchEvent({type: 'myevent1'});
+ obj.dispatchEvent({type: 'myevent2'});
+ obj.dispatchEvent({type: 'myevent3'});
+ obj.removeEventListener('myevent2', onMyEvent);
+ obj.dispatchEvent({type: 'myevent1'});
+ obj.dispatchEvent({type: 'myevent2'});
+ obj.dispatchEvent({type: 'myevent3'});
+ expect(called).to.equal(5);
+ });
+});
diff --git a/test/unit/pixi/utils/Polyk.js b/test/unit/pixi/utils/Polyk.js
new file mode 100644
index 0000000..dfc7128
--- /dev/null
+++ b/test/unit/pixi/utils/Polyk.js
@@ -0,0 +1,14 @@
+describe('pixi/utils/Polyk', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+ var PolyK = PIXI.PolyK;
+
+ it('Module exists', function () {
+ expect(PolyK).to.be.an('object');
+ });
+
+ it('Members exist', function () {
+ expect(PolyK).to.respondTo('Triangulate');
+ });
+});
diff --git a/test/unit/pixi/utils/Utils.js b/test/unit/pixi/utils/Utils.js
new file mode 100644
index 0000000..c97b3c6
--- /dev/null
+++ b/test/unit/pixi/utils/Utils.js
@@ -0,0 +1,17 @@
+describe('Utils', function () {
+ 'use strict';
+
+ var expect = chai.expect;
+
+ it('requestAnimationFrame exists', function () {
+ expect(global).to.respondTo('requestAnimationFrame');
+ });
+
+ it('cancelAnimationFrame exists', function () {
+ expect(global).to.respondTo('cancelAnimationFrame');
+ });
+
+ it('requestAnimFrame exists', function () {
+ expect(global).to.respondTo('requestAnimFrame');
+ });
+});
diff --git a/test/unit/renderers/CanvasRenderer.js b/test/unit/renderers/CanvasRenderer.js
deleted file mode 100644
index 09d21f5..0000000
--- a/test/unit/renderers/CanvasRenderer.js
+++ /dev/null
@@ -1,3 +0,0 @@
-define(function() {
- Q.module('CanvasRenderer');
-});
diff --git a/.gitignore b/.gitignore
index 12e1b62..0b88317 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
node_modules
.DS_Store
-.project
\ No newline at end of file
+.project
+*.log
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..63e4d7c
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,8 @@
+language: node_js
+node_js:
+ - 0.10
+
+before_script:
+ - npm install -g grunt-cli
+ - export DISPLAY=:99.0
+ - sh -e /etc/init.d/xvfb start
diff --git a/Gruntfile.js b/Gruntfile.js
index b083b49..103938c 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -1,10 +1,12 @@
+'use strict';
+
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-connect');
- grunt.loadNpmTasks('grunt-contrib-qunit');
grunt.loadNpmTasks('grunt-contrib-yuidoc');
+ grunt.loadTasks('tasks');
var root = 'src/pixi/',
debug = 'bin/pixi.dev.js',
@@ -79,7 +81,7 @@
},
files: {
srcBlob: '<%= dirs.src %>/**/*.js',
- testBlob: '<%= dirs.test %>/unit/**/*.js',
+ testBlob: '<%= dirs.test %>/{functional,lib/pixi,unit}/**/*.js',
build: '<%= dirs.build %>/pixi.dev.js',
buildMin: '<%= dirs.build %>/pixi.js'
},
@@ -94,7 +96,12 @@
},
jshint: {
beforeconcat: srcFiles,
- test: ['<%= files.testBlob %>'],
+ test: {
+ src: ['<%= files.testBlob %>'],
+ options: {
+ expr: true
+ }
+ },
options: {
asi: true,
smarttabs: true
@@ -128,12 +135,6 @@
]
},
connect: {
- qunit: {
- options: {
- port: grunt.option('port-test') || 9002,
- base: './'
- }
- },
test: {
options: {
port: grunt.option('port-test') || 9002,
@@ -142,13 +143,6 @@
}
}
},
- qunit: {
- all: {
- options: {
- urls: ['http://localhost:' + (grunt.option('port-test') || 9002) + '/test/index.html']
- }
- }
- },
yuidoc: {
compile: {
name: '<%= pkg.name %>',
@@ -161,6 +155,13 @@
outdir: '<%= dirs.docs %>'
}
}
+ },
+ karma: {
+ unit: {
+ configFile: 'test/karma.conf.js',
+ // browsers: ['Chrome'],
+ singleRun: true
+ }
}
});
@@ -182,9 +183,10 @@
}
)
- grunt.registerTask('default', ['concat', 'uglify', 'distribute']);
grunt.registerTask('build', ['concat', 'uglify', 'distribute']);
- grunt.registerTask('test', ['build', 'connect:qunit', 'qunit']);
+ grunt.registerTask('test', ['concat', 'jshint:test', 'karma']);
grunt.registerTask('docs', ['yuidoc']);
-
-}
\ No newline at end of file
+ grunt.registerTask('default', ['test', 'uglify', 'distribute']);
+ // Travis CI task.
+ grunt.registerTask('travis', ['test']);
+}
diff --git a/README.md b/README.md
index c62ef86..690cfe4 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,8 @@

+[](http://travis-ci.org/drkibitz/pixi.js)
+
#### JavaScript 2D Renderer ####
The aim of this project is to provide a fast lightweight 2D library that works
diff --git a/package.json b/package.json
index b373240..1246a68 100644
--- a/package.json
+++ b/package.json
@@ -18,14 +18,21 @@
"main": "bin/pixi.js",
+ "scripts": {
+ "test": "grunt travis --verbose"
+ },
+
"dependencies": {},
"devDependencies": {
"grunt": "~0.4.x",
- "grunt-contrib-jshint": "0.3.x",
+ "grunt-contrib-jshint": "0.6.x",
"grunt-contrib-uglify": "0.2.x",
- "grunt-contrib-connect": "0.2.x",
- "grunt-contrib-qunit": "0.2.x",
+ "grunt-contrib-connect": "0.3.x",
"grunt-contrib-yuidoc": "0.4.x",
- "grunt-contrib-concat": "0.1.x"
+ "grunt-contrib-concat": "0.3.x",
+ "chai": "~1.7.0",
+ "karma": "0.11.0",
+ "karma-firefox-launcher": "0.1.0",
+ "karma-mocha": "0.1.0"
}
}
diff --git a/src/pixi/InteractionManager.js b/src/pixi/InteractionManager.js
index a7c520e..ee82bbd 100644
--- a/src/pixi/InteractionManager.js
+++ b/src/pixi/InteractionManager.js
@@ -62,7 +62,6 @@
this.onTouchEnd = this.onTouchEnd.bind(this);
this.onTouchMove = this.onTouchMove.bind(this);
-
this.last = 0;
}
diff --git a/src/pixi/core/Ellipse.js b/src/pixi/core/Ellipse.js
index 1a95d20..eef1059 100644
--- a/src/pixi/core/Ellipse.js
+++ b/src/pixi/core/Ellipse.js
@@ -78,7 +78,7 @@
return (normx + normy < 0.25);
}
-PIXI.Ellipse.getBounds = function()
+PIXI.Ellipse.prototype.getBounds = function()
{
return new PIXI.Rectangle(this.x, this.y, this.width, this.height);
}
diff --git a/tasks/karma.js b/tasks/karma.js
new file mode 100644
index 0000000..c340485
--- /dev/null
+++ b/tasks/karma.js
@@ -0,0 +1,27 @@
+'use strict';
+
+var path = require('path');
+var server = require('karma').server;
+
+module.exports = function (grunt) {
+ grunt.registerMultiTask('karma', 'run karma.', function() {
+ var done = this.async();
+ var options = this.options({
+ background: false
+ });
+ var data = this.data;
+
+ //merge options onto data, with data taking precedence
+ data = grunt.util._.merge(options, data);
+ data.configFile = path.resolve(data.configFile);
+ if (data.configFile) {
+ data.configFile = grunt.template.process(data.configFile);
+ }
+
+ server.start(
+ data,
+ function(code) {
+ done(!code);
+ });
+ });
+};
diff --git a/test/functional/example-1-basics/bunny.png b/test/functional/example-1-basics/bunny.png
new file mode 100644
index 0000000..79c3167
--- /dev/null
+++ b/test/functional/example-1-basics/bunny.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-30.png b/test/functional/example-1-basics/frame-30.png
new file mode 100644
index 0000000..96e3409
--- /dev/null
+++ b/test/functional/example-1-basics/frame-30.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-60.png b/test/functional/example-1-basics/frame-60.png
new file mode 100644
index 0000000..af3f4ce
--- /dev/null
+++ b/test/functional/example-1-basics/frame-60.png
Binary files differ
diff --git a/test/functional/example-1-basics/frame-90.png b/test/functional/example-1-basics/frame-90.png
new file mode 100644
index 0000000..099b823
--- /dev/null
+++ b/test/functional/example-1-basics/frame-90.png
Binary files differ
diff --git a/test/functional/example-1-basics/index.js b/test/functional/example-1-basics/index.js
new file mode 100644
index 0000000..7ae7a98
--- /dev/null
+++ b/test/functional/example-1-basics/index.js
@@ -0,0 +1,133 @@
+describe('Example 1 - Basics', function () {
+ 'use strict';
+
+ var baseUri = '/base/test/functional/example-1-basics';
+ var expect = chai.expect;
+ var currentFrame = 0;
+ var frameEvents = {};
+ var stage;
+ var renderer;
+ var bunny;
+
+ function onFrame(frame, callback) {
+ frameEvents[frame] = callback;
+ }
+
+ function animate() {
+ currentFrame += 1;
+
+ requestAnimFrame( animate );
+
+ // just for fun, lets rotate mr rabbit a little
+ bunny.rotation += 0.1;
+
+ // render the stage
+ renderer.render(stage);
+
+ if (frameEvents[currentFrame])
+ frameEvents[currentFrame](currentFrame);
+ }
+
+ function initScene() {
+ // create an new instance of a pixi stage
+ stage = new PIXI.Stage(0x66FF99);
+
+ // create a renderer instance
+ renderer = PIXI.autoDetectRenderer(400, 300);
+ console.log('Is PIXI.WebGLRenderer: ' + (renderer instanceof PIXI.WebGLRenderer));
+
+ // add the renderer view element to the DOM
+ document.body.appendChild(renderer.view);
+
+ requestAnimFrame( animate );
+
+ // create a texture from an image path
+ var texture = PIXI.Texture.fromImage(baseUri + "/bunny.png");
+ // create a new Sprite using the texture
+ bunny = new PIXI.Sprite(texture);
+
+ // center the sprites anchor point
+ bunny.anchor.x = 0.5;
+ bunny.anchor.y = 0.5;
+
+ // move the sprite t the center of the screen
+ bunny.position.x = 200;
+ bunny.position.y = 150;
+
+ stage.addChild(bunny);
+ }
+
+ it('assets loaded', function (done) {
+ var loader = new PIXI.AssetLoader([
+ baseUri + '/bunny.png',
+ baseUri + '/frame-30.png',
+ baseUri + '/frame-60.png',
+ baseUri + '/frame-90.png'
+ ]);
+ // loader.on('onProgress', function (event) {
+ // console.log(event.content);
+ // });
+ loader.on('onComplete', function (event) {
+ done();
+ initScene();
+ });
+ loader.load();
+ });
+
+ it('frame 30 should match', function (done) {
+ this.timeout(700);
+ onFrame(30, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-30.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 60 should match', function (done) {
+ this.timeout(1200);
+ onFrame(60, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-60.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ it('frame 90 should match', function (done) {
+ this.timeout(1700);
+ onFrame(90, function () {
+ var str = renderer.view.toDataURL('image/png');
+ //console.log('
');
+ resemble(str)
+ .compareTo(baseUri + '/frame-90.png')
+ .onComplete(function (data) {
+ expect(data).to.be.an('object');
+ expect(data.isSameDimensions).to.equal(true);
+ expect(data.misMatchPercentage).to.be.below(0.2);
+ done();
+ });
+ });
+ });
+
+ // it('capture something', function (done) {
+ // this.timeout(2000000);
+ // onFrame(30, function () {
+ // var img = new Image();
+ // img.src = renderer.view.toDataURL('image/png');
+ // document.body.appendChild(img);
+ // });
+ // });
+});
diff --git a/test/index.html b/test/index.html
deleted file mode 100644
index 9cbcac5..0000000
--- a/test/index.html
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
- Pixi.js Test Suite
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/test/karma.conf.js b/test/karma.conf.js
new file mode 100644
index 0000000..c66a696
--- /dev/null
+++ b/test/karma.conf.js
@@ -0,0 +1,82 @@
+module.exports = function(config) {
+ config.set({
+
+ // base path, that will be used to resolve files and exclude
+ basePath : '../',
+
+ frameworks : ['mocha'],
+
+ // list of files / patterns to load in the browser
+ files : [
+ 'node_modules/chai/chai.js',
+ 'bin/pixi.dev.js',
+ 'test/lib/**/*.js',
+ 'test/unit/**/*.js',
+ // 'test/functional/**/*.js',
+ {pattern: 'test/**/*.png', watched: false, included: false, served: true}
+ ],
+
+ // list of files to exclude
+ exclude : [],
+
+ // use dolts reporter, as travis terminal does not support escaping sequences
+ // possible values: 'dots', 'progress', 'junit', 'teamcity'
+ // CLI --reporters progress
+ reporters : ['progress'],
+
+ // web server port
+ // CLI --port 9876
+ port : 9876,
+
+ // cli runner port
+ // CLI --runner-port 9100
+ runnerPort : 9100,
+
+ // enable / disable colors in the output (reporters and logs)
+ // CLI --colors --no-colors
+ colors : true,
+
+ // level of logging
+ // possible values: karma.LOG_DISABLE || karma.LOG_ERROR || karma.LOG_WARN || karma.LOG_INFO || karma.LOG_DEBUG
+ // CLI --log-level debug
+ logLevel : config.LOG_DEBUG,
+
+ // enable / disable watching file and executing tests whenever any file changes
+ // CLI --auto-watch --no-auto-watch
+ autoWatch : false,
+
+ // Start these browsers, currently available:
+ // - Chrome
+ // - ChromeCanary
+ // - Firefox
+ // - Opera
+ // - Safari (only Mac)
+ // - PhantomJS
+ // - IE (only Windows)
+ // CLI --browsers Chrome,Firefox,Safari
+ browsers : ['Firefox'],
+
+ // If browser does not capture in given timeout [ms], kill it
+ // CLI --capture-timeout 5000
+ captureTimeout : 5000,
+
+ // Auto run tests on start (when browsers are captured) and exit
+ // CLI --single-run --no-single-run
+ singleRun : true,
+
+ // report which specs are slower than 500ms
+ // CLI --report-slower-than 500
+ reportSlowerThan : 1000,
+
+ preprocessors : {
+ // '**/client/js/*.js': 'coverage'
+ },
+
+ plugins : [
+ 'karma-mocha',
+ // 'karma-chrome-launcher',
+ 'karma-firefox-launcher',
+ // 'karma-phantomjs-launcher'
+ ]
+ });
+};
diff --git a/test/lib/pixi/core/Matrix.js b/test/lib/pixi/core/Matrix.js
new file mode 100644
index 0000000..d26386b
--- /dev/null
+++ b/test/lib/pixi/core/Matrix.js
@@ -0,0 +1,40 @@
+
+function pixi_core_Matrix_confirmNewMat3(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(1);
+ expect(matrix[5]).to.equal(0);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(1);
+}
+
+function pixi_core_Matrix_confirmNewMat4(matrix) {
+ var expect = chai.expect;
+
+ expect(matrix).to.be.an.instanceof(PIXI.Matrix);
+ expect(matrix).to.not.be.empty;
+
+ expect(matrix[0]).to.equal(1);
+ expect(matrix[1]).to.equal(0);
+ expect(matrix[2]).to.equal(0);
+ expect(matrix[3]).to.equal(0);
+ expect(matrix[4]).to.equal(0);
+ expect(matrix[5]).to.equal(1);
+ expect(matrix[6]).to.equal(0);
+ expect(matrix[7]).to.equal(0);
+ expect(matrix[8]).to.equal(0);
+ expect(matrix[9]).to.equal(0);
+ expect(matrix[10]).to.equal(1);
+ expect(matrix[11]).to.equal(0);
+ expect(matrix[12]).to.equal(0);
+ expect(matrix[13]).to.equal(0);
+ expect(matrix[14]).to.equal(0);
+ expect(matrix[15]).to.equal(1);
+}
diff --git a/test/lib/pixi/core/Point.js b/test/lib/pixi/core/Point.js
new file mode 100644
index 0000000..e5df07b
--- /dev/null
+++ b/test/lib/pixi/core/Point.js
@@ -0,0 +1,10 @@
+
+function pixi_core_Point_confirm(obj, x, y) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Point);
+ expect(obj).to.respondTo('clone');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+}
diff --git a/test/lib/pixi/core/Rectangle.js b/test/lib/pixi/core/Rectangle.js
new file mode 100644
index 0000000..23f0d12
--- /dev/null
+++ b/test/lib/pixi/core/Rectangle.js
@@ -0,0 +1,13 @@
+
+function pixi_core_Rectangle_confirm(obj, x, y, width, height) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.Rectangle);
+ expect(obj).to.respondTo('clone');
+ expect(obj).to.respondTo('contains');
+
+ expect(obj).to.have.property('x', x);
+ expect(obj).to.have.property('y', y);
+ expect(obj).to.have.property('width', width);
+ expect(obj).to.have.property('height', height);
+}
diff --git a/test/lib/pixi/display/DisplayObject.js b/test/lib/pixi/display/DisplayObject.js
new file mode 100644
index 0000000..1388a7f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObject.js
@@ -0,0 +1,43 @@
+
+function pixi_display_DisplayObject_confirmNew(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObject);
+ expect(obj).to.respondTo('setInteractive');
+ expect(obj).to.respondTo('addFilter');
+ expect(obj).to.respondTo('removeFilter');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.property('last', obj);
+ expect(obj).to.have.property('first', obj);
+
+ expect(obj).to.contain.property('position');
+ pixi_core_Point_confirm(obj.position, 0, 0);
+ expect(obj).to.contain.property('scale');
+ pixi_core_Point_confirm(obj.scale, 1, 1);
+ expect(obj).to.contain.property('pivot');
+ pixi_core_Point_confirm(obj.pivot, 0, 0);
+
+ expect(obj).to.have.property('rotation', 0);
+ expect(obj).to.have.property('alpha', 1);
+ expect(obj).to.have.property('visible', true);
+ expect(obj).to.have.property('buttonMode', false);
+ expect(obj).to.have.property('parent', null);
+ expect(obj).to.have.property('worldAlpha', 1);
+
+ expect(obj).to.have.property('hitArea');
+ expect(obj).to.have.property('interactive'); // TODO: Have a better default value
+ expect('mask' in obj).to.be.true; // TODO: Have a better default value
+ expect(obj.mask).to.be.undefined;
+
+ expect(obj).to.have.property('renderable');
+ expect(obj).to.have.property('stage');
+
+ expect(obj).to.have.deep.property('worldTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.worldTransform);
+ expect(obj).to.have.deep.property('localTransform.length', 9);
+ pixi_core_Matrix_confirmNewMat3(obj.localTransform);
+
+ expect(obj).to.have.deep.property('color.length', 0);
+ expect(obj).to.have.property('dynamic', true);
+}
diff --git a/test/lib/pixi/display/DisplayObjectContainer.js b/test/lib/pixi/display/DisplayObjectContainer.js
new file mode 100644
index 0000000..085c59f
--- /dev/null
+++ b/test/lib/pixi/display/DisplayObjectContainer.js
@@ -0,0 +1,16 @@
+
+function pixi_display_DisplayObjectContainer_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObject_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.DisplayObjectContainer);
+ expect(obj).to.respondTo('addChild');
+ expect(obj).to.respondTo('addChildAt');
+ expect(obj).to.respondTo('swapChildren');
+ expect(obj).to.respondTo('getChildAt');
+ expect(obj).to.respondTo('removeChild');
+ expect(obj).to.respondTo('updateTransform');
+
+ expect(obj).to.have.deep.property('children.length', 0);
+}
diff --git a/test/lib/pixi/display/Sprite.js b/test/lib/pixi/display/Sprite.js
new file mode 100644
index 0000000..cc7a2d6
--- /dev/null
+++ b/test/lib/pixi/display/Sprite.js
@@ -0,0 +1,28 @@
+
+function pixi_display_Sprite_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Sprite);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ expect(obj).to.have.property('hitArea', null);
+ expect(obj).to.have.property('interactive', false);
+ expect(obj).to.have.property('renderable', true);
+ expect(obj).to.have.property('stage', null);
+
+ expect(obj).to.have.property('anchor');
+ pixi_core_Point_confirm(obj.anchor, 0, 0);
+
+ expect(obj).to.have.property('blendMode', PIXI.blendModes.NORMAL);
+ expect(obj).to.have.property('width', 1); // TODO: is 1 expected
+ expect(obj).to.have.property('height', 1); // TODO: is 1 expected
+
+ // FIXME: Just make this a boolean that is always there
+ expect(!!obj.updateFrame).to.equal(obj.texture.baseTexture.hasLoaded);
+
+ expect(obj).to.have.property('texture');
+ pixi_textures_Texture_confirmNew(obj.texture, done);
+}
diff --git a/test/lib/pixi/extras/Strip.js b/test/lib/pixi/extras/Strip.js
new file mode 100644
index 0000000..8927a8a
--- /dev/null
+++ b/test/lib/pixi/extras/Strip.js
@@ -0,0 +1,12 @@
+
+function pixi_extras_Strip_confirmNew(obj) {
+ var expect = chai.expect;
+
+ pixi_display_DisplayObjectContainer_confirmNew(obj);
+
+ expect(obj).to.be.an.instanceof(PIXI.Strip);
+ expect(obj).to.respondTo('setTexture');
+ expect(obj).to.respondTo('onTextureUpdate');
+
+ // TODO: Test properties
+}
diff --git a/test/lib/pixi/textures/Texture.js b/test/lib/pixi/textures/Texture.js
new file mode 100644
index 0000000..d5867b6
--- /dev/null
+++ b/test/lib/pixi/textures/Texture.js
@@ -0,0 +1,31 @@
+
+function pixi_textures_Texture_confirmNew(obj, done) {
+ var expect = chai.expect;
+
+ function confirmFrameDone() {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, obj.baseTexture.width, obj.baseTexture.height);
+
+ expect(obj).to.have.property('width', obj.baseTexture.width);
+ expect(obj).to.have.property('height', obj.baseTexture.height);
+ done();
+ }
+
+ expect(obj).to.be.an.instanceof(PIXI.Texture);
+ pixi_utils_EventTarget_like(obj);
+
+ expect(obj).to.have.property('baseTexture')
+ .and.to.be.an.instanceof(PIXI.BaseTexture);
+
+ expect(obj).to.have.property('scope', obj);
+
+ expect(obj).to.have.property('trim');
+ pixi_core_Point_confirm(obj.trim, 0, 0);
+
+ expect(obj).to.have.property('frame');
+ if (obj.baseTexture.hasLoaded) {
+ confirmFrameDone();
+ } else {
+ pixi_core_Rectangle_confirm(obj.frame, 0, 0, 1, 1);
+ obj.addEventListener('update', confirmFrameDone);
+ }
+}
diff --git a/test/lib/pixi/utils/EventTarget.js b/test/lib/pixi/utils/EventTarget.js
new file mode 100644
index 0000000..7b1dcfa
--- /dev/null
+++ b/test/lib/pixi/utils/EventTarget.js
@@ -0,0 +1,8 @@
+
+function pixi_utils_EventTarget_like(obj) {
+ var expect = chai.expect;
+
+ expect(obj).to.respondTo('addEventListener');
+ expect(obj).to.respondTo('dispatchEvent');
+ expect(obj).to.respondTo('removeEventListener');
+}
diff --git a/test/lib/qunit-1.11.0.css b/test/lib/qunit-1.11.0.css
deleted file mode 100644
index d7fc0c8..0000000
--- a/test/lib/qunit-1.11.0.css
+++ /dev/null
@@ -1,244 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-/** Font Family and Sizes */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
- font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
-}
-
-#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
-#qunit-tests { font-size: smaller; }
-
-
-/** Resets */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter {
- margin: 0;
- padding: 0;
-}
-
-
-/** Header */
-
-#qunit-header {
- padding: 0.5em 0 0.5em 1em;
-
- color: #8699a4;
- background-color: #0d3349;
-
- font-size: 1.5em;
- line-height: 1em;
- font-weight: normal;
-
- border-radius: 5px 5px 0 0;
- -moz-border-radius: 5px 5px 0 0;
- -webkit-border-top-right-radius: 5px;
- -webkit-border-top-left-radius: 5px;
-}
-
-#qunit-header a {
- text-decoration: none;
- color: #c2ccd1;
-}
-
-#qunit-header a:hover,
-#qunit-header a:focus {
- color: #fff;
-}
-
-#qunit-testrunner-toolbar label {
- display: inline-block;
- padding: 0 .5em 0 .1em;
-}
-
-#qunit-banner {
- height: 5px;
-}
-
-#qunit-testrunner-toolbar {
- padding: 0.5em 0 0.5em 2em;
- color: #5E740B;
- background-color: #eee;
- overflow: hidden;
-}
-
-#qunit-userAgent {
- padding: 0.5em 0 0.5em 2.5em;
- background-color: #2b81af;
- color: #fff;
- text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
-}
-
-#qunit-modulefilter-container {
- float: right;
-}
-
-/** Tests: Pass/Fail */
-
-#qunit-tests {
- list-style-position: inside;
-}
-
-#qunit-tests li {
- padding: 0.4em 0.5em 0.4em 2.5em;
- border-bottom: 1px solid #fff;
- list-style-position: inside;
-}
-
-#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running {
- display: none;
-}
-
-#qunit-tests li strong {
- cursor: pointer;
-}
-
-#qunit-tests li a {
- padding: 0.5em;
- color: #c2ccd1;
- text-decoration: none;
-}
-#qunit-tests li a:hover,
-#qunit-tests li a:focus {
- color: #000;
-}
-
-#qunit-tests li .runtime {
- float: right;
- font-size: smaller;
-}
-
-.qunit-assert-list {
- margin-top: 0.5em;
- padding: 0.5em;
-
- background-color: #fff;
-
- border-radius: 5px;
- -moz-border-radius: 5px;
- -webkit-border-radius: 5px;
-}
-
-.qunit-collapsed {
- display: none;
-}
-
-#qunit-tests table {
- border-collapse: collapse;
- margin-top: .2em;
-}
-
-#qunit-tests th {
- text-align: right;
- vertical-align: top;
- padding: 0 .5em 0 0;
-}
-
-#qunit-tests td {
- vertical-align: top;
-}
-
-#qunit-tests pre {
- margin: 0;
- white-space: pre-wrap;
- word-wrap: break-word;
-}
-
-#qunit-tests del {
- background-color: #e0f2be;
- color: #374e0c;
- text-decoration: none;
-}
-
-#qunit-tests ins {
- background-color: #ffcaca;
- color: #500;
- text-decoration: none;
-}
-
-/*** Test Counts */
-
-#qunit-tests b.counts { color: black; }
-#qunit-tests b.passed { color: #5E740B; }
-#qunit-tests b.failed { color: #710909; }
-
-#qunit-tests li li {
- padding: 5px;
- background-color: #fff;
- border-bottom: none;
- list-style-position: inside;
-}
-
-/*** Passing Styles */
-
-#qunit-tests li li.pass {
- color: #3c510c;
- background-color: #fff;
- border-left: 10px solid #C6E746;
-}
-
-#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
-#qunit-tests .pass .test-name { color: #366097; }
-
-#qunit-tests .pass .test-actual,
-#qunit-tests .pass .test-expected { color: #999999; }
-
-#qunit-banner.qunit-pass { background-color: #C6E746; }
-
-/*** Failing Styles */
-
-#qunit-tests li li.fail {
- color: #710909;
- background-color: #fff;
- border-left: 10px solid #EE5757;
- white-space: pre;
-}
-
-#qunit-tests > li:last-child {
- border-radius: 0 0 5px 5px;
- -moz-border-radius: 0 0 5px 5px;
- -webkit-border-bottom-right-radius: 5px;
- -webkit-border-bottom-left-radius: 5px;
-}
-
-#qunit-tests .fail { color: #000000; background-color: #EE5757; }
-#qunit-tests .fail .test-name,
-#qunit-tests .fail .module-name { color: #000000; }
-
-#qunit-tests .fail .test-actual { color: #EE5757; }
-#qunit-tests .fail .test-expected { color: green; }
-
-#qunit-banner.qunit-fail { background-color: #EE5757; }
-
-
-/** Result */
-
-#qunit-testresult {
- padding: 0.5em 0.5em 0.5em 2.5em;
-
- color: #2b81af;
- background-color: #D2E0E6;
-
- border-bottom: 1px solid white;
-}
-#qunit-testresult .module-name {
- font-weight: bold;
-}
-
-/** Fixture */
-
-#qunit-fixture {
- position: absolute;
- top: -10000px;
- left: -10000px;
- width: 1000px;
- height: 1000px;
-}
diff --git a/test/lib/qunit-1.11.0.js b/test/lib/qunit-1.11.0.js
deleted file mode 100644
index 302545f..0000000
--- a/test/lib/qunit-1.11.0.js
+++ /dev/null
@@ -1,2152 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-(function( window ) {
-
-var QUnit,
- assert,
- config,
- onErrorFnPrev,
- testId = 0,
- fileName = (sourceFromStacktrace( 0 ) || "" ).replace(/(:\d+)+\)?/, "").replace(/.+\//, ""),
- toString = Object.prototype.toString,
- hasOwn = Object.prototype.hasOwnProperty,
- // Keep a local reference to Date (GH-283)
- Date = window.Date,
- defined = {
- setTimeout: typeof window.setTimeout !== "undefined",
- sessionStorage: (function() {
- var x = "qunit-test-string";
- try {
- sessionStorage.setItem( x, x );
- sessionStorage.removeItem( x );
- return true;
- } catch( e ) {
- return false;
- }
- }())
- },
- /**
- * Provides a normalized error string, correcting an issue
- * with IE 7 (and prior) where Error.prototype.toString is
- * not properly implemented
- *
- * Based on http://es5.github.com/#x15.11.4.4
- *
- * @param {String|Error} error
- * @return {String} error message
- */
- errorString = function( error ) {
- var name, message,
- errorString = error.toString();
- if ( errorString.substring( 0, 7 ) === "[object" ) {
- name = error.name ? error.name.toString() : "Error";
- message = error.message ? error.message.toString() : "";
- if ( name && message ) {
- return name + ": " + message;
- } else if ( name ) {
- return name;
- } else if ( message ) {
- return message;
- } else {
- return "Error";
- }
- } else {
- return errorString;
- }
- },
- /**
- * Makes a clone of an object using only Array or Object as base,
- * and copies over the own enumerable properties.
- *
- * @param {Object} obj
- * @return {Object} New object with only the own properties (recursively).
- */
- objectValues = function( obj ) {
- // Grunt 0.3.x uses an older version of jshint that still has jshint/jshint#392.
- /*jshint newcap: false */
- var key, val,
- vals = QUnit.is( "array", obj ) ? [] : {};
- for ( key in obj ) {
- if ( hasOwn.call( obj, key ) ) {
- val = obj[key];
- vals[key] = val === Object(val) ? objectValues(val) : val;
- }
- }
- return vals;
- };
-
-function Test( settings ) {
- extend( this, settings );
- this.assertions = [];
- this.testNumber = ++Test.count;
-}
-
-Test.count = 0;
-
-Test.prototype = {
- init: function() {
- var a, b, li,
- tests = id( "qunit-tests" );
-
- if ( tests ) {
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml;
-
- // `a` initialized at top of scope
- a = document.createElement( "a" );
- a.innerHTML = "Rerun";
- a.href = QUnit.url({ testNumber: this.testNumber });
-
- li = document.createElement( "li" );
- li.appendChild( b );
- li.appendChild( a );
- li.className = "running";
- li.id = this.id = "qunit-test-output" + testId++;
-
- tests.appendChild( li );
- }
- },
- setup: function() {
- if ( this.module !== config.previousModule ) {
- if ( config.previousModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.previousModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
- config.previousModule = this.module;
- config.moduleStats = { all: 0, bad: 0 };
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- } else if ( config.autorun ) {
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- }
-
- config.current = this;
-
- this.testEnvironment = extend({
- setup: function() {},
- teardown: function() {}
- }, this.moduleTestEnvironment );
-
- this.started = +new Date();
- runLoggingCallbacks( "testStart", QUnit, {
- name: this.testName,
- module: this.module
- });
-
- // allow utility functions to access the current test environment
- // TODO why??
- QUnit.current_testEnvironment = this.testEnvironment;
-
- if ( !config.pollution ) {
- saveGlobal();
- }
- if ( config.notrycatch ) {
- this.testEnvironment.setup.call( this.testEnvironment );
- return;
- }
- try {
- this.testEnvironment.setup.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Setup failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- },
- run: function() {
- config.current = this;
-
- var running = id( "qunit-testresult" );
-
- if ( running ) {
- running.innerHTML = "Running:
" + this.nameHtml;
- }
-
- if ( this.async ) {
- QUnit.stop();
- }
-
- this.callbackStarted = +new Date();
-
- if ( config.notrycatch ) {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- return;
- }
-
- try {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- } catch( e ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
-
- QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + " " + this.stack + ": " + ( e.message || e ), extractStacktrace( e, 0 ) );
- // else next test will carry the responsibility
- saveGlobal();
-
- // Restart the tests if they're blocking
- if ( config.blocking ) {
- QUnit.start();
- }
- }
- },
- teardown: function() {
- config.current = this;
- if ( config.notrycatch ) {
- if ( typeof this.callbackRuntime === "undefined" ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
- }
- this.testEnvironment.teardown.call( this.testEnvironment );
- return;
- } else {
- try {
- this.testEnvironment.teardown.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Teardown failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- }
- checkPollution();
- },
- finish: function() {
- config.current = this;
- if ( config.requireExpects && this.expected === null ) {
- QUnit.pushFailure( "Expected number of assertions to be defined, but expect() was not called.", this.stack );
- } else if ( this.expected !== null && this.expected !== this.assertions.length ) {
- QUnit.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack );
- } else if ( this.expected === null && !this.assertions.length ) {
- QUnit.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions.", this.stack );
- }
-
- var i, assertion, a, b, time, li, ol,
- test = this,
- good = 0,
- bad = 0,
- tests = id( "qunit-tests" );
-
- this.runtime = +new Date() - this.started;
- config.stats.all += this.assertions.length;
- config.moduleStats.all += this.assertions.length;
-
- if ( tests ) {
- ol = document.createElement( "ol" );
- ol.className = "qunit-assert-list";
-
- for ( i = 0; i < this.assertions.length; i++ ) {
- assertion = this.assertions[i];
-
- li = document.createElement( "li" );
- li.className = assertion.result ? "pass" : "fail";
- li.innerHTML = assertion.message || ( assertion.result ? "okay" : "failed" );
- ol.appendChild( li );
-
- if ( assertion.result ) {
- good++;
- } else {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
-
- // store result when possible
- if ( QUnit.config.reorder && defined.sessionStorage ) {
- if ( bad ) {
- sessionStorage.setItem( "qunit-test-" + this.module + "-" + this.testName, bad );
- } else {
- sessionStorage.removeItem( "qunit-test-" + this.module + "-" + this.testName );
- }
- }
-
- if ( bad === 0 ) {
- addClass( ol, "qunit-collapsed" );
- }
-
- // `b` initialized at top of scope
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml + " (