Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
emscripten-core
GitHub Repository: emscripten-core/emscripten
Path: blob/main/test/embind/embind.test.js
6165 views
1
module({
2
Emscripten: '../../../../build/embind_test.js',
3
}, function(imports) {
4
/*jshint sub:true */
5
/* global console */
6
var cm = imports.Emscripten;
7
8
var CheckForLeaks = fixture("check for leaks", function() {
9
this.setUp(function() {
10
cm.setDelayFunction(undefined);
11
12
if (typeof INVOKED_FROM_EMSCRIPTEN_TEST_RUNNER === "undefined") { // TODO: Enable this to work in Emscripten runner as well!
13
assert.equal(0, cm.count_emval_handles());
14
}
15
});
16
this.tearDown(function() {
17
cm.flushPendingDeletes();
18
if (typeof INVOKED_FROM_EMSCRIPTEN_TEST_RUNNER === "undefined") { // TODO: Enable this to work in Emscripten runner as well!
19
assert.equal(0, cm.count_emval_handles());
20
}
21
});
22
});
23
24
var BaseFixture = CheckForLeaks;
25
26
BaseFixture.extend("temp jig", function() {
27
test("temp test", function() {
28
});
29
});
30
31
BaseFixture.extend("access to base class members", function() {
32
test("method name in derived class silently overrides inherited name", function() {
33
var derived = new cm.Derived();
34
assert.equal("Derived", derived.getClassName());
35
derived.delete();
36
});
37
test("can reference base method from derived class", function(){
38
var derived = new cm.Derived();
39
assert.equal("Base", derived.getClassNameFromBase());
40
derived.delete();
41
});
42
test("can reference base method from doubly derived class", function() {
43
var derivedTwice = new cm.DerivedTwice();
44
assert.equal("Base", derivedTwice.getClassNameFromBase());
45
derivedTwice.delete();
46
});
47
test("can reference base method through unbound classes", function() {
48
var derivedThrice = new cm.DerivedThrice();
49
assert.equal("Base", derivedThrice.getClassNameFromBase());
50
derivedThrice.delete();
51
});
52
test("property name in derived class hides identically named property in base class for set", function() {
53
var derived = new cm.Derived();
54
derived.setMember(7);
55
56
derived.member = 17;
57
58
assert.equal(17, derived.getMember());
59
derived.delete();
60
});
61
test("can reference base property from derived class for get", function(){
62
var derived = new cm.Derived();
63
derived.setBaseMember(5);
64
65
assert.equal(5, derived.baseMember);
66
67
derived.delete();
68
});
69
test("can reference property of any base class for get when multiply derived", function(){
70
var derived = new cm.MultiplyDerived();
71
derived.setBaseMember(11);
72
73
assert.equal(11, derived.baseMember);
74
75
derived.delete();
76
});
77
test("can reference base property from derived class for set", function(){
78
var derived = new cm.Derived();
79
80
derived.baseMember = 32;
81
82
assert.equal(32, derived.getBaseMember());
83
derived.delete();
84
});
85
test("can reference property of any base for set when multiply derived", function(){
86
var derived = new cm.MultiplyDerived();
87
derived.setBaseMember(97);
88
89
derived.baseMember = 32;
90
91
assert.equal(32, derived.getBaseMember());
92
derived.delete();
93
});
94
test("can reach around derived property to access base property with same name for get", function() {
95
var derived = new cm.Derived();
96
derived.setMember(12);
97
derived.delete();
98
});
99
100
test("if deriving from second base adjusts pointer", function() {
101
var derived = new cm.HasTwoBases;
102
assert.equal("Base2", derived.getField());
103
derived.delete();
104
});
105
106
test("properties adjust pointer", function() {
107
var derived = new cm.HasTwoBases;
108
derived.field = "Foo";
109
assert.equal("Foo", derived.getField());
110
assert.equal("Foo", derived.field);
111
derived.delete();
112
});
113
114
test("class functions are inherited in subclasses", function() {
115
assert.equal("Base", cm.Base.classFunction());
116
assert.equal("Derived", cm.Derived.classFunction());
117
assert.equal("Derived", cm.DerivedTwice.classFunction());
118
});
119
120
test("calling method on unrelated class throws error", function() {
121
var a = new cm.HasTwoBases;
122
var e = assert.throws(cm.BindingError, function() {
123
cm.Derived.prototype.setMember.call(a, "foo");
124
});
125
assert.equal('Expected null or instance of Derived, got an instance of Base2', e.message);
126
a.delete();
127
128
// Base1 and Base2 both have the method 'getField()' exposed - make sure
129
// that calling the Base2 function with a 'this' instance of Base1 doesn't accidentally work!
130
var b = new cm.Base1;
131
var e = assert.throws(cm.BindingError, function() {
132
cm.Base2.prototype.getField.call(b);
133
});
134
assert.equal('Expected null or instance of Base2, got an instance of Base1', e.message);
135
b.delete();
136
});
137
138
test("calling method with invalid this throws error", function() {
139
var e = assert.throws(cm.BindingError, function() {
140
cm.Derived.prototype.setMember.call(undefined, "foo");
141
});
142
assert.matches(/Cannot pass "(undefined|\[object global\])" as a Derived\*/, e.message);
143
144
var e = assert.throws(cm.BindingError, function() {
145
cm.Derived.prototype.setMember.call(true, "foo");
146
});
147
assert.equal('Cannot pass "true" as a Derived*', e.message);
148
149
if (cm.getCompilerSetting('STRICT_JS') && !cm.getCompilerSetting('DYNAMIC_EXECUTION')) {
150
var e = assert.throws(TypeError, function() {
151
cm.Derived.prototype.setMember.call(null, "foo");
152
});
153
assert.equal('Cannot convert "foo" to int', e.message)
154
} else {
155
var e = assert.throws(cm.BindingError, function() {
156
cm.Derived.prototype.setMember.call(null, "foo");
157
});
158
assert.equal('Cannot pass "[object global]" as a Derived*', e.message)
159
}
160
161
var e = assert.throws(cm.BindingError, function() {
162
cm.Derived.prototype.setMember.call(42, "foo");
163
});
164
assert.equal('Cannot pass "42" as a Derived*', e.message);
165
166
var e = assert.throws(cm.BindingError, function() {
167
cm.Derived.prototype.setMember.call("this", "foo");
168
});
169
assert.equal('Cannot pass "this" as a Derived*', e.message);
170
171
var e = assert.throws(cm.BindingError, function() {
172
cm.Derived.prototype.setMember.call({}, "foo");
173
});
174
assert.matches(/Cannot pass "(undefined|\[object Object\])" as a Derived\*/, e.message);
175
});
176
177
test("setting and getting property on unrelated class throws error", function() {
178
var a = new cm.HasTwoBases;
179
var e = assert.throws(cm.BindingError, function() {
180
Object.getOwnPropertyDescriptor(cm.HeldBySmartPtr.prototype, 'i').set.call(a, 10);
181
});
182
assert.equal('HeldBySmartPtr.i setter incompatible with "this" of type HasTwoBases', e.message);
183
184
var e = assert.throws(cm.BindingError, function() {
185
Object.getOwnPropertyDescriptor(cm.HeldBySmartPtr.prototype, 'i').get.call(a);
186
});
187
assert.equal('HeldBySmartPtr.i getter incompatible with "this" of type HasTwoBases', e.message);
188
189
a.delete();
190
});
191
});
192
193
BaseFixture.extend("automatic upcasting of parameters passed to C++", function() {
194
// raw
195
test("raw pointer argument is upcast to parameter type", function() {
196
var derived = new cm.Derived();
197
var name = cm.embind_test_get_class_name_via_base_ptr(derived);
198
assert.equal("Base", name);
199
derived.delete();
200
});
201
202
test("automatic raw pointer upcasting works with multiple inheritance", function() {
203
var derived = new cm.MultiplyDerived();
204
var name = cm.embind_test_get_class_name_via_base_ptr(derived);
205
assert.equal("Base", name);
206
derived.delete();
207
});
208
209
test("automatic raw pointer upcasting does not change local pointer", function() {
210
var derived = new cm.MultiplyDerived();
211
cm.embind_test_get_class_name_via_base_ptr(derived);
212
assert.equal("MultiplyDerived", derived.getClassName());
213
derived.delete();
214
});
215
216
test("passing incompatible raw pointer to method throws exception", function() {
217
var base = new cm.Base();
218
assert.throws(cm.BindingError, function() {
219
cm.embind_test_get_class_name_via_second_base_ptr(base);
220
});
221
base.delete();
222
});
223
224
// raw polymorphic
225
test("polymorphic raw pointer argument is upcast to parameter type", function() {
226
var derived = new cm.PolyDerived();
227
var name = cm.embind_test_get_class_name_via_polymorphic_base_ptr(derived);
228
assert.equal("PolyBase", name);
229
derived.delete();
230
});
231
232
test("automatic polymorphic raw pointer upcasting works with multiple inheritance", function() {
233
var derived = new cm.PolyMultiplyDerived();
234
var name = cm.embind_test_get_class_name_via_polymorphic_base_ptr(derived);
235
assert.equal("PolyBase", name);
236
derived.delete();
237
});
238
239
test("passing incompatible raw polymorphic pointer to method throws exception", function() {
240
var base = new cm.PolyBase();
241
assert.throws(cm.BindingError, function() {
242
cm.embind_test_get_class_name_via_polymorphic_second_base_ptr(base);
243
});
244
base.delete();
245
246
});
247
248
// smart
249
test("can pass smart pointer to raw pointer parameter", function() {
250
var smartBase = cm.embind_test_return_smart_base_ptr();
251
assert.equal("Base", cm.embind_test_get_class_name_via_base_ptr(smartBase));
252
smartBase.delete();
253
});
254
255
test("can pass and upcast smart pointer to raw pointer parameter", function() {
256
var smartDerived = cm.embind_test_return_smart_derived_ptr();
257
assert.equal("Base", cm.embind_test_get_class_name_via_base_ptr(smartDerived));
258
smartDerived.delete();
259
});
260
261
test("smart pointer argument is upcast to parameter type", function() {
262
var derived = cm.embind_test_return_smart_derived_ptr();
263
assert.instanceof(derived, cm.Derived);
264
assert.instanceof(derived, cm.Base);
265
var name = cm.embind_test_get_class_name_via_smart_base_ptr(derived);
266
assert.equal("Base", name);
267
derived.delete();
268
});
269
270
test("return smart derived ptr as base", function() {
271
var derived = cm.embind_test_return_smart_derived_ptr_as_base();
272
assert.equal("PolyDerived", cm.embind_test_get_virtual_class_name_via_smart_polymorphic_base_ptr(derived));
273
assert.equal("PolyDerived", derived.getClassName());
274
derived.delete();
275
});
276
277
test("return smart derived ptr as val", function() {
278
var derived = cm.embind_test_return_smart_derived_ptr_as_val();
279
assert.equal("PolyDerived", cm.embind_test_get_virtual_class_name_via_smart_polymorphic_base_ptr(derived));
280
derived.delete();
281
});
282
283
test("automatic smart pointer upcasting works with multiple inheritance", function() {
284
var derived = cm.embind_test_return_smart_multiply_derived_ptr();
285
var name = cm.embind_test_get_class_name_via_smart_base_ptr(derived);
286
assert.equal("Base", name);
287
derived.delete();
288
});
289
290
test("automatically upcasted smart pointer parameter shares ownership with original argument", function() {
291
var derived = cm.embind_test_return_smart_multiply_derived_ptr();
292
assert.equal(1, cm.MultiplyDerived.getInstanceCount());
293
cm.embind_save_smart_base_pointer(derived);
294
assert.equal(1, cm.MultiplyDerived.getInstanceCount());
295
derived.delete();
296
assert.equal(1, cm.MultiplyDerived.getInstanceCount());
297
cm.embind_save_smart_base_pointer(null);
298
assert.equal(0, cm.MultiplyDerived.getInstanceCount());
299
});
300
301
// smart polymorphic
302
test("smart polymorphic pointer argument is upcast to parameter type", function() {
303
var derived = cm.embind_test_return_smart_polymorphic_derived_ptr();
304
var name = cm.embind_test_get_class_name_via_smart_polymorphic_base_ptr(derived);
305
assert.equal("PolyBase", name);
306
derived.delete();
307
});
308
309
test("automatic smart polymorphic pointer upcasting works with multiple inheritance", function() {
310
var derived = cm.embind_test_return_smart_polymorphic_multiply_derived_ptr();
311
var name = cm.embind_test_get_class_name_via_smart_polymorphic_base_ptr(derived);
312
assert.equal("PolyBase", name);
313
derived.delete();
314
});
315
});
316
317
BaseFixture.extend("automatic downcasting of return values received from C++", function() {
318
// raw
319
test("non-polymorphic raw pointers are not downcast and do not break automatic casting mechanism", function() {
320
var base = cm.embind_test_return_raw_derived_ptr_as_base();
321
assert.equal("Base", base.getClassName());
322
assert.instanceof(base, cm.Base);
323
base.delete();
324
});
325
326
// raw polymorphic
327
test("polymorphic raw pointer return value is downcast to allocated type (if that is bound)", function() {
328
var derived = cm.embind_test_return_raw_polymorphic_derived_ptr_as_base();
329
assert.instanceof(derived, cm.PolyBase);
330
assert.instanceof(derived, cm.PolyDerived);
331
assert.equal("PolyDerived", derived.getClassName());
332
var siblingDerived = cm.embind_test_return_raw_polymorphic_sibling_derived_ptr_as_base();
333
assert.equal("PolySiblingDerived", siblingDerived.getClassName());
334
siblingDerived.delete();
335
derived.delete();
336
});
337
338
test("polymorphic raw pointer return value is downcast to the most derived bound type", function() {
339
var derivedThrice = cm.embind_test_return_raw_polymorphic_derived_four_times_not_bound_as_base();
340
// if the actual returned type is not bound, then don't assume anything
341
assert.equal("PolyBase", derivedThrice.getClassName());
342
// if we ever fix this, then reverse the assertion
343
//assert.equal("PolyDerivedThrice", derivedThrice.getClassName());
344
derivedThrice.delete();
345
});
346
347
test("polymorphic smart pointer return value is downcast to the most derived type which has an associated smart pointer", function() {
348
var derived = cm.embind_test_return_poly_derived_twice_without_smart_pointer_as_poly_base();
349
// if the actual returned type is not bound, then don't assume anything
350
assert.equal("PolyBase", derived.getClassName());
351
// if we ever fix this, then remove the assertion
352
//assert.equal("PolyDerived", derived.getClassName());
353
derived.delete();
354
});
355
356
test("automatic downcasting works with multiple inheritance", function() {
357
var base = cm.embind_test_return_raw_polymorphic_multiply_derived_ptr_as_base();
358
var secondBase = cm.embind_test_return_raw_polymorphic_multiply_derived_ptr_as_second_base();
359
assert.equal("PolyMultiplyDerived", base.getClassName());
360
// embind does not support multiple inheritance
361
//assert.equal("PolyMultiplyDerived", secondBase.getClassName());
362
secondBase.delete();
363
base.delete();
364
});
365
366
// smart
367
test("non-polymorphic smart pointers do not break automatic casting mechanism", function() {
368
});
369
370
// smart polymorphic
371
test("automatically downcasting a smart pointer does not change the underlying pointer", function() {
372
cm.PolyDerived.setPtrDerived();
373
assert.equal("PolyBase", cm.PolyDerived.getPtrClassName());
374
var derived = cm.PolyDerived.getPtr();
375
assert.equal("PolyDerived", derived.getClassName());
376
assert.equal("PolyBase", cm.PolyDerived.getPtrClassName());
377
derived.delete();
378
cm.PolyDerived.releasePtr();
379
});
380
381
test("polymorphic smart pointer return value is actual allocated type (when bound)", function() {
382
var derived = cm.embind_test_return_smart_polymorphic_derived_ptr_as_base();
383
assert.equal("PolyDerived", derived.getClassName());
384
385
var siblingDerived = cm.embind_test_return_smart_polymorphic_sibling_derived_ptr_as_base();
386
assert.equal("PolySiblingDerived", siblingDerived.getClassName());
387
388
siblingDerived.delete();
389
derived.delete();
390
});
391
});
392
393
BaseFixture.extend("string", function() {
394
var stdStringIsUTF8 = cm.getCompilerSetting('EMBIND_STD_STRING_IS_UTF8');
395
396
test("non-ascii strings", function() {
397
398
var expected = '';
399
if(stdStringIsUTF8) {
400
// ASCII
401
expected = 'aei';
402
// Latin-1 Supplement
403
expected += '\u00E1\u00E9\u00ED';
404
// Greek
405
expected += '\u03B1\u03B5\u03B9';
406
// Cyrillic
407
expected += '\u0416\u041B\u0424';
408
// CJK
409
expected += '\u5F9E\u7345\u5B50';
410
// Euro sign
411
expected += '\u20AC';
412
} else {
413
for (var i = 0; i < 128; ++i) {
414
expected += String.fromCharCode(128 + i);
415
}
416
}
417
assert.equal(expected, cm.get_non_ascii_string(stdStringIsUTF8));
418
});
419
if(!stdStringIsUTF8) {
420
test("passing non-8-bit strings from JS to std::string throws", function() {
421
assert.throws(cm.BindingError, function() {
422
cm.emval_test_take_and_return_std_string("\u1234");
423
});
424
});
425
}
426
test("can't pass integers as strings", function() {
427
var e = assert.throws(cm.BindingError, function() {
428
cm.emval_test_take_and_return_std_string(10);
429
});
430
});
431
432
test("can pass Uint8Array to std::string", function() {
433
var e = cm.emval_test_take_and_return_std_string(new Uint8Array([65, 66, 67, 68]));
434
assert.equal('ABCD', e);
435
});
436
437
test("can pass Uint8ClampedArray to std::string", function() {
438
var e = cm.emval_test_take_and_return_std_string(new Uint8ClampedArray([65, 66, 67, 68]));
439
assert.equal('ABCD', e);
440
});
441
442
test("can pass Int8Array to std::string", function() {
443
var e = cm.emval_test_take_and_return_std_string(new Int8Array([65, 66, 67, 68]));
444
assert.equal('ABCD', e);
445
});
446
447
test("can pass ArrayBuffer to std::string", function() {
448
var e = cm.emval_test_take_and_return_std_string((new Int8Array([65, 66, 67, 68])).buffer);
449
assert.equal('ABCD', e);
450
});
451
452
test("can pass string to std::string", function() {
453
var string = stdStringIsUTF8?"aeiáéíαειЖЛФ從獅子€":"ABCD";
454
455
var e = cm.emval_test_take_and_return_std_string(string);
456
assert.equal(string, e);
457
});
458
459
var utf16TestString = String.fromCharCode(10) +
460
String.fromCharCode(1234) +
461
String.fromCharCode(2345) +
462
String.fromCharCode(65535);
463
var utf32TestString = String.fromCharCode(10) +
464
String.fromCharCode(1234) +
465
String.fromCharCode(2345) +
466
String.fromCharCode(55357) +
467
String.fromCharCode(56833) +
468
String.fromCharCode(55357) +
469
String.fromCharCode(56960);
470
471
test("non-ascii wstrings", function() {
472
assert.equal(utf16TestString, cm.get_non_ascii_wstring());
473
});
474
475
test("non-ascii u16strings", function() {
476
assert.equal(utf16TestString, cm.get_non_ascii_u16string());
477
});
478
479
test("non-ascii u32strings", function() {
480
assert.equal(utf32TestString, cm.get_non_ascii_u32string());
481
});
482
483
test("passing unicode (wide) string into C++", function() {
484
assert.equal(utf16TestString, cm.take_and_return_std_wstring(utf16TestString));
485
});
486
487
test("passing unicode (utf-16) string into C++", function() {
488
assert.equal(utf16TestString, cm.take_and_return_std_u16string(utf16TestString));
489
});
490
491
test("passing unicode (utf-32) string into C++", function() {
492
assert.equal(utf32TestString, cm.take_and_return_std_u32string(utf32TestString));
493
});
494
495
if (cm.isMemoryGrowthEnabled) {
496
test("can access a literal wstring after a memory growth", function() {
497
cm.force_memory_growth();
498
assert.equal("get_literal_wstring", cm.get_literal_wstring());
499
});
500
501
test("can access a literal u16string after a memory growth", function() {
502
cm.force_memory_growth();
503
assert.equal("get_literal_u16string", cm.get_literal_u16string());
504
});
505
506
test("can access a literal u32string after a memory growth", function() {
507
cm.force_memory_growth();
508
assert.equal("get_literal_u32string", cm.get_literal_u32string());
509
});
510
}
511
512
});
513
514
BaseFixture.extend("embind", function() {
515
test("value creation", function() {
516
assert.equal(15, cm.emval_test_new_integer());
517
assert.equal("Hello everyone", cm.emval_test_new_string());
518
assert.equal("Hello everyone", cm.emval_test_get_string_from_val({key: "Hello everyone"}));
519
520
var object = cm.emval_test_new_object();
521
assert.equal('bar', object.foo);
522
assert.equal(1, object.baz);
523
});
524
525
test("pass const reference to primitive", function() {
526
assert.equal(3, cm.const_ref_adder(1, 2));
527
});
528
529
test("get instance pointer as value", function() {
530
var v = cm.emval_test_instance_pointer();
531
assert.instanceof(v, cm.DummyForPointer);
532
});
533
534
test("cast value to instance pointer using as<T*>", function() {
535
var v = cm.emval_test_instance_pointer();
536
var p_value = cm.emval_test_value_from_instance_pointer(v);
537
assert.equal(42, p_value);
538
});
539
540
test("passthrough", function() {
541
var a = {foo: 'bar'};
542
var b = cm.emval_test_passthrough(a);
543
a.bar = 'baz';
544
assert.equal('baz', b.bar);
545
546
assert.equal(0, cm.count_emval_handles());
547
});
548
549
test("void return converts to undefined", function() {
550
assert.equal(undefined, cm.emval_test_return_void());
551
});
552
553
test("booleans can be marshalled", function() {
554
assert.equal(false, cm.emval_test_not(true));
555
assert.equal(true, cm.emval_test_not(false));
556
});
557
558
test("val.is_undefined() is functional",function() {
559
assert.equal(true, cm.emval_test_is_undefined(undefined));
560
assert.equal(false, cm.emval_test_is_undefined(true));
561
assert.equal(false, cm.emval_test_is_undefined(false));
562
assert.equal(false, cm.emval_test_is_undefined(null));
563
assert.equal(false, cm.emval_test_is_undefined({}));
564
});
565
566
test("val.is_null() is functional",function() {
567
assert.equal(true, cm.emval_test_is_null(null));
568
assert.equal(false, cm.emval_test_is_null(true));
569
assert.equal(false, cm.emval_test_is_null(false));
570
assert.equal(false, cm.emval_test_is_null(undefined));
571
assert.equal(false, cm.emval_test_is_null({}));
572
});
573
574
test("val.is_true() is functional",function() {
575
assert.equal(true, cm.emval_test_is_true(true));
576
assert.equal(false, cm.emval_test_is_true(false));
577
assert.equal(false, cm.emval_test_is_true(null));
578
assert.equal(false, cm.emval_test_is_true(undefined));
579
assert.equal(false, cm.emval_test_is_true({}));
580
});
581
582
test("val.is_false() is functional",function() {
583
assert.equal(true, cm.emval_test_is_false(false));
584
assert.equal(false, cm.emval_test_is_false(true));
585
assert.equal(false, cm.emval_test_is_false(null));
586
assert.equal(false, cm.emval_test_is_false(undefined));
587
assert.equal(false, cm.emval_test_is_false({}));
588
});
589
590
test("val.equals() is functional",function() {
591
var values = [undefined, null, true, false, {}];
592
593
for(var i=0;i<values.length;++i){
594
var first = values[i];
595
for(var j=i;j<values.length;++j)
596
{
597
var second = values[j];
598
/*jshint eqeqeq:false*/
599
assert.equal((first == second), cm.emval_test_equals(first, second));
600
}
601
}
602
});
603
604
test("val.strictlyEquals() is functional", function() {
605
var values = [undefined, null, true, false, {}];
606
607
for(var i=0;i<values.length;++i){
608
var first = values[i];
609
for(var j=i;j<values.length;++j)
610
{
611
var second = values[j];
612
assert.equal(first===second, cm.emval_test_strictly_equals(first, second));
613
}
614
}
615
});
616
617
test("can pass booleans as integers", function() {
618
assert.equal(1, cm.emval_test_as_unsigned(true));
619
assert.equal(0, cm.emval_test_as_unsigned(false));
620
});
621
622
test("can pass booleans as floats", function() {
623
assert.equal(2, cm.const_ref_adder(true, true));
624
});
625
626
test("passing Symbol or BigInt as floats always throws", function() {
627
assert.throws(TypeError, function() { cm.const_ref_adder(Symbol('0'), 1); });
628
assert.throws(TypeError, function() { cm.const_ref_adder(0n, 1); });
629
});
630
631
if (cm.getCompilerSetting('ASSERTIONS')) {
632
test("can pass only number and boolean as floats with assertions", function() {
633
assert.throws(TypeError, function() { cm.const_ref_adder(1, undefined); });
634
assert.throws(TypeError, function() { cm.const_ref_adder(1, null); });
635
assert.throws(TypeError, function() { cm.const_ref_adder(1, '2'); });
636
});
637
} else {
638
test("can pass other types as floats without assertions", function() {
639
assert.equal(3, cm.const_ref_adder(1, '2'));
640
assert.equal(1, cm.const_ref_adder(1, null)); // null => 0
641
assert.true(isNaN(cm.const_ref_adder(1, 'cannot parse')));
642
assert.true(isNaN(cm.const_ref_adder(1, undefined))); // undefined => NaN
643
});
644
}
645
646
test("convert double to unsigned", function() {
647
var rv = cm.emval_test_as_unsigned(1.5);
648
assert.equal('number', typeof rv);
649
assert.equal(1, rv);
650
assert.equal(0, cm.count_emval_handles());
651
});
652
653
test("get length of array", function() {
654
assert.equal(10, cm.emval_test_get_length([0, 1, 2, 3, 4, 5, 'a', 'b', 'c', 'd']));
655
assert.equal(0, cm.count_emval_handles());
656
});
657
658
test("add a bunch of things", function() {
659
assert.equal(66.0, cm.emval_test_add(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11));
660
assert.equal(0, cm.count_emval_handles());
661
});
662
663
test("sum array", function() {
664
assert.equal(66, cm.emval_test_sum([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]));
665
assert.equal(0, cm.count_emval_handles());
666
});
667
668
test("strings", function() {
669
assert.equal("foobar", "foo" + "bar");
670
assert.equal("foobar", cm.emval_test_take_and_return_std_string("foobar"));
671
672
assert.equal("foobar", cm.emval_test_take_and_return_std_string_const_ref("foobar"));
673
});
674
675
test("nuls pass through strings", function() {
676
assert.equal("foo\0bar", cm.emval_test_take_and_return_std_string("foo\0bar"));
677
});
678
679
test("no memory leak when passing strings in by const reference", function() {
680
cm.emval_test_take_and_return_std_string_const_ref("foobar");
681
});
682
683
test("val callback arguments are not destroyed", function() {
684
cm.emval_test_callback_arg_lifetime(function() {});
685
});
686
687
test("can get global", function(){
688
/*jshint evil:true*/
689
assert.equal((new Function("return this;"))(), cm.embind_test_getglobal());
690
});
691
692
test("can create new object", function() {
693
assert.deepEqual({}, cm.embind_test_new_Object());
694
});
695
696
test("can invoke constructors with arguments", function() {
697
function constructor(i, s, argument) {
698
this.i = i;
699
this.s = s;
700
this.argument = argument;
701
}
702
constructor.prototype.method = function() {
703
return this.argument;
704
};
705
var x = {};
706
var instance = cm.embind_test_new_factory(constructor, x);
707
assert.equal(10, instance.i);
708
assert.equal("hello", instance.s);
709
assert.equal(x, instance.argument);
710
});
711
712
test("can return module property objects", function() {
713
assert.equal(cm.HEAP8, cm.get_module_property("HEAP8"));
714
});
715
716
test("can return big class instances", function() {
717
var c = cm.embind_test_return_big_class_instance();
718
assert.equal(11, c.member);
719
c.delete();
720
});
721
722
test("can return small class instances", function() {
723
var c = cm.embind_test_return_small_class_instance();
724
assert.equal(7, c.member);
725
c.delete();
726
});
727
728
test("can pass small class instances", function() {
729
var c = new cm.SmallClass();
730
var m = cm.embind_test_accept_small_class_instance(c);
731
assert.equal(7, m);
732
c.delete();
733
});
734
735
test("can pass big class instances", function() {
736
var c = new cm.BigClass();
737
var m = cm.embind_test_accept_big_class_instance(c);
738
assert.equal(11, m);
739
c.delete();
740
});
741
742
test("can pass unique_ptr", function() {
743
var p = cm.embind_test_return_unique_ptr(42);
744
var m = cm.embind_test_accept_unique_ptr(p);
745
assert.equal(42, m);
746
});
747
748
test("can pass unique_ptr to constructor", function() {
749
var c = new cm.embind_test_construct_class_with_unique_ptr(42);
750
assert.equal(42, c.getValue());
751
c.delete();
752
});
753
754
test("can get member classes then call its member functions", function() {
755
var p = new cm.ParentClass();
756
var c = p.getBigClass();
757
var m = c.getMember();
758
assert.equal(11, m);
759
c.delete();
760
p.delete();
761
});
762
763
test('C++ -> JS primitive type range checks', function() {
764
// all types should have zero.
765
assert.equal("0", cm.char_to_string(0));
766
assert.equal("0", cm.signed_char_to_string(0));
767
assert.equal("0", cm.unsigned_char_to_string(0));
768
assert.equal("0", cm.short_to_string(0));
769
assert.equal("0", cm.unsigned_short_to_string(0));
770
assert.equal("0", cm.int_to_string(0));
771
assert.equal("0", cm.unsigned_int_to_string(0));
772
assert.equal("0", cm.long_to_string(0));
773
assert.equal("0", cm.unsigned_long_to_string(0));
774
775
// all types should have positive values.
776
assert.equal("5", cm.char_to_string(5));
777
assert.equal("5", cm.signed_char_to_string(5));
778
assert.equal("5", cm.unsigned_char_to_string(5));
779
assert.equal("5", cm.short_to_string(5));
780
assert.equal("5", cm.unsigned_short_to_string(5));
781
assert.equal("5", cm.int_to_string(5));
782
assert.equal("5", cm.unsigned_int_to_string(5));
783
assert.equal("5", cm.long_to_string(5));
784
assert.equal("5", cm.unsigned_long_to_string(5));
785
786
// signed types should have negative values.
787
assert.equal("-5", cm.char_to_string(-5)); // Assuming char as signed.
788
assert.equal("-5", cm.signed_char_to_string(-5));
789
assert.equal("-5", cm.short_to_string(-5));
790
assert.equal("-5", cm.int_to_string(-5));
791
assert.equal("-5", cm.long_to_string(-5));
792
793
// assumptions: char == signed char == 8 bits
794
// unsigned char == 8 bits
795
// short == 16 bits
796
// int == long == 32 bits
797
798
// all types should have their max positive values.
799
assert.equal("127", cm.char_to_string(127));
800
assert.equal("127", cm.signed_char_to_string(127));
801
assert.equal("255", cm.unsigned_char_to_string(255));
802
assert.equal("32767", cm.short_to_string(32767));
803
assert.equal("65535", cm.unsigned_short_to_string(65535));
804
assert.equal("2147483647", cm.int_to_string(2147483647));
805
assert.equal("4294967295", cm.unsigned_int_to_string(4294967295));
806
assert.equal("2147483647", cm.long_to_string(2147483647));
807
assert.equal("4294967295", cm.unsigned_long_to_string(4294967295));
808
809
// signed types should have their min negative values.
810
assert.equal("-128", cm.char_to_string(-128));
811
assert.equal("-128", cm.signed_char_to_string(-128));
812
assert.equal("-32768", cm.short_to_string(-32768));
813
assert.equal("-2147483648", cm.int_to_string(-2147483648));
814
assert.equal("-2147483648", cm.long_to_string(-2147483648));
815
816
// passing out of range values should fail with assertions.
817
if (cm.getCompilerSetting('ASSERTIONS')) {
818
assert.throws(TypeError, function() { cm.char_to_string(-129); });
819
assert.throws(TypeError, function() { cm.char_to_string(128); });
820
assert.throws(TypeError, function() { cm.signed_char_to_string(-129); });
821
assert.throws(TypeError, function() { cm.signed_char_to_string(128); });
822
assert.throws(TypeError, function() { cm.unsigned_char_to_string(-1); });
823
assert.throws(TypeError, function() { cm.unsigned_char_to_string(256); });
824
assert.throws(TypeError, function() { cm.short_to_string(-32769); });
825
assert.throws(TypeError, function() { cm.short_to_string(32768); });
826
assert.throws(TypeError, function() { cm.unsigned_short_to_string(-1); });
827
assert.throws(TypeError, function() { cm.unsigned_short_to_string(65536); });
828
assert.throws(TypeError, function() { cm.int_to_string(-2147483649); });
829
assert.throws(TypeError, function() { cm.int_to_string(2147483648); });
830
assert.throws(TypeError, function() { cm.unsigned_int_to_string(-1); });
831
assert.throws(TypeError, function() { cm.unsigned_int_to_string(4294967296); });
832
if (cm.getCompilerSetting('MEMORY64')) {
833
assert.throws(TypeError, function() { cm.long_to_string(-18446744073709551616n); });
834
assert.throws(TypeError, function() { cm.long_to_string(18446744073709551616n); });
835
assert.throws(TypeError, function() { cm.unsigned_long_to_string(-1n); });
836
assert.throws(TypeError, function() { cm.unsigned_long_to_string(18446744073709551616n); });
837
} else {
838
assert.throws(TypeError, function() { cm.long_to_string(-2147483649); });
839
assert.throws(TypeError, function() { cm.long_to_string(2147483648); });
840
assert.throws(TypeError, function() { cm.unsigned_long_to_string(-1); });
841
assert.throws(TypeError, function() { cm.unsigned_long_to_string(4294967296); });
842
}
843
} else {
844
// test that an out of range value doesn't throw without assertions.
845
assert.equal("-129", cm.char_to_string(-129));
846
}
847
});
848
849
test("unsigned values are correctly returned when stored in memory", function() {
850
cm.store_unsigned_char(255);
851
assert.equal(255, cm.load_unsigned_char());
852
853
cm.store_unsigned_short(32768);
854
assert.equal(32768, cm.load_unsigned_short());
855
856
cm.store_unsigned_int(2147483648);
857
assert.equal(2147483648, cm.load_unsigned_int());
858
859
cm.store_unsigned_long(2147483648);
860
assert.equal(cm.getCompilerSetting('MEMORY64') ? 2147483648n : 2147483648, cm.load_unsigned_long());
861
});
862
863
if (cm.getCompilerSetting('ASSERTIONS')) {
864
test("throws type error when attempting to coerce null to int", function() {
865
var e = assert.throws(TypeError, function() {
866
cm.int_to_string(null);
867
});
868
assert.equal('Cannot convert "null" to int', e.message);
869
});
870
} else {
871
test("null is converted to 0 without assertions", function() {
872
assert.equal('0', cm.int_to_string(null));
873
});
874
}
875
876
test("access multiple class ctors", function() {
877
var a = new cm.MultipleCtors(10);
878
assert.equal(a.WhichCtorCalled(), 1);
879
var b = new cm.MultipleCtors(20, 20);
880
assert.equal(b.WhichCtorCalled(), 2);
881
var c = new cm.MultipleCtors(30, 30, 30);
882
assert.equal(c.WhichCtorCalled(), 3);
883
a.delete();
884
b.delete();
885
c.delete();
886
});
887
888
test("access multiple smart ptr ctors", function() {
889
var a = new cm.MultipleSmartCtors(10);
890
assert.equal(a.WhichCtorCalled(), 1);
891
var b = new cm.MultipleCtors(20, 20);
892
assert.equal(b.WhichCtorCalled(), 2);
893
a.delete();
894
b.delete();
895
});
896
897
test("wrong number of constructor arguments throws", function() {
898
assert.throws(cm.BindingError, function() { new cm.MultipleCtors(); });
899
assert.throws(cm.BindingError, function() { new cm.MultipleCtors(1,2,3,4); });
900
});
901
902
test("overloading of free functions", function() {
903
var a = cm.overloaded_function(10);
904
assert.equal(a, 1);
905
var b = cm.overloaded_function(20, 20);
906
assert.equal(b, 2);
907
});
908
909
test("wrong number of arguments to an overloaded free function", function() {
910
assert.throws(cm.BindingError, function() { cm.overloaded_function(); });
911
assert.throws(cm.BindingError, function() { cm.overloaded_function(30, 30, 30); });
912
});
913
914
test("overloading of class member functions", function() {
915
var foo = new cm.MultipleOverloads();
916
assert.equal(foo.Func(10), 1);
917
assert.equal(foo.WhichFuncCalled(), 1);
918
assert.equal(foo.Func(20, 20), 2);
919
assert.equal(foo.WhichFuncCalled(), 2);
920
foo.delete();
921
});
922
923
test("wrong number of arguments to an overloaded class member function", function() {
924
var foo = new cm.MultipleOverloads();
925
assert.throws(cm.BindingError, function() { foo.Func(); });
926
assert.throws(cm.BindingError, function() { foo.Func(30, 30, 30); });
927
foo.delete();
928
});
929
930
test("wrong number of arguments to an overloaded class static function", function() {
931
assert.throws(cm.BindingError, function() { cm.MultipleOverloads.StaticFunc(); });
932
assert.throws(cm.BindingError, function() { cm.MultipleOverloads.StaticFunc(30, 30, 30); });
933
});
934
935
test("overloading of derived class member functions", function() {
936
var foo = new cm.MultipleOverloadsDerived();
937
938
// NOTE: In C++, default lookup rules will hide overloads from base class if derived class creates them.
939
// In JS, we make the base class overloads implicitly available. In C++, they would need to be explicitly
940
// invoked, like foo.MultipleOverloads::Func(10);
941
assert.equal(foo.Func(10), 1);
942
assert.equal(foo.WhichFuncCalled(), 1);
943
assert.equal(foo.Func(20, 20), 2);
944
assert.equal(foo.WhichFuncCalled(), 2);
945
946
assert.equal(foo.Func(30, 30, 30), 3);
947
assert.equal(foo.WhichFuncCalled(), 3);
948
assert.equal(foo.Func(40, 40, 40, 40), 4);
949
assert.equal(foo.WhichFuncCalled(), 4);
950
foo.delete();
951
});
952
953
test("overloading of class static functions", function() {
954
assert.equal(cm.MultipleOverloads.StaticFunc(10), 1);
955
assert.equal(cm.MultipleOverloads.WhichStaticFuncCalled(), 1);
956
assert.equal(cm.MultipleOverloads.StaticFunc(20, 20), 2);
957
assert.equal(cm.MultipleOverloads.WhichStaticFuncCalled(), 2);
958
});
959
960
test("overloading of derived class static functions", function() {
961
assert.equal(cm.MultipleOverloadsDerived.StaticFunc(30, 30, 30), 3);
962
// TODO: Cannot access static member functions of a Base class via Derived.
963
// assert.equal(cm.MultipleOverloadsDerived.WhichStaticFuncCalled(), 3);
964
assert.equal(cm.MultipleOverloads.WhichStaticFuncCalled(), 3);
965
assert.equal(cm.MultipleOverloadsDerived.StaticFunc(40, 40, 40, 40), 4);
966
// TODO: Cannot access static member functions of a Base class via Derived.
967
// assert.equal(cm.MultipleOverloadsDerived.WhichStaticFuncCalled(), 4);
968
assert.equal(cm.MultipleOverloads.WhichStaticFuncCalled(), 4);
969
});
970
/*
971
test("can get templated member classes then call its member functions", function() {
972
var p = new cm.ContainsTemplatedMemberClass();
973
var c = p.getTestTemplate();
974
var m = c.getMember(1);
975
assert.equal(87, m);
976
c.delete();
977
p.delete();
978
});
979
*/
980
981
test("class member function named with a well-known symbol", function() {
982
var instance = new cm.SymbolNameClass();
983
assert.equal("Iterator", instance[Symbol.iterator]());
984
assert.equal("Species", cm.SymbolNameClass[Symbol.species]());
985
});
986
987
test("no undefined entry in overload table when depending on already bound types", function() {
988
var dummy_overloads = cm.MultipleOverloadsDependingOnDummy.prototype.dummy;
989
// check if the overloadTable is correctly named
990
// it can be minimized if using closure compiler
991
if (dummy_overloads.hasOwnProperty('overloadTable')) {
992
assert.false(dummy_overloads.overloadTable.hasOwnProperty('undefined'));
993
}
994
995
var dummy_static_overloads = cm.MultipleOverloadsDependingOnDummy.staticDummy;
996
// check if the overloadTable is correctly named
997
// it can be minimized if using closure compiler
998
if (dummy_static_overloads.hasOwnProperty('overloadTable')) {
999
assert.false(dummy_static_overloads.overloadTable.hasOwnProperty('undefined'));
1000
}
1001
1002
// this part should fail anyway if there is no overloadTable
1003
var dependOnDummy = new cm.MultipleOverloadsDependingOnDummy();
1004
var dummy = dependOnDummy.dummy();
1005
dependOnDummy.dummy(dummy);
1006
dummy.delete();
1007
dependOnDummy.delete();
1008
1009
// this part should fail anyway if there is no overloadTable
1010
var dummy = cm.MultipleOverloadsDependingOnDummy.staticDummy();
1011
cm.MultipleOverloadsDependingOnDummy.staticDummy(dummy);
1012
dummy.delete();
1013
});
1014
1015
test("no undefined entry in overload table for free functions", function() {
1016
var dummy_free_func = cm.getDummy;
1017
console.log(dummy_free_func);
1018
1019
if (dummy_free_func.hasOwnProperty('overloadTable')) {
1020
assert.false(dummy_free_func.overloadTable.hasOwnProperty('undefined'));
1021
}
1022
1023
var dummy = cm.getDummy();
1024
cm.getDummy(dummy);
1025
});
1026
});
1027
1028
BaseFixture.extend("vector", function() {
1029
test("std::vector returns as an native object", function() {
1030
var vec = cm.emval_test_return_vector();
1031
1032
assert.equal(3, vec.size());
1033
assert.equal(10, vec.get(0));
1034
assert.equal(20, vec.get(1));
1035
assert.equal(30, vec.get(2));
1036
vec.delete();
1037
});
1038
1039
test("out of bounds std::vector access returns undefined", function() {
1040
var vec = cm.emval_test_return_vector();
1041
1042
assert.equal(undefined, vec.get(4));
1043
// only test a negative index without assertions.
1044
if (!cm.getCompilerSetting('ASSERTIONS')) {
1045
assert.equal(undefined, vec.get(-1));
1046
}
1047
vec.delete();
1048
});
1049
1050
if (cm.getCompilerSetting('ASSERTIONS')) {
1051
test("out of type range array index throws with assertions", function() {
1052
var vec = cm.emval_test_return_vector();
1053
1054
assert.throws(TypeError, function() { vec.get(-1); });
1055
1056
vec.delete();
1057
});
1058
}
1059
1060
test("std::vector<std::shared_ptr<>> can be passed back", function() {
1061
var vec = cm.emval_test_return_shared_ptr_vector();
1062
1063
assert.equal(2, vec.size());
1064
var str0 = vec.get(0);
1065
var str1 = vec.get(1);
1066
1067
assert.equal('string #1', str0.get());
1068
assert.equal('string #2', str1.get());
1069
str0.delete();
1070
str1.delete();
1071
1072
vec.delete();
1073
});
1074
1075
test("objects can be pushed back", function() {
1076
var vectorHolder = new cm.VectorHolder();
1077
var vec = vectorHolder.get();
1078
assert.equal(2, vec.size());
1079
1080
var str = new cm.StringHolder('abc');
1081
vec.push_back(str);
1082
str.delete();
1083
assert.equal(3, vec.size());
1084
var str = vec.get(2);
1085
assert.equal('abc', str.get());
1086
1087
str.delete();
1088
vec.delete();
1089
vectorHolder.delete();
1090
});
1091
1092
test("can get elements with array operator", function(){
1093
var vec = cm.emval_test_return_vector();
1094
assert.equal(10, vec.get(0));
1095
vec.delete();
1096
});
1097
1098
test("can set elements with array operator", function() {
1099
var vec = cm.emval_test_return_vector();
1100
assert.equal(10, vec.get(0));
1101
vec.set(2, 60);
1102
assert.equal(60, vec.get(2));
1103
vec.delete();
1104
});
1105
1106
test("can set and get objects", function() {
1107
var vec = cm.emval_test_return_shared_ptr_vector();
1108
var str = vec.get(0);
1109
assert.equal('string #1', str.get());
1110
str.delete();
1111
vec.delete();
1112
});
1113
1114
test("resize appends the given value", function() {
1115
var vec = cm.emval_test_return_vector();
1116
1117
vec.resize(5, 42);
1118
assert.equal(5, vec.size());
1119
assert.equal(10, vec.get(0));
1120
assert.equal(20, vec.get(1));
1121
assert.equal(30, vec.get(2));
1122
assert.equal(42, vec.get(3));
1123
assert.equal(42, vec.get(4));
1124
vec.delete();
1125
});
1126
1127
test("resize preserves content when shrinking", function() {
1128
var vec = cm.emval_test_return_vector();
1129
1130
vec.resize(2, 42);
1131
assert.equal(2, vec.size());
1132
assert.equal(10, vec.get(0));
1133
assert.equal(20, vec.get(1));
1134
vec.delete();
1135
});
1136
1137
test("vectors can contain pointers", function() {
1138
var vec = cm.emval_test_return_vector_pointers();
1139
var small = vec.get(0);
1140
assert.equal(7, small.member);
1141
small.delete();
1142
vec.delete();
1143
});
1144
1145
test("std::vector is iterable", function() {
1146
var vec = cm.emval_test_return_vector();
1147
var values = [];
1148
for (var value of vec) {
1149
values.push(value);
1150
}
1151
assert.deepEqual([10, 20, 30], values);
1152
assert.deepEqual([10, 20, 30], Array.from(vec));
1153
vec.delete();
1154
});
1155
1156
test("custom class is iterable", function() {
1157
var iterable = new cm.CustomIterable();
1158
var values = [];
1159
for (var value of iterable) {
1160
values.push(value);
1161
}
1162
assert.deepEqual([1, 2, 3], values);
1163
assert.deepEqual([1, 2, 3], Array.from(iterable));
1164
iterable.delete();
1165
});
1166
1167
test("custom class with size_t is iterable", function() {
1168
var iterable = new cm.CustomIterableSizeT();
1169
if (cm.getCompilerSetting('MEMORY64')) {
1170
assert.equal(typeof iterable.count(), 'bigint');
1171
} else {
1172
assert.equal(typeof iterable.count(), 'number');
1173
}
1174
var values = [];
1175
for (var value of iterable) {
1176
values.push(value);
1177
}
1178
assert.deepEqual([10, 20, 30], values);
1179
assert.deepEqual([10, 20, 30], Array.from(iterable));
1180
iterable.delete();
1181
});
1182
});
1183
1184
BaseFixture.extend("map", function() {
1185
test("std::map returns as native object", function() {
1186
var map = cm.embind_test_get_string_int_map();
1187
1188
assert.equal(2, map.size());
1189
assert.equal(1, map.get("one"));
1190
assert.equal(2, map.get("two"));
1191
1192
map.delete();
1193
});
1194
1195
test("std::map can get keys", function() {
1196
var map = cm.embind_test_get_string_int_map();
1197
1198
var keys = map.keys();
1199
assert.equal(map.size(), keys.size());
1200
assert.equal("one", keys.get(0));
1201
assert.equal("two", keys.get(1));
1202
keys.delete();
1203
1204
map.delete();
1205
});
1206
1207
test("std::map can set keys and values", function() {
1208
var map = cm.embind_test_get_string_int_map();
1209
1210
assert.equal(2, map.size());
1211
1212
map.set("three", 3);
1213
1214
assert.equal(3, map.size());
1215
assert.equal(3, map.get("three"));
1216
1217
map.set("three", 4);
1218
1219
assert.equal(3, map.size());
1220
assert.equal(4, map.get("three"));
1221
1222
map.delete();
1223
});
1224
});
1225
1226
BaseFixture.extend("map_with_greater_comparator", function() {
1227
test("std::map with std::greater comparator", function() {
1228
var map = cm.embind_test_get_int_string_greater_map();
1229
assert.equal(2, map.size());
1230
assert.equal("one", map.get(1));
1231
assert.equal("two", map.get(2));
1232
map.delete();
1233
});
1234
1235
test("std::map with std::greater comparator keys are sorted in reverse", function() {
1236
var map = cm.embind_test_get_int_string_greater_map();
1237
var keys = map.keys();
1238
assert.equal(2, keys.size());
1239
assert.equal(2, keys.get(0));
1240
assert.equal(1, keys.get(1));
1241
keys.delete();
1242
map.delete();
1243
});
1244
});
1245
1246
BaseFixture.extend("optional", function() {
1247
if (!("embind_test_return_optional_int" in cm)) {
1248
return;
1249
}
1250
test("std::optional works with returning int", function() {
1251
var optional = cm.embind_test_return_optional_int(true);
1252
assert.equal(42, optional);
1253
1254
optional = cm.embind_test_return_optional_int(false);
1255
assert.equal(undefined, optional);
1256
});
1257
1258
test("std::optional works with returning float", function() {
1259
var optional = cm.embind_test_return_optional_float(true);
1260
assert.equal(Math.fround(4.2), optional);
1261
1262
optional = cm.embind_test_return_optional_float(false);
1263
assert.equal(undefined, optional);
1264
});
1265
1266
test("std::optional works with returning SmallClass", function() {
1267
var optional = cm.embind_test_return_optional_small_class(true);
1268
assert.equal(7, optional.member);
1269
optional.delete();
1270
1271
optional = cm.embind_test_return_optional_small_class(false);
1272
assert.equal(undefined, optional);
1273
});
1274
1275
test("std::optional works with returning SmallClass pointer", function() {
1276
var optional = cm.embind_test_return_optional_small_class_pointer(true);
1277
assert.equal(7, optional.member);
1278
optional.delete();
1279
1280
optional = cm.embind_test_return_optional_small_class(false);
1281
assert.equal(undefined, optional);
1282
});
1283
1284
test("std::optional works with returning string", function() {
1285
var optional = cm.embind_test_return_optional_string(true);
1286
assert.equal("hello", optional);
1287
1288
optional = cm.embind_test_return_optional_string(false);
1289
assert.equal(undefined, optional);
1290
});
1291
1292
test("std::optional works int arg", function() {
1293
var value = cm.embind_test_optional_int_arg(42);
1294
assert.equal(42, value);
1295
1296
value = cm.embind_test_optional_int_arg(undefined);
1297
assert.equal(-1, value);
1298
});
1299
1300
test("std::optional works float arg", function() {
1301
var value = cm.embind_test_optional_float_arg(4.2);
1302
assert.equal(Math.fround(4.2), value);
1303
1304
value = cm.embind_test_optional_float_arg(undefined);
1305
assert.equal(Math.fround(-1.1), value);
1306
});
1307
1308
test("std::optional works string arg", function() {
1309
var value = cm.embind_test_optional_string_arg("hello");
1310
assert.equal("hello", value);
1311
1312
value = cm.embind_test_optional_string_arg("");
1313
assert.equal("", value);
1314
1315
value = cm.embind_test_optional_string_arg(undefined);
1316
assert.equal("no value", value);
1317
});
1318
1319
test("std::optional works SmallClass arg", function() {
1320
var small = new cm.SmallClass();
1321
var value = cm.embind_test_optional_small_class_arg(small);
1322
assert.equal(7, value);
1323
small.delete();
1324
1325
value = cm.embind_test_optional_small_class_arg(undefined);
1326
assert.equal(-1, value);
1327
});
1328
1329
test("std::optional args can be omitted", function() {
1330
if (cm.getCompilerSetting('ASSERTIONS')) {
1331
// Argument length is only validated with assertions enabled.
1332
assert.throws(cm.BindingError, function() {
1333
cm.embind_test_optional_multiple_arg();
1334
});
1335
assert.throws(cm.BindingError, function() {
1336
cm.embind_test_optional_multiple_arg(1, 2, 3, 4);
1337
});
1338
}
1339
cm.embind_test_optional_multiple_arg(1);
1340
cm.embind_test_optional_multiple_arg(1, 2);
1341
});
1342
test("std::optional properties can be omitted", function() {
1343
// Sanity check: Not omitting still works.
1344
cm.embind_test_optional_property({x: 1, y: 2});
1345
// Omitting should also work, since "y" is std::optional.
1346
cm.embind_test_optional_property({x: 1});
1347
});
1348
});
1349
1350
BaseFixture.extend("functors", function() {
1351
test("can get and call function ptrs", function() {
1352
var ptr = cm.emval_test_get_function_ptr();
1353
assert.equal("foobar", ptr.opcall("foobar"));
1354
ptr.delete();
1355
});
1356
1357
test("can pass functor to C++", function() {
1358
var ptr = cm.emval_test_get_function_ptr();
1359
assert.equal("asdf", cm.emval_test_take_and_call_functor(ptr));
1360
ptr.delete();
1361
});
1362
1363
test("can clone handles", function() {
1364
var a = cm.emval_test_get_function_ptr();
1365
var b = a.clone();
1366
a.delete();
1367
1368
assert.throws(cm.BindingError, function() {
1369
a.delete();
1370
});
1371
b.delete();
1372
});
1373
});
1374
1375
BaseFixture.extend("classes", function() {
1376
test("class instance", function() {
1377
var a = {foo: 'bar'};
1378
assert.equal(0, cm.count_emval_handles());
1379
var c = new cm.ValHolder(a);
1380
assert.equal(1, cm.count_emval_handles());
1381
assert.equal('bar', c.getVal().foo);
1382
assert.equal(1, cm.count_emval_handles());
1383
1384
c.setVal('1234');
1385
assert.equal('1234', c.getVal());
1386
1387
c.delete();
1388
assert.equal(0, cm.count_emval_handles());
1389
});
1390
1391
test("class properties can be methods", function() {
1392
var a = {};
1393
var b = {foo: 'foo'};
1394
var c = new cm.ValHolder(a);
1395
assert.equal(a, c.val);
1396
c.val = b;
1397
assert.equal(b, c.val);
1398
c.delete();
1399
});
1400
1401
test("class properties can be std::function objects", function() {
1402
var a = {};
1403
var b = {foo: 'foo'};
1404
var c = new cm.ValHolder(a);
1405
assert.equal(a, c.function_val);
1406
c.function_val = b;
1407
assert.equal(b, c.function_val);
1408
c.delete();
1409
});
1410
1411
test("class properties can be read-only std::function objects", function() {
1412
var a = {};
1413
var h = new cm.ValHolder(a);
1414
assert.equal(a, h.readonly_function_val);
1415
var e = assert.throws(cm.BindingError, function() {
1416
h.readonly_function_val = 10;
1417
});
1418
assert.equal('ValHolder.readonly_function_val is a read-only property', e.message);
1419
h.delete();
1420
});
1421
1422
test("class properties can be function objects (functor)", function() {
1423
var a = {};
1424
var b = {foo: 'foo'};
1425
var c = new cm.ValHolder(a);
1426
assert.equal(a, c.functor_val);
1427
c.function_val = b;
1428
assert.equal(b, c.functor_val);
1429
c.delete();
1430
});
1431
1432
test("class properties can be read-only function objects (functor)", function() {
1433
var a = {};
1434
var h = new cm.ValHolder(a);
1435
assert.equal(a, h.readonly_functor_val);
1436
var e = assert.throws(cm.BindingError, function() {
1437
h.readonly_functor_val = 10;
1438
});
1439
assert.equal('ValHolder.readonly_functor_val is a read-only property', e.message);
1440
h.delete();
1441
});
1442
1443
test("class properties can be read-only", function() {
1444
var a = {};
1445
var h = new cm.ValHolder(a);
1446
assert.equal(a, h.val_readonly);
1447
var e = assert.throws(cm.BindingError, function() {
1448
h.val_readonly = 10;
1449
});
1450
assert.equal('ValHolder.val_readonly is a read-only property', e.message);
1451
h.delete();
1452
});
1453
1454
test("read-only member field", function() {
1455
var a = new cm.HasReadOnlyProperty(10);
1456
assert.equal(10, a.i);
1457
var e = assert.throws(cm.BindingError, function() {
1458
a.i = 20;
1459
});
1460
assert.equal('HasReadOnlyProperty.i is a read-only property', e.message);
1461
a.delete();
1462
});
1463
1464
test("class instance $$ property is non-enumerable", function() {
1465
var c = new cm.ValHolder(undefined);
1466
assert.deepEqual([], Object.keys(c));
1467
var d = c.clone();
1468
c.delete();
1469
1470
assert.deepEqual([], Object.keys(d));
1471
d.delete();
1472
});
1473
1474
test("class methods", function() {
1475
assert.equal(10, cm.ValHolder.some_class_method(10));
1476
1477
var b = cm.ValHolder.makeValHolder("foo");
1478
assert.equal("foo", b.getVal());
1479
b.delete();
1480
});
1481
1482
test("function objects as class constructors", function() {
1483
var a = new cm.ConstructFromStdFunction("foo", 10);
1484
assert.equal("foo", a.getVal());
1485
assert.equal(10, a.getA());
1486
1487
var b = new cm.ConstructFromFunctionObject("bar", 12);
1488
assert.equal("bar", b.getVal());
1489
assert.equal(12, b.getA());
1490
1491
a.delete();
1492
b.delete();
1493
});
1494
1495
test("function objects as class methods", function() {
1496
var b = cm.ValHolder.makeValHolder("foo");
1497
1498
// get & set via std::function
1499
assert.equal("foo", b.getValFunction());
1500
b.setValFunction("bar");
1501
1502
// get & set with templated signature
1503
assert.equal("bar", b.getThisPointer().getVal());
1504
1505
// get & set via 'callable'
1506
assert.equal("bar", b.getValFunctor());
1507
b.setValFunctor("baz");
1508
1509
assert.equal("baz", b.getValFunction());
1510
1511
b.delete();
1512
});
1513
1514
test("can't call methods on deleted class instances", function() {
1515
var c = new cm.ValHolder(undefined);
1516
c.delete();
1517
assert.throws(cm.BindingError, function() {
1518
c.getVal();
1519
});
1520
assert.throws(cm.BindingError, function() {
1521
c.delete();
1522
});
1523
});
1524
1525
test("calling constructor without new raises BindingError", function() {
1526
var e = assert.throws(cm.BindingError, function() {
1527
cm.ValHolder(undefined);
1528
});
1529
assert.equal("Use 'new' to construct ValHolder", e.message);
1530
});
1531
1532
test("can return class instances by value", function() {
1533
var c = cm.emval_test_return_ValHolder();
1534
assert.deepEqual({}, c.getVal());
1535
c.delete();
1536
});
1537
1538
test("can pass class instances to functions by reference", function() {
1539
var a = {a:1};
1540
var c = new cm.ValHolder(a);
1541
cm.emval_test_set_ValHolder_to_empty_object(c);
1542
assert.deepEqual({}, c.getVal());
1543
c.delete();
1544
});
1545
1546
test("can pass smart pointer by reference", function() {
1547
var base = cm.embind_test_return_smart_base_ptr();
1548
var name = cm.embind_test_get_class_name_via_reference_to_smart_base_ptr(base);
1549
assert.equal("Base", name);
1550
base.delete();
1551
});
1552
1553
test("can pass smart pointer by value", function() {
1554
var base = cm.embind_test_return_smart_base_ptr();
1555
var name = cm.embind_test_get_class_name_via_smart_base_ptr(base);
1556
assert.equal("Base", name);
1557
base.delete();
1558
});
1559
1560
// todo: fix this
1561
// This test does not work because we make no provision for argument values
1562
// having been changed after returning from a C++ routine invocation. In
1563
// this specific case, the original pointee of the smart pointer was
1564
// freed and replaced by a new one, but the ptr in our local handle
1565
// was never updated after returning from the call.
1566
test("can modify smart pointers passed by reference", function() {
1567
// var base = cm.embind_test_return_smart_base_ptr();
1568
// cm.embind_modify_smart_pointer_passed_by_reference(base);
1569
// assert.equal("Changed", base.getClassName());
1570
// base.delete();
1571
});
1572
1573
test("can not modify smart pointers passed by value", function() {
1574
var base = cm.embind_test_return_smart_base_ptr();
1575
cm.embind_attempt_to_modify_smart_pointer_when_passed_by_value(base);
1576
assert.equal("Base", base.getClassName());
1577
base.delete();
1578
});
1579
1580
test("const return value", function() {
1581
var c = new cm.ValHolder("foo");
1582
assert.equal("foo", c.getConstVal());
1583
c.delete();
1584
});
1585
1586
test("return object by const ref", function() {
1587
var c = new cm.ValHolder("foo");
1588
assert.equal("foo", c.getValConstRef());
1589
c.delete();
1590
});
1591
1592
test("instanceof", function() {
1593
var c = new cm.ValHolder("foo");
1594
assert.instanceof(c, cm.ValHolder);
1595
c.delete();
1596
});
1597
1598
test("can access struct fields", function() {
1599
var c = new cm.CustomStruct();
1600
assert.equal(10, c.field);
1601
assert.equal(10, c.getField());
1602
c.delete();
1603
});
1604
1605
test("can set struct fields", function() {
1606
var c = new cm.CustomStruct();
1607
c.field = 15;
1608
assert.equal(15, c.field);
1609
c.delete();
1610
});
1611
1612
test("assignment returns value", function() {
1613
var c = new cm.CustomStruct();
1614
assert.equal(15, c.field = 15);
1615
c.delete();
1616
});
1617
1618
if (cm.getCompilerSetting('ASSERTIONS')) {
1619
test("assigning string or object to integer raises TypeError with assertions", function() {
1620
var c = new cm.CustomStruct();
1621
var e = assert.throws(TypeError, function() {
1622
c.field = "hi";
1623
});
1624
assert.equal('Cannot convert "hi" to int', e.message);
1625
1626
var e = assert.throws(TypeError, function() {
1627
c.field = {foo:'bar'};
1628
});
1629
assert.equal('Cannot convert "[object Object]" to int', e.message);
1630
1631
c.delete();
1632
});
1633
} else {
1634
test("assigning string or object to integer is converted to 0", function() {
1635
var c = new cm.CustomStruct();
1636
1637
c.field = "hi";
1638
assert.equal(0, c.field);
1639
c.field = {foo:'bar'};
1640
assert.equal(0, c.field);
1641
1642
c.delete();
1643
});
1644
}
1645
1646
test("can return tuples by value", function() {
1647
var c = cm.emval_test_return_TupleVector();
1648
assert.deepEqual([1, 2, 3, 4], c);
1649
});
1650
1651
test("tuples can contain tuples", function() {
1652
var c = cm.emval_test_return_TupleVectorTuple();
1653
assert.deepEqual([[1, 2, 3, 4]], c);
1654
});
1655
1656
test("can pass tuples by value", function() {
1657
var c = cm.emval_test_take_and_return_TupleVector([4, 5, 6, 7]);
1658
assert.deepEqual([4, 5, 6, 7], c);
1659
});
1660
1661
test("can return structs by value", function() {
1662
var c = cm.emval_test_return_StructVector();
1663
assert.deepEqual({x: 1, y: 2, z: 3, w: 4}, c);
1664
});
1665
1666
test("can pass structs by value", function() {
1667
var c = cm.emval_test_take_and_return_StructVector({x: 4, y: 5, z: 6, w: 7});
1668
assert.deepEqual({x: 4, y: 5, z: 6, w: 7}, c);
1669
});
1670
1671
test("can pass and return tuples in structs", function() {
1672
var d = cm.emval_test_take_and_return_TupleInStruct({field: [1, 2, 3, 4]});
1673
assert.deepEqual({field: [1, 2, 3, 4]}, d);
1674
});
1675
1676
test("can pass and return arrays in structs", function() {
1677
var d = cm.emval_test_take_and_return_ArrayInStruct({
1678
field1: [1, 2],
1679
field2: [
1680
{ x: 1, y: 2 },
1681
{ x: 3, y: 4 }
1682
]
1683
});
1684
assert.deepEqual({
1685
field1: [1, 2],
1686
field2: [
1687
{ x: 1, y: 2 },
1688
{ x: 3, y: 4 }
1689
]
1690
}, d);
1691
});
1692
1693
test("can clone handles", function() {
1694
var a = new cm.ValHolder({});
1695
assert.equal(1, cm.count_emval_handles());
1696
var b = a.clone();
1697
a.delete();
1698
1699
assert.equal(1, cm.count_emval_handles());
1700
1701
assert.throws(cm.BindingError, function() {
1702
a.delete();
1703
});
1704
b.delete();
1705
1706
assert.equal(0, cm.count_emval_handles());
1707
});
1708
1709
test("A shared pointer set/get point to the same underlying pointer", function() {
1710
var a = new cm.SharedPtrHolder();
1711
var b = a.get();
1712
1713
a.set(b);
1714
var c = a.get();
1715
1716
assert.true(b.isAliasOf(c));
1717
b.delete();
1718
c.delete();
1719
a.delete();
1720
});
1721
1722
test("can return shared ptrs from instance methods", function() {
1723
var a = new cm.SharedPtrHolder();
1724
1725
// returns the shared_ptr.
1726
var b = a.get();
1727
1728
assert.equal("a string", b.get());
1729
b.delete();
1730
a.delete();
1731
});
1732
1733
test("smart ptrs clone correctly", function() {
1734
assert.equal(0, cm.count_emval_handles());
1735
1736
var a = cm.emval_test_return_shared_ptr();
1737
1738
var b = a.clone();
1739
a.delete();
1740
1741
assert.equal(1, cm.count_emval_handles());
1742
1743
assert.throws(cm.BindingError, function() {
1744
a.delete();
1745
});
1746
b.delete();
1747
1748
assert.equal(0, cm.count_emval_handles());
1749
});
1750
1751
test("can't clone if already deleted", function() {
1752
var a = new cm.ValHolder({});
1753
a.delete();
1754
assert.throws(cm.BindingError, function() {
1755
a.clone();
1756
});
1757
});
1758
1759
test("virtual calls work correctly", function() {
1760
var derived = cm.embind_test_return_raw_polymorphic_derived_ptr_as_base();
1761
assert.equal("PolyDerived", derived.virtualGetClassName());
1762
derived.delete();
1763
});
1764
1765
test("virtual calls work correctly on smart ptrs", function() {
1766
var derived = cm.embind_test_return_smart_polymorphic_derived_ptr_as_base();
1767
assert.equal("PolyDerived", derived.virtualGetClassName());
1768
derived.delete();
1769
});
1770
1771
test("Empty smart ptr is null", function() {
1772
var a = cm.emval_test_return_empty_shared_ptr();
1773
assert.equal(null, a);
1774
});
1775
1776
test("string cannot be given as smart pointer argument", function() {
1777
assert.throws(cm.BindingError, function() {
1778
cm.emval_test_is_shared_ptr_null("hello world");
1779
});
1780
});
1781
1782
test("number cannot be given as smart pointer argument", function() {
1783
assert.throws(cm.BindingError, function() {
1784
cm.emval_test_is_shared_ptr_null(105);
1785
});
1786
});
1787
1788
test("raw pointer cannot be given as smart pointer argument", function() {
1789
var p = new cm.ValHolder({});
1790
assert.throws(cm.BindingError, function() { cm.emval_test_is_shared_ptr_null(p); });
1791
p.delete();
1792
});
1793
1794
test("null is passed as empty smart pointer", function() {
1795
assert.true(cm.emval_test_is_shared_ptr_null(null));
1796
});
1797
1798
test("Deleting already deleted smart ptrs fails", function() {
1799
var a = cm.emval_test_return_shared_ptr();
1800
a.delete();
1801
assert.throws(cm.BindingError, function() {
1802
a.delete();
1803
});
1804
});
1805
1806
test("returned unique_ptr does not call destructor", function() {
1807
var logged = "";
1808
var c = new cm.emval_test_return_unique_ptr_lifetime(function (s) { logged += s; });
1809
assert.equal("(constructor)", logged);
1810
c.delete();
1811
});
1812
1813
test("returned unique_ptr calls destructor on delete", function() {
1814
var logged = "";
1815
var c = new cm.emval_test_return_unique_ptr_lifetime(function (s) { logged += s; });
1816
logged = "";
1817
c.delete();
1818
assert.equal("(destructor)", logged);
1819
});
1820
1821
test("StringHolder", function() {
1822
var a = new cm.StringHolder("foobar");
1823
assert.equal("foobar", a.get());
1824
1825
a.set("barfoo");
1826
assert.equal("barfoo", a.get());
1827
1828
assert.equal("barfoo", a.get_const_ref());
1829
1830
a.delete();
1831
});
1832
1833
test("can call methods on unique ptr", function() {
1834
var result = cm.emval_test_return_unique_ptr();
1835
1836
result.setVal('1234');
1837
assert.equal('1234', result.getVal());
1838
result.delete();
1839
});
1840
1841
test("can call methods on shared ptr", function(){
1842
var result = cm.emval_test_return_shared_ptr();
1843
result.setVal('1234');
1844
1845
assert.equal('1234', result.getVal());
1846
result.delete();
1847
});
1848
1849
test("Non functors throw exception", function() {
1850
var a = {foo: 'bar'};
1851
var c = new cm.ValHolder(a);
1852
assert.throws(TypeError, function() {
1853
c();
1854
});
1855
c.delete();
1856
});
1857
1858
test("non-member methods", function() {
1859
var a = {foo: 'bar'};
1860
var c = new cm.ValHolder(a);
1861
c.setEmpty(); // non-member method
1862
assert.deepEqual({}, c.getValNonMember());
1863
c.delete();
1864
});
1865
1866
test("instantiating class without constructor gives error", function() {
1867
var e = assert.throws(cm.BindingError, function() {
1868
cm.AbstractClass();
1869
});
1870
assert.equal("Use 'new' to construct AbstractClass", e.message);
1871
1872
var e = assert.throws(cm.BindingError, function() {
1873
new cm.AbstractClass();
1874
});
1875
assert.equal("AbstractClass has no accessible constructor", e.message);
1876
});
1877
1878
test("can construct class with external constructor with custom signature", function() {
1879
const valHolder = new cm.ValHolder(1,2);
1880
assert.equal(valHolder.getVal(), 3);
1881
});
1882
1883
test("can construct class with external constructor", function() {
1884
var e = new cm.HasExternalConstructor("foo");
1885
assert.instanceof(e, cm.HasExternalConstructor);
1886
assert.equal("foo", e.getString());
1887
e.delete();
1888
});
1889
1890
test("can construct class with external constructor with no copy constructor", function() {
1891
var e = new cm.HasExternalConstructorNoCopy(42);
1892
assert.instanceof(e, cm.HasExternalConstructorNoCopy);
1893
assert.equal(42, e.getInt());
1894
e.delete();
1895
});
1896
});
1897
1898
BaseFixture.extend("const", function() {
1899
test("calling non-const method with const handle is error", function() {
1900
var vh = cm.ValHolder.makeConst({});
1901
var e = assert.throws(cm.BindingError, function() {
1902
vh.setVal({});
1903
});
1904
assert.equal('Cannot convert argument of type ValHolder const* to parameter type ValHolder*', e.message);
1905
vh.delete();
1906
});
1907
1908
test("passing const pointer to non-const pointer is error", function() {
1909
var vh = new cm.ValHolder.makeConst({});
1910
var e = assert.throws(cm.BindingError, function() {
1911
cm.ValHolder.set_via_raw_pointer(vh, {});
1912
});
1913
assert.equal('Cannot convert argument of type ValHolder const* to parameter type ValHolder*', e.message);
1914
vh.delete();
1915
});
1916
});
1917
1918
BaseFixture.extend("smart pointers", function() {
1919
test("constructor can return smart pointer", function() {
1920
var e = new cm.HeldBySmartPtr(10, "foo");
1921
assert.instanceof(e, cm.HeldBySmartPtr);
1922
assert.equal(10, e.i);
1923
assert.equal("foo", e.s);
1924
var f = cm.takesHeldBySmartPtr(e);
1925
f.delete();
1926
e.delete();
1927
});
1928
1929
test("cannot pass incorrect smart pointer type", function() {
1930
var e = cm.emval_test_return_shared_ptr();
1931
assert.throws(cm.BindingError, function() {
1932
cm.takesHeldBySmartPtr(e);
1933
});
1934
e.delete();
1935
});
1936
1937
test("smart pointer object has no object keys", function() {
1938
var e = new cm.HeldBySmartPtr(10, "foo");
1939
assert.deepEqual([], Object.keys(e));
1940
1941
var f = e.clone();
1942
e.delete();
1943
1944
assert.deepEqual([], Object.keys(f));
1945
f.delete();
1946
});
1947
1948
test("smart pointer object has correct constructor name", function() {
1949
var e = new cm.HeldBySmartPtr(10, "foo");
1950
assert.equal("HeldBySmartPtr", e.constructor.name);
1951
e.delete();
1952
});
1953
1954
test("constructor can return smart pointer", function() {
1955
var e = new cm.HeldBySmartPtr(10, "foo");
1956
assert.instanceof(e, cm.HeldBySmartPtr);
1957
assert.equal(10, e.i);
1958
assert.equal("foo", e.s);
1959
var f = cm.takesHeldBySmartPtr(e);
1960
assert.instanceof(f, cm.HeldBySmartPtr);
1961
f.delete();
1962
e.delete();
1963
});
1964
1965
test("custom smart pointer", function() {
1966
var e = new cm.HeldByCustomSmartPtr(20, "bar");
1967
assert.instanceof(e, cm.HeldByCustomSmartPtr);
1968
assert.equal(20, e.i);
1969
assert.equal("bar", e.s);
1970
e.delete();
1971
});
1972
1973
test("custom smart pointer passed through wiretype", function() {
1974
var e = new cm.HeldByCustomSmartPtr(20, "bar");
1975
var f = cm.passThroughCustomSmartPtr(e);
1976
e.delete();
1977
1978
assert.instanceof(f, cm.HeldByCustomSmartPtr);
1979
assert.equal(20, f.i);
1980
assert.equal("bar", f.s);
1981
1982
f.delete();
1983
});
1984
1985
test("cannot give null to by-value argument", function() {
1986
var e = assert.throws(cm.BindingError, function() {
1987
cm.takesHeldBySmartPtr(null);
1988
});
1989
assert.equal('null is not a valid HeldBySmartPtr', e.message);
1990
});
1991
1992
test("raw pointer can take and give null", function() {
1993
assert.equal(null, cm.passThroughRawPtr(null));
1994
});
1995
1996
test("custom smart pointer can take and give null", function() {
1997
assert.equal(null, cm.passThroughCustomSmartPtr(null));
1998
});
1999
2000
test("cannot pass shared_ptr to CustomSmartPtr", function() {
2001
var o = cm.HeldByCustomSmartPtr.createSharedPtr(10, "foo");
2002
var e = assert.throws(cm.BindingError, function() {
2003
cm.passThroughCustomSmartPtr(o);
2004
});
2005
assert.equal('Cannot convert argument of type shared_ptr<HeldByCustomSmartPtr> to parameter type CustomSmartPtr<HeldByCustomSmartPtr>', e.message);
2006
o.delete();
2007
});
2008
2009
test("custom smart pointers can be passed to shared_ptr parameter", function() {
2010
var e = cm.HeldBySmartPtr.newCustomPtr(10, "abc");
2011
assert.equal(10, e.i);
2012
assert.equal("abc", e.s);
2013
2014
cm.takesHeldBySmartPtrSharedPtr(e).delete();
2015
e.delete();
2016
});
2017
2018
test("can call non-member functions as methods", function() {
2019
var e = new cm.HeldBySmartPtr(20, "bar");
2020
var f = e.returnThis();
2021
e.delete();
2022
assert.equal(20, f.i);
2023
assert.equal("bar", f.s);
2024
f.delete();
2025
});
2026
});
2027
2028
BaseFixture.extend("enumerations", function() {
2029
test("can compare enumeration values", function() {
2030
assert.equal(cm.Enum.ONE, cm.Enum.ONE);
2031
assert.notEqual(cm.Enum.ONE, cm.Enum.TWO);
2032
});
2033
2034
if (typeof INVOKED_FROM_EMSCRIPTEN_TEST_RUNNER === "undefined") { // TODO: Enable this to work in Emscripten runner as well!
2035
test("repr includes enum value", function() {
2036
assert.equal('<#Enum_ONE {}>', IMVU.repr(cm.Enum.ONE));
2037
assert.equal('<#Enum_TWO {}>', IMVU.repr(cm.Enum.TWO));
2038
});
2039
}
2040
2041
test("instanceof", function() {
2042
assert.instanceof(cm.Enum.ONE, cm.Enum);
2043
});
2044
2045
test("can pass and return enumeration values to functions", function() {
2046
assert.equal(cm.Enum.TWO, cm.emval_test_take_and_return_Enum(cm.Enum.TWO));
2047
});
2048
});
2049
2050
BaseFixture.extend("C++11 enum class", function() {
2051
test("can compare enumeration values", function() {
2052
assert.equal(cm.EnumClass.ONE, cm.EnumClass.ONE);
2053
assert.notEqual(cm.EnumClass.ONE, cm.EnumClass.TWO);
2054
});
2055
2056
if (typeof INVOKED_FROM_EMSCRIPTEN_TEST_RUNNER === "undefined") { // TODO: Enable this to work in Emscripten runner as well!
2057
test("repr includes enum value", function() {
2058
assert.equal('<#EnumClass_ONE {}>', IMVU.repr(cm.EnumClass.ONE));
2059
assert.equal('<#EnumClass_TWO {}>', IMVU.repr(cm.EnumClass.TWO));
2060
});
2061
}
2062
2063
test("instanceof", function() {
2064
assert.instanceof(cm.EnumClass.ONE, cm.EnumClass);
2065
});
2066
2067
test("can pass and return enumeration values to functions", function() {
2068
assert.equal(cm.EnumClass.TWO, cm.emval_test_take_and_return_EnumClass(cm.EnumClass.TWO));
2069
});
2070
});
2071
2072
BaseFixture.extend("enums with integer values", function() {
2073
test("can compare enumeration values", function() {
2074
assert.equal(cm.EnumNum.ONE, cm.EnumNum.ONE);
2075
assert.equal(cm.EnumNum.ONE, 0);
2076
assert.notEqual(cm.EnumNum.TWO, cm.EnumNum.ONE);
2077
});
2078
2079
if (typeof INVOKED_FROM_EMSCRIPTEN_TEST_RUNNER === "undefined") { // TODO: Enable this to work in Emscripten runner as well!
2080
test("repr includes enum value", function() {
2081
assert.equal(0, IMVU.repr(cm.EnumNum.ONE));
2082
assert.equal(1, IMVU.repr(cm.EnumNum.TWO));
2083
});
2084
}
2085
2086
test("can pass and return enumeration values to functions", function() {
2087
assert.equal(cm.EnumNum.TWO, cm.emval_test_take_and_return_EnumNum(cm.EnumNum.TWO));
2088
assert.equal(cm.EnumNum.TWO, cm.emval_test_take_and_return_EnumNum(cm.EnumNum.TWO));
2089
});
2090
});
2091
2092
2093
BaseFixture.extend("enums with string values", function() {
2094
test("can compare enumeration values", function() {
2095
assert.equal(cm.EnumStr.ONE, cm.EnumStr.ONE);
2096
assert.equal(cm.EnumStr.ONE, 'ONE');
2097
assert.notEqual(cm.EnumStr.ONE, cm.EnumStr.TWO);
2098
});
2099
2100
if (typeof INVOKED_FROM_EMSCRIPTEN_TEST_RUNNER === "undefined") { // TODO: Enable this to work in Emscripten runner as well!
2101
test("repr includes enum value", function() {
2102
assert.equal('ONE', IMVU.repr(cm.EnumStr.ONE));
2103
assert.equal('TWO', IMVU.repr(cm.EnumStr.TWO));
2104
});
2105
}
2106
2107
test("can pass and return enumeration values to functions", function() {
2108
assert.equal(cm.EnumStr.TWO, cm.emval_test_take_and_return_EnumStr(cm.EnumStr.TWO));
2109
assert.equal('TWO', cm.emval_test_take_and_return_EnumStr('TWO'));
2110
});
2111
});
2112
2113
BaseFixture.extend("emval call tests", function() {
2114
test("can call functions from C++", function() {
2115
var called = false;
2116
cm.emval_test_call_function(function(i, f, tv, sv) {
2117
called = true;
2118
assert.equal(10, i);
2119
assert.equal(1.5, f);
2120
assert.deepEqual([1.25, 2.5, 3.75, 4], tv);
2121
assert.deepEqual({x: 1.25, y: 2.5, z: 3.75, w:4}, sv);
2122
}, 10, 1.5, [1.25, 2.5, 3.75, 4], {x: 1.25, y: 2.5, z: 3.75, w:4});
2123
assert.true(called);
2124
});
2125
});
2126
2127
BaseFixture.extend("extending built-in classes", function() {
2128
// cm.ValHolder.prototype.patched = 10; // this sets instanceCounts.patched inside of Deletable module !?!
2129
2130
test("can access patched value on new instances", function() {
2131
cm.ValHolder.prototype.patched = 10;
2132
var c = new cm.ValHolder(undefined);
2133
assert.equal(10, c.patched);
2134
c.delete();
2135
cm.ValHolder.prototype.patched = undefined;
2136
});
2137
2138
test("can access patched value on returned instances", function() {
2139
cm.ValHolder.prototype.patched = 10;
2140
var c = cm.emval_test_return_ValHolder();
2141
assert.equal(10, c.patched);
2142
c.delete();
2143
cm.ValHolder.prototype.patched = undefined;
2144
});
2145
});
2146
2147
BaseFixture.extend("raw pointers", function() {
2148
test("can pass raw pointers into functions if explicitly allowed", function() {
2149
var vh = new cm.ValHolder({});
2150
cm.ValHolder.set_via_raw_pointer(vh, 10);
2151
assert.equal(10, cm.ValHolder.get_via_raw_pointer(vh));
2152
vh.delete();
2153
});
2154
2155
test("can return raw pointers from functions if explicitly allowed", function() {
2156
var p = cm.embind_test_return_raw_base_ptr();
2157
assert.equal("Base", p.getClassName());
2158
p.delete();
2159
});
2160
2161
test("can pass multiple raw pointers to functions", function() {
2162
var target = new cm.ValHolder(undefined);
2163
var source = new cm.ValHolder("hi");
2164
cm.ValHolder.transfer_via_raw_pointer(target, source);
2165
assert.equal("hi", target.getVal());
2166
target.delete();
2167
source.delete();
2168
});
2169
});
2170
2171
BaseFixture.extend("implementing abstract methods with JS objects", function() {
2172
test("can call abstract methods", function() {
2173
var obj = cm.getAbstractClass();
2174
assert.equal("from concrete", obj.abstractMethod());
2175
obj.delete();
2176
});
2177
2178
test("can implement abstract methods in JavaScript", function() {
2179
var expected = "my JS string";
2180
function MyImplementation() {
2181
this.rv = expected;
2182
}
2183
MyImplementation.prototype.abstractMethod = function() {
2184
return this.rv;
2185
};
2186
2187
var impl = cm.AbstractClass.implement(new MyImplementation);
2188
assert.equal(expected, impl.abstractMethod());
2189
assert.equal(expected, cm.callAbstractMethod(impl));
2190
impl.delete();
2191
});
2192
2193
test("can implement optional methods in JavaScript", function() {
2194
var expected = "my JS string";
2195
function MyImplementation() {
2196
this.rv = expected;
2197
}
2198
MyImplementation.prototype.optionalMethod = function() {
2199
return this.rv;
2200
};
2201
2202
var impl = cm.AbstractClass.implement(new MyImplementation);
2203
assert.equal(expected, cm.callOptionalMethod(impl, expected));
2204
impl.delete();
2205
});
2206
2207
test("if not implemented then optional method runs default", function() {
2208
var impl = cm.AbstractClass.implement({});
2209
assert.equal("optionalfoo", impl.optionalMethod("foo"));
2210
impl.delete();
2211
});
2212
2213
test("returning null shared pointer from interfaces implemented in JS code does not leak", function() {
2214
var impl = cm.AbstractClass.implement({
2215
returnsSharedPtr: function() {
2216
return null;
2217
}
2218
});
2219
cm.callReturnsSharedPtrMethod(impl);
2220
impl.delete();
2221
// Let the memory leak test superfixture check that no leaks occurred.
2222
});
2223
2224
test("returning a new shared pointer from interfaces implemented in JS code does not leak", function() {
2225
var impl = cm.AbstractClass.implement({
2226
returnsSharedPtr: function() {
2227
return cm.embind_test_return_smart_derived_ptr().deleteLater();
2228
}
2229
});
2230
cm.callReturnsSharedPtrMethod(impl);
2231
impl.delete();
2232
// Let the memory leak test superfixture check that no leaks occurred.
2233
});
2234
2235
test("void methods work", function() {
2236
var saved = {};
2237
var impl = cm.AbstractClass.implement({
2238
differentArguments: function(i, d, f, q, s) {
2239
saved.i = i;
2240
saved.d = d;
2241
saved.f = f;
2242
saved.q = q;
2243
saved.s = s;
2244
}
2245
});
2246
2247
cm.callDifferentArguments(impl, 1, 2, 3, 4, "foo");
2248
2249
assert.deepEqual(saved, {
2250
i: 1,
2251
d: 2,
2252
f: 3,
2253
q: 4,
2254
s: "foo",
2255
});
2256
2257
impl.delete();
2258
});
2259
2260
test("returning a cached new shared pointer from interfaces implemented in JS code does not leak", function() {
2261
var derived = cm.embind_test_return_smart_derived_ptr();
2262
var impl = cm.AbstractClass.implement({
2263
returnsSharedPtr: function() {
2264
return derived;
2265
}
2266
});
2267
cm.callReturnsSharedPtrMethod(impl);
2268
impl.delete();
2269
derived.delete();
2270
// Let the memory leak test superfixture check that no leaks occurred.
2271
});
2272
});
2273
2274
BaseFixture.extend("constructor prototype class inheritance", function() {
2275
var Empty = cm.AbstractClass.extend("Empty", {
2276
abstractMethod: function() {
2277
}
2278
});
2279
2280
test("can extend, construct, and delete", function() {
2281
var instance = new Empty;
2282
instance.delete();
2283
});
2284
2285
test("properties set in constructor are externally visible", function() {
2286
var HasProperty = cm.AbstractClass.extend("HasProperty", {
2287
__construct: function(x) {
2288
this.__parent.__construct.call(this);
2289
this.property = x;
2290
},
2291
abstractMethod: function() {
2292
}
2293
});
2294
var instance = new HasProperty(10);
2295
assert.equal(10, instance.property);
2296
instance.delete();
2297
});
2298
2299
test("pass derived object to c++", function() {
2300
var Implementation = cm.AbstractClass.extend("Implementation", {
2301
abstractMethod: function() {
2302
return "abc";
2303
},
2304
});
2305
var instance = new Implementation;
2306
var result = cm.callAbstractMethod(instance);
2307
instance.delete();
2308
assert.equal("abc", result);
2309
});
2310
2311
test("properties set in constructor are visible in overridden methods", function() {
2312
var HasProperty = cm.AbstractClass.extend("HasProperty", {
2313
__construct: function(x) {
2314
this.__parent.__construct.call(this);
2315
this.x = x;
2316
},
2317
abstractMethod: function() {
2318
return this.x;
2319
},
2320
});
2321
var instance = new HasProperty("xyz");
2322
var result = cm.callAbstractMethod(instance);
2323
instance.delete();
2324
assert.equal("xyz", result);
2325
});
2326
2327
test("interface methods are externally visible", function() {
2328
var instance = new Empty;
2329
var result = instance.concreteMethod();
2330
instance.delete();
2331
assert.equal("concrete", result);
2332
});
2333
2334
test("optional methods are externally visible", function() {
2335
var instance = new Empty;
2336
var result = instance.optionalMethod("_123");
2337
instance.delete();
2338
assert.equal("optional_123", result);
2339
});
2340
2341
test("optional methods: not defined", function() {
2342
var instance = new Empty;
2343
var result = cm.callOptionalMethod(instance, "_123");
2344
instance.delete();
2345
assert.equal("optional_123", result);
2346
});
2347
2348
// Calling C++ implementations of optional functions can be
2349
// made to work, but requires an interface change on the C++
2350
// side, using a technique similar to the one described at
2351
// https://wiki.python.org/moin/boost.python/OverridableVirtualFunctions
2352
//
2353
// The issue is that, in a standard binding, calling
2354
// parent.prototype.optionalMethod invokes the wrapper
2355
// function, which checks that the JS object implements
2356
// 'optionalMethod', which it does. Thus, C++ calls back into
2357
// JS, resulting in an infinite loop.
2358
//
2359
// The solution, for optional methods, is to bind a special
2360
// concrete implementation that specifically calls the base
2361
// class's implementation. See the binding of
2362
// AbstractClass::optionalMethod in embind_test.cpp.
2363
2364
test("can call parent implementation from within derived implementation", function() {
2365
var parent = cm.AbstractClass;
2366
var ExtendsOptionalMethod = parent.extend("ExtendsOptionalMethod", {
2367
abstractMethod: function() {
2368
},
2369
optionalMethod: function(s) {
2370
return "optionaljs_" + parent.prototype.optionalMethod.call(this, s);
2371
},
2372
});
2373
var instance = new ExtendsOptionalMethod;
2374
var result = cm.callOptionalMethod(instance, "_123");
2375
instance.delete();
2376
assert.equal("optionaljs_optional_123", result);
2377
});
2378
2379
test("instanceof", function() {
2380
var instance = new Empty;
2381
assert.instanceof(instance, Empty);
2382
assert.instanceof(instance, cm.AbstractClass);
2383
instance.delete();
2384
});
2385
2386
test("returning null shared pointer from interfaces implemented in JS code does not leak", function() {
2387
var C = cm.AbstractClass.extend("C", {
2388
abstractMethod: function() {
2389
},
2390
returnsSharedPtr: function() {
2391
return null;
2392
}
2393
});
2394
var impl = new C;
2395
cm.callReturnsSharedPtrMethod(impl);
2396
impl.delete();
2397
// Let the memory leak test superfixture check that no leaks occurred.
2398
});
2399
2400
test("returning a new shared pointer from interfaces implemented in JS code does not leak", function() {
2401
var C = cm.AbstractClass.extend("C", {
2402
abstractMethod: function() {
2403
},
2404
returnsSharedPtr: function() {
2405
return cm.embind_test_return_smart_derived_ptr().deleteLater();
2406
}
2407
});
2408
var impl = new C;
2409
cm.callReturnsSharedPtrMethod(impl);
2410
impl.delete();
2411
// Let the memory leak test superfixture check that no leaks occurred.
2412
});
2413
2414
test("void methods work", function() {
2415
var saved = {};
2416
var C = cm.AbstractClass.extend("C", {
2417
abstractMethod: function() {
2418
},
2419
differentArguments: function(i, d, f, q, s) {
2420
saved.i = i;
2421
saved.d = d;
2422
saved.f = f;
2423
saved.q = q;
2424
saved.s = s;
2425
}
2426
});
2427
var impl = new C;
2428
2429
cm.callDifferentArguments(impl, 1, 2, 3, 4, "foo");
2430
2431
assert.deepEqual(saved, {
2432
i: 1,
2433
d: 2,
2434
f: 3,
2435
q: 4,
2436
s: "foo",
2437
});
2438
2439
impl.delete();
2440
});
2441
2442
test("returning a cached new shared pointer from interfaces implemented in JS code does not leak", function() {
2443
var derived = cm.embind_test_return_smart_derived_ptr();
2444
var C = cm.AbstractClass.extend("C", {
2445
abstractMethod: function() {
2446
},
2447
returnsSharedPtr: function() {
2448
return derived;
2449
}
2450
});
2451
var impl = new C;
2452
cm.callReturnsSharedPtrMethod(impl);
2453
impl.delete();
2454
derived.delete();
2455
// Let the memory leak test superfixture check that no leaks occurred.
2456
});
2457
2458
test("calling pure virtual function gives good error message", function() {
2459
var C = cm.AbstractClass.extend("C", {});
2460
var error = assert.throws(cm.PureVirtualError, function() {
2461
new C;
2462
});
2463
assert.equal('Pure virtual function abstractMethod must be implemented in JavaScript', error.message);
2464
});
2465
2466
test("can extend from C++ class with constructor arguments", function() {
2467
var parent = cm.AbstractClassWithConstructor;
2468
var C = parent.extend("C", {
2469
__construct: function(x) {
2470
this.__parent.__construct.call(this, x);
2471
},
2472
abstractMethod: function() {
2473
return this.concreteMethod();
2474
}
2475
});
2476
2477
var impl = new C("hi");
2478
var rv = cm.callAbstractMethod2(impl);
2479
impl.delete();
2480
2481
assert.equal("hi", rv);
2482
});
2483
2484
test("__destruct is called when object is destroyed", function() {
2485
var parent = cm.HeldAbstractClass;
2486
var calls = [];
2487
var C = parent.extend("C", {
2488
method: function() {
2489
},
2490
__destruct: function() {
2491
calls.push("__destruct");
2492
this.__parent.__destruct.call(this);
2493
}
2494
});
2495
var impl = new C;
2496
var copy = impl.clone();
2497
impl.delete();
2498
assert.deepEqual([], calls);
2499
copy.delete();
2500
assert.deepEqual(["__destruct"], calls);
2501
});
2502
2503
test("if JavaScript implementation of interface is returned, don't wrap in new handle", function() {
2504
var parent = cm.HeldAbstractClass;
2505
var C = parent.extend("C", {
2506
method: function() {
2507
}
2508
});
2509
var impl = new C;
2510
var rv = cm.passHeldAbstractClass(impl);
2511
impl.delete();
2512
assert.equal(impl, rv);
2513
rv.delete();
2514
});
2515
2516
test("can instantiate two wrappers with constructors", function() {
2517
var parent = cm.HeldAbstractClass;
2518
var C = parent.extend("C", {
2519
__construct: function() {
2520
this.__parent.__construct.call(this);
2521
},
2522
method: function() {
2523
}
2524
});
2525
var a = new C;
2526
var b = new C;
2527
a.delete();
2528
b.delete();
2529
});
2530
2531
test("incorrectly calling parent is an error", function() {
2532
var parent = cm.HeldAbstractClass;
2533
var C = parent.extend("C", {
2534
__construct: function() {
2535
this.__parent.__construct();
2536
},
2537
method: function() {
2538
}
2539
});
2540
assert.throws(cm.BindingError, function() {
2541
new C;
2542
});
2543
});
2544
2545
test("deleteLater() works for JavaScript implementations", function() {
2546
var parent = cm.HeldAbstractClass;
2547
var C = parent.extend("C", {
2548
method: function() {
2549
}
2550
});
2551
var impl = new C;
2552
var rv = cm.passHeldAbstractClass(impl);
2553
impl.deleteLater();
2554
rv.deleteLater();
2555
cm.flushPendingDeletes();
2556
});
2557
2558
test("deleteLater() combined with delete() works for JavaScript implementations", function() {
2559
var parent = cm.HeldAbstractClass;
2560
var C = parent.extend("C", {
2561
method: function() {
2562
}
2563
});
2564
var impl = new C;
2565
var rv = cm.passHeldAbstractClass(impl);
2566
impl.deleteLater();
2567
rv.delete();
2568
cm.flushPendingDeletes();
2569
});
2570
2571
test("method arguments with pointer ownership semantics are cleaned up after call", function() {
2572
var parent = cm.AbstractClass;
2573
var C = parent.extend("C", {
2574
abstractMethod: function() {
2575
},
2576
});
2577
var impl = new C;
2578
cm.passShared(impl);
2579
impl.delete();
2580
});
2581
2582
test("method arguments with pointer ownership semantics can be cloned", function() {
2583
var parent = cm.AbstractClass;
2584
var owned;
2585
var C = parent.extend("C", {
2586
abstractMethod: function() {
2587
},
2588
passShared: function(p) {
2589
owned = p.clone();
2590
}
2591
});
2592
var impl = new C;
2593
cm.passShared(impl);
2594
impl.delete();
2595
2596
assert.equal("Derived", owned.getClassName());
2597
owned.delete();
2598
});
2599
2600
test("emscripten::val method arguments don't leak", function() {
2601
var parent = cm.AbstractClass;
2602
var got;
2603
var C = parent.extend("C", {
2604
abstractMethod: function() {
2605
},
2606
passVal: function(g) {
2607
got = g;
2608
}
2609
});
2610
var impl = new C;
2611
var v = {};
2612
cm.passVal(impl, v);
2613
impl.delete();
2614
2615
assert.equal(v, got);
2616
});
2617
});
2618
2619
BaseFixture.extend("registration order", function() {
2620
test("registration of tuple elements out of order leaves them in order", function() {
2621
var ot = cm.getOrderedTuple();
2622
assert.instanceof(ot[0], cm.FirstElement);
2623
assert.instanceof(ot[1], cm.SecondElement);
2624
ot[0].delete();
2625
ot[1].delete();
2626
});
2627
2628
test("registration of struct elements out of order", function() {
2629
var os = cm.getOrderedStruct();
2630
assert.instanceof(os.first, cm.FirstElement);
2631
assert.instanceof(os.second, cm.SecondElement);
2632
os.first.delete();
2633
os.second.delete();
2634
});
2635
});
2636
2637
if (typeof INVOKED_FROM_EMSCRIPTEN_TEST_RUNNER === "undefined") { // TODO: Enable this to work in Emscripten runner as well!
2638
2639
BaseFixture.extend("unbound types", function() {
2640
if (!cm.hasUnboundTypeNames) {
2641
return;
2642
}
2643
2644
function assertMessage(fn, message) {
2645
var e = assert.throws(cm.UnboundTypeError, fn);
2646
assert.equal(message, e.message);
2647
}
2648
2649
test("calling function with unbound types produces error", function() {
2650
assertMessage(
2651
function() {
2652
cm.getUnboundClass();
2653
},
2654
'Cannot call getUnboundClass due to unbound types: 12UnboundClass');
2655
});
2656
2657
test("unbound base class produces error", function() {
2658
assertMessage(
2659
function() {
2660
cm.getHasUnboundBase();
2661
},
2662
'Cannot call getHasUnboundBase due to unbound types: 12UnboundClass');
2663
});
2664
2665
test("construct of class with unbound base", function() {
2666
assertMessage(
2667
function() {
2668
new cm.HasUnboundBase;
2669
}, 'Cannot construct HasUnboundBase due to unbound types: 12UnboundClass');
2670
});
2671
2672
test("unbound constructor argument", function() {
2673
assertMessage(
2674
function() {
2675
new cm.HasConstructorUsingUnboundArgument(1);
2676
},
2677
'Cannot construct HasConstructorUsingUnboundArgument due to unbound types: 12UnboundClass');
2678
});
2679
2680
test("unbound constructor argument of class with unbound base", function() {
2681
assertMessage(
2682
function() {
2683
new cm.HasConstructorUsingUnboundArgumentAndUnboundBase;
2684
},
2685
'Cannot construct HasConstructorUsingUnboundArgumentAndUnboundBase due to unbound types: 18SecondUnboundClass');
2686
});
2687
2688
test('class function with unbound argument', function() {
2689
var x = new cm.BoundClass;
2690
assertMessage(
2691
function() {
2692
x.method();
2693
}, 'Cannot call BoundClass.method due to unbound types: 12UnboundClass');
2694
x.delete();
2695
});
2696
2697
test('class class function with unbound argument', function() {
2698
assertMessage(
2699
function() {
2700
cm.BoundClass.classfunction();
2701
}, 'Cannot call BoundClass.classfunction due to unbound types: 12UnboundClass');
2702
});
2703
2704
test('class property of unbound type', function() {
2705
var x = new cm.BoundClass;
2706
var y;
2707
assertMessage(
2708
function() {
2709
y = x.property;
2710
}, 'Cannot access BoundClass.property due to unbound types: 12UnboundClass');
2711
assertMessage(
2712
function() {
2713
x.property = 10;
2714
}, 'Cannot access BoundClass.property due to unbound types: 12UnboundClass');
2715
x.delete();
2716
});
2717
2718
// todo: tuple elements
2719
// todo: tuple element accessors
2720
// todo: struct fields
2721
});
2722
2723
}
2724
2725
BaseFixture.extend("noncopyable", function() {
2726
test('can call method on noncopyable object', function() {
2727
var x = new cm.Noncopyable;
2728
assert.equal('foo', x.method());
2729
x.delete();
2730
});
2731
});
2732
2733
BaseFixture.extend("function names", function() {
2734
assert.equal('ValHolder', cm.ValHolder.name);
2735
2736
assert.equal('ValHolder.setVal', cm.ValHolder.prototype.setVal.name);
2737
assert.equal('ValHolder.makeConst', cm.ValHolder.makeConst.name);
2738
});
2739
2740
BaseFixture.extend("constants", function() {
2741
assert.equal(10, cm.INT_CONSTANT);
2742
2743
assert.equal(1, cm.STATIC_CONST_INTEGER_VALUE_1);
2744
assert.equal(1000, cm.STATIC_CONST_INTEGER_VALUE_1000);
2745
2746
assert.equal("some string", cm.STRING_CONSTANT);
2747
assert.deepEqual([1, 2, 3, 4], cm.VALUE_ARRAY_CONSTANT);
2748
assert.deepEqual({x:1,y:2,z:3,w:4}, cm.VALUE_OBJECT_CONSTANT);
2749
});
2750
2751
BaseFixture.extend("object handle comparison", function() {
2752
var e = new cm.ValHolder("foo");
2753
var f = new cm.ValHolder("foo");
2754
assert.false(e.isAliasOf(undefined));
2755
assert.false(e.isAliasOf(10));
2756
assert.true(e.isAliasOf(e));
2757
assert.false(e.isAliasOf(f));
2758
assert.false(f.isAliasOf(e));
2759
e.delete();
2760
f.delete();
2761
});
2762
2763
BaseFixture.extend("derived-with-offset types compare with base", function() {
2764
var e = new cm.DerivedWithOffset;
2765
var f = cm.return_Base_from_DerivedWithOffset(e);
2766
assert.true(e.isAliasOf(f));
2767
assert.true(f.isAliasOf(e));
2768
e.delete();
2769
f.delete();
2770
});
2771
2772
BaseFixture.extend("memory view", function() {
2773
test("can pass memory view from C++ to JS", function() {
2774
var views = [];
2775
cm.callWithMemoryView(function(view) {
2776
views.push(view);
2777
});
2778
assert.equal(3, views.length);
2779
2780
assert.instanceof(views[0], Uint8Array);
2781
assert.equal(8, views[0].length);
2782
assert.deepEqual([0, 1, 2, 3, 4, 5, 6, 7], [].slice.call(new Uint8Array(views[0])));
2783
2784
assert.instanceof(views[1], Float32Array);
2785
assert.equal(4, views[1].length);
2786
assert.deepEqual([1.5, 2.5, 3.5, 4.5], [].slice.call(views[1]));
2787
2788
assert.instanceof(views[2], Int16Array);
2789
assert.equal(4, views[2].length);
2790
assert.deepEqual([1000, 100, 10, 1], [].slice.call(views[2]));
2791
});
2792
});
2793
2794
BaseFixture.extend("delete pool", function() {
2795
test("can delete objects later", function() {
2796
var v = new cm.ValHolder({});
2797
v.deleteLater();
2798
assert.deepEqual({}, v.getVal());
2799
cm.flushPendingDeletes();
2800
assert.throws(cm.BindingError, function() {
2801
v.getVal();
2802
});
2803
});
2804
2805
test("calling deleteLater twice is an error", function() {
2806
var v = new cm.ValHolder({});
2807
v.deleteLater();
2808
assert.throws(cm.BindingError, function() {
2809
v.deleteLater();
2810
});
2811
});
2812
2813
test("can clone instances that have been scheduled for deletion", function() {
2814
var v = new cm.ValHolder({});
2815
v.deleteLater();
2816
var v2 = v.clone();
2817
v2.delete();
2818
});
2819
2820
test("deleteLater returns the object", function() {
2821
var v = (new cm.ValHolder({})).deleteLater();
2822
assert.deepEqual({}, v.getVal());
2823
});
2824
2825
test("deleteLater throws if object is already deleted", function() {
2826
var v = new cm.ValHolder({});
2827
v.delete();
2828
assert.throws(cm.BindingError, function() {
2829
v.deleteLater();
2830
});
2831
});
2832
2833
test("delete throws if object is already scheduled for deletion", function() {
2834
var v = new cm.ValHolder({});
2835
v.deleteLater();
2836
assert.throws(cm.BindingError, function() {
2837
v.delete();
2838
});
2839
});
2840
2841
test("deleteLater invokes delay function", function() {
2842
var runLater;
2843
cm.setDelayFunction(function(fn) {
2844
runLater = fn;
2845
});
2846
2847
var v = new cm.ValHolder({});
2848
assert.false(runLater);
2849
v.deleteLater();
2850
assert.true(runLater);
2851
assert.false(v.isDeleted());
2852
runLater();
2853
assert.true(v.isDeleted());
2854
});
2855
2856
test("deleteLater twice invokes delay function once", function() {
2857
var count = 0;
2858
var runLater;
2859
cm.setDelayFunction(function(fn) {
2860
++count;
2861
runLater = fn;
2862
});
2863
2864
(new cm.ValHolder({})).deleteLater();
2865
(new cm.ValHolder({})).deleteLater();
2866
assert.equal(1, count);
2867
runLater();
2868
(new cm.ValHolder({})).deleteLater();
2869
assert.equal(2, count);
2870
});
2871
2872
test('The delay function is immediately invoked if the deletion queue is not empty', function() {
2873
(new cm.ValHolder({})).deleteLater();
2874
var count = 0;
2875
cm.setDelayFunction(function(fn) {
2876
++count;
2877
});
2878
assert.equal(1, count);
2879
});
2880
2881
// The idea is that an interactive application would
2882
// periodically flush the deleteLater queue by calling
2883
//
2884
// setDelayFunction(function(fn) {
2885
// setTimeout(fn, 0);
2886
// });
2887
});
2888
2889
BaseFixture.extend("references", function() {
2890
test("JS object handles can be passed through to C++ by reference", function() {
2891
var sh = new cm.StringHolder("Hello world");
2892
assert.equal("Hello world", sh.get());
2893
cm.clear_StringHolder(sh);
2894
assert.equal("", sh.get());
2895
sh.delete();
2896
});
2897
});
2898
2899
BaseFixture.extend("val::as from pointer to value", function() {
2900
test("calling as on pointer with value makes a copy", function() {
2901
var sh1 = new cm.StringHolder("Hello world");
2902
var sh2 = cm.return_StringHolder_copy(sh1);
2903
assert.equal("Hello world", sh1.get());
2904
assert.equal("Hello world", sh2.get());
2905
assert.false(sh1.isAliasOf(sh2));
2906
sh2.delete();
2907
sh1.delete();
2908
});
2909
2910
test("calling function that returns a StringHolder", function() {
2911
var sh1 = new cm.StringHolder("Hello world");
2912
var sh2 = cm.call_StringHolder_func(function() {
2913
return sh1;
2914
});
2915
assert.equal("Hello world", sh1.get());
2916
assert.equal("Hello world", sh2.get());
2917
assert.false(sh1.isAliasOf(sh2));
2918
sh2.delete();
2919
sh1.delete();
2920
});
2921
});
2922
2923
BaseFixture.extend("mixin", function() {
2924
test("can call mixin method", function() {
2925
var a = new cm.DerivedWithMixin();
2926
assert.instanceof(a, cm.Base);
2927
assert.equal(10, a.get10());
2928
a.delete();
2929
});
2930
});
2931
2932
BaseFixture.extend("val::as", function() {
2933
test("built-ins", function() {
2934
assert.equal(true, cm.val_as_bool(true));
2935
assert.equal(false, cm.val_as_bool(false));
2936
assert.equal(127, cm.val_as_char(127));
2937
assert.equal(32767, cm.val_as_short(32767));
2938
assert.equal(65536, cm.val_as_int(65536));
2939
if (cm.getCompilerSetting('MEMORY64')) {
2940
assert.equal(65536n, cm.val_as_long(65536));
2941
} else {
2942
assert.equal(65536, cm.val_as_long(65536));
2943
}
2944
assert.equal(10.5, cm.val_as_float(10.5));
2945
assert.equal(10.5, cm.val_as_double(10.5));
2946
2947
assert.equal("foo", cm.val_as_string("foo"));
2948
assert.equal("foo", cm.val_as_wstring("foo"));
2949
2950
var obj = {};
2951
assert.equal(obj, cm.val_as_val(obj));
2952
2953
// JS->C++ memory view not implemented
2954
//var ab = cm.val_as_memory_view(new ArrayBuffer(13));
2955
//assert.equal(13, ab.byteLength);
2956
});
2957
2958
test("value types", function() {
2959
var tuple = [1, 2, 3, 4];
2960
assert.deepEqual(tuple, cm.val_as_value_array(tuple));
2961
2962
var struct = {x: 1, y: 2, z: 3, w: 4};
2963
assert.deepEqual(struct, cm.val_as_value_object(struct));
2964
});
2965
2966
test("enums", function() {
2967
assert.equal(cm.Enum.ONE, cm.val_as_enum(cm.Enum.ONE));
2968
});
2969
});
2970
2971
BaseFixture.extend("val::new_", function() {
2972
test("variety of types", function() {
2973
function factory() {
2974
this.arguments = Array.prototype.slice.call(arguments, 0);
2975
}
2976
var instance = cm.construct_with_6_arguments(factory);
2977
assert.deepEqual(
2978
[6, -12.5, "a3", {x: 1, y: 2, z: 3, w: 4}, cm.EnumClass.TWO, [-1, -2, -3, -4]],
2979
instance.arguments);
2980
});
2981
2982
test("memory view", function() {
2983
function factory(before, view, after) {
2984
this.before = before;
2985
this.view = view;
2986
this.after = after;
2987
}
2988
2989
var instance = cm.construct_with_memory_view(factory);
2990
assert.equal("before", instance.before);
2991
assert.equal(10, instance.view.byteLength);
2992
assert.equal("after", instance.after);
2993
});
2994
2995
test("ints_and_float", function() {
2996
function factory(a, b, c) {
2997
this.a = a;
2998
this.b = b;
2999
this.c = c;
3000
}
3001
3002
var instance = cm.construct_with_ints_and_float(factory);
3003
assert.equal(65537, instance.a);
3004
assert.equal(4.0, instance.b);
3005
assert.equal(65538, instance.c);
3006
});
3007
3008
if (cm.isMemoryGrowthEnabled) {
3009
test("before and after memory growth", function() {
3010
var array = cm.construct_with_arguments_before_and_after_memory_growth();
3011
assert.equal(array[0].byteLength, 5);
3012
assert.equal(array[0].byteLength, array[1].byteLength);
3013
});
3014
}
3015
});
3016
3017
BaseFixture.extend("intrusive pointers", function() {
3018
test("can pass intrusive pointers", function() {
3019
var ic = new cm.IntrusiveClass;
3020
var d = cm.passThroughIntrusiveClass(ic);
3021
assert.true(ic.isAliasOf(d));
3022
ic.delete();
3023
d.delete();
3024
});
3025
3026
test("can hold intrusive pointers", function() {
3027
var ic = new cm.IntrusiveClass;
3028
var holder = new cm.IntrusiveClassHolder;
3029
holder.set(ic);
3030
ic.delete();
3031
var d = holder.get();
3032
d.delete();
3033
holder.delete();
3034
});
3035
3036
test("can extend from intrusive pointer class and still preserve reference in JavaScript", function() {
3037
var C = cm.IntrusiveClass.extend("C", {
3038
});
3039
var instance = new C;
3040
var holder = new cm.IntrusiveClassHolder;
3041
holder.set(instance);
3042
instance.delete();
3043
3044
var back = holder.get();
3045
assert.equal(back, instance);
3046
holder.delete();
3047
back.delete();
3048
});
3049
});
3050
3051
BaseFixture.extend("typeof", function() {
3052
test("typeof", function() {
3053
assert.equal("object", cm.getTypeOfVal(null));
3054
assert.equal("object", cm.getTypeOfVal({}));
3055
assert.equal("function", cm.getTypeOfVal(function(){}));
3056
assert.equal("number", cm.getTypeOfVal(1));
3057
assert.equal("string", cm.getTypeOfVal("hi"));
3058
});
3059
});
3060
3061
BaseFixture.extend("static member", function() {
3062
test("static members", function() {
3063
assert.equal(10, cm.HasStaticMember.c);
3064
assert.equal(20, cm.HasStaticMember.v);
3065
cm.HasStaticMember.v = 30;
3066
assert.equal(30, cm.HasStaticMember.v);
3067
});
3068
});
3069
});
3070
3071
/* global run_all_tests */
3072
// If running as part of the emscripten test runner suite, and not as part of the IMVU suite,
3073
// we launch the test execution from here. IMVU suite uses its own dedicated mechanism instead of this.
3074
if (typeof run_all_tests !== "undefined") {
3075
run_all_tests();
3076
}
3077
3078