Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
emscripten-core
GitHub Repository: emscripten-core/emscripten
Path: blob/main/test/embind/test_val.cpp
4150 views
1
// Copyright 2018 The Emscripten Authors. All rights reserved.
2
// Emscripten is available under two separate licenses, the MIT license and the
3
// University of Illinois/NCSA Open Source License. Both these licenses can be
4
// found in the LICENSE file.
5
6
#include <cstdio>
7
#include <iostream>
8
#include <cmath>
9
#include <emscripten/bind.h>
10
#include <emscripten/emscripten.h>
11
#include <emscripten/val.h>
12
13
using namespace emscripten;
14
using namespace std;
15
16
void test(string message) {
17
cout << "test: " << message << "...\n";
18
}
19
20
#define ensure(X) assert(X)
21
#define ensure_not(X) assert(!(X))
22
23
#define ensure_js(js_code) ensure(emscripten_run_script_int(js_code))
24
#define ensure_js_not(js_code) ensure_js((string("!( ") + js_code + " )").c_str())
25
26
void throw_js_error(val js_error) {
27
js_error.throw_();
28
}
29
30
struct Dummy {};
31
32
Dummy * makeDummy() {
33
return new Dummy();
34
}
35
36
EMSCRIPTEN_BINDINGS(test_bindings) {
37
emscripten::class_<Dummy>("Dummy");
38
emscripten::function("throw_js_error", &throw_js_error);
39
emscripten::function("makeDummy", &makeDummy, emscripten::allow_raw_pointers());
40
}
41
42
int main() {
43
printf("start\n");
44
45
test("val array()");
46
val::global().set("a", val::array());
47
ensure_js("a instanceof Array");
48
ensure_js_not("a instanceof Boolean");
49
ensure_js_not("a instanceof Number");
50
51
test("template<typename T> val array(const std::vector<T> vec)");
52
vector<val> vec1;
53
vec1.push_back(val(11));
54
vec1.push_back(val("a"));
55
vec1.push_back(val::array());
56
val::global().set("a", val::array(vec1));
57
ensure_js("a instanceof Array");
58
ensure_js_not("a instanceof Boolean");
59
ensure_js_not("a instanceof Number");
60
ensure_js("a[0] == 11");
61
ensure_js_not("a[0] == 12");
62
ensure_js("a[1] == 'a'");
63
ensure_js("a[2] instanceof Array");
64
vector<int> vec2;
65
vec2.push_back(0);
66
vec2.push_back(1);
67
vec2.push_back(3);
68
val::global().set("a", val::array(vec2));
69
ensure_js("a instanceof Array");
70
ensure_js_not("a instanceof Number");
71
ensure_js("a[0] == 0");
72
ensure_js_not("a[0] == 1");
73
ensure_js("a[1] == 1");
74
ensure_js("a[2] == 3");
75
ensure_js_not("a[2] == 2");
76
vector<int> vec2_from_iter;
77
for (val&& v : val::global("a")) {
78
vec2_from_iter.push_back(v.as<int>());
79
}
80
ensure(vec2 == vec2_from_iter);
81
82
test("template<typename Iter> val array(Iter begin, Iter end)");
83
val::global().set("a", val::array(vec1.begin(), vec1.end()));
84
ensure_js("a instanceof Array");
85
ensure_js_not("a instanceof Boolean");
86
ensure_js_not("a instanceof Number");
87
ensure_js("a[0] == 11");
88
ensure_js_not("a[0] == 12");
89
ensure_js("a[1] == 'a'");
90
ensure_js("a[2] instanceof Array");
91
val::global().set("a", val::array(vec2.begin(), vec2.end()));
92
ensure_js("a instanceof Array");
93
ensure_js_not("a instanceof Number");
94
ensure_js("a[0] == 0");
95
ensure_js_not("a[0] == 1");
96
ensure_js("a[1] == 1");
97
ensure_js("a[2] == 3");
98
ensure_js_not("a[2] == 2");
99
int arr[] = {1, 2, 3};
100
val::global().set("a", val::array(arr, arr + 3));
101
ensure_js("a instanceof Array");
102
ensure_js_not("a instanceof Number");
103
ensure_js("a[0] == 1");
104
ensure_js("a[1] == 2");
105
ensure_js("a[2] == 3");
106
107
test("val object()");
108
val::global().set("a", val::object());
109
ensure_js("a instanceof Object");
110
111
// Test emval{From,To}Handle roundtrip.
112
{
113
val a = val::global("a");
114
val a_roundtrip = val::take_ownership(EM_VAL(EM_ASM_PTR({
115
return Emval.toHandle(Emval.toValue($0));
116
}, a.as_handle())));
117
ensure(a == a_roundtrip);
118
}
119
120
test("val undefined()");
121
val::global().set("a", val::undefined());
122
ensure_js("a == undefined");
123
ensure_js("a != false");
124
125
test("val null()");
126
val::global().set("a", val::null());
127
ensure_js("a == null");
128
ensure_js("a != false");
129
130
test("val global(const char* name = 0)");
131
// best we can probably do is ensure that calling it does not raise an exception
132
val::global();
133
val::global("addEventListener");
134
135
test("template<typename T> explicit val(T&& value)");
136
val::global().set("a", val(false));
137
ensure_js("a == false");
138
val::global().set("a", val(true));
139
ensure_js("a == true");
140
val::global().set("a", val(1));
141
ensure_js("a == 1");
142
val::global().set("a", val(string("1")));
143
ensure_js("a == '1'");
144
145
test("val(const char* v)");
146
val::global().set("a", val("1"));
147
ensure_js("a == '1'");
148
149
test("val()");
150
val a;
151
val::global().set("a", a);
152
ensure_js("a === undefined");
153
a = val(1);
154
val::global().set("a", a);
155
ensure_js("a == 1");
156
val ar[2];
157
ar[0] = val(1);
158
ar[1] = val(2);
159
val::global().set("a", val::array(ar, ar + 2));
160
ensure_js("a instanceof Array");
161
ensure_js_not("a instanceof Number");
162
ensure_js("a[0] == 1");
163
ensure_js("a[1] == 2");
164
165
test("bool isNull()");
166
EM_ASM(
167
globalThis.a = null;
168
globalThis.b = false;
169
globalThis.c = null;
170
globalThis.d = null;
171
globalThis.e = null;
172
globalThis.f = null;
173
globalThis.g = null;
174
globalThis.h = null;
175
globalThis.i = null;
176
);
177
ensure(val::global("a").isNull());
178
ensure_not(val::global("b").isNull());
179
180
test("bool isUndefined()");
181
EM_ASM(
182
a = undefined;
183
b = false;
184
);
185
ensure(val::global("a").isUndefined());
186
ensure_not(val::global("b").isUndefined());
187
188
test("bool isTrue()");
189
EM_ASM(
190
a = true;
191
b = false;
192
c = null;
193
);
194
ensure(val::global("a").isTrue());
195
ensure_not(val::global("b").isTrue());
196
ensure_not(val::global("c").isTrue());
197
198
test("bool isFalse()");
199
EM_ASM(
200
a = false;
201
b = true;
202
c = null;
203
);
204
ensure(val::global("a").isFalse());
205
ensure_not(val::global("b").isFalse());
206
ensure_not(val::global("c").isFalse());
207
208
test("bool isNumber()");
209
EM_ASM(
210
a = 1;
211
b = 1.1;
212
c = true;
213
);
214
ensure(val::global("a").isNumber());
215
ensure(val::global("b").isNumber());
216
ensure_not(val::global("c").isNumber());
217
218
test("bool isString()");
219
EM_ASM(
220
a = '1';
221
b = 1;
222
c = true;
223
);
224
ensure(val::global("a").isString());
225
ensure_not(val::global("b").isString());
226
ensure_not(val::global("c").isString());
227
228
test("bool isArray()");
229
EM_ASM(
230
a = [];
231
b = [1];
232
c = true;
233
d = {};
234
);
235
ensure(val::global("a").isArray());
236
ensure(val::global("b").isArray());
237
ensure_not(val::global("c").isArray());
238
ensure_not(val::global("d").isArray());
239
240
test("val& operator=(val&& v)");
241
val source(val::object());
242
val target(val::object());
243
source.set("val", 1);
244
target = std::move(source);
245
ensure(target["val"].as<int>() == 1);
246
// move and assign to itself
247
target.set("val", 2);
248
target = std::move(target);
249
ensure(target["val"].as<int>() == 2);
250
251
test("bool equals(const val& v)");
252
EM_ASM(
253
a = 1;
254
b = 1;
255
c = 2;
256
d = true;
257
e = '1';
258
);
259
ensure(val::global("a").equals(val::global("a")));
260
ensure(val::global("a").equals(val::global("b")));
261
ensure_not(val::global("a").equals(val::global("c")));
262
ensure(val::global("a").equals(val::global("d")));
263
ensure(val::global("a").equals(val::global("e")));
264
ensure_not(val::global("c").equals(val::global("d")));
265
266
267
test("bool operator==(const val& v)");
268
EM_ASM(
269
a = 1;
270
b = 1;
271
c = 2;
272
d = true;
273
e = '1';
274
);
275
ensure(val::global("a") == val::global("a"));
276
ensure(val::global("a") == val::global("b"));
277
ensure_not(val::global("a") == val::global("c"));
278
ensure(val::global("a") == val::global("d"));
279
ensure(val::global("a") == val::global("e"));
280
ensure_not(val::global("c") == val::global("d"));
281
282
test("bool operator!=(const val& v)");
283
EM_ASM(
284
a = 1;
285
b = 1;
286
c = 2;
287
d = true;
288
e = '1';
289
);
290
ensure_not(val::global("a") != val::global("a"));
291
ensure_not(val::global("a") != val::global("b"));
292
ensure(val::global("a") != val::global("c"));
293
ensure_not(val::global("a") != val::global("d"));
294
ensure_not(val::global("a") != val::global("e"));
295
ensure(val::global("c") != val::global("d"));
296
297
test("bool strictlyEquals(const val& v)");
298
EM_ASM(
299
a = 1;
300
b = 1;
301
c = 2;
302
d = true;
303
e = '1';
304
);
305
ensure(val::global("a").strictlyEquals(val::global("a")));
306
ensure(val::global("a").strictlyEquals(val::global("b")));
307
ensure_not(val::global("a").strictlyEquals(val::global("c")));
308
ensure_not(val::global("a").strictlyEquals(val::global("d")));
309
ensure_not(val::global("a").strictlyEquals(val::global("e")));
310
ensure_not(val::global("c").strictlyEquals(val::global("d")));
311
312
test("bool operator>(const val& v)");
313
EM_ASM(
314
a = 1;
315
b = 1;
316
c = 2;
317
d = '2';
318
);
319
ensure_not(val::global("a") > val::global("a"));
320
ensure_not(val::global("a") > val::global("b"));
321
ensure_not(val::global("a") > val::global("c"));
322
ensure_not(val::global("a") > val::global("d"));
323
ensure(val::global("c") > val::global("a"));
324
ensure(val::global("d") > val::global("a"));
325
326
test("bool operator>= (const val& v)");
327
EM_ASM(
328
a = 1;
329
b = 1;
330
c = 2;
331
d = '2';
332
);
333
ensure(val::global("a") >= val::global("a"));
334
ensure(val::global("a") >= val::global("b"));
335
ensure_not(val::global("a") >= val::global("c"));
336
ensure_not(val::global("a") >= val::global("d"));
337
ensure(val::global("c") >= val::global("a"));
338
ensure(val::global("d") >= val::global("a"));
339
340
test("bool operator<(const val& v)");
341
EM_ASM(
342
a = 1;
343
b = 1;
344
c = 2;
345
d = '2';
346
);
347
ensure_not(val::global("a") < val::global("a"));
348
ensure_not(val::global("a") < val::global("b"));
349
ensure(val::global("a") < val::global("c"));
350
ensure(val::global("a") < val::global("d"));
351
ensure_not(val::global("c") < val::global("a"));
352
ensure_not(val::global("d") < val::global("a"));
353
354
test("bool operator<= (const val& v)");
355
EM_ASM(
356
a = 1;
357
b = 1;
358
c = 2;
359
d = '2';
360
);
361
ensure(val::global("a") <= val::global("a"));
362
ensure(val::global("a") <= val::global("b"));
363
ensure(val::global("a") <= val::global("c"));
364
ensure(val::global("a") <= val::global("d"));
365
ensure_not(val::global("c") <= val::global("a"));
366
ensure_not(val::global("d") <= val::global("a"));
367
368
test("bool operator!()");
369
EM_ASM(
370
a = true;
371
b = false;
372
c = null;
373
d = undefined;
374
e = 0;
375
f = 1;
376
g = "";
377
h = '0';
378
i = 'false';
379
);
380
ensure(!val::global("a") == false);
381
ensure(!val::global("b") == true);
382
ensure(!val::global("c") == true);
383
ensure(!val::global("d") == true);
384
ensure(!val::global("e") == true);
385
ensure(!val::global("f") == false);
386
ensure(!val::global("g") == true);
387
ensure(!val::global("h") == false);
388
ensure(!val::global("i") == false);
389
ensure(!!val::global("a") == true);
390
ensure(!!val::global("b") == false);
391
392
test("template<typename... Args> val new_(Args&&... args)");
393
EM_ASM(
394
globalThis.A = function() {
395
this.value = 2;
396
}
397
);
398
val::global().set("a", val::global("A").new_());
399
ensure_js("a instanceof A");
400
ensure_js("a.value == 2");
401
EM_ASM(
402
globalThis.A = function(arg1, arg2) {
403
this.arg1 = arg1;
404
this.arg2 = arg2;
405
}
406
);
407
val::global().set("a", val::global("A").new_(val(2), val("b")));
408
ensure_js("a instanceof A");
409
ensure_js("a.arg1 == 2");
410
ensure_js("a.arg2 == 'b'");
411
412
test("template<typename T> val operator[](const T& key)");
413
EM_ASM(
414
a = 2;
415
);
416
ensure(val::global()["a"].as<int>() == 2);
417
ensure_not(val::global()["a"].as<int>() == 3);
418
val k("a");
419
ensure(val::global()[k].as<int>() == 2);
420
ensure_not(val::global()[k].as<int>() == 3);
421
422
test("template<typename K, typename V> void set(const K& key, const V& value)");
423
val::global().set("a", val(2));
424
ensure_js("a == 2");
425
val::global().set("a", val(3));
426
ensure_js("a == 3");
427
val::global().set("a", 0);
428
ensure_js("a == 0");
429
val::global().set("a", false);
430
ensure_js("a == false");
431
val::global().set("a", 2);
432
ensure_js("a == 2");
433
val::global().set("a", "b");
434
ensure_js("a == 'b'");
435
val::global().set(k, 1);
436
ensure_js("a == 1");
437
val v(3);
438
val::global().set(k, v);
439
ensure("a == 3");
440
ensure(val::global()[k].as<int>() == 3);
441
442
test("template<typename... Args> val operator()(Args&&... args)");
443
EM_ASM(
444
f = function() {
445
return 2;
446
};
447
);
448
ensure(val::global("f")().as<int>() == 2);
449
ensure_not(val::global("f")().as<int>() == 3);
450
EM_ASM(
451
globalThis.f1 = function(arg1, arg2) {
452
return arg1;
453
};
454
globalThis.f2 = function(arg1, arg2) {
455
return arg2;
456
};
457
);
458
ensure(val::global("f1")(val(2),val("3")).as<int>() == 2);
459
ensure(val::global("f2")(val(2),val("3")).as<string>() == "3");
460
461
test("template<typename ReturnValue, typename... Args> ReturnValue call(const char* name, Args&&... args)");
462
EM_ASM(
463
globalThis.C = function() {
464
this.method = function() { return this; };
465
};
466
c = new C;
467
);
468
ensure(val::global("c").call<val>("method") == val::global("c"));
469
EM_ASM(
470
globalThis.C = function() {
471
this.method = function(arg) { return arg; };
472
};
473
c = new C;
474
);
475
ensure(val::global("c").call<int>("method", val(2)) == 2);
476
477
test("template<typename T, typename ...Policies> T as(Policies...)");
478
EM_ASM(
479
a = 1;
480
b = 'b';
481
);
482
ensure(val::global("a").as<int>() == (int)1);
483
ensure(val::global("a").as<double>() == (double)1.0);
484
ensure_not(val::global("a").as<double>() == (double)1.1);
485
ensure(val::global("b").as<string>() == "b");
486
487
// test:
488
// val typeof()
489
#if __STRICT_ANSI__
490
EM_ASM(
491
a = undefined;
492
b = null;
493
c = true;
494
d = 2;
495
e = '2';
496
f = Symbol();
497
g = function () {};
498
h = {};
499
);
500
if (
501
val::global("a").typeOf().as<string>() != "undefined" ||
502
val::global("a").typeOf().as<string>() == "" ||
503
val::global("b").typeOf().as<string>() != "object" ||
504
val::global("c").typeOf().as<string>() != "boolean" ||
505
val::global("d").typeOf().as<string>() != "number" ||
506
val::global("e").typeOf().as<string>() != "string" ||
507
val::global("f").typeOf().as<string>() != "symbol" ||
508
val::global("g").typeOf().as<string>() != "function" ||
509
val::global("h").typeOf().as<string>() != "object"
510
) {
511
printf("test:\nval typeof()\nfail\n");
512
assert(false);
513
}
514
#endif
515
516
test("val typeOf()");
517
EM_ASM(
518
a = undefined;
519
b = null;
520
c = true;
521
d = 2;
522
e = '2';
523
f = Symbol();
524
g = function () {};
525
h = {};
526
);
527
ensure(val::global("a").typeOf().as<string>() == "undefined");
528
ensure_not(val::global("a").typeOf().as<string>() == "");
529
ensure(val::global("b").typeOf().as<string>() == "object");
530
ensure(val::global("c").typeOf().as<string>() == "boolean");
531
ensure(val::global("d").typeOf().as<string>() == "number");
532
ensure(val::global("e").typeOf().as<string>() == "string");
533
ensure(val::global("f").typeOf().as<string>() == "symbol");
534
ensure(val::global("g").typeOf().as<string>() == "function");
535
ensure(val::global("h").typeOf().as<string>() == "object");
536
ensure(val::undefined().typeOf().as<string>() == "undefined");
537
ensure(val::null().typeOf().as<string>() == "object");
538
ensure(val(true).typeOf().as<string>() == "boolean");
539
ensure(val(2).typeOf().as<string>() == "number");
540
ensure(val("2").typeOf().as<string>() == "string");
541
ensure(val::global().call<val>("Symbol").typeOf().as<string>() == "symbol");
542
ensure(val::object().typeOf().as<string>() == "object");
543
544
test("bool instanceof(const val& v)");
545
EM_ASM(
546
globalThis.A = function() {};
547
globalThis.B = function() {};
548
a = new A;
549
);
550
ensure(val::global("a").instanceof(val::global("A")));
551
ensure_not(val::global("a").instanceof(val::global("B")));
552
553
test("bool in(const val& v)");
554
EM_ASM(
555
// can't declare like this because i get:
556
// error: use of undeclared identifier 'c'
557
// possibly a bug with EM_ASM
558
//a = {b: 'bb',c: 'cc'};
559
a = {};
560
a.b = 'bb';
561
a.c = 'cc';
562
);
563
ensure(val("c").in(val::global("a")));
564
ensure_not(val("d").in(val::global("a")));
565
566
test("template<typename T> bool delete_(const T& property)");
567
EM_ASM(
568
a = {};
569
a.b = undefined;
570
a[0] = null;
571
a[1] = 2;
572
a.c = 'c';
573
);
574
ensure_js("'b' in a");
575
ensure_js("0 in a");
576
ensure_js("1 in a");
577
ensure_js("'c' in a");
578
ensure(val::global("a").delete_("b") == true);
579
ensure_js_not("'b' in a");
580
ensure_js("0 in a");
581
ensure_js("1 in a");
582
ensure_js("'c' in a");
583
ensure(val::global("a").delete_(0) == true);
584
ensure(val::global("a").delete_(val(1)) == true);
585
ensure(val::global("a").delete_(val("c")) == true);
586
ensure_js_not("'b' in a");
587
ensure_js_not("0 in a");
588
ensure_js_not("1 in a");
589
ensure_js_not("'c' in a");
590
591
test("void throw_() const");
592
EM_ASM(
593
globalThis.test_val_throw_ = function(error) {
594
try {
595
Module.throw_js_error(error);
596
return false;
597
} catch(error_thrown) {
598
if (error_thrown != error)
599
throw error_thrown;
600
}
601
return true;
602
}
603
);
604
ensure_js("test_val_throw_(new Error)");
605
ensure_js("test_val_throw_(Error)");
606
ensure_js("test_val_throw_(2)");
607
ensure_js("test_val_throw_('message')");
608
ensure_js("test_val_throw_(new TypeError('message'))");
609
610
// these tests should probably go elsewhere as it is not a member of val
611
test("template<typename T> std::vector<T> vecFromJSArray(const val& v)");
612
EM_ASM(
613
// can't declare like this because i get:
614
// error: expected ')'
615
// possibly a bug with EM_ASM
616
//a = [1, '2'];
617
a = [];
618
a[0] = 1;
619
a[1] = '42';
620
a[2] = 'b';
621
a[3] = new Date(100000);
622
);
623
const std::vector<val>& aAsArray = vecFromJSArray<val>(val::global("a"));
624
ensure(aAsArray.at(0).as<int>() == 1);
625
ensure(aAsArray.at(1).as<string>() == "42");
626
ensure(aAsArray.at(2).as<string>() == "b");
627
ensure(aAsArray.size() == 4);
628
629
test("template<typename T> std::vector<T *> vecFromJSArray(const val& v)");
630
EM_ASM(
631
b = [];
632
b[0] = Module.makeDummy();
633
b[1] = Module.makeDummy();
634
);
635
const std::vector<Dummy *>& bAsArray = vecFromJSArray<Dummy *>(val::global("b"), allow_raw_pointers());
636
ensure(bAsArray.size() == 2);
637
for (auto *dummy : bAsArray) {
638
delete dummy;
639
}
640
641
test("template<typename T> std::vector<T> convertJSArrayToNumberVector(const val& v)");
642
643
const std::vector<float>& aAsNumberVectorFloat = convertJSArrayToNumberVector<float>(val::global("a"));
644
ensure(aAsNumberVectorFloat.size() == 4);
645
646
ensure(aAsNumberVectorFloat.at(0) == 1.f);
647
ensure(aAsNumberVectorFloat.at(1) == 42.f); // String containing numbers are converted correctly
648
ensure(std::isnan(aAsNumberVectorFloat.at(2))); // NaN returned if can not be converted for floats
649
ensure(aAsNumberVectorFloat.at(3) == 100000.f); // Date returns milliseconds since epoch
650
651
const std::vector<uint32_t>& aAsNumberVectorUint32_t = convertJSArrayToNumberVector<uint32_t>(val::global("a"));
652
ensure(aAsNumberVectorUint32_t.size() == 4);
653
654
ensure(aAsNumberVectorUint32_t.at(0) == 1);
655
ensure(aAsNumberVectorUint32_t.at(1) == 42); // String containing numbers are converted correctly
656
ensure(aAsNumberVectorUint32_t.at(2) == 0); // 0 is returned if can not be converted for integers
657
ensure(aAsNumberVectorUint32_t.at(3) == 100000); // Date returns milliseconds since epoch
658
659
test("val u8string(const char* s)");
660
val::global().set("a", val::u8string(u8"abc"));
661
ensure_js("a == 'abc'");
662
val::global().set("a", val::u8string(u8"你好"));
663
ensure_js_not("a == 'abc'");
664
ensure_js("a == '你好'");
665
auto u8_str = val::global()["a"].as<std::string>();
666
ensure(u8_str == u8"你好");
667
668
test("val u16string(const char16_t* s)");
669
val::global().set("a", val::u16string(u"hello"));
670
ensure_js("a == 'hello'");
671
val::global().set("a", val::u16string(u"世界"));
672
ensure_js_not("a == 'hello'");
673
ensure_js("a == '世界'");
674
// UTF-16 encoded SMILING FACE WITH OPEN MOUTH (U+1F603)
675
const char16_t* s = u"😃 = \U0001F603 is :-D";
676
val::global().set("a", val::u16string(s));
677
ensure_js("a == '😃 = \U0001F603 is :-D'");
678
679
test("val set() with policy");
680
Dummy *dummy = new Dummy();
681
val::global().set("a", dummy, allow_raw_pointers());
682
ensure_js("a instanceof Module.Dummy");
683
val::global().set("a", val::null());
684
delete dummy;
685
686
printf("end\n");
687
return 0;
688
}
689
690