]> git.ipfire.org Git - thirdparty/gcc.git/blame - libgo/go/syscall/js/js_test.go
libgo: update to Go1.14beta1
[thirdparty/gcc.git] / libgo / go / syscall / js / js_test.go
CommitLineData
dd931d9b
ILT
1// Copyright 2018 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5// +build js,wasm
6
4f4a855d
ILT
7// To run these tests:
8//
9// - Install Node
10// - Add /path/to/go/misc/wasm to your $PATH (so that "go test" can find
11// "go_js_wasm_exec").
12// - GOOS=js GOARCH=wasm go test
13//
14// See -exec in "go help test", and "go help run" for details.
15
dd931d9b
ILT
16package js_test
17
18import (
19 "fmt"
20 "math"
5a8ea165 21 "runtime"
dd931d9b
ILT
22 "syscall/js"
23 "testing"
24)
25
26var dummys = js.Global().Call("eval", `({
27 someBool: true,
28 someString: "abc\u1234",
29 someInt: 42,
30 someFloat: 42.123,
31 someArray: [41, 42, 43],
4f4a855d 32 someDate: new Date(),
dd931d9b
ILT
33 add: function(a, b) {
34 return a + b;
35 },
4f4a855d
ILT
36 zero: 0,
37 stringZero: "0",
dd931d9b 38 NaN: NaN,
4f4a855d
ILT
39 emptyObj: {},
40 emptyArray: [],
41 Infinity: Infinity,
42 NegInfinity: -Infinity,
43 objNumber0: new Number(0),
44 objBooleanFalse: new Boolean(false),
dd931d9b
ILT
45})`)
46
47func TestBool(t *testing.T) {
48 want := true
49 o := dummys.Get("someBool")
50 if got := o.Bool(); got != want {
51 t.Errorf("got %#v, want %#v", got, want)
52 }
53 dummys.Set("otherBool", want)
54 if got := dummys.Get("otherBool").Bool(); got != want {
55 t.Errorf("got %#v, want %#v", got, want)
56 }
5a8ea165 57 if !dummys.Get("someBool").Equal(dummys.Get("someBool")) {
dd931d9b
ILT
58 t.Errorf("same value not equal")
59 }
60}
61
62func TestString(t *testing.T) {
63 want := "abc\u1234"
64 o := dummys.Get("someString")
65 if got := o.String(); got != want {
66 t.Errorf("got %#v, want %#v", got, want)
67 }
68 dummys.Set("otherString", want)
69 if got := dummys.Get("otherString").String(); got != want {
70 t.Errorf("got %#v, want %#v", got, want)
71 }
5a8ea165 72 if !dummys.Get("someString").Equal(dummys.Get("someString")) {
dd931d9b
ILT
73 t.Errorf("same value not equal")
74 }
75
aa8901e9
ILT
76 if got, want := js.Undefined().String(), "<undefined>"; got != want {
77 t.Errorf("got %#v, want %#v", got, want)
78 }
79 if got, want := js.Null().String(), "<null>"; got != want {
80 t.Errorf("got %#v, want %#v", got, want)
81 }
82 if got, want := js.ValueOf(true).String(), "<boolean: true>"; got != want {
83 t.Errorf("got %#v, want %#v", got, want)
84 }
85 if got, want := js.ValueOf(42.5).String(), "<number: 42.5>"; got != want {
86 t.Errorf("got %#v, want %#v", got, want)
87 }
88 if got, want := js.Global().Call("Symbol").String(), "<symbol>"; got != want {
89 t.Errorf("got %#v, want %#v", got, want)
90 }
91 if got, want := js.Global().String(), "<object>"; got != want {
92 t.Errorf("got %#v, want %#v", got, want)
93 }
94 if got, want := js.Global().Get("setTimeout").String(), "<function>"; got != want {
95 t.Errorf("got %#v, want %#v", got, want)
dd931d9b
ILT
96 }
97}
98
99func TestInt(t *testing.T) {
100 want := 42
101 o := dummys.Get("someInt")
102 if got := o.Int(); got != want {
103 t.Errorf("got %#v, want %#v", got, want)
104 }
105 dummys.Set("otherInt", want)
106 if got := dummys.Get("otherInt").Int(); got != want {
107 t.Errorf("got %#v, want %#v", got, want)
108 }
5a8ea165 109 if !dummys.Get("someInt").Equal(dummys.Get("someInt")) {
dd931d9b
ILT
110 t.Errorf("same value not equal")
111 }
4f4a855d
ILT
112 if got := dummys.Get("zero").Int(); got != 0 {
113 t.Errorf("got %#v, want %#v", got, 0)
114 }
dd931d9b
ILT
115}
116
117func TestIntConversion(t *testing.T) {
118 testIntConversion(t, 0)
119 testIntConversion(t, 1)
120 testIntConversion(t, -1)
121 testIntConversion(t, 1<<20)
122 testIntConversion(t, -1<<20)
123 testIntConversion(t, 1<<40)
124 testIntConversion(t, -1<<40)
125 testIntConversion(t, 1<<60)
126 testIntConversion(t, -1<<60)
127}
128
129func testIntConversion(t *testing.T, want int) {
130 if got := js.ValueOf(want).Int(); got != want {
131 t.Errorf("got %#v, want %#v", got, want)
132 }
133}
134
135func TestFloat(t *testing.T) {
136 want := 42.123
137 o := dummys.Get("someFloat")
138 if got := o.Float(); got != want {
139 t.Errorf("got %#v, want %#v", got, want)
140 }
141 dummys.Set("otherFloat", want)
142 if got := dummys.Get("otherFloat").Float(); got != want {
143 t.Errorf("got %#v, want %#v", got, want)
144 }
5a8ea165 145 if !dummys.Get("someFloat").Equal(dummys.Get("someFloat")) {
dd931d9b
ILT
146 t.Errorf("same value not equal")
147 }
148}
149
150func TestObject(t *testing.T) {
5a8ea165 151 if !dummys.Get("someArray").Equal(dummys.Get("someArray")) {
dd931d9b
ILT
152 t.Errorf("same value not equal")
153 }
154
155 // An object and its prototype should not be equal.
156 proto := js.Global().Get("Object").Get("prototype")
157 o := js.Global().Call("eval", "new Object()")
5a8ea165 158 if proto.Equal(o) {
dd931d9b
ILT
159 t.Errorf("object equals to its prototype")
160 }
161}
162
163func TestFrozenObject(t *testing.T) {
164 o := js.Global().Call("eval", "(function () { let o = new Object(); o.field = 5; Object.freeze(o); return o; })()")
165 want := 5
166 if got := o.Get("field").Int(); want != got {
167 t.Errorf("got %#v, want %#v", got, want)
168 }
169}
170
5a8ea165
ILT
171func TestEqual(t *testing.T) {
172 if !dummys.Get("someFloat").Equal(dummys.Get("someFloat")) {
173 t.Errorf("same float is not equal")
174 }
175 if !dummys.Get("emptyObj").Equal(dummys.Get("emptyObj")) {
176 t.Errorf("same object is not equal")
177 }
178 if dummys.Get("someFloat").Equal(dummys.Get("someInt")) {
179 t.Errorf("different values are not unequal")
180 }
181}
182
dd931d9b 183func TestNaN(t *testing.T) {
5a8ea165
ILT
184 if !dummys.Get("NaN").IsNaN() {
185 t.Errorf("JS NaN is not NaN")
186 }
187 if !js.ValueOf(math.NaN()).IsNaN() {
188 t.Errorf("Go NaN is not NaN")
189 }
190 if dummys.Get("NaN").Equal(dummys.Get("NaN")) {
191 t.Errorf("NaN is equal to NaN")
dd931d9b
ILT
192 }
193}
194
195func TestUndefined(t *testing.T) {
5a8ea165
ILT
196 if !js.Undefined().IsUndefined() {
197 t.Errorf("undefined is not undefined")
198 }
199 if !js.Undefined().Equal(js.Undefined()) {
200 t.Errorf("undefined is not equal to undefined")
201 }
202 if dummys.IsUndefined() {
203 t.Errorf("object is undefined")
204 }
205 if js.Undefined().IsNull() {
206 t.Errorf("undefined is null")
207 }
208 if dummys.Set("test", js.Undefined()); !dummys.Get("test").IsUndefined() {
209 t.Errorf("could not set undefined")
dd931d9b
ILT
210 }
211}
212
213func TestNull(t *testing.T) {
5a8ea165
ILT
214 if !js.Null().IsNull() {
215 t.Errorf("null is not null")
216 }
217 if !js.Null().Equal(js.Null()) {
218 t.Errorf("null is not equal to null")
219 }
220 if dummys.IsNull() {
221 t.Errorf("object is null")
222 }
223 if js.Null().IsUndefined() {
224 t.Errorf("null is undefined")
225 }
226 if dummys.Set("test", js.Null()); !dummys.Get("test").IsNull() {
227 t.Errorf("could not set null")
228 }
229 if dummys.Set("test", nil); !dummys.Get("test").IsNull() {
230 t.Errorf("could not set nil")
dd931d9b
ILT
231 }
232}
233
234func TestLength(t *testing.T) {
235 if got := dummys.Get("someArray").Length(); got != 3 {
236 t.Errorf("got %#v, want %#v", got, 3)
237 }
238}
239
aa8901e9
ILT
240func TestGet(t *testing.T) {
241 // positive cases get tested per type
242
243 expectValueError(t, func() {
244 dummys.Get("zero").Get("badField")
245 })
246}
247
248func TestSet(t *testing.T) {
249 // positive cases get tested per type
250
251 expectValueError(t, func() {
252 dummys.Get("zero").Set("badField", 42)
253 })
254}
255
5a8ea165
ILT
256func TestDelete(t *testing.T) {
257 dummys.Set("test", 42)
258 dummys.Delete("test")
259 if dummys.Call("hasOwnProperty", "test").Bool() {
260 t.Errorf("property still exists")
261 }
262
263 expectValueError(t, func() {
264 dummys.Get("zero").Delete("badField")
265 })
266}
267
dd931d9b
ILT
268func TestIndex(t *testing.T) {
269 if got := dummys.Get("someArray").Index(1).Int(); got != 42 {
270 t.Errorf("got %#v, want %#v", got, 42)
271 }
aa8901e9
ILT
272
273 expectValueError(t, func() {
274 dummys.Get("zero").Index(1)
275 })
dd931d9b
ILT
276}
277
278func TestSetIndex(t *testing.T) {
279 dummys.Get("someArray").SetIndex(2, 99)
280 if got := dummys.Get("someArray").Index(2).Int(); got != 99 {
281 t.Errorf("got %#v, want %#v", got, 99)
282 }
aa8901e9
ILT
283
284 expectValueError(t, func() {
285 dummys.Get("zero").SetIndex(2, 99)
286 })
dd931d9b
ILT
287}
288
289func TestCall(t *testing.T) {
290 var i int64 = 40
291 if got := dummys.Call("add", i, 2).Int(); got != 42 {
292 t.Errorf("got %#v, want %#v", got, 42)
293 }
294 if got := dummys.Call("add", js.Global().Call("eval", "40"), 2).Int(); got != 42 {
295 t.Errorf("got %#v, want %#v", got, 42)
296 }
aa8901e9
ILT
297
298 expectPanic(t, func() {
299 dummys.Call("zero")
300 })
301 expectValueError(t, func() {
302 dummys.Get("zero").Call("badMethod")
303 })
dd931d9b
ILT
304}
305
306func TestInvoke(t *testing.T) {
307 var i int64 = 40
308 if got := dummys.Get("add").Invoke(i, 2).Int(); got != 42 {
309 t.Errorf("got %#v, want %#v", got, 42)
310 }
aa8901e9
ILT
311
312 expectValueError(t, func() {
313 dummys.Get("zero").Invoke()
314 })
dd931d9b
ILT
315}
316
317func TestNew(t *testing.T) {
318 if got := js.Global().Get("Array").New(42).Length(); got != 42 {
319 t.Errorf("got %#v, want %#v", got, 42)
320 }
aa8901e9
ILT
321
322 expectValueError(t, func() {
323 dummys.Get("zero").New()
324 })
dd931d9b
ILT
325}
326
327func TestInstanceOf(t *testing.T) {
328 someArray := js.Global().Get("Array").New()
329 if got, want := someArray.InstanceOf(js.Global().Get("Array")), true; got != want {
330 t.Errorf("got %#v, want %#v", got, want)
331 }
332 if got, want := someArray.InstanceOf(js.Global().Get("Function")), false; got != want {
333 t.Errorf("got %#v, want %#v", got, want)
334 }
335}
336
337func TestType(t *testing.T) {
338 if got, want := js.Undefined().Type(), js.TypeUndefined; got != want {
339 t.Errorf("got %s, want %s", got, want)
340 }
341 if got, want := js.Null().Type(), js.TypeNull; got != want {
342 t.Errorf("got %s, want %s", got, want)
343 }
344 if got, want := js.ValueOf(true).Type(), js.TypeBoolean; got != want {
345 t.Errorf("got %s, want %s", got, want)
346 }
4f4a855d
ILT
347 if got, want := js.ValueOf(0).Type(), js.TypeNumber; got != want {
348 t.Errorf("got %s, want %s", got, want)
349 }
dd931d9b
ILT
350 if got, want := js.ValueOf(42).Type(), js.TypeNumber; got != want {
351 t.Errorf("got %s, want %s", got, want)
352 }
353 if got, want := js.ValueOf("test").Type(), js.TypeString; got != want {
354 t.Errorf("got %s, want %s", got, want)
355 }
356 if got, want := js.Global().Get("Symbol").Invoke("test").Type(), js.TypeSymbol; got != want {
357 t.Errorf("got %s, want %s", got, want)
358 }
359 if got, want := js.Global().Get("Array").New().Type(), js.TypeObject; got != want {
360 t.Errorf("got %s, want %s", got, want)
361 }
362 if got, want := js.Global().Get("Array").Type(), js.TypeFunction; got != want {
363 t.Errorf("got %s, want %s", got, want)
364 }
365}
366
367type object = map[string]interface{}
368type array = []interface{}
369
370func TestValueOf(t *testing.T) {
371 a := js.ValueOf(array{0, array{0, 42, 0}, 0})
372 if got := a.Index(1).Index(1).Int(); got != 42 {
373 t.Errorf("got %v, want %v", got, 42)
374 }
375
376 o := js.ValueOf(object{"x": object{"y": 42}})
377 if got := o.Get("x").Get("y").Int(); got != 42 {
378 t.Errorf("got %v, want %v", got, 42)
379 }
380}
381
4f4a855d
ILT
382func TestZeroValue(t *testing.T) {
383 var v js.Value
5a8ea165 384 if !v.IsUndefined() {
4f4a855d
ILT
385 t.Error("zero js.Value is not js.Undefined()")
386 }
387}
388
389func TestFuncOf(t *testing.T) {
dd931d9b 390 c := make(chan struct{})
4f4a855d 391 cb := js.FuncOf(func(this js.Value, args []js.Value) interface{} {
dd931d9b
ILT
392 if got := args[0].Int(); got != 42 {
393 t.Errorf("got %#v, want %#v", got, 42)
394 }
395 c <- struct{}{}
4f4a855d 396 return nil
dd931d9b
ILT
397 })
398 defer cb.Release()
399 js.Global().Call("setTimeout", cb, 0, 42)
400 <-c
401}
402
4f4a855d
ILT
403func TestInvokeFunction(t *testing.T) {
404 called := false
405 cb := js.FuncOf(func(this js.Value, args []js.Value) interface{} {
406 cb2 := js.FuncOf(func(this js.Value, args []js.Value) interface{} {
407 called = true
408 return 42
dd931d9b 409 })
4f4a855d
ILT
410 defer cb2.Release()
411 return cb2.Invoke()
412 })
413 defer cb.Release()
414 if got := cb.Invoke().Int(); got != 42 {
415 t.Errorf("got %#v, want %#v", got, 42)
416 }
417 if !called {
418 t.Error("function not called")
dd931d9b
ILT
419 }
420}
421
5a8ea165
ILT
422func TestInterleavedFunctions(t *testing.T) {
423 c1 := make(chan struct{})
424 c2 := make(chan struct{})
425
426 js.Global().Get("setTimeout").Invoke(js.FuncOf(func(this js.Value, args []js.Value) interface{} {
427 c1 <- struct{}{}
428 <-c2
429 return nil
430 }), 0)
431
432 <-c1
433 c2 <- struct{}{}
434 // this goroutine is running, but the callback of setTimeout did not return yet, invoke another function now
435 f := js.FuncOf(func(this js.Value, args []js.Value) interface{} {
436 return nil
437 })
438 f.Invoke()
439}
440
4f4a855d
ILT
441func ExampleFuncOf() {
442 var cb js.Func
443 cb = js.FuncOf(func(this js.Value, args []js.Value) interface{} {
dd931d9b 444 fmt.Println("button clicked")
4f4a855d
ILT
445 cb.Release() // release the function if the button will not be clicked again
446 return nil
dd931d9b
ILT
447 })
448 js.Global().Get("document").Call("getElementById", "myButton").Call("addEventListener", "click", cb)
449}
4f4a855d
ILT
450
451// See
452// - https://developer.mozilla.org/en-US/docs/Glossary/Truthy
453// - https://stackoverflow.com/questions/19839952/all-falsey-values-in-javascript/19839953#19839953
454// - http://www.ecma-international.org/ecma-262/5.1/#sec-9.2
455func TestTruthy(t *testing.T) {
456 want := true
457 for _, key := range []string{
458 "someBool", "someString", "someInt", "someFloat", "someArray", "someDate",
459 "stringZero", // "0" is truthy
460 "add", // functions are truthy
461 "emptyObj", "emptyArray", "Infinity", "NegInfinity",
462 // All objects are truthy, even if they're Number(0) or Boolean(false).
463 "objNumber0", "objBooleanFalse",
464 } {
465 if got := dummys.Get(key).Truthy(); got != want {
466 t.Errorf("%s: got %#v, want %#v", key, got, want)
467 }
468 }
469
470 want = false
471 if got := dummys.Get("zero").Truthy(); got != want {
472 t.Errorf("got %#v, want %#v", got, want)
473 }
474 if got := dummys.Get("NaN").Truthy(); got != want {
475 t.Errorf("got %#v, want %#v", got, want)
476 }
477 if got := js.ValueOf("").Truthy(); got != want {
478 t.Errorf("got %#v, want %#v", got, want)
479 }
480 if got := js.Null().Truthy(); got != want {
481 t.Errorf("got %#v, want %#v", got, want)
482 }
483 if got := js.Undefined().Truthy(); got != want {
484 t.Errorf("got %#v, want %#v", got, want)
485 }
486}
aa8901e9
ILT
487
488func expectValueError(t *testing.T, fn func()) {
489 defer func() {
490 err := recover()
491 if _, ok := err.(*js.ValueError); !ok {
492 t.Errorf("expected *js.ValueError, got %T", err)
493 }
494 }()
495 fn()
496}
497
498func expectPanic(t *testing.T, fn func()) {
499 defer func() {
500 err := recover()
501 if err == nil {
502 t.Errorf("expected panic")
503 }
504 }()
505 fn()
506}
507
508var copyTests = []struct {
509 srcLen int
510 dstLen int
511 copyLen int
512}{
513 {5, 3, 3},
514 {3, 5, 3},
515 {0, 0, 0},
516}
517
518func TestCopyBytesToGo(t *testing.T) {
519 for _, tt := range copyTests {
520 t.Run(fmt.Sprintf("%d-to-%d", tt.srcLen, tt.dstLen), func(t *testing.T) {
521 src := js.Global().Get("Uint8Array").New(tt.srcLen)
522 if tt.srcLen >= 2 {
523 src.SetIndex(1, 42)
524 }
525 dst := make([]byte, tt.dstLen)
526
527 if got, want := js.CopyBytesToGo(dst, src), tt.copyLen; got != want {
528 t.Errorf("copied %d, want %d", got, want)
529 }
530 if tt.dstLen >= 2 {
531 if got, want := int(dst[1]), 42; got != want {
532 t.Errorf("got %d, want %d", got, want)
533 }
534 }
535 })
536 }
537}
538
539func TestCopyBytesToJS(t *testing.T) {
540 for _, tt := range copyTests {
541 t.Run(fmt.Sprintf("%d-to-%d", tt.srcLen, tt.dstLen), func(t *testing.T) {
542 src := make([]byte, tt.srcLen)
543 if tt.srcLen >= 2 {
544 src[1] = 42
545 }
546 dst := js.Global().Get("Uint8Array").New(tt.dstLen)
547
548 if got, want := js.CopyBytesToJS(dst, src), tt.copyLen; got != want {
549 t.Errorf("copied %d, want %d", got, want)
550 }
551 if tt.dstLen >= 2 {
552 if got, want := dst.Index(1).Int(), 42; got != want {
553 t.Errorf("got %d, want %d", got, want)
554 }
555 }
556 })
557 }
558}
5a8ea165
ILT
559
560func TestGarbageCollection(t *testing.T) {
561 before := js.JSGo.Get("_values").Length()
562 for i := 0; i < 1000; i++ {
563 _ = js.Global().Get("Object").New().Call("toString").String()
564 runtime.GC()
565 }
566 after := js.JSGo.Get("_values").Length()
567 if after-before > 500 {
568 t.Errorf("garbage collection ineffective")
569 }
570}
571
572// BenchmarkDOM is a simple benchmark which emulates a webapp making DOM operations.
573// It creates a div, and sets its id. Then searches by that id and sets some data.
574// Finally it removes that div.
575func BenchmarkDOM(b *testing.B) {
576 document := js.Global().Get("document")
577 if document.IsUndefined() {
578 b.Skip("Not a browser environment. Skipping.")
579 }
580 const data = "someString"
581 for i := 0; i < b.N; i++ {
582 div := document.Call("createElement", "div")
583 div.Call("setAttribute", "id", "myDiv")
584 document.Get("body").Call("appendChild", div)
585 myDiv := document.Call("getElementById", "myDiv")
586 myDiv.Set("innerHTML", data)
587
588 if got, want := myDiv.Get("innerHTML").String(), data; got != want {
589 b.Errorf("got %s, want %s", got, want)
590 }
591 document.Get("body").Call("removeChild", div)
592 }
593}