test.hextile.js 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. const expect = chai.expect;
  2. import Websock from '../core/websock.js';
  3. import Display from '../core/display.js';
  4. import HextileDecoder from '../core/decoders/hextile.js';
  5. import FakeWebSocket from './fake.websocket.js';
  6. function testDecodeRect(decoder, x, y, width, height, data, display, depth) {
  7. let sock;
  8. sock = new Websock;
  9. sock.open("ws://example.com");
  10. sock.on('message', () => {
  11. decoder.decodeRect(x, y, width, height, sock, display, depth);
  12. });
  13. // Empty messages are filtered at multiple layers, so we need to
  14. // do a direct call
  15. if (data.length === 0) {
  16. decoder.decodeRect(x, y, width, height, sock, display, depth);
  17. } else {
  18. sock._websocket._receiveData(new Uint8Array(data));
  19. }
  20. display.flip();
  21. }
  22. function push32(arr, num) {
  23. arr.push((num >> 24) & 0xFF,
  24. (num >> 16) & 0xFF,
  25. (num >> 8) & 0xFF,
  26. num & 0xFF);
  27. }
  28. describe('Hextile Decoder', function () {
  29. let decoder;
  30. let display;
  31. before(FakeWebSocket.replace);
  32. after(FakeWebSocket.restore);
  33. beforeEach(function () {
  34. decoder = new HextileDecoder();
  35. display = new Display(document.createElement('canvas'));
  36. display.resize(4, 4);
  37. });
  38. it('should handle a tile with fg, bg specified, normal subrects', function () {
  39. let data = [];
  40. data.push(0x02 | 0x04 | 0x08); // bg spec, fg spec, anysubrects
  41. push32(data, 0x00ff0000); // becomes 00ff0000 --> #00FF00 bg color
  42. data.push(0x00); // becomes 0000ff00 --> #0000FF fg color
  43. data.push(0x00);
  44. data.push(0xff);
  45. data.push(0x00);
  46. data.push(2); // 2 subrects
  47. data.push(0); // x: 0, y: 0
  48. data.push(1 | (1 << 4)); // width: 2, height: 2
  49. data.push(2 | (2 << 4)); // x: 2, y: 2
  50. data.push(1 | (1 << 4)); // width: 2, height: 2
  51. testDecodeRect(decoder, 0, 0, 4, 4, data, display, 24);
  52. let targetData = new Uint8Array([
  53. 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255,
  54. 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255,
  55. 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255,
  56. 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255
  57. ]);
  58. expect(display).to.have.displayed(targetData);
  59. });
  60. it('should handle a raw tile', function () {
  61. let targetData = new Uint8Array([
  62. 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255,
  63. 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255,
  64. 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255,
  65. 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255
  66. ]);
  67. let data = [];
  68. data.push(0x01); // raw
  69. for (let i = 0; i < targetData.length; i += 4) {
  70. data.push(targetData[i]);
  71. data.push(targetData[i + 1]);
  72. data.push(targetData[i + 2]);
  73. // Last byte zero to test correct alpha handling
  74. data.push(0);
  75. }
  76. testDecodeRect(decoder, 0, 0, 4, 4, data, display, 24);
  77. expect(display).to.have.displayed(targetData);
  78. });
  79. it('should handle a tile with only bg specified (solid bg)', function () {
  80. let data = [];
  81. data.push(0x02);
  82. push32(data, 0x00ff0000); // becomes 00ff0000 --> #00FF00 bg color
  83. testDecodeRect(decoder, 0, 0, 4, 4, data, display, 24);
  84. let expected = [];
  85. for (let i = 0; i < 16; i++) {
  86. push32(expected, 0x00ff00ff);
  87. }
  88. expect(display).to.have.displayed(new Uint8Array(expected));
  89. });
  90. it('should handle a tile with only bg specified and an empty frame afterwards', function () {
  91. // set the width so we can have two tiles
  92. display.resize(8, 4);
  93. let data = [];
  94. // send a bg frame
  95. data.push(0x02);
  96. push32(data, 0x00ff0000); // becomes 00ff0000 --> #00FF00 bg color
  97. // send an empty frame
  98. data.push(0x00);
  99. testDecodeRect(decoder, 0, 0, 32, 4, data, display, 24);
  100. let expected = [];
  101. for (let i = 0; i < 16; i++) {
  102. push32(expected, 0x00ff00ff); // rect 1: solid
  103. }
  104. for (let i = 0; i < 16; i++) {
  105. push32(expected, 0x00ff00ff); // rect 2: same bkground color
  106. }
  107. expect(display).to.have.displayed(new Uint8Array(expected));
  108. });
  109. it('should handle a tile with bg and coloured subrects', function () {
  110. let data = [];
  111. data.push(0x02 | 0x08 | 0x10); // bg spec, anysubrects, colouredsubrects
  112. push32(data, 0x00ff0000); // becomes 00ff0000 --> #00FF00 bg color
  113. data.push(2); // 2 subrects
  114. data.push(0x00); // becomes 0000ff00 --> #0000FF fg color
  115. data.push(0x00);
  116. data.push(0xff);
  117. data.push(0x00);
  118. data.push(0); // x: 0, y: 0
  119. data.push(1 | (1 << 4)); // width: 2, height: 2
  120. data.push(0x00); // becomes 0000ff00 --> #0000FF fg color
  121. data.push(0x00);
  122. data.push(0xff);
  123. data.push(0x00);
  124. data.push(2 | (2 << 4)); // x: 2, y: 2
  125. data.push(1 | (1 << 4)); // width: 2, height: 2
  126. testDecodeRect(decoder, 0, 0, 4, 4, data, display, 24);
  127. let targetData = new Uint8Array([
  128. 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255,
  129. 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255,
  130. 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255,
  131. 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255
  132. ]);
  133. expect(display).to.have.displayed(targetData);
  134. });
  135. it('should carry over fg and bg colors from the previous tile if not specified', function () {
  136. display.resize(4, 17);
  137. let data = [];
  138. data.push(0x02 | 0x04 | 0x08); // bg spec, fg spec, anysubrects
  139. push32(data, 0xff00ff); // becomes 00ff00ff --> #00FF00 bg color
  140. data.push(0x00); // becomes 0000ffff --> #0000FF fg color
  141. data.push(0x00);
  142. data.push(0xff);
  143. data.push(0xff);
  144. data.push(8); // 8 subrects
  145. for (let i = 0; i < 4; i++) {
  146. data.push((0 << 4) | (i * 4)); // x: 0, y: i*4
  147. data.push(1 | (1 << 4)); // width: 2, height: 2
  148. data.push((2 << 4) | (i * 4 + 2)); // x: 2, y: i * 4 + 2
  149. data.push(1 | (1 << 4)); // width: 2, height: 2
  150. }
  151. data.push(0x08); // anysubrects
  152. data.push(1); // 1 subrect
  153. data.push(0); // x: 0, y: 0
  154. data.push(1 | (1 << 4)); // width: 2, height: 2
  155. testDecodeRect(decoder, 0, 0, 4, 17, data, display, 24);
  156. let targetData = [
  157. 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255,
  158. 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255,
  159. 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255,
  160. 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255
  161. ];
  162. let expected = [];
  163. for (let i = 0; i < 4; i++) {
  164. expected = expected.concat(targetData);
  165. }
  166. expected = expected.concat(targetData.slice(0, 16));
  167. expect(display).to.have.displayed(new Uint8Array(expected));
  168. });
  169. it('should fail on an invalid subencoding', function () {
  170. let data = [45]; // an invalid subencoding
  171. expect(() => testDecodeRect(decoder, 0, 0, 4, 4, data, display, 24)).to.throw();
  172. });
  173. it('should handle empty rects', function () {
  174. display.fillRect(0, 0, 4, 4, [ 0x00, 0x00, 0xff ]);
  175. display.fillRect(2, 0, 2, 2, [ 0x00, 0xff, 0x00 ]);
  176. display.fillRect(0, 2, 2, 2, [ 0x00, 0xff, 0x00 ]);
  177. testDecodeRect(decoder, 1, 2, 0, 0, [], display, 24);
  178. let targetData = new Uint8Array([
  179. 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255,
  180. 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255,
  181. 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255,
  182. 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255
  183. ]);
  184. expect(display).to.have.displayed(targetData);
  185. });
  186. });