]> git.proxmox.com Git - mirror_novnc.git/blob - tests/test.display.js
Fixed assertion collision issues
[mirror_novnc.git] / tests / test.display.js
1 // requires local modules: util, base64, display
2 // requires test modules: assertions
3 /* jshint expr: true */
4 var expect = chai.expect;
5
6 describe('Display/Canvas Helper', function () {
7 var checked_data = [
8 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255,
9 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255,
10 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255,
11 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255
12 ];
13 checked_data = new Uint8Array(checked_data);
14
15 var basic_data = [0xff, 0x00, 0x00, 255, 0x00, 0xff, 0x00, 255, 0x00, 0x00, 0xff, 255, 0xff, 0xff, 0xff, 255];
16 basic_data = new Uint8Array(basic_data);
17
18 function make_image_canvas (input_data) {
19 var canvas = document.createElement('canvas');
20 canvas.width = 4;
21 canvas.height = 4;
22 var ctx = canvas.getContext('2d');
23 var data = ctx.createImageData(4, 4);
24 for (var i = 0; i < checked_data.length; i++) { data.data[i] = input_data[i]; }
25 ctx.putImageData(data, 0, 0);
26 return canvas;
27 }
28
29 describe('viewport handling', function () {
30 var display;
31 beforeEach(function () {
32 display = new Display({ target: document.createElement('canvas'), prefer_js: false, viewport: true });
33 display.resize(5, 5);
34 display.viewportChange(1, 1, 3, 3);
35 display.getCleanDirtyReset();
36 });
37
38 it('should take viewport location into consideration when drawing images', function () {
39 display.resize(4, 4);
40 display.viewportChange(0, 0, 2, 2);
41 display.drawImage(make_image_canvas(basic_data), 1, 1);
42
43 var expected = new Uint8Array(16);
44 var i;
45 for (i = 0; i < 8; i++) { expected[i] = basic_data[i]; }
46 for (i = 8; i < 16; i++) { expected[i] = 0; }
47 expect(display).to.have.displayed(expected);
48 });
49
50 it('should redraw the left side when shifted left', function () {
51 display.viewportChange(-1, 0, 3, 3);
52 var cdr = display.getCleanDirtyReset();
53 expect(cdr.cleanBox).to.deep.equal({ x: 1, y: 1, w: 2, h: 3 });
54 expect(cdr.dirtyBoxes).to.have.length(1);
55 expect(cdr.dirtyBoxes[0]).to.deep.equal({ x: 0, y: 1, w: 2, h: 3 });
56 });
57
58 it('should redraw the right side when shifted right', function () {
59 display.viewportChange(1, 0, 3, 3);
60 var cdr = display.getCleanDirtyReset();
61 expect(cdr.cleanBox).to.deep.equal({ x: 2, y: 1, w: 2, h: 3 });
62 expect(cdr.dirtyBoxes).to.have.length(1);
63 expect(cdr.dirtyBoxes[0]).to.deep.equal({ x: 4, y: 1, w: 1, h: 3 });
64 });
65
66 it('should redraw the top part when shifted up', function () {
67 display.viewportChange(0, -1, 3, 3);
68 var cdr = display.getCleanDirtyReset();
69 expect(cdr.cleanBox).to.deep.equal({ x: 1, y: 1, w: 3, h: 2 });
70 expect(cdr.dirtyBoxes).to.have.length(1);
71 expect(cdr.dirtyBoxes[0]).to.deep.equal({ x: 1, y: 0, w: 3, h: 1 });
72 });
73
74 it('should redraw the bottom part when shifted down', function () {
75 display.viewportChange(0, 1, 3, 3);
76 var cdr = display.getCleanDirtyReset();
77 expect(cdr.cleanBox).to.deep.equal({ x: 1, y: 2, w: 3, h: 2 });
78 expect(cdr.dirtyBoxes).to.have.length(1);
79 expect(cdr.dirtyBoxes[0]).to.deep.equal({ x: 1, y: 4, w: 3, h: 1 });
80 });
81
82 it('should reset the entire viewport to being clean after calculating the clean/dirty boxes', function () {
83 display.viewportChange(0, 1, 3, 3);
84 var cdr1 = display.getCleanDirtyReset();
85 var cdr2 = display.getCleanDirtyReset();
86 expect(cdr1).to.not.deep.equal(cdr2);
87 expect(cdr2.cleanBox).to.deep.equal({ x: 1, y: 2, w: 3, h: 3 });
88 expect(cdr2.dirtyBoxes).to.be.empty;
89 });
90
91 it('should simply mark the whole display area as dirty if not using viewports', function () {
92 display = new Display({ target: document.createElement('canvas'), prefer_js: false, viewport: false });
93 display.resize(5, 5);
94 var cdr = display.getCleanDirtyReset();
95 expect(cdr.cleanBox).to.deep.equal({ x: 0, y: 0, w: 0, h: 0 });
96 expect(cdr.dirtyBoxes).to.have.length(1);
97 expect(cdr.dirtyBoxes[0]).to.deep.equal({ x: 0, y: 0, w: 5, h: 5 });
98 });
99 });
100
101 describe('resizing', function () {
102 var display;
103 beforeEach(function () {
104 display = new Display({ target: document.createElement('canvas'), prefer_js: false, viewport: true });
105 display.resize(4, 3);
106 });
107
108 it('should change the size of the logical canvas', function () {
109 display.resize(5, 7);
110 expect(display._fb_width).to.equal(5);
111 expect(display._fb_height).to.equal(7);
112 });
113
114 it('should update the viewport dimensions', function () {
115 sinon.spy(display, 'viewportChange');
116 display.resize(2, 2);
117 expect(display.viewportChange).to.have.been.calledOnce;
118 });
119 });
120
121 describe('drawing', function () {
122
123 // TODO(directxman12): improve the tests for each of the drawing functions to cover more than just the
124 // basic cases
125 function drawing_tests (pref_js) {
126 var display;
127 beforeEach(function () {
128 display = new Display({ target: document.createElement('canvas'), prefer_js: pref_js });
129 display.resize(4, 4);
130 });
131
132 it('should clear the screen on #clear without a logo set', function () {
133 display.fillRect(0, 0, 4, 4, [0x00, 0x00, 0xff]);
134 display._logo = null;
135 display.clear();
136 display.resize(4, 4);
137 var empty = [];
138 for (var i = 0; i < 4 * display._fb_width * display._fb_height; i++) { empty[i] = 0; }
139 expect(display).to.have.displayed(new Uint8Array(empty));
140 });
141
142 it('should draw the logo on #clear with a logo set', function (done) {
143 display._logo = { width: 4, height: 4, data: make_image_canvas(checked_data).toDataURL() };
144 display._drawCtx._act_drawImg = display._drawCtx.drawImage;
145 display._drawCtx.drawImage = function (img, x, y) {
146 this._act_drawImg(img, x, y);
147 expect(display).to.have.displayed(checked_data);
148 done();
149 };
150 display.clear();
151 expect(display._fb_width).to.equal(4);
152 expect(display._fb_height).to.equal(4);
153 });
154
155 it('should support filling a rectangle with particular color via #fillRect', function () {
156 display.fillRect(0, 0, 4, 4, [0, 0xff, 0]);
157 display.fillRect(0, 0, 2, 2, [0xff, 0, 0]);
158 display.fillRect(2, 2, 2, 2, [0xff, 0, 0]);
159 expect(display).to.have.displayed(checked_data);
160 });
161
162 it('should support copying an portion of the canvas via #copyImage', function () {
163 display.fillRect(0, 0, 4, 4, [0, 0xff, 0]);
164 display.fillRect(0, 0, 2, 2, [0xff, 0, 0x00]);
165 display.copyImage(0, 0, 2, 2, 2, 2);
166 expect(display).to.have.displayed(checked_data);
167 });
168
169 it('should support drawing tile data with a background color and sub tiles', function () {
170 display.startTile(0, 0, 4, 4, [0, 0xff, 0]);
171 display.subTile(0, 0, 2, 2, [0xff, 0, 0]);
172 display.subTile(2, 2, 2, 2, [0xff, 0, 0]);
173 display.finishTile();
174 expect(display).to.have.displayed(checked_data);
175 });
176
177 it('should support drawing BGRX blit images with true color via #blitImage', function () {
178 var data = [];
179 for (var i = 0; i < 16; i++) {
180 data[i * 4] = checked_data[i * 4 + 2];
181 data[i * 4 + 1] = checked_data[i * 4 + 1];
182 data[i * 4 + 2] = checked_data[i * 4];
183 data[i * 4 + 3] = checked_data[i * 4 + 3];
184 }
185 display.blitImage(0, 0, 4, 4, data, 0);
186 expect(display).to.have.displayed(checked_data);
187 });
188
189 it('should support drawing RGB blit images with true color via #blitRgbImage', function () {
190 var data = [];
191 for (var i = 0; i < 16; i++) {
192 data[i * 3] = checked_data[i * 4];
193 data[i * 3 + 1] = checked_data[i * 4 + 1];
194 data[i * 3 + 2] = checked_data[i * 4 + 2];
195 }
196 display.blitRgbImage(0, 0, 4, 4, data, 0);
197 expect(display).to.have.displayed(checked_data);
198 });
199
200 it('should support drawing blit images from a data URL via #blitStringImage', function (done) {
201 var img_url = make_image_canvas(checked_data).toDataURL();
202 display._drawCtx._act_drawImg = display._drawCtx.drawImage;
203 display._drawCtx.drawImage = function (img, x, y) {
204 this._act_drawImg(img, x, y);
205 expect(display).to.have.displayed(checked_data);
206 done();
207 };
208 display.blitStringImage(img_url, 0, 0);
209 });
210
211 it('should support drawing solid colors with color maps', function () {
212 display._true_color = false;
213 display.set_colourMap({ 0: [0xff, 0, 0], 1: [0, 0xff, 0] });
214 display.fillRect(0, 0, 4, 4, [1]);
215 display.fillRect(0, 0, 2, 2, [0]);
216 display.fillRect(2, 2, 2, 2, [0]);
217 expect(display).to.have.displayed(checked_data);
218 });
219
220 it('should support drawing blit images with color maps', function () {
221 display._true_color = false;
222 display.set_colourMap({ 1: [0xff, 0, 0], 0: [0, 0xff, 0] });
223 var data = [1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1].map(function (elem) { return [elem]; });
224 display.blitImage(0, 0, 4, 4, data, 0);
225 expect(display).to.have.displayed(checked_data);
226 });
227
228 it('should support drawing an image object via #drawImage', function () {
229 var img = make_image_canvas(checked_data);
230 display.drawImage(img, 0, 0);
231 expect(display).to.have.displayed(checked_data);
232 });
233 }
234
235 describe('(prefering native methods)', function () { drawing_tests.call(this, false); });
236 describe('(prefering JavaScript)', function () { drawing_tests.call(this, true); });
237 });
238
239 describe('the render queue processor', function () {
240 var display;
241 beforeEach(function () {
242 display = new Display({ target: document.createElement('canvas'), prefer_js: false });
243 display.resize(4, 4);
244 sinon.spy(display, '_scan_renderQ');
245 this.old_requestAnimFrame = window.requestAnimFrame;
246 window.requestAnimFrame = function (cb) {
247 this.next_frame_cb = cb;
248 }.bind(this);
249 this.next_frame = function () { this.next_frame_cb(); };
250 });
251
252 afterEach(function () {
253 window.requestAnimFrame = this.old_requestAnimFrame;
254 });
255
256 it('should try to process an item when it is pushed on, if nothing else is on the queue', function () {
257 display.renderQ_push({ type: 'noop' }); // does nothing
258 expect(display._scan_renderQ).to.have.been.calledOnce;
259 });
260
261 it('should not try to process an item when it is pushed on if we are waiting for other items', function () {
262 display._renderQ.length = 2;
263 display.renderQ_push({ type: 'noop' });
264 expect(display._scan_renderQ).to.not.have.been.called;
265 });
266
267 it('should wait until an image is loaded to attempt to draw it and the rest of the queue', function () {
268 var img = { complete: false };
269 display._renderQ = [{ type: 'img', x: 3, y: 4, img: img },
270 { type: 'fill', x: 1, y: 2, width: 3, height: 4, color: 5 }];
271 display.drawImage = sinon.spy();
272 display.fillRect = sinon.spy();
273
274 display._scan_renderQ();
275 expect(display.drawImage).to.not.have.been.called;
276 expect(display.fillRect).to.not.have.been.called;
277
278 display._renderQ[0].img.complete = true;
279 this.next_frame();
280 expect(display.drawImage).to.have.been.calledOnce;
281 expect(display.fillRect).to.have.been.calledOnce;
282 });
283
284 it('should draw a blit image on type "blit"', function () {
285 display.blitImage = sinon.spy();
286 display.renderQ_push({ type: 'blit', x: 3, y: 4, width: 5, height: 6, data: [7, 8, 9] });
287 expect(display.blitImage).to.have.been.calledOnce;
288 expect(display.blitImage).to.have.been.calledWith(3, 4, 5, 6, [7, 8, 9], 0);
289 });
290
291 it('should draw a blit RGB image on type "blitRgb"', function () {
292 display.blitRgbImage = sinon.spy();
293 display.renderQ_push({ type: 'blitRgb', x: 3, y: 4, width: 5, height: 6, data: [7, 8, 9] });
294 expect(display.blitRgbImage).to.have.been.calledOnce;
295 expect(display.blitRgbImage).to.have.been.calledWith(3, 4, 5, 6, [7, 8, 9], 0);
296 });
297
298 it('should copy a region on type "copy"', function () {
299 display.copyImage = sinon.spy();
300 display.renderQ_push({ type: 'copy', x: 3, y: 4, width: 5, height: 6, old_x: 7, old_y: 8 });
301 expect(display.copyImage).to.have.been.calledOnce;
302 expect(display.copyImage).to.have.been.calledWith(7, 8, 3, 4, 5, 6);
303 });
304
305 it('should fill a rect with a given color on type "fill"', function () {
306 display.fillRect = sinon.spy();
307 display.renderQ_push({ type: 'fill', x: 3, y: 4, width: 5, height: 6, color: [7, 8, 9]});
308 expect(display.fillRect).to.have.been.calledOnce;
309 expect(display.fillRect).to.have.been.calledWith(3, 4, 5, 6, [7, 8, 9]);
310 });
311
312 it('should draw an image from an image object on type "img" (if complete)', function () {
313 display.drawImage = sinon.spy();
314 display.renderQ_push({ type: 'img', x: 3, y: 4, img: { complete: true } });
315 expect(display.drawImage).to.have.been.calledOnce;
316 expect(display.drawImage).to.have.been.calledWith({ complete: true }, 3, 4);
317 });
318 });
319 });