You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

242 lines
5.4 KiB

  1. ;(function(root) {
  2. 'use strict';
  3. /** Use a single `load` function */
  4. var load = typeof require == 'function' ? require : root.load;
  5. /** The unit testing framework */
  6. var QUnit = (function() {
  7. var noop = Function.prototype;
  8. return root.QUnit || (
  9. root.addEventListener || (root.addEventListener = noop),
  10. root.setTimeout || (root.setTimeout = noop),
  11. root.QUnit = load('../node_modules/qunitjs/qunit/qunit.js') || root.QUnit,
  12. (load('../node_modules/qunit-clib/qunit-clib.js') || { 'runInContext': noop }).runInContext(root),
  13. addEventListener === noop && delete root.addEventListener,
  14. root.QUnit
  15. );
  16. }());
  17. /** The `utf8` object to test */
  18. var utf8 = root.utf8 || (root.utf8 = (
  19. utf8 = load('../utf8.js') || root.utf8,
  20. utf8 = utf8.utf8 || utf8
  21. ));
  22. /*--------------------------------------------------------------------------*/
  23. function forEach(array, fn) {
  24. var index = -1;
  25. var length = array.length;
  26. while (++index < length) {
  27. fn(array[index]);
  28. }
  29. }
  30. // Quick and dirty test to see if we’re in Node & need extended tests
  31. var runExtendedTests = (function() {
  32. try {
  33. return process.argv[0] == 'node' && process.argv[2] == '--extended';
  34. } catch(error) { }
  35. }());
  36. var data = [
  37. // 1-byte
  38. {
  39. 'codePoint': 0x0000,
  40. 'decoded': '\0',
  41. 'encoded': '\0'
  42. },
  43. {
  44. 'codePoint': 0x005C,
  45. 'decoded': '\x5C',
  46. 'encoded': '\x5C'
  47. },
  48. {
  49. 'codePoint': 0x007F,
  50. 'decoded': '\x7F',
  51. 'encoded': '\x7F'
  52. },
  53. // 2-byte
  54. {
  55. 'codePoint': 0x0080,
  56. 'decoded': '\x80',
  57. 'encoded': '\xC2\x80'
  58. },
  59. {
  60. 'codePoint': 0x05CA,
  61. 'decoded': '\u05CA',
  62. 'encoded': '\xD7\x8A'
  63. },
  64. {
  65. 'codePoint': 0x07FF,
  66. 'decoded': '\u07FF',
  67. 'encoded': '\xDF\xBF',
  68. },
  69. // 3-byte
  70. {
  71. 'codePoint': 0x0800,
  72. 'decoded': '\u0800',
  73. 'encoded': '\xE0\xA0\x80',
  74. },
  75. {
  76. 'codePoint': 0x2C3C,
  77. 'decoded': '\u2C3C',
  78. 'encoded': '\xE2\xB0\xBC'
  79. },
  80. {
  81. 'codePoint': 0xFFFF,
  82. 'decoded': '\uFFFF',
  83. 'encoded': '\xEF\xBF\xBF'
  84. },
  85. // unmatched surrogate halves
  86. // high surrogates: 0xD800 to 0xDBFF
  87. {
  88. 'codePoint': 0xD800,
  89. 'decoded': '\uD800',
  90. 'encoded': '\xED\xA0\x80'
  91. },
  92. {
  93. 'description': 'High surrogate followed by another high surrogate',
  94. 'decoded': '\uD800\uD800',
  95. 'encoded': '\xED\xA0\x80\xED\xA0\x80'
  96. },
  97. {
  98. 'description': 'High surrogate followed by a symbol that is not a surrogate',
  99. 'decoded': '\uD800A',
  100. 'encoded': '\xED\xA0\x80A'
  101. },
  102. {
  103. 'description': 'Unmatched high surrogate, followed by a surrogate pair, followed by an unmatched high surrogate',
  104. 'decoded': '\uD800\uD834\uDF06\uD800',
  105. 'encoded': '\xED\xA0\x80\xF0\x9D\x8C\x86\xED\xA0\x80'
  106. },
  107. {
  108. 'codePoint': 0xD9AF,
  109. 'decoded': '\uD9AF',
  110. 'encoded': '\xED\xA6\xAF'
  111. },
  112. {
  113. 'codePoint': 0xDBFF,
  114. 'decoded': '\uDBFF',
  115. 'encoded': '\xED\xAF\xBF'
  116. },
  117. // low surrogates: 0xDC00 to 0xDFFF
  118. {
  119. 'codePoint': 0xDC00,
  120. 'decoded': '\uDC00',
  121. 'encoded': '\xED\xB0\x80'
  122. },
  123. {
  124. 'description': 'Low surrogate followed by another low surrogate',
  125. 'decoded': '\uDC00\uDC00',
  126. 'encoded': '\xED\xB0\x80\xED\xB0\x80'
  127. },
  128. {
  129. 'description': 'Low surrogate followed by a symbol that is not a surrogate',
  130. 'decoded': '\uDC00A',
  131. 'encoded': '\xED\xB0\x80A'
  132. },
  133. {
  134. 'description': 'Unmatched low surrogate, followed by a surrogate pair, followed by an unmatched low surrogate',
  135. 'decoded': '\uDC00\uD834\uDF06\uDC00',
  136. 'encoded': '\xED\xB0\x80\xF0\x9D\x8C\x86\xED\xB0\x80'
  137. },
  138. {
  139. 'codePoint': 0xDEEE,
  140. 'decoded': '\uDEEE',
  141. 'encoded': '\xED\xBB\xAE'
  142. },
  143. {
  144. 'codePoint': 0xDFFF,
  145. 'decoded': '\uDFFF',
  146. 'encoded': '\xED\xBF\xBF'
  147. },
  148. // 4-byte
  149. {
  150. 'codePoint': 0x010000,
  151. 'decoded': '\uD800\uDC00',
  152. 'encoded': '\xF0\x90\x80\x80'
  153. },
  154. {
  155. 'codePoint': 0x01D306,
  156. 'decoded': '\uD834\uDF06',
  157. 'encoded': '\xF0\x9D\x8C\x86'
  158. },
  159. {
  160. 'codePoint': 0x10FFF,
  161. 'decoded': '\uDBFF\uDFFF',
  162. 'encoded': '\xF4\x8F\xBF\xBF'
  163. }
  164. ];
  165. if (runExtendedTests) {
  166. data = data.concat(require('./data.json'));
  167. }
  168. // `throws` is a reserved word in ES3; alias it to avoid errors
  169. var raises = QUnit.assert['throws'];
  170. // explicitly call `QUnit.module()` instead of `module()`
  171. // in case we are in a CLI environment
  172. QUnit.module('utf8.js');
  173. test('encode/decode', function() {
  174. forEach(data, function(object) {
  175. var description = object.description || 'U+' + object.codePoint.toString(16).toUpperCase();
  176. ;
  177. equal(
  178. object.encoded,
  179. utf8.encode(object.decoded),
  180. 'Encoding: ' + description
  181. );
  182. equal(
  183. object.decoded,
  184. utf8.decode(object.encoded),
  185. 'Decoding: ' + description
  186. );
  187. });
  188. // Error handling
  189. raises(
  190. function() {
  191. utf8.decode('\uFFFF');
  192. },
  193. Error,
  194. 'Error: invalid UTF-8 detected'
  195. );
  196. raises(
  197. function() {
  198. utf8.decode('\xE9\x00\x00');
  199. },
  200. Error,
  201. 'Error: invalid continuation byte (4-byte sequence expected)'
  202. );
  203. raises(
  204. function() {
  205. utf8.decode('\xC2\uFFFF');
  206. },
  207. Error,
  208. 'Error: invalid continuation byte'
  209. );
  210. raises(
  211. function() {
  212. utf8.decode('\xF0\x9D');
  213. },
  214. Error,
  215. 'Error: invalid byte index'
  216. );
  217. });
  218. /*--------------------------------------------------------------------------*/
  219. // configure QUnit and call `QUnit.start()` for
  220. // Narwhal, Node.js, PhantomJS, Rhino, and RingoJS
  221. if (!root.document || root.phantom) {
  222. QUnit.config.noglobals = true;
  223. QUnit.start();
  224. }
  225. }(typeof global == 'object' && global || this));