;(function(root) {
|
|
'use strict';
|
|
|
|
/** Use a single `load` function */
|
|
var load = typeof require == 'function' ? require : root.load;
|
|
|
|
/** The unit testing framework */
|
|
var QUnit = (function() {
|
|
var noop = Function.prototype;
|
|
return root.QUnit || (
|
|
root.addEventListener || (root.addEventListener = noop),
|
|
root.setTimeout || (root.setTimeout = noop),
|
|
root.QUnit = load('../node_modules/qunitjs/qunit/qunit.js') || root.QUnit,
|
|
(load('../node_modules/qunit-clib/qunit-clib.js') || { 'runInContext': noop }).runInContext(root),
|
|
addEventListener === noop && delete root.addEventListener,
|
|
root.QUnit
|
|
);
|
|
}());
|
|
|
|
/** The `utf8` object to test */
|
|
var utf8 = root.utf8 || (root.utf8 = (
|
|
utf8 = load('../utf8.js') || root.utf8,
|
|
utf8 = utf8.utf8 || utf8
|
|
));
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
function forEach(array, fn) {
|
|
var index = -1;
|
|
var length = array.length;
|
|
while (++index < length) {
|
|
fn(array[index]);
|
|
}
|
|
}
|
|
|
|
// Quick and dirty test to see if we’re in Node & need extended tests
|
|
var runExtendedTests = (function() {
|
|
try {
|
|
return process.argv[0] == 'node' && process.argv[2] == '--extended';
|
|
} catch(error) { }
|
|
}());
|
|
|
|
var data = [
|
|
// 1-byte
|
|
{
|
|
'codePoint': 0x0000,
|
|
'decoded': '\0',
|
|
'encoded': '\0'
|
|
},
|
|
{
|
|
'codePoint': 0x005C,
|
|
'decoded': '\x5C',
|
|
'encoded': '\x5C'
|
|
},
|
|
{
|
|
'codePoint': 0x007F,
|
|
'decoded': '\x7F',
|
|
'encoded': '\x7F'
|
|
},
|
|
|
|
// 2-byte
|
|
{
|
|
'codePoint': 0x0080,
|
|
'decoded': '\x80',
|
|
'encoded': '\xC2\x80'
|
|
},
|
|
{
|
|
'codePoint': 0x05CA,
|
|
'decoded': '\u05CA',
|
|
'encoded': '\xD7\x8A'
|
|
},
|
|
{
|
|
'codePoint': 0x07FF,
|
|
'decoded': '\u07FF',
|
|
'encoded': '\xDF\xBF',
|
|
},
|
|
|
|
// 3-byte
|
|
{
|
|
'codePoint': 0x0800,
|
|
'decoded': '\u0800',
|
|
'encoded': '\xE0\xA0\x80',
|
|
},
|
|
{
|
|
'codePoint': 0x2C3C,
|
|
'decoded': '\u2C3C',
|
|
'encoded': '\xE2\xB0\xBC'
|
|
},
|
|
{
|
|
'codePoint': 0xFFFF,
|
|
'decoded': '\uFFFF',
|
|
'encoded': '\xEF\xBF\xBF'
|
|
},
|
|
// unmatched surrogate halves
|
|
// high surrogates: 0xD800 to 0xDBFF
|
|
{
|
|
'codePoint': 0xD800,
|
|
'decoded': '\uD800',
|
|
'encoded': '\xED\xA0\x80'
|
|
},
|
|
{
|
|
'description': 'High surrogate followed by another high surrogate',
|
|
'decoded': '\uD800\uD800',
|
|
'encoded': '\xED\xA0\x80\xED\xA0\x80'
|
|
},
|
|
{
|
|
'description': 'High surrogate followed by a symbol that is not a surrogate',
|
|
'decoded': '\uD800A',
|
|
'encoded': '\xED\xA0\x80A'
|
|
},
|
|
{
|
|
'description': 'Unmatched high surrogate, followed by a surrogate pair, followed by an unmatched high surrogate',
|
|
'decoded': '\uD800\uD834\uDF06\uD800',
|
|
'encoded': '\xED\xA0\x80\xF0\x9D\x8C\x86\xED\xA0\x80'
|
|
},
|
|
{
|
|
'codePoint': 0xD9AF,
|
|
'decoded': '\uD9AF',
|
|
'encoded': '\xED\xA6\xAF'
|
|
},
|
|
{
|
|
'codePoint': 0xDBFF,
|
|
'decoded': '\uDBFF',
|
|
'encoded': '\xED\xAF\xBF'
|
|
},
|
|
// low surrogates: 0xDC00 to 0xDFFF
|
|
{
|
|
'codePoint': 0xDC00,
|
|
'decoded': '\uDC00',
|
|
'encoded': '\xED\xB0\x80'
|
|
},
|
|
{
|
|
'description': 'Low surrogate followed by another low surrogate',
|
|
'decoded': '\uDC00\uDC00',
|
|
'encoded': '\xED\xB0\x80\xED\xB0\x80'
|
|
},
|
|
{
|
|
'description': 'Low surrogate followed by a symbol that is not a surrogate',
|
|
'decoded': '\uDC00A',
|
|
'encoded': '\xED\xB0\x80A'
|
|
},
|
|
{
|
|
'description': 'Unmatched low surrogate, followed by a surrogate pair, followed by an unmatched low surrogate',
|
|
'decoded': '\uDC00\uD834\uDF06\uDC00',
|
|
'encoded': '\xED\xB0\x80\xF0\x9D\x8C\x86\xED\xB0\x80'
|
|
},
|
|
{
|
|
'codePoint': 0xDEEE,
|
|
'decoded': '\uDEEE',
|
|
'encoded': '\xED\xBB\xAE'
|
|
},
|
|
{
|
|
'codePoint': 0xDFFF,
|
|
'decoded': '\uDFFF',
|
|
'encoded': '\xED\xBF\xBF'
|
|
},
|
|
|
|
// 4-byte
|
|
{
|
|
'codePoint': 0x010000,
|
|
'decoded': '\uD800\uDC00',
|
|
'encoded': '\xF0\x90\x80\x80'
|
|
},
|
|
{
|
|
'codePoint': 0x01D306,
|
|
'decoded': '\uD834\uDF06',
|
|
'encoded': '\xF0\x9D\x8C\x86'
|
|
},
|
|
{
|
|
'codePoint': 0x10FFF,
|
|
'decoded': '\uDBFF\uDFFF',
|
|
'encoded': '\xF4\x8F\xBF\xBF'
|
|
}
|
|
];
|
|
|
|
if (runExtendedTests) {
|
|
data = data.concat(require('./data.json'));
|
|
}
|
|
|
|
// `throws` is a reserved word in ES3; alias it to avoid errors
|
|
var raises = QUnit.assert['throws'];
|
|
|
|
// explicitly call `QUnit.module()` instead of `module()`
|
|
// in case we are in a CLI environment
|
|
QUnit.module('utf8.js');
|
|
|
|
test('encode/decode', function() {
|
|
forEach(data, function(object) {
|
|
var description = object.description || 'U+' + object.codePoint.toString(16).toUpperCase();
|
|
;
|
|
equal(
|
|
object.encoded,
|
|
utf8.encode(object.decoded),
|
|
'Encoding: ' + description
|
|
);
|
|
equal(
|
|
object.decoded,
|
|
utf8.decode(object.encoded),
|
|
'Decoding: ' + description
|
|
);
|
|
});
|
|
|
|
// Error handling
|
|
raises(
|
|
function() {
|
|
utf8.decode('\uFFFF');
|
|
},
|
|
Error,
|
|
'Error: invalid UTF-8 detected'
|
|
);
|
|
raises(
|
|
function() {
|
|
utf8.decode('\xE9\x00\x00');
|
|
},
|
|
Error,
|
|
'Error: invalid continuation byte (4-byte sequence expected)'
|
|
);
|
|
raises(
|
|
function() {
|
|
utf8.decode('\xC2\uFFFF');
|
|
},
|
|
Error,
|
|
'Error: invalid continuation byte'
|
|
);
|
|
raises(
|
|
function() {
|
|
utf8.decode('\xF0\x9D');
|
|
},
|
|
Error,
|
|
'Error: invalid byte index'
|
|
);
|
|
});
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
// configure QUnit and call `QUnit.start()` for
|
|
// Narwhal, Node.js, PhantomJS, Rhino, and RingoJS
|
|
if (!root.document || root.phantom) {
|
|
QUnit.config.noglobals = true;
|
|
QUnit.start();
|
|
}
|
|
}(typeof global == 'object' && global || this));
|