| Index: test/tests/typedObjects.js |
| =================================================================== |
| --- a/test/tests/typedObjects.js |
| +++ b/test/tests/typedObjects.js |
| @@ -58,17 +58,16 @@ |
| mtd: function() { |
| return this.foo * 2; |
| } |
| }, {bufferSize: 8}); |
| ok(type, "Type created"); |
| equal(typeof type.typeId, "number"); |
| equal(typeof type.byteLength, "number"); |
| - equal(type.byteLength, 8); |
| // Create an object and check default properties |
| let objects = []; |
| objects.push(type()); |
| ok(objects[0], "Object created"); |
| equal(typeof objects[0].typeId, "number"); |
| equal(objects[0].typeId, type.typeId); |
| @@ -79,17 +78,17 @@ |
| equal(typeof objects[0].byteOffset, "number"); |
| equal(objects[0].byteOffset, 0); |
| // The first 8 objects should go into the same buffer |
| for (let i = 1; i < 8; i++) |
| { |
| objects.push(type()); |
| equal(objects[i].bufferIndex, 0); |
| - equal(objects[i].byteOffset, 8 * i); |
| + equal(objects[i].byteOffset, type.byteLength * i); |
| } |
| // Properties should persist and methods should be able to access them |
| for (let i = 0; i < objects.length; i++) |
| { |
| objects[i].foo = i; |
| objects[i].bar = 8.5 - objects[i].foo; |
| } |
| @@ -104,17 +103,17 @@ |
| // Next objects should go into a new buffer |
| let obj = type(); |
| equal(obj.bufferIndex, 1); |
| equal(obj.byteOffset, 0); |
| obj = type(); |
| equal(obj.bufferIndex, 1); |
| - equal(obj.byteOffset, 8); |
| + equal(obj.byteOffset, type.byteLength); |
| }); |
| test("Object constructors", function() |
| { |
| let {ObjectType, uint8, float32} = require("typedObjects"); |
| let type = new ObjectType({ |
| foo: uint8, |
| bar: float32 |
| @@ -294,9 +293,108 @@ |
| type3.extend({foo: uint8}); |
| }, "Property masks method"); |
| throws(function() |
| { |
| type3.extend({x: function() {}}); |
| }, "Method masks property"); |
| }); |
| + |
| + test("Garbage collection", function() |
| + { |
| + let {ObjectType, uint8, float32} = require("typedObjects"); |
| + |
| + let destroyed; |
| + |
| + let type1 = new ObjectType({ |
| + foo: uint8 |
| + }, { |
| + constructor: function(foo) |
| + { |
| + this.foo = foo; |
| + }, |
| + destructor: function() |
| + { |
| + destroyed.push(["type1", this.foo]); |
| + } |
| + }); |
| + |
| + // Single release() call |
| + destroyed = []; |
| + type1(1).release(); |
| + deepEqual(destroyed, [["type1", 1]], "Destructor called after release()"); |
| + |
| + // retain() and multiple release() calls |
| + destroyed = []; |
| + let obj2 = type1(2); |
| + equal(obj2.bufferIndex, 0, "New object replaces the destroyed one"); |
| + equal(obj2.byteOffset, 0, "New object replaces the destroyed one"); |
| + |
| + obj2.retain(); |
| + obj2.release(); |
| + deepEqual(destroyed, [], "Destructor not called after release() if retain() was called"); |
| + obj2.release(); |
| + deepEqual(destroyed, [["type1", 2]], "Destructor called after second release()"); |
| + |
| + // References holding object |
| + let type2 = type1.extend({ |
| + bar: type1 |
| + }, { |
| + destructor: function(super_) |
| + { |
| + super_(); |
| + destroyed.push(["type2", this.foo]); |
| + } |
| + }); |
| + |
| + destroyed = []; |
| + let obj3 = type1(3); |
| + let obj4 = type2(4); |
| + obj4.bar = obj3; |
| + obj3.release(); |
| + deepEqual(destroyed, [], "Destructor not called if references to object exist"); |
| + obj4.bar = null; |
| + deepEqual(destroyed, [["type1", 3]], "Destructor called after reference is cleared"); |
| + |
| + // Recursive destruction |
| + destroyed = []; |
| + let obj5 = type1(5); |
| + obj4.bar = obj5; |
| + obj5.release(); |
| + deepEqual(destroyed, [], "Destructor not called if references to object exist"); |
| + obj4.release(); |
| + deepEqual(destroyed, [["type1", 4], ["type2", 4], ["type1", 5]], "Destroying an object released its references"); |
| + |
| + // Misbehaving destructors |
| + let type3 = type1.extend({}, { |
| + destructor: function(super_) |
| + { |
| + this.retain(); |
| + } |
| + }); |
| + throws(function() |
| + { |
| + type3(0).release(); |
| + }, "Retaining reference in destructor is prohibited"); |
| + |
| + let type4 = type1.extend({}, { |
| + destructor: function(super_) |
| + { |
| + this.release(); |
| + } |
| + }); |
| + throws(function() |
| + { |
| + type4(0).release(); |
| + }, "Releasing reference in destructor is prohibited"); |
| + |
| + let type5 = type1.extend({}, { |
| + destructor: function(super_) |
| + { |
| + this.retain(); |
| + this.release(); |
| + } |
| + }); |
| + type5(0).release(); |
| + ok(true, "Temporarily retaining reference in destructor is allowed"); |
| + }); |
| })(); |