tests.js 5.9 KB

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