aboutsummaryrefslogtreecommitdiff
path: root/tests/embind/embind_test.js
diff options
context:
space:
mode:
Diffstat (limited to 'tests/embind/embind_test.js')
-rw-r--r--tests/embind/embind_test.js341
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);
+ },
+ });
+});