diff options
Diffstat (limited to 'tests/embind/embind_test.js')
-rw-r--r-- | tests/embind/embind_test.js | 341 |
1 files changed, 341 insertions, 0 deletions
diff --git a/tests/embind/embind_test.js b/tests/embind/embind_test.js new file mode 100644 index 00000000..326bf740 --- /dev/null +++ b/tests/embind/embind_test.js @@ -0,0 +1,341 @@ +module({ + Emscripten: '../build/Emscripten.js' +}, function(imports) { + var cm = imports.Emscripten; + + var checkForLeaks = { + setUp: function() { + this.originalBlockCount = cm.mallinfo().uordblks; + }, + tearDown: function() { + assert.equal(this.originalBlockCount, cm.mallinfo().uordblks); + }, + }; + + fixture("embind", { + baseFixture: checkForLeaks, + + "test value creation": function() { + assert.equal(15, cm.emval_test_new_integer()); + assert.equal("Hello everyone", cm.emval_test_new_string()); + + var object = cm.emval_test_new_object(); + assert.equal('bar', object.foo); + assert.equal(1, object.baz); + }, + + "test passthrough": function() { + var a = {foo: 'bar'}; + var b = cm.emval_test_passthrough(a); + a.bar = 'baz'; + assert.equal('baz', b.bar); + + assert.equal(0, cm.count_emval_handles()); + }, + + "test void return converts to undefined": function() { + assert.equal(undefined, cm.emval_test_return_void()); + }, + + "test booleans can be marshalled": function() { + assert.equal(false, cm.emval_test_not(true)); + assert.equal(true, cm.emval_test_not(false)); + }, + + "test convert double to unsigned": function() { + var rv = cm.emval_test_as_unsigned(1.5); + assert.equal('number', typeof rv); + assert.equal(1, rv); + assert.equal(0, cm.count_emval_handles()); + }, + + "test get length of array": function() { + assert.equal(10, cm.emval_test_get_length([0, 1, 2, 3, 4, 5, 'a', 'b', 'c', 'd'])); + assert.equal(0, cm.count_emval_handles()); + }, + + "test add a bunch of things": function() { + assert.equal(66.0, cm.emval_test_add(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11)); + assert.equal(0, cm.count_emval_handles()); + }, + + "test sum array": function() { + assert.equal(66, cm.emval_test_sum([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])); + assert.equal(0, cm.count_emval_handles()); + }, + + "test strings": function() { + assert.equal("foobar", "foo" + "bar"); + assert.equal("foobar", cm.emval_test_take_and_return_std_string("foobar")); + + assert.equal("foobar", cm.emval_test_take_and_return_std_string_const_ref("foobar")); + }, + + "test no memory leak when passing strings in by const reference": function() { + var original = cm.mallinfo().uordblks; + cm.emval_test_take_and_return_std_string_const_ref("foobar"); + assert.equal(original, cm.mallinfo().uordblks); + }, + }); + + fixture("classes", { + baseFixture: checkForLeaks, + + "test class instance": function() { + var a = {foo: 'bar'}; + var c = new cm.ValHolder(a); + assert.equal('bar', c.getVal().foo); + + c.setVal('1234'); + assert.equal('1234', c.getVal()); + + c.delete(); + assert.equal(0, cm.count_emval_handles()); + }, + + "test class methods": function() { + assert.equal(10, cm.ValHolder.some_class_method(10)); + }, + + "test can't call methods on deleted class instances": function() { + var c = new cm.ValHolder(undefined); + c.delete(); + assert.throws(cm.BindingError, function() { + c.getVal(); + }); + assert.throws(cm.BindingError, function() { + c.delete(); + }); + }, + + "test isinstance": function() { + var c = new cm.ValHolder(undefined); + assert.instanceof(c, cm.ValHolder); + c.delete(); + }, + + "test can return class instances by value": function() { + var c = cm.emval_test_return_ValHolder(); + assert.deepEqual({}, c.getVal()); + c.delete(); + }, + + "test can pass class instances to functions by reference": function() { + var a = {a:1}; + var c = new cm.ValHolder(a); + cm.emval_test_set_ValHolder_to_empty_object(c); + assert.deepEqual({}, c.getVal()); + c.delete(); + }, + + "test can access struct fields": function() { + var c = new cm.CustomStruct(); + assert.equal(10, c.field); + c.delete(); + }, + + "test can set struct fields": function() { + var c = new cm.CustomStruct(); + c.field = 15; + assert.equal(15, c.field); + c.delete(); + }, + + "test assignment returns value": function() { + var c = new cm.CustomStruct(); + assert.equal(15, c.field = 15); + c.delete(); + }, + + "test assigning string to integer raises TypeError": function() { + var c = new cm.CustomStruct(); + + var e = assert.throws(TypeError, function() { + c.field = "hi"; + }); + assert.equal('Cannot convert "hi" to int', e.message); + + var e = assert.throws(TypeError, function() { + c.field = {foo:'bar'}; + }); + assert.equal('Cannot convert "[object Object]" to int', e.message); + + c.delete(); + }, + + "test can return tuples by value": function() { + var c = cm.emval_test_return_TupleVector(); + assert.deepEqual([1, 2, 3], c); + }, + + "test tuples can contain tuples": function() { + var c = cm.emval_test_return_TupleVectorTuple(); + assert.deepEqual([[1, 2, 3]], c); + }, + + "test can pass tuples by value": function() { + var c = cm.emval_test_take_and_return_TupleVector([4, 5, 6]); + assert.deepEqual([4, 5, 6], c); + }, + + "test can return structs by value": function() { + var c = cm.emval_test_return_StructVector(); + assert.deepEqual({x: 1, y: 2, z: 3}, c); + }, + + "test can pass structs by value": function() { + var c = cm.emval_test_take_and_return_StructVector({x: 4, y: 5, z: 6}); + assert.deepEqual({x: 4, y: 5, z: 6}, c); + }, + + "test can pass and return tuples in structs": function() { + var d = cm.emval_test_take_and_return_TupleInStruct({field: [1, 2, 3]}); + assert.deepEqual({field: [1, 2, 3]}, d); + }, + + "test can clone handles": function() { + assert.equal(0, cm.count_emval_handles()); + + var a = new cm.ValHolder({}); + var b = a.clone(); + a.delete(); + + assert.equal(1, cm.count_emval_handles()); + + assert.throws(cm.BindingError, function() { + a.delete(); + }); + b.delete(); + + assert.equal(0, cm.count_emval_handles()); + }, + + "test can't clone if already deleted": function() { + var a = new cm.ValHolder({}); + a.delete(); + assert.throws(cm.BindingError, function() { + a.clone(); + }); + }, + + "test moving handles is a clone+delete": function() { + var a = new cm.ValHolder({}); + var b = a.move(); + assert.throws(cm.BindingError, function() { + a.delete(); + }); + assert.equal(1, cm.count_emval_handles()); + b.delete(); + assert.equal(0, cm.count_emval_handles()); + }, + + "test StringHolder": function() { + var a = new cm.StringHolder("foobar"); + assert.equal("foobar", a.get()); + + a.set("barfoo"); + assert.equal("barfoo", a.get()); + a.delete(); + }, + }); + + fixture("embind enumerations", { + baseFixture: checkForLeaks, + + "test can compare enumeration values": function() { + assert.equal(cm.Enum.ONE, cm.Enum.ONE); + assert.notEqual(cm.Enum.ONE, cm.Enum.TWO); + }, + + "test repr includes enum value": function() { + assert.equal('<#Enum_ONE {}>', IMVU.repr(cm.Enum.ONE)); + assert.equal('<#Enum_TWO {}>', IMVU.repr(cm.Enum.TWO)); + }, + + "test instanceof": function() { + assert.instanceof(cm.Enum.ONE, cm.Enum); + }, + + "test can pass and return enumeration values to functions": function() { + assert.equal(cm.Enum.TWO, cm.emval_test_take_and_return_Enum(cm.Enum.TWO)); + }, + }); + + fixture("C++11 enum class", { + baseFixture: checkForLeaks, + + "test can compare enumeration values": function() { + assert.equal(cm.EnumClass.ONE, cm.EnumClass.ONE); + assert.notEqual(cm.EnumClass.ONE, cm.EnumClass.TWO); + }, + + "test repr includes enum value": function() { + assert.equal('<#EnumClass_ONE {}>', IMVU.repr(cm.EnumClass.ONE)); + assert.equal('<#EnumClass_TWO {}>', IMVU.repr(cm.EnumClass.TWO)); + }, + + "test instanceof": function() { + assert.instanceof(cm.EnumClass.ONE, cm.EnumClass); + }, + + "test can pass and return enumeration values to functions": function() { + assert.equal(cm.EnumClass.TWO, cm.emval_test_take_and_return_EnumClass(cm.EnumClass.TWO)); + }, + }); + + fixture("emval call tests", { + "test can call functions from C++": function() { + var called = false; + cm.emval_test_call_function(function(i, f, tv, sv) { + called = true; + assert.equal(10, i); + assert.equal(1.5, f); + assert.deepEqual([1.25, 2.5, 3.75], tv); + assert.deepEqual({x: 1.25, y: 2.5, z: 3.75}, sv); + }, 10, 1.5, [1.25, 2.5, 3.75], {x: 1.25, y: 2.5, z: 3.75}); + assert.true(called); + }, + }); + + fixture("interfaces", { + baseFixture: checkForLeaks, + + "test can wrap JS object in native interface": function() { + var foo = { + calls: [], + method: function() { + this.calls.push('called'); + return 10; + } + }; + + assert.equal(10, cm.emval_test_call_method(foo)); + assert.deepEqual(['called'], foo.calls); + }, + + "test can pass arguments and return complicated values": function() { + var calls = []; + var foo = { + method2: function(arg1, arg2) { + calls.push([arg1, arg2]); + return arg1; + } + }; + + var result = cm.emval_test_call_method2(foo, {field: [1, 2, 3]}, 7); + assert.deepEqual({field: [1, 2, 3]}, result); + assert.deepEqual([[{field: [1, 2, 3]}, 7]], calls); + }, + + "test can call interface methods that return nothing": function() { + var calls = []; + var foo = { + method3: function() { + calls.push('called'); + } + }; + cm.emval_test_call_method3(foo); + assert.deepEqual(['called'], calls); + }, + }); +}); |