byte-helpers.test.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321
  1. import QUnit from 'qunit';
  2. import {
  3. bytesToString,
  4. stringToBytes,
  5. toUint8,
  6. concatTypedArrays,
  7. toHexString,
  8. toBinaryString,
  9. bytesToNumber,
  10. numberToBytes,
  11. bytesMatch
  12. } from '../src/byte-helpers.js';
  13. import window from 'global/window';
  14. const arrayNames = [];
  15. const BigInt = window.BigInt;
  16. [
  17. 'Array',
  18. 'Int8Array',
  19. 'Uint8Array',
  20. 'Uint8ClampedArray',
  21. 'Int16Array',
  22. 'Uint16Array',
  23. 'Int32Array',
  24. 'Uint32Array',
  25. 'Float32Array',
  26. 'Float64Array'
  27. ].forEach(function(name) {
  28. if (window[name]) {
  29. arrayNames.push(name);
  30. }
  31. });
  32. QUnit.module('bytesToString');
  33. const testString = 'hello竜';
  34. const testBytes = toUint8([
  35. // h
  36. 0x68,
  37. // e
  38. 0x65,
  39. // l
  40. 0x6c,
  41. // l
  42. 0x6c,
  43. // o
  44. 0x6f,
  45. // 竜
  46. 0xe7, 0xab, 0x9c
  47. ]);
  48. const rawBytes = toUint8([0x47, 0x40, 0x00, 0x10, 0x00, 0x00, 0xb0, 0x0d, 0x00, 0x01]);
  49. QUnit.test('should function as expected', function(assert) {
  50. arrayNames.forEach(function(name) {
  51. const testObj = name === 'Array' ? testBytes : new window[name](testBytes);
  52. assert.equal(bytesToString(testObj), testString, `testString work as a string arg with ${name}`);
  53. assert.equal(bytesToString(new window[name]()), '', `empty ${name} returns empty string`);
  54. });
  55. assert.equal(bytesToString(), '', 'undefined returns empty string');
  56. assert.equal(bytesToString(null), '', 'null returns empty string');
  57. assert.equal(bytesToString(stringToBytes(testString)), testString, 'stringToBytes -> bytesToString works');
  58. });
  59. QUnit.module('stringToBytes');
  60. QUnit.test('should function as expected', function(assert) {
  61. assert.deepEqual(stringToBytes(testString), testBytes, 'returns an array of bytes');
  62. assert.deepEqual(stringToBytes(), toUint8(), 'empty array for undefined');
  63. assert.deepEqual(stringToBytes(null), toUint8(), 'empty array for null');
  64. assert.deepEqual(stringToBytes(''), toUint8(), 'empty array for empty string');
  65. assert.deepEqual(stringToBytes(10), toUint8([0x31, 0x30]), 'converts numbers to strings');
  66. assert.deepEqual(stringToBytes(bytesToString(testBytes)), testBytes, 'bytesToString -> stringToBytes works');
  67. assert.deepEqual(stringToBytes(bytesToString(rawBytes), true), rawBytes, 'equal to original with raw bytes mode');
  68. assert.notDeepEqual(stringToBytes(bytesToString(rawBytes)), rawBytes, 'without raw byte mode works, not equal');
  69. });
  70. QUnit.module('toUint8');
  71. QUnit.test('should function as expected', function(assert) {
  72. const tests = {
  73. undef: {
  74. data: undefined,
  75. expected: new Uint8Array()
  76. },
  77. null: {
  78. data: null,
  79. expected: new Uint8Array()
  80. },
  81. string: {
  82. data: 'foo',
  83. expected: new Uint8Array()
  84. },
  85. NaN: {
  86. data: NaN,
  87. expected: new Uint8Array()
  88. },
  89. object: {
  90. data: {},
  91. expected: new Uint8Array()
  92. },
  93. number: {
  94. data: 0x11,
  95. expected: new Uint8Array([0x11])
  96. }
  97. };
  98. Object.keys(tests).forEach(function(name) {
  99. const {data, expected} = tests[name];
  100. const result = toUint8(data);
  101. assert.ok(result instanceof Uint8Array, `obj is a Uint8Array for ${name}`);
  102. assert.deepEqual(result, expected, `data is as expected for ${name}`);
  103. });
  104. arrayNames.forEach(function(name) {
  105. const testObj = name === 'Array' ? testBytes : new window[name](testBytes);
  106. const uint = toUint8(testObj);
  107. assert.ok(uint instanceof Uint8Array && uint.length > 0, `converted ${name} to Uint8Array`);
  108. });
  109. });
  110. QUnit.module('concatTypedArrays');
  111. QUnit.test('should function as expected', function(assert) {
  112. const tests = {
  113. undef: {
  114. data: concatTypedArrays(),
  115. expected: toUint8([])
  116. },
  117. empty: {
  118. data: concatTypedArrays(toUint8([])),
  119. expected: toUint8([])
  120. },
  121. single: {
  122. data: concatTypedArrays([0x01]),
  123. expected: toUint8([0x01])
  124. },
  125. array: {
  126. data: concatTypedArrays([0x01], [0x02]),
  127. expected: toUint8([0x01, 0x02])
  128. },
  129. uint: {
  130. data: concatTypedArrays(toUint8([0x01]), toUint8([0x02])),
  131. expected: toUint8([0x01, 0x02])
  132. },
  133. buffer: {
  134. data: concatTypedArrays(toUint8([0x01]).buffer, toUint8([0x02]).buffer),
  135. expected: toUint8([0x01, 0x02])
  136. },
  137. manyarray: {
  138. data: concatTypedArrays([0x01], [0x02], [0x03], [0x04]),
  139. expected: toUint8([0x01, 0x02, 0x03, 0x04])
  140. },
  141. manyuint: {
  142. data: concatTypedArrays(toUint8([0x01]), toUint8([0x02]), toUint8([0x03]), toUint8([0x04])),
  143. expected: toUint8([0x01, 0x02, 0x03, 0x04])
  144. }
  145. };
  146. Object.keys(tests).forEach(function(name) {
  147. const {data, expected} = tests[name];
  148. assert.ok(data instanceof Uint8Array, `obj is a Uint8Array for ${name}`);
  149. assert.deepEqual(data, expected, `data is as expected for ${name}`);
  150. });
  151. });
  152. QUnit.module('toHexString');
  153. QUnit.test('should function as expected', function(assert) {
  154. assert.equal(toHexString(0xFF), 'ff', 'works with single value');
  155. assert.equal(toHexString([0xFF, 0xaa]), 'ffaa', 'works with array');
  156. assert.equal(toHexString(toUint8([0xFF, 0xaa])), 'ffaa', 'works with uint8');
  157. assert.equal(toHexString(toUint8([0xFF, 0xaa]).buffer), 'ffaa', 'works with buffer');
  158. assert.equal(toHexString(toUint8([0xFF, 0xaa, 0xbb]).subarray(1, 3)), 'aabb', 'works with subarray');
  159. assert.equal(toHexString([0x01, 0x02, 0x03]), '010203', 'works with single digits');
  160. });
  161. QUnit.module('toBinaryString');
  162. QUnit.test('should function as expected', function(assert) {
  163. const ff = '11111111';
  164. const aa = '10101010';
  165. const bb = '10111011';
  166. const zerof = '00001111';
  167. const one = '00000001';
  168. const zero = '00000000';
  169. const fzero = '11110000';
  170. assert.equal(toBinaryString(0xFF), ff, 'works with single value');
  171. assert.equal(toBinaryString([0xFF, 0xaa]), ff + aa, 'works with array');
  172. assert.equal(toBinaryString(toUint8([0xFF, 0xbb])), ff + bb, 'works with uint8');
  173. assert.equal(toBinaryString(toUint8([0xFF, 0xaa]).buffer), ff + aa, 'works with buffer');
  174. assert.equal(toBinaryString(toUint8([0xFF, 0xaa, 0xbb]).subarray(1, 3)), aa + bb, 'works with subarray');
  175. assert.equal(toBinaryString([0x0F, 0x01, 0xF0, 0x00]), zerof + one + fzero + zero, 'works with varying digits digits');
  176. });
  177. QUnit.module('bytesToNumber');
  178. QUnit.test('sanity', function(assert) {
  179. assert.equal(bytesToNumber(0xFF), 0xFF, 'single value');
  180. assert.equal(bytesToNumber([0xFF, 0x01]), 0xFF01, 'works with array');
  181. assert.equal(bytesToNumber(toUint8([0xFF, 0xbb])), 0xFFBB, 'works with uint8');
  182. assert.equal(bytesToNumber(toUint8([0xFF, 0xaa]).buffer), 0xFFAA, 'works with buffer');
  183. assert.equal(bytesToNumber(toUint8([0xFF, 0xaa, 0xbb]).subarray(1, 3)), 0xAABB, 'works with subarray');
  184. });
  185. QUnit.test('unsigned and littleEndian work', function(assert) {
  186. // works with any number of bits
  187. assert.equal(bytesToNumber([0xFF]), 0xFF, 'u8');
  188. assert.equal(bytesToNumber([0xFF, 0xAA]), 0xFFAA, 'u16');
  189. assert.equal(bytesToNumber([0xFF, 0xAA, 0xBB]), 0xFFAABB, 'u24');
  190. assert.equal(bytesToNumber([0xFF, 0xAA, 0xBB, 0xCC]), 0xFFAABBCC, 'u32');
  191. assert.equal(bytesToNumber([0xFF, 0xAA, 0xBB, 0xCC, 0xDD]), 0xFFAABBCCDD, 'u40');
  192. assert.equal(bytesToNumber([0xFF, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE]), 0xFFAABBCCDDEE, 'u48');
  193. assert.equal(bytesToNumber([0xFF], {le: true}), 0xFF, 'u8 le');
  194. assert.equal(bytesToNumber([0xFF, 0xAA], {le: true}), 0xAAFF, 'u16 le');
  195. assert.equal(bytesToNumber([0xFF, 0xAA, 0xBB], {le: true}), 0xBBAAFF, 'u24 le');
  196. assert.equal(bytesToNumber([0xFF, 0xAA, 0xBB, 0xCC], {le: true}), 0xCCBBAAFF, 'u32 le');
  197. assert.equal(bytesToNumber([0xFF, 0xAA, 0xBB, 0xCC, 0xDD], {le: true}), 0xDDCCBBAAFF, 'u40 le');
  198. assert.equal(bytesToNumber([0xFF, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE], {le: true}), 0xEEDDCCBBAAFF, 'u48 le');
  199. if (BigInt) {
  200. assert.equal(bytesToNumber([0xFF, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0x99]), 0xFFAABBCCDDEE99, 'u56');
  201. assert.equal(bytesToNumber([0xFF, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0x99, 0x88]), 0xFFAABBCCDDEE9988, 'u64');
  202. assert.equal(bytesToNumber([0xFF, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0x99], {le: true}), 0x99EEDDCCBBAAFF, 'u56 le');
  203. assert.equal(bytesToNumber([0xFF, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0x99, 0x88], {le: true}), 0x8899EEDDCCBBAAFF, 'u64 le');
  204. }
  205. });
  206. QUnit.test('signed and littleEndian work', function(assert) {
  207. assert.equal(bytesToNumber([0xF0], {signed: true}), -16, 'i8');
  208. assert.equal(bytesToNumber([0x80, 0x70], {signed: true}), -32656, 'i16');
  209. assert.equal(bytesToNumber([0x80, 0x70, 0x9f], {signed: true}), -8359777, 'i24');
  210. assert.equal(bytesToNumber([0x80, 0x70, 0x9f, 0xFF], {signed: true}), -2140102657, 'i32');
  211. assert.equal(bytesToNumber([0x80, 0x70, 0x9f, 0xFF, 0x10], {signed: true}), -547866280176, 'i40');
  212. assert.equal(bytesToNumber([0x80, 0x70, 0x9f, 0xFF, 0x10, 0x89], {signed: true}), -140253767724919, 'i48');
  213. assert.equal(bytesToNumber([0xF0], {signed: true, le: true}), -16, 'i8 le');
  214. assert.equal(bytesToNumber([0x80, 0x70], {signed: true, le: true}), 0x7080, 'i16 le');
  215. assert.equal(bytesToNumber([0x80, 0x70, 0x9f], {signed: true, le: true}), -6328192, 'i24 le');
  216. assert.equal(bytesToNumber([0x80, 0x70, 0x9f, 0xFF], {signed: true, le: true}), -6328192, 'i32 le');
  217. assert.equal(bytesToNumber([0x80, 0x70, 0x9f, 0xFF, 0x10], {signed: true, le: true}), 73008115840, 'i40 le');
  218. assert.equal(bytesToNumber([0x80, 0x70, 0x9f, 0xFF, 0x10, 0x89], {signed: true, le: true}), -130768875589504, 'i48 le');
  219. if (BigInt) {
  220. assert.equal(bytesToNumber([0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF], {signed: true}), -1, 'i56');
  221. assert.equal(bytesToNumber([0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF], {signed: true}), -1, 'i64');
  222. assert.equal(bytesToNumber([0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF], {signed: true, le: true}), -1, 'i56 le');
  223. assert.equal(bytesToNumber([0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF], {signed: true, le: true}), -1, 'i64 le');
  224. }
  225. });
  226. QUnit.module('numberToBytes');
  227. QUnit.test('unsigned negative and positive', function(assert) {
  228. assert.deepEqual(numberToBytes(), toUint8([0x00]), 'no bytes');
  229. assert.deepEqual(numberToBytes(0xFF), toUint8([0xFF]), 'u8');
  230. assert.deepEqual(numberToBytes(0xFFaa), toUint8([0xFF, 0xaa]), 'u16');
  231. assert.deepEqual(numberToBytes(0xFFaabb), toUint8([0xFF, 0xaa, 0xbb]), 'u24');
  232. assert.deepEqual(numberToBytes(0xFFaabbcc), toUint8([0xFF, 0xaa, 0xbb, 0xcc]), 'u32');
  233. assert.deepEqual(numberToBytes(0xFFaabbccdd), toUint8([0xFF, 0xaa, 0xbb, 0xcc, 0xdd]), 'u40');
  234. assert.deepEqual(numberToBytes(0xFFaabbccddee), toUint8([0xFF, 0xaa, 0xbb, 0xcc, 0xdd, 0xee]), 'u48');
  235. assert.deepEqual(numberToBytes(-16), toUint8([0xF0]), 'negative to u8');
  236. assert.deepEqual(numberToBytes(-32640), toUint8([0x80, 0x80]), 'negative to u16');
  237. assert.deepEqual(numberToBytes(-3264062), toUint8([0xce, 0x31, 0xc2]), 'negative to u24');
  238. assert.deepEqual(numberToBytes(-2139062144), toUint8([0x80, 0x80, 0x80, 0x80]), 'negative to u32');
  239. assert.deepEqual(numberToBytes(-3139062144), toUint8([0xff, 0x44, 0xe5, 0xb6, 0x80]), 'negative u40');
  240. assert.deepEqual(numberToBytes(-3139062144444), toUint8([0xfd, 0x25, 0x21, 0x50, 0xe2, 0x44]), 'negative u48');
  241. if (BigInt) {
  242. assert.deepEqual(numberToBytes(BigInt('0xFFaabbccddee99')), toUint8([0xFF, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0x99]), 'u56');
  243. assert.deepEqual(numberToBytes(BigInt('0xFFaabbccddee9988')), toUint8([0xFF, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0x99, 0x88]), 'u64');
  244. assert.deepEqual(numberToBytes(BigInt('-31390621444448812')), toUint8([0x90, 0x7a, 0x65, 0x67, 0x86, 0x5d, 0xd4]), 'negative to u56');
  245. assert.deepEqual(numberToBytes(BigInt('-9187201950435737472')), toUint8([0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80]), 'u64');
  246. }
  247. });
  248. QUnit.test('unsigned littleEndian negative and positive', function(assert) {
  249. assert.deepEqual(numberToBytes(0xFF, {le: true}), toUint8([0xFF]), 'u8');
  250. assert.deepEqual(numberToBytes(0xFFaa, {le: true}), toUint8([0xaa, 0xFF]), 'u16');
  251. assert.deepEqual(numberToBytes(0xFFaabb, {le: true}), toUint8([0xbb, 0xaa, 0xFF]), 'u24');
  252. assert.deepEqual(numberToBytes(0xFFaabbcc, {le: true}), toUint8([0xcc, 0xbb, 0xaa, 0xff]), 'u32');
  253. assert.deepEqual(numberToBytes(0xFFaabbccdd, {le: true}), toUint8([0xdd, 0xcc, 0xbb, 0xaa, 0xff]), 'u40');
  254. assert.deepEqual(numberToBytes(0xFFaabbccddee, {le: true}), toUint8([0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0xff]), 'u48');
  255. assert.deepEqual(numberToBytes(-16, {le: true}), toUint8([0xF0]), 'negative to u8');
  256. assert.deepEqual(numberToBytes(-32640, {le: true}), toUint8([0x80, 0x80]), 'negative to u16');
  257. assert.deepEqual(numberToBytes(-3264062, {le: true}), toUint8([0xc2, 0x31, 0xce]), 'negative to u24');
  258. assert.deepEqual(numberToBytes(-2139062144, {le: true}), toUint8([0x80, 0x80, 0x80, 0x80]), 'negative to u32');
  259. assert.deepEqual(numberToBytes(-3139062144, {le: true}), toUint8([0x80, 0xb6, 0xe5, 0x44, 0xff]), 'negative u40');
  260. assert.deepEqual(numberToBytes(-3139062144444, {le: true}), toUint8([0x44, 0xe2, 0x50, 0x21, 0x25, 0xfd]), 'negative u48');
  261. if (BigInt) {
  262. assert.deepEqual(numberToBytes(BigInt('0xFFaabbccddee99'), {le: true}), toUint8([0x99, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0xff]), 'u56');
  263. assert.deepEqual(numberToBytes(BigInt('0xFFaabbccddee9988'), {le: true}), toUint8([0x88, 0x99, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0xff]), 'u64');
  264. assert.deepEqual(numberToBytes(BigInt('-31390621444448812'), {le: true}), toUint8([0xd4, 0x5d, 0x86, 0x67, 0x65, 0x7a, 0x90]), 'negative to u56');
  265. assert.deepEqual(numberToBytes(BigInt('-9187201950435737472'), {le: true}), toUint8([0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80]), 'u64');
  266. }
  267. });
  268. QUnit.module('bytesMatch');
  269. QUnit.test('should function as expected', function(assert) {
  270. assert.equal(bytesMatch(), false, 'no a or b bytes, false');
  271. assert.equal(bytesMatch(null, []), false, 'no a bytes, false');
  272. assert.equal(bytesMatch([]), false, 'no b bytes, false');
  273. assert.equal(bytesMatch([0x00], [0x00, 0x02]), false, 'not enough bytes');
  274. assert.equal(bytesMatch([0x00], [0x00], {offset: 1}), false, 'not due to offset');
  275. assert.equal(bytesMatch([0xbb, 0xaa], [0xaa]), false, 'bytes do not match');
  276. assert.equal(bytesMatch([0xaa], [0xaa], {mask: [0x10]}), false, 'bytes do not match due to mask');
  277. assert.equal(bytesMatch([0xaa], [0xaa]), true, 'bytes match');
  278. assert.equal(bytesMatch([0xbb, 0xaa], [0xbb]), true, 'bytes match more a');
  279. assert.equal(bytesMatch([0xbb, 0xaa], [0xaa], {offset: 1}), true, 'bytes match with offset');
  280. assert.equal(bytesMatch([0xaa], [0x20], {mask: [0x20]}), true, 'bytes match with mask');
  281. assert.equal(bytesMatch([0xbb, 0xaa], [0x20], {mask: [0x20], offset: 1}), true, 'bytes match with mask and offset');
  282. assert.equal(bytesMatch([0xbb, 0xaa, 0xaa], [0x20, 0x20], {mask: [0x20, 0x20], offset: 1}), true, 'bytes match with many masks and offset');
  283. });