Fix "PR c++/92804 ICE trying to use concept as a nested-name-specifier"
[official-gcc.git] / libgo / go / syscall / js / js_test.go
blobfea4c135afc85abec0e2178efb821cfc076f3009
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.
5 // +build js,wasm
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
14 // See -exec in "go help test", and "go help run" for details.
16 package js_test
18 import (
19 "fmt"
20 "math"
21 "runtime"
22 "syscall/js"
23 "testing"
26 var dummys = js.Global().Call("eval", `({
27 someBool: true,
28 someString: "abc\u1234",
29 someInt: 42,
30 someFloat: 42.123,
31 someArray: [41, 42, 43],
32 someDate: new Date(),
33 add: function(a, b) {
34 return a + b;
36 zero: 0,
37 stringZero: "0",
38 NaN: NaN,
39 emptyObj: {},
40 emptyArray: [],
41 Infinity: Infinity,
42 NegInfinity: -Infinity,
43 objNumber0: new Number(0),
44 objBooleanFalse: new Boolean(false),
45 })`)
47 func 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)
53 dummys.Set("otherBool", want)
54 if got := dummys.Get("otherBool").Bool(); got != want {
55 t.Errorf("got %#v, want %#v", got, want)
57 if !dummys.Get("someBool").Equal(dummys.Get("someBool")) {
58 t.Errorf("same value not equal")
62 func 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)
68 dummys.Set("otherString", want)
69 if got := dummys.Get("otherString").String(); got != want {
70 t.Errorf("got %#v, want %#v", got, want)
72 if !dummys.Get("someString").Equal(dummys.Get("someString")) {
73 t.Errorf("same value not equal")
76 if got, want := js.Undefined().String(), "<undefined>"; got != want {
77 t.Errorf("got %#v, want %#v", got, want)
79 if got, want := js.Null().String(), "<null>"; got != want {
80 t.Errorf("got %#v, want %#v", got, want)
82 if got, want := js.ValueOf(true).String(), "<boolean: true>"; got != want {
83 t.Errorf("got %#v, want %#v", got, want)
85 if got, want := js.ValueOf(42.5).String(), "<number: 42.5>"; got != want {
86 t.Errorf("got %#v, want %#v", got, want)
88 if got, want := js.Global().Call("Symbol").String(), "<symbol>"; got != want {
89 t.Errorf("got %#v, want %#v", got, want)
91 if got, want := js.Global().String(), "<object>"; got != want {
92 t.Errorf("got %#v, want %#v", got, want)
94 if got, want := js.Global().Get("setTimeout").String(), "<function>"; got != want {
95 t.Errorf("got %#v, want %#v", got, want)
99 func 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)
105 dummys.Set("otherInt", want)
106 if got := dummys.Get("otherInt").Int(); got != want {
107 t.Errorf("got %#v, want %#v", got, want)
109 if !dummys.Get("someInt").Equal(dummys.Get("someInt")) {
110 t.Errorf("same value not equal")
112 if got := dummys.Get("zero").Int(); got != 0 {
113 t.Errorf("got %#v, want %#v", got, 0)
117 func 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)
129 func testIntConversion(t *testing.T, want int) {
130 if got := js.ValueOf(want).Int(); got != want {
131 t.Errorf("got %#v, want %#v", got, want)
135 func 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)
141 dummys.Set("otherFloat", want)
142 if got := dummys.Get("otherFloat").Float(); got != want {
143 t.Errorf("got %#v, want %#v", got, want)
145 if !dummys.Get("someFloat").Equal(dummys.Get("someFloat")) {
146 t.Errorf("same value not equal")
150 func TestObject(t *testing.T) {
151 if !dummys.Get("someArray").Equal(dummys.Get("someArray")) {
152 t.Errorf("same value not equal")
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()")
158 if proto.Equal(o) {
159 t.Errorf("object equals to its prototype")
163 func 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)
171 func TestEqual(t *testing.T) {
172 if !dummys.Get("someFloat").Equal(dummys.Get("someFloat")) {
173 t.Errorf("same float is not equal")
175 if !dummys.Get("emptyObj").Equal(dummys.Get("emptyObj")) {
176 t.Errorf("same object is not equal")
178 if dummys.Get("someFloat").Equal(dummys.Get("someInt")) {
179 t.Errorf("different values are not unequal")
183 func TestNaN(t *testing.T) {
184 if !dummys.Get("NaN").IsNaN() {
185 t.Errorf("JS NaN is not NaN")
187 if !js.ValueOf(math.NaN()).IsNaN() {
188 t.Errorf("Go NaN is not NaN")
190 if dummys.Get("NaN").Equal(dummys.Get("NaN")) {
191 t.Errorf("NaN is equal to NaN")
195 func TestUndefined(t *testing.T) {
196 if !js.Undefined().IsUndefined() {
197 t.Errorf("undefined is not undefined")
199 if !js.Undefined().Equal(js.Undefined()) {
200 t.Errorf("undefined is not equal to undefined")
202 if dummys.IsUndefined() {
203 t.Errorf("object is undefined")
205 if js.Undefined().IsNull() {
206 t.Errorf("undefined is null")
208 if dummys.Set("test", js.Undefined()); !dummys.Get("test").IsUndefined() {
209 t.Errorf("could not set undefined")
213 func TestNull(t *testing.T) {
214 if !js.Null().IsNull() {
215 t.Errorf("null is not null")
217 if !js.Null().Equal(js.Null()) {
218 t.Errorf("null is not equal to null")
220 if dummys.IsNull() {
221 t.Errorf("object is null")
223 if js.Null().IsUndefined() {
224 t.Errorf("null is undefined")
226 if dummys.Set("test", js.Null()); !dummys.Get("test").IsNull() {
227 t.Errorf("could not set null")
229 if dummys.Set("test", nil); !dummys.Get("test").IsNull() {
230 t.Errorf("could not set nil")
234 func TestLength(t *testing.T) {
235 if got := dummys.Get("someArray").Length(); got != 3 {
236 t.Errorf("got %#v, want %#v", got, 3)
240 func TestGet(t *testing.T) {
241 // positive cases get tested per type
243 expectValueError(t, func() {
244 dummys.Get("zero").Get("badField")
248 func TestSet(t *testing.T) {
249 // positive cases get tested per type
251 expectValueError(t, func() {
252 dummys.Get("zero").Set("badField", 42)
256 func 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")
263 expectValueError(t, func() {
264 dummys.Get("zero").Delete("badField")
268 func TestIndex(t *testing.T) {
269 if got := dummys.Get("someArray").Index(1).Int(); got != 42 {
270 t.Errorf("got %#v, want %#v", got, 42)
273 expectValueError(t, func() {
274 dummys.Get("zero").Index(1)
278 func 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)
284 expectValueError(t, func() {
285 dummys.Get("zero").SetIndex(2, 99)
289 func 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)
294 if got := dummys.Call("add", js.Global().Call("eval", "40"), 2).Int(); got != 42 {
295 t.Errorf("got %#v, want %#v", got, 42)
298 expectPanic(t, func() {
299 dummys.Call("zero")
301 expectValueError(t, func() {
302 dummys.Get("zero").Call("badMethod")
306 func 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)
312 expectValueError(t, func() {
313 dummys.Get("zero").Invoke()
317 func 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)
322 expectValueError(t, func() {
323 dummys.Get("zero").New()
327 func 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)
332 if got, want := someArray.InstanceOf(js.Global().Get("Function")), false; got != want {
333 t.Errorf("got %#v, want %#v", got, want)
337 func TestType(t *testing.T) {
338 if got, want := js.Undefined().Type(), js.TypeUndefined; got != want {
339 t.Errorf("got %s, want %s", got, want)
341 if got, want := js.Null().Type(), js.TypeNull; got != want {
342 t.Errorf("got %s, want %s", got, want)
344 if got, want := js.ValueOf(true).Type(), js.TypeBoolean; got != want {
345 t.Errorf("got %s, want %s", got, want)
347 if got, want := js.ValueOf(0).Type(), js.TypeNumber; got != want {
348 t.Errorf("got %s, want %s", got, want)
350 if got, want := js.ValueOf(42).Type(), js.TypeNumber; got != want {
351 t.Errorf("got %s, want %s", got, want)
353 if got, want := js.ValueOf("test").Type(), js.TypeString; got != want {
354 t.Errorf("got %s, want %s", got, want)
356 if got, want := js.Global().Get("Symbol").Invoke("test").Type(), js.TypeSymbol; got != want {
357 t.Errorf("got %s, want %s", got, want)
359 if got, want := js.Global().Get("Array").New().Type(), js.TypeObject; got != want {
360 t.Errorf("got %s, want %s", got, want)
362 if got, want := js.Global().Get("Array").Type(), js.TypeFunction; got != want {
363 t.Errorf("got %s, want %s", got, want)
367 type object = map[string]interface{}
368 type array = []interface{}
370 func 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)
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)
382 func TestZeroValue(t *testing.T) {
383 var v js.Value
384 if !v.IsUndefined() {
385 t.Error("zero js.Value is not js.Undefined()")
389 func TestFuncOf(t *testing.T) {
390 c := make(chan struct{})
391 cb := js.FuncOf(func(this js.Value, args []js.Value) interface{} {
392 if got := args[0].Int(); got != 42 {
393 t.Errorf("got %#v, want %#v", got, 42)
395 c <- struct{}{}
396 return nil
398 defer cb.Release()
399 js.Global().Call("setTimeout", cb, 0, 42)
403 func 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
410 defer cb2.Release()
411 return cb2.Invoke()
413 defer cb.Release()
414 if got := cb.Invoke().Int(); got != 42 {
415 t.Errorf("got %#v, want %#v", got, 42)
417 if !called {
418 t.Error("function not called")
422 func TestInterleavedFunctions(t *testing.T) {
423 c1 := make(chan struct{})
424 c2 := make(chan struct{})
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)
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
438 f.Invoke()
441 func ExampleFuncOf() {
442 var cb js.Func
443 cb = js.FuncOf(func(this js.Value, args []js.Value) interface{} {
444 fmt.Println("button clicked")
445 cb.Release() // release the function if the button will not be clicked again
446 return nil
448 js.Global().Get("document").Call("getElementById", "myButton").Call("addEventListener", "click", cb)
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
455 func 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",
465 if got := dummys.Get(key).Truthy(); got != want {
466 t.Errorf("%s: got %#v, want %#v", key, got, want)
470 want = false
471 if got := dummys.Get("zero").Truthy(); got != want {
472 t.Errorf("got %#v, want %#v", got, want)
474 if got := dummys.Get("NaN").Truthy(); got != want {
475 t.Errorf("got %#v, want %#v", got, want)
477 if got := js.ValueOf("").Truthy(); got != want {
478 t.Errorf("got %#v, want %#v", got, want)
480 if got := js.Null().Truthy(); got != want {
481 t.Errorf("got %#v, want %#v", got, want)
483 if got := js.Undefined().Truthy(); got != want {
484 t.Errorf("got %#v, want %#v", got, want)
488 func 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)
495 fn()
498 func expectPanic(t *testing.T, fn func()) {
499 defer func() {
500 err := recover()
501 if err == nil {
502 t.Errorf("expected panic")
505 fn()
508 var copyTests = []struct {
509 srcLen int
510 dstLen int
511 copyLen int
513 {5, 3, 3},
514 {3, 5, 3},
515 {0, 0, 0},
518 func 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)
525 dst := make([]byte, tt.dstLen)
527 if got, want := js.CopyBytesToGo(dst, src), tt.copyLen; got != want {
528 t.Errorf("copied %d, want %d", got, want)
530 if tt.dstLen >= 2 {
531 if got, want := int(dst[1]), 42; got != want {
532 t.Errorf("got %d, want %d", got, want)
539 func 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
546 dst := js.Global().Get("Uint8Array").New(tt.dstLen)
548 if got, want := js.CopyBytesToJS(dst, src), tt.copyLen; got != want {
549 t.Errorf("copied %d, want %d", got, want)
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)
560 func 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()
566 after := js.JSGo.Get("_values").Length()
567 if after-before > 500 {
568 t.Errorf("garbage collection ineffective")
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.
575 func BenchmarkDOM(b *testing.B) {
576 document := js.Global().Get("document")
577 if document.IsUndefined() {
578 b.Skip("Not a browser environment. Skipping.")
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)
588 if got, want := myDiv.Get("innerHTML").String(), data; got != want {
589 b.Errorf("got %s, want %s", got, want)
591 document.Get("body").Call("removeChild", div)