Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
emscripten-core
GitHub Repository: emscripten-core/emscripten
Path: blob/main/test/embind/embind.test.js
4150 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
1146
BaseFixture.extend("map", function() {
1147
test("std::map returns as native object", function() {
1148
var map = cm.embind_test_get_string_int_map();
1149
1150
assert.equal(2, map.size());
1151
assert.equal(1, map.get("one"));
1152
assert.equal(2, map.get("two"));
1153
1154
map.delete();
1155
});
1156
1157
test("std::map can get keys", function() {
1158
var map = cm.embind_test_get_string_int_map();
1159
1160
var keys = map.keys();
1161
assert.equal(map.size(), keys.size());
1162
assert.equal("one", keys.get(0));
1163
assert.equal("two", keys.get(1));
1164
keys.delete();
1165
1166
map.delete();
1167
});
1168
1169
test("std::map can set keys and values", function() {
1170
var map = cm.embind_test_get_string_int_map();
1171
1172
assert.equal(2, map.size());
1173
1174
map.set("three", 3);
1175
1176
assert.equal(3, map.size());
1177
assert.equal(3, map.get("three"));
1178
1179
map.set("three", 4);
1180
1181
assert.equal(3, map.size());
1182
assert.equal(4, map.get("three"));
1183
1184
map.delete();
1185
});
1186
});
1187
1188
BaseFixture.extend("map_with_greater_comparator", function() {
1189
test("std::map with std::greater comparator", function() {
1190
var map = cm.embind_test_get_int_string_greater_map();
1191
assert.equal(2, map.size());
1192
assert.equal("one", map.get(1));
1193
assert.equal("two", map.get(2));
1194
map.delete();
1195
});
1196
1197
test("std::map with std::greater comparator keys are sorted in reverse", function() {
1198
var map = cm.embind_test_get_int_string_greater_map();
1199
var keys = map.keys();
1200
assert.equal(2, keys.size());
1201
assert.equal(2, keys.get(0));
1202
assert.equal(1, keys.get(1));
1203
keys.delete();
1204
map.delete();
1205
});
1206
});
1207
1208
BaseFixture.extend("optional", function() {
1209
if (!("embind_test_return_optional_int" in cm)) {
1210
return;
1211
}
1212
test("std::optional works with returning int", function() {
1213
var optional = cm.embind_test_return_optional_int(true);
1214
assert.equal(42, optional);
1215
1216
optional = cm.embind_test_return_optional_int(false);
1217
assert.equal(undefined, optional);
1218
});
1219
1220
test("std::optional works with returning float", function() {
1221
var optional = cm.embind_test_return_optional_float(true);
1222
assert.equal(Math.fround(4.2), optional);
1223
1224
optional = cm.embind_test_return_optional_float(false);
1225
assert.equal(undefined, optional);
1226
});
1227
1228
test("std::optional works with returning SmallClass", function() {
1229
var optional = cm.embind_test_return_optional_small_class(true);
1230
assert.equal(7, optional.member);
1231
optional.delete();
1232
1233
optional = cm.embind_test_return_optional_small_class(false);
1234
assert.equal(undefined, optional);
1235
});
1236
1237
test("std::optional works with returning SmallClass pointer", function() {
1238
var optional = cm.embind_test_return_optional_small_class_pointer(true);
1239
assert.equal(7, optional.member);
1240
optional.delete();
1241
1242
optional = cm.embind_test_return_optional_small_class(false);
1243
assert.equal(undefined, optional);
1244
});
1245
1246
test("std::optional works with returning string", function() {
1247
var optional = cm.embind_test_return_optional_string(true);
1248
assert.equal("hello", optional);
1249
1250
optional = cm.embind_test_return_optional_string(false);
1251
assert.equal(undefined, optional);
1252
});
1253
1254
test("std::optional works int arg", function() {
1255
var value = cm.embind_test_optional_int_arg(42);
1256
assert.equal(42, value);
1257
1258
value = cm.embind_test_optional_int_arg(undefined);
1259
assert.equal(-1, value);
1260
});
1261
1262
test("std::optional works float arg", function() {
1263
var value = cm.embind_test_optional_float_arg(4.2);
1264
assert.equal(Math.fround(4.2), value);
1265
1266
value = cm.embind_test_optional_float_arg(undefined);
1267
assert.equal(Math.fround(-1.1), value);
1268
});
1269
1270
test("std::optional works string arg", function() {
1271
var value = cm.embind_test_optional_string_arg("hello");
1272
assert.equal("hello", value);
1273
1274
value = cm.embind_test_optional_string_arg("");
1275
assert.equal("", value);
1276
1277
value = cm.embind_test_optional_string_arg(undefined);
1278
assert.equal("no value", value);
1279
});
1280
1281
test("std::optional works SmallClass arg", function() {
1282
var small = new cm.SmallClass();
1283
var value = cm.embind_test_optional_small_class_arg(small);
1284
assert.equal(7, value);
1285
small.delete();
1286
1287
value = cm.embind_test_optional_small_class_arg(undefined);
1288
assert.equal(-1, value);
1289
});
1290
1291
test("std::optional args can be omitted", function() {
1292
if (cm.getCompilerSetting('ASSERTIONS')) {
1293
// Argument length is only validated with assertions enabled.
1294
assert.throws(cm.BindingError, function() {
1295
cm.embind_test_optional_multiple_arg();
1296
});
1297
assert.throws(cm.BindingError, function() {
1298
cm.embind_test_optional_multiple_arg(1, 2, 3, 4);
1299
});
1300
}
1301
cm.embind_test_optional_multiple_arg(1);
1302
cm.embind_test_optional_multiple_arg(1, 2);
1303
});
1304
test("std::optional properties can be omitted", function() {
1305
// Sanity check: Not omitting still works.
1306
cm.embind_test_optional_property({x: 1, y: 2});
1307
// Omitting should also work, since "y" is std::optional.
1308
cm.embind_test_optional_property({x: 1});
1309
});
1310
});
1311
1312
BaseFixture.extend("functors", function() {
1313
test("can get and call function ptrs", function() {
1314
var ptr = cm.emval_test_get_function_ptr();
1315
assert.equal("foobar", ptr.opcall("foobar"));
1316
ptr.delete();
1317
});
1318
1319
test("can pass functor to C++", function() {
1320
var ptr = cm.emval_test_get_function_ptr();
1321
assert.equal("asdf", cm.emval_test_take_and_call_functor(ptr));
1322
ptr.delete();
1323
});
1324
1325
test("can clone handles", function() {
1326
var a = cm.emval_test_get_function_ptr();
1327
var b = a.clone();
1328
a.delete();
1329
1330
assert.throws(cm.BindingError, function() {
1331
a.delete();
1332
});
1333
b.delete();
1334
});
1335
});
1336
1337
BaseFixture.extend("classes", function() {
1338
test("class instance", function() {
1339
var a = {foo: 'bar'};
1340
assert.equal(0, cm.count_emval_handles());
1341
var c = new cm.ValHolder(a);
1342
assert.equal(1, cm.count_emval_handles());
1343
assert.equal('bar', c.getVal().foo);
1344
assert.equal(1, cm.count_emval_handles());
1345
1346
c.setVal('1234');
1347
assert.equal('1234', c.getVal());
1348
1349
c.delete();
1350
assert.equal(0, cm.count_emval_handles());
1351
});
1352
1353
test("class properties can be methods", function() {
1354
var a = {};
1355
var b = {foo: 'foo'};
1356
var c = new cm.ValHolder(a);
1357
assert.equal(a, c.val);
1358
c.val = b;
1359
assert.equal(b, c.val);
1360
c.delete();
1361
});
1362
1363
test("class properties can be std::function objects", function() {
1364
var a = {};
1365
var b = {foo: 'foo'};
1366
var c = new cm.ValHolder(a);
1367
assert.equal(a, c.function_val);
1368
c.function_val = b;
1369
assert.equal(b, c.function_val);
1370
c.delete();
1371
});
1372
1373
test("class properties can be read-only std::function objects", function() {
1374
var a = {};
1375
var h = new cm.ValHolder(a);
1376
assert.equal(a, h.readonly_function_val);
1377
var e = assert.throws(cm.BindingError, function() {
1378
h.readonly_function_val = 10;
1379
});
1380
assert.equal('ValHolder.readonly_function_val is a read-only property', e.message);
1381
h.delete();
1382
});
1383
1384
test("class properties can be function objects (functor)", function() {
1385
var a = {};
1386
var b = {foo: 'foo'};
1387
var c = new cm.ValHolder(a);
1388
assert.equal(a, c.functor_val);
1389
c.function_val = b;
1390
assert.equal(b, c.functor_val);
1391
c.delete();
1392
});
1393
1394
test("class properties can be read-only function objects (functor)", function() {
1395
var a = {};
1396
var h = new cm.ValHolder(a);
1397
assert.equal(a, h.readonly_functor_val);
1398
var e = assert.throws(cm.BindingError, function() {
1399
h.readonly_functor_val = 10;
1400
});
1401
assert.equal('ValHolder.readonly_functor_val is a read-only property', e.message);
1402
h.delete();
1403
});
1404
1405
test("class properties can be read-only", function() {
1406
var a = {};
1407
var h = new cm.ValHolder(a);
1408
assert.equal(a, h.val_readonly);
1409
var e = assert.throws(cm.BindingError, function() {
1410
h.val_readonly = 10;
1411
});
1412
assert.equal('ValHolder.val_readonly is a read-only property', e.message);
1413
h.delete();
1414
});
1415
1416
test("read-only member field", function() {
1417
var a = new cm.HasReadOnlyProperty(10);
1418
assert.equal(10, a.i);
1419
var e = assert.throws(cm.BindingError, function() {
1420
a.i = 20;
1421
});
1422
assert.equal('HasReadOnlyProperty.i is a read-only property', e.message);
1423
a.delete();
1424
});
1425
1426
test("class instance $$ property is non-enumerable", function() {
1427
var c = new cm.ValHolder(undefined);
1428
assert.deepEqual([], Object.keys(c));
1429
var d = c.clone();
1430
c.delete();
1431
1432
assert.deepEqual([], Object.keys(d));
1433
d.delete();
1434
});
1435
1436
test("class methods", function() {
1437
assert.equal(10, cm.ValHolder.some_class_method(10));
1438
1439
var b = cm.ValHolder.makeValHolder("foo");
1440
assert.equal("foo", b.getVal());
1441
b.delete();
1442
});
1443
1444
test("function objects as class constructors", function() {
1445
var a = new cm.ConstructFromStdFunction("foo", 10);
1446
assert.equal("foo", a.getVal());
1447
assert.equal(10, a.getA());
1448
1449
var b = new cm.ConstructFromFunctionObject("bar", 12);
1450
assert.equal("bar", b.getVal());
1451
assert.equal(12, b.getA());
1452
1453
a.delete();
1454
b.delete();
1455
});
1456
1457
test("function objects as class methods", function() {
1458
var b = cm.ValHolder.makeValHolder("foo");
1459
1460
// get & set via std::function
1461
assert.equal("foo", b.getValFunction());
1462
b.setValFunction("bar");
1463
1464
// get & set with templated signature
1465
assert.equal("bar", b.getThisPointer().getVal());
1466
1467
// get & set via 'callable'
1468
assert.equal("bar", b.getValFunctor());
1469
b.setValFunctor("baz");
1470
1471
assert.equal("baz", b.getValFunction());
1472
1473
b.delete();
1474
});
1475
1476
test("can't call methods on deleted class instances", function() {
1477
var c = new cm.ValHolder(undefined);
1478
c.delete();
1479
assert.throws(cm.BindingError, function() {
1480
c.getVal();
1481
});
1482
assert.throws(cm.BindingError, function() {
1483
c.delete();
1484
});
1485
});
1486
1487
test("calling constructor without new raises BindingError", function() {
1488
var e = assert.throws(cm.BindingError, function() {
1489
cm.ValHolder(undefined);
1490
});
1491
assert.equal("Use 'new' to construct ValHolder", e.message);
1492
});
1493
1494
test("can return class instances by value", function() {
1495
var c = cm.emval_test_return_ValHolder();
1496
assert.deepEqual({}, c.getVal());
1497
c.delete();
1498
});
1499
1500
test("can pass class instances to functions by reference", function() {
1501
var a = {a:1};
1502
var c = new cm.ValHolder(a);
1503
cm.emval_test_set_ValHolder_to_empty_object(c);
1504
assert.deepEqual({}, c.getVal());
1505
c.delete();
1506
});
1507
1508
test("can pass smart pointer by reference", function() {
1509
var base = cm.embind_test_return_smart_base_ptr();
1510
var name = cm.embind_test_get_class_name_via_reference_to_smart_base_ptr(base);
1511
assert.equal("Base", name);
1512
base.delete();
1513
});
1514
1515
test("can pass smart pointer by value", function() {
1516
var base = cm.embind_test_return_smart_base_ptr();
1517
var name = cm.embind_test_get_class_name_via_smart_base_ptr(base);
1518
assert.equal("Base", name);
1519
base.delete();
1520
});
1521
1522
// todo: fix this
1523
// This test does not work because we make no provision for argument values
1524
// having been changed after returning from a C++ routine invocation. In
1525
// this specific case, the original pointee of the smart pointer was
1526
// freed and replaced by a new one, but the ptr in our local handle
1527
// was never updated after returning from the call.
1528
test("can modify smart pointers passed by reference", function() {
1529
// var base = cm.embind_test_return_smart_base_ptr();
1530
// cm.embind_modify_smart_pointer_passed_by_reference(base);
1531
// assert.equal("Changed", base.getClassName());
1532
// base.delete();
1533
});
1534
1535
test("can not modify smart pointers passed by value", function() {
1536
var base = cm.embind_test_return_smart_base_ptr();
1537
cm.embind_attempt_to_modify_smart_pointer_when_passed_by_value(base);
1538
assert.equal("Base", base.getClassName());
1539
base.delete();
1540
});
1541
1542
test("const return value", function() {
1543
var c = new cm.ValHolder("foo");
1544
assert.equal("foo", c.getConstVal());
1545
c.delete();
1546
});
1547
1548
test("return object by const ref", function() {
1549
var c = new cm.ValHolder("foo");
1550
assert.equal("foo", c.getValConstRef());
1551
c.delete();
1552
});
1553
1554
test("instanceof", function() {
1555
var c = new cm.ValHolder("foo");
1556
assert.instanceof(c, cm.ValHolder);
1557
c.delete();
1558
});
1559
1560
test("can access struct fields", function() {
1561
var c = new cm.CustomStruct();
1562
assert.equal(10, c.field);
1563
assert.equal(10, c.getField());
1564
c.delete();
1565
});
1566
1567
test("can set struct fields", function() {
1568
var c = new cm.CustomStruct();
1569
c.field = 15;
1570
assert.equal(15, c.field);
1571
c.delete();
1572
});
1573
1574
test("assignment returns value", function() {
1575
var c = new cm.CustomStruct();
1576
assert.equal(15, c.field = 15);
1577
c.delete();
1578
});
1579
1580
if (cm.getCompilerSetting('ASSERTIONS')) {
1581
test("assigning string or object to integer raises TypeError with assertions", function() {
1582
var c = new cm.CustomStruct();
1583
var e = assert.throws(TypeError, function() {
1584
c.field = "hi";
1585
});
1586
assert.equal('Cannot convert "hi" to int', e.message);
1587
1588
var e = assert.throws(TypeError, function() {
1589
c.field = {foo:'bar'};
1590
});
1591
assert.equal('Cannot convert "[object Object]" to int', e.message);
1592
1593
c.delete();
1594
});
1595
} else {
1596
test("assigning string or object to integer is converted to 0", function() {
1597
var c = new cm.CustomStruct();
1598
1599
c.field = "hi";
1600
assert.equal(0, c.field);
1601
c.field = {foo:'bar'};
1602
assert.equal(0, c.field);
1603
1604
c.delete();
1605
});
1606
}
1607
1608
test("can return tuples by value", function() {
1609
var c = cm.emval_test_return_TupleVector();
1610
assert.deepEqual([1, 2, 3, 4], c);
1611
});
1612
1613
test("tuples can contain tuples", function() {
1614
var c = cm.emval_test_return_TupleVectorTuple();
1615
assert.deepEqual([[1, 2, 3, 4]], c);
1616
});
1617
1618
test("can pass tuples by value", function() {
1619
var c = cm.emval_test_take_and_return_TupleVector([4, 5, 6, 7]);
1620
assert.deepEqual([4, 5, 6, 7], c);
1621
});
1622
1623
test("can return structs by value", function() {
1624
var c = cm.emval_test_return_StructVector();
1625
assert.deepEqual({x: 1, y: 2, z: 3, w: 4}, c);
1626
});
1627
1628
test("can pass structs by value", function() {
1629
var c = cm.emval_test_take_and_return_StructVector({x: 4, y: 5, z: 6, w: 7});
1630
assert.deepEqual({x: 4, y: 5, z: 6, w: 7}, c);
1631
});
1632
1633
test("can pass and return tuples in structs", function() {
1634
var d = cm.emval_test_take_and_return_TupleInStruct({field: [1, 2, 3, 4]});
1635
assert.deepEqual({field: [1, 2, 3, 4]}, d);
1636
});
1637
1638
test("can pass and return arrays in structs", function() {
1639
var d = cm.emval_test_take_and_return_ArrayInStruct({
1640
field1: [1, 2],
1641
field2: [
1642
{ x: 1, y: 2 },
1643
{ x: 3, y: 4 }
1644
]
1645
});
1646
assert.deepEqual({
1647
field1: [1, 2],
1648
field2: [
1649
{ x: 1, y: 2 },
1650
{ x: 3, y: 4 }
1651
]
1652
}, d);
1653
});
1654
1655
test("can clone handles", function() {
1656
var a = new cm.ValHolder({});
1657
assert.equal(1, cm.count_emval_handles());
1658
var b = a.clone();
1659
a.delete();
1660
1661
assert.equal(1, cm.count_emval_handles());
1662
1663
assert.throws(cm.BindingError, function() {
1664
a.delete();
1665
});
1666
b.delete();
1667
1668
assert.equal(0, cm.count_emval_handles());
1669
});
1670
1671
test("A shared pointer set/get point to the same underlying pointer", function() {
1672
var a = new cm.SharedPtrHolder();
1673
var b = a.get();
1674
1675
a.set(b);
1676
var c = a.get();
1677
1678
assert.true(b.isAliasOf(c));
1679
b.delete();
1680
c.delete();
1681
a.delete();
1682
});
1683
1684
test("can return shared ptrs from instance methods", function() {
1685
var a = new cm.SharedPtrHolder();
1686
1687
// returns the shared_ptr.
1688
var b = a.get();
1689
1690
assert.equal("a string", b.get());
1691
b.delete();
1692
a.delete();
1693
});
1694
1695
test("smart ptrs clone correctly", function() {
1696
assert.equal(0, cm.count_emval_handles());
1697
1698
var a = cm.emval_test_return_shared_ptr();
1699
1700
var b = a.clone();
1701
a.delete();
1702
1703
assert.equal(1, cm.count_emval_handles());
1704
1705
assert.throws(cm.BindingError, function() {
1706
a.delete();
1707
});
1708
b.delete();
1709
1710
assert.equal(0, cm.count_emval_handles());
1711
});
1712
1713
test("can't clone if already deleted", function() {
1714
var a = new cm.ValHolder({});
1715
a.delete();
1716
assert.throws(cm.BindingError, function() {
1717
a.clone();
1718
});
1719
});
1720
1721
test("virtual calls work correctly", function() {
1722
var derived = cm.embind_test_return_raw_polymorphic_derived_ptr_as_base();
1723
assert.equal("PolyDerived", derived.virtualGetClassName());
1724
derived.delete();
1725
});
1726
1727
test("virtual calls work correctly on smart ptrs", function() {
1728
var derived = cm.embind_test_return_smart_polymorphic_derived_ptr_as_base();
1729
assert.equal("PolyDerived", derived.virtualGetClassName());
1730
derived.delete();
1731
});
1732
1733
test("Empty smart ptr is null", function() {
1734
var a = cm.emval_test_return_empty_shared_ptr();
1735
assert.equal(null, a);
1736
});
1737
1738
test("string cannot be given as smart pointer argument", function() {
1739
assert.throws(cm.BindingError, function() {
1740
cm.emval_test_is_shared_ptr_null("hello world");
1741
});
1742
});
1743
1744
test("number cannot be given as smart pointer argument", function() {
1745
assert.throws(cm.BindingError, function() {
1746
cm.emval_test_is_shared_ptr_null(105);
1747
});
1748
});
1749
1750
test("raw pointer cannot be given as smart pointer argument", function() {
1751
var p = new cm.ValHolder({});
1752
assert.throws(cm.BindingError, function() { cm.emval_test_is_shared_ptr_null(p); });
1753
p.delete();
1754
});
1755
1756
test("null is passed as empty smart pointer", function() {
1757
assert.true(cm.emval_test_is_shared_ptr_null(null));
1758
});
1759
1760
test("Deleting already deleted smart ptrs fails", function() {
1761
var a = cm.emval_test_return_shared_ptr();
1762
a.delete();
1763
assert.throws(cm.BindingError, function() {
1764
a.delete();
1765
});
1766
});
1767
1768
test("returned unique_ptr does not call destructor", function() {
1769
var logged = "";
1770
var c = new cm.emval_test_return_unique_ptr_lifetime(function (s) { logged += s; });
1771
assert.equal("(constructor)", logged);
1772
c.delete();
1773
});
1774
1775
test("returned unique_ptr calls destructor on delete", function() {
1776
var logged = "";
1777
var c = new cm.emval_test_return_unique_ptr_lifetime(function (s) { logged += s; });
1778
logged = "";
1779
c.delete();
1780
assert.equal("(destructor)", logged);
1781
});
1782
1783
test("StringHolder", function() {
1784
var a = new cm.StringHolder("foobar");
1785
assert.equal("foobar", a.get());
1786
1787
a.set("barfoo");
1788
assert.equal("barfoo", a.get());
1789
1790
assert.equal("barfoo", a.get_const_ref());
1791
1792
a.delete();
1793
});
1794
1795
test("can call methods on unique ptr", function() {
1796
var result = cm.emval_test_return_unique_ptr();
1797
1798
result.setVal('1234');
1799
assert.equal('1234', result.getVal());
1800
result.delete();
1801
});
1802
1803
test("can call methods on shared ptr", function(){
1804
var result = cm.emval_test_return_shared_ptr();
1805
result.setVal('1234');
1806
1807
assert.equal('1234', result.getVal());
1808
result.delete();
1809
});
1810
1811
test("Non functors throw exception", function() {
1812
var a = {foo: 'bar'};
1813
var c = new cm.ValHolder(a);
1814
assert.throws(TypeError, function() {
1815
c();
1816
});
1817
c.delete();
1818
});
1819
1820
test("non-member methods", function() {
1821
var a = {foo: 'bar'};
1822
var c = new cm.ValHolder(a);
1823
c.setEmpty(); // non-member method
1824
assert.deepEqual({}, c.getValNonMember());
1825
c.delete();
1826
});
1827
1828
test("instantiating class without constructor gives error", function() {
1829
var e = assert.throws(cm.BindingError, function() {
1830
cm.AbstractClass();
1831
});
1832
assert.equal("Use 'new' to construct AbstractClass", e.message);
1833
1834
var e = assert.throws(cm.BindingError, function() {
1835
new cm.AbstractClass();
1836
});
1837
assert.equal("AbstractClass has no accessible constructor", e.message);
1838
});
1839
1840
test("can construct class with external constructor with custom signature", function() {
1841
const valHolder = new cm.ValHolder(1,2);
1842
assert.equal(valHolder.getVal(), 3);
1843
});
1844
1845
test("can construct class with external constructor", function() {
1846
var e = new cm.HasExternalConstructor("foo");
1847
assert.instanceof(e, cm.HasExternalConstructor);
1848
assert.equal("foo", e.getString());
1849
e.delete();
1850
});
1851
1852
test("can construct class with external constructor with no copy constructor", function() {
1853
var e = new cm.HasExternalConstructorNoCopy(42);
1854
assert.instanceof(e, cm.HasExternalConstructorNoCopy);
1855
assert.equal(42, e.getInt());
1856
e.delete();
1857
});
1858
});
1859
1860
BaseFixture.extend("const", function() {
1861
test("calling non-const method with const handle is error", function() {
1862
var vh = cm.ValHolder.makeConst({});
1863
var e = assert.throws(cm.BindingError, function() {
1864
vh.setVal({});
1865
});
1866
assert.equal('Cannot convert argument of type ValHolder const* to parameter type ValHolder*', e.message);
1867
vh.delete();
1868
});
1869
1870
test("passing const pointer to non-const pointer is error", function() {
1871
var vh = new cm.ValHolder.makeConst({});
1872
var e = assert.throws(cm.BindingError, function() {
1873
cm.ValHolder.set_via_raw_pointer(vh, {});
1874
});
1875
assert.equal('Cannot convert argument of type ValHolder const* to parameter type ValHolder*', e.message);
1876
vh.delete();
1877
});
1878
});
1879
1880
BaseFixture.extend("smart pointers", function() {
1881
test("constructor can return smart pointer", function() {
1882
var e = new cm.HeldBySmartPtr(10, "foo");
1883
assert.instanceof(e, cm.HeldBySmartPtr);
1884
assert.equal(10, e.i);
1885
assert.equal("foo", e.s);
1886
var f = cm.takesHeldBySmartPtr(e);
1887
f.delete();
1888
e.delete();
1889
});
1890
1891
test("cannot pass incorrect smart pointer type", function() {
1892
var e = cm.emval_test_return_shared_ptr();
1893
assert.throws(cm.BindingError, function() {
1894
cm.takesHeldBySmartPtr(e);
1895
});
1896
e.delete();
1897
});
1898
1899
test("smart pointer object has no object keys", function() {
1900
var e = new cm.HeldBySmartPtr(10, "foo");
1901
assert.deepEqual([], Object.keys(e));
1902
1903
var f = e.clone();
1904
e.delete();
1905
1906
assert.deepEqual([], Object.keys(f));
1907
f.delete();
1908
});
1909
1910
test("smart pointer object has correct constructor name", function() {
1911
var e = new cm.HeldBySmartPtr(10, "foo");
1912
assert.equal("HeldBySmartPtr", e.constructor.name);
1913
e.delete();
1914
});
1915
1916
test("constructor can return smart pointer", function() {
1917
var e = new cm.HeldBySmartPtr(10, "foo");
1918
assert.instanceof(e, cm.HeldBySmartPtr);
1919
assert.equal(10, e.i);
1920
assert.equal("foo", e.s);
1921
var f = cm.takesHeldBySmartPtr(e);
1922
assert.instanceof(f, cm.HeldBySmartPtr);
1923
f.delete();
1924
e.delete();
1925
});
1926
1927
test("custom smart pointer", function() {
1928
var e = new cm.HeldByCustomSmartPtr(20, "bar");
1929
assert.instanceof(e, cm.HeldByCustomSmartPtr);
1930
assert.equal(20, e.i);
1931
assert.equal("bar", e.s);
1932
e.delete();
1933
});
1934
1935
test("custom smart pointer passed through wiretype", function() {
1936
var e = new cm.HeldByCustomSmartPtr(20, "bar");
1937
var f = cm.passThroughCustomSmartPtr(e);
1938
e.delete();
1939
1940
assert.instanceof(f, cm.HeldByCustomSmartPtr);
1941
assert.equal(20, f.i);
1942
assert.equal("bar", f.s);
1943
1944
f.delete();
1945
});
1946
1947
test("cannot give null to by-value argument", function() {
1948
var e = assert.throws(cm.BindingError, function() {
1949
cm.takesHeldBySmartPtr(null);
1950
});
1951
assert.equal('null is not a valid HeldBySmartPtr', e.message);
1952
});
1953
1954
test("raw pointer can take and give null", function() {
1955
assert.equal(null, cm.passThroughRawPtr(null));
1956
});
1957
1958
test("custom smart pointer can take and give null", function() {
1959
assert.equal(null, cm.passThroughCustomSmartPtr(null));
1960
});
1961
1962
test("cannot pass shared_ptr to CustomSmartPtr", function() {
1963
var o = cm.HeldByCustomSmartPtr.createSharedPtr(10, "foo");
1964
var e = assert.throws(cm.BindingError, function() {
1965
cm.passThroughCustomSmartPtr(o);
1966
});
1967
assert.equal('Cannot convert argument of type shared_ptr<HeldByCustomSmartPtr> to parameter type CustomSmartPtr<HeldByCustomSmartPtr>', e.message);
1968
o.delete();
1969
});
1970
1971
test("custom smart pointers can be passed to shared_ptr parameter", function() {
1972
var e = cm.HeldBySmartPtr.newCustomPtr(10, "abc");
1973
assert.equal(10, e.i);
1974
assert.equal("abc", e.s);
1975
1976
cm.takesHeldBySmartPtrSharedPtr(e).delete();
1977
e.delete();
1978
});
1979
1980
test("can call non-member functions as methods", function() {
1981
var e = new cm.HeldBySmartPtr(20, "bar");
1982
var f = e.returnThis();
1983
e.delete();
1984
assert.equal(20, f.i);
1985
assert.equal("bar", f.s);
1986
f.delete();
1987
});
1988
});
1989
1990
BaseFixture.extend("enumerations", function() {
1991
test("can compare enumeration values", function() {
1992
assert.equal(cm.Enum.ONE, cm.Enum.ONE);
1993
assert.notEqual(cm.Enum.ONE, cm.Enum.TWO);
1994
});
1995
1996
if (typeof INVOKED_FROM_EMSCRIPTEN_TEST_RUNNER === "undefined") { // TODO: Enable this to work in Emscripten runner as well!
1997
test("repr includes enum value", function() {
1998
assert.equal('<#Enum_ONE {}>', IMVU.repr(cm.Enum.ONE));
1999
assert.equal('<#Enum_TWO {}>', IMVU.repr(cm.Enum.TWO));
2000
});
2001
}
2002
2003
test("instanceof", function() {
2004
assert.instanceof(cm.Enum.ONE, cm.Enum);
2005
});
2006
2007
test("can pass and return enumeration values to functions", function() {
2008
assert.equal(cm.Enum.TWO, cm.emval_test_take_and_return_Enum(cm.Enum.TWO));
2009
});
2010
});
2011
2012
BaseFixture.extend("C++11 enum class", function() {
2013
test("can compare enumeration values", function() {
2014
assert.equal(cm.EnumClass.ONE, cm.EnumClass.ONE);
2015
assert.notEqual(cm.EnumClass.ONE, cm.EnumClass.TWO);
2016
});
2017
2018
if (typeof INVOKED_FROM_EMSCRIPTEN_TEST_RUNNER === "undefined") { // TODO: Enable this to work in Emscripten runner as well!
2019
test("repr includes enum value", function() {
2020
assert.equal('<#EnumClass_ONE {}>', IMVU.repr(cm.EnumClass.ONE));
2021
assert.equal('<#EnumClass_TWO {}>', IMVU.repr(cm.EnumClass.TWO));
2022
});
2023
}
2024
2025
test("instanceof", function() {
2026
assert.instanceof(cm.EnumClass.ONE, cm.EnumClass);
2027
});
2028
2029
test("can pass and return enumeration values to functions", function() {
2030
assert.equal(cm.EnumClass.TWO, cm.emval_test_take_and_return_EnumClass(cm.EnumClass.TWO));
2031
});
2032
});
2033
2034
BaseFixture.extend("emval call tests", function() {
2035
test("can call functions from C++", function() {
2036
var called = false;
2037
cm.emval_test_call_function(function(i, f, tv, sv) {
2038
called = true;
2039
assert.equal(10, i);
2040
assert.equal(1.5, f);
2041
assert.deepEqual([1.25, 2.5, 3.75, 4], tv);
2042
assert.deepEqual({x: 1.25, y: 2.5, z: 3.75, w:4}, sv);
2043
}, 10, 1.5, [1.25, 2.5, 3.75, 4], {x: 1.25, y: 2.5, z: 3.75, w:4});
2044
assert.true(called);
2045
});
2046
});
2047
2048
BaseFixture.extend("extending built-in classes", function() {
2049
// cm.ValHolder.prototype.patched = 10; // this sets instanceCounts.patched inside of Deletable module !?!
2050
2051
test("can access patched value on new instances", function() {
2052
cm.ValHolder.prototype.patched = 10;
2053
var c = new cm.ValHolder(undefined);
2054
assert.equal(10, c.patched);
2055
c.delete();
2056
cm.ValHolder.prototype.patched = undefined;
2057
});
2058
2059
test("can access patched value on returned instances", function() {
2060
cm.ValHolder.prototype.patched = 10;
2061
var c = cm.emval_test_return_ValHolder();
2062
assert.equal(10, c.patched);
2063
c.delete();
2064
cm.ValHolder.prototype.patched = undefined;
2065
});
2066
});
2067
2068
BaseFixture.extend("raw pointers", function() {
2069
test("can pass raw pointers into functions if explicitly allowed", function() {
2070
var vh = new cm.ValHolder({});
2071
cm.ValHolder.set_via_raw_pointer(vh, 10);
2072
assert.equal(10, cm.ValHolder.get_via_raw_pointer(vh));
2073
vh.delete();
2074
});
2075
2076
test("can return raw pointers from functions if explicitly allowed", function() {
2077
var p = cm.embind_test_return_raw_base_ptr();
2078
assert.equal("Base", p.getClassName());
2079
p.delete();
2080
});
2081
2082
test("can pass multiple raw pointers to functions", function() {
2083
var target = new cm.ValHolder(undefined);
2084
var source = new cm.ValHolder("hi");
2085
cm.ValHolder.transfer_via_raw_pointer(target, source);
2086
assert.equal("hi", target.getVal());
2087
target.delete();
2088
source.delete();
2089
});
2090
});
2091
2092
BaseFixture.extend("implementing abstract methods with JS objects", function() {
2093
test("can call abstract methods", function() {
2094
var obj = cm.getAbstractClass();
2095
assert.equal("from concrete", obj.abstractMethod());
2096
obj.delete();
2097
});
2098
2099
test("can implement abstract methods in JavaScript", function() {
2100
var expected = "my JS string";
2101
function MyImplementation() {
2102
this.rv = expected;
2103
}
2104
MyImplementation.prototype.abstractMethod = function() {
2105
return this.rv;
2106
};
2107
2108
var impl = cm.AbstractClass.implement(new MyImplementation);
2109
assert.equal(expected, impl.abstractMethod());
2110
assert.equal(expected, cm.callAbstractMethod(impl));
2111
impl.delete();
2112
});
2113
2114
test("can implement optional methods in JavaScript", function() {
2115
var expected = "my JS string";
2116
function MyImplementation() {
2117
this.rv = expected;
2118
}
2119
MyImplementation.prototype.optionalMethod = function() {
2120
return this.rv;
2121
};
2122
2123
var impl = cm.AbstractClass.implement(new MyImplementation);
2124
assert.equal(expected, cm.callOptionalMethod(impl, expected));
2125
impl.delete();
2126
});
2127
2128
test("if not implemented then optional method runs default", function() {
2129
var impl = cm.AbstractClass.implement({});
2130
assert.equal("optionalfoo", impl.optionalMethod("foo"));
2131
impl.delete();
2132
});
2133
2134
test("returning null shared pointer from interfaces implemented in JS code does not leak", function() {
2135
var impl = cm.AbstractClass.implement({
2136
returnsSharedPtr: function() {
2137
return null;
2138
}
2139
});
2140
cm.callReturnsSharedPtrMethod(impl);
2141
impl.delete();
2142
// Let the memory leak test superfixture check that no leaks occurred.
2143
});
2144
2145
test("returning a new shared pointer from interfaces implemented in JS code does not leak", function() {
2146
var impl = cm.AbstractClass.implement({
2147
returnsSharedPtr: function() {
2148
return cm.embind_test_return_smart_derived_ptr().deleteLater();
2149
}
2150
});
2151
cm.callReturnsSharedPtrMethod(impl);
2152
impl.delete();
2153
// Let the memory leak test superfixture check that no leaks occurred.
2154
});
2155
2156
test("void methods work", function() {
2157
var saved = {};
2158
var impl = cm.AbstractClass.implement({
2159
differentArguments: function(i, d, f, q, s) {
2160
saved.i = i;
2161
saved.d = d;
2162
saved.f = f;
2163
saved.q = q;
2164
saved.s = s;
2165
}
2166
});
2167
2168
cm.callDifferentArguments(impl, 1, 2, 3, 4, "foo");
2169
2170
assert.deepEqual(saved, {
2171
i: 1,
2172
d: 2,
2173
f: 3,
2174
q: 4,
2175
s: "foo",
2176
});
2177
2178
impl.delete();
2179
});
2180
2181
test("returning a cached new shared pointer from interfaces implemented in JS code does not leak", function() {
2182
var derived = cm.embind_test_return_smart_derived_ptr();
2183
var impl = cm.AbstractClass.implement({
2184
returnsSharedPtr: function() {
2185
return derived;
2186
}
2187
});
2188
cm.callReturnsSharedPtrMethod(impl);
2189
impl.delete();
2190
derived.delete();
2191
// Let the memory leak test superfixture check that no leaks occurred.
2192
});
2193
});
2194
2195
BaseFixture.extend("constructor prototype class inheritance", function() {
2196
var Empty = cm.AbstractClass.extend("Empty", {
2197
abstractMethod: function() {
2198
}
2199
});
2200
2201
test("can extend, construct, and delete", function() {
2202
var instance = new Empty;
2203
instance.delete();
2204
});
2205
2206
test("properties set in constructor are externally visible", function() {
2207
var HasProperty = cm.AbstractClass.extend("HasProperty", {
2208
__construct: function(x) {
2209
this.__parent.__construct.call(this);
2210
this.property = x;
2211
},
2212
abstractMethod: function() {
2213
}
2214
});
2215
var instance = new HasProperty(10);
2216
assert.equal(10, instance.property);
2217
instance.delete();
2218
});
2219
2220
test("pass derived object to c++", function() {
2221
var Implementation = cm.AbstractClass.extend("Implementation", {
2222
abstractMethod: function() {
2223
return "abc";
2224
},
2225
});
2226
var instance = new Implementation;
2227
var result = cm.callAbstractMethod(instance);
2228
instance.delete();
2229
assert.equal("abc", result);
2230
});
2231
2232
test("properties set in constructor are visible in overridden methods", function() {
2233
var HasProperty = cm.AbstractClass.extend("HasProperty", {
2234
__construct: function(x) {
2235
this.__parent.__construct.call(this);
2236
this.x = x;
2237
},
2238
abstractMethod: function() {
2239
return this.x;
2240
},
2241
});
2242
var instance = new HasProperty("xyz");
2243
var result = cm.callAbstractMethod(instance);
2244
instance.delete();
2245
assert.equal("xyz", result);
2246
});
2247
2248
test("interface methods are externally visible", function() {
2249
var instance = new Empty;
2250
var result = instance.concreteMethod();
2251
instance.delete();
2252
assert.equal("concrete", result);
2253
});
2254
2255
test("optional methods are externally visible", function() {
2256
var instance = new Empty;
2257
var result = instance.optionalMethod("_123");
2258
instance.delete();
2259
assert.equal("optional_123", result);
2260
});
2261
2262
test("optional methods: not defined", function() {
2263
var instance = new Empty;
2264
var result = cm.callOptionalMethod(instance, "_123");
2265
instance.delete();
2266
assert.equal("optional_123", result);
2267
});
2268
2269
// Calling C++ implementations of optional functions can be
2270
// made to work, but requires an interface change on the C++
2271
// side, using a technique similar to the one described at
2272
// https://wiki.python.org/moin/boost.python/OverridableVirtualFunctions
2273
//
2274
// The issue is that, in a standard binding, calling
2275
// parent.prototype.optionalMethod invokes the wrapper
2276
// function, which checks that the JS object implements
2277
// 'optionalMethod', which it does. Thus, C++ calls back into
2278
// JS, resulting in an infinite loop.
2279
//
2280
// The solution, for optional methods, is to bind a special
2281
// concrete implementation that specifically calls the base
2282
// class's implementation. See the binding of
2283
// AbstractClass::optionalMethod in embind_test.cpp.
2284
2285
test("can call parent implementation from within derived implementation", function() {
2286
var parent = cm.AbstractClass;
2287
var ExtendsOptionalMethod = parent.extend("ExtendsOptionalMethod", {
2288
abstractMethod: function() {
2289
},
2290
optionalMethod: function(s) {
2291
return "optionaljs_" + parent.prototype.optionalMethod.call(this, s);
2292
},
2293
});
2294
var instance = new ExtendsOptionalMethod;
2295
var result = cm.callOptionalMethod(instance, "_123");
2296
instance.delete();
2297
assert.equal("optionaljs_optional_123", result);
2298
});
2299
2300
test("instanceof", function() {
2301
var instance = new Empty;
2302
assert.instanceof(instance, Empty);
2303
assert.instanceof(instance, cm.AbstractClass);
2304
instance.delete();
2305
});
2306
2307
test("returning null shared pointer from interfaces implemented in JS code does not leak", function() {
2308
var C = cm.AbstractClass.extend("C", {
2309
abstractMethod: function() {
2310
},
2311
returnsSharedPtr: function() {
2312
return null;
2313
}
2314
});
2315
var impl = new C;
2316
cm.callReturnsSharedPtrMethod(impl);
2317
impl.delete();
2318
// Let the memory leak test superfixture check that no leaks occurred.
2319
});
2320
2321
test("returning a new shared pointer from interfaces implemented in JS code does not leak", function() {
2322
var C = cm.AbstractClass.extend("C", {
2323
abstractMethod: function() {
2324
},
2325
returnsSharedPtr: function() {
2326
return cm.embind_test_return_smart_derived_ptr().deleteLater();
2327
}
2328
});
2329
var impl = new C;
2330
cm.callReturnsSharedPtrMethod(impl);
2331
impl.delete();
2332
// Let the memory leak test superfixture check that no leaks occurred.
2333
});
2334
2335
test("void methods work", function() {
2336
var saved = {};
2337
var C = cm.AbstractClass.extend("C", {
2338
abstractMethod: function() {
2339
},
2340
differentArguments: function(i, d, f, q, s) {
2341
saved.i = i;
2342
saved.d = d;
2343
saved.f = f;
2344
saved.q = q;
2345
saved.s = s;
2346
}
2347
});
2348
var impl = new C;
2349
2350
cm.callDifferentArguments(impl, 1, 2, 3, 4, "foo");
2351
2352
assert.deepEqual(saved, {
2353
i: 1,
2354
d: 2,
2355
f: 3,
2356
q: 4,
2357
s: "foo",
2358
});
2359
2360
impl.delete();
2361
});
2362
2363
test("returning a cached new shared pointer from interfaces implemented in JS code does not leak", function() {
2364
var derived = cm.embind_test_return_smart_derived_ptr();
2365
var C = cm.AbstractClass.extend("C", {
2366
abstractMethod: function() {
2367
},
2368
returnsSharedPtr: function() {
2369
return derived;
2370
}
2371
});
2372
var impl = new C;
2373
cm.callReturnsSharedPtrMethod(impl);
2374
impl.delete();
2375
derived.delete();
2376
// Let the memory leak test superfixture check that no leaks occurred.
2377
});
2378
2379
test("calling pure virtual function gives good error message", function() {
2380
var C = cm.AbstractClass.extend("C", {});
2381
var error = assert.throws(cm.PureVirtualError, function() {
2382
new C;
2383
});
2384
assert.equal('Pure virtual function abstractMethod must be implemented in JavaScript', error.message);
2385
});
2386
2387
test("can extend from C++ class with constructor arguments", function() {
2388
var parent = cm.AbstractClassWithConstructor;
2389
var C = parent.extend("C", {
2390
__construct: function(x) {
2391
this.__parent.__construct.call(this, x);
2392
},
2393
abstractMethod: function() {
2394
return this.concreteMethod();
2395
}
2396
});
2397
2398
var impl = new C("hi");
2399
var rv = cm.callAbstractMethod2(impl);
2400
impl.delete();
2401
2402
assert.equal("hi", rv);
2403
});
2404
2405
test("__destruct is called when object is destroyed", function() {
2406
var parent = cm.HeldAbstractClass;
2407
var calls = [];
2408
var C = parent.extend("C", {
2409
method: function() {
2410
},
2411
__destruct: function() {
2412
calls.push("__destruct");
2413
this.__parent.__destruct.call(this);
2414
}
2415
});
2416
var impl = new C;
2417
var copy = impl.clone();
2418
impl.delete();
2419
assert.deepEqual([], calls);
2420
copy.delete();
2421
assert.deepEqual(["__destruct"], calls);
2422
});
2423
2424
test("if JavaScript implementation of interface is returned, don't wrap in new handle", function() {
2425
var parent = cm.HeldAbstractClass;
2426
var C = parent.extend("C", {
2427
method: function() {
2428
}
2429
});
2430
var impl = new C;
2431
var rv = cm.passHeldAbstractClass(impl);
2432
impl.delete();
2433
assert.equal(impl, rv);
2434
rv.delete();
2435
});
2436
2437
test("can instantiate two wrappers with constructors", function() {
2438
var parent = cm.HeldAbstractClass;
2439
var C = parent.extend("C", {
2440
__construct: function() {
2441
this.__parent.__construct.call(this);
2442
},
2443
method: function() {
2444
}
2445
});
2446
var a = new C;
2447
var b = new C;
2448
a.delete();
2449
b.delete();
2450
});
2451
2452
test("incorrectly calling parent is an error", function() {
2453
var parent = cm.HeldAbstractClass;
2454
var C = parent.extend("C", {
2455
__construct: function() {
2456
this.__parent.__construct();
2457
},
2458
method: function() {
2459
}
2460
});
2461
assert.throws(cm.BindingError, function() {
2462
new C;
2463
});
2464
});
2465
2466
test("deleteLater() works for JavaScript implementations", function() {
2467
var parent = cm.HeldAbstractClass;
2468
var C = parent.extend("C", {
2469
method: function() {
2470
}
2471
});
2472
var impl = new C;
2473
var rv = cm.passHeldAbstractClass(impl);
2474
impl.deleteLater();
2475
rv.deleteLater();
2476
cm.flushPendingDeletes();
2477
});
2478
2479
test("deleteLater() combined with delete() works for JavaScript implementations", function() {
2480
var parent = cm.HeldAbstractClass;
2481
var C = parent.extend("C", {
2482
method: function() {
2483
}
2484
});
2485
var impl = new C;
2486
var rv = cm.passHeldAbstractClass(impl);
2487
impl.deleteLater();
2488
rv.delete();
2489
cm.flushPendingDeletes();
2490
});
2491
2492
test("method arguments with pointer ownership semantics are cleaned up after call", function() {
2493
var parent = cm.AbstractClass;
2494
var C = parent.extend("C", {
2495
abstractMethod: function() {
2496
},
2497
});
2498
var impl = new C;
2499
cm.passShared(impl);
2500
impl.delete();
2501
});
2502
2503
test("method arguments with pointer ownership semantics can be cloned", function() {
2504
var parent = cm.AbstractClass;
2505
var owned;
2506
var C = parent.extend("C", {
2507
abstractMethod: function() {
2508
},
2509
passShared: function(p) {
2510
owned = p.clone();
2511
}
2512
});
2513
var impl = new C;
2514
cm.passShared(impl);
2515
impl.delete();
2516
2517
assert.equal("Derived", owned.getClassName());
2518
owned.delete();
2519
});
2520
2521
test("emscripten::val method arguments don't leak", function() {
2522
var parent = cm.AbstractClass;
2523
var got;
2524
var C = parent.extend("C", {
2525
abstractMethod: function() {
2526
},
2527
passVal: function(g) {
2528
got = g;
2529
}
2530
});
2531
var impl = new C;
2532
var v = {};
2533
cm.passVal(impl, v);
2534
impl.delete();
2535
2536
assert.equal(v, got);
2537
});
2538
});
2539
2540
BaseFixture.extend("registration order", function() {
2541
test("registration of tuple elements out of order leaves them in order", function() {
2542
var ot = cm.getOrderedTuple();
2543
assert.instanceof(ot[0], cm.FirstElement);
2544
assert.instanceof(ot[1], cm.SecondElement);
2545
ot[0].delete();
2546
ot[1].delete();
2547
});
2548
2549
test("registration of struct elements out of order", function() {
2550
var os = cm.getOrderedStruct();
2551
assert.instanceof(os.first, cm.FirstElement);
2552
assert.instanceof(os.second, cm.SecondElement);
2553
os.first.delete();
2554
os.second.delete();
2555
});
2556
});
2557
2558
if (typeof INVOKED_FROM_EMSCRIPTEN_TEST_RUNNER === "undefined") { // TODO: Enable this to work in Emscripten runner as well!
2559
2560
BaseFixture.extend("unbound types", function() {
2561
if (!cm.hasUnboundTypeNames) {
2562
return;
2563
}
2564
2565
function assertMessage(fn, message) {
2566
var e = assert.throws(cm.UnboundTypeError, fn);
2567
assert.equal(message, e.message);
2568
}
2569
2570
test("calling function with unbound types produces error", function() {
2571
assertMessage(
2572
function() {
2573
cm.getUnboundClass();
2574
},
2575
'Cannot call getUnboundClass due to unbound types: 12UnboundClass');
2576
});
2577
2578
test("unbound base class produces error", function() {
2579
assertMessage(
2580
function() {
2581
cm.getHasUnboundBase();
2582
},
2583
'Cannot call getHasUnboundBase due to unbound types: 12UnboundClass');
2584
});
2585
2586
test("construct of class with unbound base", function() {
2587
assertMessage(
2588
function() {
2589
new cm.HasUnboundBase;
2590
}, 'Cannot construct HasUnboundBase due to unbound types: 12UnboundClass');
2591
});
2592
2593
test("unbound constructor argument", function() {
2594
assertMessage(
2595
function() {
2596
new cm.HasConstructorUsingUnboundArgument(1);
2597
},
2598
'Cannot construct HasConstructorUsingUnboundArgument due to unbound types: 12UnboundClass');
2599
});
2600
2601
test("unbound constructor argument of class with unbound base", function() {
2602
assertMessage(
2603
function() {
2604
new cm.HasConstructorUsingUnboundArgumentAndUnboundBase;
2605
},
2606
'Cannot construct HasConstructorUsingUnboundArgumentAndUnboundBase due to unbound types: 18SecondUnboundClass');
2607
});
2608
2609
test('class function with unbound argument', function() {
2610
var x = new cm.BoundClass;
2611
assertMessage(
2612
function() {
2613
x.method();
2614
}, 'Cannot call BoundClass.method due to unbound types: 12UnboundClass');
2615
x.delete();
2616
});
2617
2618
test('class class function with unbound argument', function() {
2619
assertMessage(
2620
function() {
2621
cm.BoundClass.classfunction();
2622
}, 'Cannot call BoundClass.classfunction due to unbound types: 12UnboundClass');
2623
});
2624
2625
test('class property of unbound type', function() {
2626
var x = new cm.BoundClass;
2627
var y;
2628
assertMessage(
2629
function() {
2630
y = x.property;
2631
}, 'Cannot access BoundClass.property due to unbound types: 12UnboundClass');
2632
assertMessage(
2633
function() {
2634
x.property = 10;
2635
}, 'Cannot access BoundClass.property due to unbound types: 12UnboundClass');
2636
x.delete();
2637
});
2638
2639
// todo: tuple elements
2640
// todo: tuple element accessors
2641
// todo: struct fields
2642
});
2643
2644
}
2645
2646
BaseFixture.extend("noncopyable", function() {
2647
test('can call method on noncopyable object', function() {
2648
var x = new cm.Noncopyable;
2649
assert.equal('foo', x.method());
2650
x.delete();
2651
});
2652
});
2653
2654
BaseFixture.extend("function names", function() {
2655
assert.equal('ValHolder', cm.ValHolder.name);
2656
2657
assert.equal('ValHolder.setVal', cm.ValHolder.prototype.setVal.name);
2658
assert.equal('ValHolder.makeConst', cm.ValHolder.makeConst.name);
2659
});
2660
2661
BaseFixture.extend("constants", function() {
2662
assert.equal(10, cm.INT_CONSTANT);
2663
2664
assert.equal(1, cm.STATIC_CONST_INTEGER_VALUE_1);
2665
assert.equal(1000, cm.STATIC_CONST_INTEGER_VALUE_1000);
2666
2667
assert.equal("some string", cm.STRING_CONSTANT);
2668
assert.deepEqual([1, 2, 3, 4], cm.VALUE_ARRAY_CONSTANT);
2669
assert.deepEqual({x:1,y:2,z:3,w:4}, cm.VALUE_OBJECT_CONSTANT);
2670
});
2671
2672
BaseFixture.extend("object handle comparison", function() {
2673
var e = new cm.ValHolder("foo");
2674
var f = new cm.ValHolder("foo");
2675
assert.false(e.isAliasOf(undefined));
2676
assert.false(e.isAliasOf(10));
2677
assert.true(e.isAliasOf(e));
2678
assert.false(e.isAliasOf(f));
2679
assert.false(f.isAliasOf(e));
2680
e.delete();
2681
f.delete();
2682
});
2683
2684
BaseFixture.extend("derived-with-offset types compare with base", function() {
2685
var e = new cm.DerivedWithOffset;
2686
var f = cm.return_Base_from_DerivedWithOffset(e);
2687
assert.true(e.isAliasOf(f));
2688
assert.true(f.isAliasOf(e));
2689
e.delete();
2690
f.delete();
2691
});
2692
2693
BaseFixture.extend("memory view", function() {
2694
test("can pass memory view from C++ to JS", function() {
2695
var views = [];
2696
cm.callWithMemoryView(function(view) {
2697
views.push(view);
2698
});
2699
assert.equal(3, views.length);
2700
2701
assert.instanceof(views[0], Uint8Array);
2702
assert.equal(8, views[0].length);
2703
assert.deepEqual([0, 1, 2, 3, 4, 5, 6, 7], [].slice.call(new Uint8Array(views[0])));
2704
2705
assert.instanceof(views[1], Float32Array);
2706
assert.equal(4, views[1].length);
2707
assert.deepEqual([1.5, 2.5, 3.5, 4.5], [].slice.call(views[1]));
2708
2709
assert.instanceof(views[2], Int16Array);
2710
assert.equal(4, views[2].length);
2711
assert.deepEqual([1000, 100, 10, 1], [].slice.call(views[2]));
2712
});
2713
});
2714
2715
BaseFixture.extend("delete pool", function() {
2716
test("can delete objects later", function() {
2717
var v = new cm.ValHolder({});
2718
v.deleteLater();
2719
assert.deepEqual({}, v.getVal());
2720
cm.flushPendingDeletes();
2721
assert.throws(cm.BindingError, function() {
2722
v.getVal();
2723
});
2724
});
2725
2726
test("calling deleteLater twice is an error", function() {
2727
var v = new cm.ValHolder({});
2728
v.deleteLater();
2729
assert.throws(cm.BindingError, function() {
2730
v.deleteLater();
2731
});
2732
});
2733
2734
test("can clone instances that have been scheduled for deletion", function() {
2735
var v = new cm.ValHolder({});
2736
v.deleteLater();
2737
var v2 = v.clone();
2738
v2.delete();
2739
});
2740
2741
test("deleteLater returns the object", function() {
2742
var v = (new cm.ValHolder({})).deleteLater();
2743
assert.deepEqual({}, v.getVal());
2744
});
2745
2746
test("deleteLater throws if object is already deleted", function() {
2747
var v = new cm.ValHolder({});
2748
v.delete();
2749
assert.throws(cm.BindingError, function() {
2750
v.deleteLater();
2751
});
2752
});
2753
2754
test("delete throws if object is already scheduled for deletion", function() {
2755
var v = new cm.ValHolder({});
2756
v.deleteLater();
2757
assert.throws(cm.BindingError, function() {
2758
v.delete();
2759
});
2760
});
2761
2762
test("deleteLater invokes delay function", function() {
2763
var runLater;
2764
cm.setDelayFunction(function(fn) {
2765
runLater = fn;
2766
});
2767
2768
var v = new cm.ValHolder({});
2769
assert.false(runLater);
2770
v.deleteLater();
2771
assert.true(runLater);
2772
assert.false(v.isDeleted());
2773
runLater();
2774
assert.true(v.isDeleted());
2775
});
2776
2777
test("deleteLater twice invokes delay function once", function() {
2778
var count = 0;
2779
var runLater;
2780
cm.setDelayFunction(function(fn) {
2781
++count;
2782
runLater = fn;
2783
});
2784
2785
(new cm.ValHolder({})).deleteLater();
2786
(new cm.ValHolder({})).deleteLater();
2787
assert.equal(1, count);
2788
runLater();
2789
(new cm.ValHolder({})).deleteLater();
2790
assert.equal(2, count);
2791
});
2792
2793
test('The delay function is immediately invoked if the deletion queue is not empty', function() {
2794
(new cm.ValHolder({})).deleteLater();
2795
var count = 0;
2796
cm.setDelayFunction(function(fn) {
2797
++count;
2798
});
2799
assert.equal(1, count);
2800
});
2801
2802
// The idea is that an interactive application would
2803
// periodically flush the deleteLater queue by calling
2804
//
2805
// setDelayFunction(function(fn) {
2806
// setTimeout(fn, 0);
2807
// });
2808
});
2809
2810
BaseFixture.extend("references", function() {
2811
test("JS object handles can be passed through to C++ by reference", function() {
2812
var sh = new cm.StringHolder("Hello world");
2813
assert.equal("Hello world", sh.get());
2814
cm.clear_StringHolder(sh);
2815
assert.equal("", sh.get());
2816
sh.delete();
2817
});
2818
});
2819
2820
BaseFixture.extend("val::as from pointer to value", function() {
2821
test("calling as on pointer with value makes a copy", function() {
2822
var sh1 = new cm.StringHolder("Hello world");
2823
var sh2 = cm.return_StringHolder_copy(sh1);
2824
assert.equal("Hello world", sh1.get());
2825
assert.equal("Hello world", sh2.get());
2826
assert.false(sh1.isAliasOf(sh2));
2827
sh2.delete();
2828
sh1.delete();
2829
});
2830
2831
test("calling function that returns a StringHolder", function() {
2832
var sh1 = new cm.StringHolder("Hello world");
2833
var sh2 = cm.call_StringHolder_func(function() {
2834
return sh1;
2835
});
2836
assert.equal("Hello world", sh1.get());
2837
assert.equal("Hello world", sh2.get());
2838
assert.false(sh1.isAliasOf(sh2));
2839
sh2.delete();
2840
sh1.delete();
2841
});
2842
});
2843
2844
BaseFixture.extend("mixin", function() {
2845
test("can call mixin method", function() {
2846
var a = new cm.DerivedWithMixin();
2847
assert.instanceof(a, cm.Base);
2848
assert.equal(10, a.get10());
2849
a.delete();
2850
});
2851
});
2852
2853
BaseFixture.extend("val::as", function() {
2854
test("built-ins", function() {
2855
assert.equal(true, cm.val_as_bool(true));
2856
assert.equal(false, cm.val_as_bool(false));
2857
assert.equal(127, cm.val_as_char(127));
2858
assert.equal(32767, cm.val_as_short(32767));
2859
assert.equal(65536, cm.val_as_int(65536));
2860
if (cm.getCompilerSetting('MEMORY64')) {
2861
assert.equal(65536n, cm.val_as_long(65536));
2862
} else {
2863
assert.equal(65536, cm.val_as_long(65536));
2864
}
2865
assert.equal(10.5, cm.val_as_float(10.5));
2866
assert.equal(10.5, cm.val_as_double(10.5));
2867
2868
assert.equal("foo", cm.val_as_string("foo"));
2869
assert.equal("foo", cm.val_as_wstring("foo"));
2870
2871
var obj = {};
2872
assert.equal(obj, cm.val_as_val(obj));
2873
2874
// JS->C++ memory view not implemented
2875
//var ab = cm.val_as_memory_view(new ArrayBuffer(13));
2876
//assert.equal(13, ab.byteLength);
2877
});
2878
2879
test("value types", function() {
2880
var tuple = [1, 2, 3, 4];
2881
assert.deepEqual(tuple, cm.val_as_value_array(tuple));
2882
2883
var struct = {x: 1, y: 2, z: 3, w: 4};
2884
assert.deepEqual(struct, cm.val_as_value_object(struct));
2885
});
2886
2887
test("enums", function() {
2888
assert.equal(cm.Enum.ONE, cm.val_as_enum(cm.Enum.ONE));
2889
});
2890
});
2891
2892
BaseFixture.extend("val::new_", function() {
2893
test("variety of types", function() {
2894
function factory() {
2895
this.arguments = Array.prototype.slice.call(arguments, 0);
2896
}
2897
var instance = cm.construct_with_6_arguments(factory);
2898
assert.deepEqual(
2899
[6, -12.5, "a3", {x: 1, y: 2, z: 3, w: 4}, cm.EnumClass.TWO, [-1, -2, -3, -4]],
2900
instance.arguments);
2901
});
2902
2903
test("memory view", function() {
2904
function factory(before, view, after) {
2905
this.before = before;
2906
this.view = view;
2907
this.after = after;
2908
}
2909
2910
var instance = cm.construct_with_memory_view(factory);
2911
assert.equal("before", instance.before);
2912
assert.equal(10, instance.view.byteLength);
2913
assert.equal("after", instance.after);
2914
});
2915
2916
test("ints_and_float", function() {
2917
function factory(a, b, c) {
2918
this.a = a;
2919
this.b = b;
2920
this.c = c;
2921
}
2922
2923
var instance = cm.construct_with_ints_and_float(factory);
2924
assert.equal(65537, instance.a);
2925
assert.equal(4.0, instance.b);
2926
assert.equal(65538, instance.c);
2927
});
2928
2929
if (cm.isMemoryGrowthEnabled) {
2930
test("before and after memory growth", function() {
2931
var array = cm.construct_with_arguments_before_and_after_memory_growth();
2932
assert.equal(array[0].byteLength, 5);
2933
assert.equal(array[0].byteLength, array[1].byteLength);
2934
});
2935
}
2936
});
2937
2938
BaseFixture.extend("intrusive pointers", function() {
2939
test("can pass intrusive pointers", function() {
2940
var ic = new cm.IntrusiveClass;
2941
var d = cm.passThroughIntrusiveClass(ic);
2942
assert.true(ic.isAliasOf(d));
2943
ic.delete();
2944
d.delete();
2945
});
2946
2947
test("can hold intrusive pointers", function() {
2948
var ic = new cm.IntrusiveClass;
2949
var holder = new cm.IntrusiveClassHolder;
2950
holder.set(ic);
2951
ic.delete();
2952
var d = holder.get();
2953
d.delete();
2954
holder.delete();
2955
});
2956
2957
test("can extend from intrusive pointer class and still preserve reference in JavaScript", function() {
2958
var C = cm.IntrusiveClass.extend("C", {
2959
});
2960
var instance = new C;
2961
var holder = new cm.IntrusiveClassHolder;
2962
holder.set(instance);
2963
instance.delete();
2964
2965
var back = holder.get();
2966
assert.equal(back, instance);
2967
holder.delete();
2968
back.delete();
2969
});
2970
});
2971
2972
BaseFixture.extend("typeof", function() {
2973
test("typeof", function() {
2974
assert.equal("object", cm.getTypeOfVal(null));
2975
assert.equal("object", cm.getTypeOfVal({}));
2976
assert.equal("function", cm.getTypeOfVal(function(){}));
2977
assert.equal("number", cm.getTypeOfVal(1));
2978
assert.equal("string", cm.getTypeOfVal("hi"));
2979
});
2980
});
2981
2982
BaseFixture.extend("static member", function() {
2983
test("static members", function() {
2984
assert.equal(10, cm.HasStaticMember.c);
2985
assert.equal(20, cm.HasStaticMember.v);
2986
cm.HasStaticMember.v = 30;
2987
assert.equal(30, cm.HasStaticMember.v);
2988
});
2989
});
2990
});
2991
2992
/* global run_all_tests */
2993
// If running as part of the emscripten test runner suite, and not as part of the IMVU suite,
2994
// we launch the test execution from here. IMVU suite uses its own dedicated mechanism instead of this.
2995
if (typeof run_all_tests !== "undefined") {
2996
run_all_tests();
2997
}
2998
2999