1/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV.
2
3Permission is hereby granted, free of charge, to any person obtaining a copy
4of this software and associated documentation files (the "Software"), to deal
5in the Software without restriction, including without limitation the rights
6to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7copies of the Software, and to permit persons to whom the Software is
8furnished to do so, subject to the following conditions:
9
10The above copyright notice and this permission notice shall be included in
11all copies or substantial portions of the Software.
12
13THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19THE SOFTWARE. */
20
21describe("vec3", function() {
22    var mat3 = require("../../src/gl-matrix/mat3.js");
23    var mat4 = require("../../src/gl-matrix/mat4.js");
24    var vec3 = require("../../src/gl-matrix/vec3.js");
25
26    var out, vecA, vecB, result;
27
28    beforeEach(function() { vecA = [1, 2, 3]; vecB = [4, 5, 6]; out = [0, 0, 0]; });
29
30    describe('rotateX', function(){
31     	describe('rotation around world origin [0, 0, 0]', function(){
32    			  beforeEach(function(){ vecA = [0, 1, 0]; vecB = [0, 0, 0]; result = vec3.rotateX(out, vecA, vecB, Math.PI); });
33    			  it("should return the rotated vector", function(){ expect(result).toBeEqualish([0, -1, 0]); });
34    		});
35    		describe('rotation around an arbitrary origin', function(){
36    			  beforeEach(function(){ vecA = [2, 7, 0]; vecB = [2, 5, 0]; result = vec3.rotateX(out, vecA, vecB, Math.PI); });
37    			  it("should return the rotated vector", function(){ expect(result).toBeEqualish([2, 3, 0]); });
38    		});
39    	});
40
41    	describe('rotateY', function(){
42    		describe('rotation around world origin [0, 0, 0]', function(){
43    			  beforeEach(function(){ vecA = [1, 0, 0]; vecB = [0, 0, 0]; result = vec3.rotateY(out, vecA, vecB, Math.PI); });
44    			  it("should return the rotated vector", function(){ expect(result).toBeEqualish([-1, 0, 0]); });
45    		});
46    		describe('rotation around an arbitrary origin', function(){
47    			  beforeEach(function(){ vecA = [-2, 3, 10]; vecB = [-4, 3, 10]; result = vec3.rotateY(out, vecA, vecB, Math.PI); });
48    			  it("should return the rotated vector", function(){ expect(result).toBeEqualish([-6, 3, 10]); });
49    		});
50    	});
51
52    	describe('rotateZ', function(){
53    		describe('rotation around world origin [0, 0, 0]', function(){
54    			  beforeEach(function(){ vecA = [0, 1, 0]; vecB = [0, 0, 0]; result = vec3.rotateZ(out, vecA, vecB, Math.PI); });
55    			  it("should return the rotated vector", function(){ expect(result).toBeEqualish([0, -1, 0]); });
56    		});
57    		describe('rotation around an arbitrary origin', function(){
58    			  beforeEach(function(){ vecA = [0, 6, -5]; vecB = [0, 0, -5]; result = vec3.rotateZ(out, vecA, vecB, Math.PI); });
59    			  it("should return the rotated vector", function(){ expect(result).toBeEqualish([0, -6, -5]); });
60    		});
61    	});
62
63    describe('transformMat4', function() {
64        var matr;
65        describe("with an identity", function() {
66            beforeEach(function() { matr = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 ] });
67
68            beforeEach(function() { result = vec3.transformMat4(out, vecA, matr); });
69
70            it("should produce the input", function() {
71                expect(out).toBeEqualish([1, 2, 3]);
72            });
73
74            it("should return out", function() { expect(result).toBe(out); });
75        });
76
77        describe("with a lookAt", function() {
78            beforeEach(function() { matr = mat4.lookAt(mat4.create(), [5, 6, 7], [2, 6, 7], [0, 1, 0]); });
79
80            beforeEach(function() { result = vec3.transformMat4(out, vecA, matr); });
81
82            it("should rotate and translate the input", function() {
83                expect(out).toBeEqualish([ 4, -4, -4 ]);
84            });
85
86            it("should return out", function() { expect(result).toBe(out); });
87        });
88
89        describe("with a perspective matrix (#92)", function() {
90            it("should transform a point from perspective(pi/2, 4/3, 1, 100)", function() {
91                matr = [0.750, 0, 0, 0,
92                        0, 1, 0, 0,
93                        0, 0, -1.02, -1,
94                        0, 0, -2.02, 0];
95                result = vec3.transformMat4([], [10, 20, 30], matr);
96                expect(result).toBeEqualish([-0.25, -0.666666, 1.087333]);
97            });
98        });
99
100    });
101
102    describe('transformMat3', function() {
103        var matr;
104        describe("with an identity", function() {
105            beforeEach(function() { matr = [1, 0, 0, 0, 1, 0, 0, 0, 1 ] });
106
107            beforeEach(function() { result = vec3.transformMat3(out, vecA, matr); });
108
109            it("should produce the input", function() {
110                expect(out).toBeEqualish([1, 2, 3]);
111            });
112
113            it("should return out", function() { expect(result).toBe(out); });
114        });
115
116        describe("with 90deg about X", function() {
117            beforeEach(function() {
118                result = vec3.transformMat3(out, [0,1,0], [1,0,0,0,0,1,0,-1,0]);
119            });
120
121            it("should produce correct output", function() {
122                expect(out).toBeEqualish([0,0,1]);
123            });
124        });
125
126        describe("with 90deg about Y", function() {
127            beforeEach(function() {
128                result = vec3.transformMat3(out, [1,0,0], [0,0,-1,0,1,0,1,0,0]);
129            });
130
131            it("should produce correct output", function() {
132                expect(out).toBeEqualish([0,0,-1]);
133            });
134        });
135
136        describe("with 90deg about Z", function() {
137            beforeEach(function() {
138                result = vec3.transformMat3(out, [1,0,0], [0,1,0,-1,0,0,0,0,1]);
139            });
140
141            it("should produce correct output", function() {
142                expect(out).toBeEqualish([0,1,0]);
143            });
144        });
145
146        describe("with a lookAt normal matrix", function() {
147            beforeEach(function() {
148                matr = mat4.lookAt(mat4.create(), [5, 6, 7], [2, 6, 7], [0, 1, 0]);
149                var n = mat3.create();
150                matr = mat3.transpose(n, mat3.invert(n, mat3.fromMat4(n, matr)));
151            });
152
153            beforeEach(function() { result = vec3.transformMat3(out, [1,0,0], matr); });
154
155            it("should rotate the input", function() {
156                expect(out).toBeEqualish([ 0,0,1 ]);
157            });
158
159            it("should return out", function() { expect(result).toBe(out); });
160        });
161    });
162
163    describe("create", function() {
164        beforeEach(function() { result = vec3.create(); });
165        it("should return a 3 element array initialized to 0s", function() { expect(result).toBeEqualish([0, 0, 0]); });
166    });
167
168    describe("clone", function() {
169        beforeEach(function() { result = vec3.clone(vecA); });
170        it("should return a 3 element array initialized to the values in vecA", function() { expect(result).toBeEqualish(vecA); });
171    });
172
173    describe("fromValues", function() {
174        beforeEach(function() { result = vec3.fromValues(1, 2, 3); });
175        it("should return a 3 element array initialized to the values passed", function() { expect(result).toBeEqualish([1, 2, 3]); });
176    });
177
178    describe("copy", function() {
179        beforeEach(function() { result = vec3.copy(out, vecA); });
180        it("should place values into out", function() { expect(out).toBeEqualish([1, 2, 3]); });
181        it("should return out", function() { expect(result).toBe(out); });
182    });
183
184    describe("set", function() {
185        beforeEach(function() { result = vec3.set(out, 1, 2, 3); });
186        it("should place values into out", function() { expect(out).toBeEqualish([1, 2, 3]); });
187        it("should return out", function() { expect(result).toBe(out); });
188    });
189
190    describe("add", function() {
191        describe("with a separate output vector", function() {
192            beforeEach(function() { result = vec3.add(out, vecA, vecB); });
193
194            it("should place values into out", function() { expect(out).toBeEqualish([5, 7, 9]); });
195            it("should return out", function() { expect(result).toBe(out); });
196            it("should not modify vecA", function() { expect(vecA).toBeEqualish([1, 2, 3]); });
197            it("should not modify vecB", function() { expect(vecB).toBeEqualish([4, 5, 6]); });
198        });
199
200        describe("when vecA is the output vector", function() {
201            beforeEach(function() { result = vec3.add(vecA, vecA, vecB); });
202
203            it("should place values into vecA", function() { expect(vecA).toBeEqualish([5, 7, 9]); });
204            it("should return vecA", function() { expect(result).toBe(vecA); });
205            it("should not modify vecB", function() { expect(vecB).toBeEqualish([4, 5, 6]); });
206        });
207
208        describe("when vecB is the output vector", function() {
209            beforeEach(function() { result = vec3.add(vecB, vecA, vecB); });
210
211            it("should place values into vecB", function() { expect(vecB).toBeEqualish([5, 7, 9]); });
212            it("should return vecB", function() { expect(result).toBe(vecB); });
213            it("should not modify vecA", function() { expect(vecA).toBeEqualish([1, 2, 3]); });
214        });
215    });
216
217    describe("subtract", function() {
218        it("should have an alias called 'sub'", function() { expect(vec3.sub).toEqual(vec3.subtract); });
219
220        describe("with a separate output vector", function() {
221            beforeEach(function() { result = vec3.subtract(out, vecA, vecB); });
222
223            it("should place values into out", function() { expect(out).toBeEqualish([-3, -3, -3]); });
224            it("should return out", function() { expect(result).toBe(out); });
225            it("should not modify vecA", function() { expect(vecA).toBeEqualish([1, 2, 3]); });
226            it("should not modify vecB", function() { expect(vecB).toBeEqualish([4, 5, 6]); });
227        });
228
229        describe("when vecA is the output vector", function() {
230            beforeEach(function() { result = vec3.subtract(vecA, vecA, vecB); });
231
232            it("should place values into vecA", function() { expect(vecA).toBeEqualish([-3, -3, -3]); });
233            it("should return vecA", function() { expect(result).toBe(vecA); });
234            it("should not modify vecB", function() { expect(vecB).toBeEqualish([4, 5, 6]); });
235        });
236
237        describe("when vecB is the output vector", function() {
238            beforeEach(function() { result = vec3.subtract(vecB, vecA, vecB); });
239
240            it("should place values into vecB", function() { expect(vecB).toBeEqualish([-3, -3, -3]); });
241            it("should return vecB", function() { expect(result).toBe(vecB); });
242            it("should not modify vecA", function() { expect(vecA).toBeEqualish([1, 2, 3]); });
243        });
244    });
245
246    describe("multiply", function() {
247        it("should have an alias called 'mul'", function() { expect(vec3.mul).toEqual(vec3.multiply); });
248
249        describe("with a separate output vector", function() {
250            beforeEach(function() { result = vec3.multiply(out, vecA, vecB); });
251
252            it("should place values into out", function() { expect(out).toBeEqualish([4, 10, 18]); });
253            it("should return out", function() { expect(result).toBe(out); });
254            it("should not modify vecA", function() { expect(vecA).toBeEqualish([1, 2, 3]); });
255            it("should not modify vecB", function() { expect(vecB).toBeEqualish([4, 5, 6]); });
256        });
257
258        describe("when vecA is the output vector", function() {
259            beforeEach(function() { result = vec3.multiply(vecA, vecA, vecB); });
260
261            it("should place values into vecA", function() { expect(vecA).toBeEqualish([4, 10, 18]); });
262            it("should return vecA", function() { expect(result).toBe(vecA); });
263            it("should not modify vecB", function() { expect(vecB).toBeEqualish([4, 5, 6]); });
264        });
265
266        describe("when vecB is the output vector", function() {
267            beforeEach(function() { result = vec3.multiply(vecB, vecA, vecB); });
268
269            it("should place values into vecB", function() { expect(vecB).toBeEqualish([4, 10, 18]); });
270            it("should return vecB", function() { expect(result).toBe(vecB); });
271            it("should not modify vecA", function() { expect(vecA).toBeEqualish([1, 2, 3]); });
272        });
273    });
274
275    describe("divide", function() {
276        it("should have an alias called 'div'", function() { expect(vec3.div).toEqual(vec3.divide); });
277
278        describe("with a separate output vector", function() {
279            beforeEach(function() { result = vec3.divide(out, vecA, vecB); });
280
281            it("should place values into out", function() { expect(out).toBeEqualish([0.25, 0.4, 0.5]); });
282            it("should return out", function() { expect(result).toBe(out); });
283            it("should not modify vecA", function() { expect(vecA).toBeEqualish([1, 2, 3]); });
284            it("should not modify vecB", function() { expect(vecB).toBeEqualish([4, 5, 6]); });
285        });
286
287        describe("when vecA is the output vector", function() {
288            beforeEach(function() { result = vec3.divide(vecA, vecA, vecB); });
289
290            it("should place values into vecA", function() { expect(vecA).toBeEqualish([0.25, 0.4, 0.5]); });
291            it("should return vecA", function() { expect(result).toBe(vecA); });
292            it("should not modify vecB", function() { expect(vecB).toBeEqualish([4, 5, 6]); });
293        });
294
295        describe("when vecB is the output vector", function() {
296            beforeEach(function() { result = vec3.divide(vecB, vecA, vecB); });
297
298            it("should place values into vecB", function() { expect(vecB).toBeEqualish([0.25, 0.4, 0.5]); });
299            it("should return vecB", function() { expect(result).toBe(vecB); });
300            it("should not modify vecA", function() { expect(vecA).toBeEqualish([1, 2, 3]); });
301        });
302    });
303
304    describe("min", function() {
305        beforeEach(function() { vecA = [1, 3, 1]; vecB = [3, 1, 3]; });
306
307        describe("with a separate output vector", function() {
308            beforeEach(function() { result = vec3.min(out, vecA, vecB); });
309
310            it("should place values into out", function() { expect(out).toBeEqualish([1, 1, 1]); });
311            it("should return out", function() { expect(result).toBe(out); });
312            it("should not modify vecA", function() { expect(vecA).toBeEqualish([1, 3, 1]); });
313            it("should not modify vecB", function() { expect(vecB).toBeEqualish([3, 1, 3]); });
314        });
315
316        describe("when vecA is the output vector", function() {
317            beforeEach(function() { result = vec3.min(vecA, vecA, vecB); });
318
319            it("should place values into vecA", function() { expect(vecA).toBeEqualish([1, 1, 1]); });
320            it("should return vecA", function() { expect(result).toBe(vecA); });
321            it("should not modify vecB", function() { expect(vecB).toBeEqualish([3, 1, 3]); });
322        });
323
324        describe("when vecB is the output vector", function() {
325            beforeEach(function() { result = vec3.min(vecB, vecA, vecB); });
326
327            it("should place values into vecB", function() { expect(vecB).toBeEqualish([1, 1, 1]); });
328            it("should return vecB", function() { expect(result).toBe(vecB); });
329            it("should not modify vecA", function() { expect(vecA).toBeEqualish([1, 3, 1]); });
330        });
331    });
332
333    describe("max", function() {
334        beforeEach(function() { vecA = [1, 3, 1]; vecB = [3, 1, 3]; });
335
336        describe("with a separate output vector", function() {
337            beforeEach(function() { result = vec3.max(out, vecA, vecB); });
338
339            it("should place values into out", function() { expect(out).toBeEqualish([3, 3, 3]); });
340            it("should return out", function() { expect(result).toBe(out); });
341            it("should not modify vecA", function() { expect(vecA).toBeEqualish([1, 3, 1]); });
342            it("should not modify vecB", function() { expect(vecB).toBeEqualish([3, 1, 3]); });
343        });
344
345        describe("when vecA is the output vector", function() {
346            beforeEach(function() { result = vec3.max(vecA, vecA, vecB); });
347
348            it("should place values into vecA", function() { expect(vecA).toBeEqualish([3, 3, 3]); });
349            it("should return vecA", function() { expect(result).toBe(vecA); });
350            it("should not modify vecB", function() { expect(vecB).toBeEqualish([3, 1, 3]); });
351        });
352
353        describe("when vecB is the output vector", function() {
354            beforeEach(function() { result = vec3.max(vecB, vecA, vecB); });
355
356            it("should place values into vecB", function() { expect(vecB).toBeEqualish([3, 3, 3]); });
357            it("should return vecB", function() { expect(result).toBe(vecB); });
358            it("should not modify vecA", function() { expect(vecA).toBeEqualish([1, 3, 1]); });
359        });
360    });
361
362    describe("scale", function() {
363        describe("with a separate output vector", function() {
364            beforeEach(function() { result = vec3.scale(out, vecA, 2); });
365
366            it("should place values into out", function() { expect(out).toBeEqualish([2, 4, 6]); });
367            it("should return out", function() { expect(result).toBe(out); });
368            it("should not modify vecA", function() { expect(vecA).toBeEqualish([1, 2, 3]); });
369        });
370
371        describe("when vecA is the output vector", function() {
372            beforeEach(function() { result = vec3.scale(vecA, vecA, 2); });
373
374            it("should place values into vecA", function() { expect(vecA).toBeEqualish([2, 4, 6]); });
375            it("should return vecA", function() { expect(result).toBe(vecA); });
376        });
377    });
378
379    describe("scaleAndAdd", function() {
380        describe("with a separate output vector", function() {
381            beforeEach(function() { result = vec3.scaleAndAdd(out, vecA, vecB, 0.5); });
382
383            it("should place values into out", function() { expect(out).toBeEqualish([3, 4.5, 6]); });
384            it("should return out", function() { expect(result).toBe(out); });
385            it("should not modify vecA", function() { expect(vecA).toBeEqualish([1, 2, 3]); });
386            it("should not modify vecB", function() { expect(vecB).toBeEqualish([4, 5, 6]); });
387        });
388
389        describe("when vecA is the output vector", function() {
390            beforeEach(function() { result = vec3.scaleAndAdd(vecA, vecA, vecB, 0.5); });
391
392            it("should place values into vecA", function() { expect(vecA).toBeEqualish([3, 4.5, 6]); });
393            it("should return vecA", function() { expect(result).toBe(vecA); });
394            it("should not modify vecB", function() { expect(vecB).toBeEqualish([4, 5, 6]); });
395        });
396
397        describe("when vecB is the output vector", function() {
398            beforeEach(function() { result = vec3.scaleAndAdd(vecB, vecA, vecB, 0.5); });
399
400            it("should place values into vecB", function() { expect(vecB).toBeEqualish([3, 4.5, 6]); });
401            it("should return vecB", function() { expect(result).toBe(vecB); });
402            it("should not modify vecA", function() { expect(vecA).toBeEqualish([1, 2, 3]); });
403        });
404    });
405
406    describe("distance", function() {
407        it("should have an alias called 'dist'", function() { expect(vec3.dist).toEqual(vec3.distance); });
408
409        beforeEach(function() { result = vec3.distance(vecA, vecB); });
410
411        it("should return the distance", function() { expect(result).toBeCloseTo(5.196152); });
412    });
413
414    describe("squaredDistance", function() {
415        it("should have an alias called 'sqrDist'", function() { expect(vec3.sqrDist).toEqual(vec3.squaredDistance); });
416
417        beforeEach(function() { result = vec3.squaredDistance(vecA, vecB); });
418
419        it("should return the squared distance", function() { expect(result).toEqual(27); });
420    });
421
422    describe("length", function() {
423        it("should have an alias called 'len'", function() { expect(vec3.len).toEqual(vec3.length); });
424
425        beforeEach(function() { result = vec3.length(vecA); });
426
427        it("should return the length", function() { expect(result).toBeCloseTo(3.741657); });
428    });
429
430    describe("squaredLength", function() {
431        it("should have an alias called 'sqrLen'", function() { expect(vec3.sqrLen).toEqual(vec3.squaredLength); });
432
433        beforeEach(function() { result = vec3.squaredLength(vecA); });
434
435        it("should return the squared length", function() { expect(result).toEqual(14); });
436    });
437
438    describe("negate", function() {
439        describe("with a separate output vector", function() {
440            beforeEach(function() { result = vec3.negate(out, vecA); });
441
442            it("should place values into out", function() { expect(out).toBeEqualish([-1, -2, -3]); });
443            it("should return out", function() { expect(result).toBe(out); });
444            it("should not modify vecA", function() { expect(vecA).toBeEqualish([1, 2, 3]); });
445        });
446
447        describe("when vecA is the output vector", function() {
448            beforeEach(function() { result = vec3.negate(vecA, vecA); });
449
450            it("should place values into vecA", function() { expect(vecA).toBeEqualish([-1, -2, -3]); });
451            it("should return vecA", function() { expect(result).toBe(vecA); });
452        });
453    });
454
455    describe("normalize", function() {
456        beforeEach(function() { vecA = [5, 0, 0]; });
457
458        describe("with a separate output vector", function() {
459            beforeEach(function() { result = vec3.normalize(out, vecA); });
460
461            it("should place values into out", function() { expect(out).toBeEqualish([1, 0, 0]); });
462            it("should return out", function() { expect(result).toBe(out); });
463            it("should not modify vecA", function() { expect(vecA).toBeEqualish([5, 0, 0]); });
464        });
465
466        describe("when vecA is the output vector", function() {
467            beforeEach(function() { result = vec3.normalize(vecA, vecA); });
468
469            it("should place values into vecA", function() { expect(vecA).toBeEqualish([1, 0, 0]); });
470            it("should return vecA", function() { expect(result).toBe(vecA); });
471        });
472    });
473
474    describe("dot", function() {
475        beforeEach(function() { result = vec3.dot(vecA, vecB); });
476
477        it("should return the dot product", function() { expect(result).toEqual(32); });
478        it("should not modify vecA", function() { expect(vecA).toBeEqualish([1, 2, 3]); });
479        it("should not modify vecB", function() { expect(vecB).toBeEqualish([4, 5, 6]); });
480    });
481
482    describe("cross", function() {
483        describe("with a separate output vector", function() {
484            beforeEach(function() { result = vec3.cross(out, vecA, vecB); });
485
486            it("should place values into out", function() { expect(out).toBeEqualish([-3, 6, -3]); });
487            it("should return out", function() { expect(result).toBe(out); });
488            it("should not modify vecA", function() { expect(vecA).toBeEqualish([1, 2, 3]); });
489            it("should not modify vecB", function() { expect(vecB).toBeEqualish([4, 5, 6]); });
490        });
491
492        describe("when vecA is the output vector", function() {
493            beforeEach(function() { result = vec3.cross(vecA, vecA, vecB); });
494
495            it("should place values into vecA", function() { expect(vecA).toBeEqualish([-3, 6, -3]); });
496            it("should return vecA", function() { expect(result).toBe(vecA); });
497            it("should not modify vecB", function() { expect(vecB).toBeEqualish([4, 5, 6]); });
498        });
499
500        describe("when vecB is the output vector", function() {
501            beforeEach(function() { result = vec3.cross(vecB, vecA, vecB); });
502
503            it("should place values into vecB", function() { expect(vecB).toBeEqualish([-3, 6, -3]); });
504            it("should return vecB", function() { expect(result).toBe(vecB); });
505            it("should not modify vecA", function() { expect(vecA).toBeEqualish([1, 2, 3]); });
506        });
507    });
508
509    describe("lerp", function() {
510        describe("with a separate output vector", function() {
511            beforeEach(function() { result = vec3.lerp(out, vecA, vecB, 0.5); });
512
513            it("should place values into out", function() { expect(out).toBeEqualish([2.5, 3.5, 4.5]); });
514            it("should return out", function() { expect(result).toBe(out); });
515            it("should not modify vecA", function() { expect(vecA).toBeEqualish([1, 2, 3]); });
516            it("should not modify vecB", function() { expect(vecB).toBeEqualish([4, 5, 6]); });
517        });
518
519        describe("when vecA is the output vector", function() {
520            beforeEach(function() { result = vec3.lerp(vecA, vecA, vecB, 0.5); });
521
522            it("should place values into vecA", function() { expect(vecA).toBeEqualish([2.5, 3.5, 4.5]); });
523            it("should return vecA", function() { expect(result).toBe(vecA); });
524            it("should not modify vecB", function() { expect(vecB).toBeEqualish([4, 5, 6]); });
525        });
526
527        describe("when vecB is the output vector", function() {
528            beforeEach(function() { result = vec3.lerp(vecB, vecA, vecB, 0.5); });
529
530            it("should place values into vecB", function() { expect(vecB).toBeEqualish([2.5, 3.5, 4.5]); });
531            it("should return vecB", function() { expect(result).toBe(vecB); });
532            it("should not modify vecA", function() { expect(vecA).toBeEqualish([1, 2, 3]); });
533        });
534    });
535
536    describe("random", function() {
537        describe("with no scale", function() {
538            beforeEach(function() { result = vec3.random(out); });
539
540            it("should result in a unit length vector", function() { expect(vec3.length(out)).toBeCloseTo(1.0); });
541            it("should return out", function() { expect(result).toBe(out); });
542        });
543
544        describe("with a scale", function() {
545            beforeEach(function() { result = vec3.random(out, 5.0); });
546
547            it("should result in a unit length vector", function() { expect(vec3.length(out)).toBeCloseTo(5.0); });
548            it("should return out", function() { expect(result).toBe(out); });
549        });
550    });
551
552    describe("forEach", function() {
553        var vecArray;
554
555        beforeEach(function() {
556            vecArray = [
557                1, 2, 3,
558                4, 5, 6,
559                0, 0, 0
560            ];
561        });
562
563        describe("when performing operations that take no extra arguments", function() {
564            beforeEach(function() { result = vec3.forEach(vecArray, 0, 0, 0, vec3.normalize); });
565
566            it("should update all values", function() {
567                expect(vecArray).toBeEqualish([
568                    0.267261, 0.534522, 0.801783,
569                    0.455842, 0.569802, 0.683763,
570                    0, 0, 0
571                ]);
572            });
573            it("should return vecArray", function() { expect(result).toBe(vecArray); });
574        });
575
576        describe("when performing operations that takes one extra arguments", function() {
577            beforeEach(function() { result = vec3.forEach(vecArray, 0, 0, 0, vec3.add, vecA); });
578
579            it("should update all values", function() {
580                expect(vecArray).toBeEqualish([
581                    2, 4, 6,
582                    5, 7, 9,
583                    1, 2, 3
584                ]);
585            });
586            it("should return vecArray", function() { expect(result).toBe(vecArray); });
587            it("should not modify vecA", function() { expect(vecA).toBeEqualish([1, 2, 3]); });
588        });
589
590        describe("when specifying an offset", function() {
591            beforeEach(function() { result = vec3.forEach(vecArray, 0, 3, 0, vec3.add, vecA); });
592
593            it("should update all values except the first vector", function() {
594                expect(vecArray).toBeEqualish([
595                    1, 2, 3,
596                    5, 7, 9,
597                    1, 2, 3
598                ]);
599            });
600            it("should return vecArray", function() { expect(result).toBe(vecArray); });
601            it("should not modify vecA", function() { expect(vecA).toBeEqualish([1, 2, 3]); });
602        });
603
604        describe("when specifying a count", function() {
605            beforeEach(function() { result = vec3.forEach(vecArray, 0, 0, 2, vec3.add, vecA); });
606
607            it("should update all values except the last vector", function() {
608                expect(vecArray).toBeEqualish([
609                    2, 4, 6,
610                    5, 7, 9,
611                    0, 0, 0
612                ]);
613            });
614            it("should return vecArray", function() { expect(result).toBe(vecArray); });
615            it("should not modify vecA", function() { expect(vecA).toBeEqualish([1, 2, 3]); });
616        });
617
618        describe("when specifying a stride", function() {
619            beforeEach(function() { result = vec3.forEach(vecArray, 6, 0, 0, vec3.add, vecA); });
620
621            it("should update all values except the second vector", function() {
622                expect(vecArray).toBeEqualish([
623                    2, 4, 6,
624                    4, 5, 6,
625                    1, 2, 3
626                ]);
627            });
628            it("should return vecArray", function() { expect(result).toBe(vecArray); });
629            it("should not modify vecA", function() { expect(vecA).toBeEqualish([1, 2, 3]); });
630        });
631
632        describe("when calling a function that does not modify the out variable", function() {
633            beforeEach(function() {
634                result = vec3.forEach(vecArray, 0, 0, 0, function(out, vec) {});
635            });
636
637            it("values should remain unchanged", function() {
638                expect(vecArray).toBeEqualish([
639                    1, 2, 3,
640                    4, 5, 6,
641                    0, 0, 0
642                ]);
643            });
644            it("should return vecArray", function() { expect(result).toBe(vecArray); });
645        });
646    });
647
648    describe("angle", function() {
649        beforeEach(function() { result = vec3.angle(vecA, vecB); });
650
651        it("should return the angle", function() { expect(result).toBeEqualish(0.225726); });
652        it("should not modify vecA", function() { expect(vecA).toBeEqualish([1, 2, 3]); });
653        it("should not modify vecB", function() { expect(vecB).toBeEqualish([4, 5, 6]); });
654    });
655
656    describe("str", function() {
657        beforeEach(function() { result = vec3.str(vecA); });
658
659        it("should return a string representation of the vector", function() { expect(result).toEqual("vec3(1, 2, 3)"); });
660    });
661});
662