View
@@ -0,0 +1,73 @@
# This test matches list_bad_import, but in module mode.
# Please keep them in sync.
env GO111MODULE=on
cd example.com
# Without -e, listing an otherwise-valid package with an unsatisfied direct import should fail.
# BUG: Today it succeeds.
go list -f '{{if .Error}}error{{end}} {{if .Incomplete}}incomplete{{end}} {{range .DepsErrors}}bad dep: {{.Err}}{{end}}' example.com/direct
! stdout ^error
stdout 'incomplete'
stdout 'bad dep: .*example.com/notfound'
# Listing with -deps should also fail.
# BUG: Today, it does not.
# ! go list -deps example.com/direct
# stderr example.com/notfound
go list -deps example.com/direct
stdout example.com/notfound
# Listing an otherwise-valid package that imports some *other* package with an
# unsatisfied import should also fail.
# BUG: Today, it succeeds.
go list -f '{{if .Error}}error{{end}} {{if .Incomplete}}incomplete{{end}} {{range .DepsErrors}}bad dep: {{.Err}}{{end}}' example.com/indirect
! stdout ^error
stdout incomplete
stdout 'bad dep: .*example.com/notfound'
# Again, -deps should fail.
# BUG: Again, it does not.
# ! go list -deps example.com/indirect
# stderr example.com/notfound
go list -deps example.com/indirect
stdout example.com/notfound
# Listing the missing dependency directly should fail outright...
! go list -f '{{if .Error}}error{{end}} {{if .Incomplete}}incomplete{{end}}' example.com/notfound
stderr 'cannot find module providing package example.com/notfound'
! stdout error
! stdout incomplete
# ...but listing with -e should succeed.
go list -e -f '{{if .Error}}error{{end}} {{if .Incomplete}}incomplete{{end}}' example.com/notfound
stdout error
stdout incomplete
# The pattern "all" should match only packages that acutally exist,
# ignoring those whose existence is merely implied by imports.
go list -e -f '{{.ImportPath}} {{.Error}}' all
stdout example.com/direct
stdout example.com/indirect
# TODO: go list creates a dummy package with the import-not-found
# but really the Error belongs on example.com/direct, and this package
# should not be printed.
# ! stdout example.com/notfound
-- example.com/go.mod --
module example.com
-- example.com/direct/direct.go --
package direct
import _ "example.com/notfound"
-- example.com/indirect/indirect.go --
package indirect
import _ "example.com/direct"
-- example.com/notfound/README --
This directory intentionally left blank.
View
@@ -0,0 +1,75 @@
env GO111MODULE=on
cd m
# 'go list all' should list all of the packages used (directly or indirectly) by
# the packages in the main module, but no other packages from the standard
# library or active modules.
go list all
stdout example.com/m/useunicode
stdout example.com/m/useunsafe
[cgo] stdout example.com/m/useC
[!cgo] ! stdout example.com/m/useC
stdout '^unicode$'
stdout '^unsafe$'
! stdout index/suffixarray
# 'go list ...' should list packages in all active modules and the standard library.
# But not cmd/* - see golang.org/issue/26924.
go list ...
stdout example.com/unused/useerrors
stdout example.com/m/useunsafe
[cgo] stdout example.com/m/useC
[!cgo] ! stdout example.com/m/useC
stdout '^unicode$'
stdout '^unsafe$'
stdout index/suffixarray
! stdout cmd/pprof
# 'go list example.com/m/...' should list packages in all modules that begin with
# "example.com/m/".
go list example.com/m/...
stdout example.com/m/useunicode
stdout example.com/m/useunsafe
! stdout example.com/[^m]
! stdout ^[^e]
[cgo] stdout example.com/m/useC
[!cgo] ! stdout example.com/m/useC
# 'go list ./...' should list only packages in the current module, not other active modules.
go list ./...
stdout example.com/m/useunicode
stdout example.com/m/useunsafe
[cgo] stdout example.com/m/useC
[!cgo] ! stdout example.com/m/useC
-- m/go.mod --
module example.com/m
require example.com/unused v0.0.0 // indirect
replace example.com/unused => ../unused
require example.com/m/nested v0.0.0 // indirect
replace example.com/m/nested => ../nested
-- m/useC/useC.go --
package useC
import _ "C" // "C" is a pseudo-package, not an actual one
-- m/useunicode/useunicode.go --
package useunicode
import _ "unicode"
-- m/useunsafe/useunsafe.go --
package useunsafe
import _ "unsafe"
-- unused/go.mod --
module example.com/unused
-- unused/useerrors/useerrors.go --
package useerrors
import _ "errors"
-- nested/go.mod --
module example.com/m/nested
-- nested/useencoding/useencoding.go --
package useencoding
import _ "encoding"
View
@@ -1,10 +1,13 @@
env GO111MODULE=on
# -mod=readonly must not resolve missing modules nor update go.mod
#
# TODO(bcmills): 'go list' should suffice, but today it does not fail due to
# unresolved imports. When that is fixed, use 'go list' instead of 'go list all'.
env GOFLAGS=-mod=readonly
go mod edit -fmt
cp go.mod go.mod.empty
! go list
! go list all
stderr 'import lookup disabled by -mod=readonly'
cmp go.mod go.mod.empty
View
@@ -20,7 +20,7 @@ stdout 'Clear is better than clever.'
# However, the same module can't be used as two different paths.
go mod edit -dropreplace=rsc.io/quote/v3 -replace=not-rsc.io/quote/v3@v3.0.0=rsc.io/quote/v3@v3.0.0 -require=not-rsc.io/quote/v3@v3.0.0
! go build -o a4.exe .
stderr 'rsc.io/quote/v3@v3.0.0 used for two different module paths \(not-rsc.io/quote/v3 and rsc.io/quote/v3\)'
-- go.mod --
module quoter
View
@@ -1,18 +1,119 @@
env GO111MODULE=on
# A test in the module's root package should work.
cd a/
cp go.mod.empty go.mod
go test
stdout PASS
-- a/go.mod --
module github.com/user/a
cp go.mod.empty go.mod
go list -deps
! stdout ^testing$
# list all should include test dependencies, like testing
cp go.mod.empty go.mod
go list all
stdout ^testing$
stdout ^rsc.io/quote$
stdout ^rsc.io/testonly$
# list -deps -tests should also include testing
# but not deps of tests of deps (rsc.io/testonly).
go list -deps -test
stdout ^testing$
stdout ^rsc.io/quote$
! stdout ^rsc.io/testonly$
# list -test all should succeed
cp go.mod.empty go.mod
go list -test all
stdout '^testing'
cp go.mod.empty go.mod
go test
stdout PASS
# A test with the "_test" suffix in the module root should also work.
cd ../b/
go test
stdout PASS
# A test with the "_test" suffix of a *package* with a "_test" suffix should
# even work (not that you should ever do that).
cd ../c_test
go test
stdout PASS
cd ../d_test
go test
stdout PASS
-- a/go.mod.empty --
module example.com/user/a
-- a/a.go --
package a
-- a/a_test.go --
package a
import "testing"
import _ "rsc.io/quote"
func Test(t *testing.T) {}
-- b/go.mod --
module example.com/user/b
-- b/b.go --
package b
-- b/b_test.go --
package b_test
import "testing"
func Test(t *testing.T) {}
-- c_test/go.mod --
module example.com/c_test
-- c_test/umm.go --
// Package c_test is the non-test package for its import path!
package c_test
-- c_test/c_test_test.go --
package c_test_test
import "testing"
func Test(t *testing.T) {}
-- d_test/go.mod --
// Package d is an ordinary package in a deceptively-named directory.
module example.com/d
-- d_test/d.go --
package d
-- d_test/d_test.go --
package d_test
import "testing"
func Test(t *testing.T) {}
-- e/go.mod --
module example.com/e_test
-- e/wat.go --
// Package e_test is the non-test package for its import path,
// in a deceptively-named directory!
package e_test
-- e/e_test.go --
package e_test_test
import "testing"
func Test(t *testing.T) {}
View
@@ -155,6 +155,12 @@ package m
import _ "appengine"
import _ "appengine/datastore"
-- nonexistent.go --
// +build alternatereality
package m
import _ "nonexistent.rsc.io"
-- mypkg/go.mod --
module me
-- mypkg/mydir/d.go --
View
@@ -0,0 +1,27 @@
env GO111MODULE=on
# initial conditions: using sampler v1.3.0, not listed in go.mod.
go list -deps
stdout rsc.io/sampler
! grep 'rsc.io/sampler v1.3.0' go.mod
# update to v1.3.1, now indirect in go.mod.
go get rsc.io/sampler@v1.3.1
grep 'rsc.io/sampler v1.3.1 // indirect' go.mod
cp go.mod go.mod.good
# vendoring can but should not need to make changes.
go mod vendor
cmp go.mod go.mod.good
# go list -mod=vendor (or go build -mod=vendor) must not modify go.mod.
# golang.org/issue/26704
go list -mod=vendor
cmp go.mod go.mod.good
-- go.mod --
module m
-- x.go --
package x
import _ "rsc.io/quote"
View
@@ -0,0 +1,114 @@
env GO111MODULE=on
go list -test all
stdout rsc.io/quote
stdout golang.org/x/text/language
# why a package?
go mod why golang.org/x/text/language
cmp stdout why-language.txt
# why a module?
go mod why -m golang.org...
cmp stdout why-text-module.txt
# why a package used only in tests?
go mod why rsc.io/testonly
cmp stdout why-testonly.txt
# why a module used only in tests?
go mod why -m rsc.io/testonly
cmp stdout why-testonly.txt
# test package not needed
go mod why golang.org/x/text/unused
cmp stdout why-unused.txt
# vendor doesn't use packages used only in tests.
go mod why -vendor rsc.io/testonly
cmp stdout why-vendor.txt
# vendor doesn't use modules used only in tests.
go mod why -vendor -m rsc.io/testonly
cmp stdout why-vendor-module.txt
# test multiple packages
go mod why golang.org/x/text/language golang.org/x/text/unused
cmp stdout why-both.txt
# test multiple modules
go mod why -m rsc.io/quote rsc.io/sampler
cmp stdout why-both-module.txt
-- go.mod --
module mymodule
require rsc.io/quote v1.5.2
-- x/x.go --
package x
import _ "mymodule/z"
-- y/y.go --
package y
-- y/y_test.go --
package y
import _ "rsc.io/quote"
-- z/z.go --
package z
import _ "mymodule/y"
-- why-language.txt --
# golang.org/x/text/language
mymodule/y
mymodule/y.test
rsc.io/quote
rsc.io/sampler
golang.org/x/text/language
-- why-unused.txt --
# golang.org/x/text/unused
(main module does not need package golang.org/x/text/unused)
-- why-text-module.txt --
# golang.org/x/text
mymodule/y
mymodule/y.test
rsc.io/quote
rsc.io/sampler
golang.org/x/text/language
-- why-testonly.txt --
# rsc.io/testonly
mymodule/y
mymodule/y.test
rsc.io/quote
rsc.io/sampler
rsc.io/sampler.test
rsc.io/testonly
-- why-vendor.txt --
# rsc.io/testonly
(main module does not need to vendor package rsc.io/testonly)
-- why-vendor-module.txt --
# rsc.io/testonly
(main module does not need to vendor module rsc.io/testonly)
-- why-both.txt --
# golang.org/x/text/language
mymodule/y
mymodule/y.test
rsc.io/quote
rsc.io/sampler
golang.org/x/text/language
# golang.org/x/text/unused
(main module does not need package golang.org/x/text/unused)
-- why-both-module.txt --
# rsc.io/quote
mymodule/y
mymodule/y.test
rsc.io/quote
# rsc.io/sampler
mymodule/y
mymodule/y.test
rsc.io/quote
rsc.io/sampler
View
@@ -114,7 +114,7 @@ func (f *elfFile) goarch() string {
func (f *elfFile) loadAddress() (uint64, error) {
for _, p := range f.elf.Progs {
if p.Type == elf.PT_LOAD {
if p.Type == elf.PT_LOAD && p.Flags&elf.PF_X != 0 {
return p.Vaddr, nil
}
}
View
@@ -188,7 +188,7 @@ func playExample(file *ast.File, f *ast.FuncDecl) *ast.File {
inspectFunc = func(n ast.Node) bool {
switch e := n.(type) {
case *ast.Ident:
if e.Obj == nil {
if e.Obj == nil && e.Name != "_" {
unresolved[e.Name] = true
} else if d := topDecls[e.Obj]; d != nil {
if !hasDepDecls[d] {
View
@@ -221,13 +221,22 @@ func (p *printer) exprList(prev0 token.Pos, list []ast.Expr, depth int, mode exp
// If the previous line and the current line had single-
// line-expressions and the key sizes are small or the
// ratio between the current key and the geometric mean
// if the previous key sizes does not exceed a threshold,
// align columns and do not use formfeed.
// does not exceed a threshold, align columns and do not use
// formfeed.
// If the previous line was an empty line, break the alignment.
// (The text/tabwriter will break alignment after an empty line
// even if we don't do anything here, but we can't see that; yet
// we need to reset the variables used in the geomean
// computation after an alignment break. Do it explicitly
// instead so we're aware of the break. Was issue #26352.)
if prevSize > 0 && size > 0 {
const smallSize = 40
if count == 0 || prevSize <= smallSize && size <= smallSize {
switch {
case prevLine+1 < line:
useFF = true
case count == 0, prevSize <= smallSize && size <= smallSize:
useFF = false
} else {
default:
const r = 2.5 // threshold
geomean := math.Exp(lnsum / float64(count)) // count > 0
ratio := float64(size) / geomean
View
@@ -128,3 +128,12 @@ func main() {
abcdefghijklmnopqrstuvwxyz: "foo",
}
}
// ----------------------------------------------------------------------------
// Examples from issue #26352.
var _ = map[int]string{
1: "",
12345678901234567890123456789: "",
12345678901234567890123456789012345678: "",
}
View
@@ -128,3 +128,12 @@ func main() {
abcdefghijklmnopqrstuvwxyz: "foo",
}
}
// ----------------------------------------------------------------------------
// Examples from issue #26352.
var _ = map[int]string{
1: "",
12345678901234567890123456789: "",
12345678901234567890123456789012345678: "",
}
View
@@ -42,7 +42,7 @@ func mustTypecheck(t *testing.T, path, source string, info *Info) string {
return pkg.Name()
}
func maybeTypecheck(t *testing.T, path, source string, info *Info) string {
func mayTypecheck(t *testing.T, path, source string, info *Info) string {
fset := token.NewFileSet()
f, err := parser.ParseFile(fset, path, source, 0)
if f == nil { // ignore errors unless f is nil
@@ -265,7 +265,7 @@ func TestTypesInfo(t *testing.T) {
for _, test := range tests {
info := Info{Types: make(map[ast.Expr]TypeAndValue)}
name := maybeTypecheck(t, "TypesInfo", test.src, &info)
name := mayTypecheck(t, "TypesInfo", test.src, &info)
// look for expression type
var typ Type
View
@@ -310,7 +310,7 @@ func (check *Checker) shortVarDecl(pos token.Pos, lhs, rhs []ast.Expr) {
check.recordDef(ident, obj)
}
} else {
check.expr(&operand{}, lhs)
check.useLHS(lhs)
check.errorf(lhs.Pos(), "cannot declare %s", lhs)
}
if obj == nil {
View
@@ -34,9 +34,7 @@ func (check *Checker) call(x *operand, e *ast.CallExpr) exprKind {
check.conversion(x, T)
}
default:
for _, arg := range e.Args {
check.expr(&operand{}, arg)
}
check.use(e.Args...)
check.errorf(e.Args[n-1].Pos(), "too many arguments in conversion to %s", T)
}
x.expr = e
View
@@ -91,6 +91,7 @@ var tests = [][]string{
{"testdata/issues.src"},
{"testdata/blank.src"},
{"testdata/issue25008b.src", "testdata/issue25008a.src"}, // order (b before a) is crucial!
{"testdata/issue26390.src"}, // stand-alone test to ensure case is triggered
}
var fset = token.NewFileSet()
View
@@ -165,6 +165,31 @@ func (check *Checker) objDecl(obj Object, def *Named, path []*TypeName) {
}
case *TypeName:
// fixFor26390 enables a temporary work-around to handle alias type names
// that have not been given a type yet even though the underlying type
// is already known. See testdata/issue26390.src for a simple example.
// Set this flag to false to disable this code quickly (and comment
// out the new test in decls4.src that will fail again).
// TODO(gri) remove this for Go 1.12 in favor of a more comprehensive fix
const fixFor26390 = true
if fixFor26390 {
// If we have a package-level alias type name that has not been
// given a type yet but the underlying type is a type name that
// has been given a type already, don't report a cycle but use
// the underlying type name's type instead. The cycle shouldn't
// exist in the first place in this case and is due to the way
// methods are type-checked at the moment. See also the comment
// at the end of Checker.typeDecl below.
if d := check.objMap[obj]; d != nil && d.alias && obj.typ == Typ[Invalid] {
// If we can find the underlying type name syntactically
// and it has a type, use that type.
if tname := check.resolveBaseTypeName(ast.NewIdent(obj.name)); tname != nil && tname.typ != nil {
obj.typ = tname.typ
break
}
}
}
if useCycleMarking && check.typeCycle(obj) {
// break cycle
// (without this, calling underlying()
View
@@ -1094,6 +1094,8 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
continue
}
key, _ := kv.Key.(*ast.Ident)
// do all possible checks early (before exiting due to errors)
// so we don't drop information on the floor
check.expr(x, kv.Value)
if key == nil {
check.errorf(kv.Pos(), "invalid field name %s in struct literal", kv.Key)
View
@@ -0,0 +1,11 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package issue26390
type A = T
func (t *T) m() *A { return t }
type T struct{}
View
@@ -27,9 +27,9 @@ func absInt32(i int32) uint32 {
return uint32(i)
}
// NormFloat64 returns a normally distributed float64 in the range
// [-math.MaxFloat64, +math.MaxFloat64] with
// standard normal distribution (mean = 0, stddev = 1).
// NormFloat64 returns a normally distributed float64 in
// the range -math.MaxFloat64 through +math.MaxFloat64 inclusive,
// with standard normal distribution (mean = 0, stddev = 1).
// To produce a different normal distribution, callers can
// adjust the output using:
//
View
@@ -11,6 +11,9 @@
// The default Source is safe for concurrent use by multiple goroutines, but
// Sources created by NewSource are not.
//
// Mathematical interval notation such as [0, n) is used throughout the
// documentation for this package.
//
// For random numbers suitable for security-sensitive work, see the crypto/rand
// package.
package rand
View
@@ -95,14 +95,12 @@ type Client struct {
// A Timeout of zero means no timeout.
//
// The Client cancels requests to the underlying Transport
// using the Request.Cancel mechanism. Requests passed
// to Client.Do may still set Request.Cancel; both will
// cancel the request.
// as if the Request's Context ended.
//
// For compatibility, the Client will also use the deprecated
// CancelRequest method on Transport if found. New
// RoundTripper implementations should use Request.Cancel
// instead of implementing CancelRequest.
// RoundTripper implementations should use the Request's Context
// for cancelation instead of implementing CancelRequest.
Timeout time.Duration
}
View
@@ -339,6 +339,10 @@ func (r *Request) Context() context.Context {
// WithContext returns a shallow copy of r with its context changed
// to ctx. The provided ctx must be non-nil.
//
// For outgoing client request, the context controls the entire
// lifetime of a request and its response: obtaining a connection,
// sending the request, and reading the response headers and body.
func (r *Request) WithContext(ctx context.Context) *Request {
if ctx == nil {
panic("nil context")
View
@@ -17,17 +17,27 @@ import (
"syscall/js"
)
// jsFetchMode is a Request.Header map key that, if present,
// signals that the map entry is actually an option to the Fetch API mode setting.
// Valid values are: "cors", "no-cors", "same-origin", "navigate"
// The default is "same-origin".
//
// Reference: https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch#Parameters
const jsFetchMode = "js.fetch:mode"
// jsFetchCreds is a Request.Header map key that, if present,
// signals that the map entry is actually an option to the Fetch API credentials setting.
// Valid values are: "omit", "same-origin", "include"
// The default is "same-origin".
//
// Reference: https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch#Parameters
const jsFetchCreds = "js.fetch:credentials"
// RoundTrip implements the RoundTripper interface using the WHATWG Fetch API.
func (t *Transport) RoundTrip(req *Request) (*Response, error) {
if useFakeNetwork() {
return t.roundTrip(req)
}
headers := js.Global().Get("Headers").New()
for key, values := range req.Header {
for _, value := range values {
headers.Call("append", key, value)
}
}
ac := js.Global().Get("AbortController")
if ac != js.Undefined() {
@@ -40,12 +50,26 @@ func (t *Transport) RoundTrip(req *Request) (*Response, error) {
opt := js.Global().Get("Object").New()
// See https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch
// for options available.
opt.Set("headers", headers)
opt.Set("method", req.Method)
opt.Set("credentials", "same-origin")
if h := req.Header.Get(jsFetchCreds); h != "" {
opt.Set("credentials", h)
req.Header.Del(jsFetchCreds)
}
if h := req.Header.Get(jsFetchMode); h != "" {
opt.Set("mode", h)
req.Header.Del(jsFetchMode)
}
if ac != js.Undefined() {
opt.Set("signal", ac.Get("signal"))
}
headers := js.Global().Get("Headers").New()
for key, values := range req.Header {
for _, value := range values {
headers.Call("append", key, value)
}
}
opt.Set("headers", headers)
if req.Body != nil {
// TODO(johanbrandhorst): Stream request body when possible.
View
@@ -80,10 +80,10 @@ func testSpliceMultipleWrite(t *testing.T) {
}
func testSpliceBig(t *testing.T) {
size := 1<<31 - 1
if testing.Short() {
size = 1 << 25
}
// The maximum amount of data that internal/poll.Splice will use in a
// splice(2) call is 4 << 20. Use a bigger size here so that we test an
// amount that doesn't fit in a single call.
size := 5 << 20
srv, err := newSpliceTestServer()
if err != nil {
t.Fatal(err)
View
@@ -296,7 +296,7 @@ func Truncate(name string, size int64) error {
return nil
}
// Remove removes the named file or directory.
// Remove removes the named file or (empty) directory.
// If there is an error, it will be of type *PathError.
func Remove(name string) error {
// System call interface forces us to know
View
@@ -163,6 +163,13 @@ func wbBufFlush(dst *uintptr, src uintptr) {
// Note: Every possible return from this function must reset
// the buffer's next pointer to prevent buffer overflow.
// This *must not* modify its arguments because this
// function's argument slots do double duty in gcWriteBarrier
// as register spill slots. Currently, not modifying the
// arguments is sufficient to keep the spill slots unmodified
// (which seems unlikely to change since it costs little and
// helps with debugging).
if getg().m.dying > 0 {
// We're going down. Not much point in write barriers
// and this way we can allow write barriers in the
View
@@ -162,7 +162,22 @@ func testGdbPython(t *testing.T, cgo bool) {
args := []string{"-nx", "-q", "--batch",
"-iex", "add-auto-load-safe-path " + filepath.Join(runtime.GOROOT(), "src", "runtime"),
"-ex", "set startup-with-shell off",
"-ex", "info auto-load python-scripts",
}
if cgo {
// When we build the cgo version of the program, the system's
// linker is used. Some external linkers, like GNU gold,
// compress the .debug_gdb_scripts into .zdebug_gdb_scripts.
// Until gold and gdb can work together, temporarily load the
// python script directly.
args = append(args,
"-ex", "source "+filepath.Join(runtime.GOROOT(), "src", "runtime", "runtime-gdb.py"),
)
} else {
args = append(args,
"-ex", "info auto-load python-scripts",
)
}
args = append(args,
"-ex", "set python print-stack full",
"-ex", "br fmt.Println",
"-ex", "run",
@@ -193,7 +208,7 @@ func testGdbPython(t *testing.T, cgo bool) {
"-ex", "goroutine 1 bt",
"-ex", "echo END\n",
filepath.Join(dir, "a.exe"),
}
)
got, _ := exec.Command("gdb", args...).CombinedOutput()
t.Logf("gdb output: %s\n", got)
View
@@ -64,6 +64,9 @@ var (
valueGlobal = predefValue(5)
memory = predefValue(6) // WebAssembly linear memory
jsGo = predefValue(7) // instance of the Go class in JavaScript
objectConstructor = valueGlobal.Get("Object")
arrayConstructor = valueGlobal.Get("Array")
)
// Undefined returns the JavaScript value "undefined".
@@ -83,15 +86,17 @@ func Global() Value {
// ValueOf returns x as a JavaScript value:
//
// | Go | JavaScript |
// | --------------------- | --------------------- |
// | js.Value | [its value] |
// | js.TypedArray | [typed array] |
// | js.Callback | function |
// | nil | null |
// | bool | boolean |
// | integers and floats | number |
// | string | string |
// | Go | JavaScript |
// | ---------------------- | ---------------------- |
// | js.Value | [its value] |
// | js.TypedArray | typed array |
// | js.Callback | function |
// | nil | null |
// | bool | boolean |
// | integers and floats | number |
// | string | string |
// | []interface{} | new array |
// | map[string]interface{} | new object |
func ValueOf(x interface{}) Value {
switch x := x.(type) {
case Value:
@@ -138,6 +143,18 @@ func ValueOf(x interface{}) Value {
return floatValue(x)
case string:
return makeValue(stringVal(x))
case []interface{}:
a := arrayConstructor.New(len(x))
for i, s := range x {
a.SetIndex(i, s)
}
return a
case map[string]interface{}:
o := objectConstructor.New()
for k, v := range x {
o.Set(k, v)
}
return o
default:
panic("ValueOf: invalid value")
}
View
@@ -254,6 +254,21 @@ func TestType(t *testing.T) {
}
}
type object = map[string]interface{}
type array = []interface{}
func TestValueOf(t *testing.T) {
a := js.ValueOf(array{0, array{0, 42, 0}, 0})
if got := a.Index(1).Index(1).Int(); got != 42 {
t.Errorf("got %v, want %v", got, 42)
}
o := js.ValueOf(object{"x": object{"y": 42}})
if got := o.Get("x").Get("y").Int(); got != 42 {
t.Errorf("got %v, want %v", got, 42)
}
}
func TestCallback(t *testing.T) {
c := make(chan struct{})
cb := js.NewCallback(func(args []js.Value) {